diff -Naur softhsm-2.0.0b1-orig/src/lib/cryptoki_compat/pkcs11.h softhsm-2.0.0b1/src/lib/cryptoki_compat/pkcs11.h --- softhsm-2.0.0b1-orig/src/lib/cryptoki_compat/pkcs11.h 2014-09-09 20:05:14.000000000 -0400 +++ softhsm-2.0.0b1/src/lib/cryptoki_compat/pkcs11.h 2014-10-07 13:57:22.460010567 -0400 @@ -902,6 +902,8 @@ #define CKG_MGF1_SHA512 (0x00000004) #define CKG_MGF1_SHA224 (0x00000005) +#define CKZ_DATA_SPECIFIED (0x00000001) + struct ck_rsa_pkcs_oaep_params { ck_mechanism_type_t hash_alg; unsigned long mgf; diff -Naur softhsm-2.0.0b1-orig/src/lib/SoftHSM.cpp softhsm-2.0.0b1/src/lib/SoftHSM.cpp --- softhsm-2.0.0b1-orig/src/lib/SoftHSM.cpp 2014-10-07 13:56:04.284955056 -0400 +++ softhsm-2.0.0b1/src/lib/SoftHSM.cpp 2014-10-07 13:57:25.478089923 -0400 @@ -815,7 +815,7 @@ case CKM_RSA_PKCS_OAEP: pInfo->ulMinKeySize = rsaMinSize; pInfo->ulMaxKeySize = rsaMaxSize; - pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT; + pInfo->flags = CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP; break; case CKM_DES_KEY_GEN: case CKM_DES2_KEY_GEN: @@ -1941,22 +1941,9 @@ isRSA = true; break; case CKM_RSA_PKCS_OAEP: - 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; - } - if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->hashAlg != CKM_SHA_1) - { - ERROR_MSG("hashAlg must be CKM_SHA_1"); - return CKR_ARGUMENTS_BAD; - } - if (CK_RSA_PKCS_OAEP_PARAMS_PTR(pMechanism->pParameter)->mgf != CKG_MGF1_SHA1) - { - ERROR_MSG("mgf must be CKG_MGF1_SHA1"); - return CKR_ARGUMENTS_BAD; - } + rv = MechParamCheckRSAPKCSOAEP(pMechanism); + if (rv != CKR_OK) + return rv; mechanism = AsymMech::RSA_PKCS_OAEP; isRSA = true; @@ -4969,25 +4956,42 @@ ByteString& wrapped ) { - size_t bb = 8; + 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; - mech = AsymMech::RSA_PKCS; - CK_ULONG modulus_length; 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; } @@ -5004,6 +5008,7 @@ switch(pMechanism->mechanism) { case CKM_RSA_PKCS: + case CKM_RSA_PKCS_OAEP: if (getRSAPublicKey((RSAPublicKey*)publicKey, token, wrapKey) != CKR_OK) { cipher->recyclePublicKey(publicKey); @@ -5050,6 +5055,7 @@ 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) { @@ -5065,6 +5071,12 @@ 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; } @@ -5081,7 +5093,7 @@ CK_BBOOL isWrapKeyPrivate = wrapKey->getBooleanValue(CKA_PRIVATE, true); // Check user credentials for the wrapping key - CK_RV rv = haveRead(session->getState(), isWrapKeyOnToken, isWrapKeyPrivate); + rv = haveRead(session->getState(), isWrapKeyOnToken, isWrapKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) @@ -5093,13 +5105,13 @@ // 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 && wrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PUBLIC_KEY) + 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 && wrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) + 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 @@ -5133,8 +5145,8 @@ 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 can be used only on SECRET keys: PKCS#11 2.40 draft 2 section 2.1.6 PKCS #1 v1.5 RSA - if (pMechanism->mechanism == CKM_RSA_PKCS && keyClass != CKO_SECRET_KEY) + // 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 @@ -5338,6 +5350,12 @@ 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; } @@ -5353,6 +5371,7 @@ switch(pMechanism->mechanism) { case CKM_RSA_PKCS: + case CKM_RSA_PKCS_OAEP: if (getRSAPrivateKey((RSAPrivateKey*)unwrappingkey, token, unwrapKey) != CKR_OK) { cipher->recyclePrivateKey(unwrappingkey); @@ -5398,6 +5417,7 @@ Session* session = (Session*)handleManager->getSession(hSession); if (session == NULL) return CKR_SESSION_HANDLE_INVALID; + CK_RV rv; // Check the mechanism switch(pMechanism->mechanism) { @@ -5424,6 +5444,11 @@ 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; @@ -5441,7 +5466,7 @@ CK_BBOOL isUnwrapKeyPrivate = unwrapKey->getBooleanValue(CKA_PRIVATE, true); // Check user credentials - CK_RV rv = haveRead(session->getState(), isUnwrapKeyOnToken, isUnwrapKeyPrivate); + rv = haveRead(session->getState(), isUnwrapKeyOnToken, isUnwrapKeyPrivate); if (rv != CKR_OK) { if (rv == CKR_USER_NOT_LOGGED_IN) @@ -5457,9 +5482,9 @@ 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 && unwrapKey->getUnsignedLongValue(CKA_CLASS, CKO_VENDOR_DEFINED) != CKO_PRIVATE_KEY) + 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 && unwrapKey->getUnsignedLongValue(CKA_KEY_TYPE, CKK_VENDOR_DEFINED) != CKK_RSA) + 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 @@ -9152,3 +9177,47 @@ 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; +} diff -Naur softhsm-2.0.0b1-orig/src/lib/SoftHSM.h softhsm-2.0.0b1/src/lib/SoftHSM.h --- softhsm-2.0.0b1-orig/src/lib/SoftHSM.h 2014-09-09 20:05:23.000000000 -0400 +++ softhsm-2.0.0b1/src/lib/SoftHSM.h 2014-10-07 13:57:24.178055740 -0400 @@ -407,5 +407,7 @@ OSObject *unwrapKey, ByteString &keydata ); + + CK_RV MechParamCheckRSAPKCSOAEP(CK_MECHANISM_PTR pMechanism); }; diff -Naur softhsm-2.0.0b1-orig/src/lib/test/AsymEncryptDecryptTests.cpp softhsm-2.0.0b1/src/lib/test/AsymEncryptDecryptTests.cpp --- softhsm-2.0.0b1-orig/src/lib/test/AsymEncryptDecryptTests.cpp 2014-09-09 20:05:14.000000000 -0400 +++ softhsm-2.0.0b1/src/lib/test/AsymEncryptDecryptTests.cpp 2014-10-07 13:57:22.461010593 -0400 @@ -165,6 +165,51 @@ CPPUNIT_ASSERT(memcmp(plainText, &recoveredText[ulRecoveredTextLen-sizeof(plainText)], sizeof(plainText)) == 0); } +// Check that RSA OAEP mechanism properly validates all input parameters +void AsymEncryptDecryptTests::rsaOAEPParams(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey) +{ + // This is only supported combination of parameters + CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL_PTR, 0 }; + CK_MECHANISM mechanism = { CKM_RSA_PKCS_OAEP, NULL, 0 }; + CK_RV rv; + + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + mechanism.pParameter = &oaepParams; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + mechanism.ulParameterLen = sizeof(oaepParams); + + oaepParams.hashAlg = CKM_AES_CBC; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + oaepParams.hashAlg = CKM_SHA_1; + oaepParams.mgf = CKG_MGF1_SHA256; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + oaepParams.mgf = CKG_MGF1_SHA1; + oaepParams.source = CKZ_DATA_SPECIFIED - 1; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + oaepParams.source = CKZ_DATA_SPECIFIED; + oaepParams.pSourceData = &oaepParams; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + oaepParams.ulSourceDataLen = sizeof(oaepParams); + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); + + oaepParams.pSourceData = NULL; + rv = C_EncryptInit(hSession,&mechanism,hPublicKey); + CPPUNIT_ASSERT(rv==CKR_ARGUMENTS_BAD); +} + void AsymEncryptDecryptTests::testRsaEncryptDecrypt() { CK_RV rv; @@ -203,6 +248,7 @@ rv = generateRsaKeyPair(hSessionRW,IN_SESSION,IS_PUBLIC,IN_SESSION,IS_PUBLIC,hPublicKey,hPrivateKey); CPPUNIT_ASSERT(rv == CKR_OK); + rsaOAEPParams(hSessionRO,hPublicKey); rsaEncryptDecrypt(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); rsaEncryptDecrypt(CKM_RSA_X_509,hSessionRO,hPublicKey,hPrivateKey); rsaEncryptDecrypt(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); diff -Naur softhsm-2.0.0b1-orig/src/lib/test/AsymEncryptDecryptTests.h softhsm-2.0.0b1/src/lib/test/AsymEncryptDecryptTests.h --- softhsm-2.0.0b1-orig/src/lib/test/AsymEncryptDecryptTests.h 2014-09-09 20:05:14.000000000 -0400 +++ softhsm-2.0.0b1/src/lib/test/AsymEncryptDecryptTests.h 2014-10-07 13:57:22.462010619 -0400 @@ -52,6 +52,7 @@ protected: 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 rsaEncryptDecrypt(CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey); + void rsaOAEPParams(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey); }; #endif // !_SOFTHSM_V2_ASYMENCRYPTDECRYPTTESTS_H diff -Naur softhsm-2.0.0b1-orig/src/lib/test/AsymWrapUnwrapTests.cpp softhsm-2.0.0b1/src/lib/test/AsymWrapUnwrapTests.cpp --- softhsm-2.0.0b1-orig/src/lib/test/AsymWrapUnwrapTests.cpp 2014-09-09 20:05:23.000000000 -0400 +++ softhsm-2.0.0b1/src/lib/test/AsymWrapUnwrapTests.cpp 2014-10-07 13:57:25.480089976 -0400 @@ -155,7 +155,7 @@ 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 }; - CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, 1, NULL_PTR, 0 }; + CK_RSA_PKCS_OAEP_PARAMS oaepParams = { CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL_PTR, 0 }; CK_BYTE cipherText[2048]; CK_ULONG ulCipherTextLen; CK_BYTE symValue[64]; @@ -273,4 +273,5 @@ CPPUNIT_ASSERT(rv == CKR_OK); rsaWrapUnwrap(CKM_RSA_PKCS,hSessionRO,hPublicKey,hPrivateKey); + rsaWrapUnwrap(CKM_RSA_PKCS_OAEP,hSessionRO,hPublicKey,hPrivateKey); }