From a3103d5a43a66bb93e9d4958e5624867999f27b0 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Dec 05 2017 13:09:30 +0000 Subject: [PATCH 1/2] Support RSA-PSS from master PR#335 https://github.com/opendnssec/SoftHSMv2/pull/335/ --- diff --git a/softhsm-2.3.0-rsa-pss.patch b/softhsm-2.3.0-rsa-pss.patch new file mode 100644 index 0000000..8f01121 --- /dev/null +++ b/softhsm-2.3.0-rsa-pss.patch @@ -0,0 +1,465 @@ +From e12d04b256f1c856003ae88c5c3bfe07ce332fa7 Mon Sep 17 00:00:00 2001 +From: Nikos Mavrogiannopoulos +Date: Mon, 24 Jul 2017 13:52:59 +0200 +Subject: [PATCH] Added support for CKM_RSA_PKCS_PSS + +This mechanism is the most likely to be used by higher level +software utilizing RSA-PSS as it is in par with CKM_RSA_PKCS +and does not require to provide the whole data to be hashed. +--- + src/lib/SoftHSM.cpp | 112 +++++++++++++++++++++ + src/lib/crypto/AsymmetricAlgorithm.h | 1 + + src/lib/crypto/OSSLRSA.cpp | 190 +++++++++++++++++++++++++++++++++++ + src/lib/test/SignVerifyTests.cpp | 47 +++++++++ + src/lib/test/SignVerifyTests.h | 1 + + 5 files changed, 351 insertions(+) + +diff --git a/src/lib/SoftHSM.cpp b/src/lib/SoftHSM.cpp +index ee94d3f7..f2a8f594 100644 +--- a/src/lib/SoftHSM.cpp ++++ b/src/lib/SoftHSM.cpp +@@ -640,6 +640,10 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech + #ifdef HAVE_AES_KEY_WRAP_PAD + nrSupportedMechanisms += 1; + #endif ++#ifdef WITH_OPENSSL ++ nrSupportedMechanisms += 1; // CKM_RSA_PKCS_PSS ++#endif ++ + CK_MECHANISM_TYPE supportedMechanisms[] = + { + #ifndef WITH_FIPS +@@ -670,6 +674,9 @@ CK_RV SoftHSM::C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMech + CKM_SHA256_RSA_PKCS, + CKM_SHA384_RSA_PKCS, + CKM_SHA512_RSA_PKCS, ++#ifdef WITH_OPENSSL ++ CKM_RSA_PKCS_PSS, ++#endif + CKM_SHA1_RSA_PKCS_PSS, + CKM_SHA224_RSA_PKCS_PSS, + CKM_SHA256_RSA_PKCS_PSS, +@@ -924,6 +931,9 @@ CK_RV SoftHSM::C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_ + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: ++#ifdef WITH_OPENSSL ++ case CKM_RSA_PKCS_PSS: ++#endif + case CKM_SHA1_RSA_PKCS_PSS: + case CKM_SHA224_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS_PSS: +@@ -3749,6 +3759,58 @@ CK_RV SoftHSM::AsymSignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechan + bAllowMultiPartOp = true; + isRSA = true; + break; ++ 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; + case CKM_SHA1_RSA_PKCS_PSS: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || +@@ -4593,6 +4655,56 @@ CK_RV SoftHSM::AsymVerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMech + bAllowMultiPartOp = true; + isRSA = true; + break; ++ 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; + case CKM_SHA1_RSA_PKCS_PSS: + if (pMechanism->pParameter == NULL_PTR || + pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS) || +diff --git a/src/lib/crypto/AsymmetricAlgorithm.h b/src/lib/crypto/AsymmetricAlgorithm.h +index 54ac78d5..ca0d8400 100644 +--- a/src/lib/crypto/AsymmetricAlgorithm.h ++++ b/src/lib/crypto/AsymmetricAlgorithm.h +@@ -70,6 +70,7 @@ struct AsymMech + RSA_SHA256_PKCS, + RSA_SHA384_PKCS, + RSA_SHA512_PKCS, ++ RSA_PKCS_PSS, + RSA_SHA1_PKCS_PSS, + RSA_SHA224_PKCS_PSS, + RSA_SHA256_PKCS_PSS, +diff --git a/src/lib/crypto/OSSLRSA.cpp b/src/lib/crypto/OSSLRSA.cpp +index 91b6466c..1e5638a0 100644 +--- a/src/lib/crypto/OSSLRSA.cpp ++++ b/src/lib/crypto/OSSLRSA.cpp +@@ -121,6 +121,112 @@ bool OSSLRSA::sign(PrivateKey* privateKey, const ByteString& dataToSign, + + return true; + } ++ else if (mechanism == AsymMech::RSA_PKCS_PSS) ++ { ++ const RSA_PKCS_PSS_PARAMS *pssParam = (RSA_PKCS_PSS_PARAMS*)param; ++ ++ // Separate implementation for RSA PKCS #1 signing without hash computation ++ ++ // Check if the private key is the right type ++ if (!privateKey->isOfType(OSSLRSAPrivateKey::type)) ++ { ++ ERROR_MSG("Invalid key type supplied"); ++ ++ return false; ++ } ++ ++ if (pssParam == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS)) ++ { ++ ERROR_MSG("Invalid parameters supplied"); ++ ++ return false; ++ } ++ ++ size_t allowedLen; ++ const EVP_MD* hash = NULL; ++ ++ switch (pssParam->hashAlg) ++ { ++ case HashAlgo::SHA1: ++ hash = EVP_sha1(); ++ allowedLen = 20; ++ break; ++ case HashAlgo::SHA224: ++ hash = EVP_sha224(); ++ allowedLen = 28; ++ break; ++ case HashAlgo::SHA256: ++ hash = EVP_sha256(); ++ allowedLen = 32; ++ break; ++ case HashAlgo::SHA384: ++ hash = EVP_sha384(); ++ allowedLen = 48; ++ break; ++ case HashAlgo::SHA512: ++ hash = EVP_sha512(); ++ allowedLen = 64; ++ break; ++ default: ++ return false; ++ } ++ ++ OSSLRSAPrivateKey* osslKey = (OSSLRSAPrivateKey*) privateKey; ++ ++ RSA* rsa = osslKey->getOSSLKey(); ++ ++ if (dataToSign.size() != allowedLen) ++ { ++ ERROR_MSG("Data to sign does not match expected (%d) for RSA PSS", (int)allowedLen); ++ ++ return false; ++ } ++ ++ size_t sLen = pssParam->sLen; ++ if (sLen > ((privateKey->getBitLength()+6)/8-2-allowedLen)) ++ { ++ ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", ++ (unsigned long)sLen, privateKey->getBitLength()); ++ return false; ++ } ++ ++ ByteString em; ++ em.resize(osslKey->getN().size()); ++ ++ int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa, &em[0], (unsigned char*) dataToSign.const_byte_str(), hash, hash, pssParam->sLen); ++ if (!status) ++ { ++ ERROR_MSG("Error in RSA PSS padding generation"); ++ ++ return false; ++ } ++ ++ ++ if (!RSA_blinding_on(rsa, NULL)) ++ { ++ ERROR_MSG("Failed to turn on blinding for OpenSSL RSA key"); ++ ++ return false; ++ } ++ ++ // Perform the signature operation ++ signature.resize(osslKey->getN().size()); ++ ++ int sigLen = RSA_private_encrypt(osslKey->getN().size(), &em[0], &signature[0], rsa, RSA_NO_PADDING); ++ ++ RSA_blinding_off(rsa); ++ ++ if (sigLen == -1) ++ { ++ ERROR_MSG("An error occurred while performing the RSA-PSS signature"); ++ ++ return false; ++ } ++ ++ signature.resize(sigLen); ++ ++ return true; ++ } + else if (mechanism == AsymMech::RSA) + { + // Separate implementation for raw RSA signing +@@ -607,6 +713,90 @@ bool OSSLRSA::verify(PublicKey* publicKey, const ByteString& originalData, + + return (originalData == recoveredData); + } ++ else if (mechanism == AsymMech::RSA_PKCS_PSS) ++ { ++ const RSA_PKCS_PSS_PARAMS *pssParam = (RSA_PKCS_PSS_PARAMS*)param; ++ ++ if (pssParam == NULL || paramLen != sizeof(RSA_PKCS_PSS_PARAMS)) ++ { ++ ERROR_MSG("Invalid parameters supplied"); ++ ++ return false; ++ } ++ ++ // Check if the public key is the right type ++ if (!publicKey->isOfType(OSSLRSAPublicKey::type)) ++ { ++ ERROR_MSG("Invalid key type supplied"); ++ ++ return false; ++ } ++ ++ // Perform the RSA public key operation ++ OSSLRSAPublicKey* osslKey = (OSSLRSAPublicKey*) publicKey; ++ ++ ByteString recoveredData; ++ ++ recoveredData.resize(osslKey->getN().size()); ++ ++ RSA* rsa = osslKey->getOSSLKey(); ++ ++ int retLen = RSA_public_decrypt(signature.size(), (unsigned char*) signature.const_byte_str(), &recoveredData[0], rsa, RSA_NO_PADDING); ++ ++ if (retLen == -1) ++ { ++ ERROR_MSG("Public key operation failed"); ++ ++ return false; ++ } ++ ++ recoveredData.resize(retLen); ++ ++ size_t allowedLen; ++ const EVP_MD* hash = NULL; ++ ++ switch (pssParam->hashAlg) ++ { ++ case HashAlgo::SHA1: ++ hash = EVP_sha1(); ++ allowedLen = 20; ++ break; ++ case HashAlgo::SHA224: ++ hash = EVP_sha224(); ++ allowedLen = 28; ++ break; ++ case HashAlgo::SHA256: ++ hash = EVP_sha256(); ++ allowedLen = 32; ++ break; ++ case HashAlgo::SHA384: ++ hash = EVP_sha384(); ++ allowedLen = 48; ++ break; ++ case HashAlgo::SHA512: ++ hash = EVP_sha512(); ++ allowedLen = 64; ++ break; ++ default: ++ return false; ++ } ++ ++ if (originalData.size() != allowedLen) { ++ return false; ++ } ++ ++ size_t sLen = pssParam->sLen; ++ if (sLen > ((osslKey->getBitLength()+6)/8-2-allowedLen)) ++ { ++ ERROR_MSG("sLen (%lu) is too large for current key size (%lu)", ++ (unsigned long)sLen, osslKey->getBitLength()); ++ return false; ++ } ++ ++ int status = RSA_verify_PKCS1_PSS_mgf1(rsa, (unsigned char*)originalData.const_byte_str(), hash, hash, (unsigned char*) recoveredData.const_byte_str(), pssParam->sLen); ++ ++ return (status == 1); ++ } + else if (mechanism == AsymMech::RSA) + { + // Specific implementation for raw RSA verifiction; originalData is assumed to contain the +diff --git a/src/lib/test/SignVerifyTests.cpp b/src/lib/test/SignVerifyTests.cpp +index 4536d7aa..46ebfb61 100644 +--- a/src/lib/test/SignVerifyTests.cpp ++++ b/src/lib/test/SignVerifyTests.cpp +@@ -195,6 +195,44 @@ void SignVerifyTests::signVerifySingle(CK_MECHANISM_TYPE mechanismType, CK_SESSI + CPPUNIT_ASSERT(rv==CKR_SIGNATURE_INVALID); + } + ++void SignVerifyTests::signVerifySingleData(size_t dataSize, CK_MECHANISM_TYPE mechanismType, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPublicKey, CK_OBJECT_HANDLE hPrivateKey, CK_VOID_PTR param /* = NULL_PTR */, CK_ULONG paramLen /* = 0 */) ++{ ++ CK_RV rv; ++ CK_MECHANISM mechanism = { mechanismType, param, paramLen }; ++ CK_BYTE *data = (CK_BYTE*)malloc(dataSize); ++ CK_BYTE signature[1024]; ++ CK_ULONG ulSignatureLen = 0; ++ unsigned i; ++ ++ CPPUNIT_ASSERT(data != NULL); ++ ++ for (i=0;i= 1.0.1k-6, sqlite-devel >= 3.4.2, cppunit-devel BuildRequires: gcc-c++, pkgconfig, p11-kit-devel, nss-devel @@ -44,6 +46,8 @@ The devel package contains the libsofthsm include files %prep %setup -q -n %{name}-%{version}%{?prever} +%patch0 -p1 + %if 0%{?prever:1} autoreconf -fiv %endif From eebab4eaa8435e50ecb9c010121f627de24615c0 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Dec 05 2017 13:09:50 +0000 Subject: [PATCH 2/2] softhsm-2.3.0-2 --- diff --git a/softhsm.spec b/softhsm.spec index ceb05b5..dab9ce5 100644 --- a/softhsm.spec +++ b/softhsm.spec @@ -3,7 +3,7 @@ Summary: Software version of a PKCS#11 Hardware Security Module Name: softhsm Version: 2.3.0 -Release: %{?prever:0.}1%{?prever:.%{prever}}%{?dist} +Release: %{?prever:0.}2%{?prever:.%{prever}}%{?dist} License: BSD Url: http://www.opendnssec.org/ Source: http://dist.opendnssec.org/source/%{?prever:testing/}%{name}-%{version}.tar.gz @@ -131,6 +131,9 @@ if [ -f /var/softhsm/slot0.db ]; then fi %changelog +* Tue Dec 05 2017 Jakub Jelen - 2.3.0-2 +- Add support for RSA-PSS from upstrem PR#335 + * Tue Dec 05 2017 Jakub Jelen - 2.3.0-1 - New upstream release (#1467329)