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