Bug 1106087 - Recreate newly generated ECDH private keys with an CKA_EC_POINT attribute to support JWK and PKCS8 export r=rbarnes

This commit is contained in:
Tim Taubert 2015-04-25 14:53:43 +02:00
parent 1c1e0bfe72
commit a339ca0ee1
3 changed files with 102 additions and 30 deletions

View File

@ -63,6 +63,29 @@ StringToUsage(const nsString& aUsage, CryptoKey::KeyUsage& aUsageOut)
return NS_OK;
}
SECKEYPrivateKey*
PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
CK_ATTRIBUTE* aTemplate,
CK_ULONG aTemplateSize)
{
// Create a generic object with the contents of the key
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return nullptr;
}
ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot,
aTemplate,
aTemplateSize,
PR_FALSE));
if (!obj) {
return nullptr;
}
// Have NSS translate the object to a private key.
return PK11_FindKeyByKeyID(slot, aObjID, nullptr);
}
CryptoKey::CryptoKey(nsIGlobalObject* aGlobal)
: mGlobal(aGlobal)
, mAttributes(0)
@ -223,6 +246,73 @@ CryptoKey::SetExtractable(bool aExtractable)
}
}
// 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;
}
void
CryptoKey::ClearUsages()
{
@ -367,6 +457,9 @@ CryptoKey::PrivateKeyFromPkcs8(CryptoBuffer& aKeyData,
{
SECKEYPrivateKey* privKey;
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot) {
return nullptr;
}
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
@ -582,36 +675,6 @@ CreateECPointForCoordinates(const CryptoBuffer& aX,
return point;
}
SECKEYPrivateKey*
PrivateKeyFromPrivateKeyTemplate(SECItem* aObjID,
CK_ATTRIBUTE* aTemplate,
CK_ULONG aTemplateSize)
{
// Create a generic object with the contents of the key
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
if (!slot.get()) {
return nullptr;
}
ScopedPK11GenericObject obj(PK11_CreateGenericObject(slot.get(),
aTemplate,
aTemplateSize,
PR_FALSE));
if (!obj.get()) {
return nullptr;
}
// Have NSS translate the object to a private key by inspection
// and make a copy we can own
ScopedSECKEYPrivateKey privKey(PK11_FindKeyByKeyID(slot.get(), aObjID,
nullptr));
if (!privKey.get()) {
return nullptr;
}
return SECKEY_CopyPrivateKey(privKey.get());
}
SECKEYPrivateKey*
CryptoKey::PrivateKeyFromJwk(const JsonWebKey& aJwk,
const nsNSSShutDownPreventionLock& /*proofOfLock*/)

View File

@ -116,6 +116,7 @@ public:
nsresult SetType(const nsString& aType);
void SetType(KeyType aType);
void SetExtractable(bool aExtractable);
nsresult AddPublicKeyData(SECKEYPublicKey* point);
void ClearUsages();
nsresult AddUsage(const nsString& aUsage);
nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask);

View File

@ -2331,6 +2331,14 @@ private:
mKeyPair.mPrivateKey.get()->SetPrivateKey(mPrivateKey);
mKeyPair.mPublicKey.get()->SetPublicKey(mPublicKey);
// PK11_GenerateKeyPair() does not set a CKA_EC_POINT attribute on the
// private key, we need this later when exporting to PKCS8 and JWK though.
if (mMechanism == CKM_EC_KEY_PAIR_GEN) {
nsresult rv = mKeyPair.mPrivateKey->AddPublicKeyData(mPublicKey);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
}
return NS_OK;
}