diff options
author | Pramod Raghavendra Jayathirth <pramod.raghavendra.jayathirth@intel.com> | 2019-01-02 09:59:48 -0800 |
---|---|---|
committer | Pramod Raghavendra Jayathirth <pramod.raghavendra.jayathirth@intel.com> | 2019-03-29 09:59:04 -0700 |
commit | 7626b75b3c71173ba62c2f92d22bab8f4291e44a (patch) | |
tree | 7308a2628a014fef0f245ef4f00408cf92d15e60 /SoftHSMv2/src/lib/SoftHSM.cpp | |
parent | f2ff7a136a152b36b3aa4d0d574796e6edbef24a (diff) |
Update SoftHSM v2.0 to the latest version
Change-Id: Ib3ec2c297f897c82776a66fe2ad55b18984c0337
Issue-ID: AAF-687
Signed-off-by: Pramod Raghavendra Jayathirth <pramod.raghavendra.jayathirth@intel.com>
Diffstat (limited to 'SoftHSMv2/src/lib/SoftHSM.cpp')
-rw-r--r-- | SoftHSMv2/src/lib/SoftHSM.cpp | 1105 |
1 files changed, 1051 insertions, 54 deletions
diff --git a/SoftHSMv2/src/lib/SoftHSM.cpp b/SoftHSMv2/src/lib/SoftHSM.cpp index acb90a3..bdf5a90 100644 --- a/SoftHSMv2/src/lib/SoftHSM.cpp +++ b/SoftHSMv2/src/lib/SoftHSM.cpp @@ -42,6 +42,7 @@ #include "AsymmetricAlgorithm.h" #include "SymmetricAlgorithm.h" #include "AESKey.h" +#include "DerUtil.h" #include "DESKey.h" #include "RNG.h" #include "RSAParameters.h" @@ -53,6 +54,8 @@ #include "ECPublicKey.h" #include "ECPrivateKey.h" #include "ECParameters.h" +#include "EDPublicKey.h" +#include "EDPrivateKey.h" #include "DHParameters.h" #include "DHPublicKey.h" #include "DHPrivateKey.h" @@ -150,6 +153,8 @@ static CK_RV newP11Object(CK_OBJECT_CLASS objClass, CK_KEY_TYPE keyType, CK_CERT *p11object = new P11DHPublicKeyObj(); else if (keyType == CKK_GOSTR3410) *p11object = new P11GOSTPublicKeyObj(); + else if (keyType == CKK_EC_EDWARDS) + *p11object = new P11EDPublicKeyObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; @@ -165,6 +170,8 @@ static CK_RV newP11Object(CK_OBJECT_CLASS objClass, CK_KEY_TYPE keyType, CK_CERT *p11object = new P11DHPrivateKeyObj(); else if (keyType == CKK_GOSTR3410) *p11object = new P11GOSTPrivateKeyObj(); + else if (keyType == CKK_EC_EDWARDS) + *p11object = new P11EDPrivateKeyObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; @@ -338,6 +345,15 @@ static CK_ATTRIBUTE bsAttribute(CK_ATTRIBUTE_TYPE type, const ByteString &value) /***************************************************************************** Implementation of SoftHSM class specific functions *****************************************************************************/ +static void resetMutexFactoryCallbacks() +{ + // Reset MutexFactory callbacks to our versions + MutexFactory::i()->setCreateMutex(OSCreateMutex); + MutexFactory::i()->setDestroyMutex(OSDestroyMutex); + MutexFactory::i()->setLockMutex(OSLockMutex); + MutexFactory::i()->setUnlockMutex(OSUnlockMutex); +} + // Return the one-and-only instance SoftHSM* SoftHSM::i() @@ -373,10 +389,17 @@ SoftHSM::SoftHSM() SoftHSM::~SoftHSM() { if (handleManager != NULL) delete handleManager; + handleManager = NULL; if (sessionManager != NULL) delete sessionManager; + sessionManager = NULL; if (slotManager != NULL) delete slotManager; + slotManager = NULL; if (objectStore != NULL) delete objectStore; + objectStore = NULL; if (sessionObjectStore != NULL) delete sessionObjectStore; + sessionObjectStore = NULL; + + resetMutexFactoryCallbacks(); } /***************************************************************************** @@ -427,10 +450,7 @@ CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs) if (args->flags & CKF_OS_LOCKING_OK) { // Use our own mutex functions. - MutexFactory::i()->setCreateMutex(OSCreateMutex); - MutexFactory::i()->setDestroyMutex(OSDestroyMutex); - MutexFactory::i()->setLockMutex(OSLockMutex); - MutexFactory::i()->setUnlockMutex(OSUnlockMutex); + resetMutexFactoryCallbacks(); MutexFactory::i()->enable(); } else @@ -663,9 +683,12 @@ CK_RV SoftHSM::C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { // A list with the supported mechanisms - CK_ULONG nrSupportedMechanisms = 61; + CK_ULONG nrSupportedMechanisms = 62; #ifdef WITH_ECC - nrSupportedMechanisms += 3; + nrSupportedMechanisms += 2; +#endif +#if defined(WITH_ECC) || defined(WITH_EDDSA) + nrSupportedMechanisms += 1; #endif #ifdef WITH_FIPS nrSupportedMechanisms -= 9; @@ -682,6 +705,9 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech #ifdef WITH_AES_GCM nrSupportedMechanisms += 1; #endif +#ifdef WITH_EDDSA + nrSupportedMechanisms += 2; +#endif CK_MECHANISM_TYPE supportedMechanisms[] = { @@ -721,6 +747,7 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech CKM_SHA256_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512_RSA_PKCS_PSS, + CKM_GENERIC_SECRET_KEY_GEN, #ifndef WITH_FIPS CKM_DES_KEY_GEN, #endif @@ -768,6 +795,8 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech #ifdef WITH_ECC CKM_EC_KEY_PAIR_GEN, CKM_ECDSA, +#endif +#if defined(WITH_ECC) || defined(WITH_EDDSA) CKM_ECDH1_DERIVE, #endif #ifdef WITH_GOST @@ -775,7 +804,11 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech CKM_GOSTR3411_HMAC, CKM_GOSTR3410_KEY_PAIR_GEN, CKM_GOSTR3410, - CKM_GOSTR3410_WITH_GOSTR3411 + CKM_GOSTR3410_WITH_GOSTR3411, +#endif +#ifdef WITH_EDDSA + CKM_EC_EDWARDS_KEY_PAIR_GEN, + CKM_EDDSA, #endif }; @@ -820,7 +853,10 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ unsigned long dhMinSize, dhMaxSize; #ifdef WITH_ECC unsigned long ecdsaMinSize, ecdsaMaxSize; - unsigned long ecdhMinSize, ecdhMaxSize; +#endif +#if defined(WITH_ECC) || defined(WITH_EDDSA) + unsigned long ecdhMinSize = 0, ecdhMaxSize = 0; + unsigned long eddsaMinSize = 0, eddsaMaxSize = 0; #endif if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; @@ -905,6 +941,19 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); #endif +#ifdef WITH_EDDSA + AsymmetricAlgorithm* eddsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA); + if (eddsa != NULL) + { + eddsaMinSize = eddsa->getMinKeySize(); + eddsaMaxSize = eddsa->getMaxKeySize(); + } + else + { + return CKR_GENERAL_ERROR; + } + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); +#endif switch (type) { #ifndef WITH_FIPS @@ -992,6 +1041,11 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; break; + case CKM_GENERIC_SECRET_KEY_GEN: + pInfo->ulMinKeySize = 1; + pInfo->ulMaxKeySize = 0x80000000; + pInfo->flags = CKF_GENERATE; + break; #ifndef WITH_FIPS case CKM_DES_KEY_GEN: #endif @@ -1114,9 +1168,11 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ pInfo->ulMaxKeySize = ecdsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_EC_COMMOM; break; +#endif +#if defined(WITH_ECC) || defined(WITH_EDDSA) case CKM_ECDH1_DERIVE: - pInfo->ulMinKeySize = ecdhMinSize; - pInfo->ulMaxKeySize = ecdhMaxSize; + pInfo->ulMinKeySize = ecdhMinSize ? ecdhMinSize : eddsaMinSize; + pInfo->ulMaxKeySize = ecdhMaxSize ? ecdhMaxSize : eddsaMaxSize; pInfo->flags = CKF_DERIVE; break; #endif @@ -1152,6 +1208,18 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ pInfo->flags = CKF_SIGN | CKF_VERIFY; break; #endif +#ifdef WITH_EDDSA + case CKM_EC_EDWARDS_KEY_PAIR_GEN: + pInfo->ulMinKeySize = eddsaMinSize; + pInfo->ulMaxKeySize = eddsaMaxSize; + pInfo->flags = CKF_GENERATE_KEY_PAIR; + break; + case CKM_EDDSA: + pInfo->ulMinKeySize = eddsaMinSize; + pInfo->ulMaxKeySize = eddsaMaxSize; + pInfo->flags = CKF_SIGN | CKF_VERIFY; + break; +#endif default: DEBUG_MSG("The selected mechanism is not supported"); return CKR_MECHANISM_INVALID; @@ -3880,7 +3948,12 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan bool bAllowMultiPartOp; bool isRSA = false; bool isDSA = false; +#ifdef WITH_ECC bool isECDSA = false; +#endif +#ifdef WITH_EDDSA + bool isEDDSA = false; +#endif switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; @@ -4115,6 +4188,13 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan bAllowMultiPartOp = true; break; #endif +#ifdef WITH_EDDSA + case CKM_EDDSA: + mechanism = AsymMech::EDDSA; + bAllowMultiPartOp = false; + isEDDSA = true; + break; +#endif default: return CKR_MECHANISM_INVALID; } @@ -4180,6 +4260,27 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan } } #endif +#ifdef WITH_EDDSA + else if (isEDDSA) + { + asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA); + if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; + + privateKey = asymCrypto->newPrivateKey(); + if (privateKey == NULL) + { + CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); + return CKR_HOST_MEMORY; + } + + if (getEDPrivateKey((EDPrivateKey*)privateKey, token, key) != CKR_OK) + { + asymCrypto->recyclePrivateKey(privateKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); + return CKR_GENERAL_ERROR; + } + } +#endif else { #ifdef WITH_GOST @@ -5070,7 +5171,12 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech bool bAllowMultiPartOp; bool isRSA = false; bool isDSA = false; +#ifdef WITH_ECC bool isECDSA = false; +#endif +#ifdef WITH_EDDSA + bool isEDDSA = false; +#endif switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; @@ -5303,6 +5409,13 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech bAllowMultiPartOp = true; break; #endif +#ifdef WITH_EDDSA + case CKM_EDDSA: + mechanism = AsymMech::EDDSA; + bAllowMultiPartOp = false; + isEDDSA = true; + break; +#endif default: return CKR_MECHANISM_INVALID; } @@ -5368,6 +5481,27 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech } } #endif +#ifdef WITH_EDDSA + else if (isEDDSA) + { + asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA); + if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; + + publicKey = asymCrypto->newPublicKey(); + if (publicKey == NULL) + { + CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); + return CKR_HOST_MEMORY; + } + + if (getEDPublicKey((EDPublicKey*)publicKey, token, key) != CKR_OK) + { + asymCrypto->recyclePublicKey(publicKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); + return CKR_GENERAL_ERROR; + } + } +#endif else { #ifdef WITH_GOST @@ -5827,6 +5961,10 @@ CK_RV SoftHSM::C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMecha objClass = CKO_SECRET_KEY; keyType = CKK_AES; break; + case CKM_GENERIC_SECRET_KEY_GEN: + objClass = CKO_SECRET_KEY; + keyType = CKK_GENERIC_SECRET; + break; default: return CKR_MECHANISM_INVALID; } @@ -5859,6 +5997,9 @@ CK_RV SoftHSM::C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMecha if (pMechanism->mechanism == CKM_AES_KEY_GEN && (objClass != CKO_SECRET_KEY || keyType != CKK_AES)) return CKR_TEMPLATE_INCONSISTENT; + if (pMechanism->mechanism == CKM_GENERIC_SECRET_KEY_GEN && + (objClass != CKO_SECRET_KEY || keyType != CKK_GENERIC_SECRET)) + return CKR_TEMPLATE_INCONSISTENT; // Check authorization CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate); @@ -5908,6 +6049,12 @@ CK_RV SoftHSM::C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMecha return this->generateAES(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } + // Generate generic secret key + if (pMechanism->mechanism == CKM_GENERIC_SECRET_KEY_GEN) + { + return this->generateGeneric(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); + } + return CKR_GENERAL_ERROR; } @@ -5957,6 +6104,11 @@ CK_RV SoftHSM::C_GenerateKeyPair keyType = CKK_GOSTR3410; break; #endif +#ifdef WITH_EDDSA + case CKM_EC_EDWARDS_KEY_PAIR_GEN: + keyType = CKK_EC_EDWARDS; + break; +#endif default: return CKR_MECHANISM_INVALID; } @@ -5982,6 +6134,8 @@ CK_RV SoftHSM::C_GenerateKeyPair return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410) return CKR_TEMPLATE_INCONSISTENT; + if (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN && keyType != CKK_EC_EDWARDS) + return CKR_TEMPLATE_INCONSISTENT; // Extract information from the private key template that is needed to create the object. CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY; @@ -6003,6 +6157,8 @@ CK_RV SoftHSM::C_GenerateKeyPair return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410) return CKR_TEMPLATE_INCONSISTENT; + if (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN && keyType != CKK_EC_EDWARDS) + return CKR_TEMPLATE_INCONSISTENT; // Check user credentials CK_RV rv = haveWrite(session->getState(), ispublicKeyToken || isprivateKeyToken, ispublicKeyPrivate || isprivateKeyPrivate); @@ -6066,6 +6222,16 @@ CK_RV SoftHSM::C_GenerateKeyPair ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } + // Generate EDDSA keys + if (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) + { + return this->generateED(hSession, + pPublicKeyTemplate, ulPublicKeyAttributeCount, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey, + ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); + } + return CKR_GENERAL_ERROR; } @@ -6412,6 +6578,9 @@ CK_RV SoftHSM::C_WrapKey alg = AsymAlgo::ECDSA; break; #endif +#ifdef WITH_EDDSA + // Not yet +#endif #ifdef WITH_GOST case CKK_GOSTR3410: alg = AsymAlgo::GOST; @@ -6927,7 +7096,7 @@ CK_RV SoftHSM::C_DeriveKey switch (pMechanism->mechanism) { case CKM_DH_PKCS_DERIVE: -#ifdef WITH_ECC +#if defined(WITH_ECC) || defined(WITH_EDDSA) case CKM_ECDH1_DERIVE: #endif #ifndef WITH_FIPS @@ -6939,6 +7108,7 @@ CK_RV SoftHSM::C_DeriveKey case CKM_AES_ECB_ENCRYPT_DATA: case CKM_AES_CBC_ENCRYPT_DATA: break; + default: ERROR_MSG("Invalid mechanism"); return CKR_MECHANISM_INVALID; @@ -7021,17 +7191,23 @@ CK_RV SoftHSM::C_DeriveKey return this->deriveDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); } -#ifdef WITH_ECC +#if defined(WITH_ECC) || defined(WITH_EDDSA) // Derive ECDH secret if (pMechanism->mechanism == CKM_ECDH1_DERIVE) { // Check key class and type if (key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY) return CKR_KEY_TYPE_INCONSISTENT; - if (key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_EC) +#ifdef WITH_ECC + else if (key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) == CKK_EC) + return this->deriveECDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); +#endif +#ifdef WITH_EDDSA + else if (key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) == CKK_EC_EDWARDS) + return this->deriveEDDSA(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); +#endif + else return CKR_KEY_TYPE_INCONSISTENT; - - return this->deriveECDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); } #endif @@ -7152,6 +7328,177 @@ CK_RV SoftHSM::C_WaitForSlotEvent(CK_FLAGS /*flags*/, CK_SLOT_ID_PTR /*pSlot*/, return CKR_FUNCTION_NOT_SUPPORTED; } +CK_RV SoftHSM::generateGeneric +(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey, + CK_BBOOL isOnToken, + CK_BBOOL isPrivate) +{ + *phKey = CK_INVALID_HANDLE; + + // Get the session + Session* session = (Session*)handleManager->getSession(hSession); + if (session == NULL) + return CKR_SESSION_HANDLE_INVALID; + + // Get the token + Token* token = session->getToken(); + if (token == NULL) + return CKR_GENERAL_ERROR; + + // Extract desired parameter information + size_t keyLen = 0; + bool checkValue = true; + for (CK_ULONG i = 0; i < ulCount; i++) + { + switch (pTemplate[i].type) + { + case CKA_VALUE_LEN: + if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) + { + INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + keyLen = *(CK_ULONG*)pTemplate[i].pValue; + break; + case CKA_CHECK_VALUE: + if (pTemplate[i].ulValueLen > 0) + { + INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + checkValue = false; + break; + default: + break; + } + } + + // CKA_VALUE_LEN must be specified + if (keyLen == 0) + { + INFO_MSG("Missing CKA_VALUE_LEN in pTemplate"); + return CKR_TEMPLATE_INCOMPLETE; + } + + // Check keyLen + if (keyLen < 1 || keyLen > 0x8000000) + { + INFO_MSG("bad generic key length"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + // Generate the secret key + RNG* rng = CryptoFactory::i()->getRNG(); + if (rng == NULL) return CKR_GENERAL_ERROR; + ByteString key; + if (!rng->generateRandom(key, keyLen)) return CKR_GENERAL_ERROR; + + CK_RV rv = CKR_OK; + + // Create the secret key object using C_CreateObject + const CK_ULONG maxAttribs = 32; + CK_OBJECT_CLASS objClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_ATTRIBUTE keyAttribs[maxAttribs] = { + { CKA_CLASS, &objClass, sizeof(objClass) }, + { CKA_TOKEN, &isOnToken, sizeof(isOnToken) }, + { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + }; + CK_ULONG keyAttribsCount = 4; + + // Add the additional + if (ulCount > (maxAttribs - keyAttribsCount)) + rv = CKR_TEMPLATE_INCONSISTENT; + for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i) + { + switch (pTemplate[i].type) + { + case CKA_CLASS: + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_KEY_TYPE: + case CKA_CHECK_VALUE: + continue; + default: + keyAttribs[keyAttribsCount++] = pTemplate[i]; + break; + } + } + + if (rv == CKR_OK) + rv = CreateObject(hSession, keyAttribs, keyAttribsCount, phKey, OBJECT_OP_GENERATE); + + // Store the attributes that are being supplied + if (rv == CKR_OK) + { + OSObject* osobject = (OSObject*)handleManager->getObject(*phKey); + if (osobject == NULL_PTR || !osobject->isValid()) { + rv = CKR_FUNCTION_FAILED; + } else if (osobject->startTransaction()) { + bool bOK = true; + + // Common Attributes + bOK = bOK && osobject->setAttribute(CKA_LOCAL,true); + CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_GENERIC_SECRET_KEY_GEN; + bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); + + // Common Secret Key Attributes + bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false); + bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive); + bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false; + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable); + + // Generic Secret Key Attributes + ByteString value; + ByteString kcv; + SymmetricKey symKey; + symKey.setKeyBits(key); + symKey.setBitLen(keyLen); + if (isPrivate) + { + token->encrypt(symKey.getKeyBits(), value); + token->encrypt(symKey.getKeyCheckValue(), kcv); + } + else + { + value = symKey.getKeyBits(); + kcv = symKey.getKeyCheckValue(); + } + bOK = bOK && osobject->setAttribute(CKA_VALUE, value); + if (checkValue) + bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv); + + if (bOK) + bOK = osobject->commitTransaction(); + else + osobject->abortTransaction(); + + if (!bOK) + rv = CKR_FUNCTION_FAILED; + } else + rv = CKR_FUNCTION_FAILED; + } + + // Clean up + // Remove the key that may have been created already when the function fails. + if (rv != CKR_OK) + { + if (*phKey != CK_INVALID_HANDLE) + { + OSObject* oskey = (OSObject*)handleManager->getObject(*phKey); + handleManager->destroyObject(*phKey); + if (oskey) oskey->destroyObject(); + *phKey = CK_INVALID_HANDLE; + } + } + + return rv; +} + // Generate an AES secret key CK_RV SoftHSM::generateAES (CK_SESSION_HANDLE hSession, @@ -8430,10 +8777,10 @@ CK_RV SoftHSM::generateDSAParameters } bitLen = *(CK_ULONG*)pTemplate[i].pValue; break; - case CKA_SUBPRIME_BITS: + case CKA_SUB_PRIME_BITS: if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) { - INFO_MSG("CKA_SUBPRIME_BITS does not have the size of CK_ULONG"); + INFO_MSG("CKA_SUB_PRIME_BITS does not have the size of CK_ULONG"); return CKR_ATTRIBUTE_VALUE_INVALID; } qLen = *(CK_ULONG*)pTemplate[i].pValue; @@ -8450,11 +8797,11 @@ CK_RV SoftHSM::generateDSAParameters return CKR_TEMPLATE_INCOMPLETE; } - // No real choice for CKA_SUBPRIME_BITS + // No real choice for CKA_SUB_PRIME_BITS if ((qLen != 0) && (((bitLen >= 2048) && (qLen != 256)) || ((bitLen < 2048) && (qLen != 160)))) - INFO_MSG("CKA_SUBPRIME_BITS is ignored"); + INFO_MSG("CKA_SUB_PRIME_BITS is ignored"); // Generate domain parameters @@ -8814,6 +9161,252 @@ CK_RV SoftHSM::generateEC return rv; } +// Generate an EDDSA key pair +CK_RV SoftHSM::generateED +(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pPublicKeyTemplate, + CK_ULONG ulPublicKeyAttributeCount, + CK_ATTRIBUTE_PTR pPrivateKeyTemplate, + CK_ULONG ulPrivateKeyAttributeCount, + CK_OBJECT_HANDLE_PTR phPublicKey, + CK_OBJECT_HANDLE_PTR phPrivateKey, + CK_BBOOL isPublicKeyOnToken, + CK_BBOOL isPublicKeyPrivate, + CK_BBOOL isPrivateKeyOnToken, + CK_BBOOL isPrivateKeyPrivate) +{ + *phPublicKey = CK_INVALID_HANDLE; + *phPrivateKey = CK_INVALID_HANDLE; + + // Get the session + Session* session = (Session*)handleManager->getSession(hSession); + if (session == NULL) + return CKR_SESSION_HANDLE_INVALID; + + // Get the token + Token* token = session->getToken(); + if (token == NULL) + return CKR_GENERAL_ERROR; + + // Extract desired key information + ByteString params; + for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) + { + switch (pPublicKeyTemplate[i].type) + { + case CKA_EC_PARAMS: + params = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); + break; + default: + break; + } + } + + // The parameters must be specified to be able to generate a key pair. + if (params.size() == 0) { + INFO_MSG("Missing parameter(s) in pPublicKeyTemplate"); + return CKR_TEMPLATE_INCOMPLETE; + } + + // Set the parameters + ECParameters p; + p.setEC(params); + + // Generate key pair + AsymmetricKeyPair* kp = NULL; + AsymmetricAlgorithm* ec = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA); + if (ec == NULL) return CKR_GENERAL_ERROR; + if (!ec->generateKeyPair(&kp, &p)) + { + ERROR_MSG("Could not generate key pair"); + CryptoFactory::i()->recycleAsymmetricAlgorithm(ec); + return CKR_GENERAL_ERROR; + } + + EDPublicKey* pub = (EDPublicKey*) kp->getPublicKey(); + EDPrivateKey* priv = (EDPrivateKey*) kp->getPrivateKey(); + + CK_RV rv = CKR_OK; + + // Create a public key using C_CreateObject + if (rv == CKR_OK) + { + const CK_ULONG maxAttribs = 32; + CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE publicKeyType = CKK_EC_EDWARDS; + CK_ATTRIBUTE publicKeyAttribs[maxAttribs] = { + { CKA_CLASS, &publicKeyClass, sizeof(publicKeyClass) }, + { CKA_TOKEN, &isPublicKeyOnToken, sizeof(isPublicKeyOnToken) }, + { CKA_PRIVATE, &isPublicKeyPrivate, sizeof(isPublicKeyPrivate) }, + { CKA_KEY_TYPE, &publicKeyType, sizeof(publicKeyType) }, + }; + CK_ULONG publicKeyAttribsCount = 4; + + // Add the additional + if (ulPublicKeyAttributeCount > (maxAttribs - publicKeyAttribsCount)) + rv = CKR_TEMPLATE_INCONSISTENT; + for (CK_ULONG i=0; i < ulPublicKeyAttributeCount && rv == CKR_OK; ++i) + { + switch (pPublicKeyTemplate[i].type) + { + case CKA_CLASS: + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_KEY_TYPE: + continue; + default: + publicKeyAttribs[publicKeyAttribsCount++] = pPublicKeyTemplate[i]; + } + } + + if (rv == CKR_OK) + rv = this->CreateObject(hSession,publicKeyAttribs,publicKeyAttribsCount,phPublicKey,OBJECT_OP_GENERATE); + + // Store the attributes that are being supplied by the key generation to the object + if (rv == CKR_OK) + { + OSObject* osobject = (OSObject*)handleManager->getObject(*phPublicKey); + if (osobject == NULL_PTR || !osobject->isValid()) { + rv = CKR_FUNCTION_FAILED; + } else if (osobject->startTransaction()) { + bool bOK = true; + + // Common Key Attributes + bOK = bOK && osobject->setAttribute(CKA_LOCAL,true); + CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_EDWARDS_KEY_PAIR_GEN; + bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); + + // EDDSA Public Key Attributes + ByteString value; + if (isPublicKeyPrivate) + { + token->encrypt(pub->getA(), value); + } + else + { + value = pub->getA(); + } + bOK = bOK && osobject->setAttribute(CKA_EC_POINT, value); + + if (bOK) + bOK = osobject->commitTransaction(); + else + osobject->abortTransaction(); + + if (!bOK) + rv = CKR_FUNCTION_FAILED; + } else + rv = CKR_FUNCTION_FAILED; + } + } + + // Create a private key using C_CreateObject + if (rv == CKR_OK) + { + const CK_ULONG maxAttribs = 32; + CK_OBJECT_CLASS privateKeyClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE privateKeyType = CKK_EC_EDWARDS; + CK_ATTRIBUTE privateKeyAttribs[maxAttribs] = { + { CKA_CLASS, &privateKeyClass, sizeof(privateKeyClass) }, + { CKA_TOKEN, &isPrivateKeyOnToken, sizeof(isPrivateKeyOnToken) }, + { CKA_PRIVATE, &isPrivateKeyPrivate, sizeof(isPrivateKeyPrivate) }, + { CKA_KEY_TYPE, &privateKeyType, sizeof(privateKeyType) }, + }; + CK_ULONG privateKeyAttribsCount = 4; + if (ulPrivateKeyAttributeCount > (maxAttribs - privateKeyAttribsCount)) + rv = CKR_TEMPLATE_INCONSISTENT; + for (CK_ULONG i=0; i < ulPrivateKeyAttributeCount && rv == CKR_OK; ++i) + { + switch (pPrivateKeyTemplate[i].type) + { + case CKA_CLASS: + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_KEY_TYPE: + continue; + default: + privateKeyAttribs[privateKeyAttribsCount++] = pPrivateKeyTemplate[i]; + } + } + + if (rv == CKR_OK) + rv = this->CreateObject(hSession,privateKeyAttribs,privateKeyAttribsCount,phPrivateKey,OBJECT_OP_GENERATE); + + // Store the attributes that are being supplied by the key generation to the object + if (rv == CKR_OK) + { + OSObject* osobject = (OSObject*)handleManager->getObject(*phPrivateKey); + if (osobject == NULL_PTR || !osobject->isValid()) { + rv = CKR_FUNCTION_FAILED; + } else if (osobject->startTransaction()) { + bool bOK = true; + + // Common Key Attributes + bOK = bOK && osobject->setAttribute(CKA_LOCAL,true); + CK_ULONG ulKeyGenMechanism = (CK_ULONG)CKM_EC_EDWARDS_KEY_PAIR_GEN; + bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); + + // Common Private Key Attributes + bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false); + bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive); + bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false; + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, bNeverExtractable); + + // EDDSA Private Key Attributes + ByteString group; + ByteString value; + if (isPrivateKeyPrivate) + { + token->encrypt(priv->getEC(), group); + token->encrypt(priv->getK(), value); + } + else + { + group = priv->getEC(); + value = priv->getK(); + } + bOK = bOK && osobject->setAttribute(CKA_EC_PARAMS, group); + bOK = bOK && osobject->setAttribute(CKA_VALUE, value); + + if (bOK) + bOK = osobject->commitTransaction(); + else + osobject->abortTransaction(); + + if (!bOK) + rv = CKR_FUNCTION_FAILED; + } else + rv = CKR_FUNCTION_FAILED; + } + } + + // Clean up + ec->recycleKeyPair(kp); + CryptoFactory::i()->recycleAsymmetricAlgorithm(ec); + + // Remove keys that may have been created already when the function fails. + if (rv != CKR_OK) + { + if (*phPrivateKey != CK_INVALID_HANDLE) + { + OSObject* ospriv = (OSObject*)handleManager->getObject(*phPrivateKey); + handleManager->destroyObject(*phPrivateKey); + if (ospriv) ospriv->destroyObject(); + *phPrivateKey = CK_INVALID_HANDLE; + } + + if (*phPublicKey != CK_INVALID_HANDLE) + { + OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey); + handleManager->destroyObject(*phPublicKey); + if (ospub) ospub->destroyObject(); + *phPublicKey = CK_INVALID_HANDLE; + } + } + + return rv; +} + // Generate a DH key pair CK_RV SoftHSM::generateDH (CK_SESSION_HANDLE hSession, @@ -9820,6 +10413,7 @@ CK_RV SoftHSM::deriveDH } // Derive an ECDH secret +#ifdef WITH_ECC CK_RV SoftHSM::deriveECDH (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, @@ -9831,7 +10425,6 @@ CK_RV SoftHSM::deriveECDH CK_BBOOL isOnToken, CK_BBOOL isPrivate) { -#ifdef WITH_ECC *phKey = CK_INVALID_HANDLE; if ((pMechanism->pParameter == NULL_PTR) || @@ -10170,10 +10763,362 @@ CK_RV SoftHSM::deriveECDH } return rv; -#else - return CKR_MECHANISM_INVALID; +} +#endif + +// Derive an ECDH secret using Montgomery curves +#ifdef WITH_EDDSA +CK_RV SoftHSM::deriveEDDSA +(CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + CK_OBJECT_HANDLE hBaseKey, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phKey, + CK_KEY_TYPE keyType, + CK_BBOOL isOnToken, + CK_BBOOL isPrivate) +{ + *phKey = CK_INVALID_HANDLE; + + if ((pMechanism->pParameter == NULL_PTR) || + (pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS))) + { + DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS"); + return CKR_MECHANISM_PARAM_INVALID; + } + if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL) + { + DEBUG_MSG("kdf must be CKD_NULL"); + return CKR_MECHANISM_PARAM_INVALID; + } + if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) || + (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR)) + { + DEBUG_MSG("there must be no shared data"); + return CKR_MECHANISM_PARAM_INVALID; + } + if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) || + (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR)) + { + DEBUG_MSG("there must be a public data"); + return CKR_MECHANISM_PARAM_INVALID; + } + + // Get the session + Session* session = (Session*)handleManager->getSession(hSession); + if (session == NULL) + return CKR_SESSION_HANDLE_INVALID; + + // Get the token + Token* token = session->getToken(); + if (token == NULL) + return CKR_GENERAL_ERROR; + + // Extract desired parameter information + size_t byteLen = 0; + bool checkValue = true; + for (CK_ULONG i = 0; i < ulCount; i++) + { + switch (pTemplate[i].type) + { + case CKA_VALUE: + INFO_MSG("CKA_VALUE must not be included"); + return CKR_ATTRIBUTE_READ_ONLY; + case CKA_VALUE_LEN: + if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) + { + INFO_MSG("CKA_VALUE_LEN does not have the size of CK_ULONG"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + byteLen = *(CK_ULONG*)pTemplate[i].pValue; + break; + case CKA_CHECK_VALUE: + if (pTemplate[i].ulValueLen > 0) + { + INFO_MSG("CKA_CHECK_VALUE must be a no-value (0 length) entry"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + checkValue = false; + break; + default: + break; + } + } + + // Check the length + // byteLen == 0 impiles return max size the ECC can derive + switch (keyType) + { + case CKK_GENERIC_SECRET: + break; +#ifndef WITH_FIPS + case CKK_DES: + if (byteLen != 0 && byteLen != 8) + { + INFO_MSG("CKA_VALUE_LEN must be 0 or 8"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + byteLen = 8; + break; #endif + case CKK_DES2: + if (byteLen != 0 && byteLen != 16) + { + INFO_MSG("CKA_VALUE_LEN must be 0 or 16"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + byteLen = 16; + break; + case CKK_DES3: + if (byteLen != 0 && byteLen != 24) + { + INFO_MSG("CKA_VALUE_LEN must be 0 or 24"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + byteLen = 24; + break; + case CKK_AES: + if (byteLen != 0 && byteLen != 16 && byteLen != 24 && byteLen != 32) + { + INFO_MSG("CKA_VALUE_LEN must be 0, 16, 24, or 32"); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + break; + default: + return CKR_ATTRIBUTE_VALUE_INVALID; + } + + // Get the base key handle + OSObject *baseKey = (OSObject *)handleManager->getObject(hBaseKey); + if (baseKey == NULL || !baseKey->isValid()) + return CKR_KEY_HANDLE_INVALID; + + // Get the EDDSA algorithm handler + AsymmetricAlgorithm* eddsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA); + if (eddsa == NULL) + return CKR_MECHANISM_INVALID; + + // Get the keys + PrivateKey* privateKey = eddsa->newPrivateKey(); + if (privateKey == NULL) + { + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); + return CKR_HOST_MEMORY; + } + if (getEDPrivateKey((EDPrivateKey*)privateKey, token, baseKey) != CKR_OK) + { + eddsa->recyclePrivateKey(privateKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); + return CKR_GENERAL_ERROR; + } + + ByteString publicData; + publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen); + memcpy(&publicData[0], + CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData, + CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen); + PublicKey* publicKey = eddsa->newPublicKey(); + if (publicKey == NULL) + { + eddsa->recyclePrivateKey(privateKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); + return CKR_HOST_MEMORY; + } + if (getEDDHPublicKey((EDPublicKey*)publicKey, (EDPrivateKey*)privateKey, publicData) != CKR_OK) + { + eddsa->recyclePrivateKey(privateKey); + eddsa->recyclePublicKey(publicKey); + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); + return CKR_GENERAL_ERROR; + } + + // Derive the secret + SymmetricKey* secret = NULL; + CK_RV rv = CKR_OK; + if (!eddsa->deriveKey(&secret, publicKey, privateKey)) + rv = CKR_GENERAL_ERROR; + eddsa->recyclePrivateKey(privateKey); + eddsa->recyclePublicKey(publicKey); + + // Create the secret object using C_CreateObject + const CK_ULONG maxAttribs = 32; + CK_OBJECT_CLASS objClass = CKO_SECRET_KEY; + CK_ATTRIBUTE secretAttribs[maxAttribs] = { + { CKA_CLASS, &objClass, sizeof(objClass) }, + { CKA_TOKEN, &isOnToken, sizeof(isOnToken) }, + { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + }; + CK_ULONG secretAttribsCount = 4; + + // Add the additional + if (ulCount > (maxAttribs - secretAttribsCount)) + rv = CKR_TEMPLATE_INCONSISTENT; + for (CK_ULONG i=0; i < ulCount && rv == CKR_OK; ++i) + { + switch (pTemplate[i].type) + { + case CKA_CLASS: + case CKA_TOKEN: + case CKA_PRIVATE: + case CKA_KEY_TYPE: + case CKA_CHECK_VALUE: + continue; + default: + secretAttribs[secretAttribsCount++] = pTemplate[i]; + } + } + + if (rv == CKR_OK) + rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, phKey, OBJECT_OP_DERIVE); + + // Store the attributes that are being supplied + if (rv == CKR_OK) + { + OSObject* osobject = (OSObject*)handleManager->getObject(*phKey); + if (osobject == NULL_PTR || !osobject->isValid()) { + rv = CKR_FUNCTION_FAILED; + } else if (osobject->startTransaction()) { + bool bOK = true; + + // Common Attributes + bOK = bOK && osobject->setAttribute(CKA_LOCAL,false); + + // Common Secret Key Attributes + if (baseKey->getBooleanValue(CKA_ALWAYS_SENSITIVE, false)) + { + bool bAlwaysSensitive = osobject->getBooleanValue(CKA_SENSITIVE, false); + bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,bAlwaysSensitive); + } + else + { + bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE,false); + } + if (baseKey->getBooleanValue(CKA_NEVER_EXTRACTABLE, true)) + { + bool bNeverExtractable = osobject->getBooleanValue(CKA_EXTRACTABLE, false) == false; + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,bNeverExtractable); + } + else + { + bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE,false); + } + + // Secret Attributes + ByteString secretValue = secret->getKeyBits(); + ByteString value; + ByteString plainKCV; + ByteString kcv; + + // For generic and AES keys: + // default to return max size available. + if (byteLen == 0) + { + switch (keyType) + { + case CKK_GENERIC_SECRET: + byteLen = secretValue.size(); + break; + case CKK_AES: + if (secretValue.size() >= 32) + byteLen = 32; + else if (secretValue.size() >= 24) + byteLen = 24; + else + byteLen = 16; + } + } + + if (byteLen > secretValue.size()) + { + INFO_MSG("The derived secret is too short"); + bOK = false; + } + else + { + // Truncate value when requested, remove from the leading end + if (byteLen < secretValue.size()) + secretValue.split(secretValue.size() - byteLen); + + // Fix the odd parity for DES + if (keyType == CKK_DES || + keyType == CKK_DES2 || + keyType == CKK_DES3) + { + for (size_t i = 0; i < secretValue.size(); i++) + { + secretValue[i] = odd_parity[secretValue[i]]; + } + } + + // Get the KCV + switch (keyType) + { + case CKK_GENERIC_SECRET: + secret->setBitLen(byteLen * 8); + plainKCV = secret->getKeyCheckValue(); + break; + case CKK_DES: + case CKK_DES2: + case CKK_DES3: + secret->setBitLen(byteLen * 7); + plainKCV = ((DESKey*)secret)->getKeyCheckValue(); + break; + case CKK_AES: + secret->setBitLen(byteLen * 8); + plainKCV = ((AESKey*)secret)->getKeyCheckValue(); + break; + default: + bOK = false; + break; + } + + if (isPrivate) + { + token->encrypt(secretValue, value); + token->encrypt(plainKCV, kcv); + } + else + { + value = secretValue; + kcv = plainKCV; + } + } + bOK = bOK && osobject->setAttribute(CKA_VALUE, value); + if (checkValue) + bOK = bOK && osobject->setAttribute(CKA_CHECK_VALUE, kcv); + + if (bOK) + bOK = osobject->commitTransaction(); + else + osobject->abortTransaction(); + + if (!bOK) + rv = CKR_FUNCTION_FAILED; + } else + rv = CKR_FUNCTION_FAILED; + } + + // Clean up + eddsa->recycleSymmetricKey(secret); + CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa); + + // Remove secret that may have been created already when the function fails. + if (rv != CKR_OK) + { + if (*phKey != CK_INVALID_HANDLE) + { + OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey); + handleManager->destroyObject(*phKey); + if (ossecret) ossecret->destroyObject(); + *phKey = CK_INVALID_HANDLE; + } + } + + return rv; } +#endif // Derive an symmetric secret CK_RV SoftHSM::deriveSymmetric @@ -10994,6 +11939,70 @@ CK_RV SoftHSM::getECPublicKey(ECPublicKey* publicKey, Token* token, OSObject* ke return CKR_OK; } +CK_RV SoftHSM::getEDPrivateKey(EDPrivateKey* privateKey, Token* token, OSObject* key) +{ + if (privateKey == NULL) return CKR_ARGUMENTS_BAD; + if (token == NULL) return CKR_ARGUMENTS_BAD; + if (key == NULL) return CKR_ARGUMENTS_BAD; + + // Get the CKA_PRIVATE attribute, when the attribute is not present use default false + bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false); + + // EDDSA Private Key Attributes + ByteString group; + ByteString value; + if (isKeyPrivate) + { + bool bOK = true; + bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_PARAMS), group); + bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value); + if (!bOK) + return CKR_GENERAL_ERROR; + } + else + { + group = key->getByteStringValue(CKA_EC_PARAMS); + value = key->getByteStringValue(CKA_VALUE); + } + + privateKey->setEC(group); + privateKey->setK(value); + + return CKR_OK; +} + +CK_RV SoftHSM::getEDPublicKey(EDPublicKey* publicKey, Token* token, OSObject* key) +{ + if (publicKey == NULL) return CKR_ARGUMENTS_BAD; + if (token == NULL) return CKR_ARGUMENTS_BAD; + if (key == NULL) return CKR_ARGUMENTS_BAD; + + // Get the CKA_PRIVATE attribute, when the attribute is not present use default false + bool isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, false); + + // EC Public Key Attributes + ByteString group; + ByteString value; + if (isKeyPrivate) + { + bool bOK = true; + bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_PARAMS), group); + bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_POINT), value); + if (!bOK) + return CKR_GENERAL_ERROR; + } + else + { + group = key->getByteStringValue(CKA_EC_PARAMS); + value = key->getByteStringValue(CKA_EC_POINT); + } + + publicKey->setEC(group); + publicKey->setA(value); + + return CKR_OK; +} + CK_RV SoftHSM::getDHPrivateKey(DHPrivateKey* privateKey, Token* token, OSObject* key) { if (privateKey == NULL) return CKR_ARGUMENTS_BAD; @@ -11060,15 +12069,32 @@ CK_RV SoftHSM::getECDHPublicKey(ECPublicKey* publicKey, ECPrivateKey* privateKey return CKR_OK; } +CK_RV SoftHSM::getEDDHPublicKey(EDPublicKey* publicKey, EDPrivateKey* privateKey, ByteString& pubData) +{ + if (publicKey == NULL) return CKR_ARGUMENTS_BAD; + if (privateKey == NULL) return CKR_ARGUMENTS_BAD; + + // Copy Domain Parameters from Private Key + publicKey->setEC(privateKey->getEC()); + + // Set value + ByteString data = getECDHPubData(pubData); + publicKey->setA(data); + + return CKR_OK; +} + // ECDH pubData can be in RAW or DER format. // Need to convert RAW as SoftHSM uses DER. ByteString SoftHSM::getECDHPubData(ByteString& pubData) { size_t len = pubData.size(); size_t controlOctets = 2; - if (len == 65 || len == 97 || len == 133) + if (len == 32 || len == 65 || len == 97 || len == 133) { - // Raw: Length matches the public key size of P-256, P-384, or P-521 + // Raw: Length matches the public key size of: + // EDDSA: X25519 + // ECDSA: P-256, P-384, or P-521 controlOctets = 0; } else if (len < controlOctets || pubData[0] != 0x04) @@ -11106,36 +12132,7 @@ ByteString SoftHSM::getECDHPubData(ByteString& pubData) // DER format if (controlOctets != 0) return pubData; - // RAW format - ByteString header; - if (len < 0x80) - { - header.resize(2); - header[0] = (unsigned char)0x04; - header[1] = (unsigned char)(len & 0x7F); - } - else - { - // Count significate bytes - size_t bytes = sizeof(size_t); - for(; bytes > 0; bytes--) - { - size_t value = len >> ((bytes - 1) * 8); - if (value & 0xFF) break; - } - - // Set header data - header.resize(2 + bytes); - header[0] = (unsigned char)0x04; - header[1] = (unsigned char)(0x80 | bytes); - for (size_t i = 1; i <= bytes; i++) - { - header[2+bytes-i] = (unsigned char) (len & 0xFF); - len >>= 8; - } - } - - return header + pubData; + return DERUTIL::raw2Octet(pubData); } CK_RV SoftHSM::getGOSTPrivateKey(GOSTPrivateKey* privateKey, Token* token, OSObject* key) |