/* * Copyright (c) 2010 SURFnet bv * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /***************************************************************************** SoftHSM.cpp The implementation of the SoftHSM's main class *****************************************************************************/ #include "config.h" #include "log.h" #include "access.h" #include "Configuration.h" #include "SimpleConfigLoader.h" #include "MutexFactory.h" #include "SecureMemoryRegistry.h" #include "CryptoFactory.h" #include "AsymmetricAlgorithm.h" #include "SymmetricAlgorithm.h" #include "AESKey.h" #include "DESKey.h" #include "RNG.h" #include "RSAParameters.h" #include "RSAPublicKey.h" #include "RSAPrivateKey.h" #include "DSAParameters.h" #include "DSAPublicKey.h" #include "DSAPrivateKey.h" #include "ECPublicKey.h" #include "ECPrivateKey.h" #include "ECParameters.h" #include "DHParameters.h" #include "DHPublicKey.h" #include "DHPrivateKey.h" #include "GOSTPublicKey.h" #include "GOSTPrivateKey.h" #include "cryptoki.h" #include "SoftHSM.h" #include "osmutex.h" #include "SessionManager.h" #include "SessionObjectStore.h" #include "HandleManager.h" #include "P11Objects.h" #include "odd.h" #include "HwInfra.h" #if defined(WITH_OPENSSL) #include "OSSLCryptoFactory.h" #else #include "BotanCryptoFactory.h" #endif #include // Initialise the one-and-only instance #ifdef HAVE_CXX11 std::unique_ptr MutexFactory::instance(nullptr); std::unique_ptr SecureMemoryRegistry::instance(nullptr); #if defined(WITH_OPENSSL) std::unique_ptr OSSLCryptoFactory::instance(nullptr); #else std::unique_ptr BotanCryptoFactory::instance(nullptr); #endif std::unique_ptr SoftHSM::instance(nullptr); #else std::auto_ptr MutexFactory::instance(NULL); std::auto_ptr SecureMemoryRegistry::instance(NULL); #if defined(WITH_OPENSSL) std::auto_ptr OSSLCryptoFactory::instance(NULL); #else std::auto_ptr BotanCryptoFactory::instance(NULL); #endif std::auto_ptr SoftHSM::instance(NULL); #endif static CK_RV Extract_key_handle(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, void *private_handle) { CK_RV rv=CK_TRUE; // get value of the wrapped data (ck) CK_ATTRIBUTE valAttrib[] = { {CKA_OS_PRIVATE_HANDLE, NULL_PTR, sizeof(CK_ULONG)} }; *(CK_ULONG*)private_handle = 0; valAttrib[0].pValue = private_handle; rv = C_GetAttributeValue(hSession, hObject, valAttrib, sizeof(valAttrib)/sizeof(CK_ATTRIBUTE)); if (rv != CKR_OK) { LOG("C_GetAttributeValue() API failed ! %lx\n", rv); } return rv; } static CK_RV newP11Object(CK_OBJECT_CLASS objClass, CK_KEY_TYPE keyType, CK_CERTIFICATE_TYPE certType, P11Object **p11object) { switch(objClass) { case CKO_DATA: *p11object = new P11DataObj(); break; case CKO_CERTIFICATE: if (certType == CKC_X_509) *p11object = new P11X509CertificateObj(); else if (certType == CKC_OPENPGP) *p11object = new P11OpenPGPPublicKeyObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; case CKO_PUBLIC_KEY: if (keyType == CKK_RSA) *p11object = new P11RSAPublicKeyObj(); else if (keyType == CKK_DSA) *p11object = new P11DSAPublicKeyObj(); else if (keyType == CKK_EC) *p11object = new P11ECPublicKeyObj(); else if (keyType == CKK_DH) *p11object = new P11DHPublicKeyObj(); else if (keyType == CKK_GOSTR3410) *p11object = new P11GOSTPublicKeyObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; case CKO_PRIVATE_KEY: // we need to know the type too if (keyType == CKK_RSA) *p11object = new P11RSAPrivateKeyObj(); else if (keyType == CKK_DSA) *p11object = new P11DSAPrivateKeyObj(); else if (keyType == CKK_EC) *p11object = new P11ECPrivateKeyObj(); else if (keyType == CKK_DH) *p11object = new P11DHPrivateKeyObj(); else if (keyType == CKK_GOSTR3410) *p11object = new P11GOSTPrivateKeyObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; case CKO_SECRET_KEY: if ((keyType == CKK_GENERIC_SECRET) || (keyType == CKK_MD5_HMAC) || (keyType == CKK_SHA_1_HMAC) || (keyType == CKK_SHA224_HMAC) || (keyType == CKK_SHA256_HMAC) || (keyType == CKK_SHA384_HMAC) || (keyType == CKK_SHA512_HMAC)) { P11GenericSecretKeyObj* key = new P11GenericSecretKeyObj(); *p11object = key; key->setKeyType(keyType); } else if (keyType == CKK_AES) { *p11object = new P11AESSecretKeyObj(); } else if ((keyType == CKK_DES) || (keyType == CKK_DES2) || (keyType == CKK_DES3)) { P11DESSecretKeyObj* key = new P11DESSecretKeyObj(); *p11object = key; key->setKeyType(keyType); } else if (keyType == CKK_GOST28147) { *p11object = new P11GOSTSecretKeyObj(); } else return CKR_ATTRIBUTE_VALUE_INVALID; break; case CKO_DOMAIN_PARAMETERS: if (keyType == CKK_DSA) *p11object = new P11DSADomainObj(); else if (keyType == CKK_DH) *p11object = new P11DHDomainObj(); else return CKR_ATTRIBUTE_VALUE_INVALID; break; default: return CKR_ATTRIBUTE_VALUE_INVALID; // invalid value for a valid argument } return CKR_OK; } static CK_RV extractObjectInformation(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_CLASS &objClass, CK_KEY_TYPE &keyType, CK_CERTIFICATE_TYPE &certType, CK_BBOOL &isOnToken, CK_BBOOL &isPrivate, bool bImplicit) { bool bHasClass = false; bool bHasKeyType = false; bool bHasCertType = false; bool bHasPrivate = false; // Extract object information for (CK_ULONG i = 0; i < ulCount; ++i) { switch (pTemplate[i].type) { case CKA_CLASS: if (pTemplate[i].ulValueLen == sizeof(CK_OBJECT_CLASS)) { objClass = *(CK_OBJECT_CLASS_PTR)pTemplate[i].pValue; bHasClass = true; } break; case CKA_KEY_TYPE: if (pTemplate[i].ulValueLen == sizeof(CK_KEY_TYPE)) { keyType = *(CK_KEY_TYPE*)pTemplate[i].pValue; bHasKeyType = true; } break; case CKA_CERTIFICATE_TYPE: if (pTemplate[i].ulValueLen == sizeof(CK_CERTIFICATE_TYPE)) { certType = *(CK_CERTIFICATE_TYPE*)pTemplate[i].pValue; bHasCertType = true; } break; case CKA_TOKEN: if (pTemplate[i].ulValueLen == sizeof(CK_BBOOL)) { isOnToken = *(CK_BBOOL*)pTemplate[i].pValue; } break; case CKA_PRIVATE: if (pTemplate[i].ulValueLen == sizeof(CK_BBOOL)) { isPrivate = *(CK_BBOOL*)pTemplate[i].pValue; bHasPrivate = true; } break; default: break; } } if (bImplicit) { return CKR_OK; } if (!bHasClass) { return CKR_TEMPLATE_INCOMPLETE; } bool bKeyTypeRequired = (objClass == CKO_PUBLIC_KEY || objClass == CKO_PRIVATE_KEY || objClass == CKO_SECRET_KEY); if (bKeyTypeRequired && !bHasKeyType) { return CKR_TEMPLATE_INCOMPLETE; } if (objClass == CKO_CERTIFICATE) { if (!bHasCertType) { return CKR_TEMPLATE_INCOMPLETE; } if (!bHasPrivate) { // Change default value for certificates isPrivate = CK_FALSE; } } if (objClass == CKO_PUBLIC_KEY && !bHasPrivate) { // Change default value for public keys isPrivate = CK_FALSE; } return CKR_OK; } static CK_RV newP11Object(OSObject *object, P11Object **p11object) { CK_OBJECT_CLASS objClass = object->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED); CK_KEY_TYPE keyType = CKK_RSA; CK_CERTIFICATE_TYPE certType = CKC_X_509; if (object->attributeExists(CKA_KEY_TYPE)) keyType = object->getUnsignedLongValue(CKA_KEY_TYPE, CKK_RSA); if (object->attributeExists(CKA_CERTIFICATE_TYPE)) certType = object->getUnsignedLongValue(CKA_CERTIFICATE_TYPE, CKC_X_509); CK_RV rv = newP11Object(objClass,keyType,certType,p11object); if (rv != CKR_OK) return rv; if (!(*p11object)->init(object)) return CKR_GENERAL_ERROR; // something went wrong that shouldn't have. return CKR_OK; } #ifdef notyet static CK_ATTRIBUTE bsAttribute(CK_ATTRIBUTE_TYPE type, const ByteString &value) { CK_ATTRIBUTE attr = {type, (CK_VOID_PTR)value.const_byte_str(), value.size() }; return attr; } #endif /***************************************************************************** Implementation of SoftHSM class specific functions *****************************************************************************/ // Return the one-and-only instance SoftHSM* SoftHSM::i() { if (!instance.get()) { instance.reset(new SoftHSM()); } return instance.get(); } void SoftHSM::reset() { if (instance.get()) instance.reset(); } // Constructor SoftHSM::SoftHSM() { isInitialised = false; isRemovable = false; sessionObjectStore = NULL; objectStore = NULL; slotManager = NULL; sessionManager = NULL; handleManager = NULL; isHWavailable = false; } // Destructor SoftHSM::~SoftHSM() { if (handleManager != NULL) delete handleManager; if (sessionManager != NULL) delete sessionManager; if (slotManager != NULL) delete slotManager; if (objectStore != NULL) delete objectStore; if (sessionObjectStore != NULL) delete sessionObjectStore; } /***************************************************************************** Implementation of PKCS #11 functions *****************************************************************************/ // PKCS #11 initialisation function CK_RV SoftHSM::C_Initialize(CK_VOID_PTR pInitArgs) { CK_C_INITIALIZE_ARGS_PTR args; // Check if PKCS#11 is already initialized if (isInitialised) { ERROR_MSG("SoftHSM is already initialized"); return CKR_CRYPTOKI_ALREADY_INITIALIZED; } // Do we have any arguments? if (pInitArgs != NULL_PTR) { args = (CK_C_INITIALIZE_ARGS_PTR)pInitArgs; // Must be set to NULL_PTR in this version of PKCS#11 if (args->pReserved != NULL_PTR) { ERROR_MSG("pReserved must be set to NULL_PTR"); return CKR_ARGUMENTS_BAD; } // Can we spawn our own threads? // if (args->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) // { // DEBUG_MSG("Cannot create threads if CKF_LIBRARY_CANT_CREATE_OS_THREADS is set"); // return CKR_NEED_TO_CREATE_THREADS; // } // Are we not supplied with mutex functions? if ( args->CreateMutex == NULL_PTR && args->DestroyMutex == NULL_PTR && args->LockMutex == NULL_PTR && args->UnlockMutex == NULL_PTR ) { // Can we use our own mutex functions? 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); MutexFactory::i()->enable(); } else { // The external application is not using threading MutexFactory::i()->disable(); } } else { // We must have all mutex functions if ( args->CreateMutex == NULL_PTR || args->DestroyMutex == NULL_PTR || args->LockMutex == NULL_PTR || args->UnlockMutex == NULL_PTR ) { ERROR_MSG("Not all mutex functions are supplied"); return CKR_ARGUMENTS_BAD; } // We could use our own mutex functions if the flag is set, // but we use the external functions in both cases. // Load the external mutex functions MutexFactory::i()->setCreateMutex(args->CreateMutex); MutexFactory::i()->setDestroyMutex(args->DestroyMutex); MutexFactory::i()->setLockMutex(args->LockMutex); MutexFactory::i()->setUnlockMutex(args->UnlockMutex); MutexFactory::i()->enable(); } } else { // No concurrent access by multiple threads MutexFactory::i()->disable(); } // Initiate SecureMemoryRegistry if (SecureMemoryRegistry::i() == NULL) { ERROR_MSG("Could not load the SecureMemoryRegistry"); return CKR_GENERAL_ERROR; } // Build the CryptoFactory if (CryptoFactory::i() == NULL) { ERROR_MSG("Could not load the CryptoFactory"); return CKR_GENERAL_ERROR; } #ifdef WITH_FIPS // Check the FIPS status if (!CryptoFactory::i()->getFipsSelfTestStatus()) { ERROR_MSG("The FIPS self test failed"); return CKR_FIPS_SELF_TEST_FAILED; } #endif // (Re)load the configuration if (!Configuration::i()->reload(SimpleConfigLoader::i())) { ERROR_MSG("Could not load the configuration"); return CKR_GENERAL_ERROR; } // Configure the log level if (!setLogLevel(Configuration::i()->getString("log.level", DEFAULT_LOG_LEVEL))) { ERROR_MSG("Could not set the log level"); return CKR_GENERAL_ERROR; } // Configure object store storage backend used by all tokens. if (!ObjectStoreToken::selectBackend(Configuration::i()->getString("objectstore.backend", DEFAULT_OBJECTSTORE_BACKEND))) { ERROR_MSG("Could not set the storage backend"); return CKR_GENERAL_ERROR; } sessionObjectStore = new SessionObjectStore(); // Load the object store objectStore = new ObjectStore(Configuration::i()->getString("directories.tokendir", DEFAULT_TOKENDIR)); if (!objectStore->isValid()) { WARNING_MSG("Could not load the object store"); delete objectStore; objectStore = NULL; delete sessionObjectStore; sessionObjectStore = NULL; return CKR_GENERAL_ERROR; } isRemovable = Configuration::i()->getBool("slots.removable", false); // Load the slot manager slotManager = new SlotManager(objectStore); // Load the session manager sessionManager = new SessionManager(); // Load the handle manager handleManager = new HandleManager(); // Set the state to initialised isInitialised = true; if(prepareHWPlugin()) { printf("HW plugin NOT available to use ! \n"); isHWavailable = false; } else { printf("HW plugin available and initialized ! \n"); isHWavailable = true; } return CKR_OK; } // PKCS #11 finalisation function CK_RV SoftHSM::C_Finalize(CK_VOID_PTR pReserved) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Must be set to NULL_PTR in this version of PKCS#11 if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD; 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; CryptoFactory::reset(); SecureMemoryRegistry::reset(); isInitialised = false; SoftHSM::reset(); return CKR_OK; } // Return information about the PKCS #11 module CK_RV SoftHSM::C_GetInfo(CK_INFO_PTR pInfo) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD; pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; memset(pInfo->manufacturerID, ' ', 32); memcpy(pInfo->manufacturerID, "SoftHSM", 7); pInfo->flags = 0; memset(pInfo->libraryDescription, ' ', 32); #ifdef WITH_FIPS memcpy(pInfo->libraryDescription, "Implementation of PKCS11+FIPS", 29); #else memcpy(pInfo->libraryDescription, "Implementation of PKCS11", 24); #endif pInfo->libraryVersion.major = VERSION_MAJOR; pInfo->libraryVersion.minor = VERSION_MINOR; return CKR_OK; } // Return a list of available slots CK_RV SoftHSM::C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; return slotManager->getSlotList(objectStore, tokenPresent, pSlotList, pulCount); } // Return information about a slot CK_RV SoftHSM::C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_RV rv; if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) { return CKR_SLOT_ID_INVALID; } rv = slot->getSlotInfo(pInfo); if (rv != CKR_OK) { return rv; } if (isRemovable) { pInfo->flags |= CKF_REMOVABLE_DEVICE; } return CKR_OK; } // Return information about a token in a slot CK_RV SoftHSM::C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) { return CKR_SLOT_ID_INVALID; } Token* token = slot->getToken(); if (token == NULL) { return CKR_TOKEN_NOT_PRESENT; } return token->getTokenInfo(pInfo); } // Return the list of supported mechanisms for a given slot 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; #ifdef WITH_ECC nrSupportedMechanisms += 3; #endif #ifdef WITH_FIPS nrSupportedMechanisms -= 9; #endif #ifdef WITH_GOST nrSupportedMechanisms += 5; #endif #ifdef HAVE_AES_KEY_WRAP_PAD nrSupportedMechanisms += 1; #endif #ifdef WITH_RAW_PSS nrSupportedMechanisms += 1; // CKM_RSA_PKCS_PSS #endif #ifdef WITH_AES_GCM nrSupportedMechanisms += 1; #endif CK_MECHANISM_TYPE supportedMechanisms[] = { #ifndef WITH_FIPS CKM_MD5, #endif CKM_SHA_1, CKM_SHA224, CKM_SHA256, CKM_SHA384, CKM_SHA512, #ifndef WITH_FIPS CKM_MD5_HMAC, #endif CKM_SHA_1_HMAC, CKM_SHA224_HMAC, CKM_SHA256_HMAC, CKM_SHA384_HMAC, CKM_SHA512_HMAC, CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_X_509, #ifndef WITH_FIPS CKM_MD5_RSA_PKCS, #endif CKM_SHA1_RSA_PKCS, CKM_RSA_PKCS_OAEP, CKM_SHA224_RSA_PKCS, CKM_SHA256_RSA_PKCS, CKM_SHA384_RSA_PKCS, CKM_SHA512_RSA_PKCS, #ifdef WITH_RAW_PSS CKM_RSA_PKCS_PSS, #endif CKM_SHA1_RSA_PKCS_PSS, CKM_SHA224_RSA_PKCS_PSS, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512_RSA_PKCS_PSS, #ifndef WITH_FIPS CKM_DES_KEY_GEN, #endif CKM_DES2_KEY_GEN, CKM_DES3_KEY_GEN, #ifndef WITH_FIPS CKM_DES_ECB, CKM_DES_CBC, CKM_DES_CBC_PAD, CKM_DES_ECB_ENCRYPT_DATA, CKM_DES_CBC_ENCRYPT_DATA, #endif CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_CBC_PAD, CKM_DES3_ECB_ENCRYPT_DATA, CKM_DES3_CBC_ENCRYPT_DATA, CKM_DES3_CMAC, CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_AES_CTR, #ifdef WITH_AES_GCM CKM_AES_GCM, #endif CKM_AES_KEY_WRAP, #ifdef HAVE_AES_KEY_WRAP_PAD CKM_AES_KEY_WRAP_PAD, #endif CKM_AES_ECB_ENCRYPT_DATA, CKM_AES_CBC_ENCRYPT_DATA, CKM_AES_CMAC, CKM_DSA_PARAMETER_GEN, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1, CKM_DSA_SHA224, CKM_DSA_SHA256, CKM_DSA_SHA384, CKM_DSA_SHA512, CKM_DH_PKCS_KEY_PAIR_GEN, CKM_DH_PKCS_PARAMETER_GEN, CKM_DH_PKCS_DERIVE, #ifdef WITH_ECC CKM_EC_KEY_PAIR_GEN, CKM_ECDSA, CKM_ECDH1_DERIVE, #endif #ifdef WITH_GOST CKM_GOSTR3411, CKM_GOSTR3411_HMAC, CKM_GOSTR3410_KEY_PAIR_GEN, CKM_GOSTR3410, CKM_GOSTR3410_WITH_GOSTR3411 #endif }; if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pulCount == NULL_PTR) return CKR_ARGUMENTS_BAD; Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) { return CKR_SLOT_ID_INVALID; } if (pMechanismList == NULL_PTR) { *pulCount = nrSupportedMechanisms; return CKR_OK; } if (*pulCount < nrSupportedMechanisms) { *pulCount = nrSupportedMechanisms; return CKR_BUFFER_TOO_SMALL; } *pulCount = nrSupportedMechanisms; for (CK_ULONG i = 0; i < nrSupportedMechanisms; i ++) { pMechanismList[i] = supportedMechanisms[i]; } return CKR_OK; } // Return more information about a mechanism for a given slot CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { unsigned long rsaMinSize, rsaMaxSize; unsigned long dsaMinSize, dsaMaxSize; unsigned long dhMinSize, dhMaxSize; #ifdef WITH_ECC unsigned long ecdsaMinSize, ecdsaMaxSize; unsigned long ecdhMinSize, ecdhMaxSize; #endif if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD; Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) { return CKR_SLOT_ID_INVALID; } AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (rsa != NULL) { rsaMinSize = rsa->getMinKeySize(); rsaMaxSize = rsa->getMaxKeySize(); } else { return CKR_GENERAL_ERROR; } CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (dsa != NULL) { dsaMinSize = dsa->getMinKeySize(); // Limitation in PKCS#11 if (dsaMinSize < 512) { dsaMinSize = 512; } dsaMaxSize = dsa->getMaxKeySize(); // Limitation in PKCS#11 if (dsaMaxSize > 1024) { dsaMaxSize = 1024; } } else { return CKR_GENERAL_ERROR; } CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH); if (dh != NULL) { dhMinSize = dh->getMinKeySize(); dhMaxSize = dh->getMaxKeySize(); } else { return CKR_GENERAL_ERROR; } CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); #ifdef WITH_ECC AsymmetricAlgorithm* ecdsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA); if (ecdsa != NULL) { ecdsaMinSize = ecdsa->getMinKeySize(); ecdsaMaxSize = ecdsa->getMaxKeySize(); } else { return CKR_GENERAL_ERROR; } CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdsa); AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH); if (ecdh != NULL) { ecdhMinSize = ecdh->getMinKeySize(); ecdhMaxSize = ecdh->getMaxKeySize(); } else { return CKR_GENERAL_ERROR; } CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); #endif switch (type) { #ifndef WITH_FIPS case CKM_MD5: #endif case CKM_SHA_1: case CKM_SHA224: case CKM_SHA256: case CKM_SHA384: case CKM_SHA512: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_DIGEST; break; #ifndef WITH_FIPS case CKM_MD5_HMAC: pInfo->ulMinKeySize = 16; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; #endif case CKM_SHA_1_HMAC: pInfo->ulMinKeySize = 20; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_SHA224_HMAC: pInfo->ulMinKeySize = 28; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_SHA256_HMAC: pInfo->ulMinKeySize = 32; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_SHA384_HMAC: pInfo->ulMinKeySize = 48; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_SHA512_HMAC: pInfo->ulMinKeySize = 64; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_RSA_PKCS_KEY_PAIR_GEN: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_GENERATE_KEY_PAIR; break; case CKM_RSA_PKCS: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; break; case CKM_RSA_X_509: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_ENCRYPT | CKF_DECRYPT; break; #ifndef WITH_FIPS case CKM_MD5_RSA_PKCS: #endif case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: #ifdef WITH_RAW_PSS case CKM_RSA_PKCS_PSS: #endif case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_RSA_PKCS_OAEP: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; break; #ifndef WITH_FIPS case CKM_DES_KEY_GEN: #endif case CKM_DES2_KEY_GEN: case CKM_DES3_KEY_GEN: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_GENERATE; break; #ifndef WITH_FIPS case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: #endif case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; break; case CKM_DES3_CMAC: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_AES_KEY_GEN: pInfo->ulMinKeySize = 16; pInfo->ulMaxKeySize = 32; pInfo->flags = CKF_GENERATE; break; case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_AES_CTR: #ifdef WITH_AES_GCM case CKM_AES_GCM: #endif pInfo->ulMinKeySize = 16; pInfo->ulMaxKeySize = 32; pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; break; case CKM_AES_KEY_WRAP: pInfo->ulMinKeySize = 16; pInfo->ulMaxKeySize = 0x80000000; pInfo->flags = CKF_WRAP | CKF_UNWRAP; break; #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: pInfo->ulMinKeySize = 1; pInfo->ulMaxKeySize = 0x80000000; pInfo->flags = CKF_WRAP | CKF_UNWRAP; break; #endif #ifndef WITH_FIPS case CKM_DES_ECB_ENCRYPT_DATA: case CKM_DES_CBC_ENCRYPT_DATA: #endif case CKM_DES3_ECB_ENCRYPT_DATA: case CKM_DES3_CBC_ENCRYPT_DATA: case CKM_AES_ECB_ENCRYPT_DATA: case CKM_AES_CBC_ENCRYPT_DATA: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_DERIVE; break; case CKM_AES_CMAC: pInfo->ulMinKeySize = 16; pInfo->ulMaxKeySize = 32; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_DSA_PARAMETER_GEN: pInfo->ulMinKeySize = dsaMinSize; pInfo->ulMaxKeySize = dsaMaxSize; pInfo->flags = CKF_GENERATE; break; case CKM_DSA_KEY_PAIR_GEN: pInfo->ulMinKeySize = dsaMinSize; pInfo->ulMaxKeySize = dsaMaxSize; pInfo->flags = CKF_GENERATE_KEY_PAIR; break; case CKM_DSA: case CKM_DSA_SHA1: case CKM_DSA_SHA224: case CKM_DSA_SHA256: case CKM_DSA_SHA384: case CKM_DSA_SHA512: pInfo->ulMinKeySize = dsaMinSize; pInfo->ulMaxKeySize = dsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_DH_PKCS_KEY_PAIR_GEN: pInfo->ulMinKeySize = dhMinSize; pInfo->ulMaxKeySize = dhMaxSize; pInfo->flags = CKF_GENERATE_KEY_PAIR; break; case CKM_DH_PKCS_PARAMETER_GEN: pInfo->ulMinKeySize = dhMinSize; pInfo->ulMaxKeySize = dhMaxSize; pInfo->flags = CKF_GENERATE; break; case CKM_DH_PKCS_DERIVE: pInfo->ulMinKeySize = dhMinSize; pInfo->ulMaxKeySize = dhMaxSize; pInfo->flags = CKF_DERIVE; break; #ifdef WITH_ECC case CKM_EC_KEY_PAIR_GEN: pInfo->ulMinKeySize = ecdsaMinSize; pInfo->ulMaxKeySize = ecdsaMaxSize; #define CKF_EC_COMMOM (CKF_EC_F_P | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS) pInfo->flags = CKF_GENERATE_KEY_PAIR | CKF_EC_COMMOM; break; case CKM_ECDSA: pInfo->ulMinKeySize = ecdsaMinSize; pInfo->ulMaxKeySize = ecdsaMaxSize; pInfo->flags = CKF_SIGN | CKF_VERIFY | CKF_EC_COMMOM; break; case CKM_ECDH1_DERIVE: pInfo->ulMinKeySize = ecdhMinSize; pInfo->ulMaxKeySize = ecdhMaxSize; pInfo->flags = CKF_DERIVE; break; #endif #ifdef WITH_GOST case CKM_GOSTR3411: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_DIGEST; break; case CKM_GOSTR3411_HMAC: // Key size is not in use pInfo->ulMinKeySize = 32; pInfo->ulMaxKeySize = 512; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_GOSTR3410_KEY_PAIR_GEN: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_GENERATE_KEY_PAIR; break; case CKM_GOSTR3410: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; case CKM_GOSTR3410_WITH_GOSTR3411: // Key size is not in use pInfo->ulMinKeySize = 0; pInfo->ulMaxKeySize = 0; pInfo->flags = CKF_SIGN | CKF_VERIFY; break; #endif default: DEBUG_MSG("The selected mechanism is not supported"); return CKR_MECHANISM_INVALID; break; } return CKR_OK; } // Initialise the token in the specified slot CK_RV SoftHSM::C_InitToken(CK_SLOT_ID slotID, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) { return CKR_SLOT_ID_INVALID; } // Check if any session is open with this token. if (sessionManager->haveSession(slotID)) { return CKR_SESSION_EXISTS; } // Check the PIN if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD; if (ulPinLen < MIN_PIN_LEN || ulPinLen > MAX_PIN_LEN) return CKR_PIN_INCORRECT; ByteString soPIN(pPin, ulPinLen); return slot->initToken(soPIN, pLabel); } // Initialise the user PIN CK_RV SoftHSM::C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // The SO must be logged in if (session->getState() != CKS_RW_SO_FUNCTIONS) return CKR_USER_NOT_LOGGED_IN; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the PIN if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD; if (ulPinLen < MIN_PIN_LEN || ulPinLen > MAX_PIN_LEN) return CKR_PIN_LEN_RANGE; ByteString userPIN(pPin, ulPinLen); return token->initUserPIN(userPIN); } // Change the PIN CK_RV SoftHSM::C_SetPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_UTF8CHAR_PTR pNewPin, CK_ULONG ulNewLen) { CK_RV rv = CKR_OK; if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check the new PINs if (pOldPin == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pNewPin == NULL_PTR) return CKR_ARGUMENTS_BAD; if (ulNewLen < MIN_PIN_LEN || ulNewLen > MAX_PIN_LEN) return CKR_PIN_LEN_RANGE; ByteString oldPIN(pOldPin, ulOldLen); ByteString newPIN(pNewPin, ulNewLen); // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; switch (session->getState()) { case CKS_RW_PUBLIC_SESSION: case CKS_RW_USER_FUNCTIONS: rv = token->setUserPIN(oldPIN, newPIN); break; case CKS_RW_SO_FUNCTIONS: rv = token->setSOPIN(oldPIN, newPIN); break; default: return CKR_SESSION_READ_ONLY; } return rv; } // Open a new session to the specified slot CK_RV SoftHSM::C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; Slot* slot = slotManager->getSlot(slotID); CK_RV rv = sessionManager->openSession(slot, flags, pApplication, notify, phSession); if (rv != CKR_OK) return rv; // Get a pointer to the session object and store it in the handle manager. Session* session = sessionManager->getSession(*phSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; *phSession = handleManager->addSession(slotID,session); return CKR_OK; } // Close the given session CK_RV SoftHSM::C_CloseSession(CK_SESSION_HANDLE hSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Tell the handle manager the session has been closed. handleManager->sessionClosed(hSession); // Tell the session object store that the session has closed. sessionObjectStore->sessionClosed(hSession); // Tell the session manager the session has been closed. return sessionManager->closeSession(session->getHandle()); } // Close all open sessions CK_RV SoftHSM::C_CloseAllSessions(CK_SLOT_ID slotID) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the slot Slot* slot = slotManager->getSlot(slotID); if (slot == NULL) return CKR_SLOT_ID_INVALID; // Get the token Token* token = slot->getToken(); if (token == NULL) return CKR_TOKEN_NOT_PRESENT; // Tell the handle manager all sessions were closed for the given slotID. // The handle manager should then remove all session and object handles for this slot. handleManager->allSessionsClosed(slotID); // Tell the session object store that all sessions were closed for the given slotID. // The session object store should then remove all session objects for this slot. sessionObjectStore->allSessionsClosed(slotID); // Finally tell the session manager tho close all sessions for the given slot. // This will also trigger a logout on the associated token to occur. return sessionManager->closeAllSessions(slot); } // Retrieve information about the specified session CK_RV SoftHSM::C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return session->getInfo(pInfo); } // Determine the state of a running operation in a session CK_RV SoftHSM::C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pOperationState*/, CK_ULONG_PTR /*pulOperationStateLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Set the operation sate in a session CK_RV SoftHSM::C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pOperationState*/, CK_ULONG /*ulOperationStateLen*/, CK_OBJECT_HANDLE /*hEncryptionKey*/, CK_OBJECT_HANDLE /*hAuthenticationKey*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Login on the token in the specified session CK_RV SoftHSM::C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_RV rv = CKR_OK; if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the PIN if (pPin == NULL_PTR) return CKR_ARGUMENTS_BAD; ByteString pin(pPin, ulPinLen); // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; switch (userType) { case CKU_SO: // There cannot exist a R/O session on this slot if (sessionManager->haveROSession(session->getSlot()->getSlotID())) return CKR_SESSION_READ_ONLY_EXISTS; // Login rv = token->loginSO(pin); break; case CKU_USER: // Login rv = token->loginUser(pin); break; case CKU_CONTEXT_SPECIFIC: // Check if re-authentication is required if (!session->getReAuthentication()) return CKR_OPERATION_NOT_INITIALIZED; // Re-authenticate rv = token->reAuthenticate(pin); if (rv == CKR_OK) session->setReAuthentication(false); break; default: return CKR_USER_TYPE_INVALID; } return rv; } // Log out of the token in the specified session CK_RV SoftHSM::C_Logout(CK_SESSION_HANDLE hSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // 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; // Logout token->logout(); // [PKCS#11 v2.40, C_Logout] When logout is successful... // a. Any of the application's handles to private objects become invalid. // b. Even if a user is later logged back into the token those handles remain invalid. // c. All private session objects from sessions belonging to the application are destroyed. // Have the handle manager remove all handles pointing to private objects for this slot. CK_SLOT_ID slotID = session->getSlot()->getSlotID(); handleManager->tokenLoggedOut(slotID); sessionObjectStore->tokenLoggedOut(slotID); return CKR_OK; } // Create a new object on the token in the specified session using the given attribute template CK_RV SoftHSM::C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { return this->CreateObject(hSession,pTemplate,ulCount,phObject,OBJECT_OP_CREATE); } // Create a copy of the object with the specified handle CK_RV SoftHSM::C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phNewObject == NULL_PTR) return CKR_ARGUMENTS_BAD; *phNewObject = CK_INVALID_HANDLE; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the slot Slot* slot = session->getSlot(); if (slot == NULL_PTR) return CKR_GENERAL_ERROR; // Get the token Token* token = session->getToken(); if (token == NULL_PTR) return CKR_GENERAL_ERROR; // Check the object handle. OSObject *object = (OSObject *)handleManager->getObject(hObject); if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL wasOnToken = object->getBooleanValue(CKA_TOKEN, false); CK_BBOOL wasPrivate = object->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), wasOnToken, wasPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if the object is copyable CK_BBOOL isCopyable = object->getBooleanValue(CKA_COPYABLE, true); if (!isCopyable) return CKR_ACTION_PROHIBITED; // Extract critical information from the template CK_BBOOL isOnToken = wasOnToken; CK_BBOOL isPrivate = wasPrivate; for (CK_ULONG i = 0; i < ulCount; i++) { if ((pTemplate[i].type == CKA_TOKEN) && (pTemplate[i].ulValueLen == sizeof(CK_BBOOL))) { isOnToken = *(CK_BBOOL*)pTemplate[i].pValue; continue; } if ((pTemplate[i].type == CKA_PRIVATE) && (pTemplate[i].ulValueLen == sizeof(CK_BBOOL))) { isPrivate = *(CK_BBOOL*)pTemplate[i].pValue; continue; } } // Check privacy does not downgrade if (wasPrivate && !isPrivate) return CKR_TEMPLATE_INCONSISTENT; // Check write user credentials rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Create the object in session or on the token OSObject *newobject = NULL_PTR; if (isOnToken) { newobject = (OSObject*) token->createObject(); } else { newobject = sessionObjectStore->createObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE); } if (newobject == NULL) return CKR_GENERAL_ERROR; // Copy attributes from object class (CKA_CLASS=0 so the first) if (!newobject->startTransaction()) { newobject->destroyObject(); return CKR_FUNCTION_FAILED; } CK_ATTRIBUTE_TYPE attrType = CKA_CLASS; do { if (!object->attributeExists(attrType)) { rv = CKR_FUNCTION_FAILED; break; } OSAttribute attr = object->getAttribute(attrType); // Upgrade privacy has to encrypt byte strings if (!wasPrivate && isPrivate && attr.isByteStringAttribute() && attr.getByteStringValue().size() != 0) { ByteString value; if (!token->encrypt(attr.getByteStringValue(), value) || !newobject->setAttribute(attrType, value)) { rv = CKR_FUNCTION_FAILED; break; } } else { if (!newobject->setAttribute(attrType, attr)) { rv = CKR_FUNCTION_FAILED; break; } } attrType = object->nextAttributeType(attrType); } while (attrType != CKA_CLASS); if (rv != CKR_OK) { newobject->abortTransaction(); } else if (!newobject->commitTransaction()) { rv = CKR_FUNCTION_FAILED; } if (rv != CKR_OK) { newobject->destroyObject(); return rv; } // Get the new P11 object P11Object* newp11object = NULL; rv = newP11Object(newobject,&newp11object); if (rv != CKR_OK) { newobject->destroyObject(); return rv; } // Apply the template rv = newp11object->saveTemplate(token, isPrivate != CK_FALSE, pTemplate, ulCount, OBJECT_OP_COPY); delete newp11object; if (rv != CKR_OK) { newobject->destroyObject(); return rv; } // Set handle if (isOnToken) { *phNewObject = handleManager->addTokenObject(slot->getSlotID(), isPrivate != CK_FALSE, newobject); } else { *phNewObject = handleManager->addSessionObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE, newobject); } return CKR_OK; } // Destroy the specified object CK_RV SoftHSM::C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // 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_PTR) return CKR_GENERAL_ERROR; // Check the object handle. OSObject *object = (OSObject *)handleManager->getObject(hObject); if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true); // Check user credentials CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Check if the object is destroyable CK_BBOOL isDestroyable = object->getBooleanValue(CKA_DESTROYABLE, true); if (!isDestroyable) return CKR_ACTION_PROHIBITED; // Tell the handleManager to forget about the object. handleManager->destroyObject(hObject); // Destroy the object if (!object->destroyObject()) return CKR_FUNCTION_FAILED; return CKR_OK; } // Determine the size of the specified object CK_RV SoftHSM::C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pulSize == NULL) return CKR_ARGUMENTS_BAD; // 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_PTR) return CKR_GENERAL_ERROR; // Check the object handle. OSObject *object = (OSObject *)handleManager->getObject(hObject); if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID; *pulSize = CK_UNAVAILABLE_INFORMATION; return CKR_OK; } // Retrieve the specified attributes for the given object CK_RV SoftHSM::C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pTemplate == NULL) return CKR_ARGUMENTS_BAD; // 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; // Check the object handle. OSObject *object = (OSObject *)handleManager->getObject(hObject); if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); // CKR_USER_NOT_LOGGED_IN is not a valid return code for this function, // so we use CKR_GENERAL_ERROR. return CKR_GENERAL_ERROR; } // Wrap a P11Object around the OSObject so we can access the attributes in the // context of the object in which it is defined. P11Object* p11object = NULL; rv = newP11Object(object,&p11object); if (rv != CKR_OK) return rv; // Ask the P11Object to fill the template with attribute values. rv = p11object->loadTemplate(token, pTemplate,ulCount); delete p11object; return rv; } // Change or set the value of the specified attributes on the specified object CK_RV SoftHSM::C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pTemplate == NULL) return CKR_ARGUMENTS_BAD; // 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; // Check the object handle. OSObject *object = (OSObject *)handleManager->getObject(hObject); if (object == NULL_PTR || !object->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = object->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = object->getBooleanValue(CKA_PRIVATE, true); // Check user credentials CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Check if the object is modifiable CK_BBOOL isModifiable = object->getBooleanValue(CKA_MODIFIABLE, true); if (!isModifiable) return CKR_ACTION_PROHIBITED; // Wrap a P11Object around the OSObject so we can access the attributes in the // context of the object in which it is defined. P11Object* p11object = NULL; rv = newP11Object(object,&p11object); if (rv != CKR_OK) return rv; // Ask the P11Object to save the template with attribute values. rv = p11object->saveTemplate(token, isPrivate != CK_FALSE, pTemplate,ulCount,OBJECT_OP_SET); delete p11object; return rv; } // Initialise object search in the specified session using the specified attribute template as search parameters CK_RV SoftHSM::C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the slot Slot* slot = session->getSlot(); if (slot == NULL_PTR) return CKR_GENERAL_ERROR; // Determine whether we have a public session or not. bool isPublicSession; switch (session->getState()) { case CKS_RO_USER_FUNCTIONS: case CKS_RW_USER_FUNCTIONS: isPublicSession = false; break; default: isPublicSession = true; } // Get the token Token* token = session->getToken(); if (token == NULL_PTR) return CKR_GENERAL_ERROR; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; session->setOpType(SESSION_OP_FIND); FindOperation *findOp = FindOperation::create(); // Check if we are out of memory if (findOp == NULL_PTR) return CKR_HOST_MEMORY; std::set allObjects; token->getObjects(allObjects); sessionObjectStore->getObjects(slot->getSlotID(),allObjects); std::set handles; std::set::iterator it; for (it=allObjects.begin(); it != allObjects.end(); ++it) { // Refresh object and check if it is valid if (!(*it)->isValid()) { DEBUG_MSG("Object is not valid, skipping"); continue; } // Determine if the object has CKA_PRIVATE set to CK_TRUE bool isPrivateObject = (*it)->getBooleanValue(CKA_PRIVATE, true); // If the object is private, and we are in a public session then skip it ! if (isPublicSession && isPrivateObject) continue; // skip object // Perform the actual attribute matching. bool bAttrMatch = true; // We let an empty template match everything. for (CK_ULONG i=0; iattributeExists(pTemplate[i].type)) break; OSAttribute attr = (*it)->getAttribute(pTemplate[i].type); if (attr.isBooleanAttribute()) { if (sizeof(CK_BBOOL) != pTemplate[i].ulValueLen) break; bool bTemplateValue = (*(CK_BBOOL*)pTemplate[i].pValue == CK_TRUE); if (attr.getBooleanValue() != bTemplateValue) break; } else { if (attr.isUnsignedLongAttribute()) { if (sizeof(CK_ULONG) != pTemplate[i].ulValueLen) break; CK_ULONG ulTemplateValue = *(CK_ULONG_PTR)pTemplate[i].pValue; if (attr.getUnsignedLongValue() != ulTemplateValue) break; } else { if (attr.isByteStringAttribute()) { ByteString bsAttrValue; if (isPrivateObject && attr.getByteStringValue().size() != 0) { if (!token->decrypt(attr.getByteStringValue(), bsAttrValue)) { delete findOp; return CKR_GENERAL_ERROR; } } else bsAttrValue = attr.getByteStringValue(); if (bsAttrValue.size() != pTemplate[i].ulValueLen) break; if (pTemplate[i].ulValueLen != 0) { ByteString bsTemplateValue((const unsigned char*)pTemplate[i].pValue, pTemplate[i].ulValueLen); if (bsAttrValue != bsTemplateValue) break; } } else break; } } // The attribute matched ! bAttrMatch = true; } if (bAttrMatch) { CK_SLOT_ID slotID = slot->getSlotID(); bool isOnToken = (*it)->getBooleanValue(CKA_TOKEN, false); bool isPrivate = (*it)->getBooleanValue(CKA_PRIVATE, true); // Create an object handle for every returned object. CK_OBJECT_HANDLE hObject; if (isOnToken) hObject = handleManager->addTokenObject(slotID,isPrivate,*it); else hObject = handleManager->addSessionObject(slotID,hSession,isPrivate,*it); if (hObject == CK_INVALID_HANDLE) { delete findOp; return CKR_GENERAL_ERROR; } handles.insert(hObject); } } // Storing the object handles for the find will protect the library // whenever a stale object handle is used to access the library. findOp->setHandles(handles); session->setFindOp(findOp); return CKR_OK; } // Continue the search for objects in the specified session CK_RV SoftHSM::C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (phObject == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulObjectCount == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_FIND) return CKR_OPERATION_NOT_INITIALIZED; // return the object handles that have been added to the find operation. FindOperation *findOp = session->getFindOp(); if (findOp == NULL) return CKR_GENERAL_ERROR; // Ask the find operation to retrieve the object handles *pulObjectCount = findOp->retrieveHandles(phObject,ulMaxObjectCount); // Erase the object handles from the find operation. findOp->eraseHandles(0,*pulObjectCount); return CKR_OK; } // Finish searching for objects CK_RV SoftHSM::C_FindObjectsFinal(CK_SESSION_HANDLE hSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_FIND) return CKR_OPERATION_NOT_INITIALIZED; session->resetOp(); return CKR_OK; } // Encrypt*/Decrypt*() is for Symmetrical ciphers too static bool isSymMechanism(CK_MECHANISM_PTR pMechanism) { if (pMechanism == NULL_PTR) return false; switch(pMechanism->mechanism) { case CKM_DES_ECB: case CKM_DES_CBC: case CKM_DES_CBC_PAD: case CKM_DES3_ECB: case CKM_DES3_CBC: case CKM_DES3_CBC_PAD: case CKM_AES_ECB: case CKM_AES_CBC: case CKM_AES_CBC_PAD: case CKM_AES_CTR: case CKM_AES_GCM: return true; default: return false; } } // SymAlgorithm version of C_EncryptInit CK_RV SoftHSM::SymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for encryption if (!key->getBooleanValue(CKA_ENCRYPT, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymMode::Type mode = SymMode::Unknown; bool padding = false; ByteString iv; size_t bb = 8; size_t counterBits = 0; ByteString aad; size_t tagBytes = 0; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_DES_ECB: algo = SymAlgo::DES; mode = SymMode::ECB; bb = 7; break; case CKM_DES_CBC: algo = SymAlgo::DES; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_DES_CBC_PAD: algo = SymAlgo::DES; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; #endif case CKM_DES3_ECB: algo = SymAlgo::DES3; mode = SymMode::ECB; bb = 7; break; case CKM_DES3_CBC: algo = SymAlgo::DES3; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_DES3_CBC_PAD: algo = SymAlgo::DES3; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_AES_ECB: algo = SymAlgo::AES; mode = SymMode::ECB; break; case CKM_AES_CBC: algo = SymAlgo::AES; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); break; case CKM_AES_CBC_PAD: algo = SymAlgo::AES; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); break; case CKM_AES_CTR: algo = SymAlgo::AES; mode = SymMode::CTR; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_AES_CTR_PARAMS)) { DEBUG_MSG("CTR mode requires a counter block"); return CKR_ARGUMENTS_BAD; } counterBits = CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->ulCounterBits; if (counterBits == 0 || counterBits > 128) { DEBUG_MSG("Invalid ulCounterBits"); return CKR_MECHANISM_PARAM_INVALID; } iv.resize(16); memcpy(&iv[0], CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->cb, 16); break; #ifdef WITH_AES_GCM case CKM_AES_GCM: algo = SymAlgo::AES; mode = SymMode::GCM; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_GCM_PARAMS)) { DEBUG_MSG("GCM mode requires parameters"); return CKR_ARGUMENTS_BAD; } iv.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen); memcpy(&iv[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pIv, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen); aad.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); memcpy(&aad[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pAAD, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); tagBytes = CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulTagBits; if (tagBytes > 128 || tagBytes % 8 != 0) { DEBUG_MSG("Invalid ulTagBits value"); return CKR_ARGUMENTS_BAD; } tagBytes = tagBytes / 8; break; #endif default: return CKR_MECHANISM_INVALID; } SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* secretkey = new SymmetricKey(); if (getSymmetricKey(secretkey, token, key) != CKR_OK) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // adjust key bit length secretkey->setBitLen(secretkey->getKeyBits().size() * bb); // Initialize encryption if (!cipher->encryptInit(secretkey, mode, iv, padding, counterBits, aad, tagBytes)) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_ENCRYPT); session->setSymmetricCryptoOp(cipher); session->setAllowMultiPartOp(true); session->setAllowSinglePartOp(true); session->setSymmetricKey(secretkey); return CKR_OK; } // AsymAlgorithm version of C_EncryptInit CK_RV SoftHSM::AsymEncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for encryption if (!key->getBooleanValue(CKA_ENCRYPT, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Get the asymmetric algorithm matching the mechanism AsymMech::Type mechanism; bool isRSA = false; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; isRSA = true; break; case CKM_RSA_X_509: mechanism = AsymMech::RSA; isRSA = true; break; case CKM_RSA_PKCS_OAEP: rv = MechParamCheckRSAPKCSOAEP(pMechanism); if (rv != CKR_OK) return rv; mechanism = AsymMech::RSA_PKCS_OAEP; isRSA = true; break; default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* asymCrypto = NULL; PublicKey* publicKey = NULL; if (isRSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; publicKey = asymCrypto->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getRSAPublicKey((RSAPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } else { return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_ENCRYPT); session->setAsymmetricCryptoOp(asymCrypto); session->setMechanism(mechanism); session->setAllowMultiPartOp(false); session->setAllowSinglePartOp(true); session->setPublicKey(publicKey); return CKR_OK; } // Initialise encryption using the specified object and mechanism CK_RV SoftHSM::C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (isSymMechanism(pMechanism)) return SymEncryptInit(hSession, pMechanism, hKey); else return AsymEncryptInit(hSession, pMechanism, hKey); } // SymAlgorithm version of C_Encrypt static CK_RV SymEncrypt(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowSinglePartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check data size CK_ULONG maxSize = ulDataLen + cipher->getTagBytes(); if (cipher->isBlockCipher()) { CK_ULONG remainder = ulDataLen % cipher->getBlockSize(); if (cipher->getPaddingMode() == false && remainder != 0) { session->resetOp(); return CKR_DATA_LEN_RANGE; } // Round up to block size if (remainder != 0) { maxSize = ulDataLen + cipher->getBlockSize() - remainder; } else if (cipher->getPaddingMode() == true) { maxSize = ulDataLen + cipher->getBlockSize(); } } if (!cipher->checkMaximumBytes(ulDataLen)) { session->resetOp(); return CKR_DATA_LEN_RANGE; } if (pEncryptedData == NULL_PTR) { *pulEncryptedDataLen = maxSize; return CKR_OK; } // Check buffer size if (*pulEncryptedDataLen < maxSize) { *pulEncryptedDataLen = maxSize; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data(pData, ulDataLen); ByteString encryptedData; // Encrypt the data if (!cipher->encryptUpdate(data, encryptedData)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Finalize encryption ByteString encryptedFinal; if (!cipher->encryptFinal(encryptedFinal)) { session->resetOp(); return CKR_GENERAL_ERROR; } encryptedData += encryptedFinal; encryptedData.resize(maxSize); memcpy(pEncryptedData, encryptedData.byte_str(), encryptedData.size()); *pulEncryptedDataLen = encryptedData.size(); session->resetOp(); return CKR_OK; } // AsymAlgorithm version of C_Encrypt static CK_RV AsymEncrypt(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); AsymMech::Type mechanism = session->getMechanism(); PublicKey* publicKey = session->getPublicKey(); if (asymCrypto == NULL || !session->getAllowSinglePartOp() || publicKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the encrypted data CK_ULONG size = publicKey->getOutputLength(); if (pEncryptedData == NULL_PTR) { *pulEncryptedDataLen = size; return CKR_OK; } // Check buffer size if (*pulEncryptedDataLen < size) { *pulEncryptedDataLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data; ByteString encryptedData; // We must allow input length <= k and therfore need to prepend the data with zeroes. if (mechanism == AsymMech::RSA) { data.wipe(size-ulDataLen); } data += ByteString(pData, ulDataLen); // Encrypt the data if (!asymCrypto->encrypt(publicKey,data,encryptedData,mechanism)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (encryptedData.size() != size) { ERROR_MSG("The size of the encrypted data differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pEncryptedData, encryptedData.byte_str(), size); *pulEncryptedDataLen = size; session->resetOp(); return CKR_OK; } // Perform a single operation encryption operation in the specified session CK_RV SoftHSM::C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulEncryptedDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_ENCRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymEncrypt(session, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); else return AsymEncrypt(session, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); } // SymAlgorithm version of C_EncryptUpdate static CK_RV SymEncryptUpdate(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check data size size_t blockSize = cipher->getBlockSize(); size_t remainingSize = cipher->getBufferSize(); CK_ULONG maxSize = ulDataLen + remainingSize; if (cipher->isBlockCipher()) { int nrOfBlocks = (ulDataLen + remainingSize) / blockSize; maxSize = nrOfBlocks * blockSize; } if (!cipher->checkMaximumBytes(ulDataLen)) { session->resetOp(); return CKR_DATA_LEN_RANGE; } // Check data size if (pEncryptedData == NULL_PTR) { *pulEncryptedDataLen = maxSize; return CKR_OK; } // Check output buffer size if (*pulEncryptedDataLen < maxSize) { DEBUG_MSG("ulDataLen: %#5x output buffer size: %#5x blockSize: %#3x remainingSize: %#4x maxSize: %#5x", ulDataLen, *pulEncryptedDataLen, blockSize, remainingSize, maxSize); *pulEncryptedDataLen = maxSize; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data(pData, ulDataLen); ByteString encryptedData; // Encrypt the data if (!cipher->encryptUpdate(data, encryptedData)) { session->resetOp(); return CKR_GENERAL_ERROR; } DEBUG_MSG("ulDataLen: %#5x output buffer size: %#5x blockSize: %#3x remainingSize: %#4x maxSize: %#5x encryptedData.size(): %#5x", ulDataLen, *pulEncryptedDataLen, blockSize, remainingSize, maxSize, encryptedData.size()); // Check output size from crypto. Unrecoverable error if to large. if (*pulEncryptedDataLen < encryptedData.size()) { session->resetOp(); ERROR_MSG("EncryptUpdate returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.", *pulEncryptedDataLen, encryptedData.size()); return CKR_GENERAL_ERROR; } if (encryptedData.size() > 0) { memcpy(pEncryptedData, encryptedData.byte_str(), encryptedData.size()); } *pulEncryptedDataLen = encryptedData.size(); return CKR_OK; } // Feed data to the running encryption operation in a session CK_RV SoftHSM::C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulEncryptedDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_ENCRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymEncryptUpdate(session, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); else return CKR_FUNCTION_NOT_SUPPORTED; } // SymAlgorithm version of C_EncryptFinal static CK_RV SymEncryptFinal(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check data size size_t remainingSize = cipher->getBufferSize() + cipher->getTagBytes(); CK_ULONG size = remainingSize; if (cipher->isBlockCipher()) { size_t blockSize = cipher->getBlockSize(); bool isPadding = cipher->getPaddingMode(); if ((remainingSize % blockSize) != 0 && !isPadding) { session->resetOp(); DEBUG_MSG("Remaining buffer size is not an integral of the block size. Block size: %#2x Remaining size: %#2x", blockSize, remainingSize); return CKR_DATA_LEN_RANGE; } // when padding: an integral of the block size that is longer than the remaining data. size = isPadding ? ((remainingSize + blockSize) / blockSize) * blockSize : remainingSize; } // Give required output buffer size. if (pEncryptedData == NULL_PTR) { *pulEncryptedDataLen = size; return CKR_OK; } // Check output buffer size if (*pulEncryptedDataLen < size) { DEBUG_MSG("output buffer size: %#5x size: %#5x", *pulEncryptedDataLen, size); *pulEncryptedDataLen = size; return CKR_BUFFER_TOO_SMALL; } // Finalize encryption ByteString encryptedFinal; if (!cipher->encryptFinal(encryptedFinal)) { session->resetOp(); return CKR_GENERAL_ERROR; } DEBUG_MSG("output buffer size: %#2x size: %#2x encryptedFinal.size(): %#2x", *pulEncryptedDataLen, size, encryptedFinal.size()); // Check output size from crypto. Unrecoverable error if to large. if (*pulEncryptedDataLen < encryptedFinal.size()) { session->resetOp(); ERROR_MSG("EncryptFinal returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.", *pulEncryptedDataLen, encryptedFinal.size()); return CKR_GENERAL_ERROR; } if (encryptedFinal.size() > 0) { memcpy(pEncryptedData, encryptedFinal.byte_str(), encryptedFinal.size()); } *pulEncryptedDataLen = encryptedFinal.size(); session->resetOp(); return CKR_OK; } // Finalise the encryption operation CK_RV SoftHSM::C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_ENCRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymEncryptFinal(session, pEncryptedData, pulEncryptedDataLen); else return CKR_FUNCTION_NOT_SUPPORTED; } // SymAlgorithm version of C_DecryptInit CK_RV SoftHSM::SymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // 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; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for decryption if (!key->getBooleanValue(CKA_DECRYPT, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymMode::Type mode = SymMode::Unknown; bool padding = false; ByteString iv; size_t bb = 8; size_t counterBits = 0; ByteString aad; size_t tagBytes = 0; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_DES_ECB: algo = SymAlgo::DES; mode = SymMode::ECB; bb = 7; break; case CKM_DES_CBC: algo = SymAlgo::DES; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_DES_CBC_PAD: algo = SymAlgo::DES; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; #endif case CKM_DES3_ECB: algo = SymAlgo::DES3; mode = SymMode::ECB; bb = 7; break; case CKM_DES3_CBC: algo = SymAlgo::DES3; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_DES3_CBC_PAD: algo = SymAlgo::DES3; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); bb = 7; break; case CKM_AES_ECB: algo = SymAlgo::AES; mode = SymMode::ECB; break; case CKM_AES_CBC: algo = SymAlgo::AES; mode = SymMode::CBC; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); break; case CKM_AES_CBC_PAD: algo = SymAlgo::AES; mode = SymMode::CBC; padding = true; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen == 0) { DEBUG_MSG("CBC mode requires an init vector"); return CKR_ARGUMENTS_BAD; } iv.resize(pMechanism->ulParameterLen); memcpy(&iv[0], pMechanism->pParameter, pMechanism->ulParameterLen); break; case CKM_AES_CTR: algo = SymAlgo::AES; mode = SymMode::CTR; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_AES_CTR_PARAMS)) { DEBUG_MSG("CTR mode requires a counter block"); return CKR_ARGUMENTS_BAD; } counterBits = CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->ulCounterBits; if (counterBits == 0 || counterBits > 128) { DEBUG_MSG("Invalid ulCounterBits"); return CKR_MECHANISM_PARAM_INVALID; } iv.resize(16); memcpy(&iv[0], CK_AES_CTR_PARAMS_PTR(pMechanism->pParameter)->cb, 16); break; #ifdef WITH_AES_GCM case CKM_AES_GCM: algo = SymAlgo::AES; mode = SymMode::GCM; if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_GCM_PARAMS)) { DEBUG_MSG("GCM mode requires parameters"); return CKR_ARGUMENTS_BAD; } iv.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen); memcpy(&iv[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pIv, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulIvLen); aad.resize(CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); memcpy(&aad[0], CK_GCM_PARAMS_PTR(pMechanism->pParameter)->pAAD, CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulAADLen); tagBytes = CK_GCM_PARAMS_PTR(pMechanism->pParameter)->ulTagBits; if (tagBytes > 128 || tagBytes % 8 != 0) { DEBUG_MSG("Invalid ulTagBits value"); return CKR_ARGUMENTS_BAD; } tagBytes = tagBytes / 8; break; #endif default: return CKR_MECHANISM_INVALID; } SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* secretkey = new SymmetricKey(); if (getSymmetricKey(secretkey, token, key) != CKR_OK) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // adjust key bit length secretkey->setBitLen(secretkey->getKeyBits().size() * bb); // Initialize decryption if (!cipher->decryptInit(secretkey, mode, iv, padding, counterBits, aad, tagBytes)) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_DECRYPT); session->setSymmetricCryptoOp(cipher); session->setAllowMultiPartOp(true); session->setAllowSinglePartOp(true); session->setSymmetricKey(secretkey); return CKR_OK; } // AsymAlgorithm version of C_DecryptInit CK_RV SoftHSM::AsymDecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // 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; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for decryption if (!key->getBooleanValue(CKA_DECRYPT, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get the asymmetric algorithm matching the mechanism AsymMech::Type mechanism = AsymMech::Unknown; bool isRSA = false; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; isRSA = true; break; case CKM_RSA_X_509: mechanism = AsymMech::RSA; isRSA = true; break; case CKM_RSA_PKCS_OAEP: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { DEBUG_MSG("pParameter must be of type CK_RSA_PKCS_OAEP_PARAMS"); return CKR_ARGUMENTS_BAD; } if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1) { DEBUG_MSG("hashAlg must be CKM_SHA_1"); return CKR_ARGUMENTS_BAD; } if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1) { DEBUG_MSG("mgf must be CKG_MGF1_SHA1"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_PKCS_OAEP; isRSA = true; break; default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* asymCrypto = NULL; PrivateKey* privateKey = NULL; if (isRSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key) != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } else { return CKR_MECHANISM_INVALID; } // Check if re-authentication is required if (key->getBooleanValue(CKA_ALWAYS_AUTHENTICATE, false)) { session->setReAuthentication(true); } session->setOpType(SESSION_OP_DECRYPT); session->setAsymmetricCryptoOp(asymCrypto); session->setMechanism(mechanism); session->setAllowMultiPartOp(false); session->setAllowSinglePartOp(true); session->setPrivateKey(privateKey); return CKR_OK; } // Initialise decryption using the specified object CK_RV SoftHSM::C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (isSymMechanism(pMechanism)) return SymDecryptInit(hSession, pMechanism, hKey); else return AsymDecryptInit(hSession, pMechanism, hKey); } // SymAlgorithm version of C_Decrypt static CK_RV SymDecrypt(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowSinglePartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check encrypted data size if (cipher->isBlockCipher() && ulEncryptedDataLen % cipher->getBlockSize() != 0) { session->resetOp(); return CKR_ENCRYPTED_DATA_LEN_RANGE; } if (!cipher->checkMaximumBytes(ulEncryptedDataLen)) { session->resetOp(); return CKR_ENCRYPTED_DATA_LEN_RANGE; } if (pData == NULL_PTR) { *pulDataLen = ulEncryptedDataLen; return CKR_OK; } // Check buffer size if (*pulDataLen < ulEncryptedDataLen) { *pulDataLen = ulEncryptedDataLen; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString encryptedData(pEncryptedData, ulEncryptedDataLen); ByteString data; // Decrypt the data if (!cipher->decryptUpdate(encryptedData,data)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Finalize decryption ByteString dataFinal; if (!cipher->decryptFinal(dataFinal)) { session->resetOp(); return CKR_GENERAL_ERROR; } data += dataFinal; if (data.size() > ulEncryptedDataLen) { data.resize(ulEncryptedDataLen); } if (data.size() != 0) { memcpy(pData, data.byte_str(), data.size()); } *pulDataLen = data.size(); session->resetOp(); return CKR_OK; } // AsymAlgorithm version of C_Decrypt static CK_RV AsymDecrypt(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); AsymMech::Type mechanism = session->getMechanism(); PrivateKey* privateKey = session->getPrivateKey(); if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Size of the data CK_ULONG size = privateKey->getOutputLength(); if (pData == NULL_PTR) { *pulDataLen = size; return CKR_OK; } // Check buffer size if (*pulDataLen < size) { *pulDataLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString encryptedData(pEncryptedData, ulEncryptedDataLen); ByteString data; // Decrypt the data if (!asymCrypto->decrypt(privateKey,encryptedData,data,mechanism)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (data.size() > size) { ERROR_MSG("The size of the decrypted data exceeds the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } if (data.size() != 0) { memcpy(pData, data.byte_str(), data.size()); } *pulDataLen = data.size(); session->resetOp(); return CKR_OK; } // Perform a single operation decryption in the given session CK_RV SoftHSM::C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pEncryptedData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DECRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymDecrypt(session, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); else return AsymDecrypt(session, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); } // SymAlgorithm version of C_DecryptUpdate static CK_RV SymDecryptUpdate(Session* session, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check encrypted data size size_t blockSize = cipher->getBlockSize(); size_t remainingSize = cipher->getBufferSize(); CK_ULONG maxSize = ulEncryptedDataLen + remainingSize; if (cipher->isBlockCipher()) { // There must always be one block left in padding mode if next operation is DecryptFinal. // To guarantee that one byte is removed in padding mode when the number of blocks is calculated. size_t paddingAdjustByte = cipher->getPaddingMode() ? 1 : 0; int nrOfBlocks = (ulEncryptedDataLen + remainingSize - paddingAdjustByte) / blockSize; maxSize = nrOfBlocks * blockSize; } if (!cipher->checkMaximumBytes(ulEncryptedDataLen)) { session->resetOp(); return CKR_ENCRYPTED_DATA_LEN_RANGE; } // Give required output buffer size. if (pData == NULL_PTR) { *pDataLen = maxSize; return CKR_OK; } // Check output buffer size if (*pDataLen < maxSize) { DEBUG_MSG("Output buffer too short ulEncryptedDataLen: %#5x output buffer size: %#5x blockSize: %#3x remainingSize: %#4x maxSize: %#5x", ulEncryptedDataLen, *pDataLen, blockSize, remainingSize, maxSize); *pDataLen = maxSize; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data(pEncryptedData, ulEncryptedDataLen); ByteString decryptedData; // Encrypt the data if (!cipher->decryptUpdate(data, decryptedData)) { session->resetOp(); return CKR_GENERAL_ERROR; } DEBUG_MSG("ulEncryptedDataLen: %#5x output buffer size: %#5x blockSize: %#3x remainingSize: %#4x maxSize: %#5x decryptedData.size(): %#5x", ulEncryptedDataLen, *pDataLen, blockSize, remainingSize, maxSize, decryptedData.size()); // Check output size from crypto. Unrecoverable error if to large. if (*pDataLen < decryptedData.size()) { session->resetOp(); ERROR_MSG("DecryptUpdate returning too much data. Length of output data buffer is %i but %i bytes was returned by the decrypt.", *pDataLen, decryptedData.size()); return CKR_GENERAL_ERROR; } if (decryptedData.size() > 0) { memcpy(pData, decryptedData.byte_str(), decryptedData.size()); } *pDataLen = decryptedData.size(); return CKR_OK; } // Feed data to the running decryption operation in a session CK_RV SoftHSM::C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pEncryptedData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pDataLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DECRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymDecryptUpdate(session, pEncryptedData, ulEncryptedDataLen, pData, pDataLen); else return CKR_FUNCTION_NOT_SUPPORTED; } static CK_RV SymDecryptFinal(Session* session, CK_BYTE_PTR pDecryptedData, CK_ULONG_PTR pulDecryptedDataLen) { SymmetricAlgorithm* cipher = session->getSymmetricCryptoOp(); if (cipher == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check encrypted data size size_t remainingSize = cipher->getBufferSize(); CK_ULONG size = remainingSize; if (cipher->isBlockCipher()) { size_t blockSize = cipher->getBlockSize(); if (remainingSize % blockSize != 0) { session->resetOp(); DEBUG_MSG("Remaining data length is not an integral of the block size. Block size: %#2x Remaining size: %#2x", blockSize, remainingSize); return CKR_ENCRYPTED_DATA_LEN_RANGE; } // It is at least one padding byte. If no padding the all remains will be returned. size_t paddingAdjustByte = cipher->getPaddingMode() ? 1 : 0; size = remainingSize - paddingAdjustByte; } // Give required output buffer size. if (pDecryptedData == NULL_PTR) { *pulDecryptedDataLen = size; return CKR_OK; } // Check output buffer size if (*pulDecryptedDataLen < size) { DEBUG_MSG("output buffer size: %#5x size: %#5x", *pulDecryptedDataLen, size); *pulDecryptedDataLen = size; return CKR_BUFFER_TOO_SMALL; } // Finalize decryption ByteString decryptedFinal; if (!cipher->decryptFinal(decryptedFinal)) { session->resetOp(); return CKR_GENERAL_ERROR; } DEBUG_MSG("output buffer size: %#2x size: %#2x decryptedFinal.size(): %#2x", *pulDecryptedDataLen, size, decryptedFinal.size()); // Check output size from crypto. Unrecoverable error if to large. if (*pulDecryptedDataLen < decryptedFinal.size()) { session->resetOp(); ERROR_MSG("DecryptFinal returning too much data. Length of output data buffer is %i but %i bytes was returned by the encrypt.", *pulDecryptedDataLen, decryptedFinal.size()); return CKR_GENERAL_ERROR; } if (decryptedFinal.size() > 0) { memcpy(pDecryptedData, decryptedFinal.byte_str(), decryptedFinal.size()); } *pulDecryptedDataLen = decryptedFinal.size(); session->resetOp(); return CKR_OK; } // Finalise the decryption operation CK_RV SoftHSM::C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG_PTR pDataLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DECRYPT) return CKR_OPERATION_NOT_INITIALIZED; if (session->getSymmetricCryptoOp() != NULL) return SymDecryptFinal(session, pData, pDataLen); else return CKR_FUNCTION_NOT_SUPPORTED; } // Initialise digesting using the specified mechanism in the specified session CK_RV SoftHSM::C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the mechanism HashAlgo::Type algo = HashAlgo::Unknown; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_MD5: algo = HashAlgo::MD5; break; #endif case CKM_SHA_1: algo = HashAlgo::SHA1; break; case CKM_SHA224: algo = HashAlgo::SHA224; break; case CKM_SHA256: algo = HashAlgo::SHA256; break; case CKM_SHA384: algo = HashAlgo::SHA384; break; case CKM_SHA512: algo = HashAlgo::SHA512; break; #ifdef WITH_GOST case CKM_GOSTR3411: algo = HashAlgo::GOST; break; #endif default: return CKR_MECHANISM_INVALID; } HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(algo); if (hash == NULL) return CKR_MECHANISM_INVALID; // Initialize hashing if (hash->hashInit() == false) { CryptoFactory::i()->recycleHashAlgorithm(hash); return CKR_GENERAL_ERROR; } session->setOpType(SESSION_OP_DIGEST); session->setDigestOp(hash); session->setHashAlgo(algo); return CKR_OK; } // Digest the specified data in a one-pass operation and return the resulting digest CK_RV SoftHSM::C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pulDigestLen == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED; // Return size CK_ULONG size = session->getDigestOp()->getHashSize(); if (pDigest == NULL_PTR) { *pulDigestLen = size; return CKR_OK; } // Check buffer size if (*pulDigestLen < size) { *pulDigestLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data(pData, ulDataLen); // Digest the data if (session->getDigestOp()->hashUpdate(data) == false) { session->resetOp(); return CKR_GENERAL_ERROR; } // Get the digest ByteString digest; if (session->getDigestOp()->hashFinal(digest) == false) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (digest.size() != size) { ERROR_MSG("The size of the digest differ from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pDigest, digest.byte_str(), size); *pulDigestLen = size; session->resetOp(); return CKR_OK; } // Update a running digest operation CK_RV SoftHSM::C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED; // Get the data ByteString data(pPart, ulPartLen); // Digest the data if (session->getDigestOp()->hashUpdate(data) == false) { session->resetOp(); return CKR_GENERAL_ERROR; } return CKR_OK; } // Update a running digest operation by digesting a secret key with the specified handle CK_RV SoftHSM::C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hObject); if (key == NULL_PTR || !key->isValid()) return CKR_KEY_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); // CKR_USER_NOT_LOGGED_IN is not a valid return code for this function, // so we use CKR_GENERAL_ERROR. return CKR_GENERAL_ERROR; } // Whitelist HashAlgo::Type algo = session->getHashAlgo(); if (algo != HashAlgo::SHA1 && algo != HashAlgo::SHA224 && algo != HashAlgo::SHA256 && algo != HashAlgo::SHA384 && algo != HashAlgo::SHA512) { // Parano... if (!key->getBooleanValue(CKA_EXTRACTABLE, false)) return CKR_KEY_INDIGESTIBLE; if (key->getBooleanValue(CKA_SENSITIVE, false)) return CKR_KEY_INDIGESTIBLE; } // Get value if (!key->attributeExists(CKA_VALUE)) return CKR_KEY_INDIGESTIBLE; ByteString keybits; if (isPrivate) { if (!token->decrypt(key->getByteStringValue(CKA_VALUE), keybits)) return CKR_GENERAL_ERROR; } else { keybits = key->getByteStringValue(CKA_VALUE); } // Digest the value if (session->getDigestOp()->hashUpdate(keybits) == false) { session->resetOp(); return CKR_GENERAL_ERROR; } return CKR_OK; } // Finalise the digest operation in the specified session and return the digest CK_RV SoftHSM::C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pulDigestLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_DIGEST) return CKR_OPERATION_NOT_INITIALIZED; // Return size CK_ULONG size = session->getDigestOp()->getHashSize(); if (pDigest == NULL_PTR) { *pulDigestLen = size; return CKR_OK; } // Check buffer size if (*pulDigestLen < size) { *pulDigestLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the digest ByteString digest; if (session->getDigestOp()->hashFinal(digest) == false) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (digest.size() != size) { ERROR_MSG("The size of the digest differ from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pDigest, digest.byte_str(), size); *pulDigestLen = size; session->resetOp(); return CKR_OK; } // Sign*/Verify*() is for MACs too static bool isMacMechanism(CK_MECHANISM_PTR pMechanism) { if (pMechanism == NULL_PTR) return false; switch(pMechanism->mechanism) { case CKM_MD5_HMAC: case CKM_SHA_1_HMAC: case CKM_SHA224_HMAC: case CKM_SHA256_HMAC: case CKM_SHA384_HMAC: case CKM_SHA512_HMAC: #ifdef WITH_GOST case CKM_GOSTR3411_HMAC: #endif case CKM_DES3_CMAC: case CKM_AES_CMAC: return true; default: return false; } } // MacAlgorithm version of C_SignInit CK_RV SoftHSM::MacSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for signing if (!key->getBooleanValue(CKA_SIGN, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get key info CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED); // Get the MAC algorithm matching the mechanism // Also check mechanism constraints MacAlgo::Type algo = MacAlgo::Unknown; size_t bb = 8; size_t minSize = 0; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_MD5_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_MD5_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 16; algo = MacAlgo::HMAC_MD5; break; #endif case CKM_SHA_1_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA_1_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 20; algo = MacAlgo::HMAC_SHA1; break; case CKM_SHA224_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA224_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 28; algo = MacAlgo::HMAC_SHA224; break; case CKM_SHA256_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA256_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 32; algo = MacAlgo::HMAC_SHA256; break; case CKM_SHA384_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA384_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 48; algo = MacAlgo::HMAC_SHA384; break; case CKM_SHA512_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA512_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 64; algo = MacAlgo::HMAC_SHA512; break; #ifdef WITH_GOST case CKM_GOSTR3411_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_GOST28147) return CKR_KEY_TYPE_INCONSISTENT; minSize = 32; algo = MacAlgo::HMAC_GOST; break; #endif case CKM_DES3_CMAC: if (keyType != CKK_DES2 && keyType != CKK_DES3) return CKR_KEY_TYPE_INCONSISTENT; algo = MacAlgo::CMAC_DES; bb = 7; break; case CKM_AES_CMAC: if (keyType != CKK_AES) return CKR_KEY_TYPE_INCONSISTENT; algo = MacAlgo::CMAC_AES; break; default: return CKR_MECHANISM_INVALID; } MacAlgorithm* mac = CryptoFactory::i()->getMacAlgorithm(algo); if (mac == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* privkey = new SymmetricKey(); if (getSymmetricKey(privkey, token, key) != CKR_OK) { mac->recycleKey(privkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_GENERAL_ERROR; } // Adjust key bit length privkey->setBitLen(privkey->getKeyBits().size() * bb); // Check key size if (privkey->getBitLen() < (minSize*8)) { mac->recycleKey(privkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_KEY_SIZE_RANGE; } // Initialize signing if (!mac->signInit(privkey)) { mac->recycleKey(privkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_SIGN); session->setMacOp(mac); session->setAllowMultiPartOp(true); session->setAllowSinglePartOp(true); session->setSymmetricKey(privkey); return CKR_OK; } // AsymmetricAlgorithm version of C_SignInit CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for signing if (!key->getBooleanValue(CKA_SIGN, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get the asymmetric algorithm matching the mechanism AsymMech::Type mechanism = AsymMech::Unknown; void* param = NULL; size_t paramLen = 0; RSA_PKCS_PSS_PARAMS pssParam; bool bAllowMultiPartOp; bool isRSA = false; bool isDSA = false; bool isECDSA = false; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; bAllowMultiPartOp = false; isRSA = true; break; case CKM_RSA_X_509: mechanism = AsymMech::RSA; bAllowMultiPartOp = false; isRSA = true; break; #ifndef WITH_FIPS case CKM_MD5_RSA_PKCS: mechanism = AsymMech::RSA_MD5_PKCS; bAllowMultiPartOp = true; isRSA = true; break; #endif case CKM_SHA1_RSA_PKCS: mechanism = AsymMech::RSA_SHA1_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA224_RSA_PKCS: mechanism = AsymMech::RSA_SHA224_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA256_RSA_PKCS: mechanism = AsymMech::RSA_SHA256_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA384_RSA_PKCS: mechanism = AsymMech::RSA_SHA384_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA512_RSA_PKCS: mechanism = AsymMech::RSA_SHA512_PKCS; bAllowMultiPartOp = true; isRSA = true; break; #ifdef WITH_RAW_PSS case CKM_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { ERROR_MSG("Invalid RSA-PSS parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_PKCS_PSS; unsigned long allowedMgf; switch(CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg) { case CKM_SHA_1: pssParam.hashAlg = HashAlgo::SHA1; pssParam.mgf = AsymRSAMGF::MGF1_SHA1; allowedMgf = CKG_MGF1_SHA1; break; case CKM_SHA224: pssParam.hashAlg = HashAlgo::SHA224; pssParam.mgf = AsymRSAMGF::MGF1_SHA224; allowedMgf = CKG_MGF1_SHA224; break; case CKM_SHA256: pssParam.hashAlg = HashAlgo::SHA256; pssParam.mgf = AsymRSAMGF::MGF1_SHA256; allowedMgf = CKG_MGF1_SHA256; break; case CKM_SHA384: pssParam.hashAlg = HashAlgo::SHA384; pssParam.mgf = AsymRSAMGF::MGF1_SHA384; allowedMgf = CKG_MGF1_SHA384; break; case CKM_SHA512: pssParam.hashAlg = HashAlgo::SHA512; pssParam.mgf = AsymRSAMGF::MGF1_SHA512; allowedMgf = CKG_MGF1_SHA512; break; default: ERROR_MSG("Invalid RSA-PSS hash"); return CKR_ARGUMENTS_BAD; } if (CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != allowedMgf) { ERROR_MSG("Hash and MGF don't match"); return CKR_ARGUMENTS_BAD; } pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = false; isRSA = true; break; #endif case CKM_SHA1_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA1_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA1; pssParam.mgf = AsymRSAMGF::MGF1_SHA1; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA224_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA224 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA224) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA224_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA224; pssParam.mgf = AsymRSAMGF::MGF1_SHA224; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA256_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA256 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA256) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA256_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA256; pssParam.mgf = AsymRSAMGF::MGF1_SHA256; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA384_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA384 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA384) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA384_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA384; pssParam.mgf = AsymRSAMGF::MGF1_SHA384; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA512_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA512 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA512) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA512_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA512; pssParam.mgf = AsymRSAMGF::MGF1_SHA512; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_DSA: mechanism = AsymMech::DSA; bAllowMultiPartOp = false; isDSA = true; break; case CKM_DSA_SHA1: mechanism = AsymMech::DSA_SHA1; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA224: mechanism = AsymMech::DSA_SHA224; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA256: mechanism = AsymMech::DSA_SHA256; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA384: mechanism = AsymMech::DSA_SHA384; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA512: mechanism = AsymMech::DSA_SHA512; bAllowMultiPartOp = true; isDSA = true; break; #ifdef WITH_ECC case CKM_ECDSA: mechanism = AsymMech::ECDSA; bAllowMultiPartOp = false; isECDSA = true; break; #endif #ifdef WITH_GOST case CKM_GOSTR3410: mechanism = AsymMech::GOST; bAllowMultiPartOp = false; break; case CKM_GOSTR3410_WITH_GOSTR3411: mechanism = AsymMech::GOST_GOST; bAllowMultiPartOp = true; break; #endif default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* asymCrypto = NULL; PrivateKey* privateKey = NULL; if (isRSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key) != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } else if (isDSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getDSAPrivateKey((DSAPrivateKey*)privateKey, token, key) != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } #ifdef WITH_ECC else if (isECDSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getECPrivateKey((ECPrivateKey*)privateKey, token, key) != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } #endif else { #ifdef WITH_GOST asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getGOSTPrivateKey((GOSTPrivateKey*)privateKey, token, key) != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } #else return CKR_MECHANISM_INVALID; #endif } // Initialize signing if(isHWavailable) { // Extract HW key handle CK_ULONG hwKeyHandle = 0; if(Extract_key_handle (hSession, hKey, &hwKeyHandle) != CKR_OK) { LOG("ERROR in extracting key handle \n"); session->resetOp(); return CKR_GENERAL_ERROR; } LOG("Extracted key handle value: %lu \n", hwKeyHandle); void *hwCryptoOpaque; if(HwInfraSignInit(&hwKeyHandle, mechanism, param, paramLen, &hwCryptoOpaque) != 0) { return CKR_MECHANISM_INVALID; } session->setHwCryptoOpaque(hwCryptoOpaque); } else { if (bAllowMultiPartOp && !asymCrypto->signInit(privateKey,mechanism,param,paramLen)) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_MECHANISM_INVALID; } } session->setOpType(SESSION_OP_SIGN); session->setAsymmetricCryptoOp(asymCrypto); session->setMechanism(mechanism); session->setParameters(param, paramLen); session->setAllowMultiPartOp(bAllowMultiPartOp); session->setAllowSinglePartOp(true); session->setPrivateKey(privateKey); session->setKeyHandle(hKey); return CKR_OK; } // Initialise a signing operation using the specified key and mechanism CK_RV SoftHSM::C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (isMacMechanism(pMechanism)) return MacSignInit(hSession, pMechanism, hKey); else return AsymSignInit(hSession, pMechanism, hKey); } // MacAlgorithm version of C_Sign static CK_RV MacSign(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL || !session->getAllowSinglePartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = mac->getMacSize(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer size if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data(pData, ulDataLen); // Sign the data if (!mac->signUpdate(data)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Get the signature ByteString signature; if (!mac->signFinal(signature)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (signature.size() != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pSignature, signature.byte_str(), size); *pulSignatureLen = size; session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_Sign static CK_RV AsymSign(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); AsymMech::Type mechanism = session->getMechanism(); PrivateKey* privateKey = session->getPrivateKey(); size_t paramLen; void* param = session->getParameters(paramLen); if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Size of the signature CK_ULONG size = privateKey->getOutputLength(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer size if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data; // We must allow input length <= k and therfore need to prepend the data with zeroes. if (mechanism == AsymMech::RSA) { data.wipe(size-ulDataLen); } data += ByteString(pData, ulDataLen); ByteString signature; // Sign the data if (session->getAllowMultiPartOp()) { if (!asymCrypto->signUpdate(data) || !asymCrypto->signFinal(signature)) { session->resetOp(); return CKR_GENERAL_ERROR; } } else if (!asymCrypto->sign(privateKey,data,signature,mechanism,param,paramLen)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (signature.size() != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pSignature, signature.byte_str(), size); *pulSignatureLen = size; session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_Sign static CK_RV AsymSignHW(CK_SESSION_HANDLE hSession, Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); AsymMech::Type mechanism = session->getMechanism(); PrivateKey* privateKey = session->getPrivateKey(); CK_ULONG hwKeyHandle = 0; if (asymCrypto == NULL || !session->getAllowSinglePartOp() || privateKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = privateKey->getOutputLength(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer sizeq if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the data ByteString data; // We must allow input length <= k and therfore need to prepend the data with zeroes. if (mechanism == AsymMech::RSA) { data.wipe(size-ulDataLen); } data += ByteString(pData, ulDataLen); ByteString signature; // Extract HW key handle CK_OBJECT_HANDLE hKey = session->getKeyHandle(); if(Extract_key_handle (hSession, hKey, &hwKeyHandle) != CKR_OK) { LOG("ERROR in extracting key handle \n"); session->resetOp(); return CKR_GENERAL_ERROR; } LOG("Extracted key handle value: %lu \n", hwKeyHandle); void *hwCryptoOpaque = session->getHwCryptoOpaque(); // Sign the data if(HwInfraSign((void *)&hwKeyHandle, mechanism, pData, ulDataLen, hwCryptoOpaque, pSignature, (int *) pulSignatureLen) != 0) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (*pulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } session->resetOp(); return CKR_OK; } // Sign the data in a single pass operation CK_RV SoftHSM::C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulSignatureLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_SIGN) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacSign(session, pData, ulDataLen, pSignature, pulSignatureLen); else { if(isHWavailable) { return AsymSignHW(hSession, session, pData, ulDataLen, pSignature, pulSignatureLen); } else { return AsymSign(session, pData, ulDataLen, pSignature, pulSignatureLen); } } } // MacAlgorithm version of C_SignUpdate static CK_RV MacSignUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Get the part ByteString part(pPart, ulPartLen); // Sign the data if (!mac->signUpdate(part)) { session->resetOp(); return CKR_GENERAL_ERROR; } session->setAllowSinglePartOp(false); return CKR_OK; } // AsymmetricAlgorithm version of C_SignUpdate static CK_RV AsymSignUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); if (asymCrypto == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Get the part ByteString part(pPart, ulPartLen); // Sign the data if (!asymCrypto->signUpdate(part)) { session->resetOp(); return CKR_GENERAL_ERROR; } session->setAllowSinglePartOp(false); return CKR_OK; } // AsymmetricAlgorithm version of C_SignUpdate static CK_RV AsymSignUpdateHW( CK_SESSION_HANDLE hSession, Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); if (asymCrypto == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Get the part ByteString part(pPart, ulPartLen); #if 0 // Sign the data if (!asymCrypto->signUpdate(part)) { session->resetOp(); return CKR_GENERAL_ERROR; } #endif AsymMech::Type mechanism = session->getMechanism(); // Extract HW key handle CK_ULONG hwKeyHandle = 0; CK_OBJECT_HANDLE hKey = session->getKeyHandle(); if(Extract_key_handle (hSession, hKey, &hwKeyHandle) != CKR_OK) { LOG("ERROR in extracting key handle \n"); session->resetOp(); return CKR_GENERAL_ERROR; } void *hwCryptoOpaque = session->getHwCryptoOpaque(); // Sign the data if(HwInfraSignUpdate((void *)&hwKeyHandle, mechanism, pPart, ulPartLen, hwCryptoOpaque ) != 0) { session->resetOp(); return CKR_GENERAL_ERROR; } session->setAllowSinglePartOp(false); return CKR_OK; } // Update a running signing operation with additional data CK_RV SoftHSM::C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_SIGN) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacSignUpdate(session, pPart, ulPartLen); else { if(isHWavailable) { return AsymSignUpdateHW(hSession, session, pPart, ulPartLen); } else { return AsymSignUpdate(session, pPart, ulPartLen); } } } // MacAlgorithm version of C_SignFinal static CK_RV MacSignFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = mac->getMacSize(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer size if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the signature ByteString signature; if (!mac->signFinal(signature)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (signature.size() != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pSignature, signature.byte_str(), size); *pulSignatureLen = size; session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_SignFinal static CK_RV AsymSignFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); PrivateKey* privateKey = session->getPrivateKey(); if (asymCrypto == NULL || privateKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Size of the signature CK_ULONG size = privateKey->getOutputLength(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer size if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } // Get the signature ByteString signature; if (!asymCrypto->signFinal(signature)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (signature.size() != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } memcpy(pSignature, signature.byte_str(), size); *pulSignatureLen = size; session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_SignFinal static CK_RV AsymSignFinalHW(CK_SESSION_HANDLE hSession, Session* session, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); PrivateKey* privateKey = session->getPrivateKey(); if (asymCrypto == NULL || privateKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Check if re-authentication is required if (session->getReAuthentication()) { session->resetOp(); return CKR_USER_NOT_LOGGED_IN; } // Size of the signature CK_ULONG size = privateKey->getOutputLength(); if (pSignature == NULL_PTR) { *pulSignatureLen = size; return CKR_OK; } // Check buffer size if (*pulSignatureLen < size) { *pulSignatureLen = size; return CKR_BUFFER_TOO_SMALL; } #if 0 // Get the signature ByteString signature; if (!asymCrypto->signFinal(signature)) { session->resetOp(); return CKR_GENERAL_ERROR; } #endif AsymMech::Type mechanism = session->getMechanism(); // Extract HW key handle CK_ULONG hwKeyHandle = 0; CK_OBJECT_HANDLE hKey = session->getKeyHandle(); if(Extract_key_handle (hSession, hKey, &hwKeyHandle) != CKR_OK) { LOG("ERROR in extracting key handle \n"); session->resetOp(); return CKR_GENERAL_ERROR; } LOG("Extracted key handle value : 0x%lx \n", hwKeyHandle); void *hwCryptoOpaque = session->getHwCryptoOpaque(); // Sign the data if(HwInfraSignFinal((void *)&hwKeyHandle, mechanism, hwCryptoOpaque, pSignature, (int *) pulSignatureLen) != 0 ) { session->resetOp(); return CKR_GENERAL_ERROR; } // Check size if (*pulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_GENERAL_ERROR; } *pulSignatureLen = size; session->resetOp(); return CKR_OK; } // Finalise a running signing operation and return the signature CK_RV SoftHSM::C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pulSignatureLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_SIGN || !session->getAllowMultiPartOp()) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacSignFinal(session, pSignature, pulSignatureLen); else if(isHWavailable) { return AsymSignFinalHW(hSession, session, pSignature, pulSignatureLen); } else { return AsymSignFinal(session, pSignature, pulSignatureLen); } } // Initialise a signing operation that allows recovery of the signed data CK_RV SoftHSM::C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR /*pMechanism*/, CK_OBJECT_HANDLE /*hKey*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; return CKR_FUNCTION_NOT_SUPPORTED; } // Perform a single part signing operation that allows recovery of the signed data CK_RV SoftHSM::C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pData*/, CK_ULONG /*ulDataLen*/, CK_BYTE_PTR /*pSignature*/, CK_ULONG_PTR /*pulSignatureLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // MacAlgorithm version of C_VerifyInit CK_RV SoftHSM::MacVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for verifying if (!key->getBooleanValue(CKA_VERIFY, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get key info CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED); // Get the MAC algorithm matching the mechanism // Also check mechanism constraints MacAlgo::Type algo = MacAlgo::Unknown; size_t bb = 8; size_t minSize = 0; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_MD5_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_MD5_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 16; algo = MacAlgo::HMAC_MD5; break; #endif case CKM_SHA_1_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA_1_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 20; algo = MacAlgo::HMAC_SHA1; break; case CKM_SHA224_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA224_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 28; algo = MacAlgo::HMAC_SHA224; break; case CKM_SHA256_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA256_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 32; algo = MacAlgo::HMAC_SHA256; break; case CKM_SHA384_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA384_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 48; algo = MacAlgo::HMAC_SHA384; break; case CKM_SHA512_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_SHA512_HMAC) return CKR_KEY_TYPE_INCONSISTENT; minSize = 64; algo = MacAlgo::HMAC_SHA512; break; #ifdef WITH_GOST case CKM_GOSTR3411_HMAC: if (keyType != CKK_GENERIC_SECRET && keyType != CKK_GOST28147) return CKR_KEY_TYPE_INCONSISTENT; minSize = 32; algo = MacAlgo::HMAC_GOST; break; #endif case CKM_DES3_CMAC: if (keyType != CKK_DES2 && keyType != CKK_DES3) return CKR_KEY_TYPE_INCONSISTENT; algo = MacAlgo::CMAC_DES; bb = 7; break; case CKM_AES_CMAC: if (keyType != CKK_AES) return CKR_KEY_TYPE_INCONSISTENT; algo = MacAlgo::CMAC_AES; break; default: return CKR_MECHANISM_INVALID; } MacAlgorithm* mac = CryptoFactory::i()->getMacAlgorithm(algo); if (mac == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* pubkey = new SymmetricKey(); if (getSymmetricKey(pubkey, token, key) != CKR_OK) { mac->recycleKey(pubkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_GENERAL_ERROR; } // Adjust key bit length pubkey->setBitLen(pubkey->getKeyBits().size() * bb); // Check key size if (pubkey->getBitLen() < (minSize*8)) { mac->recycleKey(pubkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_KEY_SIZE_RANGE; } // Initialize verifying if (!mac->verifyInit(pubkey)) { mac->recycleKey(pubkey); CryptoFactory::i()->recycleMacAlgorithm(mac); return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_VERIFY); session->setMacOp(mac); session->setAllowMultiPartOp(true); session->setAllowSinglePartOp(true); session->setSymmetricKey(pubkey); return CKR_OK; } // AsymmetricAlgorithm version of C_VerifyInit CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check read user credentials CK_RV rv = haveRead(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for verifying if (!key->getBooleanValue(CKA_VERIFY, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Get the asymmetric algorithm matching the mechanism AsymMech::Type mechanism = AsymMech::Unknown; void* param = NULL; size_t paramLen = 0; RSA_PKCS_PSS_PARAMS pssParam; bool bAllowMultiPartOp; bool isRSA = false; bool isDSA = false; bool isECDSA = false; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mechanism = AsymMech::RSA_PKCS; bAllowMultiPartOp = false; isRSA = true; break; case CKM_RSA_X_509: mechanism = AsymMech::RSA; bAllowMultiPartOp = false; isRSA = true; break; #ifndef WITH_FIPS case CKM_MD5_RSA_PKCS: mechanism = AsymMech::RSA_MD5_PKCS; bAllowMultiPartOp = true; isRSA = true; break; #endif case CKM_SHA1_RSA_PKCS: mechanism = AsymMech::RSA_SHA1_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA224_RSA_PKCS: mechanism = AsymMech::RSA_SHA224_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA256_RSA_PKCS: mechanism = AsymMech::RSA_SHA256_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA384_RSA_PKCS: mechanism = AsymMech::RSA_SHA384_PKCS; bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA512_RSA_PKCS: mechanism = AsymMech::RSA_SHA512_PKCS; bAllowMultiPartOp = true; isRSA = true; break; #ifdef WITH_RAW_PSS case CKM_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_PKCS_PSS; unsigned long expectedMgf; switch(CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg) { case CKM_SHA_1: pssParam.hashAlg = HashAlgo::SHA1; pssParam.mgf = AsymRSAMGF::MGF1_SHA1; expectedMgf = CKG_MGF1_SHA1; break; case CKM_SHA224: pssParam.hashAlg = HashAlgo::SHA224; pssParam.mgf = AsymRSAMGF::MGF1_SHA224; expectedMgf = CKG_MGF1_SHA224; break; case CKM_SHA256: pssParam.hashAlg = HashAlgo::SHA256; pssParam.mgf = AsymRSAMGF::MGF1_SHA256; expectedMgf = CKG_MGF1_SHA256; break; case CKM_SHA384: pssParam.hashAlg = HashAlgo::SHA384; pssParam.mgf = AsymRSAMGF::MGF1_SHA384; expectedMgf = CKG_MGF1_SHA384; break; case CKM_SHA512: pssParam.hashAlg = HashAlgo::SHA512; pssParam.mgf = AsymRSAMGF::MGF1_SHA512; expectedMgf = CKG_MGF1_SHA512; break; default: return CKR_ARGUMENTS_BAD; } if (CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != expectedMgf) { return CKR_ARGUMENTS_BAD; } pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = false; isRSA = true; break; #endif case CKM_SHA1_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA1_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA1; pssParam.mgf = AsymRSAMGF::MGF1_SHA1; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA224_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA224 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA224) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA224_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA224; pssParam.mgf = AsymRSAMGF::MGF1_SHA224; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA256_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA256 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA256) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA256_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA256; pssParam.mgf = AsymRSAMGF::MGF1_SHA256; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA384_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA384 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA384) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA384_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA384; pssParam.mgf = AsymRSAMGF::MGF1_SHA384; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_SHA512_RSA_PKCS_PSS: if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA512 || CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA512) { ERROR_MSG("Invalid parameters"); return CKR_ARGUMENTS_BAD; } mechanism = AsymMech::RSA_SHA512_PKCS_PSS; pssParam.hashAlg = HashAlgo::SHA512; pssParam.mgf = AsymRSAMGF::MGF1_SHA512; pssParam.sLen = CK_RSA_PKCS_PSS_PARAMS_PTR(pMechanism->pParameter)->sLen; param = &pssParam; paramLen = sizeof(pssParam); bAllowMultiPartOp = true; isRSA = true; break; case CKM_DSA: mechanism = AsymMech::DSA; bAllowMultiPartOp = false; isDSA = true; break; case CKM_DSA_SHA1: mechanism = AsymMech::DSA_SHA1; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA224: mechanism = AsymMech::DSA_SHA224; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA256: mechanism = AsymMech::DSA_SHA256; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA384: mechanism = AsymMech::DSA_SHA384; bAllowMultiPartOp = true; isDSA = true; break; case CKM_DSA_SHA512: mechanism = AsymMech::DSA_SHA512; bAllowMultiPartOp = true; isDSA = true; break; #ifdef WITH_ECC case CKM_ECDSA: mechanism = AsymMech::ECDSA; bAllowMultiPartOp = false; isECDSA = true; break; #endif #ifdef WITH_GOST case CKM_GOSTR3410: mechanism = AsymMech::GOST; bAllowMultiPartOp = false; break; case CKM_GOSTR3410_WITH_GOSTR3411: mechanism = AsymMech::GOST_GOST; bAllowMultiPartOp = true; break; #endif default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* asymCrypto = NULL; PublicKey* publicKey = NULL; if (isRSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; publicKey = asymCrypto->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getRSAPublicKey((RSAPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } else if (isDSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; publicKey = asymCrypto->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getDSAPublicKey((DSAPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } #ifdef WITH_ECC else if (isECDSA) { asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; publicKey = asymCrypto->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getECPublicKey((ECPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } } #endif else { #ifdef WITH_GOST asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST); if (asymCrypto == NULL) return CKR_MECHANISM_INVALID; publicKey = asymCrypto->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } if (getGOSTPublicKey((GOSTPublicKey*)publicKey, token, key) != CKR_OK) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } #else return CKR_MECHANISM_INVALID; #endif } // Initialize verifying if (bAllowMultiPartOp && !asymCrypto->verifyInit(publicKey,mechanism,param,paramLen)) { asymCrypto->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_MECHANISM_INVALID; } session->setOpType(SESSION_OP_VERIFY); session->setAsymmetricCryptoOp(asymCrypto); session->setMechanism(mechanism); session->setParameters(param, paramLen); session->setAllowMultiPartOp(bAllowMultiPartOp); session->setAllowSinglePartOp(true); session->setPublicKey(publicKey); return CKR_OK; } // Initialise a verification operation using the specified key and mechanism CK_RV SoftHSM::C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { if (isMacMechanism(pMechanism)) return MacVerifyInit(hSession, pMechanism, hKey); else return AsymVerifyInit(hSession, pMechanism, hKey); } // MacAlgorithm version of C_Verify static CK_RV MacVerify(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL || !session->getAllowSinglePartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = mac->getMacSize(); // Check buffer size if (ulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_SIGNATURE_LEN_RANGE; } // Get the data ByteString data(pData, ulDataLen); // Verify the data if (!mac->verifyUpdate(data)) { session->resetOp(); return CKR_GENERAL_ERROR; } // Get the signature ByteString signature(pSignature, ulSignatureLen); // Verify the signature if (!mac->verifyFinal(signature)) { session->resetOp(); return CKR_SIGNATURE_INVALID; } session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_Verify static CK_RV AsymVerify(Session* session, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); AsymMech::Type mechanism = session->getMechanism(); PublicKey* publicKey = session->getPublicKey(); size_t paramLen; void* param = session->getParameters(paramLen); if (asymCrypto == NULL || !session->getAllowSinglePartOp() || publicKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = publicKey->getOutputLength(); // Check buffer size if (ulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_SIGNATURE_LEN_RANGE; } // Get the data ByteString data; // We must allow input length <= k and therfore need to prepend the data with zeroes. if (mechanism == AsymMech::RSA) { data.wipe(size-ulDataLen); } data += ByteString(pData, ulDataLen); ByteString signature(pSignature, ulSignatureLen); // Verify the data if (session->getAllowMultiPartOp()) { if (!asymCrypto->verifyUpdate(data) || !asymCrypto->verifyFinal(signature)) { session->resetOp(); return CKR_SIGNATURE_INVALID; } } else if (!asymCrypto->verify(publicKey,data,signature,mechanism,param,paramLen)) { session->resetOp(); return CKR_SIGNATURE_INVALID; } session->resetOp(); return CKR_OK; } // Perform a single pass verification operation CK_RV SoftHSM::C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pData == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pSignature == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_VERIFY) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacVerify(session, pData, ulDataLen, pSignature, ulSignatureLen); else return AsymVerify(session, pData, ulDataLen, pSignature, ulSignatureLen); } // MacAlgorithm version of C_VerifyUpdate static CK_RV MacVerifyUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Get the part ByteString part(pPart, ulPartLen); // Verify the data if (!mac->verifyUpdate(part)) { // verifyUpdate can't fail for a logical reason, so we assume total breakdown. session->resetOp(); return CKR_GENERAL_ERROR; } session->setAllowSinglePartOp(false); return CKR_OK; } // AsymmetricAlgorithm version of C_VerifyUpdate static CK_RV AsymVerifyUpdate(Session* session, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); if (asymCrypto == NULL || !session->getAllowMultiPartOp()) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Get the part ByteString part(pPart, ulPartLen); // Verify the data if (!asymCrypto->verifyUpdate(part)) { // verifyUpdate can't fail for a logical reason, so we assume total breakdown. session->resetOp(); return CKR_GENERAL_ERROR; } session->setAllowSinglePartOp(false); return CKR_OK; } // Update a running verification operation with additional data CK_RV SoftHSM::C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pPart == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_VERIFY) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacVerifyUpdate(session, pPart, ulPartLen); else return AsymVerifyUpdate(session, pPart, ulPartLen); } // MacAlgorithm version of C_SignFinal static CK_RV MacVerifyFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { MacAlgorithm* mac = session->getMacOp(); if (mac == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = mac->getMacSize(); // Check buffer size if (ulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_SIGNATURE_LEN_RANGE; } // Get the signature ByteString signature(pSignature, ulSignatureLen); // Verify the data if (!mac->verifyFinal(signature)) { session->resetOp(); return CKR_SIGNATURE_INVALID; } session->resetOp(); return CKR_OK; } // AsymmetricAlgorithm version of C_VerifyFinal static CK_RV AsymVerifyFinal(Session* session, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { AsymmetricAlgorithm* asymCrypto = session->getAsymmetricCryptoOp(); PublicKey* publicKey = session->getPublicKey(); if (asymCrypto == NULL || publicKey == NULL) { session->resetOp(); return CKR_OPERATION_NOT_INITIALIZED; } // Size of the signature CK_ULONG size = publicKey->getOutputLength(); // Check buffer size if (ulSignatureLen != size) { ERROR_MSG("The size of the signature differs from the size of the mechanism"); session->resetOp(); return CKR_SIGNATURE_LEN_RANGE; } // Get the data ByteString signature(pSignature, ulSignatureLen); // Verify the data if (!asymCrypto->verifyFinal(signature)) { session->resetOp(); return CKR_SIGNATURE_INVALID; } session->resetOp(); return CKR_OK; } // Finalise the verification operation and check the signature CK_RV SoftHSM::C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pSignature == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we are doing the correct operation if (session->getOpType() != SESSION_OP_VERIFY || !session->getAllowMultiPartOp()) return CKR_OPERATION_NOT_INITIALIZED; if (session->getMacOp() != NULL) return MacVerifyFinal(session, pSignature, ulSignatureLen); else return AsymVerifyFinal(session, pSignature, ulSignatureLen); } // Initialise a verification operation the allows recovery of the signed data from the signature CK_RV SoftHSM::C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR /*pMechanism*/, CK_OBJECT_HANDLE /*hKey*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check if we have another operation if (session->getOpType() != SESSION_OP_NONE) return CKR_OPERATION_ACTIVE; return CKR_FUNCTION_NOT_SUPPORTED; } // Perform a single part verification operation and recover the signed data CK_RV SoftHSM::C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pSignature*/, CK_ULONG /*ulSignatureLen*/, CK_BYTE_PTR /*pData*/, CK_ULONG_PTR /*pulDataLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Update a running multi-part encryption and digesting operation CK_RV SoftHSM::C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG_PTR /*pulEncryptedPartLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Update a running multi-part decryption and digesting operation CK_RV SoftHSM::C_DecryptDigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pDecryptedPart*/, CK_ULONG_PTR /*pulDecryptedPartLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Update a running multi-part signing and encryption operation CK_RV SoftHSM::C_SignEncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pPart*/, CK_ULONG /*ulPartLen*/, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG_PTR /*pulEncryptedPartLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Update a running multi-part decryption and verification operation CK_RV SoftHSM::C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR /*pEncryptedPart*/, CK_ULONG /*ulEncryptedPartLen*/, CK_BYTE_PTR /*pPart*/, CK_ULONG_PTR /*pulPartLen*/) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_SUPPORTED; } // Generate a secret key or a domain parameter set using the specified mechanism CK_RV SoftHSM::C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phKey == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check the mechanism, only accept DSA and DH parameters // and symmetric ciphers CK_OBJECT_CLASS objClass; CK_KEY_TYPE keyType; switch (pMechanism->mechanism) { case CKM_DSA_PARAMETER_GEN: objClass = CKO_DOMAIN_PARAMETERS; keyType = CKK_DSA; break; case CKM_DH_PKCS_PARAMETER_GEN: objClass = CKO_DOMAIN_PARAMETERS; keyType = CKK_DH; break; #ifndef WITH_FIPS case CKM_DES_KEY_GEN: objClass = CKO_SECRET_KEY; keyType = CKK_DES; break; #endif case CKM_DES2_KEY_GEN: objClass = CKO_SECRET_KEY; keyType = CKK_DES2; break; case CKM_DES3_KEY_GEN: objClass = CKO_SECRET_KEY; keyType = CKK_DES3; break; case CKM_AES_KEY_GEN: objClass = CKO_SECRET_KEY; keyType = CKK_AES; break; default: return CKR_MECHANISM_INVALID; } // Extract information from the template that is needed to create the object. CK_BBOOL isOnToken = CK_FALSE; CK_BBOOL isPrivate = CK_TRUE; CK_CERTIFICATE_TYPE dummy; bool isImplicit = true; extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit); // Report errors and/or unexpected usage. if (objClass != CKO_SECRET_KEY && objClass != CKO_DOMAIN_PARAMETERS) return CKR_ATTRIBUTE_VALUE_INVALID; if (pMechanism->mechanism == CKM_DSA_PARAMETER_GEN && (objClass != CKO_DOMAIN_PARAMETERS || keyType != CKK_DSA)) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DH_PKCS_PARAMETER_GEN && (objClass != CKO_DOMAIN_PARAMETERS || keyType != CKK_DH)) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES_KEY_GEN && (objClass != CKO_SECRET_KEY || keyType != CKK_DES)) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES2_KEY_GEN && (objClass != CKO_SECRET_KEY || keyType != CKK_DES2)) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES3_KEY_GEN && (objClass != CKO_SECRET_KEY || keyType != CKK_DES3)) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_KEY_GEN && (objClass != CKO_SECRET_KEY || keyType != CKK_AES)) return CKR_TEMPLATE_INCONSISTENT; // Check authorization CK_RV rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Generate DSA domain parameters if (pMechanism->mechanism == CKM_DSA_PARAMETER_GEN) { return this->generateDSAParameters(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } // Generate DH domain parameters if (pMechanism->mechanism == CKM_DH_PKCS_PARAMETER_GEN) { return this->generateDHParameters(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } // Generate DES secret key if (pMechanism->mechanism == CKM_DES_KEY_GEN) { return this->generateDES(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } // Generate DES2 secret key if (pMechanism->mechanism == CKM_DES2_KEY_GEN) { return this->generateDES2(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } // Generate DES3 secret key if (pMechanism->mechanism == CKM_DES3_KEY_GEN) { return this->generateDES3(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } // Generate AES secret key if (pMechanism->mechanism == CKM_AES_KEY_GEN) { return this->generateAES(hSession, pTemplate, ulCount, phKey, isOnToken, isPrivate); } return CKR_GENERAL_ERROR; } // Generate a key-pair using the specified mechanism CK_RV SoftHSM::C_GenerateKeyPair ( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey ) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phPublicKey == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phPrivateKey == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check the mechanism, only accept RSA, DSA, EC and DH key pair generation. CK_KEY_TYPE keyType; switch (pMechanism->mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: keyType = CKK_RSA; break; case CKM_DSA_KEY_PAIR_GEN: keyType = CKK_DSA; break; case CKM_DH_PKCS_KEY_PAIR_GEN: keyType = CKK_DH; break; #ifdef WITH_ECC case CKM_EC_KEY_PAIR_GEN: keyType = CKK_EC; break; #endif #ifdef WITH_GOST case CKM_GOSTR3410_KEY_PAIR_GEN: keyType = CKK_GOSTR3410; break; #endif default: return CKR_MECHANISM_INVALID; } CK_CERTIFICATE_TYPE dummy; // Extract information from the public key template that is needed to create the object. CK_OBJECT_CLASS publicKeyClass = CKO_PUBLIC_KEY; CK_BBOOL ispublicKeyToken = CK_FALSE; CK_BBOOL ispublicKeyPrivate = CK_FALSE; bool isPublicKeyImplicit = true; extractObjectInformation(pPublicKeyTemplate, ulPublicKeyAttributeCount, publicKeyClass, keyType, dummy, ispublicKeyToken, ispublicKeyPrivate, isPublicKeyImplicit); // Report errors caused by accidental template mix-ups in the application using this cryptoki lib. if (publicKeyClass != CKO_PUBLIC_KEY) return CKR_ATTRIBUTE_VALUE_INVALID; if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN && keyType != CKK_RSA) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN && keyType != CKK_DSA) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN && keyType != CKK_EC) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN && keyType != CKK_DH) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410) 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; CK_BBOOL isprivateKeyToken = CK_FALSE; CK_BBOOL isprivateKeyPrivate = CK_TRUE; bool isPrivateKeyImplicit = true; extractObjectInformation(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, privateKeyClass, keyType, dummy, isprivateKeyToken, isprivateKeyPrivate, isPrivateKeyImplicit); // Report errors caused by accidental template mix-ups in the application using this cryptoki lib. if (privateKeyClass != CKO_PRIVATE_KEY) return CKR_ATTRIBUTE_VALUE_INVALID; if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN && keyType != CKK_RSA) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN && keyType != CKK_DSA) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN && keyType != CKK_EC) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN && keyType != CKK_DH) return CKR_TEMPLATE_INCONSISTENT; if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN && keyType != CKK_GOSTR3410) return CKR_TEMPLATE_INCONSISTENT; // Check user credentials CK_RV rv = haveWrite(session->getState(), ispublicKeyToken || isprivateKeyToken, ispublicKeyPrivate || isprivateKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Generate RSA keys if (pMechanism->mechanism == CKM_RSA_PKCS_KEY_PAIR_GEN) { return this->generateRSA(hSession, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey, ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } // Generate DSA keys if (pMechanism->mechanism == CKM_DSA_KEY_PAIR_GEN) { return this->generateDSA(hSession, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey, ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } // Generate EC keys if (pMechanism->mechanism == CKM_EC_KEY_PAIR_GEN) { return this->generateEC(hSession, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey, ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } // Generate DH keys if (pMechanism->mechanism == CKM_DH_PKCS_KEY_PAIR_GEN) { return this->generateDH(hSession, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey, ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } // Generate GOST keys if (pMechanism->mechanism == CKM_GOSTR3410_KEY_PAIR_GEN) { return this->generateGOST(hSession, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey, ispublicKeyToken, ispublicKeyPrivate, isprivateKeyToken, isprivateKeyPrivate); } return CKR_GENERAL_ERROR; } // Internal: Wrap blob using symmetric key CK_RV SoftHSM::WrapKeySym ( CK_MECHANISM_PTR pMechanism, Token* token, OSObject* wrapKey, ByteString& keydata, ByteString& wrapped ) { // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymWrap::Type mode = SymWrap::Unknown; size_t bb = 8; #ifdef HAVE_AES_KEY_WRAP CK_ULONG wrappedlen = keydata.size(); // [PKCS#11 v2.40, 2.14.3 AES Key Wrap] // A key whose length is not a multiple of the AES Key Wrap block // size (8 bytes) will be zero padded to fit. CK_ULONG alignment = wrappedlen % 8; if (alignment != 0) { keydata.resize(wrappedlen + 8 - alignment); memset(&keydata[wrappedlen], 0, 8 - alignment); wrappedlen = keydata.size(); } #endif switch(pMechanism->mechanism) { #ifdef HAVE_AES_KEY_WRAP case CKM_AES_KEY_WRAP: if ((wrappedlen < 16) || ((wrappedlen % 8) != 0)) return CKR_KEY_SIZE_RANGE; algo = SymAlgo::AES; mode = SymWrap::AES_KEYWRAP; break; #endif #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: algo = SymAlgo::AES; mode = SymWrap::AES_KEYWRAP_PAD; break; #endif default: return CKR_MECHANISM_INVALID; } SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* wrappingkey = new SymmetricKey(); if (getSymmetricKey(wrappingkey, token, wrapKey) != CKR_OK) { cipher->recycleKey(wrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // adjust key bit length wrappingkey->setBitLen(wrappingkey->getKeyBits().size() * bb); // Wrap the key if (!cipher->wrapKey(wrappingkey, mode, keydata, wrapped)) { cipher->recycleKey(wrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } cipher->recycleKey(wrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_OK; } // Internal: Wrap blob using asymmetric key CK_RV SoftHSM::WrapKeyAsym ( CK_MECHANISM_PTR pMechanism, Token* token, OSObject* wrapKey, ByteString& keydata, ByteString& wrapped ) { const size_t bb = 8; AsymAlgo::Type algo = AsymAlgo::Unknown; AsymMech::Type mech = AsymMech::Unknown; CK_ULONG modulus_length; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: algo = AsymAlgo::RSA; if (!wrapKey->attributeExists(CKA_MODULUS_BITS)) return CKR_GENERAL_ERROR; modulus_length = wrapKey->getUnsignedLongValue(CKA_MODULUS_BITS, 0); // adjust key bit length modulus_length /= bb; break; default: return CKR_MECHANISM_INVALID; } switch(pMechanism->mechanism) { case CKM_RSA_PKCS: mech = AsymMech::RSA_PKCS; // RFC 3447 section 7.2.1 if (keydata.size() > modulus_length - 11) return CKR_KEY_SIZE_RANGE; break; case CKM_RSA_PKCS_OAEP: mech = AsymMech::RSA_PKCS_OAEP; // SHA-1 is the only supported option // PKCS#11 2.40 draft 2 section 2.1.8: input length <= k-2-2hashLen if (keydata.size() > modulus_length - 2 - 2 * 160 / 8) return CKR_KEY_SIZE_RANGE; break; default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* cipher = CryptoFactory::i()->getAsymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; PublicKey* publicKey = cipher->newPublicKey(); if (publicKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_HOST_MEMORY; } switch(pMechanism->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (getRSAPublicKey((RSAPublicKey*)publicKey, token, wrapKey) != CKR_OK) { cipher->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } break; default: return CKR_MECHANISM_INVALID; } // Wrap the key if (!cipher->wrapKey(publicKey, keydata, wrapped, mech)) { cipher->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } cipher->recyclePublicKey(publicKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_OK; } // Wrap the specified key using the specified wrapping key and mechanism CK_RV SoftHSM::C_WrapKey ( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen ) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pulWrappedKeyLen == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; CK_RV rv; // Check the mechanism, only accept advanced AES key wrapping and RSA switch(pMechanism->mechanism) { #ifdef HAVE_AES_KEY_WRAP case CKM_AES_KEY_WRAP: #endif #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: #endif case CKM_RSA_PKCS: // Does not handle optional init vector if (pMechanism->pParameter != NULL_PTR || pMechanism->ulParameterLen != 0) return CKR_ARGUMENTS_BAD; break; case CKM_RSA_PKCS_OAEP: rv = MechParamCheckRSAPKCSOAEP(pMechanism); if (rv != CKR_OK) return rv; break; default: return CKR_MECHANISM_INVALID; } // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the wrapping key handle. OSObject *wrapKey = (OSObject *)handleManager->getObject(hWrappingKey); if (wrapKey == NULL_PTR || !wrapKey->isValid()) return CKR_WRAPPING_KEY_HANDLE_INVALID; CK_BBOOL isWrapKeyOnToken = wrapKey->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isWrapKeyPrivate = wrapKey->getBooleanValue(CKA_PRIVATE, true); // Check user credentials for the wrapping key rv = haveRead(session->getState(), isWrapKeyOnToken, isWrapKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check wrapping key class and type if ((pMechanism->mechanism == CKM_AES_KEY_WRAP || pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD) && wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PUBLIC_KEY) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_KEY_WRAP && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; // Check if the wrapping key can be used for wrapping if (wrapKey->getBooleanValue(CKA_WRAP, false) == false) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the wrapping key if (!isMechanismPermitted(wrapKey, pMechanism)) return CKR_MECHANISM_INVALID; // Check the to be wrapped key handle. OSObject *key = (OSObject *)handleManager->getObject(hKey); if (key == NULL_PTR || !key->isValid()) return CKR_KEY_HANDLE_INVALID; CK_BBOOL isKeyOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check user credentials for the to be wrapped key rv = haveRead(session->getState(), isKeyOnToken, isKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if the to be wrapped key can be wrapped if (key->getBooleanValue(CKA_EXTRACTABLE, false) == false) return CKR_KEY_UNEXTRACTABLE; if (key->getBooleanValue(CKA_WRAP_WITH_TRUSTED, false) && wrapKey->getBooleanValue(CKA_TRUSTED, false) == false) return CKR_KEY_NOT_WRAPPABLE; // Check the class CK_OBJECT_CLASS keyClass = key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED); if (keyClass != CKO_SECRET_KEY && keyClass != CKO_PRIVATE_KEY) return CKR_KEY_NOT_WRAPPABLE; // CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP can be used only on SECRET keys: PKCS#11 2.40 draft 2 section 2.1.6 PKCS #1 v1.5 RSA & section 2.1.8 PKCS #1 RSA OAEP if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && keyClass != CKO_SECRET_KEY) return CKR_KEY_NOT_WRAPPABLE; // Verify the wrap template attribute if (wrapKey->attributeExists(CKA_WRAP_TEMPLATE)) { OSAttribute attr = wrapKey->getAttribute(CKA_WRAP_TEMPLATE); if (attr.isAttributeMapAttribute()) { typedef std::map attrmap_type; const attrmap_type& map = attr.getAttributeMapValue(); for (attrmap_type::const_iterator it = map.begin(); it != map.end(); ++it) { if (!key->attributeExists(it->first)) { return CKR_KEY_NOT_WRAPPABLE; } OSAttribute keyAttr = key->getAttribute(it->first); ByteString v1, v2; if (!keyAttr.peekValue(v1) || !it->second.peekValue(v2) || (v1 != v2)) { return CKR_KEY_NOT_WRAPPABLE; } } } } // Get the key data to encrypt ByteString keydata; if (keyClass == CKO_SECRET_KEY) { if (isKeyPrivate) { bool bOK = token->decrypt(key->getByteStringValue(CKA_VALUE), keydata); if (!bOK) return CKR_GENERAL_ERROR; } else { keydata = key->getByteStringValue(CKA_VALUE); } } else { CK_KEY_TYPE keyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED); AsymAlgo::Type alg = AsymAlgo::Unknown; switch (keyType) { case CKK_RSA: alg = AsymAlgo::RSA; break; case CKK_DSA: alg = AsymAlgo::DSA; break; case CKK_DH: alg = AsymAlgo::DH; break; #ifdef WITH_ECC case CKK_EC: // can be ecdh too but it doesn't matter alg = AsymAlgo::ECDSA; break; #endif #ifdef WITH_GOST case CKK_GOSTR3410: alg = AsymAlgo::GOST; break; #endif default: return CKR_KEY_NOT_WRAPPABLE; } AsymmetricAlgorithm* asymCrypto = NULL; PrivateKey* privateKey = NULL; asymCrypto = CryptoFactory::i()->getAsymmetricAlgorithm(alg); if (asymCrypto == NULL) return CKR_GENERAL_ERROR; privateKey = asymCrypto->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_HOST_MEMORY; } switch (keyType) { case CKK_RSA: rv = getRSAPrivateKey((RSAPrivateKey*)privateKey, token, key); break; case CKK_DSA: rv = getDSAPrivateKey((DSAPrivateKey*)privateKey, token, key); break; case CKK_DH: rv = getDHPrivateKey((DHPrivateKey*)privateKey, token, key); break; #ifdef WITH_ECC case CKK_EC: rv = getECPrivateKey((ECPrivateKey*)privateKey, token, key); break; #endif #ifdef WITH_GOST case CKK_GOSTR3410: rv = getGOSTPrivateKey((GOSTPrivateKey*)privateKey, token, key); break; #endif } if (rv != CKR_OK) { asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); return CKR_GENERAL_ERROR; } keydata = privateKey->PKCS8Encode(); asymCrypto->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(asymCrypto); } if (keydata.size() == 0) return CKR_KEY_NOT_WRAPPABLE; keyClass = wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED); ByteString wrapped; if (keyClass == CKO_SECRET_KEY) rv = SoftHSM::WrapKeySym(pMechanism, token, wrapKey, keydata, wrapped); else rv = SoftHSM::WrapKeyAsym(pMechanism, token, wrapKey, keydata, wrapped); if (rv != CKR_OK) return rv; if (pWrappedKey != NULL) { if (*pulWrappedKeyLen >= wrapped.size()) memcpy(pWrappedKey, wrapped.byte_str(), wrapped.size()); else rv = CKR_BUFFER_TOO_SMALL; } *pulWrappedKeyLen = wrapped.size(); return rv; } // Internal: Unwrap blob using symmetric key CK_RV SoftHSM::UnwrapKeySym ( CK_MECHANISM_PTR pMechanism, ByteString& wrapped, Token* token, OSObject* unwrapKey, ByteString& keydata ) { // Get the symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymWrap::Type mode = SymWrap::Unknown; size_t bb = 8; switch(pMechanism->mechanism) { #ifdef HAVE_AES_KEY_WRAP case CKM_AES_KEY_WRAP: algo = SymAlgo::AES; mode = SymWrap::AES_KEYWRAP; break; #endif #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: algo = SymAlgo::AES; mode = SymWrap::AES_KEYWRAP_PAD; break; #endif default: return CKR_MECHANISM_INVALID; } SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* unwrappingkey = new SymmetricKey(); if (getSymmetricKey(unwrappingkey, token, unwrapKey) != CKR_OK) { cipher->recycleKey(unwrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // adjust key bit length unwrappingkey->setBitLen(unwrappingkey->getKeyBits().size() * bb); // Unwrap the key CK_RV rv = CKR_OK; if (!cipher->unwrapKey(unwrappingkey, mode, wrapped, keydata)) rv = CKR_GENERAL_ERROR; cipher->recycleKey(unwrappingkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return rv; } // Internal: Unwrap blob using asymmetric key CK_RV SoftHSM::UnwrapKeyAsym ( CK_MECHANISM_PTR pMechanism, ByteString& wrapped, Token* token, OSObject* unwrapKey, ByteString& keydata ) { // Get the symmetric algorithm matching the mechanism AsymAlgo::Type algo = AsymAlgo::Unknown; AsymMech::Type mode = AsymMech::Unknown; switch(pMechanism->mechanism) { case CKM_RSA_PKCS: algo = AsymAlgo::RSA; mode = AsymMech::RSA_PKCS; break; case CKM_RSA_PKCS_OAEP: algo = AsymAlgo::RSA; mode = AsymMech::RSA_PKCS_OAEP; break; default: return CKR_MECHANISM_INVALID; } AsymmetricAlgorithm* cipher = CryptoFactory::i()->getAsymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; PrivateKey* unwrappingkey = cipher->newPrivateKey(); if (unwrappingkey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_HOST_MEMORY; } switch(pMechanism->mechanism) { case CKM_RSA_PKCS: case CKM_RSA_PKCS_OAEP: if (getRSAPrivateKey((RSAPrivateKey*)unwrappingkey, token, unwrapKey) != CKR_OK) { cipher->recyclePrivateKey(unwrappingkey); CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } break; default: return CKR_MECHANISM_INVALID; } // Unwrap the key CK_RV rv = CKR_OK; if (!cipher->unwrapKey(unwrappingkey, wrapped, keydata, mode)) rv = CKR_GENERAL_ERROR; cipher->recyclePrivateKey(unwrappingkey); CryptoFactory::i()->recycleAsymmetricAlgorithm(cipher); return rv; } // Unwrap the specified key using the specified unwrapping key CK_RV SoftHSM::C_UnwrapKey ( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR hKey ) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pWrappedKey == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD; if (hKey == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; CK_RV rv; // Check the mechanism switch(pMechanism->mechanism) { #ifdef HAVE_AES_KEY_WRAP case CKM_AES_KEY_WRAP: if ((ulWrappedKeyLen < 24) || ((ulWrappedKeyLen % 8) != 0)) return CKR_WRAPPED_KEY_LEN_RANGE; // Does not handle optional init vector if (pMechanism->pParameter != NULL_PTR || pMechanism->ulParameterLen != 0) return CKR_ARGUMENTS_BAD; break; #endif #ifdef HAVE_AES_KEY_WRAP_PAD case CKM_AES_KEY_WRAP_PAD: if ((ulWrappedKeyLen < 16) || ((ulWrappedKeyLen % 8) != 0)) return CKR_WRAPPED_KEY_LEN_RANGE; // Does not handle optional init vector if (pMechanism->pParameter != NULL_PTR || pMechanism->ulParameterLen != 0) return CKR_ARGUMENTS_BAD; break; #endif case CKM_RSA_PKCS: // Input length checks needs to be done later when unwrapping key is known break; case CKM_RSA_PKCS_OAEP: rv = MechParamCheckRSAPKCSOAEP(pMechanism); if (rv != CKR_OK) return rv; break; default: return CKR_MECHANISM_INVALID; } // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the unwrapping key handle. OSObject *unwrapKey = (OSObject *)handleManager->getObject(hUnwrappingKey); if (unwrapKey == NULL_PTR || !unwrapKey->isValid()) return CKR_UNWRAPPING_KEY_HANDLE_INVALID; CK_BBOOL isUnwrapKeyOnToken = unwrapKey->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isUnwrapKeyPrivate = unwrapKey->getBooleanValue(CKA_PRIVATE, true); // Check user credentials rv = haveRead(session->getState(), isUnwrapKeyOnToken, isUnwrapKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check unwrapping key class and type if ((pMechanism->mechanism == CKM_AES_KEY_WRAP || pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD) && unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_KEY_WRAP && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_KEY_WRAP_PAD && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; // Check if the unwrapping key can be used for unwrapping if (unwrapKey->getBooleanValue(CKA_UNWRAP, false) == false) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the unwrap key if (!isMechanismPermitted(unwrapKey, pMechanism)) return CKR_MECHANISM_INVALID; // Extract information from the template that is needed to create the object. CK_OBJECT_CLASS objClass; CK_KEY_TYPE keyType; CK_BBOOL isOnToken = CK_FALSE; CK_BBOOL isPrivate = CK_TRUE; CK_CERTIFICATE_TYPE dummy; bool isImplicit = false; rv = extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit); if (rv != CKR_OK) { ERROR_MSG("Mandatory attribute not present in template"); return rv; } // Report errors and/or unexpected usage. if (objClass != CKO_SECRET_KEY && objClass != CKO_PRIVATE_KEY) return CKR_ATTRIBUTE_VALUE_INVALID; // Key type will be handled at object creation // Check authorization rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Build unwrapped key template const CK_ULONG maxAttribs = 32; 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)) return CKR_TEMPLATE_INCONSISTENT; for (CK_ULONG i = 0; i < ulCount; ++i) { switch (pTemplate[i].type) { case CKA_CLASS: case CKA_TOKEN: case CKA_PRIVATE: case CKA_KEY_TYPE: continue; default: secretAttribs[secretAttribsCount++] = pTemplate[i]; } } // Apply the unwrap template if (unwrapKey->attributeExists(CKA_UNWRAP_TEMPLATE)) { OSAttribute unwrapAttr = unwrapKey->getAttribute(CKA_UNWRAP_TEMPLATE); if (unwrapAttr.isAttributeMapAttribute()) { typedef std::map attrmap_type; const attrmap_type& map = unwrapAttr.getAttributeMapValue(); for (attrmap_type::const_iterator it = map.begin(); it != map.end(); ++it) { CK_ATTRIBUTE* attr = NULL; for (CK_ULONG i = 0; i < secretAttribsCount; ++i) { if (it->first == secretAttribs[i].type) { if (attr != NULL) { return CKR_TEMPLATE_INCONSISTENT; } attr = &secretAttribs[i]; ByteString value; it->second.peekValue(value); if (attr->ulValueLen != value.size()) { return CKR_TEMPLATE_INCONSISTENT; } if (memcmp(attr->pValue, value.const_byte_str(), value.size()) != 0) { return CKR_TEMPLATE_INCONSISTENT; } } } if (attr == NULL) { return CKR_TEMPLATE_INCONSISTENT; } } } } *hKey = CK_INVALID_HANDLE; // Unwrap the key ByteString wrapped(pWrappedKey, ulWrappedKeyLen); ByteString keydata; if (unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_SECRET_KEY) rv = UnwrapKeySym(pMechanism, wrapped, token, unwrapKey, keydata); else if (unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) == CKO_PRIVATE_KEY) rv = UnwrapKeyAsym(pMechanism, wrapped, token, unwrapKey, keydata); else rv = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if (rv != CKR_OK) return rv; // Create the secret object using C_CreateObject rv = this->CreateObject(hSession, secretAttribs, secretAttribsCount, hKey, OBJECT_OP_UNWRAP); // Store the attributes that are being supplied if (rv == CKR_OK) { OSObject* osobject = (OSObject*)handleManager->getObject(*hKey); if (osobject == NULL_PTR || !osobject->isValid()) rv = CKR_FUNCTION_FAILED; if (osobject->startTransaction()) { bool bOK = true; // Common Attributes bOK = bOK && osobject->setAttribute(CKA_LOCAL, false); // Common Secret Key Attributes bOK = bOK && osobject->setAttribute(CKA_ALWAYS_SENSITIVE, false); bOK = bOK && osobject->setAttribute(CKA_NEVER_EXTRACTABLE, false); // Secret Attributes if (objClass == CKO_SECRET_KEY) { ByteString value; if (isPrivate) token->encrypt(keydata, value); else value = keydata; bOK = bOK && osobject->setAttribute(CKA_VALUE, value); } else if (keyType == CKK_RSA) { bOK = bOK && setRSAPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE); } else if (keyType == CKK_DSA) { bOK = bOK && setDSAPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE); } else if (keyType == CKK_DH) { bOK = bOK && setDHPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE); } #ifdef WITH_ECC else if (keyType == CKK_EC) { bOK = bOK && setECPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE); } #endif #ifdef WITH_GOST else if (keyType == CKK_GOSTR3410) { bOK = bOK && setGOSTPrivateKey(osobject, keydata, token, isPrivate != CK_FALSE); } #endif else bOK = false; if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } // Remove secret that may have been created already when the function fails. if (rv != CKR_OK) { if (*hKey != CK_INVALID_HANDLE) { OSObject* obj = (OSObject*)handleManager->getObject(*hKey); handleManager->destroyObject(*hKey); if (obj) obj->destroyObject(); *hKey = CK_INVALID_HANDLE; } } return rv; } // Derive a key from the specified base key CK_RV SoftHSM::C_DeriveKey ( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey ) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pMechanism == NULL_PTR) return CKR_ARGUMENTS_BAD; if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phKey == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Check the mechanism, only accept DH and ECDH derive switch (pMechanism->mechanism) { case CKM_DH_PKCS_DERIVE: #ifdef WITH_ECC case CKM_ECDH1_DERIVE: #endif #ifndef WITH_FIPS case CKM_DES_ECB_ENCRYPT_DATA: case CKM_DES_CBC_ENCRYPT_DATA: #endif case CKM_DES3_ECB_ENCRYPT_DATA: case CKM_DES3_CBC_ENCRYPT_DATA: case CKM_AES_ECB_ENCRYPT_DATA: case CKM_AES_CBC_ENCRYPT_DATA: break; default: ERROR_MSG("Invalid mechanism"); return CKR_MECHANISM_INVALID; } // Get the token Token* token = session->getToken(); if (token == NULL) return CKR_GENERAL_ERROR; // Check the key handle. OSObject *key = (OSObject *)handleManager->getObject(hBaseKey); if (key == NULL_PTR || !key->isValid()) return CKR_OBJECT_HANDLE_INVALID; CK_BBOOL isKeyOnToken = key->getBooleanValue(CKA_TOKEN, false); CK_BBOOL isKeyPrivate = key->getBooleanValue(CKA_PRIVATE, true); // Check user credentials CK_RV rv = haveRead(session->getState(), isKeyOnToken, isKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); return rv; } // Check if key can be used for derive if (!key->getBooleanValue(CKA_DERIVE, false)) return CKR_KEY_FUNCTION_NOT_PERMITTED; // Check if the specified mechanism is allowed for the key if (!isMechanismPermitted(key, pMechanism)) return CKR_MECHANISM_INVALID; // Extract information from the template that is needed to create the object. CK_OBJECT_CLASS objClass; CK_KEY_TYPE keyType; CK_BBOOL isOnToken = CK_FALSE; CK_BBOOL isPrivate = CK_TRUE; CK_CERTIFICATE_TYPE dummy; bool isImplicit = false; rv = extractObjectInformation(pTemplate, ulCount, objClass, keyType, dummy, isOnToken, isPrivate, isImplicit); if (rv != CKR_OK) { ERROR_MSG("Mandatory attribute not present in template"); return rv; } // Report errors and/or unexpected usage. if (objClass != CKO_SECRET_KEY) return CKR_ATTRIBUTE_VALUE_INVALID; if (keyType != CKK_GENERIC_SECRET && keyType != CKK_DES && keyType != CKK_DES2 && keyType != CKK_DES3 && keyType != CKK_AES) return CKR_TEMPLATE_INCONSISTENT; // Check authorization rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Derive DH secret if (pMechanism->mechanism == CKM_DH_PKCS_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_DH) return CKR_KEY_TYPE_INCONSISTENT; return this->deriveDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); } #ifdef WITH_ECC // 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) return CKR_KEY_TYPE_INCONSISTENT; return this->deriveECDH(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); } #endif // Derive symmetric secret if (pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA || pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA || pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA || pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA || pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA || pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA) { // Check key class and type CK_KEY_TYPE baseKeyType = key->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED); if (key->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_SECRET_KEY) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA && baseKeyType != CKK_DES) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA && baseKeyType != CKK_DES) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA && baseKeyType != CKK_DES2 && baseKeyType != CKK_DES3) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA && baseKeyType != CKK_DES2 && baseKeyType != CKK_DES3) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA && baseKeyType != CKK_AES) return CKR_KEY_TYPE_INCONSISTENT; if (pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA && baseKeyType != CKK_AES) return CKR_KEY_TYPE_INCONSISTENT; return this->deriveSymmetric(hSession, pMechanism, hBaseKey, pTemplate, ulCount, phKey, keyType, isOnToken, isPrivate); } return CKR_MECHANISM_INVALID; } // Seed the random number generator with new data CK_RV SoftHSM::C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pSeed == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the RNG RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) return CKR_GENERAL_ERROR; // Seed the RNG ByteString seed(pSeed, ulSeedLen); rng->seed(seed); return CKR_OK; } // Generate the specified amount of random data CK_RV SoftHSM::C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pRandomData == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the RNG RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) return CKR_GENERAL_ERROR; // Generate random data ByteString randomData; if (!rng->generateRandom(randomData, ulRandomLen)) return CKR_GENERAL_ERROR; // Return random data if (ulRandomLen != 0) { memcpy(pRandomData, randomData.byte_str(), ulRandomLen); } return CKR_OK; } // Legacy function CK_RV SoftHSM::C_GetFunctionStatus(CK_SESSION_HANDLE hSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_PARALLEL; } // Legacy function CK_RV SoftHSM::C_CancelFunction(CK_SESSION_HANDLE hSession) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; return CKR_FUNCTION_NOT_PARALLEL; } // Wait or poll for a slot event on the specified slot CK_RV SoftHSM::C_WaitForSlotEvent(CK_FLAGS /*flags*/, CK_SLOT_ID_PTR /*pSlot*/, CK_VOID_PTR /*pReserved*/) { return CKR_FUNCTION_NOT_SUPPORTED; } // Generate an AES secret key CK_RV SoftHSM::generateAES (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; } // keyLen must be 16, 24, or 32 if (keyLen != 16 && keyLen != 24 && keyLen != 32) { INFO_MSG("bad AES key length"); return CKR_ATTRIBUTE_VALUE_INVALID; } // Generate the secret key AESKey* key = new AESKey(keyLen * 8); SymmetricAlgorithm* aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES); if (aes == NULL) { ERROR_MSG("Could not get SymmetricAlgorithm"); delete key; return CKR_GENERAL_ERROR; } RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) { ERROR_MSG("Could not get RNG"); aes->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(aes); return CKR_GENERAL_ERROR; } if (!aes->generateKey(*key, rng)) { ERROR_MSG("Could not generate AES secret key"); aes->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(aes); 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_AES; 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]; } } if (rv == CKR_OK) rv = this->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_AES_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); // AES Secret Key Attributes ByteString value; ByteString kcv; if (isPrivate) { token->encrypt(key->getKeyBits(), value); token->encrypt(key->getKeyCheckValue(), kcv); } else { value = key->getKeyBits(); kcv = key->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 aes->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(aes); // 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 a DES secret key CK_RV SoftHSM::generateDES (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 bool checkValue = true; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { 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; } } // Generate the secret key DESKey* key = new DESKey(56); SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES); if (des == NULL) { ERROR_MSG("Could not get SymmetricAlgorithm"); delete key; return CKR_GENERAL_ERROR; } RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) { ERROR_MSG("Could not get RNG"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); return CKR_GENERAL_ERROR; } if (!des->generateKey(*key, rng)) { ERROR_MSG("Could not generate DES secret key"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); 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_DES; 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]; } } if (rv == CKR_OK) rv = this->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_DES_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); // DES Secret Key Attributes ByteString value; ByteString kcv; if (isPrivate) { token->encrypt(key->getKeyBits(), value); token->encrypt(key->getKeyCheckValue(), kcv); } else { value = key->getKeyBits(); kcv = key->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 des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); // 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 a DES2 secret key CK_RV SoftHSM::generateDES2 (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 bool checkValue = true; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { 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; } } // Generate the secret key DESKey* key = new DESKey(112); SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES3); if (des == NULL) { ERROR_MSG("Could not get SymmetricAlgorith"); delete key; return CKR_GENERAL_ERROR; } RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) { ERROR_MSG("Could not get RNG"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); return CKR_GENERAL_ERROR; } if (!des->generateKey(*key, rng)) { ERROR_MSG("Could not generate DES secret key"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); 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_DES2; 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]; } } if (rv == CKR_OK) rv = this->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_DES2_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); // DES Secret Key Attributes ByteString value; ByteString kcv; if (isPrivate) { token->encrypt(key->getKeyBits(), value); token->encrypt(key->getKeyCheckValue(), kcv); } else { value = key->getKeyBits(); kcv = key->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 des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); // 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 a DES3 secret key CK_RV SoftHSM::generateDES3 (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 bool checkValue = true; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { 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; } } // Generate the secret key DESKey* key = new DESKey(168); SymmetricAlgorithm* des = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::DES3); if (des == NULL) { ERROR_MSG("Could not get SymmetricAlgorithm"); delete key; return CKR_GENERAL_ERROR; } RNG* rng = CryptoFactory::i()->getRNG(); if (rng == NULL) { ERROR_MSG("Could not get RNG"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); return CKR_GENERAL_ERROR; } if (!des->generateKey(*key, rng)) { ERROR_MSG("Could not generate DES secret key"); des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); 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_DES3; 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]; } } if (rv == CKR_OK) rv = this->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_DES3_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); // DES Secret Key Attributes ByteString value; ByteString kcv; if (isPrivate) { token->encrypt(key->getKeyBits(), value); token->encrypt(key->getKeyCheckValue(), kcv); } else { value = key->getKeyBits(); kcv = key->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 des->recycleKey(key); CryptoFactory::i()->recycleSymmetricAlgorithm(des); // 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 RSA key pair CK_RV SoftHSM::generateRSA (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: bitlen and public exponent size_t bitLen = 0; ByteString exponent("010001"); for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_MODULUS_BITS: if (pPublicKeyTemplate[i].ulValueLen != sizeof(CK_ULONG)) { INFO_MSG("CKA_MODULUS_BITS does not have the size of CK_ULONG"); return CKR_ATTRIBUTE_VALUE_INVALID; } bitLen = *(CK_ULONG*)pPublicKeyTemplate[i].pValue; break; case CKA_PUBLIC_EXPONENT: exponent = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; default: break; } } // CKA_MODULUS_BITS must be specified to be able to generate a key pair. if (bitLen == 0) { INFO_MSG("Missing CKA_MODULUS_BITS in pPublicKeyTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // Set the parameters RSAParameters p; p.setE(exponent); p.setBitLength(bitLen); // Generate key pair AsymmetricKeyPair* kp = NULL; AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (rsa == NULL) return CKR_GENERAL_ERROR; if (!rsa->generateKeyPair(&kp, &p)) { ERROR_MSG("Could not generate key pair"); CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); return CKR_GENERAL_ERROR; } RSAPublicKey* pub = (RSAPublicKey*) kp->getPublicKey(); RSAPrivateKey* priv = (RSAPrivateKey*) 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_RSA; 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: case CKA_PUBLIC_EXPONENT: 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_RSA_PKCS_KEY_PAIR_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // RSA Public Key Attributes ByteString modulus; ByteString publicExponent; if (isPublicKeyPrivate) { token->encrypt(pub->getN(), modulus); token->encrypt(pub->getE(), publicExponent); } else { modulus = pub->getN(); publicExponent = pub->getE(); } bOK = bOK && osobject->setAttribute(CKA_MODULUS, modulus); bOK = bOK && osobject->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent); 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_RSA; 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_RSA_PKCS_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); // RSA Private Key Attributes ByteString modulus; ByteString publicExponent; ByteString privateExponent; ByteString prime1; ByteString prime2; ByteString exponent1; ByteString exponent2; ByteString coefficient; if (isPrivateKeyPrivate) { token->encrypt(priv->getN(), modulus); token->encrypt(priv->getE(), publicExponent); token->encrypt(priv->getD(), privateExponent); token->encrypt(priv->getP(), prime1); token->encrypt(priv->getQ(), prime2); token->encrypt(priv->getDP1(), exponent1); token->encrypt(priv->getDQ1(), exponent2); token->encrypt(priv->getPQ(), coefficient); } else { modulus = priv->getN(); publicExponent = priv->getE(); privateExponent = priv->getD(); prime1 = priv->getP(); prime2 = priv->getQ(); exponent1 = priv->getDP1(); exponent2 = priv->getDQ1(); coefficient = priv->getPQ(); } bOK = bOK && osobject->setAttribute(CKA_MODULUS, modulus); bOK = bOK && osobject->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent); bOK = bOK && osobject->setAttribute(CKA_PRIVATE_EXPONENT, privateExponent); bOK = bOK && osobject->setAttribute(CKA_PRIME_1, prime1); bOK = bOK && osobject->setAttribute(CKA_PRIME_2, prime2); bOK = bOK && osobject->setAttribute(CKA_EXPONENT_1,exponent1); bOK = bOK && osobject->setAttribute(CKA_EXPONENT_2, exponent2); bOK = bOK && osobject->setAttribute(CKA_COEFFICIENT, coefficient); if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } } // Clean up rsa->recycleKeyPair(kp); CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); // 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 DSA key pair CK_RV SoftHSM::generateDSA (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 prime; ByteString subprime; ByteString generator; for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_PRIME: prime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; case CKA_SUBPRIME: subprime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; case CKA_BASE: generator = 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 (prime.size() == 0 || subprime.size() == 0 || generator.size() == 0) { INFO_MSG("Missing parameter(s) in pPublicKeyTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // Set the parameters DSAParameters p; p.setP(prime); p.setQ(subprime); p.setG(generator); // Generate key pair AsymmetricKeyPair* kp = NULL; AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (dsa == NULL) return CKR_GENERAL_ERROR; if (!dsa->generateKeyPair(&kp, &p)) { ERROR_MSG("Could not generate key pair"); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); return CKR_GENERAL_ERROR; } DSAPublicKey* pub = (DSAPublicKey*) kp->getPublicKey(); DSAPrivateKey* priv = (DSAPrivateKey*) 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_DSA; 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_DSA_KEY_PAIR_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // DSA Public Key Attributes ByteString value; if (isPublicKeyPrivate) { token->encrypt(pub->getY(), value); } else { value = pub->getY(); } 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; } } // 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_DSA; 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_DSA_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); // DSA Private Key Attributes ByteString bPrime; ByteString bSubprime; ByteString bGenerator; ByteString bValue; if (isPrivateKeyPrivate) { token->encrypt(priv->getP(), bPrime); token->encrypt(priv->getQ(), bSubprime); token->encrypt(priv->getG(), bGenerator); token->encrypt(priv->getX(), bValue); } else { bPrime = priv->getP(); bSubprime = priv->getQ(); bGenerator = priv->getG(); bValue = priv->getX(); } bOK = bOK && osobject->setAttribute(CKA_PRIME, bPrime); bOK = bOK && osobject->setAttribute(CKA_SUBPRIME, bSubprime); bOK = bOK && osobject->setAttribute(CKA_BASE, bGenerator); bOK = bOK && osobject->setAttribute(CKA_VALUE, bValue); if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } } // Clean up dsa->recycleKeyPair(kp); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); // 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 DSA domain parameter set CK_RV SoftHSM::generateDSAParameters (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 bitLen = 0; size_t qLen = 0; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_PRIME_BITS: if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) { INFO_MSG("CKA_PRIME_BITS does not have the size of CK_ULONG"); return CKR_ATTRIBUTE_VALUE_INVALID; } bitLen = *(CK_ULONG*)pTemplate[i].pValue; break; case CKA_SUBPRIME_BITS: if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) { INFO_MSG("CKA_SUBPRIME_BITS does not have the size of CK_ULONG"); return CKR_ATTRIBUTE_VALUE_INVALID; } qLen = *(CK_ULONG*)pTemplate[i].pValue; break; default: break; } } // CKA_PRIME_BITS must be specified if (bitLen == 0) { INFO_MSG("Missing CKA_PRIME_BITS in pTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // No real choice for CKA_SUBPRIME_BITS if ((qLen != 0) && (((bitLen >= 2048) && (qLen != 256)) || ((bitLen < 2048) && (qLen != 160)))) INFO_MSG("CKA_SUBPRIME_BITS is ignored"); // Generate domain parameters AsymmetricParameters* p = NULL; AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (dsa == NULL) return CKR_GENERAL_ERROR; if (!dsa->generateParameters(&p, (void *)bitLen)) { ERROR_MSG("Could not generate parameters"); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); return CKR_GENERAL_ERROR; } DSAParameters* params = (DSAParameters*) p; CK_RV rv = CKR_OK; // Create the domain parameter object using C_CreateObject const CK_ULONG maxAttribs = 32; CK_OBJECT_CLASS objClass = CKO_DOMAIN_PARAMETERS; CK_KEY_TYPE keyType = CKK_DSA; CK_ATTRIBUTE paramsAttribs[maxAttribs] = { { CKA_CLASS, &objClass, sizeof(objClass) }, { CKA_TOKEN, &isOnToken, sizeof(isOnToken) }, { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, }; CK_ULONG paramsAttribsCount = 4; // Add the additional if (ulCount > (maxAttribs - paramsAttribsCount)) 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: continue; default: paramsAttribs[paramsAttribsCount++] = pTemplate[i]; } } if (rv == CKR_OK) rv = this->CreateObject(hSession, paramsAttribs, paramsAttribsCount, 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_DSA_PARAMETER_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // DSA Domain Parameters Attributes ByteString prime; ByteString subprime; ByteString generator; if (isPrivate) { token->encrypt(params->getP(), prime); token->encrypt(params->getQ(), subprime); token->encrypt(params->getG(), generator); } else { prime = params->getP(); subprime = params->getQ(); generator = params->getG(); } bOK = bOK && osobject->setAttribute(CKA_PRIME, prime); bOK = bOK && osobject->setAttribute(CKA_SUBPRIME, subprime); bOK = bOK && osobject->setAttribute(CKA_BASE, generator); if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } // Clean up dsa->recycleParameters(p); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); // Remove parameters that may have been created already when the function fails. if (rv != CKR_OK) { if (*phKey != CK_INVALID_HANDLE) { OSObject* osparams = (OSObject*)handleManager->getObject(*phKey); handleManager->destroyObject(*phKey); if (osparams) osparams->destroyObject(); *phKey = CK_INVALID_HANDLE; } } return rv; } // Generate an EC key pair CK_RV SoftHSM::generateEC (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::ECDSA); 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; } ECPublicKey* pub = (ECPublicKey*) kp->getPublicKey(); ECPrivateKey* priv = (ECPrivateKey*) 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; 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_KEY_PAIR_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // EC Public Key Attributes ByteString point; if (isPublicKeyPrivate) { token->encrypt(pub->getQ(), point); } else { point = pub->getQ(); } bOK = bOK && osobject->setAttribute(CKA_EC_POINT, point); 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; 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_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); // EC Private Key Attributes ByteString group; ByteString value; if (isPrivateKeyPrivate) { token->encrypt(priv->getEC(), group); token->encrypt(priv->getD(), value); } else { group = priv->getEC(); value = priv->getD(); } 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, 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 prime; ByteString generator; for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_PRIME: prime = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; case CKA_BASE: generator = 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 (prime.size() == 0 || generator.size() == 0) { INFO_MSG("Missing parameter(s) in pPublicKeyTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // Extract optional bit length size_t bitLen = 0; for (CK_ULONG i = 0; i < ulPrivateKeyAttributeCount; i++) { switch (pPrivateKeyTemplate[i].type) { case CKA_VALUE_BITS: bitLen = *(CK_ULONG*)pPrivateKeyTemplate[i].pValue; break; default: break; } } // Set the parameters DHParameters p; p.setP(prime); p.setG(generator); p.setXBitLength(bitLen); // Generate key pair AsymmetricKeyPair* kp = NULL; AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH); if (dh == NULL) return CKR_GENERAL_ERROR; if (!dh->generateKeyPair(&kp, &p)) { ERROR_MSG("Could not generate key pair"); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); return CKR_GENERAL_ERROR; } DHPublicKey* pub = (DHPublicKey*) kp->getPublicKey(); DHPrivateKey* priv = (DHPrivateKey*) 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_DH; 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_DH_PKCS_KEY_PAIR_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // DH Public Key Attributes ByteString value; if (isPublicKeyPrivate) { token->encrypt(pub->getY(), value); } else { value = pub->getY(); } 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; } } // 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_DH; 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_DH_PKCS_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); // DH Private Key Attributes ByteString bPrime; ByteString bGenerator; ByteString bValue; if (isPrivateKeyPrivate) { token->encrypt(priv->getP(), bPrime); token->encrypt(priv->getG(), bGenerator); token->encrypt(priv->getX(), bValue); } else { bPrime = priv->getP(); bGenerator = priv->getG(); bValue = priv->getX(); } bOK = bOK && osobject->setAttribute(CKA_PRIME, bPrime); bOK = bOK && osobject->setAttribute(CKA_BASE, bGenerator); bOK = bOK && osobject->setAttribute(CKA_VALUE, bValue); if (bitLen == 0) { bOK = bOK && osobject->setAttribute(CKA_VALUE_BITS, (unsigned long)priv->getX().bits()); } if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } } // Clean up dh->recycleKeyPair(kp); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); // 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 domain parameter set CK_RV SoftHSM::generateDHParameters (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 bitLen = 0; for (CK_ULONG i = 0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_PRIME_BITS: if (pTemplate[i].ulValueLen != sizeof(CK_ULONG)) { INFO_MSG("CKA_PRIME_BITS does not have the size of CK_ULONG"); return CKR_ATTRIBUTE_VALUE_INVALID; } bitLen = *(CK_ULONG*)pTemplate[i].pValue; break; default: break; } } // CKA_PRIME_BITS must be specified if (bitLen == 0) { INFO_MSG("Missing CKA_PRIME_BITS in pTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // Generate domain parameters AsymmetricParameters* p = NULL; AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH); if (dh == NULL) return CKR_GENERAL_ERROR; if (!dh->generateParameters(&p, (void *)bitLen)) { ERROR_MSG("Could not generate parameters"); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); return CKR_GENERAL_ERROR; } DHParameters* params = (DHParameters*) p; CK_RV rv = CKR_OK; // Create the domain parameter object using C_CreateObject const CK_ULONG maxAttribs = 32; CK_OBJECT_CLASS objClass = CKO_DOMAIN_PARAMETERS; CK_KEY_TYPE keyType = CKK_DH; CK_ATTRIBUTE paramsAttribs[maxAttribs] = { { CKA_CLASS, &objClass, sizeof(objClass) }, { CKA_TOKEN, &isOnToken, sizeof(isOnToken) }, { CKA_PRIVATE, &isPrivate, sizeof(isPrivate) }, { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, }; CK_ULONG paramsAttribsCount = 4; // Add the additional if (ulCount > (maxAttribs - paramsAttribsCount)) 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: continue; default: paramsAttribs[paramsAttribsCount++] = pTemplate[i]; } } if (rv == CKR_OK) rv = this->CreateObject(hSession, paramsAttribs, paramsAttribsCount, 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_DH_PKCS_PARAMETER_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // DH Domain Parameters Attributes ByteString prime; ByteString generator; if (isPrivate) { token->encrypt(params->getP(), prime); token->encrypt(params->getG(), generator); } else { prime = params->getP(); generator = params->getG(); } bOK = bOK && osobject->setAttribute(CKA_PRIME, prime); bOK = bOK && osobject->setAttribute(CKA_BASE, generator); if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } // Clean up dh->recycleParameters(p); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); // Remove parameters that may have been created already when the function fails. if (rv != CKR_OK) { if (*phKey != CK_INVALID_HANDLE) { OSObject* osparams = (OSObject*)handleManager->getObject(*phKey); handleManager->destroyObject(*phKey); if (osparams) osparams->destroyObject(); *phKey = CK_INVALID_HANDLE; } } return rv; } // Generate a GOST key pair CK_RV SoftHSM::generateGOST (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 param_3410; ByteString param_3411; ByteString param_28147; for (CK_ULONG i = 0; i < ulPublicKeyAttributeCount; i++) { switch (pPublicKeyTemplate[i].type) { case CKA_GOSTR3410_PARAMS: param_3410 = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; case CKA_GOSTR3411_PARAMS: param_3411 = ByteString((unsigned char*)pPublicKeyTemplate[i].pValue, pPublicKeyTemplate[i].ulValueLen); break; case CKA_GOST28147_PARAMS: param_28147 = 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 (param_3410.size() == 0 || param_3411.size() == 0) { INFO_MSG("Missing parameter(s) in pPublicKeyTemplate"); return CKR_TEMPLATE_INCOMPLETE; } // Set the parameters ECParameters p; p.setEC(param_3410); // Generate key pair AsymmetricKeyPair* kp = NULL; AsymmetricAlgorithm* gost = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST); if (gost == NULL) return CKR_GENERAL_ERROR; if (!gost->generateKeyPair(&kp, &p)) { ERROR_MSG("Could not generate key pair"); CryptoFactory::i()->recycleAsymmetricAlgorithm(gost); return CKR_GENERAL_ERROR; } GOSTPublicKey* pub = (GOSTPublicKey*) kp->getPublicKey(); GOSTPrivateKey* priv = (GOSTPrivateKey*) 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_GOSTR3410; 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_KEY_PAIR_GEN; bOK = bOK && osobject->setAttribute(CKA_KEY_GEN_MECHANISM,ulKeyGenMechanism); // EC Public Key Attributes ByteString point; if (isPublicKeyPrivate) { token->encrypt(pub->getQ(), point); } else { point = pub->getQ(); } bOK = bOK && osobject->setAttribute(CKA_VALUE, point); 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_GOSTR3410; 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_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); // GOST Private Key Attributes ByteString value; ByteString param_a; ByteString param_b; ByteString param_c; if (isPrivateKeyPrivate) { token->encrypt(priv->getD(), value); token->encrypt(priv->getEC(), param_a); token->encrypt(param_3411, param_b); token->encrypt(param_28147, param_c); } else { value = priv->getD(); param_a = priv->getEC(); param_b = param_3411; param_c = param_28147; } bOK = bOK && osobject->setAttribute(CKA_VALUE, value); bOK = bOK && osobject->setAttribute(CKA_GOSTR3410_PARAMS, param_a); bOK = bOK && osobject->setAttribute(CKA_GOSTR3411_PARAMS, param_b); bOK = bOK && osobject->setAttribute(CKA_GOST28147_PARAMS, param_c); if (bOK) bOK = osobject->commitTransaction(); else osobject->abortTransaction(); if (!bOK) rv = CKR_FUNCTION_FAILED; } else rv = CKR_FUNCTION_FAILED; } } // Clean up gost->recycleKeyPair(kp); CryptoFactory::i()->recycleAsymmetricAlgorithm(gost); // 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 (*phKey != CK_INVALID_HANDLE) { OSObject* ossecret = (OSObject*)handleManager->getObject(*phKey); handleManager->destroyObject(*phKey); if (ossecret) ossecret->destroyObject(); *phKey = CK_INVALID_HANDLE; } } return rv; } // Derive an ECDH secret CK_RV SoftHSM::deriveECDH (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) { #ifdef WITH_ECC *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 ECDH algorithm handler AsymmetricAlgorithm* ecdh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDH); if (ecdh == NULL) return CKR_MECHANISM_INVALID; // Get the keys PrivateKey* privateKey = ecdh->newPrivateKey(); if (privateKey == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); return CKR_HOST_MEMORY; } if (getECPrivateKey((ECPrivateKey*)privateKey, token, baseKey) != CKR_OK) { ecdh->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); 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 = ecdh->newPublicKey(); if (publicKey == NULL) { ecdh->recyclePrivateKey(privateKey); CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); return CKR_HOST_MEMORY; } if (getECDHPublicKey((ECPublicKey*)publicKey, (ECPrivateKey*)privateKey, publicData) != CKR_OK) { 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 (!ecdh->deriveKey(&secret, publicKey, privateKey)) rv = CKR_GENERAL_ERROR; ecdh->recyclePrivateKey(privateKey); ecdh->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 ecdh->recycleSymmetricKey(secret); CryptoFactory::i()->recycleAsymmetricAlgorithm(ecdh); // 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; #else return CKR_MECHANISM_INVALID; #endif } // Derive an symmetric secret CK_RV SoftHSM::deriveSymmetric (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) { DEBUG_MSG("pParameter must be supplied"); return CKR_MECHANISM_PARAM_INVALID; } ByteString data; if ((pMechanism->mechanism == CKM_DES_ECB_ENCRYPT_DATA || pMechanism->mechanism == CKM_DES3_ECB_ENCRYPT_DATA) && pMechanism->ulParameterLen == sizeof(CK_KEY_DERIVATION_STRING_DATA)) { CK_BYTE_PTR pData = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->pData; CK_ULONG ulLen = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->ulLen; if (ulLen == 0 || pData == NULL_PTR) { DEBUG_MSG("There must be data in the parameter"); return CKR_MECHANISM_PARAM_INVALID; } if (ulLen % 8 != 0) { DEBUG_MSG("The data must be a multiple of 8 bytes long"); return CKR_MECHANISM_PARAM_INVALID; } data.resize(ulLen); memcpy(&data[0], pData, ulLen); } else if ((pMechanism->mechanism == CKM_DES_CBC_ENCRYPT_DATA || pMechanism->mechanism == CKM_DES3_CBC_ENCRYPT_DATA) && pMechanism->ulParameterLen == sizeof(CK_DES_CBC_ENCRYPT_DATA_PARAMS)) { CK_BYTE_PTR pData = CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->pData; CK_ULONG length = CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->length; if (length == 0 || pData == NULL_PTR) { DEBUG_MSG("There must be data in the parameter"); return CKR_MECHANISM_PARAM_INVALID; } if (length % 8 != 0) { DEBUG_MSG("The data must be a multiple of 8 bytes long"); return CKR_MECHANISM_PARAM_INVALID; } data.resize(length); memcpy(&data[0], pData, length); } else if (pMechanism->mechanism == CKM_AES_ECB_ENCRYPT_DATA && pMechanism->ulParameterLen == sizeof(CK_KEY_DERIVATION_STRING_DATA)) { CK_BYTE_PTR pData = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->pData; CK_ULONG ulLen = CK_KEY_DERIVATION_STRING_DATA_PTR(pMechanism->pParameter)->ulLen; if (ulLen == 0 || pData == NULL_PTR) { DEBUG_MSG("There must be data in the parameter"); return CKR_MECHANISM_PARAM_INVALID; } if (ulLen % 16 != 0) { DEBUG_MSG("The data must be a multiple of 16 bytes long"); return CKR_MECHANISM_PARAM_INVALID; } data.resize(ulLen); memcpy(&data[0], pData, ulLen); } else if ((pMechanism->mechanism == CKM_AES_CBC_ENCRYPT_DATA) && pMechanism->ulParameterLen == sizeof(CK_AES_CBC_ENCRYPT_DATA_PARAMS)) { CK_BYTE_PTR pData = CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->pData; CK_ULONG length = CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->length; if (length == 0 || pData == NULL_PTR) { DEBUG_MSG("There must be data in the parameter"); return CKR_MECHANISM_PARAM_INVALID; } if (length % 16 != 0) { DEBUG_MSG("The data must be a multiple of 16 bytes long"); return CKR_MECHANISM_PARAM_INVALID; } data.resize(length); memcpy(&data[0], pData, length); } else { DEBUG_MSG("pParameter is invalid"); 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 symmetric algorithm matching the mechanism SymAlgo::Type algo = SymAlgo::Unknown; SymMode::Type mode = SymMode::Unknown; bool padding = false; ByteString iv; size_t bb = 8; switch(pMechanism->mechanism) { #ifndef WITH_FIPS case CKM_DES_ECB_ENCRYPT_DATA: algo = SymAlgo::DES; mode = SymMode::ECB; bb = 7; break; case CKM_DES_CBC_ENCRYPT_DATA: algo = SymAlgo::DES; mode = SymMode::CBC; bb = 7; iv.resize(8); memcpy(&iv[0], &(CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]), 8); break; #endif case CKM_DES3_ECB_ENCRYPT_DATA: algo = SymAlgo::DES3; mode = SymMode::ECB; bb = 7; break; case CKM_DES3_CBC_ENCRYPT_DATA: algo = SymAlgo::DES3; mode = SymMode::CBC; bb = 7; iv.resize(8); memcpy(&iv[0], &(CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]), 8); break; case CKM_AES_ECB_ENCRYPT_DATA: algo = SymAlgo::AES; mode = SymMode::ECB; break; case CKM_AES_CBC_ENCRYPT_DATA: algo = SymAlgo::AES; mode = SymMode::CBC; iv.resize(16); memcpy(&iv[0], &(CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR(pMechanism->pParameter)->iv[0]), 16); break; default: return CKR_MECHANISM_INVALID; } // Check the key handle OSObject *baseKey = (OSObject *)handleManager->getObject(hBaseKey); if (baseKey == NULL_PTR || !baseKey->isValid()) return CKR_OBJECT_HANDLE_INVALID; SymmetricAlgorithm* cipher = CryptoFactory::i()->getSymmetricAlgorithm(algo); if (cipher == NULL) return CKR_MECHANISM_INVALID; SymmetricKey* secretkey = new SymmetricKey(); if (getSymmetricKey(secretkey, token, baseKey) != CKR_OK) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // adjust key bit length secretkey->setBitLen(secretkey->getKeyBits().size() * bb); // Initialize encryption if (!cipher->encryptInit(secretkey, mode, iv, padding)) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_MECHANISM_INVALID; } // Get the data ByteString secretValue; // Encrypt the data if (!cipher->encryptUpdate(data, secretValue)) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } // Finalize encryption ByteString encryptedFinal; if (!cipher->encryptFinal(encryptedFinal)) { cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); return CKR_GENERAL_ERROR; } cipher->recycleKey(secretkey); CryptoFactory::i()->recycleSymmetricAlgorithm(cipher); secretValue += encryptedFinal; // 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 CK_RV rv = CKR_OK; 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); } 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 trailing end if (byteLen < secretValue.size()) secretValue.resize(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 SymmetricKey* secret = new SymmetricKey(); secret->setKeyBits(secretValue); 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; } delete secret; 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; } // 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; } CK_RV SoftHSM::CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject, int op) { if (!isInitialised) return CKR_CRYPTOKI_NOT_INITIALIZED; if (pTemplate == NULL_PTR) return CKR_ARGUMENTS_BAD; if (phObject == NULL_PTR) return CKR_ARGUMENTS_BAD; // Get the session Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; // Get the slot Slot* slot = session->getSlot(); if (slot == NULL_PTR) return CKR_GENERAL_ERROR; // Get the token Token* token = session->getToken(); if (token == NULL_PTR) return CKR_GENERAL_ERROR; // Extract information from the template that is needed to create the object. CK_OBJECT_CLASS objClass = CKO_DATA; CK_KEY_TYPE keyType = CKK_RSA; CK_CERTIFICATE_TYPE certType = CKC_X_509; CK_BBOOL isOnToken = CK_FALSE; CK_BBOOL isPrivate = CK_TRUE; bool isImplicit = false; CK_RV rv = extractObjectInformation(pTemplate,ulCount,objClass,keyType,certType, isOnToken, isPrivate, isImplicit); if (rv != CKR_OK) { ERROR_MSG("Mandatory attribute not present in template"); return rv; } // Check user credentials rv = haveWrite(session->getState(), isOnToken, isPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) INFO_MSG("User is not authorized"); if (rv == CKR_SESSION_READ_ONLY) INFO_MSG("Session is read-only"); return rv; } // Change order of attributes const CK_ULONG maxAttribs = 32; CK_ATTRIBUTE attribs[maxAttribs]; CK_ATTRIBUTE saveAttribs[maxAttribs]; CK_ULONG attribsCount = 0; CK_ULONG saveAttribsCount = 0; if (ulCount > maxAttribs) { return CKR_TEMPLATE_INCONSISTENT; } for (CK_ULONG i=0; i < ulCount; i++) { switch (pTemplate[i].type) { case CKA_CHECK_VALUE: saveAttribs[saveAttribsCount++] = pTemplate[i]; break; default: attribs[attribsCount++] = pTemplate[i]; } } for (CK_ULONG i=0; i < saveAttribsCount; i++) { attribs[attribsCount++] = saveAttribs[i]; } P11Object* p11object = NULL; rv = newP11Object(objClass,keyType,certType,&p11object); if (rv != CKR_OK) return rv; // Create the object in session or on the token OSObject *object = NULL_PTR; if (isOnToken) { object = (OSObject*) token->createObject(); } else { object = sessionObjectStore->createObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE); } if (object == NULL || !p11object->init(object)) { delete p11object; return CKR_GENERAL_ERROR; } rv = p11object->saveTemplate(token, isPrivate != CK_FALSE, attribs,attribsCount,op); delete p11object; if (rv != CKR_OK) return rv; if (op == OBJECT_OP_CREATE) { if (objClass == CKO_PUBLIC_KEY && (!object->startTransaction() || !object->setAttribute(CKA_LOCAL, false) || !object->commitTransaction())) { return CKR_GENERAL_ERROR; } if ((objClass == CKO_SECRET_KEY || objClass == CKO_PRIVATE_KEY) && (!object->startTransaction() || !object->setAttribute(CKA_LOCAL, false) || !object->setAttribute(CKA_ALWAYS_SENSITIVE, false) || !object->setAttribute(CKA_NEVER_EXTRACTABLE, false) || !object->commitTransaction())) { return CKR_GENERAL_ERROR; } } if (isOnToken) { *phObject = handleManager->addTokenObject(slot->getSlotID(), isPrivate != CK_FALSE, object); } else { *phObject = handleManager->addSessionObject(slot->getSlotID(), hSession, isPrivate != CK_FALSE, object); } return CKR_OK; } CK_RV SoftHSM::getRSAPrivateKey(RSAPrivateKey* 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); // RSA Private Key Attributes ByteString modulus; ByteString publicExponent; ByteString privateExponent; ByteString prime1; ByteString prime2; ByteString exponent1; ByteString exponent2; ByteString coefficient; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_MODULUS), modulus); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PUBLIC_EXPONENT), publicExponent); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIVATE_EXPONENT), privateExponent); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME_1), prime1); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME_2), prime2); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EXPONENT_1), exponent1); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EXPONENT_2), exponent2); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_COEFFICIENT), coefficient); if (!bOK) return CKR_GENERAL_ERROR; } else { modulus = key->getByteStringValue(CKA_MODULUS); publicExponent = key->getByteStringValue(CKA_PUBLIC_EXPONENT); privateExponent = key->getByteStringValue(CKA_PRIVATE_EXPONENT); prime1 = key->getByteStringValue(CKA_PRIME_1); prime2 = key->getByteStringValue(CKA_PRIME_2); exponent1 = key->getByteStringValue(CKA_EXPONENT_1); exponent2 = key->getByteStringValue(CKA_EXPONENT_2); coefficient = key->getByteStringValue(CKA_COEFFICIENT); } privateKey->setN(modulus); privateKey->setE(publicExponent); privateKey->setD(privateExponent); privateKey->setP(prime1); privateKey->setQ(prime2); privateKey->setDP1(exponent1); privateKey->setDQ1(exponent2); privateKey->setPQ(coefficient); return CKR_OK; } CK_RV SoftHSM::getRSAPublicKey(RSAPublicKey* 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); // RSA Public Key Attributes ByteString modulus; ByteString publicExponent; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_MODULUS), modulus); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PUBLIC_EXPONENT), publicExponent); if (!bOK) return CKR_GENERAL_ERROR; } else { modulus = key->getByteStringValue(CKA_MODULUS); publicExponent = key->getByteStringValue(CKA_PUBLIC_EXPONENT); } publicKey->setN(modulus); publicKey->setE(publicExponent); return CKR_OK; } CK_RV SoftHSM::getDSAPrivateKey(DSAPrivateKey* 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); // DSA Private Key Attributes ByteString prime; ByteString subprime; ByteString generator; ByteString value; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_SUBPRIME), subprime); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value); if (!bOK) return CKR_GENERAL_ERROR; } else { prime = key->getByteStringValue(CKA_PRIME); subprime = key->getByteStringValue(CKA_SUBPRIME); generator = key->getByteStringValue(CKA_BASE); value = key->getByteStringValue(CKA_VALUE); } privateKey->setP(prime); privateKey->setQ(subprime); privateKey->setG(generator); privateKey->setX(value); return CKR_OK; } CK_RV SoftHSM::getDSAPublicKey(DSAPublicKey* 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); // DSA Public Key Attributes ByteString prime; ByteString subprime; ByteString generator; ByteString value; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_SUBPRIME), subprime); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value); if (!bOK) return CKR_GENERAL_ERROR; } else { prime = key->getByteStringValue(CKA_PRIME); subprime = key->getByteStringValue(CKA_SUBPRIME); generator = key->getByteStringValue(CKA_BASE); value = key->getByteStringValue(CKA_VALUE); } publicKey->setP(prime); publicKey->setQ(subprime); publicKey->setG(generator); publicKey->setY(value); return CKR_OK; } CK_RV SoftHSM::getECPrivateKey(ECPrivateKey* 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); // EC 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->setD(value); return CKR_OK; } CK_RV SoftHSM::getECPublicKey(ECPublicKey* 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 point; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_PARAMS), group); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_EC_POINT), point); if (!bOK) return CKR_GENERAL_ERROR; } else { group = key->getByteStringValue(CKA_EC_PARAMS); point = key->getByteStringValue(CKA_EC_POINT); } publicKey->setEC(group); publicKey->setQ(point); return CKR_OK; } CK_RV SoftHSM::getDHPrivateKey(DHPrivateKey* 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); // DH Private Key Attributes ByteString prime; ByteString generator; ByteString value; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_PRIME), prime); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_BASE), generator); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value); if (!bOK) return CKR_GENERAL_ERROR; } else { prime = key->getByteStringValue(CKA_PRIME); generator = key->getByteStringValue(CKA_BASE); value = key->getByteStringValue(CKA_VALUE); } privateKey->setP(prime); privateKey->setG(generator); privateKey->setX(value); return CKR_OK; } CK_RV SoftHSM::getDHPublicKey(DHPublicKey* publicKey, DHPrivateKey* privateKey, ByteString& pubParams) { if (publicKey == NULL) return CKR_ARGUMENTS_BAD; if (privateKey == NULL) return CKR_ARGUMENTS_BAD; // Copy Domain Parameters from Private Key publicKey->setP(privateKey->getP()); publicKey->setG(privateKey->getG()); // Set value publicKey->setY(pubParams); return CKR_OK; } CK_RV SoftHSM::getECDHPublicKey(ECPublicKey* publicKey, ECPrivateKey* 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->setQ(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) { // Raw: Length matches the public key size of P-256, P-384, or P-521 controlOctets = 0; } else if (len < controlOctets || pubData[0] != 0x04) { // Raw: Too short or does not start with 0x04 controlOctets = 0; } else if (pubData[1] < 0x80) { // Raw: Length octet does not match remaining data length if (pubData[1] != (len - controlOctets)) controlOctets = 0; } else { size_t lengthOctets = pubData[1] & 0x7F; controlOctets += lengthOctets; if (controlOctets >= len) { // Raw: Too short controlOctets = 0; } else { ByteString length(&pubData[2], lengthOctets); if (length.long_val() != (len - controlOctets)) { // Raw: Length octets does not match remaining data length controlOctets = 0; } } } // 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; } CK_RV SoftHSM::getGOSTPrivateKey(GOSTPrivateKey* 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); // GOST Private Key Attributes ByteString value; ByteString param; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), value); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_GOSTR3410_PARAMS), param); if (!bOK) return CKR_GENERAL_ERROR; } else { value = key->getByteStringValue(CKA_VALUE); param = key->getByteStringValue(CKA_GOSTR3410_PARAMS); } privateKey->setD(value); privateKey->setEC(param); return CKR_OK; } CK_RV SoftHSM::getGOSTPublicKey(GOSTPublicKey* 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); // GOST Public Key Attributes ByteString point; ByteString param; if (isKeyPrivate) { bool bOK = true; bOK = bOK && token->decrypt(key->getByteStringValue(CKA_VALUE), point); bOK = bOK && token->decrypt(key->getByteStringValue(CKA_GOSTR3410_PARAMS), param); if (!bOK) return CKR_GENERAL_ERROR; } else { point = key->getByteStringValue(CKA_VALUE); param = key->getByteStringValue(CKA_GOSTR3410_PARAMS); } publicKey->setQ(point); publicKey->setEC(param); return CKR_OK; } CK_RV SoftHSM::getSymmetricKey(SymmetricKey* skey, Token* token, OSObject* key) { if (skey == 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); ByteString keybits; if (isKeyPrivate) { if (!token->decrypt(key->getByteStringValue(CKA_VALUE), keybits)) return CKR_GENERAL_ERROR; } else { keybits = key->getByteStringValue(CKA_VALUE); } skey->setKeyBits(keybits); return CKR_OK; } bool SoftHSM::setRSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const { AsymmetricAlgorithm* rsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::RSA); if (rsa == NULL) return false; PrivateKey* priv = rsa->newPrivateKey(); if (priv == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); return false; } if (!priv->PKCS8Decode(ber)) { rsa->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); return false; } // RSA Private Key Attributes ByteString modulus; ByteString publicExponent; ByteString privateExponent; ByteString prime1; ByteString prime2; ByteString exponent1; ByteString exponent2; ByteString coefficient; if (isPrivate) { token->encrypt(((RSAPrivateKey*)priv)->getN(), modulus); token->encrypt(((RSAPrivateKey*)priv)->getE(), publicExponent); token->encrypt(((RSAPrivateKey*)priv)->getD(), privateExponent); token->encrypt(((RSAPrivateKey*)priv)->getP(), prime1); token->encrypt(((RSAPrivateKey*)priv)->getQ(), prime2); token->encrypt(((RSAPrivateKey*)priv)->getDP1(), exponent1); token->encrypt(((RSAPrivateKey*)priv)->getDQ1(), exponent2); token->encrypt(((RSAPrivateKey*)priv)->getPQ(), coefficient); } else { modulus = ((RSAPrivateKey*)priv)->getN(); publicExponent = ((RSAPrivateKey*)priv)->getE(); privateExponent = ((RSAPrivateKey*)priv)->getD(); prime1 = ((RSAPrivateKey*)priv)->getP(); prime2 = ((RSAPrivateKey*)priv)->getQ(); exponent1 = ((RSAPrivateKey*)priv)->getDP1(); exponent2 = ((RSAPrivateKey*)priv)->getDQ1(); coefficient = ((RSAPrivateKey*)priv)->getPQ(); } bool bOK = true; bOK = bOK && key->setAttribute(CKA_MODULUS, modulus); bOK = bOK && key->setAttribute(CKA_PUBLIC_EXPONENT, publicExponent); bOK = bOK && key->setAttribute(CKA_PRIVATE_EXPONENT, privateExponent); bOK = bOK && key->setAttribute(CKA_PRIME_1, prime1); bOK = bOK && key->setAttribute(CKA_PRIME_2, prime2); bOK = bOK && key->setAttribute(CKA_EXPONENT_1,exponent1); bOK = bOK && key->setAttribute(CKA_EXPONENT_2, exponent2); bOK = bOK && key->setAttribute(CKA_COEFFICIENT, coefficient); rsa->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(rsa); return bOK; } bool SoftHSM::setDSAPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const { AsymmetricAlgorithm* dsa = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DSA); if (dsa == NULL) return false; PrivateKey* priv = dsa->newPrivateKey(); if (priv == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); return false; } if (!priv->PKCS8Decode(ber)) { dsa->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); return false; } // DSA Private Key Attributes ByteString prime; ByteString subprime; ByteString generator; ByteString value; if (isPrivate) { token->encrypt(((DSAPrivateKey*)priv)->getP(), prime); token->encrypt(((DSAPrivateKey*)priv)->getQ(), subprime); token->encrypt(((DSAPrivateKey*)priv)->getG(), generator); token->encrypt(((DSAPrivateKey*)priv)->getX(), value); } else { prime = ((DSAPrivateKey*)priv)->getP(); subprime = ((DSAPrivateKey*)priv)->getQ(); generator = ((DSAPrivateKey*)priv)->getG(); value = ((DSAPrivateKey*)priv)->getX(); } bool bOK = true; bOK = bOK && key->setAttribute(CKA_PRIME, prime); bOK = bOK && key->setAttribute(CKA_SUBPRIME, subprime); bOK = bOK && key->setAttribute(CKA_BASE, generator); bOK = bOK && key->setAttribute(CKA_VALUE, value); dsa->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(dsa); return bOK; } bool SoftHSM::setDHPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const { AsymmetricAlgorithm* dh = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::DH); if (dh == NULL) return false; PrivateKey* priv = dh->newPrivateKey(); if (priv == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); return false; } if (!priv->PKCS8Decode(ber)) { dh->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); return false; } // DH Private Key Attributes ByteString prime; ByteString generator; ByteString value; if (isPrivate) { token->encrypt(((DHPrivateKey*)priv)->getP(), prime); token->encrypt(((DHPrivateKey*)priv)->getG(), generator); token->encrypt(((DHPrivateKey*)priv)->getX(), value); } else { prime = ((DHPrivateKey*)priv)->getP(); generator = ((DHPrivateKey*)priv)->getG(); value = ((DHPrivateKey*)priv)->getX(); } bool bOK = true; bOK = bOK && key->setAttribute(CKA_PRIME, prime); bOK = bOK && key->setAttribute(CKA_BASE, generator); bOK = bOK && key->setAttribute(CKA_VALUE, value); dh->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(dh); return bOK; } bool SoftHSM::setECPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const { AsymmetricAlgorithm* ecc = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::ECDSA); if (ecc == NULL) return false; PrivateKey* priv = ecc->newPrivateKey(); if (priv == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc); return false; } if (!priv->PKCS8Decode(ber)) { ecc->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc); return false; } // EC Private Key Attributes ByteString group; ByteString value; if (isPrivate) { token->encrypt(((ECPrivateKey*)priv)->getEC(), group); token->encrypt(((ECPrivateKey*)priv)->getD(), value); } else { group = ((ECPrivateKey*)priv)->getEC(); value = ((ECPrivateKey*)priv)->getD(); } bool bOK = true; bOK = bOK && key->setAttribute(CKA_EC_PARAMS, group); bOK = bOK && key->setAttribute(CKA_VALUE, value); ecc->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(ecc); return bOK; } bool SoftHSM::setGOSTPrivateKey(OSObject* key, const ByteString &ber, Token* token, bool isPrivate) const { AsymmetricAlgorithm* gost = CryptoFactory::i()->getAsymmetricAlgorithm(AsymAlgo::GOST); if (gost == NULL) return false; PrivateKey* priv = gost->newPrivateKey(); if (priv == NULL) { CryptoFactory::i()->recycleAsymmetricAlgorithm(gost); return false; } if (!priv->PKCS8Decode(ber)) { gost->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(gost); return false; } // GOST Private Key Attributes ByteString value; ByteString param_a; if (isPrivate) { token->encrypt(((GOSTPrivateKey*)priv)->getD(), value); token->encrypt(((GOSTPrivateKey*)priv)->getEC(), param_a); } else { value = ((GOSTPrivateKey*)priv)->getD(); param_a = ((GOSTPrivateKey*)priv)->getEC(); } bool bOK = true; bOK = bOK && key->setAttribute(CKA_VALUE, value); bOK = bOK && key->setAttribute(CKA_GOSTR3410_PARAMS, param_a); gost->recyclePrivateKey(priv); CryptoFactory::i()->recycleAsymmetricAlgorithm(gost); return bOK; } CK_RV SoftHSM::MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism) { // This is a programming error if (pMechanism->mechanism != CKM_RSA_PKCS_OAEP) { ERROR_MSG("MechParamCheckRSAPKCSOAEP called on wrong mechanism"); return CKR_GENERAL_ERROR; } if (pMechanism->pParameter == NULL_PTR || pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_OAEP_PARAMS)) { ERROR_MSG("pParameter must be of type CK_RSA_PKCS_OAEP_PARAMS"); return CKR_ARGUMENTS_BAD; } CK_RSA_PKCS_OAEP_PARAMS_PTR params = (CK_RSA_PKCS_OAEP_PARAMS_PTR)pMechanism->pParameter; if (params->hashAlg != CKM_SHA_1) { ERROR_MSG("hashAlg must be CKM_SHA_1"); return CKR_ARGUMENTS_BAD; } if (params->mgf != CKG_MGF1_SHA1) { ERROR_MSG("mgf must be CKG_MGF1_SHA1"); return CKR_ARGUMENTS_BAD; } if (params->source != CKZ_DATA_SPECIFIED) { ERROR_MSG("source must be CKZ_DATA_SPECIFIED"); return CKR_ARGUMENTS_BAD; } if (params->pSourceData != NULL) { ERROR_MSG("pSourceData must be NULL"); return CKR_ARGUMENTS_BAD; } if (params->ulSourceDataLen != 0) { ERROR_MSG("ulSourceDataLen must be 0"); return CKR_ARGUMENTS_BAD; } return CKR_OK; } bool SoftHSM::isMechanismPermitted(OSObject* key, CK_MECHANISM_PTR pMechanism) { OSAttribute attribute = key->getAttribute(CKA_ALLOWED_MECHANISMS); std::set allowed = attribute.getMechanismTypeSetValue(); if (allowed.empty()) { return true; } return allowed.find(pMechanism->mechanism) != allowed.end(); }