summaryrefslogtreecommitdiff
path: root/lib/cryptohi
diff options
context:
space:
mode:
authorRobert Relyea <rrelyea@redhat.com>2019-06-04 11:50:24 -0700
committerRobert Relyea <rrelyea@redhat.com>2019-06-04 11:50:24 -0700
commitd5b4513b83b39994b68c5f9dd5d3a58376f71bcb (patch)
treeb1750e22dc84b3c5ec2f4dfa3097e62bd64b64ed /lib/cryptohi
parent9dc8e666d68ce6aa5e0cb9b0e1c2862cdb4db9cb (diff)
downloadnss-hg-d5b4513b83b39994b68c5f9dd5d3a58376f71bcb.tar.gz
Bug 1473806 3.38 certutil -R cannot use EC orphan key
gtests/pk11_gtest/pk11_import_unittest.cc Pick up the gtest changes from patch https://phabricator.services.mozilla.com/D33262#change-GhQvkCURcwqg Update the gtest to accept dsa and dh keys as well. lib/cryptohi/seckey.c When converting private keys to public keys, if we can't find a cert, look for a public key. If none found use the CKM_NSS_PUB_FROM_PRIV derive mechanism to create one. lib/pk11wrap/pk11priv.h lib/pk11wrap/pk11skey.c Implement an internal function that can be used to derive a public key from a private key. Give appropriate warnings about what has to happen to make this public. lib/softoken/lowkey.c Add code to the low level derive public from private to actually calculate public componants that aren't stored in the private key. lib/softoken/pkcs11i.h lib/softoken/pkcs11.c Add helper function to populate a PKCS #11 object from a NSSLOWKEYPublicKey. lib/util/pkcs11n.h lib/softoken/pkcs11c.c Implement CKM_NSS_PUB_FROM_PRIV. Differential Revision: https://phabricator.services.mozilla.com/D33682
Diffstat (limited to 'lib/cryptohi')
-rw-r--r--lib/cryptohi/seckey.c96
1 files changed, 91 insertions, 5 deletions
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;
}