Skip to content

Commit 5c8d939

Browse files
AearsisOndřej Hlavatý
authored and
Ondřej Hlavatý
committed
Implement key derivation functions for CKM_ECDH1_DERIVE
Signed-off-by: Ondřej Hlavatý <[email protected]>
1 parent a181dae commit 5c8d939

File tree

1 file changed

+166
-32
lines changed

1 file changed

+166
-32
lines changed

src/lib/SoftHSM.cpp

+166-32
Original file line numberDiff line numberDiff line change
@@ -10607,29 +10607,52 @@ CK_RV SoftHSM::deriveECDH
1060710607
CK_BBOOL isPrivate)
1060810608
{
1060910609
*phKey = CK_INVALID_HANDLE;
10610+
HashAlgorithm* kdfAlgorithm = NULL;
1061010611

1061110612
if ((pMechanism->pParameter == NULL_PTR) ||
1061210613
(pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)))
1061310614
{
1061410615
DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS");
1061510616
return CKR_MECHANISM_PARAM_INVALID;
1061610617
}
10617-
if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL)
10618-
{
10619-
DEBUG_MSG("kdf must be CKD_NULL");
10620-
return CKR_MECHANISM_PARAM_INVALID;
10621-
}
10622-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) ||
10623-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR))
10618+
10619+
CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter);
10620+
10621+
if ((ecdhParams->ulPublicDataLen == 0) ||
10622+
(ecdhParams->pPublicData == NULL_PTR))
1062410623
{
10625-
DEBUG_MSG("there must be no shared data");
10624+
DEBUG_MSG("there must be a public data");
1062610625
return CKR_MECHANISM_PARAM_INVALID;
1062710626
}
10628-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) ||
10629-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR))
10627+
10628+
switch (ecdhParams->kdf)
1063010629
{
10631-
DEBUG_MSG("there must be a public data");
10632-
return CKR_MECHANISM_PARAM_INVALID;
10630+
case CKD_NULL:
10631+
if ((ecdhParams->ulSharedDataLen != 0) ||
10632+
(ecdhParams->pSharedData != NULL_PTR))
10633+
{
10634+
DEBUG_MSG("there must be no shared data when KDF is CKD_NULL");
10635+
return CKR_MECHANISM_PARAM_INVALID;
10636+
}
10637+
break;
10638+
case CKD_SHA1_KDF:
10639+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
10640+
break;
10641+
case CKD_SHA224_KDF:
10642+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224);
10643+
break;
10644+
case CKD_SHA256_KDF:
10645+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
10646+
break;
10647+
case CKD_SHA384_KDF:
10648+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
10649+
break;
10650+
case CKD_SHA512_KDF:
10651+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512);
10652+
break;
10653+
default:
10654+
DEBUG_MSG("Unknown KDF");
10655+
return CKR_MECHANISM_PARAM_INVALID;
1063310656
}
1063410657

1063510658
// Get the session
@@ -10678,6 +10701,14 @@ CK_RV SoftHSM::deriveECDH
1067810701
switch (keyType)
1067910702
{
1068010703
case CKK_GENERIC_SECRET:
10704+
if (kdfAlgorithm != NULL) {
10705+
const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32);
10706+
if (byteLen > maxLen)
10707+
{
10708+
INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen);
10709+
return CKR_ATTRIBUTE_VALUE_INVALID;
10710+
}
10711+
}
1068110712
break;
1068210713
#ifndef WITH_FIPS
1068310714
case CKK_DES:
@@ -10741,10 +10772,8 @@ CK_RV SoftHSM::deriveECDH
1074110772
}
1074210773

1074310774
ByteString publicData;
10744-
publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10745-
memcpy(&publicData[0],
10746-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
10747-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10775+
publicData.resize(ecdhParams->ulPublicDataLen);
10776+
memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen);
1074810777
PublicKey* publicKey = ecdh->newPublicKey();
1074910778
if (publicKey == NULL)
1075010779
{
@@ -10768,6 +10797,44 @@ CK_RV SoftHSM::deriveECDH
1076810797
ecdh->recyclePrivateKey(privateKey);
1076910798
ecdh->recyclePublicKey(publicKey);
1077010799

10800+
// Apply key derivation function (ANSI X9.63)
10801+
if (rv == CKR_OK && kdfAlgorithm != NULL) {
10802+
const ByteString& secretBits = secret->getKeyBits();
10803+
const size_t counterOffset = secretBits.size();
10804+
unsigned long counter = 1;
10805+
10806+
ByteString hashInput;
10807+
hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen);
10808+
10809+
// Prepare hash input content - derived secret, 4 bytes for counter, shared data
10810+
memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size());
10811+
memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen);
10812+
10813+
ByteString hashOutput;
10814+
ByteString derivedOutput;
10815+
10816+
while (derivedOutput.size() < byteLen) {
10817+
hashInput[counterOffset + 0] = (counter >> 48) & 0xFF;
10818+
hashInput[counterOffset + 1] = (counter >> 32) & 0xFF;
10819+
hashInput[counterOffset + 2] = (counter >> 16) & 0xFF;
10820+
hashInput[counterOffset + 3] = (counter >> 0) & 0xFF;
10821+
10822+
kdfAlgorithm->hashInit();
10823+
kdfAlgorithm->hashUpdate(hashInput);
10824+
kdfAlgorithm->hashFinal(hashOutput);
10825+
10826+
derivedOutput += hashOutput;
10827+
counter++;
10828+
}
10829+
10830+
// Trim to desired length
10831+
derivedOutput.resize(byteLen);
10832+
10833+
secret->setBitLen(byteLen * 8);
10834+
if (!secret->setKeyBits(derivedOutput))
10835+
rv = CKR_FUNCTION_FAILED;
10836+
}
10837+
1077110838
// Create the secret object using C_CreateObject
1077210839
const CK_ULONG maxAttribs = 32;
1077310840
CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
@@ -10961,29 +11028,52 @@ CK_RV SoftHSM::deriveEDDSA
1096111028
CK_BBOOL isPrivate)
1096211029
{
1096311030
*phKey = CK_INVALID_HANDLE;
11031+
HashAlgorithm* kdfAlgorithm = NULL;
1096411032

1096511033
if ((pMechanism->pParameter == NULL_PTR) ||
1096611034
(pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)))
1096711035
{
1096811036
DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS");
1096911037
return CKR_MECHANISM_PARAM_INVALID;
1097011038
}
10971-
if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL)
10972-
{
10973-
DEBUG_MSG("kdf must be CKD_NULL");
10974-
return CKR_MECHANISM_PARAM_INVALID;
10975-
}
10976-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) ||
10977-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR))
11039+
11040+
CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter);
11041+
11042+
if ((ecdhParams->ulPublicDataLen == 0) ||
11043+
(ecdhParams->pPublicData == NULL_PTR))
1097811044
{
10979-
DEBUG_MSG("there must be no shared data");
11045+
DEBUG_MSG("there must be a public data");
1098011046
return CKR_MECHANISM_PARAM_INVALID;
1098111047
}
10982-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) ||
10983-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR))
11048+
11049+
switch (ecdhParams->kdf)
1098411050
{
10985-
DEBUG_MSG("there must be a public data");
10986-
return CKR_MECHANISM_PARAM_INVALID;
11051+
case CKD_NULL:
11052+
if ((ecdhParams->ulSharedDataLen != 0) ||
11053+
(ecdhParams->pSharedData != NULL_PTR))
11054+
{
11055+
DEBUG_MSG("there must be no shared data when KDF is CKD_NULL");
11056+
return CKR_MECHANISM_PARAM_INVALID;
11057+
}
11058+
break;
11059+
case CKD_SHA1_KDF:
11060+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
11061+
break;
11062+
case CKD_SHA224_KDF:
11063+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224);
11064+
break;
11065+
case CKD_SHA256_KDF:
11066+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
11067+
break;
11068+
case CKD_SHA384_KDF:
11069+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
11070+
break;
11071+
case CKD_SHA512_KDF:
11072+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512);
11073+
break;
11074+
default:
11075+
DEBUG_MSG("Unknown KDF");
11076+
return CKR_MECHANISM_PARAM_INVALID;
1098711077
}
1098811078

1098911079
// Get the session
@@ -11032,6 +11122,14 @@ CK_RV SoftHSM::deriveEDDSA
1103211122
switch (keyType)
1103311123
{
1103411124
case CKK_GENERIC_SECRET:
11125+
if (kdfAlgorithm != NULL) {
11126+
const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32);
11127+
if (byteLen > maxLen)
11128+
{
11129+
INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen);
11130+
return CKR_ATTRIBUTE_VALUE_INVALID;
11131+
}
11132+
}
1103511133
break;
1103611134
#ifndef WITH_FIPS
1103711135
case CKK_DES:
@@ -11095,10 +11193,8 @@ CK_RV SoftHSM::deriveEDDSA
1109511193
}
1109611194

1109711195
ByteString publicData;
11098-
publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
11099-
memcpy(&publicData[0],
11100-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
11101-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
11196+
publicData.resize(ecdhParams->ulPublicDataLen);
11197+
memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen);
1110211198
PublicKey* publicKey = eddsa->newPublicKey();
1110311199
if (publicKey == NULL)
1110411200
{
@@ -11122,6 +11218,44 @@ CK_RV SoftHSM::deriveEDDSA
1112211218
eddsa->recyclePrivateKey(privateKey);
1112311219
eddsa->recyclePublicKey(publicKey);
1112411220

11221+
// Apply key derivation function (ANSI X9.63)
11222+
if (rv == CKR_OK && kdfAlgorithm != NULL) {
11223+
const ByteString& secretBits = secret->getKeyBits();
11224+
const size_t counterOffset = secretBits.size();
11225+
unsigned long counter = 1;
11226+
11227+
ByteString hashInput;
11228+
hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen);
11229+
11230+
// Prepare hash input content - derived secret, 4 bytes for counter, shared data
11231+
memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size());
11232+
memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen);
11233+
11234+
ByteString hashOutput;
11235+
ByteString derivedOutput;
11236+
11237+
while (derivedOutput.size() < byteLen) {
11238+
hashInput[counterOffset + 0] = (counter >> 48) & 0xFF;
11239+
hashInput[counterOffset + 1] = (counter >> 32) & 0xFF;
11240+
hashInput[counterOffset + 2] = (counter >> 16) & 0xFF;
11241+
hashInput[counterOffset + 3] = (counter >> 0) & 0xFF;
11242+
11243+
kdfAlgorithm->hashInit();
11244+
kdfAlgorithm->hashUpdate(hashInput);
11245+
kdfAlgorithm->hashFinal(hashOutput);
11246+
11247+
derivedOutput += hashOutput;
11248+
counter++;
11249+
}
11250+
11251+
// Trim to desired length
11252+
derivedOutput.resize(byteLen);
11253+
11254+
secret->setBitLen(byteLen * 8);
11255+
if (!secret->setKeyBits(derivedOutput))
11256+
rv = CKR_FUNCTION_FAILED;
11257+
}
11258+
1112511259
// Create the secret object using C_CreateObject
1112611260
const CK_ULONG maxAttribs = 32;
1112711261
CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;

0 commit comments

Comments
 (0)