summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/cryptohi
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/cryptohi')
-rw-r--r--security/nss/lib/cryptohi/sechash.c35
-rw-r--r--security/nss/lib/cryptohi/sechash.h2
-rw-r--r--security/nss/lib/cryptohi/seckey.c96
3 files changed, 127 insertions, 6 deletions
diff --git a/security/nss/lib/cryptohi/sechash.c b/security/nss/lib/cryptohi/sechash.c
index b12621100..474fdfff9 100644
--- a/security/nss/lib/cryptohi/sechash.c
+++ b/security/nss/lib/cryptohi/sechash.c
@@ -202,7 +202,6 @@ HASH_GetHashTypeByOidTag(SECOidTag hashOid)
ht = HASH_AlgSHA512;
break;
default:
- ht = HASH_AlgNULL;
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
break;
}
@@ -210,6 +209,40 @@ HASH_GetHashTypeByOidTag(SECOidTag hashOid)
}
SECOidTag
+HASH_GetHashOidTagByHashType(HASH_HashType type)
+{
+ SECOidTag oid = SEC_OID_UNKNOWN;
+
+ switch (type) {
+ case HASH_AlgMD2:
+ oid = SEC_OID_MD2;
+ break;
+ case HASH_AlgMD5:
+ oid = SEC_OID_MD5;
+ break;
+ case HASH_AlgSHA1:
+ oid = SEC_OID_SHA1;
+ break;
+ case HASH_AlgSHA224:
+ oid = SEC_OID_SHA224;
+ break;
+ case HASH_AlgSHA256:
+ oid = SEC_OID_SHA256;
+ break;
+ case HASH_AlgSHA384:
+ oid = SEC_OID_SHA384;
+ break;
+ case HASH_AlgSHA512:
+ oid = SEC_OID_SHA512;
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ break;
+ }
+ return oid;
+}
+
+SECOidTag
HASH_GetHashOidTagByHMACOidTag(SECOidTag hmacOid)
{
SECOidTag hashOid = SEC_OID_UNKNOWN;
diff --git a/security/nss/lib/cryptohi/sechash.h b/security/nss/lib/cryptohi/sechash.h
index 94ff7ed3d..16e8b6713 100644
--- a/security/nss/lib/cryptohi/sechash.h
+++ b/security/nss/lib/cryptohi/sechash.h
@@ -53,6 +53,8 @@ extern HASH_HashType HASH_GetHashTypeByOidTag(SECOidTag hashOid);
extern SECOidTag HASH_GetHashOidTagByHMACOidTag(SECOidTag hmacOid);
extern SECOidTag HASH_GetHMACOidTagByHashOidTag(SECOidTag hashOid);
+extern SECOidTag HASH_GetHashOidTagByHashType(HASH_HashType type);
+
SEC_END_PROTOS
#endif /* _HASH_H_ */
diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c
index 173096050..fa13bc33e 100644
--- a/security/nss/lib/cryptohi/seckey.c
+++ b/security/nss/lib/cryptohi/seckey.c
@@ -1211,6 +1211,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)
{
@@ -1218,6 +1249,8 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateKey *privk)
PLArenaPool *arena;
CERTCertificate *cert;
SECStatus rv;
+ CK_OBJECT_HANDLE pubKeyHandle;
+ SECItem decodedPoint;
/*
* First try to look up the cert.
@@ -1248,11 +1281,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);
@@ -1263,7 +1332,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);
@@ -1273,7 +1341,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;
@@ -1281,7 +1365,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;
}