OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/child/webcrypto/shared_crypto.h" | 5 #include "content/child/webcrypto/shared_crypto.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 void PrintTo(const CryptoData& data, ::std::ostream* os) { | 83 void PrintTo(const CryptoData& data, ::std::ostream* os) { |
84 *os << "[" << base::HexEncode(data.bytes(), data.byte_length()) << "]"; | 84 *os << "[" << base::HexEncode(data.bytes(), data.byte_length()) << "]"; |
85 } | 85 } |
86 | 86 |
87 bool operator==(const content::webcrypto::CryptoData& a, | 87 bool operator==(const content::webcrypto::CryptoData& a, |
88 const content::webcrypto::CryptoData& b) { | 88 const content::webcrypto::CryptoData& b) { |
89 return a.byte_length() == b.byte_length() && | 89 return a.byte_length() == b.byte_length() && |
90 memcmp(a.bytes(), b.bytes(), a.byte_length()) == 0; | 90 memcmp(a.bytes(), b.bytes(), a.byte_length()) == 0; |
91 } | 91 } |
92 | 92 |
| 93 bool operator!=(const content::webcrypto::CryptoData& a, |
| 94 const content::webcrypto::CryptoData& b) { |
| 95 return !(a == b); |
| 96 } |
| 97 |
93 namespace { | 98 namespace { |
94 | 99 |
95 // ----------------------------------------------------------------------------- | 100 // ----------------------------------------------------------------------------- |
96 | 101 |
97 // TODO(eroman): For Linux builds using system NSS, AES-GCM support is a | 102 // TODO(eroman): For Linux builds using system NSS, AES-GCM support is a |
98 // runtime dependency. Test it by trying to import a key. | 103 // runtime dependency. Test it by trying to import a key. |
99 // TODO(padolph): Consider caching the result of the import key test. | 104 // TODO(padolph): Consider caching the result of the import key test. |
100 bool SupportsAesGcm() { | 105 bool SupportsAesGcm() { |
101 std::vector<uint8> key_raw(16, 0); | 106 std::vector<uint8> key_raw(16, 0); |
102 | 107 |
(...skipping 736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
839 | 844 |
840 blink::WebCryptoAlgorithm test_hash = GetDigestAlgorithm(test, "hash"); | 845 blink::WebCryptoAlgorithm test_hash = GetDigestAlgorithm(test, "hash"); |
841 const std::vector<uint8> test_key = GetBytesFromHexString(test, "key"); | 846 const std::vector<uint8> test_key = GetBytesFromHexString(test, "key"); |
842 const std::vector<uint8> test_message = | 847 const std::vector<uint8> test_message = |
843 GetBytesFromHexString(test, "message"); | 848 GetBytesFromHexString(test, "message"); |
844 const std::vector<uint8> test_mac = GetBytesFromHexString(test, "mac"); | 849 const std::vector<uint8> test_mac = GetBytesFromHexString(test, "mac"); |
845 | 850 |
846 blink::WebCryptoAlgorithm algorithm = | 851 blink::WebCryptoAlgorithm algorithm = |
847 CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac); | 852 CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac); |
848 | 853 |
849 blink::WebCryptoAlgorithm importAlgorithm = | 854 blink::WebCryptoAlgorithm import_algorithm = |
850 CreateHmacImportAlgorithm(test_hash.id()); | 855 CreateHmacImportAlgorithm(test_hash.id()); |
851 | 856 |
852 blink::WebCryptoKey key = ImportSecretKeyFromRaw( | 857 blink::WebCryptoKey key = ImportSecretKeyFromRaw( |
853 test_key, | 858 test_key, |
854 importAlgorithm, | 859 import_algorithm, |
855 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify); | 860 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify); |
856 | 861 |
857 EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id()); | 862 EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id()); |
858 EXPECT_EQ(test_key.size() * 8, key.algorithm().hmacParams()->lengthBits()); | 863 EXPECT_EQ(test_key.size() * 8, key.algorithm().hmacParams()->lengthBits()); |
859 | 864 |
860 // Verify exported raw key is identical to the imported data | 865 // Verify exported raw key is identical to the imported data |
861 std::vector<uint8> raw_key; | 866 std::vector<uint8> raw_key; |
862 EXPECT_EQ(Status::Success(), | 867 EXPECT_EQ(Status::Success(), |
863 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key)); | 868 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key)); |
864 EXPECT_BYTES_EQ(test_key, raw_key); | 869 EXPECT_BYTES_EQ(test_key, raw_key); |
(...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2184 | 2189 |
2185 std::vector<uint8> exported_key_pkcs8; | 2190 std::vector<uint8> exported_key_pkcs8; |
2186 ASSERT_EQ( | 2191 ASSERT_EQ( |
2187 Status::Success(), | 2192 Status::Success(), |
2188 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8)); | 2193 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8)); |
2189 | 2194 |
2190 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | 2195 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), |
2191 CryptoData(exported_key_pkcs8)); | 2196 CryptoData(exported_key_pkcs8)); |
2192 } | 2197 } |
2193 | 2198 |
| 2199 // Tests importing multiple RSA private keys from JWK, and then exporting to |
| 2200 // PKCS8. |
| 2201 // |
| 2202 // This is a regression test for http://crbug.com/378315, for which importing |
| 2203 // a sequence of keys from JWK could yield the wrong key. The first key would |
| 2204 // be imported correctly, however every key after that would actually import |
| 2205 // the first key. |
| 2206 TEST_F(SharedCryptoTest, MAYBE(ImportMultipleRSAPrivateKeysJwk)) { |
| 2207 scoped_ptr<base::ListValue> key_list; |
| 2208 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); |
| 2209 |
| 2210 // For this test to be meaningful the keys MUST be kept alive before importing |
| 2211 // new keys. |
| 2212 std::vector<blink::WebCryptoKey> live_keys; |
| 2213 |
| 2214 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) { |
| 2215 SCOPED_TRACE(key_index); |
| 2216 |
| 2217 base::DictionaryValue* key_values; |
| 2218 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values)); |
| 2219 |
| 2220 // Get the JWK representation of the key. |
| 2221 base::DictionaryValue* key_jwk; |
| 2222 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk)); |
| 2223 |
| 2224 // Get the PKCS8 representation of the key. |
| 2225 std::string pkcs8_hex_string; |
| 2226 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string)); |
| 2227 std::vector<uint8> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string); |
| 2228 |
| 2229 // Get the modulus length for the key. |
| 2230 int modulus_length_bits = 0; |
| 2231 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits)); |
| 2232 |
| 2233 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
| 2234 |
| 2235 // Import the key from JWK. |
| 2236 ASSERT_EQ( |
| 2237 Status::Success(), |
| 2238 ImportKeyJwkFromDict(*key_jwk, |
| 2239 CreateRsaHashedImportAlgorithm( |
| 2240 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 2241 blink::WebCryptoAlgorithmIdSha256), |
| 2242 true, |
| 2243 blink::WebCryptoKeyUsageSign, |
| 2244 &private_key)); |
| 2245 |
| 2246 live_keys.push_back(private_key); |
| 2247 |
| 2248 EXPECT_EQ( |
| 2249 modulus_length_bits, |
| 2250 static_cast<int>( |
| 2251 private_key.algorithm().rsaHashedParams()->modulusLengthBits())); |
| 2252 |
| 2253 // Export to PKCS8 and verify that it matches expectation. |
| 2254 std::vector<uint8> exported_key_pkcs8; |
| 2255 ASSERT_EQ( |
| 2256 Status::Success(), |
| 2257 ExportKey( |
| 2258 blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8)); |
| 2259 |
| 2260 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8); |
| 2261 } |
| 2262 } |
| 2263 |
| 2264 // Import an RSA private key using JWK. Next import a JWK containing the same |
| 2265 // modulus, but mismatched parameters for the rest. It should NOT be possible |
| 2266 // that the second import retrieves the first key. See http://crbug.com/378315 |
| 2267 // for how that could happen. |
| 2268 TEST_F(SharedCryptoTest, MAYBE(ImportJwkExistingModulusAndInvalid)) { |
| 2269 #if defined(USE_NSS) |
| 2270 if (!NSS_VersionCheck("3.16.2")) { |
| 2271 LOG(WARNING) << "Skipping test because lacks NSS support"; |
| 2272 return; |
| 2273 } |
| 2274 #endif |
| 2275 |
| 2276 scoped_ptr<base::ListValue> key_list; |
| 2277 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); |
| 2278 |
| 2279 // Import a 1024-bit private key. |
| 2280 base::DictionaryValue* key1_props; |
| 2281 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props)); |
| 2282 base::DictionaryValue* key1_jwk; |
| 2283 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk)); |
| 2284 |
| 2285 blink::WebCryptoKey key1 = blink::WebCryptoKey::createNull(); |
| 2286 ASSERT_EQ(Status::Success(), |
| 2287 ImportKeyJwkFromDict(*key1_jwk, |
| 2288 CreateRsaHashedImportAlgorithm( |
| 2289 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 2290 blink::WebCryptoAlgorithmIdSha256), |
| 2291 true, |
| 2292 blink::WebCryptoKeyUsageSign, |
| 2293 &key1)); |
| 2294 |
| 2295 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits()); |
| 2296 |
| 2297 // Construct a JWK using the modulus of key1, but all the other fields from |
| 2298 // another key (also a 1024-bit private key). |
| 2299 base::DictionaryValue* key2_props; |
| 2300 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props)); |
| 2301 base::DictionaryValue* key2_jwk; |
| 2302 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk)); |
| 2303 std::string modulus; |
| 2304 key1_jwk->GetString("n", &modulus); |
| 2305 key2_jwk->SetString("n", modulus); |
| 2306 |
| 2307 // This should fail, as the n,e,d parameters are not consistent. It MUST NOT |
| 2308 // somehow return the key created earlier. |
| 2309 blink::WebCryptoKey key2 = blink::WebCryptoKey::createNull(); |
| 2310 ASSERT_EQ(Status::OperationError(), |
| 2311 ImportKeyJwkFromDict(*key2_jwk, |
| 2312 CreateRsaHashedImportAlgorithm( |
| 2313 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 2314 blink::WebCryptoAlgorithmIdSha256), |
| 2315 true, |
| 2316 blink::WebCryptoKeyUsageSign, |
| 2317 &key2)); |
| 2318 } |
| 2319 |
2194 // Import a JWK RSA private key with some optional parameters missing (q, dp, | 2320 // Import a JWK RSA private key with some optional parameters missing (q, dp, |
2195 // dq, qi). | 2321 // dq, qi). |
2196 // | 2322 // |
2197 // The only optional parameter included is "p". | 2323 // The only optional parameter included is "p". |
2198 // | 2324 // |
2199 // This fails because JWA says that producers must include either ALL optional | 2325 // This fails because JWA says that producers must include either ALL optional |
2200 // parameters or NONE. | 2326 // parameters or NONE. |
2201 TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkMissingOptionalParams)) { | 2327 TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkMissingOptionalParams)) { |
2202 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 2328 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
2203 | 2329 |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2448 // This should fail since spki is for public keys. | 2574 // This should fail since spki is for public keys. |
2449 EXPECT_EQ( | 2575 EXPECT_EQ( |
2450 Status::Success(), | 2576 Status::Success(), |
2451 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key)); | 2577 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key)); |
2452 EXPECT_EQ(Status::ErrorUnexpectedKeyType(), | 2578 EXPECT_EQ(Status::ErrorUnexpectedKeyType(), |
2453 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output)); | 2579 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output)); |
2454 } | 2580 } |
2455 | 2581 |
2456 TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { | 2582 TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { |
2457 // Import a key pair. | 2583 // Import a key pair. |
2458 blink::WebCryptoAlgorithm importAlgorithm = | 2584 blink::WebCryptoAlgorithm import_algorithm = |
2459 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | 2585 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
2460 blink::WebCryptoAlgorithmIdSha1); | 2586 blink::WebCryptoAlgorithmIdSha1); |
2461 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 2587 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
2462 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 2588 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
2463 ASSERT_NO_FATAL_FAILURE( | 2589 ASSERT_NO_FATAL_FAILURE( |
2464 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), | 2590 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
2465 HexStringToBytes(kPrivateKeyPkcs8DerHex), | 2591 HexStringToBytes(kPrivateKeyPkcs8DerHex), |
2466 importAlgorithm, | 2592 import_algorithm, |
2467 false, | 2593 false, |
2468 blink::WebCryptoKeyUsageVerify, | 2594 blink::WebCryptoKeyUsageVerify, |
2469 blink::WebCryptoKeyUsageSign, | 2595 blink::WebCryptoKeyUsageSign, |
2470 &public_key, | 2596 &public_key, |
2471 &private_key)); | 2597 &private_key)); |
2472 | 2598 |
2473 blink::WebCryptoAlgorithm algorithm = | 2599 blink::WebCryptoAlgorithm algorithm = |
2474 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); | 2600 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); |
2475 | 2601 |
2476 std::vector<uint8> signature; | 2602 std::vector<uint8> signature; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2581 CryptoData(data), | 2707 CryptoData(data), |
2582 &is_match)); | 2708 &is_match)); |
2583 EXPECT_FALSE(is_match); | 2709 EXPECT_FALSE(is_match); |
2584 } | 2710 } |
2585 | 2711 |
2586 TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { | 2712 TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { |
2587 scoped_ptr<base::ListValue> tests; | 2713 scoped_ptr<base::ListValue> tests; |
2588 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests)); | 2714 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests)); |
2589 | 2715 |
2590 // Import the key pair. | 2716 // Import the key pair. |
2591 blink::WebCryptoAlgorithm importAlgorithm = | 2717 blink::WebCryptoAlgorithm import_algorithm = |
2592 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | 2718 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
2593 blink::WebCryptoAlgorithmIdSha1); | 2719 blink::WebCryptoAlgorithmIdSha1); |
2594 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 2720 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
2595 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 2721 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
2596 ASSERT_NO_FATAL_FAILURE( | 2722 ASSERT_NO_FATAL_FAILURE( |
2597 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), | 2723 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
2598 HexStringToBytes(kPrivateKeyPkcs8DerHex), | 2724 HexStringToBytes(kPrivateKeyPkcs8DerHex), |
2599 importAlgorithm, | 2725 import_algorithm, |
2600 false, | 2726 false, |
2601 blink::WebCryptoKeyUsageVerify, | 2727 blink::WebCryptoKeyUsageVerify, |
2602 blink::WebCryptoKeyUsageSign, | 2728 blink::WebCryptoKeyUsageSign, |
2603 &public_key, | 2729 &public_key, |
2604 &private_key)); | 2730 &private_key)); |
2605 | 2731 |
2606 blink::WebCryptoAlgorithm algorithm = | 2732 blink::WebCryptoAlgorithm algorithm = |
2607 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); | 2733 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); |
2608 | 2734 |
2609 // Validate the signatures are computed and verified as expected. | 2735 // Validate the signatures are computed and verified as expected. |
(...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4108 EXPECT_EQ(public_key_spki, unwrapped_public_key_spki); | 4234 EXPECT_EQ(public_key_spki, unwrapped_public_key_spki); |
4109 EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8); | 4235 EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8); |
4110 | 4236 |
4111 EXPECT_NE(public_key_spki, wrapped_public_key); | 4237 EXPECT_NE(public_key_spki, wrapped_public_key); |
4112 EXPECT_NE(private_key_pkcs8, wrapped_private_key); | 4238 EXPECT_NE(private_key_pkcs8, wrapped_private_key); |
4113 } | 4239 } |
4114 | 4240 |
4115 } // namespace webcrypto | 4241 } // namespace webcrypto |
4116 | 4242 |
4117 } // namespace content | 4243 } // namespace content |
OLD | NEW |