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 <stddef.h>
6 #include <stdint.h>
7 
8 #include "base/check_op.h"
9 #include "base/stl_util.h"
10 #include "base/values.h"
11 #include "components/webcrypto/algorithm_dispatch.h"
12 #include "components/webcrypto/algorithms/test_helpers.h"
13 #include "components/webcrypto/crypto_data.h"
14 #include "components/webcrypto/status.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
17 #include "third_party/blink/public/platform/web_crypto_key.h"
18 #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
19 
20 namespace webcrypto {
21 
22 namespace {
23 
24 // Helper for ImportJwkRsaFailures. Restores the JWK JSON
25 // dictionary to a good state
RestoreJwkRsaDictionary(base::DictionaryValue * dict)26 void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
27   dict->Clear();
28   dict->SetString("kty", "RSA");
29   dict->SetString("alg", "RS256");
30   dict->SetString("use", "sig");
31   dict->SetBoolean("ext", false);
32   dict->SetString(
33       "n",
34       "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
35       "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
36       "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
37   dict->SetString("e", "AQAB");
38 }
39 
40 class WebCryptoRsaSsaTest : public WebCryptoTestBase {};
41 
TEST_F(WebCryptoRsaSsaTest,ImportExportSpki)42 TEST_F(WebCryptoRsaSsaTest, ImportExportSpki) {
43   // Passing case: Import a valid RSA key in SPKI format.
44   blink::WebCryptoKey key;
45   ASSERT_EQ(Status::Success(),
46             ImportKey(blink::kWebCryptoKeyFormatSpki,
47                       CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
48                       CreateRsaHashedImportAlgorithm(
49                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
50                           blink::kWebCryptoAlgorithmIdSha256),
51                       true, blink::kWebCryptoKeyUsageVerify, &key));
52   EXPECT_TRUE(key.Handle());
53   EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
54   EXPECT_TRUE(key.Extractable());
55   EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
56   EXPECT_EQ(kModulusLengthBits,
57             key.Algorithm().RsaHashedParams()->ModulusLengthBits());
58   EXPECT_BYTES_EQ_HEX(
59       "010001",
60       CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
61 
62   // Failing case: Import RSA key but provide an inconsistent input algorithm.
63   EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
64             ImportKey(blink::kWebCryptoKeyFormatSpki,
65                       CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
66                       CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
67                       blink::kWebCryptoKeyUsageEncrypt, &key));
68 
69   // Passing case: Export a previously imported RSA public key in SPKI format
70   // and compare to original data.
71   std::vector<uint8_t> output;
72   ASSERT_EQ(Status::Success(),
73             ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
74   EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
75 
76   // Failing case: Try to export a previously imported RSA public key in raw
77   // format (not allowed for a public key).
78   EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
79             ExportKey(blink::kWebCryptoKeyFormatRaw, key, &output));
80 
81   // Failing case: Try to export a non-extractable key
82   ASSERT_EQ(Status::Success(),
83             ImportKey(blink::kWebCryptoKeyFormatSpki,
84                       CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
85                       CreateRsaHashedImportAlgorithm(
86                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
87                           blink::kWebCryptoAlgorithmIdSha256),
88                       false, blink::kWebCryptoKeyUsageVerify, &key));
89   EXPECT_TRUE(key.Handle());
90   EXPECT_FALSE(key.Extractable());
91   EXPECT_EQ(Status::ErrorKeyNotExtractable(),
92             ExportKey(blink::kWebCryptoKeyFormatSpki, key, &output));
93 
94   // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
95   // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
96   // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
97   // (e.g. SHA-1 in OID, SHA-256 in params)
98   // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
99   // as OAEP/PSS
100 }
101 
TEST_F(WebCryptoRsaSsaTest,ImportExportPkcs8)102 TEST_F(WebCryptoRsaSsaTest, ImportExportPkcs8) {
103   // Passing case: Import a valid RSA key in PKCS#8 format.
104   blink::WebCryptoKey key;
105   ASSERT_EQ(Status::Success(),
106             ImportKey(blink::kWebCryptoKeyFormatPkcs8,
107                       CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
108                       CreateRsaHashedImportAlgorithm(
109                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
110                           blink::kWebCryptoAlgorithmIdSha1),
111                       true, blink::kWebCryptoKeyUsageSign, &key));
112   EXPECT_TRUE(key.Handle());
113   EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, key.GetType());
114   EXPECT_TRUE(key.Extractable());
115   EXPECT_EQ(blink::kWebCryptoKeyUsageSign, key.Usages());
116   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
117             key.Algorithm().RsaHashedParams()->GetHash().Id());
118   EXPECT_EQ(kModulusLengthBits,
119             key.Algorithm().RsaHashedParams()->ModulusLengthBits());
120   EXPECT_BYTES_EQ_HEX(
121       "010001",
122       CryptoData(key.Algorithm().RsaHashedParams()->PublicExponent()));
123 
124   std::vector<uint8_t> exported_key;
125   ASSERT_EQ(Status::Success(),
126             ExportKey(blink::kWebCryptoKeyFormatPkcs8, key, &exported_key));
127   EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
128 
129   // Failing case: Import RSA key but provide an inconsistent input algorithm
130   // and usage. Several issues here:
131   //   * AES-CBC doesn't support PKCS8 key format
132   //   * AES-CBC doesn't support "sign" usage
133   EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
134             ImportKey(blink::kWebCryptoKeyFormatPkcs8,
135                       CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
136                       CreateAlgorithm(blink::kWebCryptoAlgorithmIdAesCbc), true,
137                       blink::kWebCryptoKeyUsageSign, &key));
138 }
139 
140 // Tests JWK import and export by doing a roundtrip key conversion and ensuring
141 // it was lossless:
142 //
143 //   PKCS8 --> JWK --> PKCS8
TEST_F(WebCryptoRsaSsaTest,ImportRsaPrivateKeyJwkToPkcs8RoundTrip)144 TEST_F(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
145   blink::WebCryptoKey key;
146   ASSERT_EQ(Status::Success(),
147             ImportKey(blink::kWebCryptoKeyFormatPkcs8,
148                       CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
149                       CreateRsaHashedImportAlgorithm(
150                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
151                           blink::kWebCryptoAlgorithmIdSha1),
152                       true, blink::kWebCryptoKeyUsageSign, &key));
153 
154   std::vector<uint8_t> exported_key_jwk;
155   ASSERT_EQ(Status::Success(),
156             ExportKey(blink::kWebCryptoKeyFormatJwk, key, &exported_key_jwk));
157 
158   // All of the optional parameters (p, q, dp, dq, qi) should be present in the
159   // output.
160   const char* expected_jwk =
161       "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
162       "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
163       "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
164       "\"KPoTk4ZVvh-"
165       "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
166       "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
167       "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
168       "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
169       "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
170       "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
171       "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
172       "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
173       "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
174       "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
175       "\"JxVqukEm0kqB86Uoy_sn9WiG-"
176       "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
177 
178   ASSERT_EQ(CryptoData(std::string(expected_jwk)),
179             CryptoData(exported_key_jwk));
180 
181   ASSERT_EQ(
182       Status::Success(),
183       ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
184                 CreateRsaHashedImportAlgorithm(
185                     blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
186                     blink::kWebCryptoAlgorithmIdSha1),
187                 true, blink::kWebCryptoKeyUsageSign, &key));
188 
189   std::vector<uint8_t> exported_key_pkcs8;
190   ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8, key,
191                                          &exported_key_pkcs8));
192 
193   ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
194             CryptoData(exported_key_pkcs8));
195 }
196 
197 // Tests importing multiple RSA private keys from JWK, and then exporting to
198 // PKCS8.
199 //
200 // This is a regression test for http://crbug.com/378315, for which importing
201 // a sequence of keys from JWK could yield the wrong key. The first key would
202 // be imported correctly, however every key after that would actually import
203 // the first key.
TEST_F(WebCryptoRsaSsaTest,ImportMultipleRSAPrivateKeysJwk)204 TEST_F(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
205   base::ListValue key_list;
206   ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
207 
208   // For this test to be meaningful the keys MUST be kept alive before importing
209   // new keys.
210   std::vector<blink::WebCryptoKey> live_keys;
211 
212   for (size_t key_index = 0; key_index < key_list.GetSize(); ++key_index) {
213     SCOPED_TRACE(key_index);
214 
215     base::DictionaryValue* key_values;
216     ASSERT_TRUE(key_list.GetDictionary(key_index, &key_values));
217 
218     // Get the JWK representation of the key.
219     base::DictionaryValue* key_jwk;
220     ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
221 
222     // Get the PKCS8 representation of the key.
223     std::string pkcs8_hex_string;
224     ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
225     std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
226 
227     // Get the modulus length for the key.
228     int modulus_length_bits = 0;
229     ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
230 
231     blink::WebCryptoKey private_key;
232 
233     // Import the key from JWK.
234     ASSERT_EQ(Status::Success(),
235               ImportKeyJwkFromDict(
236                   *key_jwk,
237                   CreateRsaHashedImportAlgorithm(
238                       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
239                       blink::kWebCryptoAlgorithmIdSha256),
240                   true, blink::kWebCryptoKeyUsageSign, &private_key));
241 
242     live_keys.push_back(private_key);
243 
244     EXPECT_EQ(
245         modulus_length_bits,
246         static_cast<int>(
247             private_key.Algorithm().RsaHashedParams()->ModulusLengthBits()));
248 
249     // Export to PKCS8 and verify that it matches expectation.
250     std::vector<uint8_t> exported_key_pkcs8;
251     ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
252                                            private_key, &exported_key_pkcs8));
253 
254     EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
255   }
256 }
257 
258 // Import an RSA private key using JWK. Next import a JWK containing the same
259 // modulus, but mismatched parameters for the rest. It should NOT be possible
260 // that the second import retrieves the first key. See http://crbug.com/378315
261 // for how that could happen.
TEST_F(WebCryptoRsaSsaTest,ImportJwkExistingModulusAndInvalid)262 TEST_F(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
263   base::ListValue key_list;
264   ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
265 
266   // Import a 1024-bit private key.
267   base::DictionaryValue* key1_props;
268   ASSERT_TRUE(key_list.GetDictionary(1, &key1_props));
269   base::DictionaryValue* key1_jwk;
270   ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
271 
272   blink::WebCryptoKey key1;
273   ASSERT_EQ(
274       Status::Success(),
275       ImportKeyJwkFromDict(*key1_jwk,
276                            CreateRsaHashedImportAlgorithm(
277                                blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
278                                blink::kWebCryptoAlgorithmIdSha256),
279                            true, blink::kWebCryptoKeyUsageSign, &key1));
280 
281   ASSERT_EQ(1024u, key1.Algorithm().RsaHashedParams()->ModulusLengthBits());
282 
283   // Construct a JWK using the modulus of key1, but all the other fields from
284   // another key (also a 1024-bit private key).
285   base::DictionaryValue* key2_props;
286   ASSERT_TRUE(key_list.GetDictionary(5, &key2_props));
287   base::DictionaryValue* key2_jwk;
288   ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
289   std::string modulus;
290   key1_jwk->GetString("n", &modulus);
291   key2_jwk->SetString("n", modulus);
292 
293   // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
294   // somehow return the key created earlier.
295   blink::WebCryptoKey key2;
296   ASSERT_EQ(
297       Status::OperationError(),
298       ImportKeyJwkFromDict(*key2_jwk,
299                            CreateRsaHashedImportAlgorithm(
300                                blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
301                                blink::kWebCryptoAlgorithmIdSha256),
302                            true, blink::kWebCryptoKeyUsageSign, &key2));
303 }
304 
TEST_F(WebCryptoRsaSsaTest,GenerateKeyPairRsa)305 TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
306   // Note: using unrealistic short key lengths here to avoid bogging down tests.
307 
308   // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
309   const unsigned int modulus_length = 256;
310   const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
311   blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
312       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
313       blink::kWebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
314   bool extractable = true;
315   const blink::WebCryptoKeyUsageMask public_usages =
316       blink::kWebCryptoKeyUsageVerify;
317   const blink::WebCryptoKeyUsageMask private_usages =
318       blink::kWebCryptoKeyUsageSign;
319   const blink::WebCryptoKeyUsageMask usages = public_usages | private_usages;
320   blink::WebCryptoKey public_key;
321   blink::WebCryptoKey private_key;
322 
323   EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
324                                                &public_key, &private_key));
325   ASSERT_FALSE(public_key.IsNull());
326   ASSERT_FALSE(private_key.IsNull());
327   EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
328   EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
329   EXPECT_EQ(modulus_length,
330             public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
331   EXPECT_EQ(modulus_length,
332             private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
333   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
334             public_key.Algorithm().RsaHashedParams()->GetHash().Id());
335   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
336             private_key.Algorithm().RsaHashedParams()->GetHash().Id());
337   EXPECT_TRUE(public_key.Extractable());
338   EXPECT_EQ(extractable, private_key.Extractable());
339   EXPECT_EQ(public_usages, public_key.Usages());
340   EXPECT_EQ(private_usages, private_key.Usages());
341 
342   // Try exporting the generated key pair, and then re-importing to verify that
343   // the exported data was valid.
344   std::vector<uint8_t> public_key_spki;
345   EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatSpki,
346                                          public_key, &public_key_spki));
347 
348   public_key = blink::WebCryptoKey::CreateNull();
349   ASSERT_EQ(
350       Status::Success(),
351       ImportKey(blink::kWebCryptoKeyFormatSpki, CryptoData(public_key_spki),
352                 CreateRsaHashedImportAlgorithm(
353                     blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
354                     blink::kWebCryptoAlgorithmIdSha256),
355                 true, public_usages, &public_key));
356   EXPECT_EQ(modulus_length,
357             public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
358 
359   std::vector<uint8_t> private_key_pkcs8;
360   EXPECT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatPkcs8,
361                                          private_key, &private_key_pkcs8));
362   private_key = blink::WebCryptoKey::CreateNull();
363   ASSERT_EQ(
364       Status::Success(),
365       ImportKey(blink::kWebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
366                 CreateRsaHashedImportAlgorithm(
367                     blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
368                     blink::kWebCryptoAlgorithmIdSha256),
369                 true, private_usages, &private_key));
370   EXPECT_EQ(modulus_length,
371             private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
372 
373   // Fail with bad modulus.
374   algorithm = CreateRsaHashedKeyGenAlgorithm(
375       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
376       blink::kWebCryptoAlgorithmIdSha256, 0, public_exponent);
377   EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
378             GenerateKeyPair(algorithm, extractable, usages, &public_key,
379                             &private_key));
380 
381   // Fail with bad exponent: larger than unsigned long.
382   unsigned int exponent_length = sizeof(unsigned long) + 1;  // NOLINT
383   const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
384   algorithm = CreateRsaHashedKeyGenAlgorithm(
385       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
386       blink::kWebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
387   EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
388             GenerateKeyPair(algorithm, extractable, usages, &public_key,
389                             &private_key));
390 
391   // Fail with bad exponent: empty.
392   const std::vector<uint8_t> empty_exponent;
393   algorithm = CreateRsaHashedKeyGenAlgorithm(
394       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
395       blink::kWebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
396   EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
397             GenerateKeyPair(algorithm, extractable, usages, &public_key,
398                             &private_key));
399 
400   // Fail with bad exponent: all zeros.
401   std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
402   algorithm = CreateRsaHashedKeyGenAlgorithm(
403       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
404       blink::kWebCryptoAlgorithmIdSha256, modulus_length,
405       exponent_with_leading_zeros);
406   EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
407             GenerateKeyPair(algorithm, extractable, usages, &public_key,
408                             &private_key));
409 
410   // Key generation success using exponent with leading zeros.
411   exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
412                                      public_exponent.begin(),
413                                      public_exponent.end());
414   algorithm = CreateRsaHashedKeyGenAlgorithm(
415       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
416       blink::kWebCryptoAlgorithmIdSha256, modulus_length,
417       exponent_with_leading_zeros);
418   EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
419                                                &public_key, &private_key));
420   EXPECT_FALSE(public_key.IsNull());
421   EXPECT_FALSE(private_key.IsNull());
422   EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
423   EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
424   EXPECT_TRUE(public_key.Extractable());
425   EXPECT_EQ(extractable, private_key.Extractable());
426   EXPECT_EQ(public_usages, public_key.Usages());
427   EXPECT_EQ(private_usages, private_key.Usages());
428 
429   // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
430   algorithm = CreateRsaHashedKeyGenAlgorithm(
431       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
432       blink::kWebCryptoAlgorithmIdSha1, modulus_length, public_exponent);
433   EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, false, usages,
434                                                &public_key, &private_key));
435   EXPECT_FALSE(public_key.IsNull());
436   EXPECT_FALSE(private_key.IsNull());
437   EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key.GetType());
438   EXPECT_EQ(blink::kWebCryptoKeyTypePrivate, private_key.GetType());
439   EXPECT_EQ(modulus_length,
440             public_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
441   EXPECT_EQ(modulus_length,
442             private_key.Algorithm().RsaHashedParams()->ModulusLengthBits());
443   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
444             public_key.Algorithm().RsaHashedParams()->GetHash().Id());
445   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
446             private_key.Algorithm().RsaHashedParams()->GetHash().Id());
447   // Even though "extractable" was set to false, the public key remains
448   // extractable.
449   EXPECT_TRUE(public_key.Extractable());
450   EXPECT_FALSE(private_key.Extractable());
451   EXPECT_EQ(public_usages, public_key.Usages());
452   EXPECT_EQ(private_usages, private_key.Usages());
453 
454   // Exporting a private key as SPKI format doesn't make sense. However this
455   // will first fail because the key is not extractable.
456   std::vector<uint8_t> output;
457   EXPECT_EQ(Status::ErrorKeyNotExtractable(),
458             ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
459 
460   // Re-generate an extractable private_key and try to export it as SPKI format.
461   // This should fail since spki is for public keys.
462   EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, true, usages,
463                                                &public_key, &private_key));
464   EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
465             ExportKey(blink::kWebCryptoKeyFormatSpki, private_key, &output));
466 }
467 
TEST_F(WebCryptoRsaSsaTest,GenerateKeyPairRsaBadModulusLength)468 TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
469   const unsigned int kBadModulusBits[] = {
470       0,
471       248,         // Too small.
472       257,         // Not a multiple of 8.
473       1023,        // Not a multiple of 8.
474       0xFFFFFFFF,  // Too big.
475       16384 + 8,   // 16384 is the maxmimum length that NSS succeeds for.
476   };
477 
478   const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
479 
480   for (size_t i = 0; i < base::size(kBadModulusBits); ++i) {
481     const unsigned int modulus_length_bits = kBadModulusBits[i];
482     blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
483         blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
484         blink::kWebCryptoAlgorithmIdSha256, modulus_length_bits,
485         public_exponent);
486     bool extractable = true;
487     const blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
488     blink::WebCryptoKey public_key;
489     blink::WebCryptoKey private_key;
490 
491     EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
492               GenerateKeyPair(algorithm, extractable, usages, &public_key,
493                               &private_key));
494   }
495 }
496 
497 // Try generating RSA key pairs using unsupported public exponents. Only
498 // exponents of 3 and 65537 are supported. Although OpenSSL can support other
499 // values, it can also hang when given invalid exponents. To avoid hanging, use
500 // a whitelist of known safe exponents.
TEST_F(WebCryptoRsaSsaTest,GenerateKeyPairRsaBadExponent)501 TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
502   const unsigned int modulus_length = 1024;
503 
504   const char* const kPublicExponents[] = {
505       "11",  // 17 - This is a valid public exponent, but currently disallowed.
506       "00",
507       "01",
508       "02",
509       "010000",  // 65536
510   };
511 
512   for (size_t i = 0; i < base::size(kPublicExponents); ++i) {
513     SCOPED_TRACE(i);
514     blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
515         blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
516         blink::kWebCryptoAlgorithmIdSha256, modulus_length,
517         HexStringToBytes(kPublicExponents[i]));
518 
519     blink::WebCryptoKey public_key;
520     blink::WebCryptoKey private_key;
521 
522     EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
523               GenerateKeyPair(algorithm, true, blink::kWebCryptoKeyUsageSign,
524                               &public_key, &private_key));
525   }
526 }
527 
TEST_F(WebCryptoRsaSsaTest,SignVerifyFailures)528 TEST_F(WebCryptoRsaSsaTest, SignVerifyFailures) {
529   // Import a key pair.
530   blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
531       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
532       blink::kWebCryptoAlgorithmIdSha1);
533   blink::WebCryptoKey public_key;
534   blink::WebCryptoKey private_key;
535   ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
536       HexStringToBytes(kPublicKeySpkiDerHex),
537       HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
538       blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
539       &public_key, &private_key));
540 
541   blink::WebCryptoAlgorithm algorithm =
542       CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
543 
544   std::vector<uint8_t> signature;
545   bool signature_match;
546 
547   // Compute a signature.
548   const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
549   ASSERT_EQ(Status::Success(),
550             Sign(algorithm, private_key, CryptoData(data), &signature));
551 
552   // Ensure truncated signature does not verify by passing one less byte.
553   EXPECT_EQ(Status::Success(),
554             Verify(algorithm, public_key,
555                    CryptoData(signature.data(),
556                               static_cast<unsigned int>(signature.size()) - 1),
557                    CryptoData(data), &signature_match));
558   EXPECT_FALSE(signature_match);
559 
560   // Ensure truncated signature does not verify by passing no bytes.
561   EXPECT_EQ(Status::Success(), Verify(algorithm, public_key, CryptoData(),
562                                       CryptoData(data), &signature_match));
563   EXPECT_FALSE(signature_match);
564 
565   // Ensure corrupted signature does not verify.
566   std::vector<uint8_t> corrupt_sig = signature;
567   corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
568   EXPECT_EQ(Status::Success(),
569             Verify(algorithm, public_key, CryptoData(corrupt_sig),
570                    CryptoData(data), &signature_match));
571   EXPECT_FALSE(signature_match);
572 
573   // Ensure signatures that are greater than the modulus size fail.
574   const unsigned int long_message_size_bytes = 1024;
575   DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
576   const unsigned char kLongSignature[long_message_size_bytes] = {0};
577   EXPECT_EQ(Status::Success(),
578             Verify(algorithm, public_key,
579                    CryptoData(kLongSignature, sizeof(kLongSignature)),
580                    CryptoData(data), &signature_match));
581   EXPECT_FALSE(signature_match);
582 
583   // Ensure that signing and verifying with an incompatible algorithm fails.
584   algorithm = CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaOaep);
585 
586   EXPECT_EQ(Status::ErrorUnexpected(),
587             Sign(algorithm, private_key, CryptoData(data), &signature));
588   EXPECT_EQ(Status::ErrorUnexpected(),
589             Verify(algorithm, public_key, CryptoData(signature),
590                    CryptoData(data), &signature_match));
591 
592   // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
593   // based solely on the contents of the input signature data. In the Web Crypto
594   // implementation, the inner hash should be specified uniquely by the key
595   // algorithm parameter. To validate this behavior, call Verify with a computed
596   // signature that used one hash type (SHA-1), but pass in a key with a
597   // different inner hash type (SHA-256). If the hash type is determined by the
598   // signature itself (undesired), the verify will pass, while if the hash type
599   // is specified by the key algorithm (desired), the verify will fail.
600 
601   // Compute a signature using SHA-1 as the inner hash.
602   EXPECT_EQ(Status::Success(),
603             Sign(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
604                  private_key, CryptoData(data), &signature));
605 
606   blink::WebCryptoKey public_key_256;
607   EXPECT_EQ(Status::Success(),
608             ImportKey(blink::kWebCryptoKeyFormatSpki,
609                       CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
610                       CreateRsaHashedImportAlgorithm(
611                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
612                           blink::kWebCryptoAlgorithmIdSha256),
613                       true, blink::kWebCryptoKeyUsageVerify, &public_key_256));
614 
615   // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
616   // signature should not verify.
617   // NOTE: public_key was produced by generateKey, and so its associated
618   // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
619   // it has no inner hash to conflict with the input algorithm.
620   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha1,
621             private_key.Algorithm().RsaHashedParams()->GetHash().Id());
622   EXPECT_EQ(blink::kWebCryptoAlgorithmIdSha256,
623             public_key_256.Algorithm().RsaHashedParams()->GetHash().Id());
624 
625   bool is_match;
626   EXPECT_EQ(Status::Success(),
627             Verify(CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
628                    public_key_256, CryptoData(signature), CryptoData(data),
629                    &is_match));
630   EXPECT_FALSE(is_match);
631 }
632 
TEST_F(WebCryptoRsaSsaTest,SignVerifyKnownAnswer)633 TEST_F(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
634   base::ListValue tests;
635   ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
636 
637   // Import the key pair.
638   blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
639       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
640       blink::kWebCryptoAlgorithmIdSha1);
641   blink::WebCryptoKey public_key;
642   blink::WebCryptoKey private_key;
643   ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
644       HexStringToBytes(kPublicKeySpkiDerHex),
645       HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
646       blink::kWebCryptoKeyUsageVerify, blink::kWebCryptoKeyUsageSign,
647       &public_key, &private_key));
648 
649   blink::WebCryptoAlgorithm algorithm =
650       CreateAlgorithm(blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
651 
652   // Validate the signatures are computed and verified as expected.
653   std::vector<uint8_t> signature;
654   for (size_t test_index = 0; test_index < tests.GetSize(); ++test_index) {
655     SCOPED_TRACE(test_index);
656 
657     base::DictionaryValue* test;
658     ASSERT_TRUE(tests.GetDictionary(test_index, &test));
659 
660     std::vector<uint8_t> test_message =
661         GetBytesFromHexString(test, "message_hex");
662     std::vector<uint8_t> test_signature =
663         GetBytesFromHexString(test, "signature_hex");
664 
665     signature.clear();
666     ASSERT_EQ(Status::Success(), Sign(algorithm, private_key,
667                                       CryptoData(test_message), &signature));
668     EXPECT_BYTES_EQ(test_signature, signature);
669 
670     bool is_match = false;
671     ASSERT_EQ(Status::Success(),
672               Verify(algorithm, public_key, CryptoData(test_signature),
673                      CryptoData(test_message), &is_match));
674     EXPECT_TRUE(is_match);
675   }
676 }
677 
678 // Try importing an RSA-SSA public key with unsupported key usages using SPKI
679 // format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest,ImportRsaSsaPublicKeyBadUsage_SPKI)680 TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
681   const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
682       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
683       blink::kWebCryptoAlgorithmIdSha256);
684 
685   blink::WebCryptoKeyUsageMask bad_usages[] = {
686       blink::kWebCryptoKeyUsageSign,
687       blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
688       blink::kWebCryptoKeyUsageEncrypt,
689       blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
690   };
691 
692   for (size_t i = 0; i < base::size(bad_usages); ++i) {
693     SCOPED_TRACE(i);
694 
695     blink::WebCryptoKey public_key;
696     ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
697               ImportKey(blink::kWebCryptoKeyFormatSpki,
698                         CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
699                         algorithm, false, bad_usages[i], &public_key));
700   }
701 }
702 
703 // Try importing an RSA-SSA public key with unsupported key usages using JWK
704 // format. RSA-SSA public keys only support the 'verify' usage.
TEST_F(WebCryptoRsaSsaTest,ImportRsaSsaPublicKeyBadUsage_JWK)705 TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
706   const blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
707       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
708       blink::kWebCryptoAlgorithmIdSha256);
709 
710   blink::WebCryptoKeyUsageMask bad_usages[] = {
711       blink::kWebCryptoKeyUsageSign,
712       blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
713       blink::kWebCryptoKeyUsageEncrypt,
714       blink::kWebCryptoKeyUsageEncrypt | blink::kWebCryptoKeyUsageDecrypt,
715   };
716 
717   base::DictionaryValue dict;
718   RestoreJwkRsaDictionary(&dict);
719   dict.Remove("use", nullptr);
720   dict.SetString("alg", "RS256");
721 
722   for (size_t i = 0; i < base::size(bad_usages); ++i) {
723     SCOPED_TRACE(i);
724 
725     blink::WebCryptoKey public_key;
726     ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
727               ImportKeyJwkFromDict(dict, algorithm, false, bad_usages[i],
728                                    &public_key));
729   }
730 }
731 
732 // Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
733 //   'sign', 'verify'
TEST_F(WebCryptoRsaSsaTest,GenerateKeyBadUsages)734 TEST_F(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
735   blink::WebCryptoKeyUsageMask bad_usages[] = {
736       blink::kWebCryptoKeyUsageDecrypt,
737       blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageDecrypt,
738       blink::kWebCryptoKeyUsageWrapKey,
739   };
740 
741   const unsigned int modulus_length = 256;
742   const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
743 
744   for (size_t i = 0; i < base::size(bad_usages); ++i) {
745     SCOPED_TRACE(i);
746 
747     blink::WebCryptoKey public_key;
748     blink::WebCryptoKey private_key;
749 
750     ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
751               GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
752                                   blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
753                                   blink::kWebCryptoAlgorithmIdSha256,
754                                   modulus_length, public_exponent),
755                               true, bad_usages[i], &public_key, &private_key));
756   }
757 }
758 
759 // Generate an RSA-SSA key pair. The public and private keys should select the
760 // key usages which are applicable, and not have the exact same usages as was
761 // specified to GenerateKey
TEST_F(WebCryptoRsaSsaTest,GenerateKeyPairIntersectUsages)762 TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
763   const unsigned int modulus_length = 256;
764   const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
765 
766   blink::WebCryptoKey public_key;
767   blink::WebCryptoKey private_key;
768 
769   ASSERT_EQ(
770       Status::Success(),
771       GenerateKeyPair(
772           CreateRsaHashedKeyGenAlgorithm(
773               blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
774               blink::kWebCryptoAlgorithmIdSha256, modulus_length,
775               public_exponent),
776           true, blink::kWebCryptoKeyUsageSign | blink::kWebCryptoKeyUsageVerify,
777           &public_key, &private_key));
778 
779   EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, public_key.Usages());
780   EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
781 
782   // Try again but this time without the Verify usages.
783   ASSERT_EQ(Status::Success(),
784             GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
785                                 blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
786                                 blink::kWebCryptoAlgorithmIdSha256,
787                                 modulus_length, public_exponent),
788                             true, blink::kWebCryptoKeyUsageSign, &public_key,
789                             &private_key));
790 
791   EXPECT_EQ(0, public_key.Usages());
792   EXPECT_EQ(blink::kWebCryptoKeyUsageSign, private_key.Usages());
793 }
794 
TEST_F(WebCryptoRsaSsaTest,GenerateKeyPairEmptyUsages)795 TEST_F(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
796   const unsigned int modulus_length = 256;
797   const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
798 
799   blink::WebCryptoKey public_key;
800   blink::WebCryptoKey private_key;
801 
802   ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
803             GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
804                                 blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
805                                 blink::kWebCryptoAlgorithmIdSha256,
806                                 modulus_length, public_exponent),
807                             true, 0, &public_key, &private_key));
808 }
809 
TEST_F(WebCryptoRsaSsaTest,ImportKeyEmptyUsages)810 TEST_F(WebCryptoRsaSsaTest, ImportKeyEmptyUsages) {
811   blink::WebCryptoKey public_key;
812   blink::WebCryptoKey private_key;
813 
814   // Public without usage does not throw an error.
815   ASSERT_EQ(Status::Success(),
816             ImportKey(blink::kWebCryptoKeyFormatSpki,
817                       CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
818                       CreateRsaHashedImportAlgorithm(
819                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
820                           blink::kWebCryptoAlgorithmIdSha256),
821                       true, 0, &public_key));
822   EXPECT_EQ(0, public_key.Usages());
823 
824   // Private empty usage will throw an error.
825   ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
826             ImportKey(blink::kWebCryptoKeyFormatPkcs8,
827                       CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
828                       CreateRsaHashedImportAlgorithm(
829                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
830                           blink::kWebCryptoAlgorithmIdSha1),
831                       true, 0, &private_key));
832 
833   std::vector<uint8_t> public_jwk;
834   ASSERT_EQ(Status::Success(),
835             ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &public_jwk));
836 
837   ASSERT_EQ(Status::Success(),
838             ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(public_jwk),
839                       CreateRsaHashedImportAlgorithm(
840                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
841                           blink::kWebCryptoAlgorithmIdSha256),
842                       true, 0, &public_key));
843   EXPECT_EQ(0, public_key.Usages());
844 
845   // With correct usage to get correct imported private_key
846   std::vector<uint8_t> private_jwk;
847   ImportKey(blink::kWebCryptoKeyFormatPkcs8,
848             CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
849             CreateRsaHashedImportAlgorithm(
850                 blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
851                 blink::kWebCryptoAlgorithmIdSha1),
852             true, blink::kWebCryptoKeyUsageSign, &private_key);
853 
854   ASSERT_EQ(Status::Success(), ExportKey(blink::kWebCryptoKeyFormatJwk,
855                                          private_key, &private_jwk));
856 
857   ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
858             ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(private_jwk),
859                       CreateRsaHashedImportAlgorithm(
860                           blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
861                           blink::kWebCryptoAlgorithmIdSha1),
862                       true, 0, &private_key));
863 }
864 
TEST_F(WebCryptoRsaSsaTest,ImportExportJwkRsaPublicKey)865 TEST_F(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
866   struct TestCase {
867     const blink::WebCryptoAlgorithmId hash;
868     const blink::WebCryptoKeyUsageMask usage;
869     const char* const jwk_alg;
870   };
871   const TestCase kTests[] = {{blink::kWebCryptoAlgorithmIdSha1,
872                               blink::kWebCryptoKeyUsageVerify, "RS1"},
873                              {blink::kWebCryptoAlgorithmIdSha256,
874                               blink::kWebCryptoKeyUsageVerify, "RS256"},
875                              {blink::kWebCryptoAlgorithmIdSha384,
876                               blink::kWebCryptoKeyUsageVerify, "RS384"},
877                              {blink::kWebCryptoAlgorithmIdSha512,
878                               blink::kWebCryptoKeyUsageVerify, "RS512"}};
879 
880   for (size_t test_index = 0; test_index < base::size(kTests); ++test_index) {
881     SCOPED_TRACE(test_index);
882     const TestCase& test = kTests[test_index];
883 
884     const blink::WebCryptoAlgorithm import_algorithm =
885         CreateRsaHashedImportAlgorithm(
886             blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
887 
888     // Import the spki to create a public key
889     blink::WebCryptoKey public_key;
890     ASSERT_EQ(Status::Success(),
891               ImportKey(blink::kWebCryptoKeyFormatSpki,
892                         CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
893                         import_algorithm, true, test.usage, &public_key));
894 
895     // Export the public key as JWK and verify its contents
896     std::vector<uint8_t> jwk;
897     ASSERT_EQ(Status::Success(),
898               ExportKey(blink::kWebCryptoKeyFormatJwk, public_key, &jwk));
899     EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
900                                 kPublicKeyExponentHex, test.usage));
901 
902     // Import the JWK back in to create a new key
903     blink::WebCryptoKey public_key2;
904     ASSERT_EQ(Status::Success(),
905               ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(jwk),
906                         import_algorithm, true, test.usage, &public_key2));
907     ASSERT_TRUE(public_key2.Handle());
908     EXPECT_EQ(blink::kWebCryptoKeyTypePublic, public_key2.GetType());
909     EXPECT_TRUE(public_key2.Extractable());
910     EXPECT_EQ(import_algorithm.Id(), public_key2.Algorithm().Id());
911 
912     // Export the new key as spki and compare to the original.
913     std::vector<uint8_t> spki;
914     ASSERT_EQ(Status::Success(),
915               ExportKey(blink::kWebCryptoKeyFormatSpki, public_key2, &spki));
916     EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
917   }
918 }
919 
TEST_F(WebCryptoRsaSsaTest,ImportJwkRsaFailures)920 TEST_F(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
921   base::DictionaryValue dict;
922   RestoreJwkRsaDictionary(&dict);
923   blink::WebCryptoAlgorithm algorithm = CreateRsaHashedImportAlgorithm(
924       blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
925       blink::kWebCryptoAlgorithmIdSha256);
926   blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify;
927   blink::WebCryptoKey key;
928 
929   // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
930   // entry, while an RSA private key must have those plus at least a "d"
931   // (private exponent) entry.
932   // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
933   // section 6.3.
934 
935   // Baseline pass.
936   EXPECT_EQ(Status::Success(),
937             ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
938   EXPECT_EQ(algorithm.Id(), key.Algorithm().Id());
939   EXPECT_FALSE(key.Extractable());
940   EXPECT_EQ(blink::kWebCryptoKeyUsageVerify, key.Usages());
941   EXPECT_EQ(blink::kWebCryptoKeyTypePublic, key.GetType());
942 
943   // The following are specific failure cases for when kty = "RSA".
944 
945   // Fail if either "n" or "e" is not present or malformed.
946   const std::string kKtyParmName[] = {"n", "e"};
947   for (size_t idx = 0; idx < base::size(kKtyParmName); ++idx) {
948     // Fail on missing parameter.
949     dict.Remove(kKtyParmName[idx], nullptr);
950     EXPECT_NE(Status::Success(),
951               ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
952     RestoreJwkRsaDictionary(&dict);
953 
954     // Fail on bad b64 parameter encoding.
955     dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
956     EXPECT_NE(Status::Success(),
957               ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
958     RestoreJwkRsaDictionary(&dict);
959 
960     // Fail on empty parameter.
961     dict.SetString(kKtyParmName[idx], "");
962     EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
963               ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
964     RestoreJwkRsaDictionary(&dict);
965   }
966 }
967 
968 // Try importing an RSA-SSA key from JWK format, having specified both Sign and
969 // Verify usage, AND an invalid JWK.
970 //
971 // Parsing the invalid JWK will fail before the usage check is done.
TEST_F(WebCryptoRsaSsaTest,ImportRsaSsaJwkBadUsageAndData)972 TEST_F(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageAndData) {
973   std::string bad_data = "hello";
974 
975   blink::WebCryptoKey key;
976   ASSERT_EQ(
977       Status::ErrorJwkNotDictionary(),
978       ImportKey(blink::kWebCryptoKeyFormatJwk, CryptoData(bad_data),
979                 CreateRsaHashedImportAlgorithm(
980                     blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
981                     blink::kWebCryptoAlgorithmIdSha256),
982                 true,
983                 blink::kWebCryptoKeyUsageVerify | blink::kWebCryptoKeyUsageSign,
984                 &key));
985 }
986 
987 // Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
TEST_F(WebCryptoRsaSsaTest,ImportInvalidKeyData)988 TEST_F(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
989   base::ListValue tests;
990   ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
991 
992   for (size_t test_index = 0; test_index < tests.GetSize(); ++test_index) {
993     SCOPED_TRACE(test_index);
994 
995     const base::DictionaryValue* test;
996     ASSERT_TRUE(tests.GetDictionary(test_index, &test));
997 
998     blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
999     std::vector<uint8_t> key_data =
1000         GetKeyDataFromJsonTestCase(test, key_format);
1001     std::string test_error;
1002     ASSERT_TRUE(test->GetString("error", &test_error));
1003 
1004     blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageSign;
1005     if (key_format == blink::kWebCryptoKeyFormatSpki)
1006       usages = blink::kWebCryptoKeyUsageVerify;
1007     blink::WebCryptoKey key;
1008     Status status = ImportKey(key_format, CryptoData(key_data),
1009                               CreateRsaHashedImportAlgorithm(
1010                                   blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1011                                   blink::kWebCryptoAlgorithmIdSha256),
1012                               true, usages, &key);
1013     EXPECT_EQ(test_error, StatusToString(status));
1014   }
1015 }
1016 
1017 }  // namespace
1018 
1019 }  // namespace webcrypto
1020