aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/lib/SoftHSM.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/lib/SoftHSM.cpp')
-rw-r--r--SoftHSMv2/src/lib/SoftHSM.cpp1105
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)