OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/logging.h" | |
6 #include "base/stl_util.h" | |
7 #include "content/child/webcrypto/algorithm_dispatch.h" | |
8 #include "content/child/webcrypto/crypto_data.h" | |
9 #include "content/child/webcrypto/jwk.h" | |
10 #include "content/child/webcrypto/status.h" | |
11 #include "content/child/webcrypto/test/test_helpers.h" | |
12 #include "content/child/webcrypto/webcrypto_util.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
16 | |
17 namespace content { | |
18 | |
19 namespace webcrypto { | |
20 | |
21 namespace { | |
22 | |
23 // Creates an RSA-OAEP algorithm | |
24 blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm( | |
25 const std::vector<uint8_t>& label) { | |
26 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
27 blink::WebCryptoAlgorithmIdRsaOaep, | |
28 new blink::WebCryptoRsaOaepParams(!label.empty(), vector_as_array(&label), | |
29 label.size())); | |
30 } | |
31 | |
32 scoped_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() { | |
33 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); | |
34 jwk->SetString("kty", "RSA"); | |
35 jwk->SetString("n", | |
36 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex))); | |
37 jwk->SetString("e", | |
38 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex))); | |
39 return jwk.Pass(); | |
40 } | |
41 | |
42 // Import a PKCS#8 private key that uses RSAPrivateKey with the | |
43 // id-rsaEncryption OID. | |
44 TEST(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) { | |
45 if (!SupportsRsaOaep()) { | |
46 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
47 return; | |
48 } | |
49 | |
50 blink::WebCryptoKey private_key; | |
51 ASSERT_EQ(Status::Success(), | |
52 ImportKey(blink::WebCryptoKeyFormatPkcs8, | |
53 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | |
54 CreateRsaHashedImportAlgorithm( | |
55 blink::WebCryptoAlgorithmIdRsaOaep, | |
56 blink::WebCryptoAlgorithmIdSha1), | |
57 true, blink::WebCryptoKeyUsageDecrypt, &private_key)); | |
58 } | |
59 | |
60 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) { | |
61 if (!SupportsRsaOaep()) { | |
62 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
63 return; | |
64 } | |
65 | |
66 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
67 | |
68 blink::WebCryptoKey public_key; | |
69 ASSERT_EQ( | |
70 Status::Success(), | |
71 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
72 blink::WebCryptoAlgorithmIdRsaOaep, | |
73 blink::WebCryptoAlgorithmIdSha1), | |
74 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
75 } | |
76 | |
77 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) { | |
78 if (!SupportsRsaOaep()) { | |
79 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
80 return; | |
81 } | |
82 | |
83 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
84 jwk->SetString("alg", "RSA-OAEP"); | |
85 | |
86 blink::WebCryptoKey public_key; | |
87 ASSERT_EQ( | |
88 Status::Success(), | |
89 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
90 blink::WebCryptoAlgorithmIdRsaOaep, | |
91 blink::WebCryptoAlgorithmIdSha1), | |
92 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
93 } | |
94 | |
95 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) { | |
96 if (!SupportsRsaOaep()) { | |
97 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
98 return; | |
99 } | |
100 | |
101 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
102 jwk->SetString("alg", "RSA-OAEP-512"); | |
103 | |
104 blink::WebCryptoKey public_key; | |
105 ASSERT_EQ( | |
106 Status::ErrorJwkAlgorithmInconsistent(), | |
107 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
108 blink::WebCryptoAlgorithmIdRsaOaep, | |
109 blink::WebCryptoAlgorithmIdSha1), | |
110 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
111 } | |
112 | |
113 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) { | |
114 if (!SupportsRsaOaep()) { | |
115 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
116 return; | |
117 } | |
118 | |
119 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
120 jwk->SetString("kty", "oct"); | |
121 jwk->SetString("alg", "RSA-OAEP"); | |
122 | |
123 blink::WebCryptoKey public_key; | |
124 ASSERT_EQ( | |
125 Status::ErrorJwkUnexpectedKty("RSA"), | |
126 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
127 blink::WebCryptoAlgorithmIdRsaOaep, | |
128 blink::WebCryptoAlgorithmIdSha1), | |
129 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
130 } | |
131 | |
132 TEST(WebCryptoRsaOaepTest, ExportPublicJwk) { | |
133 if (!SupportsRsaOaep()) { | |
134 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
135 return; | |
136 } | |
137 | |
138 struct TestData { | |
139 blink::WebCryptoAlgorithmId hash_alg; | |
140 const char* expected_jwk_alg; | |
141 } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"}, | |
142 {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"}, | |
143 {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"}, | |
144 {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}}; | |
145 for (size_t i = 0; i < arraysize(kTestData); ++i) { | |
146 const TestData& test_data = kTestData[i]; | |
147 SCOPED_TRACE(test_data.expected_jwk_alg); | |
148 | |
149 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
150 jwk->SetString("alg", test_data.expected_jwk_alg); | |
151 | |
152 // Import the key in a known-good format | |
153 blink::WebCryptoKey public_key; | |
154 ASSERT_EQ(Status::Success(), | |
155 ImportKeyJwkFromDict( | |
156 *jwk.get(), | |
157 CreateRsaHashedImportAlgorithm( | |
158 blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg), | |
159 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
160 | |
161 // Now export the key as JWK and verify its contents | |
162 std::vector<uint8_t> jwk_data; | |
163 ASSERT_EQ(Status::Success(), | |
164 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data)); | |
165 EXPECT_TRUE(VerifyPublicJwk(jwk_data, test_data.expected_jwk_alg, | |
166 kPublicKeyModulusHex, kPublicKeyExponentHex, | |
167 blink::WebCryptoKeyUsageEncrypt)); | |
168 } | |
169 } | |
170 | |
171 TEST(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) { | |
172 if (!SupportsRsaOaep()) { | |
173 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
174 return; | |
175 } | |
176 | |
177 scoped_ptr<base::ListValue> tests; | |
178 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests)); | |
179 | |
180 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) { | |
181 SCOPED_TRACE(test_index); | |
182 | |
183 base::DictionaryValue* test = NULL; | |
184 ASSERT_TRUE(tests->GetDictionary(test_index, &test)); | |
185 | |
186 blink::WebCryptoAlgorithm digest_algorithm = | |
187 GetDigestAlgorithm(test, "hash"); | |
188 ASSERT_FALSE(digest_algorithm.isNull()); | |
189 std::vector<uint8_t> public_key_der = | |
190 GetBytesFromHexString(test, "public_key"); | |
191 std::vector<uint8_t> private_key_der = | |
192 GetBytesFromHexString(test, "private_key"); | |
193 std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext"); | |
194 std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext"); | |
195 std::vector<uint8_t> label = GetBytesFromHexString(test, "label"); | |
196 | |
197 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
198 blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id()); | |
199 blink::WebCryptoKey public_key; | |
200 blink::WebCryptoKey private_key; | |
201 | |
202 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
203 public_key_der, private_key_der, import_algorithm, false, | |
204 blink::WebCryptoKeyUsageEncrypt, blink::WebCryptoKeyUsageDecrypt, | |
205 &public_key, &private_key)); | |
206 | |
207 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
208 std::vector<uint8_t> decrypted_data; | |
209 ASSERT_EQ(Status::Success(), | |
210 Decrypt(op_algorithm, private_key, CryptoData(ciphertext), | |
211 &decrypted_data)); | |
212 EXPECT_BYTES_EQ(plaintext, decrypted_data); | |
213 std::vector<uint8_t> encrypted_data; | |
214 ASSERT_EQ(Status::Success(), | |
215 Encrypt(op_algorithm, public_key, CryptoData(plaintext), | |
216 &encrypted_data)); | |
217 std::vector<uint8_t> redecrypted_data; | |
218 ASSERT_EQ(Status::Success(), | |
219 Decrypt(op_algorithm, private_key, CryptoData(encrypted_data), | |
220 &redecrypted_data)); | |
221 EXPECT_BYTES_EQ(plaintext, redecrypted_data); | |
222 } | |
223 } | |
224 | |
225 TEST(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) { | |
226 if (!SupportsRsaOaep()) { | |
227 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
228 return; | |
229 } | |
230 | |
231 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1; | |
232 const size_t kHashSize = 20; | |
233 | |
234 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
235 | |
236 blink::WebCryptoKey public_key; | |
237 ASSERT_EQ(Status::Success(), | |
238 ImportKeyJwkFromDict( | |
239 *jwk.get(), CreateRsaHashedImportAlgorithm( | |
240 blink::WebCryptoAlgorithmIdRsaOaep, kHash), | |
241 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
242 | |
243 // The maximum size of an encrypted message is: | |
244 // modulus length | |
245 // - 1 (leading octet) | |
246 // - hash size (maskedSeed) | |
247 // - hash size (lHash portion of maskedDB) | |
248 // - 1 (at least one octet for the padding string) | |
249 size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize); | |
250 | |
251 // The label has no influence on the maximum message size. For simplicity, | |
252 // use the empty string. | |
253 std::vector<uint8_t> label; | |
254 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
255 | |
256 // Test that a message just before the boundary succeeds. | |
257 std::string large_message; | |
258 large_message.resize(kMaxMessageSize - 1, 'A'); | |
259 | |
260 std::vector<uint8_t> ciphertext; | |
261 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key, | |
262 CryptoData(large_message), &ciphertext)); | |
263 | |
264 // Test that a message at the boundary succeeds. | |
265 large_message.resize(kMaxMessageSize, 'A'); | |
266 ciphertext.clear(); | |
267 | |
268 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key, | |
269 CryptoData(large_message), &ciphertext)); | |
270 | |
271 // Test that a message greater than the largest size fails. | |
272 large_message.resize(kMaxMessageSize + 1, 'A'); | |
273 ciphertext.clear(); | |
274 | |
275 ASSERT_EQ(Status::OperationError(), | |
276 Encrypt(op_algorithm, public_key, CryptoData(large_message), | |
277 &ciphertext)); | |
278 } | |
279 | |
280 // Ensures that if the selected hash algorithm for the RSA-OAEP message is too | |
281 // large, then it is rejected, independent of the actual message to be | |
282 // encrypted. | |
283 // For example, a 1024-bit RSA key is too small to accomodate a message that | |
284 // uses OAEP with SHA-512, since it requires 1040 bits to encode | |
285 // (2 * hash size + 2 padding bytes). | |
286 TEST(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) { | |
287 if (!SupportsRsaOaep()) { | |
288 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
289 return; | |
290 } | |
291 | |
292 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512; | |
293 | |
294 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
295 | |
296 blink::WebCryptoKey public_key; | |
297 ASSERT_EQ(Status::Success(), | |
298 ImportKeyJwkFromDict( | |
299 *jwk.get(), CreateRsaHashedImportAlgorithm( | |
300 blink::WebCryptoAlgorithmIdRsaOaep, kHash), | |
301 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
302 | |
303 // The label has no influence on the maximum message size. For simplicity, | |
304 // use the empty string. | |
305 std::vector<uint8_t> label; | |
306 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
307 | |
308 std::string small_message("A"); | |
309 std::vector<uint8_t> ciphertext; | |
310 // This is an operation error, as the internal consistency checking of the | |
311 // algorithm parameters is up to the implementation. | |
312 ASSERT_EQ(Status::OperationError(), | |
313 Encrypt(op_algorithm, public_key, CryptoData(small_message), | |
314 &ciphertext)); | |
315 } | |
316 | |
317 TEST(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) { | |
318 if (!SupportsRsaOaep()) { | |
319 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
320 return; | |
321 } | |
322 | |
323 blink::WebCryptoKey private_key; | |
324 ASSERT_EQ(Status::Success(), | |
325 ImportKey(blink::WebCryptoKeyFormatPkcs8, | |
326 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | |
327 CreateRsaHashedImportAlgorithm( | |
328 blink::WebCryptoAlgorithmIdRsaOaep, | |
329 blink::WebCryptoAlgorithmIdSha1), | |
330 true, blink::WebCryptoKeyUsageDecrypt, &private_key)); | |
331 | |
332 // The label has no influence on the maximum message size. For simplicity, | |
333 // use the empty string. | |
334 std::vector<uint8_t> label; | |
335 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
336 | |
337 std::string large_dummy_message(kModulusLengthBits / 8, 'A'); | |
338 std::vector<uint8_t> plaintext; | |
339 | |
340 ASSERT_EQ(Status::OperationError(), | |
341 Decrypt(op_algorithm, private_key, CryptoData(large_dummy_message), | |
342 &plaintext)); | |
343 } | |
344 | |
345 TEST(WebCryptoRsaOaepTest, WrapUnwrapRawKey) { | |
346 if (!SupportsRsaOaep()) { | |
347 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
348 return; | |
349 } | |
350 | |
351 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
352 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); | |
353 blink::WebCryptoKey public_key; | |
354 blink::WebCryptoKey private_key; | |
355 | |
356 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
357 HexStringToBytes(kPublicKeySpkiDerHex), | |
358 HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false, | |
359 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, | |
360 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, | |
361 &public_key, &private_key)); | |
362 | |
363 std::vector<uint8_t> label; | |
364 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); | |
365 | |
366 const std::string key_hex = "000102030405060708090A0B0C0D0E0F"; | |
367 const blink::WebCryptoAlgorithm key_algorithm = | |
368 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); | |
369 | |
370 blink::WebCryptoKey key = | |
371 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm, | |
372 blink::WebCryptoKeyUsageEncrypt); | |
373 ASSERT_FALSE(key.isNull()); | |
374 | |
375 std::vector<uint8_t> wrapped_key; | |
376 ASSERT_EQ(Status::Success(), | |
377 WrapKey(blink::WebCryptoKeyFormatRaw, key, public_key, | |
378 wrapping_algorithm, &wrapped_key)); | |
379 | |
380 // Verify that |wrapped_key| can be decrypted and yields the key data. | |
381 // Because |private_key| supports both decrypt and unwrap, this is valid. | |
382 std::vector<uint8_t> decrypted_key; | |
383 ASSERT_EQ(Status::Success(), | |
384 Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key), | |
385 &decrypted_key)); | |
386 EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key); | |
387 | |
388 // Now attempt to unwrap the key, which should also decrypt the data. | |
389 blink::WebCryptoKey unwrapped_key; | |
390 ASSERT_EQ(Status::Success(), | |
391 UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key), | |
392 private_key, wrapping_algorithm, key_algorithm, true, | |
393 blink::WebCryptoKeyUsageEncrypt, &unwrapped_key)); | |
394 ASSERT_FALSE(unwrapped_key.isNull()); | |
395 | |
396 std::vector<uint8_t> raw_key; | |
397 ASSERT_EQ(Status::Success(), | |
398 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); | |
399 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); | |
400 } | |
401 | |
402 TEST(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) { | |
403 if (!SupportsRsaOaep()) { | |
404 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
405 return; | |
406 } | |
407 | |
408 // The public and private portions of a 2048-bit RSA key with the | |
409 // id-rsaEncryption OID | |
410 const char kPublicKey2048SpkiDerHex[] = | |
411 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce" | |
412 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764" | |
413 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68" | |
414 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f" | |
415 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08" | |
416 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606" | |
417 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca" | |
418 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d" | |
419 "5d0203010001"; | |
420 const char kPrivateKey2048Pkcs8DerHex[] = | |
421 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201" | |
422 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30" | |
423 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448" | |
424 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872" | |
425 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34" | |
426 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936" | |
427 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7" | |
428 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b" | |
429 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3" | |
430 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c" | |
431 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42" | |
432 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4" | |
433 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62" | |
434 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a" | |
435 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339" | |
436 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c" | |
437 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3" | |
438 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a" | |
439 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c" | |
440 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133" | |
441 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622" | |
442 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277" | |
443 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5" | |
444 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945" | |
445 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b" | |
446 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb" | |
447 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af" | |
448 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562" | |
449 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792" | |
450 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab" | |
451 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0" | |
452 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca" | |
453 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0" | |
454 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b"; | |
455 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
456 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); | |
457 blink::WebCryptoKey public_key; | |
458 blink::WebCryptoKey private_key; | |
459 | |
460 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
461 HexStringToBytes(kPublicKey2048SpkiDerHex), | |
462 HexStringToBytes(kPrivateKey2048Pkcs8DerHex), import_algorithm, false, | |
463 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, | |
464 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, | |
465 &public_key, &private_key)); | |
466 | |
467 std::vector<uint8_t> label; | |
468 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); | |
469 | |
470 const std::string key_hex = "000102030405060708090a0b0c0d0e0f"; | |
471 const blink::WebCryptoAlgorithm key_algorithm = | |
472 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); | |
473 | |
474 blink::WebCryptoKey key = | |
475 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm, | |
476 blink::WebCryptoKeyUsageEncrypt); | |
477 ASSERT_FALSE(key.isNull()); | |
478 | |
479 std::vector<uint8_t> wrapped_key; | |
480 ASSERT_EQ(Status::Success(), | |
481 WrapKey(blink::WebCryptoKeyFormatJwk, key, public_key, | |
482 wrapping_algorithm, &wrapped_key)); | |
483 | |
484 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object. | |
485 // Because |private_key| supports both decrypt and unwrap, this is valid. | |
486 std::vector<uint8_t> decrypted_jwk; | |
487 ASSERT_EQ(Status::Success(), | |
488 Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key), | |
489 &decrypted_jwk)); | |
490 EXPECT_TRUE(VerifySecretJwk(decrypted_jwk, "A128CBC", key_hex, | |
491 blink::WebCryptoKeyUsageEncrypt)); | |
492 | |
493 // Now attempt to unwrap the key, which should also decrypt the data. | |
494 blink::WebCryptoKey unwrapped_key; | |
495 ASSERT_EQ(Status::Success(), | |
496 UnwrapKey(blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key), | |
497 private_key, wrapping_algorithm, key_algorithm, true, | |
498 blink::WebCryptoKeyUsageEncrypt, &unwrapped_key)); | |
499 ASSERT_FALSE(unwrapped_key.isNull()); | |
500 | |
501 std::vector<uint8_t> raw_key; | |
502 ASSERT_EQ(Status::Success(), | |
503 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); | |
504 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); | |
505 } | |
506 | |
507 TEST(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) { | |
508 if (!SupportsRsaOaep()) { | |
509 LOG(WARNING) << "RSA-OAEP support not present; skipping."; | |
510 return; | |
511 } | |
512 | |
513 struct TestCase { | |
514 const blink::WebCryptoAlgorithmId hash; | |
515 const blink::WebCryptoKeyUsageMask usage; | |
516 const char* const jwk_alg; | |
517 }; | |
518 const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1, | |
519 blink::WebCryptoKeyUsageEncrypt, | |
520 "RSA-OAEP"}, | |
521 {blink::WebCryptoAlgorithmIdSha256, | |
522 blink::WebCryptoKeyUsageEncrypt, | |
523 "RSA-OAEP-256"}, | |
524 {blink::WebCryptoAlgorithmIdSha384, | |
525 blink::WebCryptoKeyUsageEncrypt, | |
526 "RSA-OAEP-384"}, | |
527 {blink::WebCryptoAlgorithmIdSha512, | |
528 blink::WebCryptoKeyUsageEncrypt, | |
529 "RSA-OAEP-512"}}; | |
530 | |
531 for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) { | |
532 SCOPED_TRACE(test_index); | |
533 const TestCase& test = kTests[test_index]; | |
534 | |
535 const blink::WebCryptoAlgorithm import_algorithm = | |
536 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep, | |
537 test.hash); | |
538 | |
539 // Import the spki to create a public key | |
540 blink::WebCryptoKey public_key; | |
541 ASSERT_EQ(Status::Success(), | |
542 ImportKey(blink::WebCryptoKeyFormatSpki, | |
543 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)), | |
544 import_algorithm, true, test.usage, &public_key)); | |
545 | |
546 // Export the public key as JWK and verify its contents | |
547 std::vector<uint8_t> jwk; | |
548 ASSERT_EQ(Status::Success(), | |
549 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk)); | |
550 EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex, | |
551 kPublicKeyExponentHex, test.usage)); | |
552 | |
553 // Import the JWK back in to create a new key | |
554 blink::WebCryptoKey public_key2; | |
555 ASSERT_EQ(Status::Success(), | |
556 ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk), | |
557 import_algorithm, true, test.usage, &public_key2)); | |
558 ASSERT_TRUE(public_key2.handle()); | |
559 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type()); | |
560 EXPECT_TRUE(public_key2.extractable()); | |
561 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id()); | |
562 | |
563 // TODO(eroman): Export the SPKI and verify matches. | |
564 } | |
565 } | |
566 | |
567 } // namespace | |
568 | |
569 } // namespace webcrypto | |
570 | |
571 } // namespace content | |
OLD | NEW |