Update SoftHSM v2.0 to the latest version
[aaf/sshsm.git] / SoftHSMv2 / src / lib / SoftHSM.cpp
index acb90a3..bdf5a90 100644 (file)
@@ -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
@@ -1151,6 +1207,18 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_
                        pInfo->ulMaxKeySize = 0;
                        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");
@@ -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;
@@ -4114,6 +4187,13 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan
                        mechanism = AsymMech::GOST_GOST;
                        bAllowMultiPartOp = true;
                        break;
+#endif
+#ifdef WITH_EDDSA
+               case CKM_EDDSA:
+                       mechanism = AsymMech::EDDSA;
+                       bAllowMultiPartOp = false;
+                       isEDDSA = true;
+                       break;
 #endif
                default:
                        return CKR_MECHANISM_INVALID;
@@ -4179,6 +4259,27 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan
                        return CKR_GENERAL_ERROR;
                }
        }
+#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
        {
@@ -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;
@@ -5302,6 +5408,13 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
                        mechanism = AsymMech::GOST_GOST;
                        bAllowMultiPartOp = true;
                        break;
+#endif
+#ifdef WITH_EDDSA
+               case CKM_EDDSA:
+                       mechanism = AsymMech::EDDSA;
+                       bAllowMultiPartOp = false;
+                       isEDDSA = true;
+                       break;
 #endif
                default:
                        return CKR_MECHANISM_INVALID;
@@ -5367,6 +5480,27 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech
                        return CKR_GENERAL_ERROR;
                }
        }
+#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
        {
@@ -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;
 }
 
@@ -5956,6 +6103,11 @@ CK_RV SoftHSM::C_GenerateKeyPair
                case CKM_GOSTR3410_KEY_PAIR_GEN:
                        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,
@@ -9482,31 +10075,346 @@ CK_RV SoftHSM::generateGOST
        gost->recycleKeyPair(kp);
        CryptoFactory::i()->recycleAsymmetricAlgorithm(gost);
 
-       // Remove keys that may have been created already when the function fails.
+       // 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;
+}
+
+// Derive a DH secret
+CK_RV SoftHSM::deriveDH
+(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) return CKR_MECHANISM_PARAM_INVALID;
+       if (pMechanism->ulParameterLen == 0) 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
+       switch (keyType)
+       {
+               case CKK_GENERIC_SECRET:
+                       if (byteLen == 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be set");
+                               return CKR_TEMPLATE_INCOMPLETE;
+                       }
+                       break;
+#ifndef WITH_FIPS
+               case CKK_DES:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 8;
+                       break;
+#endif
+               case CKK_DES2:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 16;
+                       break;
+               case CKK_DES3:
+                       if (byteLen != 0)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must not be set");
+                               return CKR_ATTRIBUTE_READ_ONLY;
+                       }
+                       byteLen = 24;
+                       break;
+               case CKK_AES:
+                       if (byteLen != 16 && byteLen != 24 && byteLen != 32)
+                       {
+                               INFO_MSG("CKA_VALUE_LEN must be 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 DH algorithm handler
+       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
+       if (dh == NULL)
+               return CKR_MECHANISM_INVALID;
+
+       // Get the keys
+       PrivateKey* privateKey = dh->newPrivateKey();
+       if (privateKey == NULL)
+       {
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getDHPrivateKey((DHPrivateKey*)privateKey, token, baseKey) != CKR_OK)
+       {
+               dh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       ByteString mechParameters;
+       mechParameters.resize(pMechanism->ulParameterLen);
+       memcpy(&mechParameters[0], pMechanism->pParameter, pMechanism->ulParameterLen);
+       PublicKey* publicKey = dh->newPublicKey();
+       if (publicKey == NULL)
+       {
+               dh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_HOST_MEMORY;
+       }
+       if (getDHPublicKey((DHPublicKey*)publicKey, (DHPrivateKey*)privateKey, mechParameters) != CKR_OK)
+       {
+               dh->recyclePrivateKey(privateKey);
+               dh->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               return CKR_GENERAL_ERROR;
+       }
+
+       // Derive the secret
+       SymmetricKey* secret = NULL;
+       CK_RV rv = CKR_OK;
+       if (!dh->deriveKey(&secret, publicKey, privateKey))
+               rv = CKR_GENERAL_ERROR;
+       dh->recyclePrivateKey(privateKey);
+       dh->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;
+
+                       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
+       dh->recycleSymmetricKey(secret);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+
+       // Remove secret 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)
+               if (*phKey != CK_INVALID_HANDLE)
                {
-                       OSObject* ospub = (OSObject*)handleManager->getObject(*phPublicKey);
-                       handleManager->destroyObject(*phPublicKey);
-                       if (ospub) ospub->destroyObject();
-                       *phPublicKey = CK_INVALID_HANDLE;
+                       OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey);
+                       handleManager->destroyObject(*phKey);
+                       if (ossecret) ossecret->destroyObject();
+                       *phKey = CK_INVALID_HANDLE;
                }
        }
 
        return rv;
 }
 
-// Derive a DH secret
-CK_RV SoftHSM::deriveDH
+// Derive an ECDH secret
+#ifdef WITH_ECC
+CK_RV SoftHSM::deriveECDH
 (CK_SESSION_HANDLE hSession,
        CK_MECHANISM_PTR pMechanism,
        CK_OBJECT_HANDLE hBaseKey,
@@ -9519,8 +10427,29 @@ CK_RV SoftHSM::deriveDH
 {
        *phKey = CK_INVALID_HANDLE;
 
-       if (pMechanism->pParameter == NULL_PTR) return CKR_MECHANISM_PARAM_INVALID;
-       if (pMechanism->ulParameterLen == 0) return CKR_MECHANISM_PARAM_INVALID;
+       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);
@@ -9564,45 +10493,41 @@ CK_RV SoftHSM::deriveDH
        }
 
        // Check the length
+       // byteLen == 0 impiles return max size the ECC can derive
        switch (keyType)
        {
                case CKK_GENERIC_SECRET:
-                       if (byteLen == 0)
-                       {
-                               INFO_MSG("CKA_VALUE_LEN must be set");
-                               return CKR_TEMPLATE_INCOMPLETE;
-                       }
                        break;
 #ifndef WITH_FIPS
                case CKK_DES:
-                       if (byteLen != 0)
+                       if (byteLen != 0 && byteLen != 8)
                        {
-                               INFO_MSG("CKA_VALUE_LEN must not be set");
-                               return CKR_ATTRIBUTE_READ_ONLY;
+                               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)
+                       if (byteLen != 0 && byteLen != 16)
                        {
-                               INFO_MSG("CKA_VALUE_LEN must not be set");
-                               return CKR_ATTRIBUTE_READ_ONLY;
+                               INFO_MSG("CKA_VALUE_LEN must be 0 or 16");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
                        }
                        byteLen = 16;
                        break;
                case CKK_DES3:
-                       if (byteLen != 0)
+                       if (byteLen != 0 && byteLen != 24)
                        {
-                               INFO_MSG("CKA_VALUE_LEN must not be set");
-                               return CKR_ATTRIBUTE_READ_ONLY;
+                               INFO_MSG("CKA_VALUE_LEN must be 0 or 24");
+                               return CKR_ATTRIBUTE_VALUE_INVALID;
                        }
                        byteLen = 24;
                        break;
                case CKK_AES:
-                       if (byteLen != 16 && byteLen != 24 && byteLen != 32)
+                       if (byteLen != 0 && byteLen != 16 && byteLen != 24 && byteLen != 32)
                        {
-                               INFO_MSG("CKA_VALUE_LEN must be 16, 24, or 32");
+                               INFO_MSG("CKA_VALUE_LEN must be 0, 16, 24, or 32");
                                return CKR_ATTRIBUTE_VALUE_INVALID;
                        }
                        break;
@@ -9615,50 +10540,52 @@ CK_RV SoftHSM::deriveDH
        if (baseKey == NULL || !baseKey->isValid())
                return CKR_KEY_HANDLE_INVALID;
 
-       // Get the DH algorithm handler
-       AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH);
-       if (dh == NULL)
+       // Get the ECDH algorithm handler
+       AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH);
+       if (ecdh == NULL)
                return CKR_MECHANISM_INVALID;
 
        // Get the keys
-       PrivateKey* privateKey = dh->newPrivateKey();
+       PrivateKey* privateKey = ecdh->newPrivateKey();
        if (privateKey == NULL)
        {
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
                return CKR_HOST_MEMORY;
        }
-       if (getDHPrivateKey((DHPrivateKey*)privateKey, token, baseKey) != CKR_OK)
+       if (getECPrivateKey((ECPrivateKey*)privateKey, token, baseKey) != CKR_OK)
        {
-               dh->recyclePrivateKey(privateKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               ecdh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
                return CKR_GENERAL_ERROR;
        }
 
-       ByteString mechParameters;
-       mechParameters.resize(pMechanism->ulParameterLen);
-       memcpy(&mechParameters[0], pMechanism->pParameter, pMechanism->ulParameterLen);
-       PublicKey* publicKey = dh->newPublicKey();
+       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 = ecdh->newPublicKey();
        if (publicKey == NULL)
        {
-               dh->recyclePrivateKey(privateKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               ecdh->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
                return CKR_HOST_MEMORY;
        }
-       if (getDHPublicKey((DHPublicKey*)publicKey, (DHPrivateKey*)privateKey, mechParameters) != CKR_OK)
+       if (getECDHPublicKey((ECPublicKey*)publicKey, (ECPrivateKey*)privateKey, publicData) != CKR_OK)
        {
-               dh->recyclePrivateKey(privateKey);
-               dh->recyclePublicKey(publicKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+               ecdh->recyclePrivateKey(privateKey);
+               ecdh->recyclePublicKey(publicKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
                return CKR_GENERAL_ERROR;
        }
 
        // Derive the secret
        SymmetricKey* secret = NULL;
        CK_RV rv = CKR_OK;
-       if (!dh->deriveKey(&secret, publicKey, privateKey))
+       if (!ecdh->deriveKey(&secret, publicKey, privateKey))
                rv = CKR_GENERAL_ERROR;
-       dh->recyclePrivateKey(privateKey);
-       dh->recyclePublicKey(publicKey);
+       ecdh->recyclePrivateKey(privateKey);
+       ecdh->recyclePublicKey(publicKey);
 
        // Create the secret object using C_CreateObject
        const CK_ULONG maxAttribs = 32;
@@ -9730,6 +10657,25 @@ CK_RV SoftHSM::deriveDH
                        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");
@@ -9801,8 +10747,8 @@ CK_RV SoftHSM::deriveDH
        }
 
        // Clean up
-       dh->recycleSymmetricKey(secret);
-       CryptoFactory::i()->recycleAsymmetricAlgorithm(dh);
+       ecdh->recycleSymmetricKey(secret);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
 
        // Remove secret that may have been created already when the function fails.
        if (rv != CKR_OK)
@@ -9818,9 +10764,11 @@ CK_RV SoftHSM::deriveDH
 
        return rv;
 }
+#endif
 
-// Derive an ECDH secret
-CK_RV SoftHSM::deriveECDH
+// 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,
@@ -9831,7 +10779,6 @@ CK_RV SoftHSM::deriveECDH
        CK_BBOOL isOnToken,
        CK_BBOOL isPrivate)
 {
-#ifdef WITH_ECC
        *phKey = CK_INVALID_HANDLE;
 
        if ((pMechanism->pParameter == NULL_PTR) ||
@@ -9947,22 +10894,22 @@ CK_RV SoftHSM::deriveECDH
        if (baseKey == NULL || !baseKey->isValid())
                return CKR_KEY_HANDLE_INVALID;
 
-       // Get the ECDH algorithm handler
-       AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH);
-       if (ecdh == NULL)
+       // Get the EDDSA algorithm handler
+       AsymmetricAlgorithm* eddsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::EDDSA);
+       if (eddsa == NULL)
                return CKR_MECHANISM_INVALID;
 
        // Get the keys
-       PrivateKey* privateKey = ecdh->newPrivateKey();
+       PrivateKey* privateKey = eddsa->newPrivateKey();
        if (privateKey == NULL)
        {
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa);
                return CKR_HOST_MEMORY;
        }
-       if (getECPrivateKey((ECPrivateKey*)privateKey, token, baseKey) != CKR_OK)
+       if (getEDPrivateKey((EDPrivateKey*)privateKey, token, baseKey) != CKR_OK)
        {
-               ecdh->recyclePrivateKey(privateKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               eddsa->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa);
                return CKR_GENERAL_ERROR;
        }
 
@@ -9971,28 +10918,28 @@ CK_RV SoftHSM::deriveECDH
        memcpy(&publicData[0],
               CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->pPublicData,
               CK_ECDH1_DERIVE_PARAMS_PTR(pMechanism->pParameter)->ulPublicDataLen);
-       PublicKey* publicKey = ecdh->newPublicKey();
+       PublicKey* publicKey = eddsa->newPublicKey();
        if (publicKey == NULL)
        {
-               ecdh->recyclePrivateKey(privateKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               eddsa->recyclePrivateKey(privateKey);
+               CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa);
                return CKR_HOST_MEMORY;
        }
-       if (getECDHPublicKey((ECPublicKey*)publicKey, (ECPrivateKey*)privateKey, publicData) != CKR_OK)
+       if (getEDDHPublicKey((EDPublicKey*)publicKey, (EDPrivateKey*)privateKey, publicData) != CKR_OK)
        {
-               ecdh->recyclePrivateKey(privateKey);
-               ecdh->recyclePublicKey(publicKey);
-               CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+               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 (!ecdh->deriveKey(&secret, publicKey, privateKey))
+       if (!eddsa->deriveKey(&secret, publicKey, privateKey))
                rv = CKR_GENERAL_ERROR;
-       ecdh->recyclePrivateKey(privateKey);
-       ecdh->recyclePublicKey(publicKey);
+       eddsa->recyclePrivateKey(privateKey);
+       eddsa->recyclePublicKey(publicKey);
 
        // Create the secret object using C_CreateObject
        const CK_ULONG maxAttribs = 32;
@@ -10154,8 +11101,8 @@ CK_RV SoftHSM::deriveECDH
        }
 
        // Clean up
-       ecdh->recycleSymmetricKey(secret);
-       CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh);
+       eddsa->recycleSymmetricKey(secret);
+       CryptoFactory::i()->recycleAsymmetricAlgorithm(eddsa);
 
        // Remove secret that may have been created already when the function fails.
        if (rv != CKR_OK)
@@ -10170,10 +11117,8 @@ CK_RV SoftHSM::deriveECDH
        }
 
        return rv;
-#else
-       return CKR_MECHANISM_INVALID;
-#endif
 }
+#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)