Skip to content

Commit b8895b5

Browse files
committed
Implement key derivation functions for CKM_ECDH1_DERIVE
Signed-off-by: Ondřej Hlavatý <[email protected]>
1 parent 8f5e4e4 commit b8895b5

File tree

1 file changed

+166
-32
lines changed

1 file changed

+166
-32
lines changed

src/lib/SoftHSM.cpp

Lines changed: 166 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10343,29 +10343,52 @@ CK_RV SoftHSM::deriveECDH
1034310343
CK_BBOOL isPrivate)
1034410344
{
1034510345
*phKey = CK_INVALID_HANDLE;
10346+
HashAlgorithm* kdfAlgorithm = NULL;
1034610347

1034710348
if ((pMechanism->pParameter == NULL_PTR) ||
1034810349
(pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)))
1034910350
{
1035010351
DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS");
1035110352
return CKR_MECHANISM_PARAM_INVALID;
1035210353
}
10353-
if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL)
10354-
{
10355-
DEBUG_MSG("kdf must be CKD_NULL");
10356-
return CKR_MECHANISM_PARAM_INVALID;
10357-
}
10358-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) ||
10359-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR))
10354+
10355+
CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter);
10356+
10357+
if ((ecdhParams->ulPublicDataLen == 0) ||
10358+
(ecdhParams->pPublicData == NULL_PTR))
1036010359
{
10361-
DEBUG_MSG("there must be no shared data");
10360+
DEBUG_MSG("there must be a public data");
1036210361
return CKR_MECHANISM_PARAM_INVALID;
1036310362
}
10364-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) ||
10365-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR))
10363+
10364+
switch (ecdhParams->kdf)
1036610365
{
10367-
DEBUG_MSG("there must be a public data");
10368-
return CKR_MECHANISM_PARAM_INVALID;
10366+
case CKD_NULL:
10367+
if ((ecdhParams->ulSharedDataLen != 0) ||
10368+
(ecdhParams->pSharedData != NULL_PTR))
10369+
{
10370+
DEBUG_MSG("there must be no shared data when KDF is CKD_NULL");
10371+
return CKR_MECHANISM_PARAM_INVALID;
10372+
}
10373+
break;
10374+
case CKD_SHA1_KDF:
10375+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
10376+
break;
10377+
case CKD_SHA224_KDF:
10378+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224);
10379+
break;
10380+
case CKD_SHA256_KDF:
10381+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
10382+
break;
10383+
case CKD_SHA384_KDF:
10384+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
10385+
break;
10386+
case CKD_SHA512_KDF:
10387+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512);
10388+
break;
10389+
default:
10390+
DEBUG_MSG("Unknown KDF");
10391+
return CKR_MECHANISM_PARAM_INVALID;
1036910392
}
1037010393

1037110394
// Get the session
@@ -10414,6 +10437,14 @@ CK_RV SoftHSM::deriveECDH
1041410437
switch (keyType)
1041510438
{
1041610439
case CKK_GENERIC_SECRET:
10440+
if (kdfAlgorithm != NULL) {
10441+
const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32);
10442+
if (byteLen > maxLen)
10443+
{
10444+
INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen);
10445+
return CKR_ATTRIBUTE_VALUE_INVALID;
10446+
}
10447+
}
1041710448
break;
1041810449
#ifndef WITH_FIPS
1041910450
case CKK_DES:
@@ -10477,10 +10508,8 @@ CK_RV SoftHSM::deriveECDH
1047710508
}
1047810509

1047910510
ByteString publicData;
10480-
publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10481-
memcpy(&publicData[0],
10482-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
10483-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10511+
publicData.resize(ecdhParams->ulPublicDataLen);
10512+
memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen);
1048410513
PublicKey* publicKey = ecdh->newPublicKey();
1048510514
if (publicKey == NULL)
1048610515
{
@@ -10504,6 +10533,44 @@ CK_RV SoftHSM::deriveECDH
1050410533
ecdh->recyclePrivateKey(privateKey);
1050510534
ecdh->recyclePublicKey(publicKey);
1050610535

10536+
// Apply key derivation function (ANSI X9.63)
10537+
if (rv == CKR_OK && kdfAlgorithm != NULL) {
10538+
const ByteString& secretBits = secret->getKeyBits();
10539+
const size_t counterOffset = secretBits.size();
10540+
unsigned long counter = 1;
10541+
10542+
ByteString hashInput;
10543+
hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen);
10544+
10545+
// Prepare hash input content - derived secret, 4 bytes for counter, shared data
10546+
memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size());
10547+
memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen);
10548+
10549+
ByteString hashOutput;
10550+
ByteString derivedOutput;
10551+
10552+
while (derivedOutput.size() < byteLen) {
10553+
hashInput[counterOffset + 0] = (counter >> 48) & 0xFF;
10554+
hashInput[counterOffset + 1] = (counter >> 32) & 0xFF;
10555+
hashInput[counterOffset + 2] = (counter >> 16) & 0xFF;
10556+
hashInput[counterOffset + 3] = (counter >> 0) & 0xFF;
10557+
10558+
kdfAlgorithm->hashInit();
10559+
kdfAlgorithm->hashUpdate(hashInput);
10560+
kdfAlgorithm->hashFinal(hashOutput);
10561+
10562+
derivedOutput += hashOutput;
10563+
counter++;
10564+
}
10565+
10566+
// Trim to desired length
10567+
derivedOutput.resize(byteLen);
10568+
10569+
secret->setBitLen(byteLen * 8);
10570+
if (!secret->setKeyBits(derivedOutput))
10571+
rv = CKR_FUNCTION_FAILED;
10572+
}
10573+
1050710574
// Create the secret object using C_CreateObject
1050810575
const CK_ULONG maxAttribs = 32;
1050910576
CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
@@ -10697,29 +10764,52 @@ CK_RV SoftHSM::deriveEDDSA
1069710764
CK_BBOOL isPrivate)
1069810765
{
1069910766
*phKey = CK_INVALID_HANDLE;
10767+
HashAlgorithm* kdfAlgorithm = NULL;
1070010768

1070110769
if ((pMechanism->pParameter == NULL_PTR) ||
1070210770
(pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)))
1070310771
{
1070410772
DEBUG_MSG("pParameter must be of type CK_ECDH1_DERIVE_PARAMS");
1070510773
return CKR_MECHANISM_PARAM_INVALID;
1070610774
}
10707-
if (CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->kdf != CKD_NULL)
10708-
{
10709-
DEBUG_MSG("kdf must be CKD_NULL");
10710-
return CKR_MECHANISM_PARAM_INVALID;
10711-
}
10712-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulSharedDataLen != 0) ||
10713-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pSharedData != NULL_PTR))
10775+
10776+
CK_ECDH1_DERIVE_PARAMS_PTR ecdhParams = CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter);
10777+
10778+
if ((ecdhParams->ulPublicDataLen == 0) ||
10779+
(ecdhParams->pPublicData == NULL_PTR))
1071410780
{
10715-
DEBUG_MSG("there must be no shared data");
10781+
DEBUG_MSG("there must be a public data");
1071610782
return CKR_MECHANISM_PARAM_INVALID;
1071710783
}
10718-
if ((CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen == 0) ||
10719-
(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData == NULL_PTR))
10784+
10785+
switch (ecdhParams->kdf)
1072010786
{
10721-
DEBUG_MSG("there must be a public data");
10722-
return CKR_MECHANISM_PARAM_INVALID;
10787+
case CKD_NULL:
10788+
if ((ecdhParams->ulSharedDataLen != 0) ||
10789+
(ecdhParams->pSharedData != NULL_PTR))
10790+
{
10791+
DEBUG_MSG("there must be no shared data when KDF is CKD_NULL");
10792+
return CKR_MECHANISM_PARAM_INVALID;
10793+
}
10794+
break;
10795+
case CKD_SHA1_KDF:
10796+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA1);
10797+
break;
10798+
case CKD_SHA224_KDF:
10799+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA224);
10800+
break;
10801+
case CKD_SHA256_KDF:
10802+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
10803+
break;
10804+
case CKD_SHA384_KDF:
10805+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA384);
10806+
break;
10807+
case CKD_SHA512_KDF:
10808+
kdfAlgorithm = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA512);
10809+
break;
10810+
default:
10811+
DEBUG_MSG("Unknown KDF");
10812+
return CKR_MECHANISM_PARAM_INVALID;
1072310813
}
1072410814

1072510815
// Get the session
@@ -10768,6 +10858,14 @@ CK_RV SoftHSM::deriveEDDSA
1076810858
switch (keyType)
1076910859
{
1077010860
case CKK_GENERIC_SECRET:
10861+
if (kdfAlgorithm != NULL) {
10862+
const size_t maxLen = kdfAlgorithm->getHashSize() * (1UL << 32);
10863+
if (byteLen > maxLen)
10864+
{
10865+
INFO_MSG("CKA_VALUE_LEN must be at most %zu", maxLen);
10866+
return CKR_ATTRIBUTE_VALUE_INVALID;
10867+
}
10868+
}
1077110869
break;
1077210870
#ifndef WITH_FIPS
1077310871
case CKK_DES:
@@ -10831,10 +10929,8 @@ CK_RV SoftHSM::deriveEDDSA
1083110929
}
1083210930

1083310931
ByteString publicData;
10834-
publicData.resize(CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10835-
memcpy(&publicData[0],
10836-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
10837-
CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
10932+
publicData.resize(ecdhParams->ulPublicDataLen);
10933+
memcpy(&publicData[0], ecdhParams->pPublicData, ecdhParams->ulPublicDataLen);
1083810934
PublicKey* publicKey = eddsa->newPublicKey();
1083910935
if (publicKey == NULL)
1084010936
{
@@ -10858,6 +10954,44 @@ CK_RV SoftHSM::deriveEDDSA
1085810954
eddsa->recyclePrivateKey(privateKey);
1085910955
eddsa->recyclePublicKey(publicKey);
1086010956

10957+
// Apply key derivation function (ANSI X9.63)
10958+
if (rv == CKR_OK && kdfAlgorithm != NULL) {
10959+
const ByteString& secretBits = secret->getKeyBits();
10960+
const size_t counterOffset = secretBits.size();
10961+
unsigned long counter = 1;
10962+
10963+
ByteString hashInput;
10964+
hashInput.resize(secretBits.size() + 4 + ecdhParams->ulSharedDataLen);
10965+
10966+
// Prepare hash input content - derived secret, 4 bytes for counter, shared data
10967+
memcpy(&hashInput[0], secretBits.const_byte_str(), secretBits.size());
10968+
memcpy(&hashInput[secretBits.size() + 4], ecdhParams->pSharedData, ecdhParams->ulSharedDataLen);
10969+
10970+
ByteString hashOutput;
10971+
ByteString derivedOutput;
10972+
10973+
while (derivedOutput.size() < byteLen) {
10974+
hashInput[counterOffset + 0] = (counter >> 48) & 0xFF;
10975+
hashInput[counterOffset + 1] = (counter >> 32) & 0xFF;
10976+
hashInput[counterOffset + 2] = (counter >> 16) & 0xFF;
10977+
hashInput[counterOffset + 3] = (counter >> 0) & 0xFF;
10978+
10979+
kdfAlgorithm->hashInit();
10980+
kdfAlgorithm->hashUpdate(hashInput);
10981+
kdfAlgorithm->hashFinal(hashOutput);
10982+
10983+
derivedOutput += hashOutput;
10984+
counter++;
10985+
}
10986+
10987+
// Trim to desired length
10988+
derivedOutput.resize(byteLen);
10989+
10990+
secret->setBitLen(byteLen * 8);
10991+
if (!secret->setKeyBits(derivedOutput))
10992+
rv = CKR_FUNCTION_FAILED;
10993+
}
10994+
1086110995
// Create the secret object using C_CreateObject
1086210996
const CK_ULONG maxAttribs = 32;
1086310997
CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;

0 commit comments

Comments
 (0)