Index: content/child/webcrypto/shared_crypto_unittest.cc |
diff --git a/content/child/webcrypto/shared_crypto_unittest.cc b/content/child/webcrypto/shared_crypto_unittest.cc |
index 81877f651b1d0c65b006ed5448abb625fc618c99..a25db7760542b637480a8d077e1d5bb736771f95 100644 |
--- a/content/child/webcrypto/shared_crypto_unittest.cc |
+++ b/content/child/webcrypto/shared_crypto_unittest.cc |
@@ -90,6 +90,11 @@ bool operator==(const content::webcrypto::CryptoData& a, |
memcmp(a.bytes(), b.bytes(), a.byte_length()) == 0; |
} |
+bool operator!=(const content::webcrypto::CryptoData& a, |
+ const content::webcrypto::CryptoData& b) { |
+ return !(a == b); |
+} |
+ |
namespace { |
// ----------------------------------------------------------------------------- |
@@ -846,12 +851,12 @@ TEST_F(SharedCryptoTest, HMACSampleSets) { |
blink::WebCryptoAlgorithm algorithm = |
CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac); |
- blink::WebCryptoAlgorithm importAlgorithm = |
+ blink::WebCryptoAlgorithm import_algorithm = |
CreateHmacImportAlgorithm(test_hash.id()); |
blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
test_key, |
- importAlgorithm, |
+ import_algorithm, |
blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify); |
EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id()); |
@@ -2191,6 +2196,127 @@ TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkToPkcs8RoundTrip)) { |
CryptoData(exported_key_pkcs8)); |
} |
+// Tests importing multiple RSA private keys from JWK, and then exporting to |
+// PKCS8. |
+// |
+// This is a regression test for http://crbug.com/378315, for which importing |
+// a sequence of keys from JWK could yield the wrong key. The first key would |
+// be imported correctly, however every key after that would actually import |
+// the first key. |
+TEST_F(SharedCryptoTest, MAYBE(ImportMultipleRSAPrivateKeysJwk)) { |
+ scoped_ptr<base::ListValue> key_list; |
+ ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); |
+ |
+ // For this test to be meaningful the keys MUST be kept alive before importing |
+ // new keys. |
+ std::vector<blink::WebCryptoKey> live_keys; |
+ |
+ for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) { |
+ SCOPED_TRACE(key_index); |
+ |
+ base::DictionaryValue* key_values; |
+ ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values)); |
+ |
+ // Get the JWK representation of the key. |
+ base::DictionaryValue* key_jwk; |
+ ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk)); |
+ |
+ // Get the PKCS8 representation of the key. |
+ std::string pkcs8_hex_string; |
+ ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string)); |
+ std::vector<uint8> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string); |
+ |
+ // Get the modulus length for the key. |
+ int modulus_length_bits = 0; |
+ ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits)); |
+ |
+ blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
+ |
+ // Import the key from JWK. |
+ ASSERT_EQ( |
+ Status::Success(), |
+ ImportKeyJwkFromDict(*key_jwk, |
+ CreateRsaHashedImportAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
+ blink::WebCryptoAlgorithmIdSha256), |
+ true, |
+ blink::WebCryptoKeyUsageSign, |
+ &private_key)); |
+ |
+ live_keys.push_back(private_key); |
+ |
+ EXPECT_EQ( |
+ modulus_length_bits, |
+ static_cast<int>( |
+ private_key.algorithm().rsaHashedParams()->modulusLengthBits())); |
+ |
+ // Export to PKCS8 and verify that it matches expectation. |
+ std::vector<uint8> exported_key_pkcs8; |
+ ASSERT_EQ( |
+ Status::Success(), |
+ ExportKey( |
+ blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8)); |
+ |
+ EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8); |
+ } |
+} |
+ |
+// Import an RSA private key using JWK. Next import a JWK containing the same |
+// modulus, but mismatched parameters for the rest. It should NOT be possible |
+// that the second import retrieves the first key. See http://crbug.com/378315 |
+// for how that could happen. |
+TEST_F(SharedCryptoTest, MAYBE(ImportJwkExistingModulusAndInvalid)) { |
+#if defined(USE_NSS) |
+ if (!NSS_VersionCheck("3.16.2")) { |
+ LOG(WARNING) << "Skipping test because lacks NSS support"; |
+ return; |
+ } |
+#endif |
+ |
+ scoped_ptr<base::ListValue> key_list; |
+ ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); |
+ |
+ // Import a 1024-bit private key. |
+ base::DictionaryValue* key1_props; |
+ ASSERT_TRUE(key_list->GetDictionary(1, &key1_props)); |
+ base::DictionaryValue* key1_jwk; |
+ ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk)); |
+ |
+ blink::WebCryptoKey key1 = blink::WebCryptoKey::createNull(); |
+ ASSERT_EQ(Status::Success(), |
+ ImportKeyJwkFromDict(*key1_jwk, |
+ CreateRsaHashedImportAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
+ blink::WebCryptoAlgorithmIdSha256), |
+ true, |
+ blink::WebCryptoKeyUsageSign, |
+ &key1)); |
+ |
+ ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits()); |
+ |
+ // Construct a JWK using the modulus of key1, but all the other fields from |
+ // another key (also a 1024-bit private key). |
+ base::DictionaryValue* key2_props; |
+ ASSERT_TRUE(key_list->GetDictionary(5, &key2_props)); |
+ base::DictionaryValue* key2_jwk; |
+ ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk)); |
+ std::string modulus; |
+ key1_jwk->GetString("n", &modulus); |
+ key2_jwk->SetString("n", modulus); |
+ |
+ // This should fail, as the n,e,d parameters are not consistent. It MUST NOT |
+ // somehow return the key created earlier. |
+ blink::WebCryptoKey key2 = blink::WebCryptoKey::createNull(); |
+ ASSERT_EQ(Status::OperationError(), |
+ ImportKeyJwkFromDict(*key2_jwk, |
+ CreateRsaHashedImportAlgorithm( |
+ blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
+ blink::WebCryptoAlgorithmIdSha256), |
+ true, |
+ blink::WebCryptoKeyUsageSign, |
+ &key2)); |
+} |
+ |
// Import a JWK RSA private key with some optional parameters missing (q, dp, |
// dq, qi). |
// |
@@ -2455,7 +2581,7 @@ TEST_F(SharedCryptoTest, MAYBE(GenerateKeyPairRsa)) { |
TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { |
// Import a key pair. |
- blink::WebCryptoAlgorithm importAlgorithm = |
+ blink::WebCryptoAlgorithm import_algorithm = |
CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
blink::WebCryptoAlgorithmIdSha1); |
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
@@ -2463,7 +2589,7 @@ TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { |
ASSERT_NO_FATAL_FAILURE( |
ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
HexStringToBytes(kPrivateKeyPkcs8DerHex), |
- importAlgorithm, |
+ import_algorithm, |
false, |
blink::WebCryptoKeyUsageVerify, |
blink::WebCryptoKeyUsageSign, |
@@ -2588,7 +2714,7 @@ TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { |
ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests)); |
// Import the key pair. |
- blink::WebCryptoAlgorithm importAlgorithm = |
+ blink::WebCryptoAlgorithm import_algorithm = |
CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
blink::WebCryptoAlgorithmIdSha1); |
blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
@@ -2596,7 +2722,7 @@ TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { |
ASSERT_NO_FATAL_FAILURE( |
ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
HexStringToBytes(kPrivateKeyPkcs8DerHex), |
- importAlgorithm, |
+ import_algorithm, |
false, |
blink::WebCryptoKeyUsageVerify, |
blink::WebCryptoKeyUsageSign, |