summaryrefslogtreecommitdiff
path: root/backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch
diff options
context:
space:
mode:
Diffstat (limited to 'backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch')
-rw-r--r--backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch256
1 files changed, 256 insertions, 0 deletions
diff --git a/backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch b/backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch
new file mode 100644
index 0000000..19acaf0
--- /dev/null
+++ b/backport-Bug-1666891-Add-PK11_Pub-Wrap-Unwrap.patch
@@ -0,0 +1,256 @@
+From d055ada2383eaf28d7b28dd7b0b639e2515279e1 Mon Sep 17 00:00:00 2001
+From: jinlun <jinlun@huawei.com>
+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 <ascheel@redhat.com>
+
+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, &param,
++ 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, &param, 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
+