summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2019-06-06 14:49:28 -0700
committerRobert Relyea <rrelyea@redhat.com>2019-06-06 14:49:28 -0700
commitc93463d134c11b89cc622cc7472990068b3f8d56 (patch)
treeaec6050283e34de00440d21df2c82df475d0bb4e
parent0280ec37dc2525a06468911825edd1497187c215 (diff)
parentd5b4513b83b39994b68c5f9dd5d3a58376f71bcb (diff)
downloadnss-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.cc97
-rw-r--r--lib/cryptohi/seckey.c96
-rw-r--r--lib/pk11wrap/pk11priv.h1
-rw-r--r--lib/pk11wrap/pk11skey.c29
-rw-r--r--lib/softoken/lowkey.c27
-rw-r--r--lib/softoken/pkcs11.c113
-rw-r--r--lib/softoken/pkcs11c.c33
-rw-r--r--lib/softoken/pkcs11i.h2
-rw-r--r--lib/util/pkcs11n.h3
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