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(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 |
| 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 |