Blame SOURCES/nss-8-fix-public-key-from-priv.patch

ddf7d0
diff -up ./gtests/pk11_gtest/pk11_import_unittest.cc.pub-priv-mech ./gtests/pk11_gtest/pk11_import_unittest.cc
ddf7d0
--- ./gtests/pk11_gtest/pk11_import_unittest.cc.pub-priv-mech	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./gtests/pk11_gtest/pk11_import_unittest.cc	2019-06-05 16:43:42.276498676 -0700
ddf7d0
@@ -78,17 +78,40 @@ class Pk11KeyImportTestBase : public ::t
ddf7d0
   CK_MECHANISM_TYPE mech_;
ddf7d0
 
ddf7d0
  private:
ddf7d0
+  SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) {
ddf7d0
+    SECItem null = { siBuffer, NULL, 0};
ddf7d0
+    switch(SECKEY_GetPublicKeyType(pub_key.get())) {
ddf7d0
+    case rsaKey:
ddf7d0
+    case rsaPssKey:
ddf7d0
+    case rsaOaepKey:
ddf7d0
+       return pub_key->u.rsa.modulus;
ddf7d0
+    case keaKey:
ddf7d0
+       return pub_key->u.kea.publicValue;
ddf7d0
+    case dsaKey:
ddf7d0
+       return pub_key->u.dsa.publicValue;
ddf7d0
+    case dhKey:
ddf7d0
+       return pub_key->u.dh.publicValue;
ddf7d0
+    case ecKey:
ddf7d0
+       return pub_key->u.ec.publicValue;
ddf7d0
+    case fortezzaKey: /* depricated */
ddf7d0
+    case nullKey:
ddf7d0
+    /* didn't use default here so we can catch new key types at compile time */
ddf7d0
+       break;
ddf7d0
+    }
ddf7d0
+    return null;
ddf7d0
+  }
ddf7d0
   void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key,
ddf7d0
                          const SECItem* expected_public) {
ddf7d0
     // Verify the public key exists.
ddf7d0
     StackSECItem priv_id;
ddf7d0
+    KeyType type = SECKEY_GetPrivateKeyType(priv_key.get());
ddf7d0
     SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(),
ddf7d0
                                          CKA_ID, &priv_id);
ddf7d0
     ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: "
ddf7d0
                               << PORT_ErrorToName(PORT_GetError());
ddf7d0
 
ddf7d0
     CK_ATTRIBUTE_TYPE value_type = CKA_VALUE;
ddf7d0
-    switch (SECKEY_GetPrivateKeyType(priv_key.get())) {
ddf7d0
+    switch (type) {
ddf7d0
       case rsaKey:
ddf7d0
         value_type = CKA_MODULUS;
ddf7d0
         break;
ddf7d0
@@ -106,6 +129,8 @@ class Pk11KeyImportTestBase : public ::t
ddf7d0
         FAIL() << "unknown key type";
ddf7d0
     }
ddf7d0
 
ddf7d0
+    // Scan public key objects until we find one with the same CKA_ID as
ddf7d0
+    // priv_key
ddf7d0
     std::unique_ptr<PK11GenericObject, PK11GenericObjectsDeleter> objs(
ddf7d0
         PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY));
ddf7d0
     ASSERT_NE(nullptr, objs);
ddf7d0
@@ -128,20 +153,46 @@ class Pk11KeyImportTestBase : public ::t
ddf7d0
       ASSERT_EQ(1U, token.len);
ddf7d0
       ASSERT_NE(0, token.data[0]);
ddf7d0
 
ddf7d0
-      StackSECItem value;
ddf7d0
-      rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &value);
ddf7d0
+      StackSECItem raw_value;
ddf7d0
+      SECItem decoded_value;
ddf7d0
+      rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value);
ddf7d0
       ASSERT_EQ(SECSuccess, rv);
ddf7d0
+      SECItem value = raw_value;
ddf7d0
 
ddf7d0
+      // Decode the EC_POINT and check the output against expected.
ddf7d0
       // CKA_EC_POINT isn't stable, see Bug 1520649.
ddf7d0
+      ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
ddf7d0
+      ASSERT_TRUE(arena);
ddf7d0
       if (value_type == CKA_EC_POINT) {
ddf7d0
-        continue;
ddf7d0
-      }
ddf7d0
 
ddf7d0
+        // If this fails due to the noted inconsistency, we may need to
ddf7d0
+        // check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag
ddf7d0
+        rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value,
ddf7d0
+                                    SEC_ASN1_GET(SEC_OctetStringTemplate),
ddf7d0
+                                    &raw_value);
ddf7d0
+        ASSERT_EQ(SECSuccess, rv);
ddf7d0
+        value = decoded_value;
ddf7d0
+      }
ddf7d0
       ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value))
ddf7d0
           << "expected: "
ddf7d0
           << DataBuffer(expected_public->data, expected_public->len)
ddf7d0
           << std::endl
ddf7d0
           << "actual: " << DataBuffer(value.data, value.len) << std::endl;
ddf7d0
+
ddf7d0
+      // Finally, convert the private to public and ensure it matches.
ddf7d0
+      ScopedSECKEYPublicKey pub_key(
ddf7d0
+            SECKEY_ConvertToPublicKey(priv_key.get()));
ddf7d0
+      ASSERT_TRUE(pub_key);
ddf7d0
+      SECItem converted_public = GetPublicComponent(pub_key);
ddf7d0
+      ASSERT_TRUE(converted_public.len != 0);
ddf7d0
+
ddf7d0
+      ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public))
ddf7d0
+            << "expected: "
ddf7d0
+            << DataBuffer(expected_public->data, expected_public->len)
ddf7d0
+            << std::endl
ddf7d0
+            << "actual: "
ddf7d0
+            << DataBuffer(converted_public.data, converted_public.len)
ddf7d0
+            << std::endl;
ddf7d0
     }
ddf7d0
   }
ddf7d0
 
ddf7d0
diff -up ./lib/cryptohi/seckey.c.pub-priv-mech ./lib/cryptohi/seckey.c
ddf7d0
--- ./lib/cryptohi/seckey.c.pub-priv-mech	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/cryptohi/seckey.c	2019-06-05 16:43:42.277498676 -0700
ddf7d0
@@ -1206,6 +1206,37 @@ SECKEY_CopyPublicKey(const SECKEYPublicK
ddf7d0
     return NULL;
ddf7d0
 }
ddf7d0
 
ddf7d0
+/*
ddf7d0
+ * Use the private key to find a public key handle. The handle will be on
ddf7d0
+ * the same slot as the private key.
ddf7d0
+ */
ddf7d0
+static CK_OBJECT_HANDLE
ddf7d0
+seckey_FindPublicKeyHandle(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk)
ddf7d0
+{
ddf7d0
+    CK_OBJECT_HANDLE keyID;
ddf7d0
+
ddf7d0
+    /* this helper function is only used below. If we want to make this more
ddf7d0
+     * general, we would need to free up any already cached handles if the
ddf7d0
+     * slot doesn't match up with the private key slot */
ddf7d0
+    PORT_Assert(pubk->pkcs11ID == CK_INVALID_HANDLE);
ddf7d0
+
ddf7d0
+    /* first look for a matching public key */
ddf7d0
+    keyID = PK11_MatchItem(privk->pkcs11Slot, privk->pkcs11ID, CKO_PUBLIC_KEY);
ddf7d0
+    if (keyID != CK_INVALID_HANDLE) {
ddf7d0
+        return keyID;
ddf7d0
+    }
ddf7d0
+
ddf7d0
+    /* none found, create a temp one, make the pubk the owner */
ddf7d0
+    pubk->pkcs11ID = PK11_DerivePubKeyFromPrivKey(privk);
ddf7d0
+    if (pubk->pkcs11ID == CK_INVALID_HANDLE) {
ddf7d0
+        /* end of the road. Token doesn't have matching public key, nor can
ddf7d0
+          * token regenerate a new public key from and existing private key. */
ddf7d0
+        return CK_INVALID_HANDLE;
ddf7d0
+    }
ddf7d0
+    pubk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot);
ddf7d0
+    return pubk->pkcs11ID;
ddf7d0
+}
ddf7d0
+
ddf7d0
 SECKEYPublicKey *
ddf7d0
 SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk)
ddf7d0
 {
ddf7d0
@@ -1213,6 +1244,8 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
ddf7d0
     PLArenaPool *arena;
ddf7d0
     CERTCertificate *cert;
ddf7d0
     SECStatus rv;
ddf7d0
+    CK_OBJECT_HANDLE pubKeyHandle;
ddf7d0
+    SECItem decodedPoint;
ddf7d0
 
ddf7d0
     /*
ddf7d0
      * First try to look up the cert.
ddf7d0
@@ -1243,11 +1276,47 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
ddf7d0
 
ddf7d0
     switch (privk->keyType) {
ddf7d0
         case nullKey:
ddf7d0
-        case dhKey:
ddf7d0
-        case dsaKey:
ddf7d0
             /* Nothing to query, if the cert isn't there, we're done -- no way
ddf7d0
              * to get the public key */
ddf7d0
             break;
ddf7d0
+        case dsaKey:
ddf7d0
+            pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk);
ddf7d0
+            if (pubKeyHandle == CK_INVALID_HANDLE)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_BASE, arena, &pubk->u.dsa.params.base);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_PRIME, arena, &pubk->u.dsa.params.prime);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_SUBPRIME, arena, &pubk->u.dsa.params.subPrime);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_VALUE, arena, &pubk->u.dsa.publicValue);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            return pubk;
ddf7d0
+        case dhKey:
ddf7d0
+            pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk);
ddf7d0
+            if (pubKeyHandle == CK_INVALID_HANDLE)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_BASE, arena, &pubk->u.dh.base);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_PRIME, arena, &pubk->u.dh.prime);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                    CKA_VALUE, arena, &pubk->u.dh.publicValue);
ddf7d0
+            if (rv != SECSuccess)
ddf7d0
+                break;
ddf7d0
+            return pubk;
ddf7d0
         case rsaKey:
ddf7d0
             rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID,
ddf7d0
                                     CKA_MODULUS, arena, &pubk->u.rsa.modulus);
ddf7d0
@@ -1258,7 +1327,6 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
ddf7d0
             if (rv != SECSuccess)
ddf7d0
                 break;
ddf7d0
             return pubk;
ddf7d0
-            break;
ddf7d0
         case ecKey:
ddf7d0
             rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID,
ddf7d0
                                     CKA_EC_PARAMS, arena, &pubk->u.ec.DEREncodedParams);
ddf7d0
@@ -1268,7 +1336,23 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
ddf7d0
             rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID,
ddf7d0
                                     CKA_EC_POINT, arena, &pubk->u.ec.publicValue);
ddf7d0
             if (rv != SECSuccess || pubk->u.ec.publicValue.len == 0) {
ddf7d0
-                break;
ddf7d0
+                pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk);
ddf7d0
+                if (pubKeyHandle == CK_INVALID_HANDLE)
ddf7d0
+                    break;
ddf7d0
+                rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
ddf7d0
+                                        CKA_EC_POINT, arena, &pubk->u.ec.publicValue);
ddf7d0
+                if (rv != SECSuccess)
ddf7d0
+                    break;
ddf7d0
+            }
ddf7d0
+            /* ec.publicValue should be decoded, PKCS #11 defines CKA_EC_POINT
ddf7d0
+             * as encoded, but it's not always. try do decoded it and if it
ddf7d0
+             * succeeds store the decoded value */
ddf7d0
+            rv = SEC_QuickDERDecodeItem(arena, &decodedPoint,
ddf7d0
+                                        SEC_ASN1_GET(SEC_OctetStringTemplate), &pubk->u.ec.publicValue);
ddf7d0
+            if (rv == SECSuccess) {
ddf7d0
+                /* both values are in the public key arena, so it's safe to
ddf7d0
+                 * overwrite  the old value */
ddf7d0
+                pubk->u.ec.publicValue = decodedPoint;
ddf7d0
             }
ddf7d0
             pubk->u.ec.encoding = ECPoint_Undefined;
ddf7d0
             return pubk;
ddf7d0
@@ -1276,7 +1360,9 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
ddf7d0
             break;
ddf7d0
     }
ddf7d0
 
ddf7d0
-    PORT_FreeArena(arena, PR_FALSE);
ddf7d0
+    /* must use Destroy public key here, because some paths create temporary
ddf7d0
+     * PKCS #11 objects which need to be freed */
ddf7d0
+    SECKEY_DestroyPublicKey(pubk);
ddf7d0
     return NULL;
ddf7d0
 }
ddf7d0
 
ddf7d0
diff -up ./lib/pk11wrap/pk11priv.h.pub-priv-mech ./lib/pk11wrap/pk11priv.h
ddf7d0
--- ./lib/pk11wrap/pk11priv.h.pub-priv-mech	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/pk11wrap/pk11priv.h	2019-06-05 16:43:42.277498676 -0700
ddf7d0
@@ -111,6 +111,7 @@ CK_OBJECT_HANDLE PK11_FindObjectForCert(
ddf7d0
 PK11SymKey *pk11_CopyToSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
ddf7d0
                             CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey);
ddf7d0
 unsigned int pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType);
ddf7d0
+CK_OBJECT_HANDLE PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey);
ddf7d0
 
ddf7d0
 /**********************************************************************
ddf7d0
  *                   Certs
ddf7d0
diff -up ./lib/pk11wrap/pk11skey.c.pub-priv-mech ./lib/pk11wrap/pk11skey.c
ddf7d0
--- ./lib/pk11wrap/pk11skey.c.pub-priv-mech	2019-06-05 16:37:38.726685789 -0700
ddf7d0
+++ ./lib/pk11wrap/pk11skey.c	2019-06-05 16:43:42.278498675 -0700
ddf7d0
@@ -1841,6 +1841,35 @@ loser:
ddf7d0
 }
ddf7d0
 
ddf7d0
 /*
ddf7d0
+ * This regenerate a public key from a private key. This function is currently
ddf7d0
+ * NSS private. If we want to make it public, we need to add and optional
ddf7d0
+ * template or at least flags (a.la. PK11_DeriveWithFlags).
ddf7d0
+ */
ddf7d0
+CK_OBJECT_HANDLE
ddf7d0
+PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey)
ddf7d0
+{
ddf7d0
+    PK11SlotInfo *slot = privKey->pkcs11Slot;
ddf7d0
+    CK_MECHANISM mechanism;
ddf7d0
+    CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE;
ddf7d0
+    CK_RV crv;
ddf7d0
+
ddf7d0
+    mechanism.mechanism = CKM_NSS_PUB_FROM_PRIV;
ddf7d0
+    mechanism.pParameter = NULL;
ddf7d0
+    mechanism.ulParameterLen = 0;
ddf7d0
+
ddf7d0
+    PK11_EnterSlotMonitor(slot);
ddf7d0
+    crv = PK11_GETTAB(slot)->C_DeriveKey(slot->session, &mechanism,
ddf7d0
+                                         privKey->pkcs11ID, NULL, 0,
ddf7d0
+                                         &objectID);
ddf7d0
+    PK11_ExitSlotMonitor(slot);
ddf7d0
+    if (crv != CKR_OK) {
ddf7d0
+        PORT_SetError(PK11_MapError(crv));
ddf7d0
+        return CK_INVALID_HANDLE;
ddf7d0
+    }
ddf7d0
+    return objectID;
ddf7d0
+}
ddf7d0
+
ddf7d0
+/*
ddf7d0
  * This Generates a wrapping key based on a privateKey, publicKey, and two
ddf7d0
  * random numbers. For Mail usage RandomB should be NULL. In the Sender's
ddf7d0
  * case RandomA is generate, outherwize it is passed.
ddf7d0
diff -up ./lib/softoken/lowkey.c.pub-priv-mech ./lib/softoken/lowkey.c
ddf7d0
--- ./lib/softoken/lowkey.c.pub-priv-mech	2019-05-10 14:14:18.000000000 -0700
ddf7d0
+++ ./lib/softoken/lowkey.c	2019-06-05 16:44:20.469479019 -0700
ddf7d0
@@ -261,6 +261,7 @@ NSSLOWKEYPublicKey *
ddf7d0
 nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk)
ddf7d0
 {
ddf7d0
     NSSLOWKEYPublicKey *pubk;
ddf7d0
+    SECItem publicValue;
ddf7d0
     PLArenaPool *arena;
ddf7d0
 
ddf7d0
     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
ddf7d0
@@ -301,6 +302,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr
ddf7d0
 
ddf7d0
                 pubk->arena = arena;
ddf7d0
                 pubk->keyType = privk->keyType;
ddf7d0
+                /* if the public key value doesn't exist, calculate it */
ddf7d0
+                if (privk->u.dsa.publicValue.len == 0) {
ddf7d0
+                    rv = DH_Derive(&privk->u.dsa.params.base, &privk->u.dsa.params.prime,
ddf7d0
+                                   &privk->u.dsa.privateValue, &publicValue, 0);
ddf7d0
+                    if (rv != SECSuccess) {
ddf7d0
+                        break;
ddf7d0
+                    }
ddf7d0
+                    rv = SECITEM_CopyItem(privk->arena, &privk->u.dsa.publicValue, &publicValue);
ddf7d0
+                    SECITEM_FreeItem(&publicValue, PR_FALSE);
ddf7d0
+                    if (rv != SECSuccess) {
ddf7d0
+                        break;
ddf7d0
+                    }
ddf7d0
+                }
ddf7d0
                 rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue,
ddf7d0
                                       &privk->u.dsa.publicValue);
ddf7d0
                 if (rv != SECSuccess)
ddf7d0
@@ -327,6 +341,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr
ddf7d0
 
ddf7d0
                 pubk->arena = arena;
ddf7d0
                 pubk->keyType = privk->keyType;
ddf7d0
+                /* if the public key value doesn't exist, calculate it */
ddf7d0
+                if (privk->u.dh.publicValue.len == 0) {
ddf7d0
+                    rv = DH_Derive(&privk->u.dh.base, &privk->u.dh.prime,
ddf7d0
+                                   &privk->u.dh.privateValue, &publicValue, 0);
ddf7d0
+                    if (rv != SECSuccess) {
ddf7d0
+                        break;
ddf7d0
+                    }
ddf7d0
+                    rv = SECITEM_CopyItem(privk->arena, &privk->u.dh.publicValue, &publicValue);
ddf7d0
+                    SECITEM_FreeItem(&publicValue, PR_FALSE);
ddf7d0
+                    if (rv != SECSuccess) {
ddf7d0
+                        break;
ddf7d0
+                    }
ddf7d0
+                }
ddf7d0
                 rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue,
ddf7d0
                                       &privk->u.dh.publicValue);
ddf7d0
                 if (rv != SECSuccess)
ddf7d0
diff -up ./lib/softoken/pkcs11c.c.pub-priv-mech ./lib/softoken/pkcs11c.c
ddf7d0
--- ./lib/softoken/pkcs11c.c.pub-priv-mech	2019-06-05 16:37:38.743685780 -0700
ddf7d0
+++ ./lib/softoken/pkcs11c.c	2019-06-05 16:44:20.472479017 -0700
ddf7d0
@@ -6569,6 +6569,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
ddf7d0
             extractValue = PR_FALSE;
ddf7d0
             classType = CKO_PRIVATE_KEY;
ddf7d0
             break;
ddf7d0
+        case CKM_NSS_PUB_FROM_PRIV:
ddf7d0
+            extractValue = PR_FALSE;
ddf7d0
+            classType = CKO_PUBLIC_KEY;
ddf7d0
+            break;
ddf7d0
         case CKM_NSS_JPAKE_FINAL_SHA1:   /* fall through */
ddf7d0
         case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */
ddf7d0
         case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */
ddf7d0
@@ -6610,6 +6614,35 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
ddf7d0
     }
ddf7d0
 
ddf7d0
     switch (mechanism) {
ddf7d0
+        /* get a public key from a private key. nsslowkey_ConvertToPublickey()
ddf7d0
+         * will generate the public portion if it doesn't already exist. */
ddf7d0
+        case CKM_NSS_PUB_FROM_PRIV: {
ddf7d0
+            NSSLOWKEYPrivateKey *privKey;
ddf7d0
+            NSSLOWKEYPublicKey *pubKey;
ddf7d0
+            int error;
ddf7d0
+
ddf7d0
+            crv = sftk_GetULongAttribute(sourceKey, CKA_KEY_TYPE, &keyType);
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+
ddf7d0
+            /* privKey is stored in sourceKey and will be destroyed when
ddf7d0
+             * the sourceKey is freed. */
ddf7d0
+            privKey = sftk_GetPrivKey(sourceKey, keyType, &crv;;
ddf7d0
+            if (privKey == NULL) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            pubKey = nsslowkey_ConvertToPublicKey(privKey);
ddf7d0
+            if (pubKey == NULL) {
ddf7d0
+                error = PORT_GetError();
ddf7d0
+                crv = sftk_MapCryptError(error);
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_PutPubKey(key, sourceKey, keyType, pubKey);
ddf7d0
+            nsslowkey_DestroyPublicKey(pubKey);
ddf7d0
+            break;
ddf7d0
+        }
ddf7d0
+
ddf7d0
         case CKM_NSS_IKE_PRF_DERIVE:
ddf7d0
             if (pMechanism->ulParameterLen !=
ddf7d0
                 sizeof(CK_NSS_IKE_PRF_DERIVE_PARAMS)) {
ddf7d0
diff -up ./lib/softoken/pkcs11.c.pub-priv-mech ./lib/softoken/pkcs11.c
ddf7d0
--- ./lib/softoken/pkcs11.c.pub-priv-mech	2019-06-05 16:37:38.728685788 -0700
ddf7d0
+++ ./lib/softoken/pkcs11.c	2019-06-05 16:44:20.473479017 -0700
ddf7d0
@@ -2206,6 +2206,123 @@ sftk_GetPrivKey(SFTKObject *object, CK_K
ddf7d0
     return priv;
ddf7d0
 }
ddf7d0
 
ddf7d0
+/* populate a public key object from a lowpublic keys structure */
ddf7d0
+CK_RV
ddf7d0
+sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType, NSSLOWKEYPublicKey *pubKey)
ddf7d0
+{
ddf7d0
+    CK_OBJECT_CLASS classType = CKO_PUBLIC_KEY;
ddf7d0
+    CK_BBOOL cktrue = CK_TRUE;
ddf7d0
+    CK_RV crv = CKR_OK;
ddf7d0
+    sftk_DeleteAttributeType(publicKey, CKA_CLASS);
ddf7d0
+    sftk_DeleteAttributeType(publicKey, CKA_KEY_TYPE);
ddf7d0
+    sftk_DeleteAttributeType(publicKey, CKA_VALUE);
ddf7d0
+
ddf7d0
+    switch (keyType) {
ddf7d0
+        case CKK_RSA:
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_MODULUS);
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_PUBLIC_EXPONENT);
ddf7d0
+            /* format the keys */
ddf7d0
+            /* fill in the RSA dependent paramenters in the public key */
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_MODULUS,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.rsa.modulus));
ddf7d0
+            if (crv != CKR_OK)
ddf7d0
+                break;
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_PUBLIC_EXPONENT,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.rsa.publicExponent));
ddf7d0
+            break;
ddf7d0
+        case CKK_DSA:
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_PRIME);
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_SUBPRIME);
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_BASE);
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dsa.params.prime));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_SUBPRIME,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dsa.params.subPrime));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_BASE,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dsa.params.base));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dsa.publicValue));
ddf7d0
+            break;
ddf7d0
+
ddf7d0
+        case CKK_DH:
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_PRIME);
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_BASE);
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dh.prime));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_BASE,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dh.base));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.dh.publicValue));
ddf7d0
+            break;
ddf7d0
+
ddf7d0
+        case CKK_EC:
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_EC_PARAMS);
ddf7d0
+            sftk_DeleteAttributeType(publicKey, CKA_EC_POINT);
ddf7d0
+
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_EC_PARAMS,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.ec.ecParams.DEREncoding));
ddf7d0
+            if (crv != CKR_OK) {
ddf7d0
+                break;
ddf7d0
+            }
ddf7d0
+
ddf7d0
+            crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT,
ddf7d0
+                                        sftk_item_expand(&pubKey->u.ec.publicValue));
ddf7d0
+            break;
ddf7d0
+
ddf7d0
+        default:
ddf7d0
+            return CKR_KEY_TYPE_INCONSISTENT;
ddf7d0
+    }
ddf7d0
+    crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType,
ddf7d0
+                                sizeof(CK_OBJECT_CLASS));
ddf7d0
+    if (crv != CKR_OK)
ddf7d0
+        return crv;
ddf7d0
+    crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType,
ddf7d0
+                                sizeof(CK_KEY_TYPE));
ddf7d0
+    if (crv != CKR_OK)
ddf7d0
+        return crv;
ddf7d0
+    /* now handle the operator attributes */
ddf7d0
+    if (sftk_isTrue(privateKey, CKA_DECRYPT)) {
ddf7d0
+        crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
ddf7d0
+        if (crv != CKR_OK) {
ddf7d0
+            return crv;
ddf7d0
+        }
ddf7d0
+    }
ddf7d0
+    if (sftk_isTrue(privateKey, CKA_SIGN)) {
ddf7d0
+        crv = sftk_forceAttribute(publicKey, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));
ddf7d0
+        if (crv != CKR_OK) {
ddf7d0
+            return crv;
ddf7d0
+        }
ddf7d0
+    }
ddf7d0
+    if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) {
ddf7d0
+        crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL));
ddf7d0
+        if (crv != CKR_OK) {
ddf7d0
+            return crv;
ddf7d0
+        }
ddf7d0
+    }
ddf7d0
+    if (sftk_isTrue(privateKey, CKA_DERIVE)) {
ddf7d0
+        crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
ddf7d0
+        if (crv != CKR_OK) {
ddf7d0
+            return crv;
ddf7d0
+        }
ddf7d0
+    }
ddf7d0
+    return crv;
ddf7d0
+}
ddf7d0
+
ddf7d0
 /*
ddf7d0
  **************************** Symetric Key utils ************************
ddf7d0
  */
ddf7d0
diff -up ./lib/softoken/pkcs11i.h.pub-priv-mech ./lib/softoken/pkcs11i.h
ddf7d0
--- ./lib/softoken/pkcs11i.h.pub-priv-mech	2019-06-05 16:37:38.730685787 -0700
ddf7d0
+++ ./lib/softoken/pkcs11i.h	2019-06-05 16:44:20.473479017 -0700
ddf7d0
@@ -695,6 +695,9 @@ extern NSSLOWKEYPublicKey *sftk_GetPubKe
ddf7d0
                                           CK_KEY_TYPE key_type, CK_RV *crvp);
ddf7d0
 extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object,
ddf7d0
                                             CK_KEY_TYPE key_type, CK_RV *crvp);
ddf7d0
+extern CK_RV sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privKey,
ddf7d0
+                            CK_KEY_TYPE keyType,
ddf7d0
+                            NSSLOWKEYPublicKey *pubKey);
ddf7d0
 extern void sftk_FormatDESKey(unsigned char *key, int length);
ddf7d0
 extern PRBool sftk_CheckDESKey(unsigned char *key);
ddf7d0
 extern PRBool sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type);
ddf7d0
diff -up ./lib/util/pkcs11n.h.pub-priv-mech ./lib/util/pkcs11n.h
ddf7d0
--- ./lib/util/pkcs11n.h.pub-priv-mech	2019-06-05 16:37:38.733685785 -0700
ddf7d0
+++ ./lib/util/pkcs11n.h	2019-06-05 16:44:54.389461561 -0700
ddf7d0
@@ -152,11 +152,6 @@
ddf7d0
 #define CKM_NSS_HKDF_SHA384 (CKM_NSS + 5)
ddf7d0
 #define CKM_NSS_HKDF_SHA512 (CKM_NSS + 6)
ddf7d0
 
ddf7d0
-/* IKE mechanism (to be proposed to PKCS #11 */
ddf7d0
-#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 7)
ddf7d0
-#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 8)
ddf7d0
-#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 9)
ddf7d0
-#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 10)
ddf7d0
 
ddf7d0
 /* J-PAKE round 1 key generation mechanisms.
ddf7d0
  *
ddf7d0
@@ -238,6 +233,15 @@
ddf7d0
 
ddf7d0
 #define CKM_NSS_CHACHA20_CTR (CKM_NSS + 33)
ddf7d0
 
ddf7d0
+/* IKE mechanism (to be proposed to PKCS #11 */
ddf7d0
+#define CKM_NSS_IKE_PRF_PLUS_DERIVE (CKM_NSS + 34)
ddf7d0
+#define CKM_NSS_IKE_PRF_DERIVE (CKM_NSS + 35)
ddf7d0
+#define CKM_NSS_IKE1_PRF_DERIVE (CKM_NSS + 36)
ddf7d0
+#define CKM_NSS_IKE1_APP_B_PRF_DERIVE (CKM_NSS + 37)
ddf7d0
+
ddf7d0
+/* Derive a public key from a bare private key */
ddf7d0
+#define CKM_NSS_PUB_FROM_PRIV (CKM_NSS + 40)
ddf7d0
+
ddf7d0
 /*
ddf7d0
  * HISTORICAL:
ddf7d0
  * Do not attempt to use these. They are only used by NETSCAPE's internal