diff options
-rw-r--r-- | pkcs11.c | 279 |
1 files changed, 152 insertions, 127 deletions
@@ -2103,17 +2103,42 @@ static CK_RV generate_keypair(p11_session_t *session, /* + * Add data to a digest. + */ + +static CK_RV digest_update(const hal_hash_descriptor_t * const descriptor, + hal_hash_state_t **state, + const uint8_t * const data, const size_t data_len) +{ + assert(descriptor != NULL && state != NULL && data != NULL); + + if (*state == NULL) { + switch (hal_hash_initialize(descriptor, state, NULL, 0)) { + case HAL_OK: + break; + case HAL_ERROR_ALLOCATION_FAILURE: + return CKR_HOST_MEMORY; + default: + return CKR_FUNCTION_FAILED; + } + } + + if (!hal_check(hal_hash_update(*state, data, data_len))) + return CKR_FUNCTION_FAILED; + + return CKR_OK; +} + +/* * Construct a PKCS #1 DigestInfo object. This requires some (very * basic) ASN.1 encoding, which we perform inline. */ static int pkcs1_construct_digestinfo(const hal_hash_descriptor_t * const desc, - const uint8_t * const data, const size_t data_len, + hal_hash_state_t *state, uint8_t *digest_info, const size_t digest_info_len) { - uint8_t statebuf[desc->hash_state_length]; - hal_hash_state_t *state = NULL; - uint8_t *d = digest_info; + assert(desc != NULL && state != NULL && digest_info != NULL); /* * Make sure size of output buffer is right. Caller is responsible @@ -2127,6 +2152,8 @@ static int pkcs1_construct_digestinfo(const hal_hash_descriptor_t * const desc, assert(digest_info_len == desc->digest_length + desc->digest_algorithm_id_length + 4); assert(digest_info_len < 130); + uint8_t *d = digest_info; + *d++ = 0x30; /* SEQUENCE */ *d++ = (uint8_t) (digest_info_len - 2); @@ -2138,14 +2165,7 @@ static int pkcs1_construct_digestinfo(const hal_hash_descriptor_t * const desc, assert(digest_info + digest_info_len == d + desc->digest_length); - const int ok = (hal_check(hal_hash_initialize(desc, &state, statebuf, sizeof(statebuf))) && - hal_check(hal_hash_update(state, data, data_len)) && - hal_check(hal_hash_finalize(state, d, desc->digest_length))); - - memset(statebuf, 0, sizeof(statebuf)); - if (!ok) - memset(digest_info, 0, digest_info_len); - return ok; + return hal_check(hal_hash_finalize(state, d, desc->digest_length)); } /* @@ -2195,31 +2215,70 @@ static int pkcs1_5_pad(const uint8_t * const data, const size_t data_len, } /* - * Sign a PKCS #1 DigestInfo using an RSA key and PKCS #1.5 padding. + * Generate an RSA PKCS #1.5 signature. * * As explained in RFC 3447, the RSASP1 (signature generation) * operation is the same mathematical operation as the RSADP * (decryption) operation (both use the private key as exponent). */ -static CK_RV sign_rsa_pkcs(const hal_rsa_key_t * const key, - const uint8_t * const digest_info, const size_t digest_info_len, - uint8_t *signature, const size_t signature_len) +static CK_RV sign_rsa_pkcs(p11_session_t *session, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) { + uint8_t keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *key = NULL; + size_t signature_len; CK_RV rv; - assert(digest_info != NULL && signature != NULL); + assert(session != NULL && pulSignatureLen != NULL); - if (!pkcs1_5_pad(digest_info, digest_info_len, signature, signature_len)) - lose(CKR_DATA_LEN_RANGE); + const hal_hash_descriptor_t * const desc = session->sign_digest_descriptor; + const size_t digest_info_len = desc == NULL ? 1 : desc->digest_length + 4 + desc->digest_algorithm_id_length; + uint8_t digest_info[digest_info_len]; - if (!hal_check(hal_rsa_decrypt(key, signature, signature_len, signature, signature_len))) + if (!p11_object_get_rsa_private_key(session->sign_key_handle, + &key, keybuf, sizeof(keybuf))) lose(CKR_FUNCTION_FAILED); - return CKR_OK; + /* + * Retrieve signature length, which is just the the modulus length. + */ + + if (!hal_check(hal_rsa_key_get_modulus(key, NULL, &signature_len, 0))) + lose(CKR_FUNCTION_FAILED); + + rv = signature_len > *pulSignatureLen ? CKR_BUFFER_TOO_SMALL : CKR_OK; + + *pulSignatureLen = signature_len; + + if (pSignature != NULL && rv == CKR_BUFFER_TOO_SMALL) + lose(CKR_BUFFER_TOO_SMALL); + + if (pSignature != NULL && desc != NULL) { + + if (!pkcs1_construct_digestinfo(desc, session->sign_digest_state, digest_info, sizeof(digest_info))) + lose(CKR_FUNCTION_FAILED); + + pData = digest_info; + ulDataLen = sizeof(digest_info); + } + + if (pSignature != NULL) { + + if (!pkcs1_5_pad(pData, ulDataLen, pSignature, signature_len)) + lose(CKR_DATA_LEN_RANGE); + + if (!hal_check(hal_rsa_decrypt(key, pSignature, signature_len, pSignature, signature_len))) + lose(CKR_FUNCTION_FAILED); + } + + rv = CKR_OK; /* Fall through */ fail: - memset(signature, 0, signature_len); + hal_rsa_key_clear(key); return rv; } @@ -2233,37 +2292,59 @@ static CK_RV sign_rsa_pkcs(const hal_rsa_key_t * const key, * unnecessary, but it's also harmless. */ -static CK_RV verify_rsa_pkcs(const hal_rsa_key_t * const key, - const uint8_t * const digest_info, const size_t digest_info_len, - const uint8_t * const signature, const size_t signature_len) +CK_RV verify_rsa_pkcs(p11_session_t *session, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) { - assert(digest_info != NULL && signature != NULL); + uint8_t keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *key = NULL; + CK_RV rv; + + assert(session != NULL); - uint8_t expected[signature_len], received[signature_len]; + const hal_hash_descriptor_t * const desc = session->verify_digest_descriptor; + const size_t digest_info_len = desc == NULL ? 1 : desc->digest_length + 4 + desc->digest_algorithm_id_length; + uint8_t digest_info[digest_info_len]; + uint8_t expected[ulSignatureLen], received[ulSignatureLen]; unsigned diff = 0; - CK_RV rv; - if (!pkcs1_5_pad(digest_info, digest_info_len, expected, sizeof(expected))) + if (!p11_object_get_rsa_public_key(session->verify_key_handle, + &key, keybuf, sizeof(keybuf))) + lose(CKR_FUNCTION_FAILED); + + if (session->verify_digest_descriptor != NULL) { + + if (!pkcs1_construct_digestinfo(session->verify_digest_descriptor, + session->verify_digest_state, + digest_info, sizeof(digest_info))) + lose(CKR_FUNCTION_FAILED); + + pData = digest_info; + ulSignatureLen = sizeof(digest_info); + + } + + if (!pkcs1_5_pad(pData, ulDataLen, expected, sizeof(expected))) lose(CKR_DATA_LEN_RANGE); - if (!hal_check(hal_rsa_encrypt(key, signature, signature_len, received, sizeof(received)))) + if (!hal_check(hal_rsa_encrypt(key, pSignature, ulSignatureLen, received, sizeof(received)))) lose(CKR_FUNCTION_FAILED); - for (int i = 0; i < signature_len; i++) + for (int i = 0; i < ulSignatureLen; i++) diff |= expected[i] ^ received[i]; if (diff != 0) lose(CKR_SIGNATURE_INVALID); - rv = CKR_OK; + rv = CKR_OK; /* Fall through */ fail: - memset(expected, 0, sizeof(expected)); - memset(received, 0, sizeof(received)); + hal_rsa_key_clear(key); return rv; } - /* @@ -3347,17 +3428,10 @@ CK_RV C_DigestUpdate(CK_SESSION_HANDLE hSession, if (!session->digest_descriptor->can_restore_state) lose(CKR_FUNCTION_FAILED); - if (session->digest_state == NULL) { - hal_error_t err = hal_hash_initialize(session->digest_descriptor, - &session->digest_state, NULL, 0); - if (err == HAL_ERROR_ALLOCATION_FAILURE) - lose(CKR_HOST_MEMORY); - else if (err != HAL_OK) - lose(CKR_FUNCTION_FAILED); - } - - if (!hal_check(hal_hash_update(session->digest_state, pPart, ulPartLen))) - lose(CKR_FUNCTION_FAILED); + if ((rv = digest_update(session->digest_descriptor, + &session->digest_state, + pPart, ulPartLen)) != CKR_OK) + goto fail; return mutex_unlock(p11_global_mutex); @@ -3511,10 +3585,8 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, { ENTER_PUBLIC_FUNCTION(C_Sign); - uint8_t keybuf[hal_rsa_key_t_size]; - hal_rsa_key_t *key = NULL; p11_session_t *session; - size_t signature_len; + CK_KEY_TYPE key_type; CK_RV rv; mutex_lock_or_return_failure(p11_global_mutex); @@ -3528,67 +3600,35 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, if (session->sign_key_handle == CK_INVALID_HANDLE) lose(CKR_OPERATION_NOT_INITIALIZED); - /* - * From here down this function is RSA-specific, and will need - * rewriting when we add support for other algorithms. - */ -#warning RSA-specific - - if (!p11_object_get_rsa_private_key(session->sign_key_handle, - &key, keybuf, sizeof(keybuf))) - lose(CKR_FUNCTION_FAILED); + if (session->sign_digest_state != NULL) + lose(CKR_OPERATION_ACTIVE); - /* - * Retrieve signature length. For RSA this is just the modulus - * length, other algorithms will need a more generic solution. - */ -#warning RSA-specific + if (session->sign_digest_descriptor != NULL && + (rv = digest_update(session->sign_digest_descriptor, + &session->sign_digest_state, pData, ulDataLen)) != CKR_OK) + goto fail; - if (!hal_check(hal_rsa_key_get_modulus(key, NULL, &signature_len, 0))) + if (!p11_attribute_get_ulong(session->sign_key_handle, CKA_KEY_TYPE, &key_type)) lose(CKR_FUNCTION_FAILED); - rv = signature_len > *pulSignatureLen ? CKR_BUFFER_TOO_SMALL : CKR_OK; - - *pulSignatureLen = signature_len; - - if (pSignature == NULL) { - hal_rsa_key_clear(key); - return mutex_unlock(p11_global_mutex); - } - - if (rv == CKR_BUFFER_TOO_SMALL) - lose(CKR_BUFFER_TOO_SMALL); + switch (key_type) { - if (session->sign_digest_descriptor != NULL) { - uint8_t digest_info[session->sign_digest_descriptor->digest_length + 4 + - session->sign_digest_descriptor->digest_algorithm_id_length]; - - if (!pkcs1_construct_digestinfo(session->sign_digest_descriptor, - pData, ulDataLen, digest_info, sizeof(digest_info))) - lose(CKR_FUNCTION_FAILED); - - rv = sign_rsa_pkcs(key, digest_info, sizeof(digest_info), pSignature, signature_len); - memset(digest_info, 0, sizeof(digest_info)); - if (rv != CKR_OK) - goto fail; - } + case CKK_RSA: + rv = sign_rsa_pkcs(session, pData, ulDataLen, pSignature, pulSignatureLen); + break; - else { - if ((rv = sign_rsa_pkcs(key, pData, ulDataLen, pSignature, signature_len)) != CKR_OK) - goto fail; + default: + lose(CKR_FUNCTION_FAILED); } - rv = CKR_OK; /* Fall through */ + fail: /* Fall through */ - fail: - - if (session != NULL) { + if (session != NULL && pSignature != NULL) { session->sign_key_handle = CK_INVALID_HANDLE; session->sign_digest_descriptor = NULL; + hal_hash_cleanup(&session->sign_digest_state); } - hal_rsa_key_clear(key); - mutex_unlock_return_with_rv(rv, p11_global_mutex); } @@ -3691,9 +3731,8 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, { ENTER_PUBLIC_FUNCTION(C_Verify); - uint8_t keybuf[hal_rsa_key_t_size]; - hal_rsa_key_t *key = NULL; p11_session_t *session; + CK_KEY_TYPE key_type; CK_RV rv; mutex_lock_or_return_failure(p11_global_mutex); @@ -3707,46 +3746,32 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, if (session->verify_key_handle == CK_INVALID_HANDLE) lose(CKR_OPERATION_NOT_INITIALIZED); - /* - * From here down this function is RSA-specific, and will need - * rewriting when we add support for other algorithms. - */ -#warning RSA-specific + if (session->verify_digest_descriptor != NULL && + (rv = digest_update(session->verify_digest_descriptor, + &session->verify_digest_state, pData, ulDataLen)) != CKR_OK) + goto fail; - if (!p11_object_get_rsa_public_key(session->verify_key_handle, - &key, keybuf, sizeof(keybuf))) + if (!p11_attribute_get_ulong(session->verify_key_handle, CKA_KEY_TYPE, &key_type)) lose(CKR_FUNCTION_FAILED); - if (session->verify_digest_descriptor != NULL) { - uint8_t digest_info[session->verify_digest_descriptor->digest_length + 4 + - session->verify_digest_descriptor->digest_algorithm_id_length]; + switch (key_type) { - if (!pkcs1_construct_digestinfo(session->verify_digest_descriptor, - pData, ulDataLen, digest_info, sizeof(digest_info))) - lose(CKR_FUNCTION_FAILED); - - rv = verify_rsa_pkcs(key, digest_info, sizeof(digest_info), pSignature, ulSignatureLen); - memset(digest_info, 0, sizeof(digest_info)); - if (rv != CKR_OK) - goto fail; - } + case CKK_RSA: + rv = verify_rsa_pkcs(session, pData, ulDataLen, pSignature, ulSignatureLen); + break; - else { - if ((rv = verify_rsa_pkcs(key, pData, ulDataLen, pSignature, ulSignatureLen)) != CKR_OK) - goto fail; + default: + lose(CKR_FUNCTION_FAILED); } - - rv = CKR_OK; /* Fall through */ - - fail: + + fail: /* Fall through */ if (session != NULL) { session->verify_key_handle = CK_INVALID_HANDLE; session->verify_digest_descriptor = NULL; + hal_hash_cleanup(&session->verify_digest_state); } - hal_rsa_key_clear(key); - mutex_unlock_return_with_rv(rv, p11_global_mutex); } |