diff options
author | Robert Relyea <rrelyea@redhat.com> | 2019-06-06 14:49:28 -0700 |
---|---|---|
committer | Robert Relyea <rrelyea@redhat.com> | 2019-06-06 14:49:28 -0700 |
commit | c93463d134c11b89cc622cc7472990068b3f8d56 (patch) | |
tree | aec6050283e34de00440d21df2c82df475d0bb4e | |
parent | 0280ec37dc2525a06468911825edd1497187c215 (diff) | |
parent | d5b4513b83b39994b68c5f9dd5d3a58376f71bcb (diff) | |
download | nss-hg-c93463d134c11b89cc622cc7472990068b3f8d56.tar.gz |
Merge Bug 1473806 3.38 certutil -R cannot use EC orphan key
onto tip
-rw-r--r-- | gtests/pk11_gtest/pk11_import_unittest.cc | 97 | ||||
-rw-r--r-- | lib/cryptohi/seckey.c | 96 | ||||
-rw-r--r-- | lib/pk11wrap/pk11priv.h | 1 | ||||
-rw-r--r-- | lib/pk11wrap/pk11skey.c | 29 | ||||
-rw-r--r-- | lib/softoken/lowkey.c | 27 | ||||
-rw-r--r-- | lib/softoken/pkcs11.c | 113 | ||||
-rw-r--r-- | lib/softoken/pkcs11c.c | 33 | ||||
-rw-r--r-- | lib/softoken/pkcs11i.h | 2 | ||||
-rw-r--r-- | lib/util/pkcs11n.h | 3 |
9 files changed, 379 insertions, 22 deletions
diff --git a/gtests/pk11_gtest/pk11_import_unittest.cc b/gtests/pk11_gtest/pk11_import_unittest.cc index a155bbd73..5ffa92e64 100644 --- a/gtests/pk11_gtest/pk11_import_unittest.cc +++ b/gtests/pk11_gtest/pk11_import_unittest.cc @@ -48,8 +48,15 @@ class Pk11KeyImportTestBase : public ::testing::Test { ScopedSECKEYEncryptedPrivateKeyInfo key_info; ScopedSECItem public_value; GenerateAndExport(&key_type, &key_info, &public_value); - ASSERT_NE(nullptr, key_info); + ASSERT_NE(nullptr, public_value); + // Note: NSS is currently unable export wrapped DH keys, so this doesn't + // test + // CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify + if (key_type == dhKey) { + return; + } + ASSERT_NE(nullptr, key_info); // Now import the encrypted key. static const uint8_t nick[] = "nick"; @@ -78,17 +85,41 @@ class Pk11KeyImportTestBase : public ::testing::Test { CK_MECHANISM_TYPE mech_; private: + SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) { + SECItem null = {siBuffer, NULL, 0}; + switch (SECKEY_GetPublicKeyType(pub_key.get())) { + case rsaKey: + case rsaPssKey: + case rsaOaepKey: + return pub_key->u.rsa.modulus; + case keaKey: + return pub_key->u.kea.publicValue; + case dsaKey: + return pub_key->u.dsa.publicValue; + case dhKey: + return pub_key->u.dh.publicValue; + case ecKey: + return pub_key->u.ec.publicValue; + case fortezzaKey: /* depricated */ + case nullKey: + /* didn't use default here so we can catch new key types at compile time + */ + break; + } + return null; + } void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key, const SECItem* expected_public) { // Verify the public key exists. StackSECItem priv_id; + KeyType type = SECKEY_GetPrivateKeyType(priv_key.get()); SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(), CKA_ID, &priv_id); ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: " << PORT_ErrorToName(PORT_GetError()); CK_ATTRIBUTE_TYPE value_type = CKA_VALUE; - switch (SECKEY_GetPrivateKeyType(priv_key.get())) { + switch (type) { case rsaKey: value_type = CKA_MODULUS; break; @@ -106,6 +137,8 @@ class Pk11KeyImportTestBase : public ::testing::Test { FAIL() << "unknown key type"; } + // Scan public key objects until we find one with the same CKA_ID as + // priv_key std::unique_ptr<PK11GenericObject, PK11GenericObjectsDeleter> objs( PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY)); ASSERT_NE(nullptr, objs); @@ -128,20 +161,44 @@ class Pk11KeyImportTestBase : public ::testing::Test { ASSERT_EQ(1U, token.len); ASSERT_NE(0, token.data[0]); - StackSECItem value; - rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &value); + StackSECItem raw_value; + SECItem decoded_value; + rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value); ASSERT_EQ(SECSuccess, rv); + SECItem value = raw_value; + // Decode the EC_POINT and check the output against expected. // CKA_EC_POINT isn't stable, see Bug 1520649. + ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + ASSERT_TRUE(arena); if (value_type == CKA_EC_POINT) { - continue; + // If this fails due to the noted inconsistency, we may need to + // check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag + rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value, + SEC_ASN1_GET(SEC_OctetStringTemplate), + &raw_value); + ASSERT_EQ(SECSuccess, rv); + value = decoded_value; } - ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value)) << "expected: " << DataBuffer(expected_public->data, expected_public->len) << std::endl << "actual: " << DataBuffer(value.data, value.len) << std::endl; + + // Finally, convert the private to public and ensure it matches. + ScopedSECKEYPublicKey pub_key(SECKEY_ConvertToPublicKey(priv_key.get())); + ASSERT_TRUE(pub_key); + SECItem converted_public = GetPublicComponent(pub_key); + ASSERT_TRUE(converted_public.len != 0); + + ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public)) + << "expected: " + << DataBuffer(expected_public->data, expected_public->len) + << std::endl + << "actual: " + << DataBuffer(converted_public.data, converted_public.len) + << std::endl; } } @@ -160,13 +217,6 @@ class Pk11KeyImportTestBase : public ::testing::Test { ScopedSECKEYPublicKey pub_key(pub_tmp); ASSERT_NE(nullptr, pub_key); - // Wrap and export the key. - ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo( - slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1, - nullptr)); - ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: " - << PORT_ErrorToName(PORT_GetError()); - // Save the public value, which we will need on import */ SECItem* pub_val; KeyType t = SECKEY_GetPublicKeyType(pub_key.get()); @@ -190,8 +240,22 @@ class Pk11KeyImportTestBase : public ::testing::Test { CheckForPublicKey(priv_key, pub_val); *key_type = t; - key_info->swap(epki); public_value->reset(SECITEM_DupItem(pub_val)); + + // Note: NSS is currently unable export wrapped DH keys, so this doesn't + // test + // CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify + if (mech_ == CKM_DH_PKCS_KEY_PAIR_GEN) { + return; + } + // Wrap and export the key. + ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo( + slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1, + nullptr)); + ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: " + << PORT_ErrorToName(PORT_GetError()); + + key_info->swap(epki); } ScopedPK11SlotInfo slot_; @@ -281,9 +345,8 @@ TEST_P(Pk11KeyImportTest, GenerateExportImport) { Test(); } INSTANTIATE_TEST_CASE_P(Pk11KeyImportTest, Pk11KeyImportTest, ::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN, - CKM_DSA_KEY_PAIR_GEN)); -// Note: NSS is currently unable export wrapped DH keys, so this doesn't test -// CKM_DH_PKCS_KEY_PAIR_GEN. + CKM_DSA_KEY_PAIR_GEN, + CKM_DH_PKCS_KEY_PAIR_GEN)); class Pk11KeyImportTestEC : public Pk11KeyImportTestBase, public ::testing::WithParamInterface<SECOidTag> { diff --git a/lib/cryptohi/seckey.c b/lib/cryptohi/seckey.c index 080909772..75c97faee 100644 --- a/lib/cryptohi/seckey.c +++ b/lib/cryptohi/seckey.c @@ -1206,6 +1206,37 @@ SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk) return NULL; } +/* + * Use the private key to find a public key handle. The handle will be on + * the same slot as the private key. + */ +static CK_OBJECT_HANDLE +seckey_FindPublicKeyHandle(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk) +{ + CK_OBJECT_HANDLE keyID; + + /* this helper function is only used below. If we want to make this more + * general, we would need to free up any already cached handles if the + * slot doesn't match up with the private key slot */ + PORT_Assert(pubk->pkcs11ID == CK_INVALID_HANDLE); + + /* first look for a matching public key */ + keyID = PK11_MatchItem(privk->pkcs11Slot, privk->pkcs11ID, CKO_PUBLIC_KEY); + if (keyID != CK_INVALID_HANDLE) { + return keyID; + } + + /* none found, create a temp one, make the pubk the owner */ + pubk->pkcs11ID = PK11_DerivePubKeyFromPrivKey(privk); + if (pubk->pkcs11ID == CK_INVALID_HANDLE) { + /* end of the road. Token doesn't have matching public key, nor can + * token regenerate a new public key from and existing private key. */ + return CK_INVALID_HANDLE; + } + pubk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot); + return pubk->pkcs11ID; +} + SECKEYPublicKey * SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) { @@ -1213,6 +1244,8 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) PLArenaPool *arena; CERTCertificate *cert; SECStatus rv; + CK_OBJECT_HANDLE pubKeyHandle; + SECItem decodedPoint; /* * First try to look up the cert. @@ -1243,11 +1276,47 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) switch (privk->keyType) { case nullKey: - case dhKey: - case dsaKey: /* Nothing to query, if the cert isn't there, we're done -- no way * to get the public key */ break; + case dsaKey: + pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); + if (pubKeyHandle == CK_INVALID_HANDLE) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_BASE, arena, &pubk->u.dsa.params.base); + if (rv != SECSuccess) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_PRIME, arena, &pubk->u.dsa.params.prime); + if (rv != SECSuccess) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_SUBPRIME, arena, &pubk->u.dsa.params.subPrime); + if (rv != SECSuccess) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_VALUE, arena, &pubk->u.dsa.publicValue); + if (rv != SECSuccess) + break; + return pubk; + case dhKey: + pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); + if (pubKeyHandle == CK_INVALID_HANDLE) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_BASE, arena, &pubk->u.dh.base); + if (rv != SECSuccess) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_PRIME, arena, &pubk->u.dh.prime); + if (rv != SECSuccess) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_VALUE, arena, &pubk->u.dh.publicValue); + if (rv != SECSuccess) + break; + return pubk; case rsaKey: rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, CKA_MODULUS, arena, &pubk->u.rsa.modulus); @@ -1258,7 +1327,6 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) if (rv != SECSuccess) break; return pubk; - break; case ecKey: rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, CKA_EC_PARAMS, arena, &pubk->u.ec.DEREncodedParams); @@ -1268,7 +1336,23 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, CKA_EC_POINT, arena, &pubk->u.ec.publicValue); if (rv != SECSuccess || pubk->u.ec.publicValue.len == 0) { - break; + pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk); + if (pubKeyHandle == CK_INVALID_HANDLE) + break; + rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle, + CKA_EC_POINT, arena, &pubk->u.ec.publicValue); + if (rv != SECSuccess) + break; + } + /* ec.publicValue should be decoded, PKCS #11 defines CKA_EC_POINT + * as encoded, but it's not always. try do decoded it and if it + * succeeds store the decoded value */ + rv = SEC_QuickDERDecodeItem(arena, &decodedPoint, + SEC_ASN1_GET(SEC_OctetStringTemplate), &pubk->u.ec.publicValue); + if (rv == SECSuccess) { + /* both values are in the public key arena, so it's safe to + * overwrite the old value */ + pubk->u.ec.publicValue = decodedPoint; } pubk->u.ec.encoding = ECPoint_Undefined; return pubk; @@ -1276,7 +1360,9 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk) break; } - PORT_FreeArena(arena, PR_FALSE); + /* must use Destroy public key here, because some paths create temporary + * PKCS #11 objects which need to be freed */ + SECKEY_DestroyPublicKey(pubk); return NULL; } diff --git a/lib/pk11wrap/pk11priv.h b/lib/pk11wrap/pk11priv.h index 8848c81ec..13fc74c3a 100644 --- a/lib/pk11wrap/pk11priv.h +++ b/lib/pk11wrap/pk11priv.h @@ -111,6 +111,7 @@ CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert, PK11SymKey *pk11_CopyToSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey); unsigned int pk11_GetPredefinedKeyLength(CK_KEY_TYPE keyType); +CK_OBJECT_HANDLE PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey); /********************************************************************** * Certs diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c index cf2a40a2f..6024d6c80 100644 --- a/lib/pk11wrap/pk11skey.c +++ b/lib/pk11wrap/pk11skey.c @@ -1840,6 +1840,35 @@ loser: } /* + * This regenerate a public key from a private key. This function is currently + * NSS private. If we want to make it public, we need to add and optional + * template or at least flags (a.la. PK11_DeriveWithFlags). + */ +CK_OBJECT_HANDLE +PK11_DerivePubKeyFromPrivKey(SECKEYPrivateKey *privKey) +{ + PK11SlotInfo *slot = privKey->pkcs11Slot; + CK_MECHANISM mechanism; + CK_OBJECT_HANDLE objectID = CK_INVALID_HANDLE; + CK_RV crv; + + mechanism.mechanism = CKM_NSS_PUB_FROM_PRIV; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_DeriveKey(slot->session, &mechanism, + privKey->pkcs11ID, NULL, 0, + &objectID); + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + return CK_INVALID_HANDLE; + } + return objectID; +} + +/* * This Generates a wrapping key based on a privateKey, publicKey, and two * random numbers. For Mail usage RandomB should be NULL. In the Sender's * case RandomA is generate, outherwize it is passed. diff --git a/lib/softoken/lowkey.c b/lib/softoken/lowkey.c index a28a3a55e..e9bbff1d9 100644 --- a/lib/softoken/lowkey.c +++ b/lib/softoken/lowkey.c @@ -261,6 +261,7 @@ NSSLOWKEYPublicKey * nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) { NSSLOWKEYPublicKey *pubk; + SECItem publicValue; PLArenaPool *arena; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); @@ -301,6 +302,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) pubk->arena = arena; pubk->keyType = privk->keyType; + /* if the public key value doesn't exist, calculate it */ + if (privk->u.dsa.publicValue.len == 0) { + rv = DH_Derive(&privk->u.dsa.params.base, &privk->u.dsa.params.prime, + &privk->u.dsa.privateValue, &publicValue, 0); + if (rv != SECSuccess) { + break; + } + rv = SECITEM_CopyItem(privk->arena, &privk->u.dsa.publicValue, &publicValue); + SECITEM_FreeItem(&publicValue, PR_FALSE); + if (rv != SECSuccess) { + break; + } + } rv = SECITEM_CopyItem(arena, &pubk->u.dsa.publicValue, &privk->u.dsa.publicValue); if (rv != SECSuccess) @@ -327,6 +341,19 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) pubk->arena = arena; pubk->keyType = privk->keyType; + /* if the public key value doesn't exist, calculate it */ + if (privk->u.dh.publicValue.len == 0) { + rv = DH_Derive(&privk->u.dh.base, &privk->u.dh.prime, + &privk->u.dh.privateValue, &publicValue, 0); + if (rv != SECSuccess) { + break; + } + rv = SECITEM_CopyItem(privk->arena, &privk->u.dh.publicValue, &publicValue); + SECITEM_FreeItem(&publicValue, PR_FALSE); + if (rv != SECSuccess) { + break; + } + } rv = SECITEM_CopyItem(arena, &pubk->u.dh.publicValue, &privk->u.dh.publicValue); if (rv != SECSuccess) diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c index 8fc9eda81..b555354af 100644 --- a/lib/softoken/pkcs11.c +++ b/lib/softoken/pkcs11.c @@ -2200,6 +2200,119 @@ sftk_GetPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) return priv; } +/* populate a public key object from a lowpublic keys structure */ +CK_RV +sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType, NSSLOWKEYPublicKey *pubKey) +{ + CK_OBJECT_CLASS classType = CKO_PUBLIC_KEY; + CK_BBOOL cktrue = CK_TRUE; + CK_RV crv = CKR_OK; + sftk_DeleteAttributeType(publicKey, CKA_CLASS); + sftk_DeleteAttributeType(publicKey, CKA_KEY_TYPE); + sftk_DeleteAttributeType(publicKey, CKA_VALUE); + + switch (keyType) { + case CKK_RSA: + sftk_DeleteAttributeType(publicKey, CKA_MODULUS); + sftk_DeleteAttributeType(publicKey, CKA_PUBLIC_EXPONENT); + /* format the keys */ + /* fill in the RSA dependent paramenters in the public key */ + crv = sftk_AddAttributeType(publicKey, CKA_MODULUS, + sftk_item_expand(&pubKey->u.rsa.modulus)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_PUBLIC_EXPONENT, + sftk_item_expand(&pubKey->u.rsa.publicExponent)); + break; + case CKK_DSA: + sftk_DeleteAttributeType(publicKey, CKA_PRIME); + sftk_DeleteAttributeType(publicKey, CKA_SUBPRIME); + sftk_DeleteAttributeType(publicKey, CKA_BASE); + crv = sftk_AddAttributeType(publicKey, CKA_PRIME, + sftk_item_expand(&pubKey->u.dsa.params.prime)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_SUBPRIME, + sftk_item_expand(&pubKey->u.dsa.params.subPrime)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_BASE, + sftk_item_expand(&pubKey->u.dsa.params.base)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_VALUE, + sftk_item_expand(&pubKey->u.dsa.publicValue)); + break; + case CKK_DH: + sftk_DeleteAttributeType(publicKey, CKA_PRIME); + sftk_DeleteAttributeType(publicKey, CKA_BASE); + crv = sftk_AddAttributeType(publicKey, CKA_PRIME, + sftk_item_expand(&pubKey->u.dh.prime)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_BASE, + sftk_item_expand(&pubKey->u.dh.base)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_VALUE, + sftk_item_expand(&pubKey->u.dh.publicValue)); + break; + case CKK_EC: + sftk_DeleteAttributeType(publicKey, CKA_EC_PARAMS); + sftk_DeleteAttributeType(publicKey, CKA_EC_POINT); + crv = sftk_AddAttributeType(publicKey, CKA_EC_PARAMS, + sftk_item_expand(&pubKey->u.ec.ecParams.DEREncoding)); + if (crv != CKR_OK) { + break; + } + crv = sftk_AddAttributeType(publicKey, CKA_EC_POINT, + sftk_item_expand(&pubKey->u.ec.publicValue)); + break; + default: + return CKR_KEY_TYPE_INCONSISTENT; + } + crv = sftk_AddAttributeType(publicKey, CKA_CLASS, &classType, + sizeof(CK_OBJECT_CLASS)); + if (crv != CKR_OK) + return crv; + crv = sftk_AddAttributeType(publicKey, CKA_KEY_TYPE, &keyType, + sizeof(CK_KEY_TYPE)); + if (crv != CKR_OK) + return crv; + /* now handle the operator attributes */ + if (sftk_isTrue(privateKey, CKA_DECRYPT)) { + crv = sftk_forceAttribute(publicKey, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL)); + if (crv != CKR_OK) { + return crv; + } + } + if (sftk_isTrue(privateKey, CKA_SIGN)) { + crv = sftk_forceAttribute(publicKey, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); + if (crv != CKR_OK) { + return crv; + } + } + if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) { + crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL)); + if (crv != CKR_OK) { + return crv; + } + } + if (sftk_isTrue(privateKey, CKA_DERIVE)) { + crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL)); + if (crv != CKR_OK) { + return crv; + } + } + return crv; +} + /* **************************** Symetric Key utils ************************ */ diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c index 8b3c68d44..61867245b 100644 --- a/lib/softoken/pkcs11c.c +++ b/lib/softoken/pkcs11c.c @@ -6566,6 +6566,10 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, extractValue = PR_FALSE; classType = CKO_PRIVATE_KEY; break; + case CKM_NSS_PUB_FROM_PRIV: + extractValue = PR_FALSE; + classType = CKO_PUBLIC_KEY; + break; case CKM_NSS_JPAKE_FINAL_SHA1: /* fall through */ case CKM_NSS_JPAKE_FINAL_SHA256: /* fall through */ case CKM_NSS_JPAKE_FINAL_SHA384: /* fall through */ @@ -6607,6 +6611,35 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession, } switch (mechanism) { + /* get a public key from a private key. nsslowkey_ConvertToPublickey() + * will generate the public portion if it doesn't already exist. */ + case CKM_NSS_PUB_FROM_PRIV: { + NSSLOWKEYPrivateKey *privKey; + NSSLOWKEYPublicKey *pubKey; + int error; + + crv = sftk_GetULongAttribute(sourceKey, CKA_KEY_TYPE, &keyType); + if (crv != CKR_OK) { + break; + } + + /* privKey is stored in sourceKey and will be destroyed when + * the sourceKey is freed. */ + privKey = sftk_GetPrivKey(sourceKey, keyType, &crv); + if (privKey == NULL) { + break; + } + pubKey = nsslowkey_ConvertToPublicKey(privKey); + if (pubKey == NULL) { + error = PORT_GetError(); + crv = sftk_MapCryptError(error); + break; + } + crv = sftk_PutPubKey(key, sourceKey, keyType, pubKey); + nsslowkey_DestroyPublicKey(pubKey); + break; + } + /* * generate the master secret */ diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h index 0693c1713..2e9022d5e 100644 --- a/lib/softoken/pkcs11i.h +++ b/lib/softoken/pkcs11i.h @@ -691,6 +691,8 @@ extern NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp); extern NSSLOWKEYPrivateKey *sftk_GetPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp); +extern CK_RV sftk_PutPubKey(SFTKObject *publicKey, SFTKObject *privKey, CK_KEY_TYPE keyType, + NSSLOWKEYPublicKey *pubKey); extern void sftk_FormatDESKey(unsigned char *key, int length); extern PRBool sftk_CheckDESKey(unsigned char *key); extern PRBool sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type); diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h index fab747ba3..f97092c64 100644 --- a/lib/util/pkcs11n.h +++ b/lib/util/pkcs11n.h @@ -232,6 +232,9 @@ #define CKM_NSS_CHACHA20_CTR (CKM_NSS + 33) +/* IKE is here, skip those entries */ +#define CKM_NSS_PUB_FROM_PRIV (CKM_NSS + 40) + /* * HISTORICAL: * Do not attempt to use these. They are only used by NETSCAPE's internal |