From 6a80ee51ba03fd8958c566882922ddb4df39c7cd Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Wed, 9 Sep 2015 17:21:47 -0400 Subject: Add ECDSA signature and verification. Compiles, not tested. --- pkcs11.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/pkcs11.c b/pkcs11.c index 646d15f..6a83127 100644 --- a/pkcs11.c +++ b/pkcs11.c @@ -2322,7 +2322,7 @@ CK_RV verify_rsa_pkcs(p11_session_t *session, lose(CKR_FUNCTION_FAILED); pData = digest_info; - ulSignatureLen = sizeof(digest_info); + ulDataLen = sizeof(digest_info); } @@ -2345,6 +2345,120 @@ CK_RV verify_rsa_pkcs(p11_session_t *session, return rv; } +#warning May need to do something about truncating oversized hashes for ECDSA, see PKCS11 spec + +/* + * Generate an ECDSA signature. + */ + +static CK_RV sign_ecdsa(p11_session_t *session, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG_PTR pulSignatureLen) +{ + uint8_t keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *key = NULL; + hal_ecdsa_curve_t curve; + size_t signature_len; + CK_RV rv; + + assert(session != NULL && pulSignatureLen != NULL); + + const hal_hash_descriptor_t * const desc = session->sign_digest_descriptor; + const size_t digest_len = desc == NULL ? 1 : desc->digest_length; + uint8_t digest[digest_len]; + + if (!p11_object_get_ec_private_key(session->sign_key_handle, &key, keybuf, sizeof(keybuf))) + lose(CKR_FUNCTION_FAILED); + + /* + * Signature length is determined by curve parameters. + */ + + if (!hal_check(hal_ecdsa_key_get_curve(key, &curve))) + lose(CKR_FUNCTION_FAILED); + + switch (curve) { + case HAL_ECDSA_CURVE_P256: signature_len = 256; break; + case HAL_ECDSA_CURVE_P384: signature_len = 384; break; + case HAL_ECDSA_CURVE_P521: signature_len = 521; break; + default: lose(CKR_FUNCTION_FAILED); + } + + signature_len = ((signature_len + 7) / 8) * 2; + + 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 (!hal_check(hal_hash_finalize(session->sign_digest_state, digest, sizeof(digest)))) + lose(CKR_FUNCTION_FAILED); + + pData = digest; + ulDataLen = sizeof(digest); + } + + if (pSignature != NULL && !hal_check(hal_ecdsa_sign(key, pData, ulDataLen, + pSignature, pulSignatureLen, *pulSignatureLen, + HAL_ECDSA_SIGNATURE_FORMAT_PKCS11))) + lose(CKR_FUNCTION_FAILED); + + rv = CKR_OK; /* Fall through */ + + fail: + hal_ecdsa_key_clear(key); + return rv; +} + +/* + * Verify an ECDSA signature. + */ + +static CK_RV verify_ecdsa(p11_session_t *session, + CK_BYTE_PTR pData, + CK_ULONG ulDataLen, + CK_BYTE_PTR pSignature, + CK_ULONG ulSignatureLen) +{ + uint8_t keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *key = NULL; + CK_RV rv; + + assert(session != NULL && pSignature != NULL); + + const hal_hash_descriptor_t * const desc = session->verify_digest_descriptor; + const size_t digest_len = desc == NULL ? 1 : desc->digest_length; + uint8_t digest[digest_len]; + + if (!p11_object_get_ec_public_key(session->verify_key_handle, &key, keybuf, sizeof(keybuf))) + lose(CKR_FUNCTION_FAILED); + + if (session->verify_digest_descriptor != NULL) { + + if (!hal_check(hal_hash_finalize(session->verify_digest_state, digest, sizeof(digest)))) + lose(CKR_FUNCTION_FAILED); + + pData = digest; + ulDataLen = sizeof(digest); + + } + + if (!hal_check(hal_ecdsa_verify(key, pData, ulDataLen, pSignature, ulSignatureLen, HAL_ECDSA_SIGNATURE_FORMAT_PKCS11))) + lose(CKR_SIGNATURE_INVALID); + + rv = CKR_OK; /* Fall through */ + + fail: + hal_ecdsa_key_clear(key); + return rv; +} + /* @@ -3617,6 +3731,10 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession, rv = sign_rsa_pkcs(session, pData, ulDataLen, pSignature, pulSignatureLen); break; + case CKK_EC: + rv = sign_ecdsa(session, pData, ulDataLen, pSignature, pulSignatureLen); + break; + default: lose(CKR_FUNCTION_FAILED); } @@ -3760,6 +3878,10 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, rv = verify_rsa_pkcs(session, pData, ulDataLen, pSignature, ulSignatureLen); break; + case CKK_EC: + rv = verify_ecdsa(session, pData, ulDataLen, pSignature, ulSignatureLen); + break; + default: lose(CKR_FUNCTION_FAILED); } -- cgit v1.2.3