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.
5 #include "base/logging.h"
6 #include "base/stl_util.h"
7 #include "content/child/webcrypto/algorithm_dispatch.h"
8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/status.h"
10 #include "content/child/webcrypto/test/test_helpers.h"
11 #include "content/child/webcrypto/webcrypto_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
23 // Helper for ImportJwkRsaFailures. Restores the JWK JSON
24 // dictionary to a good state
25 void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
27 dict->SetString("kty", "RSA");
28 dict->SetString("alg", "RS256");
29 dict->SetString("use", "sig");
30 dict->SetBoolean("ext", false);
33 "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
34 "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
35 "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
36 dict->SetString("e", "AQAB");
39 TEST(WebCryptoRsaSsaTest, ImportExportSpki) {
40 // Passing case: Import a valid RSA key in SPKI format.
41 blink::WebCryptoKey key;
42 ASSERT_EQ(Status::Success(),
43 ImportKey(blink::WebCryptoKeyFormatSpki,
44 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
45 CreateRsaHashedImportAlgorithm(
46 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
47 blink::WebCryptoAlgorithmIdSha256),
49 blink::WebCryptoKeyUsageVerify,
51 EXPECT_TRUE(key.handle());
52 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
53 EXPECT_TRUE(key.extractable());
54 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
55 EXPECT_EQ(kModulusLengthBits,
56 key.algorithm().rsaHashedParams()->modulusLengthBits());
59 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
61 // Failing case: Import RSA key but provide an inconsistent input algorithm.
62 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
63 ImportKey(blink::WebCryptoKeyFormatSpki,
64 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
65 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
67 blink::WebCryptoKeyUsageEncrypt,
70 // Passing case: Export a previously imported RSA public key in SPKI format
71 // and compare to original data.
72 std::vector<uint8_t> output;
73 ASSERT_EQ(Status::Success(),
74 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
75 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
77 // Failing case: Try to export a previously imported RSA public key in raw
78 // format (not allowed for a public key).
79 EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
80 ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
82 // Failing case: Try to export a non-extractable key
83 ASSERT_EQ(Status::Success(),
84 ImportKey(blink::WebCryptoKeyFormatSpki,
85 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
86 CreateRsaHashedImportAlgorithm(
87 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
88 blink::WebCryptoAlgorithmIdSha256),
90 blink::WebCryptoKeyUsageVerify,
92 EXPECT_TRUE(key.handle());
93 EXPECT_FALSE(key.extractable());
94 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
95 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
97 // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
98 // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
99 // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
100 // (e.g. SHA-1 in OID, SHA-256 in params)
101 // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
105 TEST(WebCryptoRsaSsaTest, ImportExportPkcs8) {
106 if (!SupportsRsaPrivateKeyImport())
109 // Passing case: Import a valid RSA key in PKCS#8 format.
110 blink::WebCryptoKey key;
111 ASSERT_EQ(Status::Success(),
112 ImportKey(blink::WebCryptoKeyFormatPkcs8,
113 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
114 CreateRsaHashedImportAlgorithm(
115 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
116 blink::WebCryptoAlgorithmIdSha1),
118 blink::WebCryptoKeyUsageSign,
120 EXPECT_TRUE(key.handle());
121 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
122 EXPECT_TRUE(key.extractable());
123 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
124 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
125 key.algorithm().rsaHashedParams()->hash().id());
126 EXPECT_EQ(kModulusLengthBits,
127 key.algorithm().rsaHashedParams()->modulusLengthBits());
130 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
132 std::vector<uint8_t> exported_key;
133 ASSERT_EQ(Status::Success(),
134 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
135 EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
137 // Failing case: Import RSA key but provide an inconsistent input algorithm
138 // and usage. Several issues here:
139 // * AES-CBC doesn't support PKCS8 key format
140 // * AES-CBC doesn't support "sign" usage
141 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
142 ImportKey(blink::WebCryptoKeyFormatPkcs8,
143 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
144 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
146 blink::WebCryptoKeyUsageSign,
150 // Tests JWK import and export by doing a roundtrip key conversion and ensuring
153 // PKCS8 --> JWK --> PKCS8
154 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
155 if (!SupportsRsaPrivateKeyImport())
158 blink::WebCryptoKey key;
159 ASSERT_EQ(Status::Success(),
160 ImportKey(blink::WebCryptoKeyFormatPkcs8,
161 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
162 CreateRsaHashedImportAlgorithm(
163 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
164 blink::WebCryptoAlgorithmIdSha1),
166 blink::WebCryptoKeyUsageSign,
169 std::vector<uint8_t> exported_key_jwk;
170 ASSERT_EQ(Status::Success(),
171 ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
173 // All of the optional parameters (p, q, dp, dq, qi) should be present in the
175 const char* expected_jwk =
176 "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
177 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
178 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
180 "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
181 "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
182 "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
183 "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
184 "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
185 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
186 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
187 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
188 "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
189 "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
190 "\"JxVqukEm0kqB86Uoy_sn9WiG-"
191 "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
193 ASSERT_EQ(CryptoData(std::string(expected_jwk)),
194 CryptoData(exported_key_jwk));
196 ASSERT_EQ(Status::Success(),
197 ImportKey(blink::WebCryptoKeyFormatJwk,
198 CryptoData(exported_key_jwk),
199 CreateRsaHashedImportAlgorithm(
200 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
201 blink::WebCryptoAlgorithmIdSha1),
203 blink::WebCryptoKeyUsageSign,
206 std::vector<uint8_t> exported_key_pkcs8;
209 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8));
211 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
212 CryptoData(exported_key_pkcs8));
215 // Tests importing multiple RSA private keys from JWK, and then exporting to
218 // This is a regression test for http://crbug.com/378315, for which importing
219 // a sequence of keys from JWK could yield the wrong key. The first key would
220 // be imported correctly, however every key after that would actually import
222 TEST(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
223 if (!SupportsRsaPrivateKeyImport())
226 scoped_ptr<base::ListValue> key_list;
227 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
229 // For this test to be meaningful the keys MUST be kept alive before importing
231 std::vector<blink::WebCryptoKey> live_keys;
233 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
234 SCOPED_TRACE(key_index);
236 base::DictionaryValue* key_values;
237 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
239 // Get the JWK representation of the key.
240 base::DictionaryValue* key_jwk;
241 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
243 // Get the PKCS8 representation of the key.
244 std::string pkcs8_hex_string;
245 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
246 std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
248 // Get the modulus length for the key.
249 int modulus_length_bits = 0;
250 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
252 blink::WebCryptoKey private_key;
254 // Import the key from JWK.
257 ImportKeyJwkFromDict(*key_jwk,
258 CreateRsaHashedImportAlgorithm(
259 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
260 blink::WebCryptoAlgorithmIdSha256),
262 blink::WebCryptoKeyUsageSign,
265 live_keys.push_back(private_key);
270 private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
272 // Export to PKCS8 and verify that it matches expectation.
273 std::vector<uint8_t> exported_key_pkcs8;
277 blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8));
279 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
283 // Import an RSA private key using JWK. Next import a JWK containing the same
284 // modulus, but mismatched parameters for the rest. It should NOT be possible
285 // that the second import retrieves the first key. See http://crbug.com/378315
286 // for how that could happen.
287 TEST(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
288 if (!SupportsRsaPrivateKeyImport())
291 scoped_ptr<base::ListValue> key_list;
292 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
294 // Import a 1024-bit private key.
295 base::DictionaryValue* key1_props;
296 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
297 base::DictionaryValue* key1_jwk;
298 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
300 blink::WebCryptoKey key1;
301 ASSERT_EQ(Status::Success(),
302 ImportKeyJwkFromDict(*key1_jwk,
303 CreateRsaHashedImportAlgorithm(
304 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
305 blink::WebCryptoAlgorithmIdSha256),
307 blink::WebCryptoKeyUsageSign,
310 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
312 // Construct a JWK using the modulus of key1, but all the other fields from
313 // another key (also a 1024-bit private key).
314 base::DictionaryValue* key2_props;
315 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
316 base::DictionaryValue* key2_jwk;
317 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
319 key1_jwk->GetString("n", &modulus);
320 key2_jwk->SetString("n", modulus);
322 // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
323 // somehow return the key created earlier.
324 blink::WebCryptoKey key2;
325 ASSERT_EQ(Status::OperationError(),
326 ImportKeyJwkFromDict(*key2_jwk,
327 CreateRsaHashedImportAlgorithm(
328 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
329 blink::WebCryptoAlgorithmIdSha256),
331 blink::WebCryptoKeyUsageSign,
335 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
336 // Note: using unrealistic short key lengths here to avoid bogging down tests.
338 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
339 const unsigned int modulus_length = 256;
340 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
341 blink::WebCryptoAlgorithm algorithm =
342 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
343 blink::WebCryptoAlgorithmIdSha256,
346 bool extractable = true;
347 const blink::WebCryptoKeyUsageMask usages = 0;
348 blink::WebCryptoKey public_key;
349 blink::WebCryptoKey private_key;
351 EXPECT_EQ(Status::Success(),
353 algorithm, extractable, usages, &public_key, &private_key));
354 EXPECT_FALSE(public_key.isNull());
355 EXPECT_FALSE(private_key.isNull());
356 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
357 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
358 EXPECT_EQ(modulus_length,
359 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
360 EXPECT_EQ(modulus_length,
361 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
362 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
363 public_key.algorithm().rsaHashedParams()->hash().id());
364 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
365 private_key.algorithm().rsaHashedParams()->hash().id());
366 EXPECT_TRUE(public_key.extractable());
367 EXPECT_EQ(extractable, private_key.extractable());
368 EXPECT_EQ(usages, public_key.usages());
369 EXPECT_EQ(usages, private_key.usages());
371 // Try exporting the generated key pair, and then re-importing to verify that
372 // the exported data was valid.
373 std::vector<uint8_t> public_key_spki;
376 ExportKey(blink::WebCryptoKeyFormatSpki, public_key, &public_key_spki));
378 if (SupportsRsaPrivateKeyImport()) {
379 public_key = blink::WebCryptoKey::createNull();
380 EXPECT_EQ(Status::Success(),
381 ImportKey(blink::WebCryptoKeyFormatSpki,
382 CryptoData(public_key_spki),
383 CreateRsaHashedImportAlgorithm(
384 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
385 blink::WebCryptoAlgorithmIdSha256),
389 EXPECT_EQ(modulus_length,
390 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
392 std::vector<uint8_t> private_key_pkcs8;
396 blink::WebCryptoKeyFormatPkcs8, private_key, &private_key_pkcs8));
397 private_key = blink::WebCryptoKey::createNull();
398 EXPECT_EQ(Status::Success(),
399 ImportKey(blink::WebCryptoKeyFormatPkcs8,
400 CryptoData(private_key_pkcs8),
401 CreateRsaHashedImportAlgorithm(
402 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
403 blink::WebCryptoAlgorithmIdSha256),
407 EXPECT_EQ(modulus_length,
408 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
411 // Fail with bad modulus.
413 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
414 blink::WebCryptoAlgorithmIdSha256,
417 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
419 algorithm, extractable, usages, &public_key, &private_key));
421 // Fail with bad exponent: larger than unsigned long.
422 unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
423 const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
425 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
426 blink::WebCryptoAlgorithmIdSha256,
429 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
431 algorithm, extractable, usages, &public_key, &private_key));
433 // Fail with bad exponent: empty.
434 const std::vector<uint8_t> empty_exponent;
436 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
437 blink::WebCryptoAlgorithmIdSha256,
440 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
442 algorithm, extractable, usages, &public_key, &private_key));
444 // Fail with bad exponent: all zeros.
445 std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
447 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
448 blink::WebCryptoAlgorithmIdSha256,
450 exponent_with_leading_zeros);
451 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
453 algorithm, extractable, usages, &public_key, &private_key));
455 // Key generation success using exponent with leading zeros.
456 exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
457 public_exponent.begin(),
458 public_exponent.end());
460 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
461 blink::WebCryptoAlgorithmIdSha256,
463 exponent_with_leading_zeros);
464 EXPECT_EQ(Status::Success(),
466 algorithm, extractable, usages, &public_key, &private_key));
467 EXPECT_FALSE(public_key.isNull());
468 EXPECT_FALSE(private_key.isNull());
469 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
470 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
471 EXPECT_TRUE(public_key.extractable());
472 EXPECT_EQ(extractable, private_key.extractable());
473 EXPECT_EQ(usages, public_key.usages());
474 EXPECT_EQ(usages, private_key.usages());
476 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
478 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
479 blink::WebCryptoAlgorithmIdSha1,
484 GenerateKeyPair(algorithm, false, usages, &public_key, &private_key));
485 EXPECT_FALSE(public_key.isNull());
486 EXPECT_FALSE(private_key.isNull());
487 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
488 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
489 EXPECT_EQ(modulus_length,
490 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
491 EXPECT_EQ(modulus_length,
492 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
493 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
494 public_key.algorithm().rsaHashedParams()->hash().id());
495 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
496 private_key.algorithm().rsaHashedParams()->hash().id());
497 // Even though "extractable" was set to false, the public key remains
499 EXPECT_TRUE(public_key.extractable());
500 EXPECT_FALSE(private_key.extractable());
501 EXPECT_EQ(usages, public_key.usages());
502 EXPECT_EQ(usages, private_key.usages());
504 // Exporting a private key as SPKI format doesn't make sense. However this
505 // will first fail because the key is not extractable.
506 std::vector<uint8_t> output;
507 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
508 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
510 // Re-generate an extractable private_key and try to export it as SPKI format.
511 // This should fail since spki is for public keys.
514 GenerateKeyPair(algorithm, true, usages, &public_key, &private_key));
515 EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
516 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
519 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
520 const unsigned int kBadModulusBits[] = {
523 257, // Not a multiple of 8.
524 1023, // Not a multiple of 8.
525 0xFFFFFFFF, // Too big.
526 16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
529 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
531 for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
532 const unsigned int modulus_length_bits = kBadModulusBits[i];
533 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
534 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
535 blink::WebCryptoAlgorithmIdSha256,
538 bool extractable = true;
539 const blink::WebCryptoKeyUsageMask usages = 0;
540 blink::WebCryptoKey public_key;
541 blink::WebCryptoKey private_key;
543 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
545 algorithm, extractable, usages, &public_key, &private_key));
549 // Try generating RSA key pairs using unsupported public exponents. Only
550 // exponents of 3 and 65537 are supported. While both OpenSSL and NSS can
551 // support other values, OpenSSL hangs when given invalid exponents, so use a
552 // whitelist to validate the parameters.
553 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
554 const unsigned int modulus_length = 1024;
556 const char* const kPublicExponents[] = {
557 "11", // 17 - This is a valid public exponent, but currently disallowed.
562 for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
564 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
565 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
566 blink::WebCryptoAlgorithmIdSha256,
568 HexStringToBytes(kPublicExponents[i]));
570 blink::WebCryptoKey public_key;
571 blink::WebCryptoKey private_key;
573 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
574 GenerateKeyPair(algorithm, true, 0, &public_key, &private_key));
578 TEST(WebCryptoRsaSsaTest, SignVerifyFailures) {
579 if (!SupportsRsaPrivateKeyImport())
582 // Import a key pair.
583 blink::WebCryptoAlgorithm import_algorithm =
584 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
585 blink::WebCryptoAlgorithmIdSha1);
586 blink::WebCryptoKey public_key;
587 blink::WebCryptoKey private_key;
588 ASSERT_NO_FATAL_FAILURE(
589 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
590 HexStringToBytes(kPrivateKeyPkcs8DerHex),
593 blink::WebCryptoKeyUsageVerify,
594 blink::WebCryptoKeyUsageSign,
598 blink::WebCryptoAlgorithm algorithm =
599 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
601 std::vector<uint8_t> signature;
602 bool signature_match;
604 // Compute a signature.
605 const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
606 ASSERT_EQ(Status::Success(),
607 Sign(algorithm, private_key, CryptoData(data), &signature));
609 // Ensure truncated signature does not verify by passing one less byte.
614 CryptoData(vector_as_array(&signature), signature.size() - 1),
617 EXPECT_FALSE(signature_match);
619 // Ensure truncated signature does not verify by passing no bytes.
620 EXPECT_EQ(Status::Success(),
626 EXPECT_FALSE(signature_match);
628 // Ensure corrupted signature does not verify.
629 std::vector<uint8_t> corrupt_sig = signature;
630 corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
631 EXPECT_EQ(Status::Success(),
634 CryptoData(corrupt_sig),
637 EXPECT_FALSE(signature_match);
639 // Ensure signatures that are greater than the modulus size fail.
640 const unsigned int long_message_size_bytes = 1024;
641 DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
642 const unsigned char kLongSignature[long_message_size_bytes] = {0};
643 EXPECT_EQ(Status::Success(),
646 CryptoData(kLongSignature, sizeof(kLongSignature)),
649 EXPECT_FALSE(signature_match);
651 // Ensure that signing and verifying with an incompatible algorithm fails.
652 algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
654 EXPECT_EQ(Status::ErrorUnexpected(),
655 Sign(algorithm, private_key, CryptoData(data), &signature));
656 EXPECT_EQ(Status::ErrorUnexpected(),
659 CryptoData(signature),
663 // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
664 // based solely on the contents of the input signature data. In the Web Crypto
665 // implementation, the inner hash should be specified uniquely by the key
666 // algorithm parameter. To validate this behavior, call Verify with a computed
667 // signature that used one hash type (SHA-1), but pass in a key with a
668 // different inner hash type (SHA-256). If the hash type is determined by the
669 // signature itself (undesired), the verify will pass, while if the hash type
670 // is specified by the key algorithm (desired), the verify will fail.
672 // Compute a signature using SHA-1 as the inner hash.
673 EXPECT_EQ(Status::Success(),
674 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
679 blink::WebCryptoKey public_key_256;
680 EXPECT_EQ(Status::Success(),
681 ImportKey(blink::WebCryptoKeyFormatSpki,
682 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
683 CreateRsaHashedImportAlgorithm(
684 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
685 blink::WebCryptoAlgorithmIdSha256),
687 blink::WebCryptoKeyUsageVerify,
690 // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
691 // signature should not verify.
692 // NOTE: public_key was produced by generateKey, and so its associated
693 // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
694 // it has no inner hash to conflict with the input algorithm.
695 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
696 private_key.algorithm().rsaHashedParams()->hash().id());
697 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
698 public_key_256.algorithm().rsaHashedParams()->hash().id());
701 EXPECT_EQ(Status::Success(),
702 Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
704 CryptoData(signature),
707 EXPECT_FALSE(is_match);
710 TEST(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
711 if (!SupportsRsaPrivateKeyImport())
714 scoped_ptr<base::ListValue> tests;
715 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
717 // Import the key pair.
718 blink::WebCryptoAlgorithm import_algorithm =
719 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
720 blink::WebCryptoAlgorithmIdSha1);
721 blink::WebCryptoKey public_key;
722 blink::WebCryptoKey private_key;
723 ASSERT_NO_FATAL_FAILURE(
724 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
725 HexStringToBytes(kPrivateKeyPkcs8DerHex),
728 blink::WebCryptoKeyUsageVerify,
729 blink::WebCryptoKeyUsageSign,
733 blink::WebCryptoAlgorithm algorithm =
734 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
736 // Validate the signatures are computed and verified as expected.
737 std::vector<uint8_t> signature;
738 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
739 SCOPED_TRACE(test_index);
741 base::DictionaryValue* test;
742 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
744 std::vector<uint8_t> test_message =
745 GetBytesFromHexString(test, "message_hex");
746 std::vector<uint8_t> test_signature =
747 GetBytesFromHexString(test, "signature_hex");
752 Sign(algorithm, private_key, CryptoData(test_message), &signature));
753 EXPECT_BYTES_EQ(test_signature, signature);
755 bool is_match = false;
756 ASSERT_EQ(Status::Success(),
759 CryptoData(test_signature),
760 CryptoData(test_message),
762 EXPECT_TRUE(is_match);
766 // Try importing an RSA-SSA public key with unsupported key usages using SPKI
767 // format. RSA-SSA public keys only support the 'verify' usage.
768 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
769 const blink::WebCryptoAlgorithm algorithm =
770 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
771 blink::WebCryptoAlgorithmIdSha256);
773 blink::WebCryptoKeyUsageMask bad_usages[] = {
774 blink::WebCryptoKeyUsageSign,
775 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
776 blink::WebCryptoKeyUsageEncrypt,
777 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
780 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
783 blink::WebCryptoKey public_key;
784 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
785 ImportKey(blink::WebCryptoKeyFormatSpki,
786 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
794 // Try importing an RSA-SSA public key with unsupported key usages using JWK
795 // format. RSA-SSA public keys only support the 'verify' usage.
796 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
797 const blink::WebCryptoAlgorithm algorithm =
798 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
799 blink::WebCryptoAlgorithmIdSha256);
801 blink::WebCryptoKeyUsageMask bad_usages[] = {
802 blink::WebCryptoKeyUsageSign,
803 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
804 blink::WebCryptoKeyUsageEncrypt,
805 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
808 base::DictionaryValue dict;
809 RestoreJwkRsaDictionary(&dict);
810 dict.Remove("use", NULL);
811 dict.SetString("alg", "RS256");
813 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
816 blink::WebCryptoKey public_key;
817 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
818 ImportKeyJwkFromDict(
819 dict, algorithm, false, bad_usages[i], &public_key));
823 // Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
825 TEST(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
826 blink::WebCryptoKeyUsageMask bad_usages[] = {
827 blink::WebCryptoKeyUsageDecrypt,
828 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
829 blink::WebCryptoKeyUsageWrapKey,
832 const unsigned int modulus_length = 256;
833 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
835 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
838 blink::WebCryptoKey public_key;
839 blink::WebCryptoKey private_key;
841 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
842 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
843 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
844 blink::WebCryptoAlgorithmIdSha256,
854 // Generate an RSA-SSA key pair. The public and private keys should select the
855 // key usages which are applicable, and not have the exact same usages as was
856 // specified to GenerateKey
857 TEST(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
858 const unsigned int modulus_length = 256;
859 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
861 blink::WebCryptoKey public_key;
862 blink::WebCryptoKey private_key;
864 ASSERT_EQ(Status::Success(),
866 CreateRsaHashedKeyGenAlgorithm(
867 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
868 blink::WebCryptoAlgorithmIdSha256,
872 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
876 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
877 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
879 // Try again but this time without the Verify usages.
880 ASSERT_EQ(Status::Success(),
881 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
882 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
883 blink::WebCryptoAlgorithmIdSha256,
887 blink::WebCryptoKeyUsageSign,
891 EXPECT_EQ(0, public_key.usages());
892 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
895 TEST(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
897 const blink::WebCryptoAlgorithmId hash;
898 const blink::WebCryptoKeyUsageMask usage;
899 const char* const jwk_alg;
901 const TestCase kTests[] = {
902 {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
903 {blink::WebCryptoAlgorithmIdSha256, blink::WebCryptoKeyUsageVerify,
905 {blink::WebCryptoAlgorithmIdSha384, blink::WebCryptoKeyUsageVerify,
907 {blink::WebCryptoAlgorithmIdSha512, blink::WebCryptoKeyUsageVerify,
910 for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
911 SCOPED_TRACE(test_index);
912 const TestCase& test = kTests[test_index];
914 const blink::WebCryptoAlgorithm import_algorithm =
915 CreateRsaHashedImportAlgorithm(
916 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
918 // Import the spki to create a public key
919 blink::WebCryptoKey public_key;
920 ASSERT_EQ(Status::Success(),
921 ImportKey(blink::WebCryptoKeyFormatSpki,
922 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
928 // Export the public key as JWK and verify its contents
929 std::vector<uint8_t> jwk;
930 ASSERT_EQ(Status::Success(),
931 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
932 EXPECT_TRUE(VerifyPublicJwk(jwk,
934 kPublicKeyModulusHex,
935 kPublicKeyExponentHex,
938 // Import the JWK back in to create a new key
939 blink::WebCryptoKey public_key2;
940 ASSERT_EQ(Status::Success(),
941 ImportKey(blink::WebCryptoKeyFormatJwk,
947 ASSERT_TRUE(public_key2.handle());
948 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
949 EXPECT_TRUE(public_key2.extractable());
950 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
952 // Export the new key as spki and compare to the original.
953 std::vector<uint8_t> spki;
954 ASSERT_EQ(Status::Success(),
955 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
956 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
960 TEST(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
961 base::DictionaryValue dict;
962 RestoreJwkRsaDictionary(&dict);
963 blink::WebCryptoAlgorithm algorithm =
964 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
965 blink::WebCryptoAlgorithmIdSha256);
966 blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
967 blink::WebCryptoKey key;
969 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
970 // entry, while an RSA private key must have those plus at least a "d"
971 // (private exponent) entry.
972 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
976 EXPECT_EQ(Status::Success(),
977 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
978 EXPECT_EQ(algorithm.id(), key.algorithm().id());
979 EXPECT_FALSE(key.extractable());
980 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
981 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
983 // The following are specific failure cases for when kty = "RSA".
985 // Fail if either "n" or "e" is not present or malformed.
986 const std::string kKtyParmName[] = {"n", "e"};
987 for (size_t idx = 0; idx < arraysize(kKtyParmName); ++idx) {
988 // Fail on missing parameter.
989 dict.Remove(kKtyParmName[idx], NULL);
990 EXPECT_NE(Status::Success(),
991 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
992 RestoreJwkRsaDictionary(&dict);
994 // Fail on bad b64 parameter encoding.
995 dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
996 EXPECT_NE(Status::Success(),
997 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
998 RestoreJwkRsaDictionary(&dict);
1000 // Fail on empty parameter.
1001 dict.SetString(kKtyParmName[idx], "");
1002 EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
1003 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
1004 RestoreJwkRsaDictionary(&dict);
1008 // Try importing an RSA-SSA key from JWK format, having specified both Sign and
1009 // Verify usage, and an invalid JWK.
1011 // The test must fail with a usage error BEFORE attempting to read the JWK data.
1012 // Although both Sign and Verify are valid usages for RSA-SSA keys, it is
1013 // invalid to have them both at the same time for one key (since Sign applies to
1014 // private keys, whereas Verify applies to public keys).
1016 // If the implementation does not fail fast, this test will crash dereferencing
1018 TEST(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageFailFast) {
1019 CryptoData bad_data(NULL, 128); // Invalid buffer of length 128.
1021 blink::WebCryptoKey key;
1023 Status::ErrorCreateKeyBadUsages(),
1024 ImportKey(blink::WebCryptoKeyFormatJwk,
1026 CreateRsaHashedImportAlgorithm(
1027 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1028 blink::WebCryptoAlgorithmIdSha256),
1030 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageSign,
1034 // Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
1035 TEST(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
1036 if (!SupportsRsaPrivateKeyImport())
1039 scoped_ptr<base::ListValue> tests;
1040 ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
1042 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
1043 SCOPED_TRACE(test_index);
1045 const base::DictionaryValue* test;
1046 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
1048 blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
1049 std::vector<uint8_t> key_data =
1050 GetKeyDataFromJsonTestCase(test, key_format);
1051 std::string test_error;
1052 ASSERT_TRUE(test->GetString("error", &test_error));
1054 blink::WebCryptoKey key;
1055 Status status = ImportKey(key_format, CryptoData(key_data),
1056 CreateRsaHashedImportAlgorithm(
1057 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1058 blink::WebCryptoAlgorithmIdSha256),
1060 EXPECT_EQ(test_error, StatusToString(status));
1066 } // namespace webcrypto
1068 } // namespace content