Removing uses of X11 native key events.
[chromium-blink-merge.git] / content / child / webcrypto / test / rsa_ssa_unittest.cc
blobf3246c07b8148731d1c306648e8f2bc31bd356b6
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"
17 namespace content {
19 namespace webcrypto {
21 namespace {
23 // Helper for ImportJwkRsaFailures. Restores the JWK JSON
24 // dictionary to a good state
25 void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
26 dict->Clear();
27 dict->SetString("kty", "RSA");
28 dict->SetString("alg", "RS256");
29 dict->SetString("use", "sig");
30 dict->SetBoolean("ext", false);
31 dict->SetString(
32 "n",
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 = blink::WebCryptoKey::createNull();
42 ASSERT_EQ(Status::Success(),
43 ImportKey(blink::WebCryptoKeyFormatSpki,
44 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
45 CreateRsaHashedImportAlgorithm(
46 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
47 blink::WebCryptoAlgorithmIdSha256),
48 true,
49 blink::WebCryptoKeyUsageVerify,
50 &key));
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());
57 EXPECT_BYTES_EQ_HEX(
58 "010001",
59 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
61 // Failing case: Empty SPKI data
62 EXPECT_EQ(
63 Status::ErrorImportEmptyKeyData(),
64 ImportKey(blink::WebCryptoKeyFormatSpki,
65 CryptoData(std::vector<uint8_t>()),
66 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
67 true,
68 blink::WebCryptoKeyUsageVerify,
69 &key));
71 // Failing case: Bad DER encoding.
72 EXPECT_EQ(
73 Status::DataError(),
74 ImportKey(blink::WebCryptoKeyFormatSpki,
75 CryptoData(HexStringToBytes("618333c4cb")),
76 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
77 true,
78 blink::WebCryptoKeyUsageVerify,
79 &key));
81 // Failing case: Import RSA key but provide an inconsistent input algorithm.
82 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
83 ImportKey(blink::WebCryptoKeyFormatSpki,
84 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
85 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
86 true,
87 blink::WebCryptoKeyUsageEncrypt,
88 &key));
90 // Passing case: Export a previously imported RSA public key in SPKI format
91 // and compare to original data.
92 std::vector<uint8_t> output;
93 ASSERT_EQ(Status::Success(),
94 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
95 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
97 // Failing case: Try to export a previously imported RSA public key in raw
98 // format (not allowed for a public key).
99 EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
100 ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
102 // Failing case: Try to export a non-extractable key
103 ASSERT_EQ(Status::Success(),
104 ImportKey(blink::WebCryptoKeyFormatSpki,
105 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
106 CreateRsaHashedImportAlgorithm(
107 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
108 blink::WebCryptoAlgorithmIdSha256),
109 false,
110 blink::WebCryptoKeyUsageVerify,
111 &key));
112 EXPECT_TRUE(key.handle());
113 EXPECT_FALSE(key.extractable());
114 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
115 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
117 // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
118 // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
119 // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
120 // (e.g. SHA-1 in OID, SHA-256 in params)
121 // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
122 // as OAEP/PSS
125 TEST(WebCryptoRsaSsaTest, ImportExportPkcs8) {
126 if (!SupportsRsaPrivateKeyImport())
127 return;
129 // Passing case: Import a valid RSA key in PKCS#8 format.
130 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
131 ASSERT_EQ(Status::Success(),
132 ImportKey(blink::WebCryptoKeyFormatPkcs8,
133 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
134 CreateRsaHashedImportAlgorithm(
135 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
136 blink::WebCryptoAlgorithmIdSha1),
137 true,
138 blink::WebCryptoKeyUsageSign,
139 &key));
140 EXPECT_TRUE(key.handle());
141 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
142 EXPECT_TRUE(key.extractable());
143 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
144 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
145 key.algorithm().rsaHashedParams()->hash().id());
146 EXPECT_EQ(kModulusLengthBits,
147 key.algorithm().rsaHashedParams()->modulusLengthBits());
148 EXPECT_BYTES_EQ_HEX(
149 "010001",
150 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
152 std::vector<uint8_t> exported_key;
153 ASSERT_EQ(Status::Success(),
154 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
155 EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
157 // Failing case: Empty PKCS#8 data
158 EXPECT_EQ(Status::ErrorImportEmptyKeyData(),
159 ImportKey(blink::WebCryptoKeyFormatPkcs8,
160 CryptoData(std::vector<uint8_t>()),
161 CreateRsaHashedImportAlgorithm(
162 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
163 blink::WebCryptoAlgorithmIdSha1),
164 true,
165 blink::WebCryptoKeyUsageSign,
166 &key));
168 // Failing case: Bad DER encoding.
169 EXPECT_EQ(
170 Status::DataError(),
171 ImportKey(blink::WebCryptoKeyFormatPkcs8,
172 CryptoData(HexStringToBytes("618333c4cb")),
173 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
174 true,
175 blink::WebCryptoKeyUsageSign,
176 &key));
178 // Failing case: Import RSA key but provide an inconsistent input algorithm
179 // and usage. Several issues here:
180 // * AES-CBC doesn't support PKCS8 key format
181 // * AES-CBC doesn't support "sign" usage
182 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
183 ImportKey(blink::WebCryptoKeyFormatPkcs8,
184 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
185 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
186 true,
187 blink::WebCryptoKeyUsageSign,
188 &key));
191 // Tests importing of PKCS8 data that does not define a valid RSA key.
192 TEST(WebCryptoRsaSsaTest, ImportInvalidPkcs8) {
193 if (!SupportsRsaPrivateKeyImport())
194 return;
196 // kPrivateKeyPkcs8DerHex defines an RSA private key in PKCS8 format, whose
197 // parameters appear at the following offsets:
199 // n: (offset=36, len=129)
200 // e: (offset=167, len=3)
201 // d: (offset=173, len=128)
202 // p: (offset=303, len=65)
203 // q: (offset=370, len=65)
204 // dp: (offset=437, len=64)
205 // dq; (offset=503, len=64)
206 // qi: (offset=569, len=64)
208 // Do several tests, each of which invert a single byte within the input.
209 const unsigned int kOffsetsToCorrupt[] = {
210 50, // inside n
211 168, // inside e
212 175, // inside d
213 333, // inside p
214 373, // inside q
215 450, // inside dp
216 550, // inside dq
217 600, // inside qi
220 for (size_t test_index = 0; test_index < arraysize(kOffsetsToCorrupt);
221 ++test_index) {
222 SCOPED_TRACE(test_index);
224 unsigned int i = kOffsetsToCorrupt[test_index];
225 std::vector<uint8_t> corrupted_data =
226 HexStringToBytes(kPrivateKeyPkcs8DerHex);
227 corrupted_data[i] = ~corrupted_data[i];
229 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
230 EXPECT_EQ(Status::DataError(),
231 ImportKey(blink::WebCryptoKeyFormatPkcs8,
232 CryptoData(corrupted_data),
233 CreateRsaHashedImportAlgorithm(
234 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
235 blink::WebCryptoAlgorithmIdSha1),
236 true,
237 blink::WebCryptoKeyUsageSign,
238 &key));
242 // Tests JWK import and export by doing a roundtrip key conversion and ensuring
243 // it was lossless:
245 // PKCS8 --> JWK --> PKCS8
246 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
247 if (!SupportsRsaPrivateKeyImport())
248 return;
250 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
251 ASSERT_EQ(Status::Success(),
252 ImportKey(blink::WebCryptoKeyFormatPkcs8,
253 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
254 CreateRsaHashedImportAlgorithm(
255 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
256 blink::WebCryptoAlgorithmIdSha1),
257 true,
258 blink::WebCryptoKeyUsageSign,
259 &key));
261 std::vector<uint8_t> exported_key_jwk;
262 ASSERT_EQ(Status::Success(),
263 ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
265 // All of the optional parameters (p, q, dp, dq, qi) should be present in the
266 // output.
267 const char* expected_jwk =
268 "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
269 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
270 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
271 "\"KPoTk4ZVvh-"
272 "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
273 "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
274 "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
275 "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
276 "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
277 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
278 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
279 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
280 "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
281 "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
282 "\"JxVqukEm0kqB86Uoy_sn9WiG-"
283 "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
285 ASSERT_EQ(CryptoData(std::string(expected_jwk)),
286 CryptoData(exported_key_jwk));
288 ASSERT_EQ(Status::Success(),
289 ImportKey(blink::WebCryptoKeyFormatJwk,
290 CryptoData(exported_key_jwk),
291 CreateRsaHashedImportAlgorithm(
292 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
293 blink::WebCryptoAlgorithmIdSha1),
294 true,
295 blink::WebCryptoKeyUsageSign,
296 &key));
298 std::vector<uint8_t> exported_key_pkcs8;
299 ASSERT_EQ(
300 Status::Success(),
301 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8));
303 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
304 CryptoData(exported_key_pkcs8));
307 // Tests importing multiple RSA private keys from JWK, and then exporting to
308 // PKCS8.
310 // This is a regression test for http://crbug.com/378315, for which importing
311 // a sequence of keys from JWK could yield the wrong key. The first key would
312 // be imported correctly, however every key after that would actually import
313 // the first key.
314 TEST(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
315 if (!SupportsRsaPrivateKeyImport())
316 return;
318 scoped_ptr<base::ListValue> key_list;
319 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
321 // For this test to be meaningful the keys MUST be kept alive before importing
322 // new keys.
323 std::vector<blink::WebCryptoKey> live_keys;
325 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
326 SCOPED_TRACE(key_index);
328 base::DictionaryValue* key_values;
329 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
331 // Get the JWK representation of the key.
332 base::DictionaryValue* key_jwk;
333 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
335 // Get the PKCS8 representation of the key.
336 std::string pkcs8_hex_string;
337 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
338 std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
340 // Get the modulus length for the key.
341 int modulus_length_bits = 0;
342 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
344 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
346 // Import the key from JWK.
347 ASSERT_EQ(
348 Status::Success(),
349 ImportKeyJwkFromDict(*key_jwk,
350 CreateRsaHashedImportAlgorithm(
351 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
352 blink::WebCryptoAlgorithmIdSha256),
353 true,
354 blink::WebCryptoKeyUsageSign,
355 &private_key));
357 live_keys.push_back(private_key);
359 EXPECT_EQ(
360 modulus_length_bits,
361 static_cast<int>(
362 private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
364 // Export to PKCS8 and verify that it matches expectation.
365 std::vector<uint8_t> exported_key_pkcs8;
366 ASSERT_EQ(
367 Status::Success(),
368 ExportKey(
369 blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8));
371 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
375 // Import an RSA private key using JWK. Next import a JWK containing the same
376 // modulus, but mismatched parameters for the rest. It should NOT be possible
377 // that the second import retrieves the first key. See http://crbug.com/378315
378 // for how that could happen.
379 TEST(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
380 if (!SupportsRsaPrivateKeyImport())
381 return;
383 scoped_ptr<base::ListValue> key_list;
384 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
386 // Import a 1024-bit private key.
387 base::DictionaryValue* key1_props;
388 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
389 base::DictionaryValue* key1_jwk;
390 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
392 blink::WebCryptoKey key1 = blink::WebCryptoKey::createNull();
393 ASSERT_EQ(Status::Success(),
394 ImportKeyJwkFromDict(*key1_jwk,
395 CreateRsaHashedImportAlgorithm(
396 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
397 blink::WebCryptoAlgorithmIdSha256),
398 true,
399 blink::WebCryptoKeyUsageSign,
400 &key1));
402 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
404 // Construct a JWK using the modulus of key1, but all the other fields from
405 // another key (also a 1024-bit private key).
406 base::DictionaryValue* key2_props;
407 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
408 base::DictionaryValue* key2_jwk;
409 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
410 std::string modulus;
411 key1_jwk->GetString("n", &modulus);
412 key2_jwk->SetString("n", modulus);
414 // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
415 // somehow return the key created earlier.
416 blink::WebCryptoKey key2 = blink::WebCryptoKey::createNull();
417 ASSERT_EQ(Status::OperationError(),
418 ImportKeyJwkFromDict(*key2_jwk,
419 CreateRsaHashedImportAlgorithm(
420 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
421 blink::WebCryptoAlgorithmIdSha256),
422 true,
423 blink::WebCryptoKeyUsageSign,
424 &key2));
427 // Import a JWK RSA private key with some optional parameters missing (q, dp,
428 // dq, qi).
430 // The only optional parameter included is "p".
432 // This fails because JWA says that producers must include either ALL optional
433 // parameters or NONE.
434 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkMissingOptionalParams) {
435 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
437 base::DictionaryValue dict;
438 dict.SetString("kty", "RSA");
439 dict.SetString("alg", "RS1");
441 dict.SetString(
442 "n",
443 "pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
444 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
445 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
446 dict.SetString("e", "AQAB");
447 dict.SetString(
448 "d",
449 "M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
450 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
451 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
453 dict.SetString("p",
454 "5-"
455 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31W"
456 "hU1vZs8w0Fgs7bc0-2o5kQw");
458 ASSERT_EQ(Status::ErrorJwkPropertyMissing("q"),
459 ImportKeyJwkFromDict(dict,
460 CreateRsaHashedImportAlgorithm(
461 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
462 blink::WebCryptoAlgorithmIdSha1),
463 true,
464 blink::WebCryptoKeyUsageSign,
465 &key));
468 // Import a JWK RSA private key, without any of the optional parameters.
470 // According to JWA, such keys are valid, but applications SHOULD
471 // include all the parameters when sending, and recipients MAY
472 // accept them, but are not required to. Chromium's WebCrypto does
473 // not allow such degenerate keys.
474 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkIncorrectOptionalEmpty) {
475 if (!SupportsRsaPrivateKeyImport())
476 return;
478 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
480 base::DictionaryValue dict;
481 dict.SetString("kty", "RSA");
482 dict.SetString("alg", "RS1");
484 dict.SetString(
485 "n",
486 "pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
487 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
488 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
489 dict.SetString("e", "AQAB");
490 dict.SetString(
491 "d",
492 "M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
493 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
494 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
496 ASSERT_EQ(Status::ErrorJwkPropertyMissing("p"),
497 ImportKeyJwkFromDict(dict,
498 CreateRsaHashedImportAlgorithm(
499 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
500 blink::WebCryptoAlgorithmIdSha1),
501 true,
502 blink::WebCryptoKeyUsageSign,
503 &key));
506 // Tries importing a public RSA key whose exponent contains leading zeros.
507 TEST(WebCryptoRsaSsaTest, ImportJwkRsaNonMinimalExponent) {
508 base::DictionaryValue dict;
510 dict.SetString("kty", "RSA");
511 dict.SetString("e", "AAEAAQ"); // 00 01 00 01
512 dict.SetString(
513 "n",
514 "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
515 "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
516 "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
518 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
520 EXPECT_EQ(Status::ErrorJwkBigIntegerHasLeadingZero("e"),
521 ImportKeyJwkFromDict(dict,
522 CreateRsaHashedImportAlgorithm(
523 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
524 blink::WebCryptoAlgorithmIdSha256),
525 false,
526 blink::WebCryptoKeyUsageVerify,
527 &key));
530 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
531 // Note: using unrealistic short key lengths here to avoid bogging down tests.
533 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
534 const unsigned int modulus_length = 256;
535 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
536 blink::WebCryptoAlgorithm algorithm =
537 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
538 blink::WebCryptoAlgorithmIdSha256,
539 modulus_length,
540 public_exponent);
541 bool extractable = true;
542 const blink::WebCryptoKeyUsageMask usage_mask = 0;
543 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
544 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
546 EXPECT_EQ(Status::Success(),
547 GenerateKeyPair(
548 algorithm, extractable, usage_mask, &public_key, &private_key));
549 EXPECT_FALSE(public_key.isNull());
550 EXPECT_FALSE(private_key.isNull());
551 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
552 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
553 EXPECT_EQ(modulus_length,
554 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
555 EXPECT_EQ(modulus_length,
556 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
557 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
558 public_key.algorithm().rsaHashedParams()->hash().id());
559 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
560 private_key.algorithm().rsaHashedParams()->hash().id());
561 EXPECT_TRUE(public_key.extractable());
562 EXPECT_EQ(extractable, private_key.extractable());
563 EXPECT_EQ(usage_mask, public_key.usages());
564 EXPECT_EQ(usage_mask, private_key.usages());
566 // Try exporting the generated key pair, and then re-importing to verify that
567 // the exported data was valid.
568 std::vector<uint8_t> public_key_spki;
569 EXPECT_EQ(
570 Status::Success(),
571 ExportKey(blink::WebCryptoKeyFormatSpki, public_key, &public_key_spki));
573 if (SupportsRsaPrivateKeyImport()) {
574 public_key = blink::WebCryptoKey::createNull();
575 EXPECT_EQ(Status::Success(),
576 ImportKey(blink::WebCryptoKeyFormatSpki,
577 CryptoData(public_key_spki),
578 CreateRsaHashedImportAlgorithm(
579 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
580 blink::WebCryptoAlgorithmIdSha256),
581 true,
582 usage_mask,
583 &public_key));
584 EXPECT_EQ(modulus_length,
585 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
587 std::vector<uint8_t> private_key_pkcs8;
588 EXPECT_EQ(
589 Status::Success(),
590 ExportKey(
591 blink::WebCryptoKeyFormatPkcs8, private_key, &private_key_pkcs8));
592 private_key = blink::WebCryptoKey::createNull();
593 EXPECT_EQ(Status::Success(),
594 ImportKey(blink::WebCryptoKeyFormatPkcs8,
595 CryptoData(private_key_pkcs8),
596 CreateRsaHashedImportAlgorithm(
597 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
598 blink::WebCryptoAlgorithmIdSha256),
599 true,
600 usage_mask,
601 &private_key));
602 EXPECT_EQ(modulus_length,
603 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
606 // Fail with bad modulus.
607 algorithm =
608 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
609 blink::WebCryptoAlgorithmIdSha256,
611 public_exponent);
612 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
613 GenerateKeyPair(
614 algorithm, extractable, usage_mask, &public_key, &private_key));
616 // Fail with bad exponent: larger than unsigned long.
617 unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
618 const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
619 algorithm =
620 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
621 blink::WebCryptoAlgorithmIdSha256,
622 modulus_length,
623 long_exponent);
624 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
625 GenerateKeyPair(
626 algorithm, extractable, usage_mask, &public_key, &private_key));
628 // Fail with bad exponent: empty.
629 const std::vector<uint8_t> empty_exponent;
630 algorithm =
631 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
632 blink::WebCryptoAlgorithmIdSha256,
633 modulus_length,
634 empty_exponent);
635 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
636 GenerateKeyPair(
637 algorithm, extractable, usage_mask, &public_key, &private_key));
639 // Fail with bad exponent: all zeros.
640 std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
641 algorithm =
642 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
643 blink::WebCryptoAlgorithmIdSha256,
644 modulus_length,
645 exponent_with_leading_zeros);
646 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
647 GenerateKeyPair(
648 algorithm, extractable, usage_mask, &public_key, &private_key));
650 // Key generation success using exponent with leading zeros.
651 exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
652 public_exponent.begin(),
653 public_exponent.end());
654 algorithm =
655 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
656 blink::WebCryptoAlgorithmIdSha256,
657 modulus_length,
658 exponent_with_leading_zeros);
659 EXPECT_EQ(Status::Success(),
660 GenerateKeyPair(
661 algorithm, extractable, usage_mask, &public_key, &private_key));
662 EXPECT_FALSE(public_key.isNull());
663 EXPECT_FALSE(private_key.isNull());
664 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
665 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
666 EXPECT_TRUE(public_key.extractable());
667 EXPECT_EQ(extractable, private_key.extractable());
668 EXPECT_EQ(usage_mask, public_key.usages());
669 EXPECT_EQ(usage_mask, private_key.usages());
671 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
672 algorithm =
673 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
674 blink::WebCryptoAlgorithmIdSha1,
675 modulus_length,
676 public_exponent);
677 EXPECT_EQ(
678 Status::Success(),
679 GenerateKeyPair(algorithm, false, usage_mask, &public_key, &private_key));
680 EXPECT_FALSE(public_key.isNull());
681 EXPECT_FALSE(private_key.isNull());
682 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
683 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
684 EXPECT_EQ(modulus_length,
685 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
686 EXPECT_EQ(modulus_length,
687 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
688 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
689 public_key.algorithm().rsaHashedParams()->hash().id());
690 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
691 private_key.algorithm().rsaHashedParams()->hash().id());
692 // Even though "extractable" was set to false, the public key remains
693 // extractable.
694 EXPECT_TRUE(public_key.extractable());
695 EXPECT_FALSE(private_key.extractable());
696 EXPECT_EQ(usage_mask, public_key.usages());
697 EXPECT_EQ(usage_mask, private_key.usages());
699 // Exporting a private key as SPKI format doesn't make sense. However this
700 // will first fail because the key is not extractable.
701 std::vector<uint8_t> output;
702 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
703 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
705 // Re-generate an extractable private_key and try to export it as SPKI format.
706 // This should fail since spki is for public keys.
707 EXPECT_EQ(
708 Status::Success(),
709 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key));
710 EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
711 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
714 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
715 const unsigned int kBadModulusBits[] = {
717 248, // Too small.
718 257, // Not a multiple of 8.
719 1023, // Not a multiple of 8.
720 0xFFFFFFFF, // Too big.
721 16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
724 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
726 for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
727 const unsigned int modulus_length_bits = kBadModulusBits[i];
728 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
729 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
730 blink::WebCryptoAlgorithmIdSha256,
731 modulus_length_bits,
732 public_exponent);
733 bool extractable = true;
734 const blink::WebCryptoKeyUsageMask usage_mask = 0;
735 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
736 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
738 EXPECT_EQ(
739 Status::ErrorGenerateRsaUnsupportedModulus(),
740 GenerateKeyPair(
741 algorithm, extractable, usage_mask, &public_key, &private_key));
745 // Try generating RSA key pairs using unsupported public exponents. Only
746 // exponents of 3 and 65537 are supported. While both OpenSSL and NSS can
747 // support other values, OpenSSL hangs when given invalid exponents, so use a
748 // whitelist to validate the parameters.
749 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
750 const unsigned int modulus_length = 1024;
752 const char* const kPublicExponents[] = {
753 "11", // 17 - This is a valid public exponent, but currently disallowed.
754 "00", "01", "02",
755 "010000", // 65536
758 for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
759 SCOPED_TRACE(i);
760 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
761 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
762 blink::WebCryptoAlgorithmIdSha256,
763 modulus_length,
764 HexStringToBytes(kPublicExponents[i]));
766 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
767 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
769 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
770 GenerateKeyPair(algorithm, true, 0, &public_key, &private_key));
774 TEST(WebCryptoRsaSsaTest, SignVerifyFailures) {
775 if (!SupportsRsaPrivateKeyImport())
776 return;
778 // Import a key pair.
779 blink::WebCryptoAlgorithm import_algorithm =
780 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
781 blink::WebCryptoAlgorithmIdSha1);
782 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
783 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
784 ASSERT_NO_FATAL_FAILURE(
785 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
786 HexStringToBytes(kPrivateKeyPkcs8DerHex),
787 import_algorithm,
788 false,
789 blink::WebCryptoKeyUsageVerify,
790 blink::WebCryptoKeyUsageSign,
791 &public_key,
792 &private_key));
794 blink::WebCryptoAlgorithm algorithm =
795 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
797 std::vector<uint8_t> signature;
798 bool signature_match;
800 // Compute a signature.
801 const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
802 ASSERT_EQ(Status::Success(),
803 Sign(algorithm, private_key, CryptoData(data), &signature));
805 // Ensure truncated signature does not verify by passing one less byte.
806 EXPECT_EQ(
807 Status::Success(),
808 Verify(algorithm,
809 public_key,
810 CryptoData(vector_as_array(&signature), signature.size() - 1),
811 CryptoData(data),
812 &signature_match));
813 EXPECT_FALSE(signature_match);
815 // Ensure truncated signature does not verify by passing no bytes.
816 EXPECT_EQ(Status::Success(),
817 Verify(algorithm,
818 public_key,
819 CryptoData(),
820 CryptoData(data),
821 &signature_match));
822 EXPECT_FALSE(signature_match);
824 // Ensure corrupted signature does not verify.
825 std::vector<uint8_t> corrupt_sig = signature;
826 corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
827 EXPECT_EQ(Status::Success(),
828 Verify(algorithm,
829 public_key,
830 CryptoData(corrupt_sig),
831 CryptoData(data),
832 &signature_match));
833 EXPECT_FALSE(signature_match);
835 // Ensure signatures that are greater than the modulus size fail.
836 const unsigned int long_message_size_bytes = 1024;
837 DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
838 const unsigned char kLongSignature[long_message_size_bytes] = {0};
839 EXPECT_EQ(Status::Success(),
840 Verify(algorithm,
841 public_key,
842 CryptoData(kLongSignature, sizeof(kLongSignature)),
843 CryptoData(data),
844 &signature_match));
845 EXPECT_FALSE(signature_match);
847 // Ensure that signing and verifying with an incompatible algorithm fails.
848 algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
850 EXPECT_EQ(Status::ErrorUnexpected(),
851 Sign(algorithm, private_key, CryptoData(data), &signature));
852 EXPECT_EQ(Status::ErrorUnexpected(),
853 Verify(algorithm,
854 public_key,
855 CryptoData(signature),
856 CryptoData(data),
857 &signature_match));
859 // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
860 // based solely on the contents of the input signature data. In the Web Crypto
861 // implementation, the inner hash should be specified uniquely by the key
862 // algorithm parameter. To validate this behavior, call Verify with a computed
863 // signature that used one hash type (SHA-1), but pass in a key with a
864 // different inner hash type (SHA-256). If the hash type is determined by the
865 // signature itself (undesired), the verify will pass, while if the hash type
866 // is specified by the key algorithm (desired), the verify will fail.
868 // Compute a signature using SHA-1 as the inner hash.
869 EXPECT_EQ(Status::Success(),
870 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
871 private_key,
872 CryptoData(data),
873 &signature));
875 blink::WebCryptoKey public_key_256 = blink::WebCryptoKey::createNull();
876 EXPECT_EQ(Status::Success(),
877 ImportKey(blink::WebCryptoKeyFormatSpki,
878 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
879 CreateRsaHashedImportAlgorithm(
880 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
881 blink::WebCryptoAlgorithmIdSha256),
882 true,
883 blink::WebCryptoKeyUsageVerify,
884 &public_key_256));
886 // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
887 // signature should not verify.
888 // NOTE: public_key was produced by generateKey, and so its associated
889 // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
890 // it has no inner hash to conflict with the input algorithm.
891 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
892 private_key.algorithm().rsaHashedParams()->hash().id());
893 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
894 public_key_256.algorithm().rsaHashedParams()->hash().id());
896 bool is_match;
897 EXPECT_EQ(Status::Success(),
898 Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
899 public_key_256,
900 CryptoData(signature),
901 CryptoData(data),
902 &is_match));
903 EXPECT_FALSE(is_match);
906 TEST(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
907 if (!SupportsRsaPrivateKeyImport())
908 return;
910 scoped_ptr<base::ListValue> tests;
911 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
913 // Import the key pair.
914 blink::WebCryptoAlgorithm import_algorithm =
915 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
916 blink::WebCryptoAlgorithmIdSha1);
917 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
918 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
919 ASSERT_NO_FATAL_FAILURE(
920 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
921 HexStringToBytes(kPrivateKeyPkcs8DerHex),
922 import_algorithm,
923 false,
924 blink::WebCryptoKeyUsageVerify,
925 blink::WebCryptoKeyUsageSign,
926 &public_key,
927 &private_key));
929 blink::WebCryptoAlgorithm algorithm =
930 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
932 // Validate the signatures are computed and verified as expected.
933 std::vector<uint8_t> signature;
934 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
935 SCOPED_TRACE(test_index);
937 base::DictionaryValue* test;
938 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
940 std::vector<uint8_t> test_message =
941 GetBytesFromHexString(test, "message_hex");
942 std::vector<uint8_t> test_signature =
943 GetBytesFromHexString(test, "signature_hex");
945 signature.clear();
946 ASSERT_EQ(
947 Status::Success(),
948 Sign(algorithm, private_key, CryptoData(test_message), &signature));
949 EXPECT_BYTES_EQ(test_signature, signature);
951 bool is_match = false;
952 ASSERT_EQ(Status::Success(),
953 Verify(algorithm,
954 public_key,
955 CryptoData(test_signature),
956 CryptoData(test_message),
957 &is_match));
958 EXPECT_TRUE(is_match);
962 // Try importing an RSA-SSA public key with unsupported key usages using SPKI
963 // format. RSA-SSA public keys only support the 'verify' usage.
964 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
965 const blink::WebCryptoAlgorithm algorithm =
966 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
967 blink::WebCryptoAlgorithmIdSha256);
969 blink::WebCryptoKeyUsageMask bad_usages[] = {
970 blink::WebCryptoKeyUsageSign,
971 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
972 blink::WebCryptoKeyUsageEncrypt,
973 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
976 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
977 SCOPED_TRACE(i);
979 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
980 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
981 ImportKey(blink::WebCryptoKeyFormatSpki,
982 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
983 algorithm,
984 false,
985 bad_usages[i],
986 &public_key));
990 // Try importing an RSA-SSA public key with unsupported key usages using JWK
991 // format. RSA-SSA public keys only support the 'verify' usage.
992 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
993 const blink::WebCryptoAlgorithm algorithm =
994 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
995 blink::WebCryptoAlgorithmIdSha256);
997 blink::WebCryptoKeyUsageMask bad_usages[] = {
998 blink::WebCryptoKeyUsageSign,
999 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
1000 blink::WebCryptoKeyUsageEncrypt,
1001 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
1004 base::DictionaryValue dict;
1005 RestoreJwkRsaDictionary(&dict);
1006 dict.Remove("use", NULL);
1007 dict.SetString("alg", "RS256");
1009 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
1010 SCOPED_TRACE(i);
1012 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1013 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
1014 ImportKeyJwkFromDict(
1015 dict, algorithm, false, bad_usages[i], &public_key));
1019 // Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
1020 // 'sign', 'verify'
1021 TEST(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
1022 blink::WebCryptoKeyUsageMask bad_usages[] = {
1023 blink::WebCryptoKeyUsageDecrypt,
1024 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
1025 blink::WebCryptoKeyUsageWrapKey,
1028 const unsigned int modulus_length = 256;
1029 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
1031 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
1032 SCOPED_TRACE(i);
1034 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1035 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
1037 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
1038 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
1039 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1040 blink::WebCryptoAlgorithmIdSha256,
1041 modulus_length,
1042 public_exponent),
1043 true,
1044 bad_usages[i],
1045 &public_key,
1046 &private_key));
1050 // Generate an RSA-SSA key pair. The public and private keys should select the
1051 // key usages which are applicable, and not have the exact same usages as was
1052 // specified to GenerateKey
1053 TEST(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
1054 const unsigned int modulus_length = 256;
1055 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
1057 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1058 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
1060 ASSERT_EQ(Status::Success(),
1061 GenerateKeyPair(
1062 CreateRsaHashedKeyGenAlgorithm(
1063 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1064 blink::WebCryptoAlgorithmIdSha256,
1065 modulus_length,
1066 public_exponent),
1067 true,
1068 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
1069 &public_key,
1070 &private_key));
1072 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
1073 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
1075 // Try again but this time without the Verify usages.
1076 ASSERT_EQ(Status::Success(),
1077 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
1078 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1079 blink::WebCryptoAlgorithmIdSha256,
1080 modulus_length,
1081 public_exponent),
1082 true,
1083 blink::WebCryptoKeyUsageSign,
1084 &public_key,
1085 &private_key));
1087 EXPECT_EQ(0, public_key.usages());
1088 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
1091 TEST(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
1092 struct TestCase {
1093 const blink::WebCryptoAlgorithmId hash;
1094 const blink::WebCryptoKeyUsageMask usage;
1095 const char* const jwk_alg;
1097 const TestCase kTests[] = {
1098 {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
1099 {blink::WebCryptoAlgorithmIdSha256, blink::WebCryptoKeyUsageVerify,
1100 "RS256"},
1101 {blink::WebCryptoAlgorithmIdSha384, blink::WebCryptoKeyUsageVerify,
1102 "RS384"},
1103 {blink::WebCryptoAlgorithmIdSha512, blink::WebCryptoKeyUsageVerify,
1104 "RS512"}};
1106 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests);
1107 ++test_index) {
1108 SCOPED_TRACE(test_index);
1109 const TestCase& test = kTests[test_index];
1111 const blink::WebCryptoAlgorithm import_algorithm =
1112 CreateRsaHashedImportAlgorithm(
1113 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
1115 // Import the spki to create a public key
1116 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1117 ASSERT_EQ(Status::Success(),
1118 ImportKey(blink::WebCryptoKeyFormatSpki,
1119 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
1120 import_algorithm,
1121 true,
1122 test.usage,
1123 &public_key));
1125 // Export the public key as JWK and verify its contents
1126 std::vector<uint8_t> jwk;
1127 ASSERT_EQ(Status::Success(),
1128 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
1129 EXPECT_TRUE(VerifyPublicJwk(jwk,
1130 test.jwk_alg,
1131 kPublicKeyModulusHex,
1132 kPublicKeyExponentHex,
1133 test.usage));
1135 // Import the JWK back in to create a new key
1136 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull();
1137 ASSERT_EQ(Status::Success(),
1138 ImportKey(blink::WebCryptoKeyFormatJwk,
1139 CryptoData(jwk),
1140 import_algorithm,
1141 true,
1142 test.usage,
1143 &public_key2));
1144 ASSERT_TRUE(public_key2.handle());
1145 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
1146 EXPECT_TRUE(public_key2.extractable());
1147 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
1149 // Export the new key as spki and compare to the original.
1150 std::vector<uint8_t> spki;
1151 ASSERT_EQ(Status::Success(),
1152 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
1153 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
1157 TEST(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
1158 base::DictionaryValue dict;
1159 RestoreJwkRsaDictionary(&dict);
1160 blink::WebCryptoAlgorithm algorithm =
1161 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1162 blink::WebCryptoAlgorithmIdSha256);
1163 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageVerify;
1164 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1166 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
1167 // entry, while an RSA private key must have those plus at least a "d"
1168 // (private exponent) entry.
1169 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
1170 // section 6.3.
1172 // Baseline pass.
1173 EXPECT_EQ(Status::Success(),
1174 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1175 EXPECT_EQ(algorithm.id(), key.algorithm().id());
1176 EXPECT_FALSE(key.extractable());
1177 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
1178 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
1180 // The following are specific failure cases for when kty = "RSA".
1182 // Fail if either "n" or "e" is not present or malformed.
1183 const std::string kKtyParmName[] = {"n", "e"};
1184 for (size_t idx = 0; idx < ARRAYSIZE_UNSAFE(kKtyParmName); ++idx) {
1185 // Fail on missing parameter.
1186 dict.Remove(kKtyParmName[idx], NULL);
1187 EXPECT_NE(Status::Success(),
1188 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1189 RestoreJwkRsaDictionary(&dict);
1191 // Fail on bad b64 parameter encoding.
1192 dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
1193 EXPECT_NE(Status::Success(),
1194 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1195 RestoreJwkRsaDictionary(&dict);
1197 // Fail on empty parameter.
1198 dict.SetString(kKtyParmName[idx], "");
1199 EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
1200 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1201 RestoreJwkRsaDictionary(&dict);
1205 } // namespace
1207 } // namespace webcrypto
1209 } // namespace content