// NSS exports private EC keys without the CKA_EC_POINT attribute, i.e. the // public value. To properly export the private key to JWK or PKCS #8 we need // the public key data though and so we use this method to augment a private // key with data from the given public key. nsresult CryptoKey::AddPublicKeyData(SECKEYPublicKey* aPublicKey) { // This should be a private key. MOZ_ASSERT(GetKeyType() == PRIVATE); // There should be a private NSS key with type 'EC'. MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey); // The given public key should have the same key type. MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType); nsNSSShutDownPreventionLock locker; // Read EC params. ScopedAutoSECItem params; SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey.get(), CKA_EC_PARAMS, ¶ms); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } // Read private value. ScopedAutoSECItem value; rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey.get(), CKA_VALUE, &value); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } SECItem* point = &aPublicKey->u.ec.publicValue; CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_BBOOL falseValue = CK_FALSE; CK_KEY_TYPE ecValue = CKK_EC; CK_ATTRIBUTE keyTemplate[9] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &ecValue, sizeof(ecValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, // PrivateKeyFromPrivateKeyTemplate sets the ID. { CKA_ID, nullptr, 0 }, { CKA_EC_PARAMS, params.data, params.len }, { CKA_EC_POINT, point->data, point->len }, { CKA_VALUE, value.data, value.len }, }; mPrivateKey = PrivateKeyFromPrivateKeyTemplate(keyTemplate, ArrayLength(keyTemplate)); NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR); return NS_OK; }
SECKEYPrivateKey* CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_BBOOL falseValue = CK_FALSE; if (aJwk.mKty.EqualsLiteral(JWK_TYPE_EC)) { // Verify that all of the required parameters are present CryptoBuffer x, y, d; if (!aJwk.mCrv.WasPassed() || !aJwk.mX.WasPassed() || NS_FAILED(x.FromJwkBase64(aJwk.mX.Value())) || !aJwk.mY.WasPassed() || NS_FAILED(y.FromJwkBase64(aJwk.mY.Value())) || !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value()))) { return nullptr; } nsString namedCurve; if (!NormalizeToken(aJwk.mCrv.Value(), namedCurve)) { return nullptr; } ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return nullptr; } // Create parameters. SECItem* params = CreateECParamsForCurve(namedCurve, arena.get()); if (!params) { return nullptr; } SECItem* ecPoint = CreateECPointForCoordinates(x, y, arena.get()); if (!ecPoint) { return nullptr; } // Compute the ID for this key // This is generated with a SHA-1 hash, so unlikely to collide ScopedSECItem objID(PK11_MakeIDFromPubKey(ecPoint)); if (!objID.get()) { return nullptr; } // Populate template from parameters CK_KEY_TYPE ecValue = CKK_EC; CK_ATTRIBUTE keyTemplate[9] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &ecValue, sizeof(ecValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_EC_PARAMS, params->data, params->len }, { CKA_EC_POINT, ecPoint->data, ecPoint->len }, { CKA_VALUE, (void*) d.Elements(), d.Length() }, }; return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate, PR_ARRAY_SIZE(keyTemplate)); } if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) { // Verify that all of the required parameters are present CryptoBuffer n, e, d, p, q, dp, dq, qi; if (!aJwk.mN.WasPassed() || NS_FAILED(n.FromJwkBase64(aJwk.mN.Value())) || !aJwk.mE.WasPassed() || NS_FAILED(e.FromJwkBase64(aJwk.mE.Value())) || !aJwk.mD.WasPassed() || NS_FAILED(d.FromJwkBase64(aJwk.mD.Value())) || !aJwk.mP.WasPassed() || NS_FAILED(p.FromJwkBase64(aJwk.mP.Value())) || !aJwk.mQ.WasPassed() || NS_FAILED(q.FromJwkBase64(aJwk.mQ.Value())) || !aJwk.mDp.WasPassed() || NS_FAILED(dp.FromJwkBase64(aJwk.mDp.Value())) || !aJwk.mDq.WasPassed() || NS_FAILED(dq.FromJwkBase64(aJwk.mDq.Value())) || !aJwk.mQi.WasPassed() || NS_FAILED(qi.FromJwkBase64(aJwk.mQi.Value()))) { return nullptr; } ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return nullptr; } // Compute the ID for this key // This is generated with a SHA-1 hash, so unlikely to collide SECItem nItem = { siBuffer, nullptr, 0 }; if (!n.ToSECItem(arena, &nItem)) { return nullptr; } ScopedSECItem objID(PK11_MakeIDFromPubKey(&nItem)); if (!objID.get()) { return nullptr; } // Populate template from parameters CK_KEY_TYPE rsaValue = CKK_RSA; CK_ATTRIBUTE keyTemplate[14] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &rsaValue, sizeof(rsaValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_MODULUS, (void*) n.Elements(), n.Length() }, { CKA_PUBLIC_EXPONENT, (void*) e.Elements(), e.Length() }, { CKA_PRIVATE_EXPONENT, (void*) d.Elements(), d.Length() }, { CKA_PRIME_1, (void*) p.Elements(), p.Length() }, { CKA_PRIME_2, (void*) q.Elements(), q.Length() }, { CKA_EXPONENT_1, (void*) dp.Elements(), dp.Length() }, { CKA_EXPONENT_2, (void*) dq.Elements(), dq.Length() }, { CKA_COEFFICIENT, (void*) qi.Elements(), qi.Length() }, }; return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate, PR_ARRAY_SIZE(keyTemplate)); } return nullptr; }
// NSS exports private EC keys without the CKA_EC_POINT attribute, i.e. the // public value. To properly export the private key to JWK or PKCS #8 we need // the public key data though and so we use this method to augment a private // key with data from the given public key. nsresult CryptoKey::AddPublicKeyData(SECKEYPublicKey* aPublicKey) { // This should be a private key. MOZ_ASSERT(GetKeyType() == PRIVATE); // There should be a private NSS key with type 'EC'. MOZ_ASSERT(mPrivateKey && mPrivateKey->keyType == ecKey); // The given public key should have the same key type. MOZ_ASSERT(aPublicKey->keyType == mPrivateKey->keyType); nsNSSShutDownPreventionLock locker; ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return NS_ERROR_DOM_OPERATION_ERR; } // Generate a random 160-bit object ID. ScopedSECItem objID(::SECITEM_AllocItem(nullptr, nullptr, 20)); SECStatus rv = PK11_GenerateRandomOnSlot(slot, objID->data, objID->len); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } // Read EC params. ScopedSECItem params(::SECITEM_AllocItem(nullptr, nullptr, 0)); rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_EC_PARAMS, params); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } // Read private value. ScopedSECItem value(::SECITEM_AllocItem(nullptr, nullptr, 0)); rv = PK11_ReadRawAttribute(PK11_TypePrivKey, mPrivateKey, CKA_VALUE, value); if (rv != SECSuccess) { return NS_ERROR_DOM_OPERATION_ERR; } SECItem* point = &aPublicKey->u.ec.publicValue; CK_OBJECT_CLASS privateKeyValue = CKO_PRIVATE_KEY; CK_BBOOL falseValue = CK_FALSE; CK_KEY_TYPE ecValue = CKK_EC; CK_ATTRIBUTE keyTemplate[9] = { { CKA_CLASS, &privateKeyValue, sizeof(privateKeyValue) }, { CKA_KEY_TYPE, &ecValue, sizeof(ecValue) }, { CKA_TOKEN, &falseValue, sizeof(falseValue) }, { CKA_SENSITIVE, &falseValue, sizeof(falseValue) }, { CKA_PRIVATE, &falseValue, sizeof(falseValue) }, { CKA_ID, objID->data, objID->len }, { CKA_EC_PARAMS, params->data, params->len }, { CKA_EC_POINT, point->data, point->len }, { CKA_VALUE, value->data, value->len }, }; mPrivateKey = PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate, PR_ARRAY_SIZE(keyTemplate)); NS_ENSURE_TRUE(mPrivateKey, NS_ERROR_DOM_OPERATION_ERR); return NS_OK; }