Chromium Code Reviews| 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 1280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2145 | 2150 |
| 2146 std::vector<uint8> exported_key_pkcs8; | 2151 std::vector<uint8> exported_key_pkcs8; |
| 2147 ASSERT_EQ( | 2152 ASSERT_EQ( |
| 2148 Status::Success(), | 2153 Status::Success(), |
| 2149 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8)); | 2154 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8)); |
| 2150 | 2155 |
| 2151 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | 2156 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), |
| 2152 CryptoData(exported_key_pkcs8)); | 2157 CryptoData(exported_key_pkcs8)); |
| 2153 } | 2158 } |
| 2154 | 2159 |
| 2160 // Tests importing multiple RSA private keys from JWK, and then exporting to | |
| 2161 // PKCS8. | |
| 2162 // | |
| 2163 // This is a regression test for http://crbug.com/378315, for which importing | |
| 2164 // a sequence of keys from JWK could yield the wrong key. The first key would | |
| 2165 // be imported correctly, however every key after that would actually import | |
| 2166 // the first key. | |
| 2167 TEST_F(SharedCryptoTest, MAYBE(ImportMultipleRSAPrivateKeysJwk)) { | |
| 2168 scoped_ptr<base::ListValue> key_list; | |
| 2169 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); | |
| 2170 | |
| 2171 // For this test to be meaningful the keys MUST be kept alive before importing | |
| 2172 // new keys. | |
| 2173 std::vector<blink::WebCryptoKey> live_keys; | |
| 2174 | |
| 2175 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) { | |
| 2176 SCOPED_TRACE(key_index); | |
| 2177 | |
| 2178 base::DictionaryValue* key_values; | |
| 2179 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values)); | |
| 2180 | |
| 2181 // Get the JWK representation of the key. | |
| 2182 base::DictionaryValue* key_jwk; | |
| 2183 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk)); | |
| 2184 | |
| 2185 // Get the PKCS8 representation of the key. | |
| 2186 std::string pkcs8_hex_string; | |
| 2187 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string)); | |
| 2188 std::vector<uint8> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string); | |
| 2189 | |
| 2190 // Get the modulus length for the key. | |
| 2191 int modulus_length_bits = 0; | |
| 2192 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits)); | |
| 2193 | |
| 2194 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | |
| 2195 | |
| 2196 // Import the key from JWK. | |
| 2197 ASSERT_EQ( | |
| 2198 Status::Success(), | |
| 2199 ImportKeyJwkFromDict(*key_jwk, | |
| 2200 CreateRsaHashedImportAlgorithm( | |
| 2201 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
| 2202 blink::WebCryptoAlgorithmIdSha256), | |
| 2203 true, | |
| 2204 blink::WebCryptoKeyUsageSign, | |
| 2205 &private_key)); | |
| 2206 | |
| 2207 live_keys.push_back(private_key); | |
| 2208 | |
| 2209 EXPECT_EQ( | |
| 2210 modulus_length_bits, | |
| 2211 static_cast<int>( | |
| 2212 private_key.algorithm().rsaHashedParams()->modulusLengthBits())); | |
| 2213 | |
| 2214 // Export to PKCS8 and verify that it matches expectation. | |
| 2215 std::vector<uint8> exported_key_pkcs8; | |
| 2216 ASSERT_EQ( | |
| 2217 Status::Success(), | |
| 2218 ExportKey( | |
| 2219 blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8)); | |
| 2220 | |
| 2221 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8); | |
| 2222 } | |
| 2223 } | |
| 2224 | |
| 2225 // Import an RSA private key using JWK. Next import a JWK containing the same | |
| 2226 // modulus, but mismatched parameters for the rest. It should NOT be possible | |
| 2227 // that the second import retrieves the first key. See http://crbug.com/378315 | |
| 2228 // for how that could happen. | |
| 2229 TEST_F(SharedCryptoTest, MAYBE(DISABLED_ImportJwkExistingModulusAndInvalid)) { | |
| 2230 scoped_ptr<base::ListValue> key_list; | |
| 2231 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list)); | |
| 2232 | |
| 2233 // Import a 1024-bit private key. | |
| 2234 base::DictionaryValue* key1_props; | |
| 2235 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props)); | |
| 2236 base::DictionaryValue* key1_jwk; | |
| 2237 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk)); | |
| 2238 | |
| 2239 blink::WebCryptoKey key1 = blink::WebCryptoKey::createNull(); | |
| 2240 ASSERT_EQ(Status::Success(), | |
| 2241 ImportKeyJwkFromDict(*key1_jwk, | |
| 2242 CreateRsaHashedImportAlgorithm( | |
| 2243 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
| 2244 blink::WebCryptoAlgorithmIdSha256), | |
| 2245 true, | |
| 2246 blink::WebCryptoKeyUsageSign, | |
| 2247 &key1)); | |
| 2248 | |
| 2249 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits()); | |
| 2250 | |
| 2251 // Construct a JWK using the modulus of key1, but all the other fields from | |
| 2252 // another key (also a 1024-bit private key). | |
| 2253 base::DictionaryValue* key2_props; | |
| 2254 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props)); | |
| 2255 base::DictionaryValue* key2_jwk; | |
| 2256 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk)); | |
| 2257 std::string modulus; | |
| 2258 key1_jwk->GetString("n", &modulus); | |
| 2259 key2_jwk->SetString("n", modulus); | |
| 2260 | |
| 2261 // If NSS did validations of the input, this would fail. Failing would be the | |
|
Ryan Sleevi
2014/06/05 23:21:25
I'm not a fan of this test, even DISABLED_, since
eroman
2014/06/05 23:43:35
Once the NSS side rolls in, presumably I can chang
| |
| 2262 // right thing to do. Barring that ensure at least the key isn't bogus. | |
| 2263 blink::WebCryptoKey key2 = blink::WebCryptoKey::createNull(); | |
| 2264 ASSERT_EQ(Status::Success(), | |
| 2265 ImportKeyJwkFromDict(*key2_jwk, | |
| 2266 CreateRsaHashedImportAlgorithm( | |
| 2267 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
| 2268 blink::WebCryptoAlgorithmIdSha256), | |
| 2269 true, | |
| 2270 blink::WebCryptoKeyUsageSign, | |
| 2271 &key2)); | |
| 2272 ASSERT_EQ(1024u, key2.algorithm().rsaHashedParams()->modulusLengthBits()); | |
| 2273 | |
| 2274 // Export to PKCS8 to make sure key1 != key2. | |
| 2275 std::vector<uint8> exported_key1; | |
| 2276 std::vector<uint8> exported_key2; | |
| 2277 ASSERT_EQ(Status::Success(), | |
| 2278 ExportKey(blink::WebCryptoKeyFormatPkcs8, key1, &exported_key1)); | |
| 2279 ASSERT_EQ(Status::Success(), | |
| 2280 ExportKey(blink::WebCryptoKeyFormatPkcs8, key2, &exported_key2)); | |
| 2281 | |
| 2282 EXPECT_NE(CryptoData(exported_key1), CryptoData(exported_key2)); | |
| 2283 } | |
| 2284 | |
| 2155 // Import a JWK RSA private key with some optional parameters missing (q, dp, | 2285 // Import a JWK RSA private key with some optional parameters missing (q, dp, |
| 2156 // dq, qi). | 2286 // dq, qi). |
| 2157 // | 2287 // |
| 2158 // The only optional parameter included is "p". | 2288 // The only optional parameter included is "p". |
| 2159 // | 2289 // |
| 2160 // This fails because JWA says that producers must include either ALL optional | 2290 // This fails because JWA says that producers must include either ALL optional |
| 2161 // parameters or NONE. | 2291 // parameters or NONE. |
| 2162 TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkMissingOptionalParams)) { | 2292 TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkMissingOptionalParams)) { |
| 2163 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 2293 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 2164 | 2294 |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2409 // This should fail since spki is for public keys. | 2539 // This should fail since spki is for public keys. |
| 2410 EXPECT_EQ( | 2540 EXPECT_EQ( |
| 2411 Status::Success(), | 2541 Status::Success(), |
| 2412 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key)); | 2542 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key)); |
| 2413 EXPECT_EQ(Status::ErrorUnexpectedKeyType(), | 2543 EXPECT_EQ(Status::ErrorUnexpectedKeyType(), |
| 2414 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output)); | 2544 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output)); |
| 2415 } | 2545 } |
| 2416 | 2546 |
| 2417 TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { | 2547 TEST_F(SharedCryptoTest, MAYBE(RsaSsaSignVerifyFailures)) { |
| 2418 // Import a key pair. | 2548 // Import a key pair. |
| 2419 blink::WebCryptoAlgorithm importAlgorithm = | 2549 blink::WebCryptoAlgorithm import_algorithm = |
| 2420 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | 2550 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 2421 blink::WebCryptoAlgorithmIdSha1); | 2551 blink::WebCryptoAlgorithmIdSha1); |
| 2422 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 2552 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| 2423 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 2553 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
| 2424 ASSERT_NO_FATAL_FAILURE( | 2554 ASSERT_NO_FATAL_FAILURE( |
| 2425 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), | 2555 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
| 2426 HexStringToBytes(kPrivateKeyPkcs8DerHex), | 2556 HexStringToBytes(kPrivateKeyPkcs8DerHex), |
| 2427 importAlgorithm, | 2557 import_algorithm, |
| 2428 false, | 2558 false, |
| 2429 blink::WebCryptoKeyUsageVerify, | 2559 blink::WebCryptoKeyUsageVerify, |
| 2430 blink::WebCryptoKeyUsageSign, | 2560 blink::WebCryptoKeyUsageSign, |
| 2431 &public_key, | 2561 &public_key, |
| 2432 &private_key)); | 2562 &private_key)); |
| 2433 | 2563 |
| 2434 blink::WebCryptoAlgorithm algorithm = | 2564 blink::WebCryptoAlgorithm algorithm = |
| 2435 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); | 2565 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); |
| 2436 | 2566 |
| 2437 std::vector<uint8> signature; | 2567 std::vector<uint8> signature; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2542 CryptoData(data), | 2672 CryptoData(data), |
| 2543 &is_match)); | 2673 &is_match)); |
| 2544 EXPECT_FALSE(is_match); | 2674 EXPECT_FALSE(is_match); |
| 2545 } | 2675 } |
| 2546 | 2676 |
| 2547 TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { | 2677 TEST_F(SharedCryptoTest, MAYBE(RsaSignVerifyKnownAnswer)) { |
| 2548 scoped_ptr<base::ListValue> tests; | 2678 scoped_ptr<base::ListValue> tests; |
| 2549 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests)); | 2679 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests)); |
| 2550 | 2680 |
| 2551 // Import the key pair. | 2681 // Import the key pair. |
| 2552 blink::WebCryptoAlgorithm importAlgorithm = | 2682 blink::WebCryptoAlgorithm import_algorithm = |
| 2553 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | 2683 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, |
| 2554 blink::WebCryptoAlgorithmIdSha1); | 2684 blink::WebCryptoAlgorithmIdSha1); |
| 2555 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); | 2685 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); |
| 2556 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); | 2686 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); |
| 2557 ASSERT_NO_FATAL_FAILURE( | 2687 ASSERT_NO_FATAL_FAILURE( |
| 2558 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), | 2688 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex), |
| 2559 HexStringToBytes(kPrivateKeyPkcs8DerHex), | 2689 HexStringToBytes(kPrivateKeyPkcs8DerHex), |
| 2560 importAlgorithm, | 2690 import_algorithm, |
| 2561 false, | 2691 false, |
| 2562 blink::WebCryptoKeyUsageVerify, | 2692 blink::WebCryptoKeyUsageVerify, |
| 2563 blink::WebCryptoKeyUsageSign, | 2693 blink::WebCryptoKeyUsageSign, |
| 2564 &public_key, | 2694 &public_key, |
| 2565 &private_key)); | 2695 &private_key)); |
| 2566 | 2696 |
| 2567 blink::WebCryptoAlgorithm algorithm = | 2697 blink::WebCryptoAlgorithm algorithm = |
| 2568 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); | 2698 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5); |
| 2569 | 2699 |
| 2570 // Validate the signatures are computed and verified as expected. | 2700 // Validate the signatures are computed and verified as expected. |
| (...skipping 1498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4069 EXPECT_EQ(public_key_spki, unwrapped_public_key_spki); | 4199 EXPECT_EQ(public_key_spki, unwrapped_public_key_spki); |
| 4070 EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8); | 4200 EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8); |
| 4071 | 4201 |
| 4072 EXPECT_NE(public_key_spki, wrapped_public_key); | 4202 EXPECT_NE(public_key_spki, wrapped_public_key); |
| 4073 EXPECT_NE(private_key_pkcs8, wrapped_private_key); | 4203 EXPECT_NE(private_key_pkcs8, wrapped_private_key); |
| 4074 } | 4204 } |
| 4075 | 4205 |
| 4076 } // namespace webcrypto | 4206 } // namespace webcrypto |
| 4077 | 4207 |
| 4078 } // namespace content | 4208 } // namespace content |
| OLD | NEW |