Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / webcrypto / test / rsa_ssa_unittest.cc
blob1a01a60400c9e3407e8e979cc91cb8dc23b1521a
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;
42 ASSERT_EQ(Status::Success(),
43 ImportKey(blink::WebCryptoKeyFormatSpki,
44 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
45 CreateRsaHashedImportAlgorithm(
46 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
47 blink::WebCryptoAlgorithmIdSha256),
48 true, blink::WebCryptoKeyUsageVerify, &key));
49 EXPECT_TRUE(key.handle());
50 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
51 EXPECT_TRUE(key.extractable());
52 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
53 EXPECT_EQ(kModulusLengthBits,
54 key.algorithm().rsaHashedParams()->modulusLengthBits());
55 EXPECT_BYTES_EQ_HEX(
56 "010001",
57 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
59 // Failing case: Import RSA key but provide an inconsistent input algorithm.
60 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
61 ImportKey(blink::WebCryptoKeyFormatSpki,
62 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
63 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
64 blink::WebCryptoKeyUsageEncrypt, &key));
66 // Passing case: Export a previously imported RSA public key in SPKI format
67 // and compare to original data.
68 std::vector<uint8_t> output;
69 ASSERT_EQ(Status::Success(),
70 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
71 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
73 // Failing case: Try to export a previously imported RSA public key in raw
74 // format (not allowed for a public key).
75 EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
76 ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
78 // Failing case: Try to export a non-extractable key
79 ASSERT_EQ(Status::Success(),
80 ImportKey(blink::WebCryptoKeyFormatSpki,
81 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
82 CreateRsaHashedImportAlgorithm(
83 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
84 blink::WebCryptoAlgorithmIdSha256),
85 false, blink::WebCryptoKeyUsageVerify, &key));
86 EXPECT_TRUE(key.handle());
87 EXPECT_FALSE(key.extractable());
88 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
89 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
91 // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
92 // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
93 // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
94 // (e.g. SHA-1 in OID, SHA-256 in params)
95 // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
96 // as OAEP/PSS
99 TEST(WebCryptoRsaSsaTest, ImportExportPkcs8) {
100 if (!SupportsRsaPrivateKeyImport())
101 return;
103 // Passing case: Import a valid RSA key in PKCS#8 format.
104 blink::WebCryptoKey key;
105 ASSERT_EQ(Status::Success(),
106 ImportKey(blink::WebCryptoKeyFormatPkcs8,
107 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
108 CreateRsaHashedImportAlgorithm(
109 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
110 blink::WebCryptoAlgorithmIdSha1),
111 true, blink::WebCryptoKeyUsageSign, &key));
112 EXPECT_TRUE(key.handle());
113 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
114 EXPECT_TRUE(key.extractable());
115 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
116 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
117 key.algorithm().rsaHashedParams()->hash().id());
118 EXPECT_EQ(kModulusLengthBits,
119 key.algorithm().rsaHashedParams()->modulusLengthBits());
120 EXPECT_BYTES_EQ_HEX(
121 "010001",
122 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
124 std::vector<uint8_t> exported_key;
125 ASSERT_EQ(Status::Success(),
126 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
127 EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
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::WebCryptoKeyFormatPkcs8,
135 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
136 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), true,
137 blink::WebCryptoKeyUsageSign, &key));
140 // Tests JWK import and export by doing a roundtrip key conversion and ensuring
141 // it was lossless:
143 // PKCS8 --> JWK --> PKCS8
144 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
145 if (!SupportsRsaPrivateKeyImport())
146 return;
148 blink::WebCryptoKey key;
149 ASSERT_EQ(Status::Success(),
150 ImportKey(blink::WebCryptoKeyFormatPkcs8,
151 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
152 CreateRsaHashedImportAlgorithm(
153 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
154 blink::WebCryptoAlgorithmIdSha1),
155 true, blink::WebCryptoKeyUsageSign, &key));
157 std::vector<uint8_t> exported_key_jwk;
158 ASSERT_EQ(Status::Success(),
159 ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
161 // All of the optional parameters (p, q, dp, dq, qi) should be present in the
162 // output.
163 const char* expected_jwk =
164 "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
165 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
166 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
167 "\"KPoTk4ZVvh-"
168 "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
169 "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
170 "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
171 "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
172 "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
173 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
174 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
175 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
176 "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
177 "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
178 "\"JxVqukEm0kqB86Uoy_sn9WiG-"
179 "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
181 ASSERT_EQ(CryptoData(std::string(expected_jwk)),
182 CryptoData(exported_key_jwk));
184 ASSERT_EQ(
185 Status::Success(),
186 ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(exported_key_jwk),
187 CreateRsaHashedImportAlgorithm(
188 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
189 blink::WebCryptoAlgorithmIdSha1),
190 true, blink::WebCryptoKeyUsageSign, &key));
192 std::vector<uint8_t> exported_key_pkcs8;
193 ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8, key,
194 &exported_key_pkcs8));
196 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
197 CryptoData(exported_key_pkcs8));
200 // Tests importing multiple RSA private keys from JWK, and then exporting to
201 // PKCS8.
203 // This is a regression test for http://crbug.com/378315, for which importing
204 // a sequence of keys from JWK could yield the wrong key. The first key would
205 // be imported correctly, however every key after that would actually import
206 // the first key.
207 TEST(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
208 if (!SupportsRsaPrivateKeyImport())
209 return;
211 scoped_ptr<base::ListValue> key_list;
212 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
214 // For this test to be meaningful the keys MUST be kept alive before importing
215 // new keys.
216 std::vector<blink::WebCryptoKey> live_keys;
218 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
219 SCOPED_TRACE(key_index);
221 base::DictionaryValue* key_values;
222 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
224 // Get the JWK representation of the key.
225 base::DictionaryValue* key_jwk;
226 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
228 // Get the PKCS8 representation of the key.
229 std::string pkcs8_hex_string;
230 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
231 std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
233 // Get the modulus length for the key.
234 int modulus_length_bits = 0;
235 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
237 blink::WebCryptoKey private_key;
239 // Import the key from JWK.
240 ASSERT_EQ(Status::Success(),
241 ImportKeyJwkFromDict(
242 *key_jwk, CreateRsaHashedImportAlgorithm(
243 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
244 blink::WebCryptoAlgorithmIdSha256),
245 true, blink::WebCryptoKeyUsageSign, &private_key));
247 live_keys.push_back(private_key);
249 EXPECT_EQ(
250 modulus_length_bits,
251 static_cast<int>(
252 private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
254 // Export to PKCS8 and verify that it matches expectation.
255 std::vector<uint8_t> exported_key_pkcs8;
256 ASSERT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
257 private_key, &exported_key_pkcs8));
259 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
263 // Import an RSA private key using JWK. Next import a JWK containing the same
264 // modulus, but mismatched parameters for the rest. It should NOT be possible
265 // that the second import retrieves the first key. See http://crbug.com/378315
266 // for how that could happen.
267 TEST(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
268 if (!SupportsRsaPrivateKeyImport())
269 return;
271 scoped_ptr<base::ListValue> key_list;
272 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
274 // Import a 1024-bit private key.
275 base::DictionaryValue* key1_props;
276 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
277 base::DictionaryValue* key1_jwk;
278 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
280 blink::WebCryptoKey key1;
281 ASSERT_EQ(Status::Success(),
282 ImportKeyJwkFromDict(*key1_jwk,
283 CreateRsaHashedImportAlgorithm(
284 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
285 blink::WebCryptoAlgorithmIdSha256),
286 true, blink::WebCryptoKeyUsageSign, &key1));
288 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
290 // Construct a JWK using the modulus of key1, but all the other fields from
291 // another key (also a 1024-bit private key).
292 base::DictionaryValue* key2_props;
293 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
294 base::DictionaryValue* key2_jwk;
295 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
296 std::string modulus;
297 key1_jwk->GetString("n", &modulus);
298 key2_jwk->SetString("n", modulus);
300 // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
301 // somehow return the key created earlier.
302 blink::WebCryptoKey key2;
303 ASSERT_EQ(Status::OperationError(),
304 ImportKeyJwkFromDict(*key2_jwk,
305 CreateRsaHashedImportAlgorithm(
306 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
307 blink::WebCryptoAlgorithmIdSha256),
308 true, blink::WebCryptoKeyUsageSign, &key2));
311 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
312 // Note: using unrealistic short key lengths here to avoid bogging down tests.
314 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
315 const unsigned int modulus_length = 256;
316 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
317 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
318 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
319 blink::WebCryptoAlgorithmIdSha256, modulus_length, public_exponent);
320 bool extractable = true;
321 const blink::WebCryptoKeyUsageMask public_usages =
322 blink::WebCryptoKeyUsageVerify;
323 const blink::WebCryptoKeyUsageMask private_usages =
324 blink::WebCryptoKeyUsageSign;
325 const blink::WebCryptoKeyUsageMask usages = public_usages | private_usages;
326 blink::WebCryptoKey public_key;
327 blink::WebCryptoKey private_key;
329 EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
330 &public_key, &private_key));
331 ASSERT_FALSE(public_key.isNull());
332 ASSERT_FALSE(private_key.isNull());
333 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
334 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
335 EXPECT_EQ(modulus_length,
336 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
337 EXPECT_EQ(modulus_length,
338 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
339 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
340 public_key.algorithm().rsaHashedParams()->hash().id());
341 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
342 private_key.algorithm().rsaHashedParams()->hash().id());
343 EXPECT_TRUE(public_key.extractable());
344 EXPECT_EQ(extractable, private_key.extractable());
345 EXPECT_EQ(public_usages, public_key.usages());
346 EXPECT_EQ(private_usages, private_key.usages());
348 // Try exporting the generated key pair, and then re-importing to verify that
349 // the exported data was valid.
350 std::vector<uint8_t> public_key_spki;
351 EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatSpki,
352 public_key, &public_key_spki));
354 if (SupportsRsaPrivateKeyImport()) {
355 public_key = blink::WebCryptoKey::createNull();
356 ASSERT_EQ(
357 Status::Success(),
358 ImportKey(blink::WebCryptoKeyFormatSpki, CryptoData(public_key_spki),
359 CreateRsaHashedImportAlgorithm(
360 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
361 blink::WebCryptoAlgorithmIdSha256),
362 true, public_usages, &public_key));
363 EXPECT_EQ(modulus_length,
364 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
366 std::vector<uint8_t> private_key_pkcs8;
367 EXPECT_EQ(Status::Success(), ExportKey(blink::WebCryptoKeyFormatPkcs8,
368 private_key, &private_key_pkcs8));
369 private_key = blink::WebCryptoKey::createNull();
370 ASSERT_EQ(
371 Status::Success(),
372 ImportKey(blink::WebCryptoKeyFormatPkcs8, CryptoData(private_key_pkcs8),
373 CreateRsaHashedImportAlgorithm(
374 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
375 blink::WebCryptoAlgorithmIdSha256),
376 true, private_usages, &private_key));
377 EXPECT_EQ(modulus_length,
378 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
381 // Fail with bad modulus.
382 algorithm = CreateRsaHashedKeyGenAlgorithm(
383 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
384 blink::WebCryptoAlgorithmIdSha256, 0, public_exponent);
385 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
386 GenerateKeyPair(algorithm, extractable, usages, &public_key,
387 &private_key));
389 // Fail with bad exponent: larger than unsigned long.
390 unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
391 const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
392 algorithm = CreateRsaHashedKeyGenAlgorithm(
393 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
394 blink::WebCryptoAlgorithmIdSha256, modulus_length, long_exponent);
395 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
396 GenerateKeyPair(algorithm, extractable, usages, &public_key,
397 &private_key));
399 // Fail with bad exponent: empty.
400 const std::vector<uint8_t> empty_exponent;
401 algorithm = CreateRsaHashedKeyGenAlgorithm(
402 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
403 blink::WebCryptoAlgorithmIdSha256, modulus_length, empty_exponent);
404 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
405 GenerateKeyPair(algorithm, extractable, usages, &public_key,
406 &private_key));
408 // Fail with bad exponent: all zeros.
409 std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
410 algorithm = CreateRsaHashedKeyGenAlgorithm(
411 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
412 blink::WebCryptoAlgorithmIdSha256, modulus_length,
413 exponent_with_leading_zeros);
414 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
415 GenerateKeyPair(algorithm, extractable, usages, &public_key,
416 &private_key));
418 // Key generation success using exponent with leading zeros.
419 exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
420 public_exponent.begin(),
421 public_exponent.end());
422 algorithm =
423 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
424 blink::WebCryptoAlgorithmIdSha256,
425 modulus_length,
426 exponent_with_leading_zeros);
427 EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, extractable, usages,
428 &public_key, &private_key));
429 EXPECT_FALSE(public_key.isNull());
430 EXPECT_FALSE(private_key.isNull());
431 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
432 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
433 EXPECT_TRUE(public_key.extractable());
434 EXPECT_EQ(extractable, private_key.extractable());
435 EXPECT_EQ(public_usages, public_key.usages());
436 EXPECT_EQ(private_usages, private_key.usages());
438 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
439 algorithm =
440 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
441 blink::WebCryptoAlgorithmIdSha1,
442 modulus_length,
443 public_exponent);
444 EXPECT_EQ(
445 Status::Success(),
446 GenerateKeyPair(algorithm, false, usages, &public_key, &private_key));
447 EXPECT_FALSE(public_key.isNull());
448 EXPECT_FALSE(private_key.isNull());
449 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
450 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
451 EXPECT_EQ(modulus_length,
452 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
453 EXPECT_EQ(modulus_length,
454 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
455 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
456 public_key.algorithm().rsaHashedParams()->hash().id());
457 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
458 private_key.algorithm().rsaHashedParams()->hash().id());
459 // Even though "extractable" was set to false, the public key remains
460 // extractable.
461 EXPECT_TRUE(public_key.extractable());
462 EXPECT_FALSE(private_key.extractable());
463 EXPECT_EQ(public_usages, public_key.usages());
464 EXPECT_EQ(private_usages, private_key.usages());
466 // Exporting a private key as SPKI format doesn't make sense. However this
467 // will first fail because the key is not extractable.
468 std::vector<uint8_t> output;
469 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
470 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
472 // Re-generate an extractable private_key and try to export it as SPKI format.
473 // This should fail since spki is for public keys.
474 EXPECT_EQ(Status::Success(), GenerateKeyPair(algorithm, true, usages,
475 &public_key, &private_key));
476 EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
477 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
480 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
481 const unsigned int kBadModulusBits[] = {
483 248, // Too small.
484 257, // Not a multiple of 8.
485 1023, // Not a multiple of 8.
486 0xFFFFFFFF, // Too big.
487 16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
490 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
492 for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
493 const unsigned int modulus_length_bits = kBadModulusBits[i];
494 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
495 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
496 blink::WebCryptoAlgorithmIdSha256, modulus_length_bits,
497 public_exponent);
498 bool extractable = true;
499 const blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
500 blink::WebCryptoKey public_key;
501 blink::WebCryptoKey private_key;
503 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
504 GenerateKeyPair(algorithm, extractable, usages, &public_key,
505 &private_key));
509 // Try generating RSA key pairs using unsupported public exponents. Only
510 // exponents of 3 and 65537 are supported. While both OpenSSL and NSS can
511 // support other values, OpenSSL hangs when given invalid exponents, so use a
512 // whitelist to validate the parameters.
513 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
514 const unsigned int modulus_length = 1024;
516 const char* const kPublicExponents[] = {
517 "11", // 17 - This is a valid public exponent, but currently disallowed.
518 "00",
519 "01",
520 "02",
521 "010000", // 65536
524 for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
525 SCOPED_TRACE(i);
526 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
527 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
528 blink::WebCryptoAlgorithmIdSha256, modulus_length,
529 HexStringToBytes(kPublicExponents[i]));
531 blink::WebCryptoKey public_key;
532 blink::WebCryptoKey private_key;
534 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
535 GenerateKeyPair(algorithm, true, blink::WebCryptoKeyUsageSign,
536 &public_key, &private_key));
540 TEST(WebCryptoRsaSsaTest, SignVerifyFailures) {
541 if (!SupportsRsaPrivateKeyImport())
542 return;
544 // Import a key pair.
545 blink::WebCryptoAlgorithm import_algorithm =
546 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
547 blink::WebCryptoAlgorithmIdSha1);
548 blink::WebCryptoKey public_key;
549 blink::WebCryptoKey private_key;
550 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
551 HexStringToBytes(kPublicKeySpkiDerHex),
552 HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
553 blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
554 &private_key));
556 blink::WebCryptoAlgorithm algorithm =
557 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
559 std::vector<uint8_t> signature;
560 bool signature_match;
562 // Compute a signature.
563 const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
564 ASSERT_EQ(Status::Success(),
565 Sign(algorithm, private_key, CryptoData(data), &signature));
567 // Ensure truncated signature does not verify by passing one less byte.
568 EXPECT_EQ(Status::Success(), Verify(algorithm, public_key,
569 CryptoData(vector_as_array(&signature),
570 signature.size() - 1),
571 CryptoData(data), &signature_match));
572 EXPECT_FALSE(signature_match);
574 // Ensure truncated signature does not verify by passing no bytes.
575 EXPECT_EQ(Status::Success(), Verify(algorithm, public_key, CryptoData(),
576 CryptoData(data), &signature_match));
577 EXPECT_FALSE(signature_match);
579 // Ensure corrupted signature does not verify.
580 std::vector<uint8_t> corrupt_sig = signature;
581 corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
582 EXPECT_EQ(Status::Success(),
583 Verify(algorithm, public_key, CryptoData(corrupt_sig),
584 CryptoData(data), &signature_match));
585 EXPECT_FALSE(signature_match);
587 // Ensure signatures that are greater than the modulus size fail.
588 const unsigned int long_message_size_bytes = 1024;
589 DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
590 const unsigned char kLongSignature[long_message_size_bytes] = {0};
591 EXPECT_EQ(Status::Success(),
592 Verify(algorithm, public_key,
593 CryptoData(kLongSignature, sizeof(kLongSignature)),
594 CryptoData(data), &signature_match));
595 EXPECT_FALSE(signature_match);
597 // Ensure that signing and verifying with an incompatible algorithm fails.
598 algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
600 EXPECT_EQ(Status::ErrorUnexpected(),
601 Sign(algorithm, private_key, CryptoData(data), &signature));
602 EXPECT_EQ(Status::ErrorUnexpected(),
603 Verify(algorithm, public_key, CryptoData(signature),
604 CryptoData(data), &signature_match));
606 // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
607 // based solely on the contents of the input signature data. In the Web Crypto
608 // implementation, the inner hash should be specified uniquely by the key
609 // algorithm parameter. To validate this behavior, call Verify with a computed
610 // signature that used one hash type (SHA-1), but pass in a key with a
611 // different inner hash type (SHA-256). If the hash type is determined by the
612 // signature itself (undesired), the verify will pass, while if the hash type
613 // is specified by the key algorithm (desired), the verify will fail.
615 // Compute a signature using SHA-1 as the inner hash.
616 EXPECT_EQ(Status::Success(),
617 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
618 private_key, CryptoData(data), &signature));
620 blink::WebCryptoKey public_key_256;
621 EXPECT_EQ(Status::Success(),
622 ImportKey(blink::WebCryptoKeyFormatSpki,
623 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
624 CreateRsaHashedImportAlgorithm(
625 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
626 blink::WebCryptoAlgorithmIdSha256),
627 true, blink::WebCryptoKeyUsageVerify, &public_key_256));
629 // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
630 // signature should not verify.
631 // NOTE: public_key was produced by generateKey, and so its associated
632 // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
633 // it has no inner hash to conflict with the input algorithm.
634 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
635 private_key.algorithm().rsaHashedParams()->hash().id());
636 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
637 public_key_256.algorithm().rsaHashedParams()->hash().id());
639 bool is_match;
640 EXPECT_EQ(Status::Success(),
641 Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
642 public_key_256, CryptoData(signature), CryptoData(data),
643 &is_match));
644 EXPECT_FALSE(is_match);
647 TEST(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
648 if (!SupportsRsaPrivateKeyImport())
649 return;
651 scoped_ptr<base::ListValue> tests;
652 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
654 // Import the key pair.
655 blink::WebCryptoAlgorithm import_algorithm =
656 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
657 blink::WebCryptoAlgorithmIdSha1);
658 blink::WebCryptoKey public_key;
659 blink::WebCryptoKey private_key;
660 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
661 HexStringToBytes(kPublicKeySpkiDerHex),
662 HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false,
663 blink::WebCryptoKeyUsageVerify, blink::WebCryptoKeyUsageSign, &public_key,
664 &private_key));
666 blink::WebCryptoAlgorithm algorithm =
667 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
669 // Validate the signatures are computed and verified as expected.
670 std::vector<uint8_t> signature;
671 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
672 SCOPED_TRACE(test_index);
674 base::DictionaryValue* test;
675 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
677 std::vector<uint8_t> test_message =
678 GetBytesFromHexString(test, "message_hex");
679 std::vector<uint8_t> test_signature =
680 GetBytesFromHexString(test, "signature_hex");
682 signature.clear();
683 ASSERT_EQ(Status::Success(), Sign(algorithm, private_key,
684 CryptoData(test_message), &signature));
685 EXPECT_BYTES_EQ(test_signature, signature);
687 bool is_match = false;
688 ASSERT_EQ(Status::Success(),
689 Verify(algorithm, public_key, CryptoData(test_signature),
690 CryptoData(test_message), &is_match));
691 EXPECT_TRUE(is_match);
695 // Try importing an RSA-SSA public key with unsupported key usages using SPKI
696 // format. RSA-SSA public keys only support the 'verify' usage.
697 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
698 const blink::WebCryptoAlgorithm algorithm =
699 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
700 blink::WebCryptoAlgorithmIdSha256);
702 blink::WebCryptoKeyUsageMask bad_usages[] = {
703 blink::WebCryptoKeyUsageSign,
704 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
705 blink::WebCryptoKeyUsageEncrypt,
706 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
709 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
710 SCOPED_TRACE(i);
712 blink::WebCryptoKey public_key;
713 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
714 ImportKey(blink::WebCryptoKeyFormatSpki,
715 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
716 algorithm, false, bad_usages[i], &public_key));
720 // Try importing an RSA-SSA public key with unsupported key usages using JWK
721 // format. RSA-SSA public keys only support the 'verify' usage.
722 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
723 const blink::WebCryptoAlgorithm algorithm =
724 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
725 blink::WebCryptoAlgorithmIdSha256);
727 blink::WebCryptoKeyUsageMask bad_usages[] = {
728 blink::WebCryptoKeyUsageSign,
729 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
730 blink::WebCryptoKeyUsageEncrypt,
731 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
734 base::DictionaryValue dict;
735 RestoreJwkRsaDictionary(&dict);
736 dict.Remove("use", NULL);
737 dict.SetString("alg", "RS256");
739 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
740 SCOPED_TRACE(i);
742 blink::WebCryptoKey public_key;
743 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
744 ImportKeyJwkFromDict(dict, algorithm, false, bad_usages[i],
745 &public_key));
749 // Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
750 // 'sign', 'verify'
751 TEST(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
752 blink::WebCryptoKeyUsageMask bad_usages[] = {
753 blink::WebCryptoKeyUsageDecrypt,
754 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
755 blink::WebCryptoKeyUsageWrapKey,
758 const unsigned int modulus_length = 256;
759 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
761 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
762 SCOPED_TRACE(i);
764 blink::WebCryptoKey public_key;
765 blink::WebCryptoKey private_key;
767 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
768 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
769 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
770 blink::WebCryptoAlgorithmIdSha256,
771 modulus_length, public_exponent),
772 true, bad_usages[i], &public_key, &private_key));
776 // Generate an RSA-SSA key pair. The public and private keys should select the
777 // key usages which are applicable, and not have the exact same usages as was
778 // specified to GenerateKey
779 TEST(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
780 const unsigned int modulus_length = 256;
781 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
783 blink::WebCryptoKey public_key;
784 blink::WebCryptoKey private_key;
786 ASSERT_EQ(Status::Success(),
787 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
788 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
789 blink::WebCryptoAlgorithmIdSha256,
790 modulus_length, public_exponent),
791 true, blink::WebCryptoKeyUsageSign |
792 blink::WebCryptoKeyUsageVerify,
793 &public_key, &private_key));
795 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
796 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
798 // Try again but this time without the Verify usages.
799 ASSERT_EQ(Status::Success(),
800 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
801 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
802 blink::WebCryptoAlgorithmIdSha256,
803 modulus_length, public_exponent),
804 true, blink::WebCryptoKeyUsageSign, &public_key,
805 &private_key));
807 EXPECT_EQ(0, public_key.usages());
808 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
811 TEST(WebCryptoRsaSsaTest, GenerateKeyPairEmptyUsages) {
812 const unsigned int modulus_length = 256;
813 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
815 blink::WebCryptoKey public_key;
816 blink::WebCryptoKey private_key;
818 ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
819 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
820 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
821 blink::WebCryptoAlgorithmIdSha256,
822 modulus_length, public_exponent),
823 true, 0, &public_key, &private_key));
826 TEST(WebCryptoRsaSsaTest, ImportKeyEmptyUsages) {
827 if (!SupportsRsaPrivateKeyImport())
828 return;
830 blink::WebCryptoKey public_key;
831 blink::WebCryptoKey private_key;
833 // Public without usage does not throw an error.
834 ASSERT_EQ(Status::Success(),
835 ImportKey(blink::WebCryptoKeyFormatSpki,
836 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
837 CreateRsaHashedImportAlgorithm(
838 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
839 blink::WebCryptoAlgorithmIdSha256),
840 true, 0, &public_key));
841 EXPECT_EQ(0, public_key.usages());
843 // Private empty usage will throw an error.
844 ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
845 ImportKey(blink::WebCryptoKeyFormatPkcs8,
846 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
847 CreateRsaHashedImportAlgorithm(
848 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
849 blink::WebCryptoAlgorithmIdSha1),
850 true, 0, &private_key));
852 std::vector<uint8_t> public_jwk;
853 ASSERT_EQ(Status::Success(),
854 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &public_jwk));
856 ASSERT_EQ(Status::Success(),
857 ImportKey(blink::WebCryptoKeyFormatJwk,
858 CryptoData(public_jwk),
859 CreateRsaHashedImportAlgorithm(
860 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
861 blink::WebCryptoAlgorithmIdSha256),
862 true, 0, &public_key));
863 EXPECT_EQ(0, public_key.usages());
865 // With correct usage to get correct imported private_key
866 std::vector<uint8_t> private_jwk;
867 ImportKey(blink::WebCryptoKeyFormatPkcs8,
868 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
869 CreateRsaHashedImportAlgorithm(
870 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
871 blink::WebCryptoAlgorithmIdSha1),
872 true, blink::WebCryptoKeyUsageSign, &private_key);
874 ASSERT_EQ(Status::Success(),
875 ExportKey(blink::WebCryptoKeyFormatJwk, private_key, &private_jwk));
877 ASSERT_EQ(Status::ErrorCreateKeyEmptyUsages(),
878 ImportKey(blink::WebCryptoKeyFormatJwk,
879 CryptoData(private_jwk),
880 CreateRsaHashedImportAlgorithm(
881 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
882 blink::WebCryptoAlgorithmIdSha1),
883 true, 0, &private_key));
886 TEST(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
887 struct TestCase {
888 const blink::WebCryptoAlgorithmId hash;
889 const blink::WebCryptoKeyUsageMask usage;
890 const char* const jwk_alg;
892 const TestCase kTests[] = {
893 {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
894 {blink::WebCryptoAlgorithmIdSha256,
895 blink::WebCryptoKeyUsageVerify,
896 "RS256"},
897 {blink::WebCryptoAlgorithmIdSha384,
898 blink::WebCryptoKeyUsageVerify,
899 "RS384"},
900 {blink::WebCryptoAlgorithmIdSha512,
901 blink::WebCryptoKeyUsageVerify,
902 "RS512"}};
904 for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) {
905 SCOPED_TRACE(test_index);
906 const TestCase& test = kTests[test_index];
908 const blink::WebCryptoAlgorithm import_algorithm =
909 CreateRsaHashedImportAlgorithm(
910 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
912 // Import the spki to create a public key
913 blink::WebCryptoKey public_key;
914 ASSERT_EQ(Status::Success(),
915 ImportKey(blink::WebCryptoKeyFormatSpki,
916 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
917 import_algorithm, true, test.usage, &public_key));
919 // Export the public key as JWK and verify its contents
920 std::vector<uint8_t> jwk;
921 ASSERT_EQ(Status::Success(),
922 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
923 EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex,
924 kPublicKeyExponentHex, test.usage));
926 // Import the JWK back in to create a new key
927 blink::WebCryptoKey public_key2;
928 ASSERT_EQ(Status::Success(),
929 ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk),
930 import_algorithm, true, test.usage, &public_key2));
931 ASSERT_TRUE(public_key2.handle());
932 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
933 EXPECT_TRUE(public_key2.extractable());
934 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
936 // Export the new key as spki and compare to the original.
937 std::vector<uint8_t> spki;
938 ASSERT_EQ(Status::Success(),
939 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
940 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
944 TEST(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
945 base::DictionaryValue dict;
946 RestoreJwkRsaDictionary(&dict);
947 blink::WebCryptoAlgorithm algorithm =
948 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
949 blink::WebCryptoAlgorithmIdSha256);
950 blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageVerify;
951 blink::WebCryptoKey key;
953 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
954 // entry, while an RSA private key must have those plus at least a "d"
955 // (private exponent) entry.
956 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
957 // section 6.3.
959 // Baseline pass.
960 EXPECT_EQ(Status::Success(),
961 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
962 EXPECT_EQ(algorithm.id(), key.algorithm().id());
963 EXPECT_FALSE(key.extractable());
964 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
965 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
967 // The following are specific failure cases for when kty = "RSA".
969 // Fail if either "n" or "e" is not present or malformed.
970 const std::string kKtyParmName[] = {"n", "e"};
971 for (size_t idx = 0; idx < arraysize(kKtyParmName); ++idx) {
972 // Fail on missing parameter.
973 dict.Remove(kKtyParmName[idx], NULL);
974 EXPECT_NE(Status::Success(),
975 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
976 RestoreJwkRsaDictionary(&dict);
978 // Fail on bad b64 parameter encoding.
979 dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
980 EXPECT_NE(Status::Success(),
981 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
982 RestoreJwkRsaDictionary(&dict);
984 // Fail on empty parameter.
985 dict.SetString(kKtyParmName[idx], "");
986 EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
987 ImportKeyJwkFromDict(dict, algorithm, false, usages, &key));
988 RestoreJwkRsaDictionary(&dict);
992 // Try importing an RSA-SSA key from JWK format, having specified both Sign and
993 // Verify usage, and an invalid JWK.
995 // The test must fail with a usage error BEFORE attempting to read the JWK data.
996 // Although both Sign and Verify are valid usages for RSA-SSA keys, it is
997 // invalid to have them both at the same time for one key (since Sign applies to
998 // private keys, whereas Verify applies to public keys).
1000 // If the implementation does not fail fast, this test will crash dereferencing
1001 // invalid memory.
1002 TEST(WebCryptoRsaSsaTest, ImportRsaSsaJwkBadUsageFailFast) {
1003 CryptoData bad_data(NULL, 128); // Invalid buffer of length 128.
1005 blink::WebCryptoKey key;
1006 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
1007 ImportKey(blink::WebCryptoKeyFormatJwk, bad_data,
1008 CreateRsaHashedImportAlgorithm(
1009 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1010 blink::WebCryptoAlgorithmIdSha256),
1011 true, blink::WebCryptoKeyUsageVerify |
1012 blink::WebCryptoKeyUsageSign,
1013 &key));
1016 // Imports invalid JWK/SPKI/PKCS8 data and verifies that it fails as expected.
1017 TEST(WebCryptoRsaSsaTest, ImportInvalidKeyData) {
1018 if (!SupportsRsaPrivateKeyImport())
1019 return;
1021 scoped_ptr<base::ListValue> tests;
1022 ASSERT_TRUE(ReadJsonTestFileToList("bad_rsa_keys.json", &tests));
1024 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
1025 SCOPED_TRACE(test_index);
1027 const base::DictionaryValue* test;
1028 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
1030 blink::WebCryptoKeyFormat key_format = GetKeyFormatFromJsonTestCase(test);
1031 std::vector<uint8_t> key_data =
1032 GetKeyDataFromJsonTestCase(test, key_format);
1033 std::string test_error;
1034 ASSERT_TRUE(test->GetString("error", &test_error));
1036 blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
1037 if (key_format == blink::WebCryptoKeyFormatSpki)
1038 usages = blink::WebCryptoKeyUsageVerify;
1039 blink::WebCryptoKey key;
1040 Status status = ImportKey(key_format, CryptoData(key_data),
1041 CreateRsaHashedImportAlgorithm(
1042 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1043 blink::WebCryptoAlgorithmIdSha256),
1044 true, usages, &key);
1045 EXPECT_EQ(test_error, StatusToString(status));
1049 } // namespace
1051 } // namespace webcrypto
1053 } // namespace content