From f84cec479d41fb143487af7e78a6b3056f6b8823 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Mon, 8 Dec 2008 21:38:18 +0000 Subject: Implement concept of logins (no-op). Do RSA testing, and fix problems discovered in RSA code. --- ckcapi-key.c | 51 +++++++++++++++++++++++++--------- ckcapi-rsa.c | 4 +-- ckcapi-session.c | 24 ++++++++++++++++ ckcapi-session.h | 4 +++ ckcapi-token.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- ckcapi-token.h | 6 ++++ ckcapi.c | 53 ++++++++++++++++++++++++++++++----- 7 files changed, 201 insertions(+), 26 deletions(-) diff --git a/ckcapi-key.c b/ckcapi-key.c index 89ef726..7618e1e 100644 --- a/ckcapi-key.c +++ b/ckcapi-key.c @@ -98,7 +98,8 @@ typedef struct _KeyObjectData KeyObjectData; static CK_RV -load_key_handle (CkCapiObjectData* objdata, HCRYPTKEY* ret_key) +load_key_handle (CkCapiObjectData* objdata, HCRYPTPROV* ret_prov, + HCRYPTKEY* ret_key) { KeyObjectData* kdata = (KeyObjectData*)objdata; HCRYPTPROV prov; @@ -106,6 +107,8 @@ load_key_handle (CkCapiObjectData* objdata, HCRYPTKEY* ret_key) DWORD error; ASSERT(kdata); + ASSERT(ret_key); + ASSERT(ret_prov); if(!CryptAcquireContextW(&prov, kdata->prov_info->pwszContainerName, kdata->prov_info->pwszProvName, @@ -121,12 +124,9 @@ load_key_handle (CkCapiObjectData* objdata, HCRYPTKEY* ret_key) return ckcapi_winerr_to_ckr(error); } - if(ret_key) - *ret_key = key; - else - CryptDestroyKey(key); + *ret_key = key; + *ret_prov = prov; - CryptReleaseContext(prov, 0); return CKR_OK; } @@ -135,6 +135,7 @@ static CK_RV load_raw_public_key(KeyObjectData* kdata) { BOOL success = FALSE; + HCRYPTPROV prov; HCRYPTKEY key; CK_RV ret; DWORD error; @@ -142,7 +143,7 @@ load_raw_public_key(KeyObjectData* kdata) ASSERT(kdata); ASSERT(!kdata->raw_public_key.pbData); - ret = load_key_handle(&kdata->base, &key); + ret = load_key_handle(&kdata->base, &prov, &key); if(ret != CKR_OK) return ret; @@ -161,6 +162,7 @@ load_raw_public_key(KeyObjectData* kdata) } } + CryptReleaseContext(prov, 0); CryptDestroyKey(key); if(success) @@ -237,12 +239,13 @@ key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) { KeyObjectData* kdata = (KeyObjectData*)objdata; CK_BBOOL val; - CK_BBOOL is_private; + CK_BBOOL is_private, is_rsa; ASSERT(objdata); ASSERT(attr); is_private = (kdata->object_class == CKO_PRIVATE_KEY); + is_rsa = kdata->prov_info->dwProvType == PROV_RSA_FULL; switch(attr->type) { @@ -268,7 +271,7 @@ key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) * - CKK_RSA but not CKK_DSA. */ case CKA_DECRYPT: - val = CK_TRUE; + val = is_private && is_rsa; break; /* @@ -280,6 +283,14 @@ key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) val = CK_FALSE; break; + /* + * Whether or not this key can be used to encrypt?. + * TODO: Support for RSA public keys. + */ + case CKA_ENCRYPT: + val = CK_FALSE; + break; + /* * Whether this key can be exported or not. * TODO: We may want to support this for public keys. @@ -340,11 +351,10 @@ key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) /* * Can this key sign recoverable. - * - Private RSA keys can sign recoverable. - * TODO: When implementing DSA more logic needed. + * TODO: Private RSA keys can sign recoverable. */ case CKA_SIGN_RECOVER: - val = is_private; + val = CK_FALSE; break; /* @@ -371,6 +381,21 @@ key_bool_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) case CKA_WRAP_WITH_TRUSTED: return CKR_ATTRIBUTE_TYPE_INVALID; + /* + * Whether this key can be used to verify? + * TODO: Support for public keys. + */ + case CKA_VERIFY: + val = CK_FALSE; + break; + + /* + * Whether this key can be used to verify? + * TODO: Support for public keys. + */ + case CKA_VERIFY_RECOVER: + val = CK_FALSE; + break; default: return CKR_ATTRIBUTE_TYPE_INVALID; @@ -490,7 +515,7 @@ key_bytes_attribute(CkCapiObjectData* objdata, CK_ATTRIBUTE_PTR attr) case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: - if(kdata->prov_info->dwProvType = PROV_RSA_FULL) + if(kdata->prov_info->dwProvType == PROV_RSA_FULL) return lookup_rsa_attribute(kdata, attr); else return CKR_ATTRIBUTE_TYPE_INVALID; diff --git a/ckcapi-rsa.c b/ckcapi-rsa.c index 122ac53..032bf82 100644 --- a/ckcapi-rsa.c +++ b/ckcapi-rsa.c @@ -170,7 +170,7 @@ ckcapi_rsa_pkcs_sign_init(CkCapiObjectData *keydata, void** operation) ASSERT(!*operation); prov_info = ckcapi_key_object_data_get_prov_info(keydata); - if(prov_info->dwProvType == PROV_RSA_FULL) + if(prov_info->dwProvType != PROV_RSA_FULL) return CKR_KEY_TYPE_INCONSISTENT; *operation = keydata; @@ -302,7 +302,7 @@ ckcapi_rsa_pkcs_decrypt_init(CkCapiObjectData* keydata, void** operation) ASSERT(!*operation); prov_info = ckcapi_key_object_data_get_prov_info(keydata); - if(prov_info->dwProvType == PROV_RSA_FULL) + if(prov_info->dwProvType != PROV_RSA_FULL) return CKR_KEY_TYPE_INCONSISTENT; *operation = keydata; diff --git a/ckcapi-session.c b/ckcapi-session.c index f4f00aa..064e477 100644 --- a/ckcapi-session.c +++ b/ckcapi-session.c @@ -212,6 +212,26 @@ ckcapi_session_destroy(CkCapiSession* sess) free(sess); } +void +ckcapi_session_get_info(CkCapiSession* sess, CK_SESSION_INFO_PTR info) +{ + ASSERT(sess); + ASSERT(info); + + info->slotID = sess->slot; + info->flags = CKF_SERIAL_SESSION; + if(sess->read_write) + info->flags |= CKF_RW_SESSION; + + if(ckcapi_token_is_logged_in(sess->slot)) + info->state = sess->read_write ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS; + else + info->state = sess->read_write ? CKS_RW_PUBLIC_SESSION : CKS_RO_PUBLIC_SESSION; + + /* TODO: We could implement some use of GetLastError() here */ + info->ulDeviceError = 0; +} + static CK_RV lock_ref_internal(CkCapiArray* sessions, CK_SESSION_HANDLE id, BOOL remove, BOOL writable, CkCapiSession** sess_ret) @@ -824,8 +844,10 @@ ckcapi_session_sign_init(CkCapiSession* sess, CK_MECHANISM_PTR mech, case CKM_RSA_PKCS: ret = ckcapi_rsa_pkcs_sign_init(objdata, &ctx->mech_data); ctx->mech_cleanup = ckcapi_rsa_pkcs_sign_cleanup; + break; default: ret = CKR_MECHANISM_INVALID; + break; }; if(ret != CKR_OK) @@ -904,8 +926,10 @@ ckcapi_session_decrypt_init(CkCapiSession* sess, CK_MECHANISM_PTR mech, case CKM_RSA_PKCS: ret = ckcapi_rsa_pkcs_decrypt_init(objdata, &ctx->mech_data); ctx->mech_cleanup = ckcapi_rsa_pkcs_decrypt_cleanup; + break; default: ret = CKR_MECHANISM_INVALID; + break; }; if(ret != CKR_OK) diff --git a/ckcapi-session.h b/ckcapi-session.h index 7b71c07..f486277 100644 --- a/ckcapi-session.h +++ b/ckcapi-session.h @@ -63,6 +63,10 @@ void ckcapi_session_destroy (CkCapiSession* sess); /* Register a new session */ CK_RV ckcapi_session_register (CkCapiSession* sess); +/* Get information about a session */ +void ckcapi_session_get_info (CkCapiSession* sess, + CK_SESSION_INFO_PTR info); + /* Get a session from a handle, and lock it */ CK_RV ckcapi_session_get_lock_ref (CK_ULONG id, BOOL writable, CkCapiSession **sess); diff --git a/ckcapi-token.c b/ckcapi-token.c index a2beb74..4f0a7a3 100644 --- a/ckcapi-token.c +++ b/ckcapi-token.c @@ -23,6 +23,7 @@ static CkCapiArray* object_array = NULL; static CkCapiHash* object_hash = NULL; +static CkCapiArray* logged_in_slots = NULL; typedef struct _SlotInfo { @@ -34,11 +35,11 @@ SlotInfo; #define SLOT_OFFSET 0x00001000 -static const SlotInfo slot_info[] = { +static SlotInfo slot_info[] = { { "My", "Personal Certificates", CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CERTS }, { "AddressBook", "Address Book Certificates", CKCAPI_SLOT_CERTS }, - { "CA", "Certificate Authorities", CKCAPI_SLOT_CA | CKCAPI_SLOT_CERTS}, - { "Root", "Root Authorities", CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CA | CKCAPI_SLOT_CERTS}, + { "CA", "Certificate Authorities", CKCAPI_SLOT_CA | CKCAPI_SLOT_CERTS }, + { "Root", "Root Authorities", CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CA | CKCAPI_SLOT_CERTS }, { "Trust", "Trust", CKCAPI_SLOT_CERTS }, { "TrustedPeople", "Trusted People", CKCAPI_SLOT_TRUSTED | CKCAPI_SLOT_CERTS }, { "AuthRoot", "Auth Root", CKCAPI_SLOT_CERTS }, @@ -130,6 +131,12 @@ ckcapi_token_cleanup_all(void) object_array = NULL; } + if(logged_in_slots) + { + ckcapi_array_free(logged_in_slots, TRUE); + logged_in_slots = NULL; + } + ckcapi_unlock_global(); } @@ -213,7 +220,7 @@ ckcapi_token_register_object(CK_SLOT_ID slot, CkCapiObject* obj) /* Sanity check, in case calcs went wrong somewhere */ ASSERT(klen < 0xFFFFFF); -/* xxxxx hash function xxxxx */ + /* Look in the hash and find a previous object */ prev = ckcapi_hash_get(object_hash, key, klen); if(prev) @@ -267,3 +274,73 @@ ckcapi_token_register_object(CK_SLOT_ID slot, CkCapiObject* obj) return ret; } + +CK_BBOOL +ckcapi_token_is_logged_in(CK_SLOT_ID slot) +{ + unsigned int count, offset; + + ASSERT(ckcapi_token_is_valid(slot)); + + if(!logged_in_slots) + return CK_FALSE; + + offset = SLOT_TO_OFFSET(slot); + count = ckcapi_token_get_count(); + + ASSERT(logged_in_slots->len == count && offset < count); + return ckcapi_array_index(logged_in_slots, CK_BBOOL, offset); +} + +CK_RV +ckcapi_token_login(CK_SLOT_ID slot) +{ + unsigned int i, count; + unsigned int offset; + CK_BBOOL value; + + ASSERT(ckcapi_token_is_valid(slot)); + + offset = SLOT_TO_OFFSET(slot); + count = ckcapi_token_get_count(); + + if(!logged_in_slots) + { + logged_in_slots = ckcapi_array_sized_new(0, 1, sizeof(CK_BBOOL), count); + if(!logged_in_slots) + return CKR_HOST_MEMORY; + + value = CK_FALSE; + for(i = 0; i < count; ++i) + ckcapi_array_append(logged_in_slots, value); + + } + + ASSERT(logged_in_slots->len == count && offset < count); + if(ckcapi_array_index(logged_in_slots, CK_BBOOL, offset)) + return CKR_USER_ALREADY_LOGGED_IN; + + ckcapi_array_index(logged_in_slots, CK_BBOOL, offset) = CK_TRUE; + return CKR_OK; +} + +CK_RV +ckcapi_token_logout(CK_SLOT_ID slot) +{ + unsigned int count, offset; + + ASSERT(ckcapi_token_is_valid(slot)); + + if(!logged_in_slots) + return CKR_USER_NOT_LOGGED_IN; + + offset = SLOT_TO_OFFSET(slot); + count = ckcapi_token_get_count(); + + ASSERT(logged_in_slots->len == count && offset < count); + if(!ckcapi_array_index(logged_in_slots, CK_BBOOL, offset)) + return CKR_USER_NOT_LOGGED_IN; + + ckcapi_array_index(logged_in_slots, CK_BBOOL, offset) = CK_FALSE; + return CKR_OK; +} diff --git a/ckcapi-token.h b/ckcapi-token.h index 2024fa6..1176701 100644 --- a/ckcapi-token.h +++ b/ckcapi-token.h @@ -51,4 +51,10 @@ const char* ckcapi_token_get_store_name (CK_SLOT_ID slot); CK_ULONG ckcapi_token_get_flags (CK_SLOT_ID slot); +CK_RV ckcapi_token_login (CK_SLOT_ID slot); + +CK_RV ckcapi_token_logout (CK_SLOT_ID slot); + +CK_BBOOL ckcapi_token_is_logged_in (CK_SLOT_ID slot); + #endif /* CKCAPI_TOKEN_H */ diff --git a/ckcapi.c b/ckcapi.c index 378746e..50df4d7 100644 --- a/ckcapi.c +++ b/ckcapi.c @@ -76,7 +76,7 @@ ckcapi_debug(const char* msg, ...) strncpy(buf + len, "\n", 1024 - len); buf[LINE - 1] = 0; - OutputDebugStringA(buf); + // OutputDebugStringA(buf); } /* Bah humbug, MSVC doesn't have __func__ */ @@ -664,12 +664,21 @@ CC_C_CancelFunction(CK_SESSION_HANDLE session) static CK_RV CC_C_GetSessionInfo(CK_SESSION_HANDLE session, CK_SESSION_INFO_PTR info) { + CkCapiSession* sess; + CK_RV ret; + ENTER(C_GetSessionInfo); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); PREREQ(info, CKR_ARGUMENTS_BAD); - // TODO: Implement - RETURN(CKR_FUNCTION_NOT_SUPPORTED); + ret = ckcapi_session_get_lock_ref(session, FALSE, &sess); + if(ret == CKR_OK) + { + ckcapi_session_get_info(sess, info); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); } static CK_RV @@ -721,21 +730,51 @@ static CK_RV CC_C_Login(CK_SESSION_HANDLE session, CK_USER_TYPE user_type, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) { + CkCapiSession* sess; + CK_RV ret; + ENTER(C_Login); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); + + ret = ckcapi_session_get_lock_ref(session, FALSE, &sess); + if(ret == CKR_OK) + { + switch(user_type) + { + case CKU_USER: + ret = ckcapi_token_login(sess->slot); + break; + case CKU_SO: + ret = CKR_USER_TYPE_INVALID; + break; + default: + ret = CKR_USER_TYPE_INVALID; + break; + } - /* TODO: Implement our local concept of logged in */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); } static CK_RV CC_C_Logout(CK_SESSION_HANDLE session) { + CkCapiSession* sess; + CK_RV ret; + ENTER(C_Logout); PREREQ(cryptoki_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); - /* TODO: Implement our local concept of logged in */ - RETURN(CKR_FUNCTION_NOT_SUPPORTED); + ret = ckcapi_session_get_lock_ref(session, FALSE, &sess); + if(ret == CKR_OK) + { + ret = ckcapi_token_logout(sess->slot); + ckcapi_session_unref_unlock(sess); + } + + RETURN(ret); } static CK_RV -- cgit v1.2.3