Blob Blame Raw
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);
 }