diff options
Diffstat (limited to 'usr/src/lib/libkmf/libkmf/common/pk11keys.c')
-rw-r--r-- | usr/src/lib/libkmf/libkmf/common/pk11keys.c | 406 |
1 files changed, 315 insertions, 91 deletions
diff --git a/usr/src/lib/libkmf/libkmf/common/pk11keys.c b/usr/src/lib/libkmf/libkmf/common/pk11keys.c index 5a6e945009..df2cd0f8df 100644 --- a/usr/src/lib/libkmf/libkmf/common/pk11keys.c +++ b/usr/src/lib/libkmf/libkmf/common/pk11keys.c @@ -1,26 +1,91 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <kmfapiP.h> #include <sha1.h> #include <security/cryptoki.h> -#include <algorithm.h> #include <ber_der.h> #define MAX_PUBLIC_KEY_TEMPLATES (20) #define MAX_PRIVATE_KEY_TEMPLATES (24) #define MAX_SECRET_KEY_TEMPLATES (24) -static KMF_RETURN -create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech, +typedef struct +{ + KMF_ALGORITHM_INDEX kmfAlgorithmId; + CK_KEY_TYPE ckKeyType; + CK_MECHANISM_TYPE signmech; + CK_MECHANISM_TYPE vfymech; + CK_MECHANISM_TYPE hashmech; +} ALG_INFO; + +static const ALG_INFO alg_info_map[] = { + { KMF_ALGID_RSA, CKK_RSA, CKM_RSA_PKCS, CKM_RSA_PKCS, NULL}, + { KMF_ALGID_DSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA_1 }, + { KMF_ALGID_ECDSA, CKK_EC, CKM_ECDSA, CKM_ECDSA, CKM_SHA_1 }, + { KMF_ALGID_SHA1WithDSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA_1 }, + { KMF_ALGID_SHA256WithDSA, CKK_DSA, CKM_DSA, CKM_DSA, CKM_SHA256 }, + + /* + * For RSA, the verify can be done using a single mechanism, + * but signing must be done separately because not all hardware + * tokens support the combined hash+key operations. + */ + { KMF_ALGID_MD5WithRSA, CKK_RSA, CKM_RSA_PKCS, + CKM_MD5_RSA_PKCS, CKM_MD5}, + { KMF_ALGID_SHA1WithRSA, CKK_RSA, CKM_RSA_PKCS, + CKM_SHA1_RSA_PKCS, CKM_SHA_1}, + { KMF_ALGID_SHA256WithRSA, CKK_RSA, CKM_RSA_PKCS, + CKM_SHA256_RSA_PKCS, CKM_SHA256}, + { KMF_ALGID_SHA384WithRSA, CKK_RSA, CKM_RSA_PKCS, + CKM_SHA384_RSA_PKCS, CKM_SHA384}, + { KMF_ALGID_SHA512WithRSA, CKK_RSA, CKM_RSA_PKCS, + CKM_SHA512_RSA_PKCS, CKM_SHA512}, + { KMF_ALGID_SHA1WithECDSA, CKK_EC, CKM_ECDSA, + CKM_ECDSA, CKM_SHA_1}, + { KMF_ALGID_SHA256WithECDSA, CKK_EC, CKM_ECDSA, + CKM_ECDSA, CKM_SHA256}, + { KMF_ALGID_SHA384WithECDSA, CKK_EC, CKM_ECDSA, + CKM_ECDSA, CKM_SHA384}, + { KMF_ALGID_SHA512WithECDSA, CKK_EC, CKM_ECDSA, + CKM_ECDSA, CKM_SHA512} +}; + +KMF_RETURN +get_pk11_data(KMF_ALGORITHM_INDEX AlgId, + CK_KEY_TYPE *keytype, CK_MECHANISM_TYPE *signmech, + CK_MECHANISM_TYPE *hashmech, boolean_t vfy) +{ + uint32_t uIndex; + uint32_t uMapSize = + sizeof (alg_info_map) / sizeof (ALG_INFO); + + for (uIndex = 0; uIndex < uMapSize; uIndex++) { + if (alg_info_map[uIndex].kmfAlgorithmId == AlgId) { + if (keytype) + *keytype = alg_info_map[uIndex].ckKeyType; + if (hashmech) + *hashmech = alg_info_map[uIndex].hashmech; + if (signmech) + *signmech = + (vfy ? alg_info_map[uIndex].vfymech : + alg_info_map[uIndex].signmech); + return (KMF_OK); + } + } + /* no match */ + return (KMF_ERR_BAD_ALGORITHM); +} + +KMF_RETURN +kmf_create_pk11_session(CK_SESSION_HANDLE *sessionp, + CK_MECHANISM_TYPE wanted_mech, CK_FLAGS wanted_flags) { CK_RV rv; @@ -56,7 +121,8 @@ create_pk11_session(CK_SESSION_HANDLE *sessionp, CK_MECHANISM_TYPE wanted_mech, for (i = 0; i < pulCount; i++) { rv = C_GetMechanismInfo(pSlotList[i], wanted_mech, &info); - if (rv == CKR_OK && (info.flags & wanted_flags)) + if (rv == CKR_OK && + (info.flags & wanted_flags) == wanted_flags) break; } if (i < pulCount) { @@ -173,7 +239,7 @@ PKCS_CreatePublicKey( } /* Fill in the common key attributes */ - if (!pkcs_algid_to_keytype(AlgorithmId, &ckKeyType)) { + if (get_pk11_data(AlgorithmId, &ckKeyType, NULL, NULL, 0)) { goto cleanup; } if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates, @@ -210,6 +276,7 @@ PKCS_CreatePublicKey( MAX_PUBLIC_KEY_TEMPLATES, CKA_MODULUS, (CK_BYTE *)KeyParts[KMF_RSA_MODULUS].Data, (CK_ULONG)KeyParts[KMF_RSA_MODULUS].Length) || + !PKCS_AddTemplate(ckTemplate, &ckNumTemplates, MAX_PUBLIC_KEY_TEMPLATES, CKA_PUBLIC_EXPONENT, (CK_BYTE *)KeyParts[KMF_RSA_PUBLIC_EXPONENT].Data, @@ -239,6 +306,20 @@ PKCS_CreatePublicKey( goto cleanup; } break; + case CKK_EC: + if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, CKA_EC_POINT, + (CK_BYTE *)KeyParts[KMF_ECDSA_POINT].Data, + (CK_ULONG)KeyParts[KMF_ECDSA_POINT].Length) || + + !PKCS_AddTemplate(ckTemplate, &ckNumTemplates, + MAX_PUBLIC_KEY_TEMPLATES, CKA_EC_PARAMS, + (CK_BYTE *)KeyParts[KMF_ECDSA_PARAMS].Data, + (CK_ULONG)KeyParts[KMF_ECDSA_PARAMS].Length)) { + mrReturn = KMF_ERR_INTERNAL; + goto cleanup; + } + break; default: mrReturn = KMF_ERR_BAD_PARAMETER; } @@ -274,18 +355,16 @@ cleanup: * - Public Key with label: * Attempts to find a public key with the corresponding label. */ -KMF_RETURN +static KMF_RETURN PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, const KMF_X509_SPKI *pKey, CK_KEY_TYPE ckRequestedKeyType, - CK_OBJECT_HANDLE *pckKeyHandle, - KMF_BOOL *pbTemporary) + CK_OBJECT_HANDLE *pckKeyHandle) { KMF_RETURN mrReturn = KMF_OK; - /* Key searching variables */ - CK_OBJECT_HANDLE ckKeyHandle; + CK_OBJECT_HANDLE ckKeyHandle = 0; CK_OBJECT_CLASS ckObjClass; CK_KEY_TYPE ckKeyType; CK_ATTRIBUTE ckTemplate[3]; @@ -299,8 +378,6 @@ PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, if (mrReturn != KMF_OK) return (mrReturn); - *pbTemporary = KMF_TRUE; - /* Fetch the key class and algorithm from the object */ ckNumTemplates = 0; if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates, @@ -309,21 +386,20 @@ PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, !PKCS_AddTemplate(ckTemplate, &ckNumTemplates, ckMaxTemplates, CKA_KEY_TYPE, (CK_BYTE *)&ckKeyType, sizeof (ckKeyType))) { + (void) C_DestroyObject(ckSession, ckKeyHandle); return (KMF_ERR_INTERNAL); } ckRv = C_GetAttributeValue(ckSession, ckKeyHandle, ckTemplate, ckNumTemplates); if (ckRv != CKR_OK) { + (void) C_DestroyObject(ckSession, ckKeyHandle); return (ckRv); } /* Make sure the results match the expected values */ if ((ckKeyType != ckRequestedKeyType) || (ckObjClass != CKO_PUBLIC_KEY)) { - if (*pbTemporary == KMF_TRUE) { - (void) C_DestroyObject(ckSession, ckKeyHandle); - } - + (void) C_DestroyObject(ckSession, ckKeyHandle); return (KMF_ERR_BAD_KEY_FORMAT); } @@ -333,95 +409,136 @@ PKCS_AcquirePublicKeyHandle(CK_SESSION_HANDLE ckSession, return (KMF_OK); } -KMF_SIGNATURE_MODE -PKCS_GetDefaultSignatureMode(KMF_ALGORITHM_INDEX AlgId) -{ - KMF_SIGNATURE_MODE AlgMode; - - switch (AlgId) { - case KMF_ALGID_RSA: - case KMF_ALGID_MD5WithRSA: - case KMF_ALGID_MD2WithRSA: - case KMF_ALGID_SHA1WithRSA: - AlgMode = KMF_ALGMODE_PKCS1_EMSA_V15; - break; - default: - AlgMode = KMF_ALGMODE_NONE; - break; - } - - return (AlgMode); -} - +/* + * Utility routine for verifying generic data using + * the cryptographic framework (PKCS#11). + * There are situations where we want to force this + * operation to happen in a specific keystore. + * For example: + * libelfsign.so.1 verifies signatures on crypto libraries. + * We must use pkcs11 functions to verify the pkcs11 + * plugins in order to keep the validation within the + * Cryptographic Framework's FIPS-140 boundary. To avoid + * a circular dependency, pksc11_softtoken.so.1 is + * interposed by libkcfd.so.1 via kcfd, which prevents + * libpkcs11.so.1's interfaces from being used when libkmf.so.1 + * is called from kcfd. + * + * This also saves code and time because verify operations + * only use public keys and do not need acccess to any + * keystore specific functions. + */ KMF_RETURN -PKCS_VerifyData(KMF_HANDLE_T kmfh, +PKCS_VerifyData(KMF_HANDLE_T handle, KMF_ALGORITHM_INDEX AlgorithmId, KMF_X509_SPKI *keyp, KMF_DATA *data, - KMF_DATA *signed_data) + KMF_DATA *signature) { - KMF_RETURN rv = KMF_OK; - PKCS_ALGORITHM_MAP *pAlgMap = NULL; - CK_RV ckRv; - CK_MECHANISM ckMechanism; - CK_OBJECT_HANDLE ckKeyHandle; - KMF_BOOL bTempKey; + KMF_RETURN rv = KMF_OK; + CK_RV ckRv; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_MECHANISM ckMechanism; + CK_MECHANISM_TYPE mechtype, hashmech; + CK_OBJECT_HANDLE ckKeyHandle = 0; + CK_KEY_TYPE pk11keytype; CK_SESSION_HANDLE ckSession = 0; + CK_ATTRIBUTE subprime = { CKA_SUBPRIME, NULL, 0 }; + CK_BYTE *dataptr; + CK_ULONG datalen; + KMF_DATA hashData = {NULL, 0}; + uchar_t digest[1024]; if (AlgorithmId == KMF_ALGID_NONE) return (KMF_ERR_BAD_ALGORITHM); - pAlgMap = pkcs_get_alg_map(KMF_ALGCLASS_SIGNATURE, - AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId)); - - if (!pAlgMap) + if (get_pk11_data(AlgorithmId, &pk11keytype, &mechtype, &hashmech, 1)) return (KMF_ERR_BAD_ALGORITHM); - rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism, - CKF_VERIFY); - + /* + * Verify in metaslot/softtoken since only the public key is needed + * and not all hardware tokens support the combined [hash]-RSA/DSA/EC + * mechanisms. + */ + rv = kmf_create_pk11_session(&ckSession, mechtype, 0); if (rv != KMF_OK) return (rv); /* Fetch the verifying key */ rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp, - pAlgMap->key_type, &ckKeyHandle, &bTempKey); + pk11keytype, &ckKeyHandle); if (rv != KMF_OK) { (void) C_CloseSession(ckSession); return (rv); } + dataptr = data->Data; + datalen = data->Length; + /* + * For some mechanisms, we must compute the hash separately + * and then do the verify. + */ + if (hashmech != 0 && + (mechtype == CKM_ECDSA || + mechtype == CKM_DSA || + mechtype == CKM_RSA_PKCS)) { + hashData.Data = digest; + hashData.Length = sizeof (digest); + + rv = PKCS_DigestData(handle, ckSession, + hashmech, data, &hashData, + (mechtype == CKM_RSA_PKCS)); + if (rv) + goto cleanup; - ckMechanism.mechanism = pAlgMap->pkcs_mechanism; + dataptr = hashData.Data; + datalen = hashData.Length; + } + if (mechtype == CKM_DSA && + hashmech == CKM_SHA256) { + /* + * FIPS 186-3 says that when using DSA + * the hash must be truncated to the size of the + * subprime. + */ + ckRv = C_GetAttributeValue(ckSession, + ckKeyHandle, &subprime, 1); + if (ckRv != CKR_OK) { + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckRv; + rv = KMF_ERR_INTERNAL; + goto cleanup; + } + datalen = subprime.ulValueLen; + } + + ckMechanism.mechanism = mechtype; ckMechanism.pParameter = NULL; ckMechanism.ulParameterLen = 0; ckRv = C_VerifyInit(ckSession, &ckMechanism, ckKeyHandle); if (ckRv != CKR_OK) { - if (bTempKey) - (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; - (void) C_CloseSession(ckSession); - return (KMF_ERR_INTERNAL); + rv = KMF_ERR_INTERNAL; + goto cleanup; } - - ckRv = C_Verify(ckSession, (CK_BYTE *)data->Data, - (CK_ULONG)data->Length, - (CK_BYTE *)signed_data->Data, - (CK_ULONG)signed_data->Length); + ckRv = C_Verify(ckSession, + dataptr, datalen, + (CK_BYTE *)signature->Data, + (CK_ULONG)signature->Length); if (ckRv != CKR_OK) { kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; rv = KMF_ERR_INTERNAL; } - if (bTempKey) - (void) C_DestroyObject(ckSession, ckKeyHandle); +cleanup: + if (ckKeyHandle != 0) + (void) C_DestroyObject(ckSession, ckKeyHandle); (void) C_CloseSession(ckSession); return (rv); - } KMF_RETURN @@ -432,11 +549,11 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, KMF_DATA *ciphertext) { KMF_RETURN rv = KMF_OK; - PKCS_ALGORITHM_MAP *pAlgMap = NULL; CK_RV ckRv; CK_MECHANISM ckMechanism; - CK_OBJECT_HANDLE ckKeyHandle; - KMF_BOOL bTempKey; + CK_MECHANISM_TYPE mechtype; + CK_KEY_TYPE keytype; + CK_OBJECT_HANDLE ckKeyHandle = 0; CK_SESSION_HANDLE ckSession = NULL; CK_ULONG out_len = 0, in_len = 0, total_encrypted = 0; uint8_t *in_data, *out_data; @@ -446,21 +563,16 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, CK_ULONG ckMaxTemplates = (sizeof (ckTemplate) / sizeof (CK_ATTRIBUTE)); - pAlgMap = pkcs_get_alg_map(KMF_ALGCLASS_SIGNATURE, - AlgorithmId, PKCS_GetDefaultSignatureMode(AlgorithmId)); - - if (!pAlgMap) + if (get_pk11_data(AlgorithmId, &keytype, &mechtype, NULL, 0)) return (KMF_ERR_BAD_ALGORITHM); - rv = create_pk11_session(&ckSession, pAlgMap->pkcs_mechanism, - CKF_ENCRYPT); - + rv = kmf_create_pk11_session(&ckSession, mechtype, CKF_ENCRYPT); if (rv != KMF_OK) return (rv); /* Get the public key used in encryption */ rv = PKCS_AcquirePublicKeyHandle(ckSession, keyp, - pAlgMap->key_type, &ckKeyHandle, &bTempKey); + keytype, &ckKeyHandle); if (rv != KMF_OK) { (void) C_CloseSession(ckSession); @@ -471,7 +583,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, ckNumTemplates = 0; if (!PKCS_AddTemplate(ckTemplate, &ckNumTemplates, ckMaxTemplates, CKA_MODULUS, (CK_BYTE *)NULL, sizeof (CK_ULONG))) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); (void) C_CloseSession(ckSession); return (KMF_ERR_INTERNAL); @@ -481,7 +593,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, ckTemplate, ckNumTemplates); if (ckRv != CKR_OK) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; @@ -491,13 +603,13 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, out_len = ckTemplate[0].ulValueLen; if (out_len > ciphertext->Length) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); (void) C_CloseSession(ckSession); return (KMF_ERR_BUFFER_SIZE); } - ckMechanism.mechanism = pAlgMap->pkcs_mechanism; + ckMechanism.mechanism = mechtype; ckMechanism.pParameter = NULL_PTR; ckMechanism.ulParameterLen = 0; @@ -512,7 +624,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, for (i = 0; i < blocks; i++) { ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle); if (ckRv != CKR_OK) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; @@ -523,7 +635,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, (CK_BYTE_PTR)out_data, &out_len); if (ckRv != CKR_OK) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; @@ -540,7 +652,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, /* Encrypt the remaining data */ ckRv = C_EncryptInit(ckSession, &ckMechanism, ckKeyHandle); if (ckRv != CKR_OK) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; @@ -553,7 +665,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, (CK_BYTE_PTR)out_data, &out_len); if (ckRv != CKR_OK) { - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; kmfh->lasterr.errcode = ckRv; @@ -568,7 +680,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, ciphertext->Length = total_encrypted; - if (bTempKey) + if (ckKeyHandle != 0) (void) C_DestroyObject(ckSession, ckKeyHandle); (void) C_CloseSession(ckSession); @@ -577,7 +689,7 @@ PKCS_EncryptData(KMF_HANDLE_T kmfh, } static void -DigestData(KMF_DATA *IDInput, KMF_DATA *IDOutput) +create_id_hash(KMF_DATA *IDInput, KMF_DATA *IDOutput) { SHA1_CTX ctx; @@ -616,9 +728,12 @@ GetIDFromSPKI(KMF_X509_SPKI *spki, KMF_DATA *ID) /* Check the KEY algorithm */ if (algId == KMF_ALGID_RSA) { - DigestData(&KeyParts[KMF_RSA_MODULUS], ID); + create_id_hash(&KeyParts[KMF_RSA_MODULUS], ID); } else if (algId == KMF_ALGID_DSA) { - DigestData(&KeyParts[KMF_DSA_PUBLIC_VALUE], ID); + create_id_hash(&KeyParts[KMF_DSA_PUBLIC_VALUE], ID); + } else if (algId == KMF_ALGID_SHA1WithECDSA || + algId == KMF_ALGID_ECDSA) { + create_id_hash(&KeyParts[KMF_ECDSA_POINT], ID); } else { /* We only support RSA and DSA keys for now */ rv = KMF_ERR_BAD_ALGORITHM; @@ -637,3 +752,112 @@ GetIDFromSPKI(KMF_X509_SPKI *spki, KMF_DATA *ID) return (rv); } + +/* + * For PKCS1 encoding (necessary for RSA signatures), we + * must prepend the following prefixes before computing + * the digest. + */ +static uchar_t SHA1_DER_PREFIX[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 +}; +static uchar_t MD5_DER_PREFIX[] = { + 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, + 0x04, 0x10 +}; +static uchar_t SHA256_DER_PREFIX[] = {0x30, 0x31, 0x30, 0x0d, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20}; + +static uchar_t SHA384_DER_PREFIX[] = {0x30, 0x41, 0x30, 0x0d, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30}; + +static uchar_t SHA512_DER_PREFIX[] = {0x30, 0x51, 0x30, 0x0d, + 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40}; + +#define MAX_SHA2_DIGEST_LENGTH 64 +/* + * Compute hashes using metaslot (or softtoken). + * Not all hardware tokens support the combined HASH + RSA/EC + * Signing operations so it is safer to separate the hashing + * from the signing. This function generates a hash using a + * separate session. The resulting digest can be signed later. + */ +KMF_RETURN +PKCS_DigestData(KMF_HANDLE_T handle, + CK_SESSION_HANDLE hSession, + CK_MECHANISM_TYPE mechtype, + KMF_DATA *tobesigned, KMF_DATA *output, + boolean_t pkcs1_encoding) +{ + KMF_RETURN rv = KMF_OK; + CK_RV ckrv; + CK_MECHANISM mechanism; + KMF_HANDLE *kmfh = (KMF_HANDLE *)handle; + CK_BYTE outbuf[MAX_SHA2_DIGEST_LENGTH + + sizeof (SHA512_DER_PREFIX)]; + CK_ULONG outlen = sizeof (outbuf); + + mechanism.mechanism = mechtype; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + ckrv = C_DigestInit(hSession, &mechanism); + if (ckrv != CKR_OK) { + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckrv; + rv = KMF_ERR_INTERNAL; + goto end; + } + + ckrv = C_Digest(hSession, tobesigned->Data, + tobesigned->Length, outbuf, &outlen); + if (ckrv != CKR_OK) { + kmfh->lasterr.kstype = KMF_KEYSTORE_PK11TOKEN; + kmfh->lasterr.errcode = ckrv; + rv = KMF_ERR_INTERNAL; + } + + if (pkcs1_encoding) { + uchar_t *pfx; + int pfxlen; + switch (mechtype) { + case CKM_MD5: + pfx = MD5_DER_PREFIX; + pfxlen = sizeof (MD5_DER_PREFIX); + break; + case CKM_SHA_1: + pfx = SHA1_DER_PREFIX; + pfxlen = sizeof (SHA1_DER_PREFIX); + break; + case CKM_SHA256: + pfx = SHA256_DER_PREFIX; + pfxlen = sizeof (SHA256_DER_PREFIX); + break; + case CKM_SHA384: + pfx = SHA384_DER_PREFIX; + pfxlen = sizeof (SHA384_DER_PREFIX); + break; + case CKM_SHA512: + pfx = SHA512_DER_PREFIX; + pfxlen = sizeof (SHA512_DER_PREFIX); + break; + default: + rv = KMF_ERR_BAD_ALGORITHM; + goto end; + } + (void) memcpy(output->Data, pfx, pfxlen); + (void) memcpy(output->Data + pfxlen, outbuf, outlen); + output->Length = outlen + pfxlen; + } else { + (void) memcpy(output->Data, outbuf, outlen); + output->Length = outlen; + } + +end: + return (rv); +} |