diff --git a/src/lib/SoftHSM.cpp b/src/lib/SoftHSM.cpp index 50a05d2ea..62c695b99 100644 --- a/src/lib/SoftHSM.cpp +++ b/src/lib/SoftHSM.cpp @@ -746,6 +746,7 @@ void SoftHSM::prepareSupportedMechanisms(std::mapflags = CKF_WRAP | CKF_UNWRAP; break; #endif + case CKM_RSA_AES_KEY_WRAP: + pInfo->ulMinKeySize = rsaMinSize; + pInfo->ulMaxKeySize = rsaMaxSize; + pInfo->flags = CKF_WRAP | CKF_UNWRAP; + break; + #ifndef WITH_FIPS case CKM_DES_ECB_ENCRYPT_DATA: case CKM_DES_CBC_ENCRYPT_DATA: @@ -6456,6 +6463,102 @@ CK_RV SoftHSM::WrapKeyAsym return CKR_OK; } +// Internal: Wrap with mechanism RSA_AES_KEY_WRAP +CK_RV SoftHSM::WrapMechRsaAesKw +( + CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + Token *token, + OSObject *wrapKey, + ByteString &keydata, + ByteString &wrapped +) +{ + CK_RV rv = CKR_OK; + ByteString wrapped_1; // buffer for the wrapped AES key; + ByteString wrapped_2; // buffer for the wrapped target key; + CK_RSA_AES_KEY_WRAP_PARAMS_PTR params = (CK_RSA_AES_KEY_WRAP_PARAMS_PTR)pMechanism->pParameter; + CK_ULONG emphKeyLen = params->aes_key_bits / 8; + CK_OBJECT_HANDLE hEmphKey = CK_INVALID_HANDLE; + CK_OBJECT_CLASS emphKeyClass = CKO_SECRET_KEY; + CK_KEY_TYPE emphKeyType = CKK_AES; + CK_BBOOL bFalse = CK_FALSE; + CK_BBOOL bTrue = CK_TRUE; + CK_ATTRIBUTE emph_temp[] = { + {CKA_CLASS, &emphKeyClass, sizeof(CK_OBJECT_CLASS)}, + {CKA_KEY_TYPE, &emphKeyType, sizeof(CK_KEY_TYPE)}, + {CKA_TOKEN, &bFalse, sizeof(CK_BBOOL)}, + {CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL)}, + {CKA_WRAP, &bTrue, sizeof(CK_BBOOL)}, + {CKA_EXTRACTABLE, &bTrue, sizeof(CK_BBOOL)}, + {CKA_VALUE_LEN, &emphKeyLen, sizeof(CK_ULONG)} + }; + + // Generates temporary random AES key of ulAESKeyBits length. + rv = this->generateAES(hSession, emph_temp, sizeof(emph_temp)/sizeof(CK_ATTRIBUTE), &hEmphKey, bFalse, bTrue); + if (rv != CKR_OK) + { + // Remove secret that may have been created already when the function fails. + if (hEmphKey != CK_INVALID_HANDLE) + { + OSObject *emphKey = (OSObject *)handleManager->getObject(hEmphKey); + handleManager->destroyObject(hEmphKey); + if(emphKey) emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + } + return rv; + } + + OSObject *emphKey = (OSObject *)handleManager->getObject(hEmphKey); + if (emphKey == NULL_PTR || !emphKey->isValid()) + { + rv = CKR_FUNCTION_FAILED; + handleManager->destroyObject(hEmphKey); + if(emphKey) emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + return rv; + } + + CK_MECHANISM emphMech = {CKM_AES_KEY_WRAP_PAD, NULL_PTR, 0}; + // Wraps the target key with the temporary AES key using CKM_AES_KEY_WRAP_PAD (RFC5649). + rv = SoftHSM::WrapKeySym(&emphMech, token, emphKey, keydata, wrapped_2); + if (rv != CKR_OK) + { + handleManager->destroyObject(hEmphKey); + emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + return rv; + } + + // Get the AES emph key data + ByteString emphkeydata; + ByteString emphKeyValue = emphKey->getByteStringValue(CKA_VALUE); + token->decrypt(emphKeyValue, emphkeydata); + + // Remove the emph key handle. + handleManager->destroyObject(hEmphKey); + emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + + CK_MECHANISM oaepMech = {CKM_RSA_PKCS_OAEP, params->oaep_params, sizeof(CK_RSA_PKCS_OAEP_PARAMS)}; + // Wraps the AES emph key with the wrapping RSA key using CKM_RSA_PKCS_OAEP with parameters of OAEPParams. + rv = SoftHSM::WrapKeyAsym(&oaepMech, token, wrapKey, emphkeydata, wrapped_1); + + // Zeroizes the temporary AES emph key + emphkeydata.wipe(); + emphKeyValue.wipe(); + + if (rv != CKR_OK) + { + return rv; + } + + // Concatenates two wrapped keys and outputs the concatenated blob. + wrapped = wrapped_1 + wrapped_2; + + return rv; +} + // Wrap the specified key using the specified wrapping key and mechanism CK_RV SoftHSM::C_WrapKey @@ -6498,6 +6601,11 @@ CK_RV SoftHSM::C_WrapKey if (rv != CKR_OK) return rv; break; + case CKM_RSA_AES_KEY_WRAP: + rv = MechParamCheckRSAAESKEYWRAP(pMechanism); + if (rv != CKR_OK) + return rv; + break; case CKM_AES_CBC: case CKM_AES_CBC_PAD: if (pMechanism->pParameter == NULL_PTR || @@ -6532,13 +6640,15 @@ CK_RV SoftHSM::C_WrapKey // 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) + if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP || pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) && + 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) + if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP || pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) && + wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; @@ -6712,12 +6822,24 @@ CK_RV SoftHSM::C_WrapKey keyClass = wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED); ByteString wrapped; - if (keyClass == CKO_SECRET_KEY) - rv = SoftHSM::WrapKeySym(pMechanism, token, wrapKey, keydata, wrapped); + + if (pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) + { + rv = WrapMechRsaAesKw(hSession, pMechanism, token, wrapKey, keydata, wrapped); + if (rv != CKR_OK) + { + return rv; + } + } else - rv = SoftHSM::WrapKeyAsym(pMechanism, token, wrapKey, keydata, wrapped); - if (rv != CKR_OK) - return rv; + { + 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()) @@ -6901,6 +7023,148 @@ CK_RV SoftHSM::UnwrapKeyAsym return rv; } +// Internal: Unwrap with mechanism RSA_AES_KEY_WRAP +CK_RV SoftHSM::UnwrapMechRsaAesKw +( + CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + Token *token, + OSObject *unwrapKey, + ByteString &wrapped, + ByteString &keydata +) +{ + CK_RV rv = CKR_OK; + CK_OBJECT_HANDLE hEmphKey = CK_INVALID_HANDLE; + CK_RSA_AES_KEY_WRAP_PARAMS_PTR params = (CK_RSA_AES_KEY_WRAP_PARAMS_PTR)pMechanism->pParameter; + ByteString emphkeydata; + ByteString modulus; + ByteString modulusValue = unwrapKey->getByteStringValue(CKA_MODULUS); + + CK_BBOOL isUnwrapKeyPrivate = unwrapKey->getBooleanValue(CKA_PRIVATE, true); + if(isUnwrapKeyPrivate) + { + token->decrypt(modulusValue, modulus); + } + else + { + modulus = modulusValue; + } + + CK_ULONG ulWrappedKeyLen = wrapped.size(); + CK_ULONG wrappedLen1 = modulus.size(); + CK_ULONG wrappedLen2 = ulWrappedKeyLen - wrappedLen1; + + ByteString wrapped_1(&wrapped[0], wrappedLen1); // the wrapped AES key + CK_MECHANISM oaepMech = {CKM_RSA_PKCS_OAEP, params->oaep_params, sizeof(CK_RSA_PKCS_OAEP_PARAMS)}; + + // Un-wraps the temporary AES key from the first part with the private RSA key using CKM_RSA_PKCS_OAEP. + rv = UnwrapKeyAsym(&oaepMech, wrapped_1, token, unwrapKey, emphkeydata); + if (rv != CKR_OK) + { + emphkeydata.wipe(); + return rv; + } + + CK_OBJECT_CLASS emphKeyClass = CKO_SECRET_KEY; + CK_KEY_TYPE emphKeyType = CKK_AES; + CK_BBOOL bFalse = CK_FALSE; + CK_BBOOL bTrue = CK_TRUE; + CK_ATTRIBUTE emph_temp[] = { + {CKA_CLASS, &emphKeyClass, sizeof(CK_OBJECT_CLASS)}, + {CKA_KEY_TYPE, &emphKeyType, sizeof(CK_KEY_TYPE)}, + {CKA_TOKEN, &bFalse, sizeof(CK_BBOOL)}, + {CKA_PRIVATE, &bTrue, sizeof(CK_BBOOL)}, + {CKA_UNWRAP, &bTrue, sizeof(CK_BBOOL)} + }; + + // Create the temporary AES object using C_CreateObject + rv = this->CreateObject(hSession, emph_temp, sizeof(emph_temp) / sizeof(CK_ATTRIBUTE), &hEmphKey, OBJECT_OP_UNWRAP); + if (rv != CKR_OK) + { + // Remove secret that may have been created already when the function fails. + if (hEmphKey != CK_INVALID_HANDLE) + { + OSObject *emphKey = (OSObject *)handleManager->getObject(hEmphKey); + handleManager->destroyObject(hEmphKey); + if(emphKey) emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + } + emphkeydata.wipe(); + return rv; + } + + // Store the attributes of emphkey + OSObject *emphKey = (OSObject *)handleManager->getObject(hEmphKey); + if (emphKey == NULL_PTR || !emphKey->isValid()) + { + rv = CKR_FUNCTION_FAILED; + handleManager->destroyObject(hEmphKey); + if(emphKey) emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + emphkeydata.wipe(); + return rv; + } + + if (emphKey->startTransaction()) + { + bool bOK = true; + // Common Attributes + bOK = bOK && emphKey->setAttribute(CKA_LOCAL, false); + // Common Secret Key Attributes + bOK = bOK && emphKey->setAttribute(CKA_ALWAYS_SENSITIVE, false); + bOK = bOK && emphKey->setAttribute(CKA_NEVER_EXTRACTABLE, false); + // Secret Attributes + ByteString emphKeyValue; + token->encrypt(emphkeydata, emphKeyValue); + bOK = bOK && emphKey->setAttribute(CKA_VALUE, emphKeyValue); + + if (bOK) + { + bOK = emphKey->commitTransaction(); + } + else + { + emphKey->abortTransaction(); + } + + // Zeroizes the temporary AES key. + emphkeydata.wipe(); + emphKeyValue.wipe(); + + if (!bOK) + { + rv = CKR_FUNCTION_FAILED; + handleManager->destroyObject(hEmphKey); + emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + return rv; + } + } + else + { + rv = CKR_FUNCTION_FAILED; + emphkeydata.wipe(); + handleManager->destroyObject(hEmphKey); + emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + return rv; + } + + ByteString wrapped_2(&wrapped[wrappedLen1], wrappedLen2); // the wrapped target key + CK_MECHANISM emphMech = {CKM_AES_KEY_WRAP_PAD, NULL_PTR, 0}; + + // Un-wraps the target key from the second part with the temporary AES key using CKM_AES_KEY_WRAP_PAD (RFC5649) + rv = UnwrapKeySym(&emphMech, wrapped_2, token, emphKey, keydata); + + // remove the emphkey handle + handleManager->destroyObject(hEmphKey); + emphKey->destroyObject(); + hEmphKey = CK_INVALID_HANDLE; + + return rv; +} + // Unwrap the specified key using the specified unwrapping key CK_RV SoftHSM::C_UnwrapKey ( @@ -6957,6 +7221,11 @@ CK_RV SoftHSM::C_UnwrapKey if (rv != CKR_OK) return rv; break; + case CKM_RSA_AES_KEY_WRAP: + rv = MechParamCheckRSAAESKEYWRAP(pMechanism); + if (rv != CKR_OK) + return rv; + break; case CKM_AES_CBC_PAD: // TODO check block length @@ -7004,9 +7273,11 @@ CK_RV SoftHSM::C_UnwrapKey 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) + if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP || pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) && + 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) + if ((pMechanism->mechanism == CKM_RSA_PKCS || pMechanism->mechanism == CKM_RSA_PKCS_OAEP || pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) && + unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) return CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; if ((pMechanism->mechanism == CKM_AES_CBC || pMechanism->mechanism == CKM_AES_CBC_PAD) && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_AES) return CKR_WRAPPING_KEY_TYPE_INCONSISTENT; @@ -7128,14 +7399,26 @@ CK_RV SoftHSM::C_UnwrapKey // 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); + + if (pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) + { + rv = UnwrapMechRsaAesKw(hSession, pMechanism, token, unwrapKey, wrapped, keydata); + if (rv != CKR_OK) + { + return rv; + } + } else - rv = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT; - if (rv != CKR_OK) - return rv; + { + 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); @@ -12860,6 +13143,56 @@ CK_RV SoftHSM::MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism) return CKR_OK; } + +CK_RV SoftHSM::MechParamCheckRSAAESKEYWRAP(CK_MECHANISM_PTR pMechanism) +{ + // This is a programming error + if (pMechanism->mechanism != CKM_RSA_AES_KEY_WRAP) { + ERROR_MSG("MechParamCheckRSAAESKEYWRAP called on wrong mechanism"); + return CKR_GENERAL_ERROR; + } + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) + { + ERROR_MSG("pParameter must be of type CK_RSA_AES_KEY_WRAP_PARAMS"); + return CKR_ARGUMENTS_BAD; + } + + CK_RSA_AES_KEY_WRAP_PARAMS_PTR params = (CK_RSA_AES_KEY_WRAP_PARAMS_PTR)pMechanism->pParameter; + if (params->aes_key_bits != 128 && params->aes_key_bits != 192 && params->aes_key_bits != 256) + { + ERROR_MSG("length of the temporary AES key in bits can be only 128, 192 or 256"); + return CKR_ARGUMENTS_BAD; + } + if (params->oaep_params == NULL_PTR) + { + ERROR_MSG("oaep_params must be of type CK_RSA_PKCS_OAEP_PARAMS"); + return CKR_ARGUMENTS_BAD; + } + if (params->oaep_params->mgf < 1UL || params->oaep_params->mgf > 5UL) + { + ERROR_MSG("mgf not supported"); + return CKR_ARGUMENTS_BAD; + } + if (params->oaep_params->source != CKZ_DATA_SPECIFIED) + { + ERROR_MSG("source must be CKZ_DATA_SPECIFIED"); + return CKR_ARGUMENTS_BAD; + } + if (params->oaep_params->pSourceData != NULL) + { + ERROR_MSG("pSourceData must be NULL"); + return CKR_ARGUMENTS_BAD; + } + if (params->oaep_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) { std::list mechs = supportedMechanisms; diff --git a/src/lib/SoftHSM.h b/src/lib/SoftHSM.h index e92a1772c..644686b2b 100644 --- a/src/lib/SoftHSM.h +++ b/src/lib/SoftHSM.h @@ -487,7 +487,28 @@ class SoftHSM ByteString &keydata ); + CK_RV WrapMechRsaAesKw + ( + CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + Token *token, + OSObject *wrapKey, + ByteString &keydata, + ByteString &wrapped + ); + + CK_RV UnwrapMechRsaAesKw + ( + CK_SESSION_HANDLE hSession, + CK_MECHANISM_PTR pMechanism, + Token *token, + OSObject *unwrapKey, + ByteString &wrapped, + ByteString &keydata + ); + CK_RV MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism); + CK_RV MechParamCheckRSAAESKEYWRAP(CK_MECHANISM_PTR pMechanism); bool isMechanismPermitted(OSObject* key, CK_MECHANISM_PTR pMechanism); void prepareSupportedMechanisms(std::map &t); diff --git a/src/lib/pkcs11/pkcs11.h b/src/lib/pkcs11/pkcs11.h index 7b6aa3ada..cd195794c 100644 --- a/src/lib/pkcs11/pkcs11.h +++ b/src/lib/pkcs11/pkcs11.h @@ -195,6 +195,9 @@ extern "C" { #define source_data pSourceData #define source_data_len ulSourceDataLen +#define aes_key_bits ulAESKeyBits +#define oaep_params pOAEPParams + #define counter_bits ulCounterBits #define iv_ptr pIv #define iv_len ulIvLen @@ -976,6 +979,11 @@ struct ck_rsa_pkcs_oaep_params { unsigned long source_data_len; }; +struct ck_rsa_aes_key_wrap_params { + unsigned long aes_key_bits; + ck_rsa_pkcs_oaep_params *oaep_params; +}; + struct ck_aes_ctr_params { unsigned long counter_bits; unsigned char cb[16]; @@ -1626,6 +1634,9 @@ typedef struct ck_rsa_pkcs_pss_params *CK_RSA_PKCS_PSS_PARAMS_PTR; typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS; typedef struct ck_rsa_pkcs_oaep_params *CK_RSA_PKCS_OAEP_PARAMS_PTR; +typedef struct ck_rsa_aes_key_wrap_params CK_RSA_AES_KEY_WRAP_PARAMS; +typedef struct ck_rsa_aes_key_wrap_params *CK_RSA_AES_KEY_WRAP_PARAMS_PTR; + typedef struct ck_aes_ctr_params CK_AES_CTR_PARAMS; typedef struct ck_aes_ctr_params *CK_AES_CTR_PARAMS_PTR; diff --git a/src/lib/test/AsymWrapUnwrapTests.cpp b/src/lib/test/AsymWrapUnwrapTests.cpp index 9daa302c5..917747bf1 100644 --- a/src/lib/test/AsymWrapUnwrapTests.cpp +++ b/src/lib/test/AsymWrapUnwrapTests.cpp @@ -37,13 +37,14 @@ #include "AsymWrapUnwrapTests.h" // CKA_TOKEN +const CK_BBOOL ON_TOKEN = CK_TRUE; const CK_BBOOL IN_SESSION = CK_FALSE; // CKA_PRIVATE const CK_BBOOL IS_PUBLIC = CK_FALSE; +const CK_BBOOL IS_PRIVATE = CK_TRUE; - -//CPPUNIT_TEST_SUITE_REGISTRATION(AsymWrapUnwrapTests); +CPPUNIT_TEST_SUITE_REGISTRATION(AsymWrapUnwrapTests); // Generate throw-away (session) symmetric key CK_RV AsymWrapUnwrapTests::generateAesKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE &hKey) @@ -70,16 +71,20 @@ CK_RV AsymWrapUnwrapTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBO { CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_ULONG bits = 1536; + CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; + CK_OBJECT_CLASS pvtClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; CK_BYTE pubExp[] = {0x01, 0x00, 0x01}; CK_BYTE subject[] = { 0x12, 0x34 }; // dummy CK_BYTE id[] = { 123 } ; // dummy - CK_BBOOL bFalse = CK_FALSE; CK_BBOOL bTrue = CK_TRUE; CK_ATTRIBUTE pukAttribs[] = { { CKA_TOKEN, &bTokenPuk, sizeof(bTokenPuk) }, { CKA_PRIVATE, &bPrivatePuk, sizeof(bPrivatePuk) }, - { CKA_ENCRYPT, &bFalse, sizeof(bFalse) }, - { CKA_VERIFY, &bFalse, sizeof(bFalse) }, + { CKA_CLASS, &pubClass, sizeof(pubClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType)}, + { CKA_ENCRYPT,&bTrue, sizeof(bTrue) }, + { CKA_VERIFY, &bTrue, sizeof(bTrue) }, { CKA_WRAP, &bTrue, sizeof(bTrue) }, { CKA_MODULUS_BITS, &bits, sizeof(bits) }, { CKA_PUBLIC_EXPONENT, &pubExp[0], sizeof(pubExp) } @@ -87,12 +92,15 @@ CK_RV AsymWrapUnwrapTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBO CK_ATTRIBUTE prkAttribs[] = { { CKA_TOKEN, &bTokenPrk, sizeof(bTokenPrk) }, { CKA_PRIVATE, &bPrivatePrk, sizeof(bPrivatePrk) }, + { CKA_CLASS, &pvtClass, sizeof(pvtClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType)}, { CKA_SUBJECT, &subject[0], sizeof(subject) }, { CKA_ID, &id[0], sizeof(id) }, { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, - { CKA_DECRYPT, &bFalse, sizeof(bFalse) }, - { CKA_SIGN, &bFalse, sizeof(bFalse) }, + { CKA_DECRYPT, &bTrue, sizeof(bTrue) }, + { CKA_SIGN, &bTrue, sizeof(bTrue) }, { CKA_UNWRAP, &bTrue, sizeof(bTrue) }, + { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue)}, }; hPuk = CK_INVALID_HANDLE; @@ -103,6 +111,80 @@ CK_RV AsymWrapUnwrapTests::generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBO &hPuk, &hPrk) ); } +void AsymWrapUnwrapTests::rsaWrapUnwrapPvt(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey) +{ + CK_RV rv = CKR_OK; + CK_MECHANISM_INFO mechInfo; + CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL_PTR, 0 }; + CK_RSA_AES_KEY_WRAP_PARAMS rsa_aes_params = { 256, &oaepParams }; + CK_MECHANISM mechanism = {CKM_RSA_AES_KEY_WRAP, &rsa_aes_params, sizeof(rsa_aes_params)}; + CK_MECHANISM sv_mechanism = { CKM_RSA_PKCS, NULL_PTR, 0 }; + CK_BYTE data[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,0x0C, 0x0D, 0x0F }; + CK_BYTE signature[256]; + CK_ULONG ulSignatureLen = 0; + CK_BYTE cipherText[2048]; + CK_ULONG ulCipherTextLen = 0; + CK_ULONG wrappedLenEstimation = 0; + CK_OBJECT_HANDLE targetPvtKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE targetPubKey = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE unwrappedKey = CK_INVALID_HANDLE; + CK_BBOOL bFalse = CK_FALSE; + CK_BBOOL bTrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; + CK_KEY_TYPE keyType = CKK_RSA; + CK_ATTRIBUTE unwrapTemplate[] = { + { CKA_CLASS, &keyClass, sizeof(keyClass) }, + { CKA_KEY_TYPE, &keyType, sizeof(keyType) }, + { CKA_TOKEN, &bFalse, sizeof(bFalse) }, + { CKA_SENSITIVE, &bTrue, sizeof(bTrue) }, + { CKA_EXTRACTABLE, &bTrue, sizeof(bTrue) } + }; + + // Generate temporary asymmetric key pair + rv = generateRsaKeyPair( hSession, IN_SESSION, IS_PRIVATE, IN_SESSION, IS_PRIVATE, targetPubKey, targetPvtKey ); + CPPUNIT_ASSERT(rv == CKR_OK); + + // Check if the specified mechanism supports Wrap/Unwrap + rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, CKM_RSA_AES_KEY_WRAP, &mechInfo) ); + CPPUNIT_ASSERT(rv==CKR_OK); + CPPUNIT_ASSERT(mechInfo.flags&CKF_WRAP); + CPPUNIT_ASSERT(mechInfo.flags&CKF_UNWRAP); + + // Estimate wrapped length + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, targetPvtKey, NULL_PTR, &wrappedLenEstimation) ); + CPPUNIT_ASSERT(rv==CKR_OK); + CPPUNIT_ASSERT(wrappedLenEstimation>0); + + // This should always fail because wrapped data have to be longer than 0 bytes + ulCipherTextLen = 0; + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, targetPvtKey, cipherText, &ulCipherTextLen) ); + CPPUNIT_ASSERT(rv==CKR_BUFFER_TOO_SMALL); + + // Do real wrapping + ulCipherTextLen = sizeof(cipherText); + rv = CRYPTOKI_F_PTR( C_WrapKey(hSession, &mechanism, hPublicKey, targetPvtKey, cipherText, &ulCipherTextLen) ); + CPPUNIT_ASSERT(rv==CKR_OK); + CPPUNIT_ASSERT(wrappedLenEstimation==ulCipherTextLen); + + rv = CRYPTOKI_F_PTR( C_UnwrapKey(hSession, &mechanism, hPrivateKey, cipherText, ulCipherTextLen, unwrapTemplate, sizeof(unwrapTemplate)/sizeof(CK_ATTRIBUTE), &unwrappedKey) ); + CPPUNIT_ASSERT(rv==CKR_OK); + CPPUNIT_ASSERT(unwrappedKey != CK_INVALID_HANDLE); + + // Verify the private key is unwrapped properly + rv = CRYPTOKI_F_PTR( C_SignInit(hSession, &sv_mechanism, unwrappedKey) ); + CPPUNIT_ASSERT(rv==CKR_OK); + + ulSignatureLen = sizeof(signature); + rv = CRYPTOKI_F_PTR( C_Sign(hSession, data, sizeof(data), signature, &ulSignatureLen) ); + CPPUNIT_ASSERT(rv==CKR_OK); + + rv = CRYPTOKI_F_PTR( C_VerifyInit(hSession, &sv_mechanism, targetPubKey) ); + CPPUNIT_ASSERT(rv==CKR_OK); + + rv = CRYPTOKI_F_PTR( C_Verify(hSession, data, sizeof(data), signature, ulSignatureLen) ); + CPPUNIT_ASSERT(rv==CKR_OK); +} + void AsymWrapUnwrapTests::rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey) { CK_MECHANISM mechanism = { mechanismType, NULL_PTR, 0 }; @@ -142,6 +224,12 @@ void AsymWrapUnwrapTests::rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESS mechanism.ulParameterLen = sizeof(oaepParams); } + if (mechanismType == CKM_RSA_AES_KEY_WRAP) + { + rsaWrapUnwrapPvt(hSession, hPublicKey, hPrivateKey); + return; + } + // Generate temporary symmetric key and remember it's value rv = generateAesKey(hSession, symKey); CPPUNIT_ASSERT(rv==CKR_OK); @@ -150,8 +238,8 @@ void AsymWrapUnwrapTests::rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESS CPPUNIT_ASSERT(rv==CKR_OK); ulSymValueLen = valueTemplate[0].ulValueLen; - // CKM_RSA_PKCS Wrap/Unwrap support - rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, CKM_RSA_PKCS, &mechInfo) ); + // Check if the specified mechanism supports Wrap/Unwrap + rv = CRYPTOKI_F_PTR( C_GetMechanismInfo(m_initializedTokenSlotID, mechanismType, &mechInfo) ); CPPUNIT_ASSERT(rv==CKR_OK); CPPUNIT_ASSERT(mechInfo.flags&CKF_WRAP); CPPUNIT_ASSERT(mechInfo.flags&CKF_UNWRAP); @@ -218,9 +306,35 @@ void AsymWrapUnwrapTests::testRsaWrapUnwrap() CK_OBJECT_HANDLE hPrivateKey = CK_INVALID_HANDLE; // Generate all combinations of session/token public/private key pairs. + // Public Session Keys rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPublicKey,hPrivateKey); CPPUNIT_ASSERT(rv == CKR_OK); rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_AES_KEY_WRAP, hSessionRO, hPublicKey, hPrivateKey); + + // Private Session Keys + rv = generateRsaKeyPair(hSessionRW, IN_SESSION, IS_PRIVATE, IN_SESSION, IS_PRIVATE, hPublicKey, hPrivateKey); + CPPUNIT_ASSERT(rv == CKR_OK); + + rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_AES_KEY_WRAP, hSessionRO, hPublicKey, hPrivateKey); + + // Public Token Keys + rv = generateRsaKeyPair(hSessionRW, ON_TOKEN, IS_PUBLIC, ON_TOKEN, IS_PUBLIC, hPublicKey, hPrivateKey); + CPPUNIT_ASSERT(rv == CKR_OK); + + rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_AES_KEY_WRAP, hSessionRO, hPublicKey, hPrivateKey); + + // Private Token Keys + rv = generateRsaKeyPair(hSessionRW, ON_TOKEN, IS_PRIVATE, ON_TOKEN, IS_PRIVATE, hPublicKey, hPrivateKey); + CPPUNIT_ASSERT(rv == CKR_OK); + + rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_AES_KEY_WRAP, hSessionRO, hPublicKey, hPrivateKey); } diff --git a/src/lib/test/AsymWrapUnwrapTests.h b/src/lib/test/AsymWrapUnwrapTests.h index 97f69408b..6d1228d24 100644 --- a/src/lib/test/AsymWrapUnwrapTests.h +++ b/src/lib/test/AsymWrapUnwrapTests.h @@ -50,6 +50,9 @@ class AsymWrapUnwrapTests : public TestsBase CK_RV generateAesKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE &hKey); CK_RV generateRsaKeyPair(CK_SESSION_HANDLE hSession, CK_BBOOL bTokenPuk, CK_BBOOL bPrivatePuk, CK_BBOOL bTokenPrk, CK_BBOOL bPrivatePrk, CK_OBJECT_HANDLE &hPuk, CK_OBJECT_HANDLE &hPrk); void rsaWrapUnwrap(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey); + +private: + void rsaWrapUnwrapPvt(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey); }; #endif // !_SOFTHSM_V2_ASYMWRAPUNWRAPTESTS_H