5f43a7
5f43a7
# HG changeset patch
5f43a7
# User Robert Relyea <rrelyea@redhat.com>
5f43a7
# Date 1603492441 25200
5f43a7
# Node ID 33f920fcd1753d2b8f4a5e4f31e317c102d8cbfe
5f43a7
# Parent  e3bd9c2f925932b301440fb07ea1228f2d4e39ac
5f43a7
Bug 1666891 - Add PK11_Pub{Wrap,Unwrap}SymKeyWithMechanism r=mt,rrelyea
5f43a7
5f43a7
Summary
5f43a7
5f43a7
This is useful for RSA-OAEP support.
5f43a7
5f43a7
The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
5f43a7
be present for PKCS#11 calls. This provides required context for OAEP.
5f43a7
However, PK11_PubWrapSymKey lacks a way of providing this context and
5f43a7
historically silently converted CKM_RSA_PKCS_OAEP to CKM_RSA_PKCS when
5f43a7
a RSA key is provided. Introducing a new call will let us indicate
5f43a7
parameters and potentially support other mechanisms in the future.
5f43a7
This call mirrors the earlier calls introduced for RSA-PSS:
5f43a7
PK11_SignWithMechanism and PK11_VerifyWithMechanism.
5f43a7
5f43a7
The CKM_RSA_PKCS_OAEP mechanism requires a CK_RSA_PKCS_OAEP_PARAMS
5f43a7
be present for PKCS#11 calls. This provides required context for OAEP.
5f43a7
However, PK11_PubUnwrapSymKey lacks a way of providing this context,
5f43a7
and additionally lacked a way of indicating which mechanism type to use
5f43a7
for the unwrap operation (instead detecting it by key type). Introducing
5f43a7
a new call will let us indicate parameters and potentially support other
5f43a7
mechanisms in the future.
5f43a7
5f43a7
Signed-off-by: Alexander Scheel <ascheel@redhat.com>
5f43a7
5f43a7
Differential Revision: https://phabricator.services.mozilla.com/D93424
5f43a7
5f43a7
diff --git a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
5f43a7
--- a/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
5f43a7
+++ b/gtests/pk11_gtest/pk11_rsaoaep_unittest.cc
5f43a7
@@ -111,9 +111,76 @@ INSTANTIATE_TEST_CASE_P(
5f43a7
 
5f43a7
 INSTANTIATE_TEST_CASE_P(
5f43a7
     WycheproofOaep2048Sha512Sha1Test, RsaOaepWycheproofTest,
5f43a7
     ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha1WycheproofVectors));
5f43a7
 
5f43a7
 INSTANTIATE_TEST_CASE_P(
5f43a7
     WycheproofOaep2048Sha512Sha512Test, RsaOaepWycheproofTest,
5f43a7
     ::testing::ValuesIn(kRsaOaep2048Sha512Mgf1Sha512WycheproofVectors));
5f43a7
+
5f43a7
+TEST(Pkcs11RsaOaepTest, TestOaepWrapUnwrap) {
5f43a7
+  const size_t kRsaKeyBits = 2048;
5f43a7
+  const size_t kwrappedBufLen = 4096;
5f43a7
+
5f43a7
+  SECStatus rv = SECFailure;
5f43a7
+
5f43a7
+  ScopedSECKEYPrivateKey priv;
5f43a7
+  ScopedSECKEYPublicKey pub;
5f43a7
+  PK11RSAGenParams rsa_params;
5f43a7
+  rsa_params.keySizeInBits = kRsaKeyBits;
5f43a7
+  rsa_params.pe = 65537;
5f43a7
+
5f43a7
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
5f43a7
+  ASSERT_NE(slot, nullptr);
5f43a7
+
5f43a7
+  SECKEYPublicKey* p_pub_tmp = nullptr;
5f43a7
+  priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
5f43a7
+                                  &rsa_params, &p_pub_tmp, false, false,
5f43a7
+                                  nullptr));
5f43a7
+  pub.reset(p_pub_tmp);
5f43a7
+
5f43a7
+  ASSERT_NE(priv.get(), nullptr);
5f43a7
+  ASSERT_NE(pub.get(), nullptr);
5f43a7
+
5f43a7
+  ScopedPK11SymKey to_wrap(
5f43a7
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
5f43a7
+
5f43a7
+  CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256,
5f43a7
+                                         CKZ_DATA_SPECIFIED, NULL, 0};
5f43a7
+
5f43a7
+  SECItem param = {siBuffer, (unsigned char*)&oaep_params, sizeof(oaep_params)};
5f43a7
+
5f43a7
+  ScopedSECItem wrapped(SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
5f43a7
+  rv = PK11_PubWrapSymKeyWithMechanism(pub.get(), CKM_RSA_PKCS_OAEP, &param,
5f43a7
+                                       to_wrap.get(), wrapped.get());
5f43a7
+  ASSERT_EQ(rv, SECSuccess);
5f43a7
+
5f43a7
+  PK11SymKey* p_unwrapped_tmp = nullptr;
5f43a7
+
5f43a7
+  // This fails because this method is broken and assumes CKM_RSA_PKCS and
5f43a7
+  // doesn't understand OAEP.
5f43a7
+  p_unwrapped_tmp = PK11_PubUnwrapSymKey(priv.get(), wrapped.get(), CKM_AES_CBC,
5f43a7
+                                         CKA_DECRYPT, 16);
5f43a7
+  ASSERT_EQ(p_unwrapped_tmp, nullptr);
5f43a7
+
5f43a7
+  ScopedPK11SymKey unwrapped;
5f43a7
+  p_unwrapped_tmp = PK11_PubUnwrapSymKeyWithMechanism(
5f43a7
+      priv.get(), CKM_RSA_PKCS_OAEP, &param, wrapped.get(), CKM_AES_CBC,
5f43a7
+      CKA_DECRYPT, 16);
5f43a7
+  ASSERT_NE(p_unwrapped_tmp, nullptr);
5f43a7
+
5f43a7
+  unwrapped.reset(p_unwrapped_tmp);
5f43a7
+
5f43a7
+  // Extract key's value in order to validate decryption worked.
5f43a7
+  rv = PK11_ExtractKeyValue(to_wrap.get());
5f43a7
+  ASSERT_EQ(rv, SECSuccess);
5f43a7
+
5f43a7
+  rv = PK11_ExtractKeyValue(unwrapped.get());
5f43a7
+  ASSERT_EQ(rv, SECSuccess);
5f43a7
+
5f43a7
+  // References owned by PKCS#11 layer; no need to scope and free.
5f43a7
+  SECItem* expectedItem = PK11_GetKeyData(to_wrap.get());
5f43a7
+  SECItem* actualItem = PK11_GetKeyData(unwrapped.get());
5f43a7
+
5f43a7
+  ASSERT_EQ(SECITEM_CompareItem(actualItem, expectedItem), 0);
5f43a7
+}
5f43a7
 }  // namespace nss_test
5f43a7
diff --git a/lib/nss/nss.def b/lib/nss/nss.def
5f43a7
--- a/lib/nss/nss.def
5f43a7
+++ b/lib/nss/nss.def
5f43a7
@@ -1181,3 +1181,10 @@ SECMOD_GetSystemFIPSEnabled;
5f43a7
 ;+    local:
5f43a7
 ;+       *;
5f43a7
 ;+};
5f43a7
+;+NSS_3.59 {   # NSS 3.59 release
5f43a7
+;+    global:
5f43a7
+PK11_PubWrapSymKeyWithMechanism;
5f43a7
+PK11_PubUnwrapSymKeyWithMechanism;
5f43a7
+;+    local:
5f43a7
+;+       *;
5f43a7
+;+};
5f43a7
diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h
5f43a7
--- a/lib/pk11wrap/pk11pub.h
5f43a7
+++ b/lib/pk11wrap/pk11pub.h
5f43a7
@@ -352,16 +352,21 @@ void PK11_SetSymKeyUserData(PK11SymKey *
5f43a7
  * will return NULL. Returned data is still owned and managed by the SymKey,
5f43a7
  * the caller should not free the data.
5f43a7
  *
5f43a7
  */
5f43a7
 void *PK11_GetSymKeyUserData(PK11SymKey *symKey);
5f43a7
 
5f43a7
 SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
5f43a7
                              PK11SymKey *symKey, SECItem *wrappedKey);
5f43a7
+SECStatus PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
5f43a7
+                                          CK_MECHANISM_TYPE mechType,
5f43a7
+                                          SECItem *param,
5f43a7
+                                          PK11SymKey *symKey,
5f43a7
+                                          SECItem *wrappedKey);
5f43a7
 SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params,
5f43a7
                           PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey);
5f43a7
 /* move a key to 'slot' optionally set the key attributes according to either
5f43a7
  * operation or the  flags and making the key permanent at the same time.
5f43a7
  * If the key is moved to the same slot, operation and flags values are
5f43a7
  * currently ignored */
5f43a7
 PK11SymKey *PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation,
5f43a7
                             CK_FLAGS flags, PRBool perm, PK11SymKey *symKey);
5f43a7
@@ -446,16 +451,23 @@ PK11SymKey *PK11_UnwrapSymKeyWithFlagsPe
5f43a7
  *  PK11_PubUnwrap returns a key which can do exactly one operation, and is
5f43a7
  * ephemeral (session key).
5f43a7
  *  PK11_PubUnwrapWithFlagsPerm is the same as PK11_PubUnwrap except you can
5f43a7
  * use * CKF_ flags to enable more than one operation, and optionally make
5f43a7
  * the key permanent (token key).
5f43a7
  */
5f43a7
 PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey,
5f43a7
                                  CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
5f43a7
+PK11SymKey *PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *key,
5f43a7
+                                              CK_MECHANISM_TYPE mechType,
5f43a7
+                                              SECItem *param,
5f43a7
+                                              SECItem *wrapppedKey,
5f43a7
+                                              CK_MECHANISM_TYPE target,
5f43a7
+                                              CK_ATTRIBUTE_TYPE operation,
5f43a7
+                                              int keySize);
5f43a7
 PK11SymKey *PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey,
5f43a7
                                               SECItem *wrappedKey, CK_MECHANISM_TYPE target,
5f43a7
                                               CK_ATTRIBUTE_TYPE operation, int keySize,
5f43a7
                                               CK_FLAGS flags, PRBool isPerm);
5f43a7
 PK11SymKey *PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
5f43a7
                               SECItem *keyID, void *wincx);
5f43a7
 SECStatus PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force);
5f43a7
 SECStatus PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey);
5f43a7
diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
5f43a7
--- a/lib/pk11wrap/pk11skey.c
5f43a7
+++ b/lib/pk11wrap/pk11skey.c
5f43a7
@@ -1270,53 +1270,69 @@ PK11_ConvertSessionSymKeyToTokenSymKey(P
5f43a7
         PORT_SetError(PK11_MapError(crv));
5f43a7
         return NULL;
5f43a7
     }
5f43a7
 
5f43a7
     return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin,
5f43a7
                                  symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/);
5f43a7
 }
5f43a7
 
5f43a7
-/*
5f43a7
- * This function does a straight public key wrap (which only RSA can do).
5f43a7
- * Use PK11_PubGenKey and PK11_WrapSymKey to implement the FORTEZZA and
5f43a7
- * Diffie-Hellman Ciphers. */
5f43a7
+/* This function does a straight public key wrap with the CKM_RSA_PKCS
5f43a7
+ * mechanism. */
5f43a7
 SECStatus
5f43a7
 PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,
5f43a7
                    PK11SymKey *symKey, SECItem *wrappedKey)
5f43a7
 {
5f43a7
+    CK_MECHANISM_TYPE inferred = pk11_mapWrapKeyType(pubKey->keyType);
5f43a7
+    return PK11_PubWrapSymKeyWithMechanism(pubKey, inferred, NULL, symKey,
5f43a7
+                                           wrappedKey);
5f43a7
+}
5f43a7
+
5f43a7
+/* This function wraps a symmetric key with a public key, such as with the
5f43a7
+ * CKM_RSA_PKCS and CKM_RSA_PKCS_OAEP mechanisms. */
5f43a7
+SECStatus
5f43a7
+PK11_PubWrapSymKeyWithMechanism(SECKEYPublicKey *pubKey,
5f43a7
+                                CK_MECHANISM_TYPE mechType, SECItem *param,
5f43a7
+                                PK11SymKey *symKey, SECItem *wrappedKey)
5f43a7
+{
5f43a7
     PK11SlotInfo *slot;
5f43a7
     CK_ULONG len = wrappedKey->len;
5f43a7
     PK11SymKey *newKey = NULL;
5f43a7
     CK_OBJECT_HANDLE id;
5f43a7
     CK_MECHANISM mechanism;
5f43a7
     PRBool owner = PR_TRUE;
5f43a7
     CK_SESSION_HANDLE session;
5f43a7
     CK_RV crv;
5f43a7
 
5f43a7
     if (symKey == NULL) {
5f43a7
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
5f43a7
         return SECFailure;
5f43a7
     }
5f43a7
 
5f43a7
     /* if this slot doesn't support the mechanism, go to a slot that does */
5f43a7
-    newKey = pk11_ForceSlot(symKey, type, CKA_ENCRYPT);
5f43a7
+    newKey = pk11_ForceSlot(symKey, mechType, CKA_ENCRYPT);
5f43a7
     if (newKey != NULL) {
5f43a7
         symKey = newKey;
5f43a7
     }
5f43a7
 
5f43a7
     if (symKey->slot == NULL) {
5f43a7
         PORT_SetError(SEC_ERROR_NO_MODULE);
5f43a7
         return SECFailure;
5f43a7
     }
5f43a7
 
5f43a7
     slot = symKey->slot;
5f43a7
-    mechanism.mechanism = pk11_mapWrapKeyType(pubKey->keyType);
5f43a7
-    mechanism.pParameter = NULL;
5f43a7
-    mechanism.ulParameterLen = 0;
5f43a7
+
5f43a7
+    mechanism.mechanism = mechType;
5f43a7
+    if (param == NULL) {
5f43a7
+        mechanism.pParameter = NULL;
5f43a7
+        mechanism.ulParameterLen = 0;
5f43a7
+    } else {
5f43a7
+        mechanism.pParameter = param->data;
5f43a7
+        mechanism.ulParameterLen = param->len;
5f43a7
+    }
5f43a7
 
5f43a7
     id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE);
5f43a7
     if (id == CK_INVALID_HANDLE) {
5f43a7
         if (newKey) {
5f43a7
             PK11_FreeSymKey(newKey);
5f43a7
         }
5f43a7
         return SECFailure; /* Error code has been set. */
5f43a7
     }
5f43a7
@@ -2878,30 +2894,43 @@ PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKe
5f43a7
     templateCount = attrs - keyTemplate;
5f43a7
     templateCount += pk11_OpFlagsToAttributes(flags, attrs, &cktrue);
5f43a7
 
5f43a7
     return pk11_AnyUnwrapKey(wrappingKey->slot, wrappingKey->objectID,
5f43a7
                              wrapType, param, wrappedKey, target, operation, keySize,
5f43a7
                              wrappingKey->cx, keyTemplate, templateCount, isPerm);
5f43a7
 }
5f43a7
 
5f43a7
-/* unwrap a symetric key with a private key. */
5f43a7
+/* unwrap a symmetric key with a private key. Only supports CKM_RSA_PKCS. */
5f43a7
 PK11SymKey *
5f43a7
 PK11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,
5f43a7
                      CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
5f43a7
 {
5f43a7
     CK_MECHANISM_TYPE wrapType = pk11_mapWrapKeyType(wrappingKey->keyType);
5f43a7
+
5f43a7
+    return PK11_PubUnwrapSymKeyWithMechanism(wrappingKey, wrapType, NULL,
5f43a7
+                                             wrappedKey, target, operation,
5f43a7
+                                             keySize);
5f43a7
+}
5f43a7
+
5f43a7
+/* unwrap a symmetric key with a private key with the given parameters. */
5f43a7
+PK11SymKey *
5f43a7
+PK11_PubUnwrapSymKeyWithMechanism(SECKEYPrivateKey *wrappingKey,
5f43a7
+                                  CK_MECHANISM_TYPE mechType, SECItem *param,
5f43a7
+                                  SECItem *wrappedKey, CK_MECHANISM_TYPE target,
5f43a7
+                                  CK_ATTRIBUTE_TYPE operation, int keySize)
5f43a7
+{
5f43a7
     PK11SlotInfo *slot = wrappingKey->pkcs11Slot;
5f43a7
 
5f43a7
     if (SECKEY_HAS_ATTRIBUTE_SET(wrappingKey, CKA_PRIVATE)) {
5f43a7
         PK11_HandlePasswordCheck(slot, wrappingKey->wincx);
5f43a7
     }
5f43a7
 
5f43a7
-    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID,
5f43a7
-                             wrapType, NULL, wrappedKey, target, operation, keySize,
5f43a7
+    return pk11_AnyUnwrapKey(slot, wrappingKey->pkcs11ID, mechType, param,
5f43a7
+                             wrappedKey, target, operation, keySize,
5f43a7
                              wrappingKey->wincx, NULL, 0, PR_FALSE);
5f43a7
 }
5f43a7
 
5f43a7
 /* unwrap a symetric key with a private key. */
5f43a7
 PK11SymKey *
5f43a7
 PK11_PubUnwrapSymKeyWithFlags(SECKEYPrivateKey *wrappingKey,
5f43a7
                               SECItem *wrappedKey, CK_MECHANISM_TYPE target,
5f43a7
                               CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags)
5f43a7