diff options
author | Robert Relyea <rrelyea@redhat.com> | 2019-06-04 11:50:24 -0700 |
---|---|---|
committer | Robert Relyea <rrelyea@redhat.com> | 2019-06-04 11:50:24 -0700 |
commit | d5b4513b83b39994b68c5f9dd5d3a58376f71bcb (patch) | |
tree | b1750e22dc84b3c5ec2f4dfa3097e62bd64b64ed /lib/cryptohi | |
parent | 9dc8e666d68ce6aa5e0cb9b0e1c2862cdb4db9cb (diff) | |
download | nss-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.c | 96 |
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; } |