diff --git a/src/lib/SoftHSM.cpp b/src/lib/SoftHSM.cpp index 54f9089f2..bc235d524 100644 --- a/src/lib/SoftHSM.cpp +++ b/src/lib/SoftHSM.cpp @@ -10607,6 +10607,7 @@ CK_RV SoftHSM::deriveECDH CK_BBOOL isPrivate) { *phKey = CK_INVALID_HANDLE; + HashAlgorithm* kdfAlgorithm = NULL; if ((pMechanism->pParameter == NULL_PTR) || (pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS))) @@ -10614,22 +10615,44 @@ CK_RV SoftHSM::deriveECDH 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)) + + CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter); + + if ((ecdhParams->ulPublicDataLen == 0) || + (ecdhParams->pPublicData == NULL_PTR)) { - DEBUG_MSG("there must be no shared data"); + DEBUG_MSG("there must be a public 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)) + + switch (ecdhParams->kdf) { - DEBUG_MSG("there must be a public data"); - return CKR_MECHANISM_PARAM_INVALID; + case CKD_NULL: + if ((ecdhParams->ulSharedDataLen != 0) || + (ecdhParams->pSharedData != NULL_PTR)) + { + DEBUG_MSG("there must be no shared data when KDF is CKD_NULL"); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKD_SHA1_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1); + break; + case CKD_SHA224_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224); + break; + case CKD_SHA256_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256); + break; + case CKD_SHA384_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384); + break; + case CKD_SHA512_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512); + break; + default: + DEBUG_MSG("Unknown KDF"); + return CKR_MECHANISM_PARAM_INVALID; } // Get the session @@ -10678,6 +10701,14 @@ CK_RV SoftHSM::deriveECDH switch (keyType) { case CKK_GENERIC_SECRET: + if (kdfAlgorithm != NULL) { + const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32); + if (byteLen > maxLen) + { + INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } break; #ifndef WITH_FIPS case CKK_DES: @@ -10741,10 +10772,8 @@ CK_RV SoftHSM::deriveECDH } 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); + publicData.resize(ecdhParams->ulPublicDataLen); + memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen); PublicKey* publicKey = ecdh->newPublicKey(); if (publicKey == NULL) { @@ -10768,6 +10797,44 @@ CK_RV SoftHSM::deriveECDH ecdh->recyclePrivateKey(privateKey); ecdh->recyclePublicKey(publicKey); + // Apply key derivation function (ANSI X9.63) + if (rv == CKR_OK && kdfAlgorithm != NULL) { + const ByteString& secretBits = secret->getKeyBits(); + const size_t counterOffset = secretBits.size(); + unsigned long counter = 1; + + ByteString hashInput; + hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen); + + // Prepare hash input content - derived secret, 4 bytes for counter, shared data + memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size()); + memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen); + + ByteString hashOutput; + ByteString derivedOutput; + + while (derivedOutput.size() < byteLen) { + hashInput[counterOffset + 0] = (counter >> 48) & 0xFF; + hashInput[counterOffset + 1] = (counter >> 32) & 0xFF; + hashInput[counterOffset + 2] = (counter >> 16) & 0xFF; + hashInput[counterOffset + 3] = (counter >> 0) & 0xFF; + + kdfAlgorithm->hashInit(); + kdfAlgorithm->hashUpdate(hashInput); + kdfAlgorithm->hashFinal(hashOutput); + + derivedOutput += hashOutput; + counter++; + } + + // Trim to desired length + derivedOutput.resize(byteLen); + + secret->setBitLen(byteLen * 8); + if (!secret->setKeyBits(derivedOutput)) + rv = CKR_FUNCTION_FAILED; + } + // Create the secret object using C_CreateObject const CK_ULONG maxAttribs = 32; CK_OBJECT_CLASS objClass = CKO_SECRET_KEY; @@ -10961,6 +11028,7 @@ CK_RV SoftHSM::deriveEDDSA CK_BBOOL isPrivate) { *phKey = CK_INVALID_HANDLE; + HashAlgorithm* kdfAlgorithm = NULL; if ((pMechanism->pParameter == NULL_PTR) || (pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS))) @@ -10968,22 +11036,44 @@ CK_RV SoftHSM::deriveEDDSA 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)) + + CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter); + + if ((ecdhParams->ulPublicDataLen == 0) || + (ecdhParams->pPublicData == NULL_PTR)) { - DEBUG_MSG("there must be no shared data"); + DEBUG_MSG("there must be a public 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)) + + switch (ecdhParams->kdf) { - DEBUG_MSG("there must be a public data"); - return CKR_MECHANISM_PARAM_INVALID; + case CKD_NULL: + if ((ecdhParams->ulSharedDataLen != 0) || + (ecdhParams->pSharedData != NULL_PTR)) + { + DEBUG_MSG("there must be no shared data when KDF is CKD_NULL"); + return CKR_MECHANISM_PARAM_INVALID; + } + break; + case CKD_SHA1_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1); + break; + case CKD_SHA224_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224); + break; + case CKD_SHA256_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256); + break; + case CKD_SHA384_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384); + break; + case CKD_SHA512_KDF: + kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512); + break; + default: + DEBUG_MSG("Unknown KDF"); + return CKR_MECHANISM_PARAM_INVALID; } // Get the session @@ -11032,6 +11122,14 @@ CK_RV SoftHSM::deriveEDDSA switch (keyType) { case CKK_GENERIC_SECRET: + if (kdfAlgorithm != NULL) { + const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32); + if (byteLen > maxLen) + { + INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + } break; #ifndef WITH_FIPS case CKK_DES: @@ -11095,10 +11193,8 @@ CK_RV SoftHSM::deriveEDDSA } 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); + publicData.resize(ecdhParams->ulPublicDataLen); + memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen); PublicKey* publicKey = eddsa->newPublicKey(); if (publicKey == NULL) { @@ -11122,6 +11218,44 @@ CK_RV SoftHSM::deriveEDDSA eddsa->recyclePrivateKey(privateKey); eddsa->recyclePublicKey(publicKey); + // Apply key derivation function (ANSI X9.63) + if (rv == CKR_OK && kdfAlgorithm != NULL) { + const ByteString& secretBits = secret->getKeyBits(); + const size_t counterOffset = secretBits.size(); + unsigned long counter = 1; + + ByteString hashInput; + hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen); + + // Prepare hash input content - derived secret, 4 bytes for counter, shared data + memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size()); + memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen); + + ByteString hashOutput; + ByteString derivedOutput; + + while (derivedOutput.size() < byteLen) { + hashInput[counterOffset + 0] = (counter >> 48) & 0xFF; + hashInput[counterOffset + 1] = (counter >> 32) & 0xFF; + hashInput[counterOffset + 2] = (counter >> 16) & 0xFF; + hashInput[counterOffset + 3] = (counter >> 0) & 0xFF; + + kdfAlgorithm->hashInit(); + kdfAlgorithm->hashUpdate(hashInput); + kdfAlgorithm->hashFinal(hashOutput); + + derivedOutput += hashOutput; + counter++; + } + + // Trim to desired length + derivedOutput.resize(byteLen); + + secret->setBitLen(byteLen * 8); + if (!secret->setKeyBits(derivedOutput)) + rv = CKR_FUNCTION_FAILED; + } + // Create the secret object using C_CreateObject const CK_ULONG maxAttribs = 32; CK_OBJECT_CLASS objClass = CKO_SECRET_KEY; diff --git a/src/lib/test/DeriveTests.cpp b/src/lib/test/DeriveTests.cpp index 9438ac230..0a5ab25d3 100644 --- a/src/lib/test/DeriveTests.cpp +++ b/src/lib/test/DeriveTests.cpp @@ -328,7 +328,7 @@ void DeriveTests::dhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicK } #if defined(WITH_ECC) || defined(WITH_EDDSA) -void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw) +void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw, ck_ec_kdf_t kdf, bool useSharedData, CK_ULONG secLen = 32) { CK_ATTRIBUTE valAttrib = { CKA_EC_POINT, NULL_PTR, 0 }; CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); @@ -337,7 +337,7 @@ void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPubli rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSession, hPublicKey, &valAttrib, 1) ); CPPUNIT_ASSERT(rv == CKR_OK); - CK_ECDH1_DERIVE_PARAMS parms = { CKD_NULL, 0, NULL_PTR, 0, NULL_PTR }; + CK_ECDH1_DERIVE_PARAMS parms = { kdf, 0, NULL_PTR, 0, NULL_PTR }; // Use RAW or DER format if (useRaw) { @@ -366,6 +366,12 @@ void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPubli parms.ulPublicDataLen = valAttrib.ulValueLen; } + if (useSharedData) + { + parms.pSharedData = (unsigned char *) "TEST"; + parms.ulSharedDataLen = 4; + } + CK_MECHANISM mechanism = { CKM_ECDH1_DERIVE, NULL, 0 }; mechanism.pParameter = &parms; mechanism.ulParameterLen = sizeof(parms); @@ -373,7 +379,6 @@ void DeriveTests::ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPubli CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_BBOOL bFalse = CK_FALSE; CK_BBOOL bTrue = CK_TRUE; - CK_ULONG secLen = 32; CK_ATTRIBUTE keyAttribs[] = { { CKA_CLASS, &keyClass, sizeof(keyClass) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, @@ -536,9 +541,9 @@ void DeriveTests::testEcdsaDerive() rv = generateEcKeyPair("P-256",hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); CK_OBJECT_HANDLE hKey1 = CK_INVALID_HANDLE; - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); CK_OBJECT_HANDLE hKey2 = CK_INVALID_HANDLE; - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Private Session Keys @@ -546,8 +551,8 @@ void DeriveTests::testEcdsaDerive() CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEcKeyPair("P-384",hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Public Token Keys @@ -555,8 +560,8 @@ void DeriveTests::testEcdsaDerive() CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEcKeyPair("P-521",hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Private Token Keys @@ -564,9 +569,48 @@ void DeriveTests::testEcdsaDerive() CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEcKeyPair("P-256",hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); + + CK_OBJECT_HANDLE hKey3 = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey4 = CK_INVALID_HANDLE; + + CK_ATTRIBUTE keyAttribs[] = { + { CKA_VALUE, NULL_PTR, 0 }, + }; + CK_BYTE val1[48]; + CK_BYTE val2[48]; + + // KDF's + for (ck_ec_kdf_t kdf : { CKD_SHA1_KDF, CKD_SHA224_KDF, CKD_SHA256_KDF, CKD_SHA384_KDF, CKD_SHA512_KDF }) + { + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,kdf,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,kdf,false); + CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); + + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey3,true,kdf,true); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey4,false,kdf,true); + CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey3,hKey4)); + + CPPUNIT_ASSERT(!compareSecret(hSessionRW,hKey1,hKey3)); + + // ANSI X9.63 KDF's derive arbitrarily long sequences of bytes, short are prefixes of longer + + keyAttribs[0].pValue = val1; + keyAttribs[0].ulValueLen = sizeof(val1); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,kdf,false,24); + CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRW, hKey1, keyAttribs, 1) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + keyAttribs[0].pValue = val2; + keyAttribs[0].ulValueLen = sizeof(val2); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,kdf,false,48); + rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRW, hKey2, keyAttribs, 1) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + CPPUNIT_ASSERT(memcmp(val1, val2, 24) == 0); + } } #endif @@ -616,9 +660,9 @@ void DeriveTests::testEddsaDerive(const char* alg) rv = generateEdKeyPair(alg,hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); CK_OBJECT_HANDLE hKey1 = CK_INVALID_HANDLE; - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); CK_OBJECT_HANDLE hKey2 = CK_INVALID_HANDLE; - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Private Session Keys @@ -626,8 +670,8 @@ void DeriveTests::testEddsaDerive(const char* alg) CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEdKeyPair(alg,hSessionRW,IN_SESSION,IS_PRIVATE,IN_SESSION,IS_PRIVATE,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Public Token Keys @@ -635,8 +679,8 @@ void DeriveTests::testEddsaDerive(const char* alg) CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEdKeyPair(alg,hSessionRW,ON_TOKEN,IS_PUBLIC,ON_TOKEN,IS_PUBLIC,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); // Private Token Keys @@ -644,9 +688,48 @@ void DeriveTests::testEddsaDerive(const char* alg) CPPUNIT_ASSERT(rv == CKR_OK); rv = generateEdKeyPair(alg,hSessionRW,ON_TOKEN,IS_PRIVATE,ON_TOKEN,IS_PRIVATE,hPuk2,hPrk2); CPPUNIT_ASSERT(rv == CKR_OK); - ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true); - ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,CKD_NULL,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,CKD_NULL,false); CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); + + CK_OBJECT_HANDLE hKey3 = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE hKey4 = CK_INVALID_HANDLE; + + CK_ATTRIBUTE keyAttribs[] = { + { CKA_VALUE, NULL_PTR, 0 }, + }; + CK_BYTE val1[48]; + CK_BYTE val2[48]; + + // KDF's + for (ck_ec_kdf_t kdf : { CKD_SHA1_KDF, CKD_SHA224_KDF, CKD_SHA256_KDF, CKD_SHA384_KDF, CKD_SHA512_KDF }) + { + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,kdf,false); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,kdf,false); + CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey1,hKey2)); + + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey3,true,kdf,true); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey4,false,kdf,true); + CPPUNIT_ASSERT(compareSecret(hSessionRW,hKey3,hKey4)); + + CPPUNIT_ASSERT(!compareSecret(hSessionRW,hKey1,hKey3)); + + // ANSI X9.63 KDF's derive arbitrarily long sequences of bytes, short are prefixes of longer + + keyAttribs[0].pValue = val1; + keyAttribs[0].ulValueLen = sizeof(val1); + ecdhDerive(hSessionRW,hPuk1,hPrk2,hKey1,true,kdf,false,24); + CK_RV rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRW, hKey1, keyAttribs, 1) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + keyAttribs[0].pValue = val2; + keyAttribs[0].ulValueLen = sizeof(val2); + ecdhDerive(hSessionRW,hPuk2,hPrk1,hKey2,false,kdf,false,48); + rv = CRYPTOKI_F_PTR( C_GetAttributeValue(hSessionRW, hKey2, keyAttribs, 1) ); + CPPUNIT_ASSERT(rv == CKR_OK); + + CPPUNIT_ASSERT(memcmp(val1, val2, 24) == 0); + } } #endif diff --git a/src/lib/test/DeriveTests.h b/src/lib/test/DeriveTests.h index 2514d30fb..4497a7899 100644 --- a/src/lib/test/DeriveTests.h +++ b/src/lib/test/DeriveTests.h @@ -75,7 +75,7 @@ class DeriveTests : public TestsBase CK_RV generateEcKeyPair(const char* curve, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk); #endif #if defined(WITH_ECC) || defined(WITH_EDDSA) - void ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw); + void ecdhDerive(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_OBJECT_HANDLE &hKey, bool useRaw, ck_ec_kdf_t kdf, bool useSharedData, CK_ULONG secLen); #endif #ifdef WITH_EDDSA CK_RV generateEdKeyPair(const char* alg, CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk);