Chromium Code Reviews| Index: content/child/webcrypto/platform_crypto_nss.cc |
| diff --git a/content/child/webcrypto/platform_crypto_nss.cc b/content/child/webcrypto/platform_crypto_nss.cc |
| index 3d0e9923a69f4185b2bdb2e4919fa2ff61e25204..80fa2663c73e1ca2d0d05ece371b9d65d0be9492 100644 |
| --- a/content/child/webcrypto/platform_crypto_nss.cc |
| +++ b/content/child/webcrypto/platform_crypto_nss.cc |
| @@ -18,6 +18,7 @@ |
| #include "content/child/webcrypto/status.h" |
| #include "content/child/webcrypto/webcrypto_util.h" |
| #include "crypto/nss_util.h" |
| +#include "crypto/random.h" |
| #include "crypto/scoped_nss_types.h" |
| #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| @@ -1717,6 +1718,39 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, |
| AddOptionalAttribute(CKA_PUBLIC_EXPONENT, public_exponent, &key_template); |
| AddOptionalAttribute(CKA_PRIVATE_EXPONENT, private_exponent, &key_template); |
| + // Manufacture a CKA_ID so the created key can be retrieved later as a |
| + // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more |
| + // direct way to do this in NSS. |
| + // |
| + // A randomly generated value is used for the ID. |
| + // |
| + // NSS assigns the CKA_ID to PK11_MakeIDFromPubKey() for the other key |
| + // creation paths. However it is incorrect to try and use that as the CKA_ID |
| + // here because: |
| + // |
| + // (1) CreateGenericObject does not validate its parameters. It is therefore |
| + // possible to construct a key using the known public modulus, and all |
| + // the other parameters are bogus. FindKeyByKeyID() returns the first |
| + // key matching the ID. So this would effectively allow an attacker to |
| + // retrieve a private key of their choice. |
| + // NSS 3.16.2 does validate parameters. |
| + // |
| + // (2) The ID space is shared by different key types. So even if parameters |
| + // were validated by NSS, FindKeyByKeyID() could still return the wrong |
| + // key. For instance it might return a DH key that happens to have same |
| + // values for its public data. |
| + // Ryan says this isn't possible in practice, because matching values for |
|
Ryan Sleevi
2014/06/02 23:55:57
We don't do this in comments :)
But I'm glad Rya
|
| + // valid keys can't be easily guessed. |
| + // |
| + // (3) Even if the above two problems were non-issues, there is no guarantee |
| + // that FindKeyByKeyID() returns the object just created. If the same |
| + // private key were imported multiple times, with different flags, using |
| + // the wrong one could lead to problems. |
| + std::vector<uint8> cka_id(20); |
| + crypto::RandBytes(&cka_id[0], cka_id.size()); |
| + AddOptionalAttribute(CKA_ID, CryptoData(cka_id), &key_template); |
| + SECItem object_id = MakeSECItemForBuffer(CryptoData(cka_id)); |
| + |
| // Optional properties (all of these will have been specified or none). |
| AddOptionalAttribute(CKA_PRIME_1, prime1, &key_template); |
| AddOptionalAttribute(CKA_PRIME_2, prime2, &key_template); |
| @@ -1732,18 +1766,9 @@ Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, |
| if (!key_object) |
| return Status::OperationError(); |
| - // The ID isn't guaranteed to be set by PKCS#11. However it is by softtoken so |
| - // this should work. |
| - SECItem object_id = {}; |
| - if (PK11_ReadRawAttribute( |
| - PK11_TypeGeneric, key_object.get(), CKA_ID, &object_id) != SECSuccess) |
| - return Status::OperationError(); |
| - |
| crypto::ScopedSECKEYPrivateKey private_key( |
| PK11_FindKeyByKeyID(slot.get(), &object_id, NULL)); |
| - SECITEM_FreeItem(&object_id, PR_FALSE); |
| - |
| if (!private_key) |
| return Status::OperationError(); |