From d055ada2383eaf28d7b28dd7b0b639e2515279e1 Mon Sep 17 00:00:00 2001 From: jinlun Date: Tue, 20 Feb 2024 14:41:43 +0800 Subject: [PATCH] Bug 1666891 - Add PK11_Pub{Wrap,Unwrap}SymKeyWithMechanism r=mt,rrelyea Summary This is useful for RSA-OAEP support. The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS be present for PKCS#11 calls. This provides required context for OAEP. However, PK11_PubWrapSymKey lacks a way of providing this context and historically silently converted CKM_RSA_PKCS_OAEP to CKM_RSA_PKCS when a RSA key is provided. Introducing a new call will let us indicate parameters and potentially support other mechanisms in the future. This call mirrors the earlier calls introduced for RSA-PSS: PK11_SignWithMechanism and PK11_VerifyWithMechanism. The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS be present for PKCS#11 calls. This provides required context for OAEP. However, PK11_PubUnwrapSymKey lacks a way of providing this context, and additionally lacked a way of indicating which mechanism type to use for the unwrap operation (instead detecting it by key type). Introducing a new call will let us indicate parameters and potentially support other mechanisms in the future. Signed-off-by: Alexander Scheel Differential Revision: https://phabricator.services.mozilla.com/D93424 --- gtests/pk11_gtest/pk11_rsaoaep_unittest.cc | 67 ++++++++++++++++++++++ lib/nss/nss.def | 7 +++ lib/pk11wrap/pk11pub.h | 12 ++++ lib/pk11wrap/pk11skey.c | 51 ++++++++++++---- 4 files changed, 126 insertions(+), 11 deletions(-) diff --git a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc index 3a986b4..d14eb9c 100644 --- a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc +++ b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc @@ -116,4 +116,71 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( WycheproofOaep2048Sha512Sha512Test, RsaOaepWycheproofTest, ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha512WycheproofVectors)); + +TEST(Pkcs11RsaOaepTest, TestOaepWrapUnwrap) { + const size_t kRsaKeyBits = 2048; + const size_t kwrappedBufLen = 4096; + + SECStatus rv = SECFailure; + + ScopedSECKEYPrivateKey priv; + ScopedSECKEYPublicKey pub; + PK11RSAGenParams rsa_params; + rsa_params.keySizeInBits = kRsaKeyBits; + rsa_params.pe = 65537; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_NE(slot, nullptr); + + SECKEYPublicKey* p_pub_tmp = nullptr; + priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsa_params, &p_pub_tmp, false, false, + nullptr)); + pub.reset(p_pub_tmp); + + ASSERT_NE(priv.get(), nullptr); + ASSERT_NE(pub.get(), nullptr); + + ScopedPK11SymKey to_wrap( + PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr)); + + CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, + CKZ_DATA_SPECIFIED, NULL, 0}; + + SECItem param = {siBuffer, (unsigned char*)&oaep_params, sizeof(oaep_params)}; + + ScopedSECItem wrapped(SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen)); + rv = PK11_PubWrapSymKeyWithMechanism(pub.get(), CKM_RSA_PKCS_OAEP, ¶m, + to_wrap.get(), wrapped.get()); + ASSERT_EQ(rv, SECSuccess); + + PK11SymKey* p_unwrapped_tmp = nullptr; + + // This fails because this method is broken and assumes CKM_RSA_PKCS and + // doesn't understand OAEP. + p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC, + CKA_DECRYPT, 16); + ASSERT_EQ(p_unwrapped_tmp, nullptr); + + ScopedPK11SymKey unwrapped; + p_unwrapped_tmp = PK11_PubUnwrapSymKeyWithMechanism( + priv.get(), CKM_RSA_PKCS_OAEP, ¶m, wrapped.get(), CKM_AES_CBC, + CKA_DECRYPT, 16); + ASSERT_NE(p_unwrapped_tmp, nullptr); + + unwrapped.reset(p_unwrapped_tmp); + + // Extract key's value in order to validate decryption worked. + rv = PK11_ExtractKeyValue(to_wrap.get()); + ASSERT_EQ(rv, SECSuccess); + + rv = PK11_ExtractKeyValue(unwrapped.get()); + ASSERT_EQ(rv, SECSuccess); + + // References owned by PKCS#11 layer; no need to scope and free. + SECItem* expectedItem = PK11_GetKeyData(to_wrap.get()); + SECItem* actualItem = PK11_GetKeyData(unwrapped.get()); + + ASSERT_EQ(SECITEM_CompareItem(actualItem, expectedItem), 0); +} } // namespace nss_test diff --git a/lib/nss/nss.def b/lib/nss/nss.def index 1840b8d..4055a98 100644 --- a/lib/nss/nss.def +++ b/lib/nss/nss.def @@ -1181,3 +1181,10 @@ SECMOD_GetSystemFIPSEnabled; ;+ local: ;+ *; ;+}; +;+NSS_3.59 { # NSS 3.59 release +;+ global: +PK11_PubWrapSymKeyWithMechanism; +PK11_PubUnwrapSymKeyWithMechanism; +;+ local: +;+ *; +;+}; diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h index 5edcbf9..3af8487 100644 --- a/lib/pk11wrap/pk11pub.h +++ b/lib/pk11wrap/pk11pub.h @@ -354,6 +354,11 @@ void *PK11_GetSymKeyUserData(PK11SymKey *symKey); SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, PK11SymKey *symKey, SECItem *wrappedKey); +SECStatus PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey, + CK_MECHANISM_TYPE mechType, + SECItem *param, + PK11SymKey *symKey, + SECItem *wrappedKey); SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params, PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey); /* move a key to 'slot' optionally set the key attributes according to either @@ -448,6 +453,13 @@ PK11SymKey *PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, */ PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); +PK11SymKey *PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *key, + CK_MECHANISM_TYPE mechType, + SECItem *param, + SECItem *wrapppedKey, + CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, + int keySize); PK11SymKey *PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c index 996c039..eed833a 100644 --- a/lib/pk11wrap/pk11skey.c +++ b/lib/pk11wrap/pk11skey.c @@ -1248,13 +1248,23 @@ PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx) symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/); } -/* - * This function does a straight public key wrap (which only RSA can do). - * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and - * Diffie-Hellman Ciphers. */ +/* This function does a straight public key wrap with the CKM_RSA_PKCS + * mechanism. */ SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, PK11SymKey *symKey, SECItem *wrappedKey) +{ + CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType); + return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey, + wrappedKey); +} + +/* This function wraps a symmetric key with a public key, such as with the + * CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */ +SECStatus +PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey, + CK_MECHANISM_TYPE mechType, SECItem *param, + PK11SymKey *symKey, SECItem *wrappedKey) { PK11SlotInfo *slot; CK_ULONG len = wrappedKey->len; @@ -1271,7 +1281,7 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, } /* if this slot doesn't support the mechanism, go to a slot that does */ - newKey = pk11_ForceSlot(symKey, type, CKA_ENCRYPT); + newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT); if (newKey != NULL) { symKey = newKey; } @@ -1282,9 +1292,15 @@ PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, } slot = symKey->slot; - mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType); - mechanism.pParameter = NULL; - mechanism.ulParameterLen = 0; + + mechanism.mechanism = mechType; + if (param == NULL) { + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + } else { + mechanism.pParameter = param->data; + mechanism.ulParameterLen = param->len; + } id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE); if (id == CK_INVALID_HANDLE) { @@ -2856,20 +2872,33 @@ PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, wrappingKey->cx, keyTemplate, templateCount, isPerm); } -/* unwrap a symetric key with a private key. */ +/* unwrap a symmetric key with a private key. Only supports CKM_RSA_PKCS. */ PK11SymKey * PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize) { CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType); + + return PK11_PubUnwrapSymKeyWithMechanism(wrappingKey, wrapType, NULL, + wrappedKey, target, operation, + keySize); +} + +/* unwrap a symmetric key with a private key with the given parameters. */ +PK11SymKey * +PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey, + CK_MECHANISM_TYPE mechType, SECItem *param, + SECItem *wrappedKey, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize) +{ PK11SlotInfo *slot = wrappingKey->pkcs11Slot; if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) { PK11_HandlePasswordCheck(slot, wrappingKey->wincx); } - return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, - wrapType, NULL, wrappedKey, target, operation, keySize, + return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, mechType, param, + wrappedKey, target, operation, keySize, wrappingKey->wincx, NULL, 0, PR_FALSE); } -- 2.33.0