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