Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: content/child/webcrypto/test/aes_kw_unittest.cc

Issue 489643002: [refactor] Split up a large (5k lines) unit-test into multiple files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile error (by removing NSS ifdefed code) Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm>
6 #include <string>
7 #include <vector>
8
9 #include "base/basictypes.h"
10 #include "base/file_util.h"
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/path_service.h"
16 #include "base/stl_util.h" 5 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "content/child/webcrypto/algorithm_dispatch.h" 6 #include "content/child/webcrypto/algorithm_dispatch.h"
21 #include "content/child/webcrypto/crypto_data.h" 7 #include "content/child/webcrypto/crypto_data.h"
22 #include "content/child/webcrypto/status.h" 8 #include "content/child/webcrypto/status.h"
9 #include "content/child/webcrypto/test/test_helpers.h"
23 #include "content/child/webcrypto/webcrypto_util.h" 10 #include "content/child/webcrypto/webcrypto_util.h"
24 #include "content/public/common/content_paths.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
27 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
28 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
29 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
30 #include "third_party/re2/re2/re2.h"
31
32 #if !defined(USE_OPENSSL)
33 #include <nss.h>
34 #include <pk11pub.h>
35
36 #include "crypto/nss_util.h"
37 #include "crypto/scoped_nss_types.h"
38 #endif
39
40 #define EXPECT_BYTES_EQ(expected, actual) \
41 EXPECT_EQ(CryptoData(expected), CryptoData(actual))
42
43 #define EXPECT_BYTES_EQ_HEX(expected_hex, actual_bytes) \
44 EXPECT_BYTES_EQ(HexStringToBytes(expected_hex), actual_bytes)
45 13
46 namespace content { 14 namespace content {
47 15
48 namespace webcrypto { 16 namespace webcrypto {
49 17
50 // These functions are used by GTEST to support EXPECT_EQ() for
51 // webcrypto::Status and webcrypto::CryptoData
52
53 void PrintTo(const Status& status, ::std::ostream* os) {
54 if (status.IsSuccess())
55 *os << "Success";
56 else
57 *os << "Error type: " << status.error_type()
58 << " Error details: " << status.error_details();
59 }
60
61 bool operator==(const Status& a, const Status& b) {
62 if (a.IsSuccess() != b.IsSuccess())
63 return false;
64 if (a.IsSuccess())
65 return true;
66 return a.error_type() == b.error_type() &&
67 a.error_details() == b.error_details();
68 }
69
70 bool operator!=(const Status& a, const Status& b) {
71 return !(a == b);
72 }
73
74 void PrintTo(const CryptoData& data, ::std::ostream* os) {
75 *os << "[" << base::HexEncode(data.bytes(), data.byte_length()) << "]";
76 }
77
78 bool operator==(const CryptoData& a, const CryptoData& b) {
79 return a.byte_length() == b.byte_length() &&
80 memcmp(a.bytes(), b.bytes(), a.byte_length()) == 0;
81 }
82
83 bool operator!=(const CryptoData& a, const CryptoData& b) {
84 return !(a == b);
85 }
86
87 namespace { 18 namespace {
88 19
89 // -----------------------------------------------------------------------------
90
91 // TODO(eroman): For Linux builds using system NSS, AES-GCM support is a
92 // runtime dependency. Test it by trying to import a key.
93 // TODO(padolph): Consider caching the result of the import key test.
94 bool SupportsAesGcm() {
95 std::vector<uint8_t> key_raw(16, 0);
96
97 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
98 Status status = ImportKey(blink::WebCryptoKeyFormatRaw,
99 CryptoData(key_raw),
100 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
101 true,
102 blink::WebCryptoKeyUsageEncrypt,
103 &key);
104
105 if (status.IsError())
106 EXPECT_EQ(blink::WebCryptoErrorTypeNotSupported, status.error_type());
107 return status.IsSuccess();
108 }
109
110 bool SupportsRsaOaep() {
111 #if defined(USE_OPENSSL)
112 return true;
113 #else
114 crypto::EnsureNSSInit();
115 // TODO(eroman): Exclude version test for OS_CHROMEOS
116 #if defined(USE_NSS)
117 if (!NSS_VersionCheck("3.16.2"))
118 return false;
119 #endif
120 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
121 return !!PK11_DoesMechanism(slot.get(), CKM_RSA_PKCS_OAEP);
122 #endif
123 }
124
125 bool SupportsRsaPrivateKeyImport() {
126 // TODO(eroman): Exclude version test for OS_CHROMEOS
127 #if defined(USE_NSS)
128 crypto::EnsureNSSInit();
129 if (!NSS_VersionCheck("3.16.2")) {
130 LOG(WARNING) << "RSA key import is not supported by this version of NSS. "
131 "Skipping some tests";
132 return false;
133 }
134 #endif
135 return true;
136 }
137
138 blink::WebCryptoAlgorithm CreateRsaHashedKeyGenAlgorithm(
139 blink::WebCryptoAlgorithmId algorithm_id,
140 const blink::WebCryptoAlgorithmId hash_id,
141 unsigned int modulus_length,
142 const std::vector<uint8_t>& public_exponent) {
143 DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
144 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep);
145 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
146 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
147 algorithm_id,
148 new blink::WebCryptoRsaHashedKeyGenParams(
149 CreateAlgorithm(hash_id),
150 modulus_length,
151 vector_as_array(&public_exponent),
152 public_exponent.size()));
153 }
154
155 // Creates an RSA-OAEP algorithm
156 blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
157 const std::vector<uint8_t>& label) {
158 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
159 blink::WebCryptoAlgorithmIdRsaOaep,
160 new blink::WebCryptoRsaOaepParams(
161 !label.empty(), vector_as_array(&label), label.size()));
162 }
163
164 // Creates an AES-CBC algorithm.
165 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
166 const std::vector<uint8_t>& iv) {
167 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
168 blink::WebCryptoAlgorithmIdAesCbc,
169 new blink::WebCryptoAesCbcParams(vector_as_array(&iv), iv.size()));
170 }
171
172 // Creates an AES-GCM algorithm.
173 blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
174 const std::vector<uint8_t>& iv,
175 const std::vector<uint8_t>& additional_data,
176 unsigned int tag_length_bits) {
177 EXPECT_TRUE(SupportsAesGcm());
178 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
179 blink::WebCryptoAlgorithmIdAesGcm,
180 new blink::WebCryptoAesGcmParams(vector_as_array(&iv),
181 iv.size(),
182 true,
183 vector_as_array(&additional_data),
184 additional_data.size(),
185 true,
186 tag_length_bits));
187 }
188
189 // Creates an HMAC algorithm whose parameters struct is compatible with key
190 // generation. It is an error to call this with a hash_id that is not a SHA*.
191 // The key_length_bits parameter is optional, with zero meaning unspecified.
192 blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
193 blink::WebCryptoAlgorithmId hash_id,
194 unsigned int key_length_bits) {
195 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
196 // key_length_bytes == 0 means unspecified
197 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
198 blink::WebCryptoAlgorithmIdHmac,
199 new blink::WebCryptoHmacKeyGenParams(
200 CreateAlgorithm(hash_id), (key_length_bits != 0), key_length_bits));
201 }
202
203 // Returns a slightly modified version of the input vector.
204 //
205 // - For non-empty inputs a single bit is inverted.
206 // - For empty inputs, a byte is added.
207 std::vector<uint8_t> Corrupted(const std::vector<uint8_t>& input) {
208 std::vector<uint8_t> corrupted_data(input);
209 if (corrupted_data.empty())
210 corrupted_data.push_back(0);
211 corrupted_data[corrupted_data.size() / 2] ^= 0x01;
212 return corrupted_data;
213 }
214
215 std::vector<uint8_t> HexStringToBytes(const std::string& hex) {
216 std::vector<uint8_t> bytes;
217 base::HexStringToBytes(hex, &bytes);
218 return bytes;
219 }
220
221 std::vector<uint8_t> MakeJsonVector(const std::string& json_string) {
222 return std::vector<uint8_t>(json_string.begin(), json_string.end());
223 }
224
225 std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) {
226 std::string json;
227 base::JSONWriter::Write(&dict, &json);
228 return MakeJsonVector(json);
229 }
230
231 // ----------------------------------------------------------------
232 // Helpers for working with JSON data files for test expectations.
233 // ----------------------------------------------------------------
234
235 // Reads a file in "src/content/test/data/webcrypto" to a base::Value.
236 // The file must be JSON, however it can also include C++ style comments.
237 ::testing::AssertionResult ReadJsonTestFile(const char* test_file_name,
238 scoped_ptr<base::Value>* value) {
239 base::FilePath test_data_dir;
240 if (!PathService::Get(DIR_TEST_DATA, &test_data_dir))
241 return ::testing::AssertionFailure() << "Couldn't retrieve test dir";
242
243 base::FilePath file_path =
244 test_data_dir.AppendASCII("webcrypto").AppendASCII(test_file_name);
245
246 std::string file_contents;
247 if (!base::ReadFileToString(file_path, &file_contents)) {
248 return ::testing::AssertionFailure()
249 << "Couldn't read test file: " << file_path.value();
250 }
251
252 // Strip C++ style comments out of the "json" file, otherwise it cannot be
253 // parsed.
254 re2::RE2::GlobalReplace(&file_contents, re2::RE2("\\s*//.*"), "");
255
256 // Parse the JSON to a dictionary.
257 value->reset(base::JSONReader::Read(file_contents));
258 if (!value->get()) {
259 return ::testing::AssertionFailure()
260 << "Couldn't parse test file JSON: " << file_path.value();
261 }
262
263 return ::testing::AssertionSuccess();
264 }
265
266 // Same as ReadJsonTestFile(), but return the value as a List.
267 ::testing::AssertionResult ReadJsonTestFileToList(
268 const char* test_file_name,
269 scoped_ptr<base::ListValue>* list) {
270 // Read the JSON.
271 scoped_ptr<base::Value> json;
272 ::testing::AssertionResult result = ReadJsonTestFile(test_file_name, &json);
273 if (!result)
274 return result;
275
276 // Cast to an ListValue.
277 base::ListValue* list_value = NULL;
278 if (!json->GetAsList(&list_value) || !list_value)
279 return ::testing::AssertionFailure() << "The JSON was not a list";
280
281 list->reset(list_value);
282 ignore_result(json.release());
283
284 return ::testing::AssertionSuccess();
285 }
286
287 // Read a string property from the dictionary with path |property_name|
288 // (which can include periods for nested dictionaries). Interprets the
289 // string as a hex encoded string and converts it to a bytes list.
290 //
291 // Returns empty vector on failure.
292 std::vector<uint8_t> GetBytesFromHexString(base::DictionaryValue* dict,
293 const char* property_name) {
294 std::string hex_string;
295 if (!dict->GetString(property_name, &hex_string)) {
296 EXPECT_TRUE(false) << "Couldn't get string property: " << property_name;
297 return std::vector<uint8_t>();
298 }
299
300 return HexStringToBytes(hex_string);
301 }
302
303 // Reads a string property with path "property_name" and converts it to a
304 // WebCryptoAlgorith. Returns null algorithm on failure.
305 blink::WebCryptoAlgorithm GetDigestAlgorithm(base::DictionaryValue* dict,
306 const char* property_name) {
307 std::string algorithm_name;
308 if (!dict->GetString(property_name, &algorithm_name)) {
309 EXPECT_TRUE(false) << "Couldn't get string property: " << property_name;
310 return blink::WebCryptoAlgorithm::createNull();
311 }
312
313 struct {
314 const char* name;
315 blink::WebCryptoAlgorithmId id;
316 } kDigestNameToId[] = {
317 {"sha-1", blink::WebCryptoAlgorithmIdSha1},
318 {"sha-256", blink::WebCryptoAlgorithmIdSha256},
319 {"sha-384", blink::WebCryptoAlgorithmIdSha384},
320 {"sha-512", blink::WebCryptoAlgorithmIdSha512},
321 };
322
323 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDigestNameToId); ++i) {
324 if (kDigestNameToId[i].name == algorithm_name)
325 return CreateAlgorithm(kDigestNameToId[i].id);
326 }
327
328 return blink::WebCryptoAlgorithm::createNull();
329 }
330
331 // Helper for ImportJwkRsaFailures. Restores the JWK JSON
332 // dictionary to a good state
333 void RestoreJwkRsaDictionary(base::DictionaryValue* dict) {
334 dict->Clear();
335 dict->SetString("kty", "RSA");
336 dict->SetString("alg", "RS256");
337 dict->SetString("use", "sig");
338 dict->SetBoolean("ext", false);
339 dict->SetString(
340 "n",
341 "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
342 "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
343 "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
344 dict->SetString("e", "AQAB");
345 }
346
347 // Returns true if any of the vectors in the input list have identical content.
348 // Dumb O(n^2) implementation but should be fast enough for the input sizes that
349 // are used.
350 bool CopiesExist(const std::vector<std::vector<uint8_t> >& bufs) {
351 for (size_t i = 0; i < bufs.size(); ++i) {
352 for (size_t j = i + 1; j < bufs.size(); ++j) {
353 if (CryptoData(bufs[i]) == CryptoData(bufs[j]))
354 return true;
355 }
356 }
357 return false;
358 }
359
360 blink::WebCryptoAlgorithm CreateAesKeyGenAlgorithm(
361 blink::WebCryptoAlgorithmId aes_alg_id,
362 unsigned short length) {
363 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
364 aes_alg_id, new blink::WebCryptoAesKeyGenParams(length));
365 }
366
367 blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
368 unsigned short key_length_bits) {
369 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc,
370 key_length_bits);
371 }
372
373 blink::WebCryptoAlgorithm CreateAesGcmKeyGenAlgorithm(
374 unsigned short key_length_bits) {
375 EXPECT_TRUE(SupportsAesGcm());
376 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesGcm,
377 key_length_bits);
378 }
379
380 blink::WebCryptoAlgorithm CreateAesKwKeyGenAlgorithm( 20 blink::WebCryptoAlgorithm CreateAesKwKeyGenAlgorithm(
381 unsigned short key_length_bits) { 21 unsigned short key_length_bits) {
382 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesKw, 22 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesKw,
383 key_length_bits); 23 key_length_bits);
384 } 24 }
385 25
386 // The following key pair is comprised of the SPKI (public key) and PKCS#8
387 // (private key) representations of the key pair provided in Example 1 of the
388 // NIST test vectors at
389 // ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
390 const unsigned int kModulusLengthBits = 1024;
391 const char* const kPublicKeySpkiDerHex =
392 "30819f300d06092a864886f70d010101050003818d0030818902818100a5"
393 "6e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad9"
394 "91d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfc"
395 "e0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e"
396 "6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cf"
397 "fb2249bd9a21370203010001";
398 const char* const kPrivateKeyPkcs8DerHex =
399 "30820275020100300d06092a864886f70d01010105000482025f3082025b"
400 "02010002818100a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52"
401 "a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab"
402 "7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921c"
403 "b23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef"
404 "22e1e1f20d0ce8cffb2249bd9a2137020301000102818033a5042a90b27d"
405 "4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c"
406 "568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee"
407 "896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31"
408 "b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b3"
409 "25024100e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e8629"
410 "6b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b"
411 "3b6dcd3eda8e6443024100b69dca1cf7d4d7ec81e75b90fcca874abcde12"
412 "3fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc72"
413 "3e6963364a1f9425452b269a6799fd024028fa13938655be1f8a159cbaca"
414 "5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8d"
415 "d3ede2448328f385d81b30e8e43b2fffa02786197902401a8b38f398fa71"
416 "2049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd"
417 "48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729024027"
418 "156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319"
419 "584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24"
420 "a79f4d";
421 // The modulus and exponent (in hex) of kPublicKeySpkiDerHex
422 const char* const kPublicKeyModulusHex =
423 "A56E4A0E701017589A5187DC7EA841D156F2EC0E36AD52A44DFEB1E61F7AD991D8C51056"
424 "FFEDB162B4C0F283A12A88A394DFF526AB7291CBB307CEABFCE0B1DFD5CD9508096D5B2B"
425 "8B6DF5D671EF6377C0921CB23C270A70E2598E6FF89D19F105ACC2D3F0CB35F29280E138"
426 "6B6F64C4EF22E1E1F20D0CE8CFFB2249BD9A2137";
427 const char* const kPublicKeyExponentHex = "010001";
428
429 blink::WebCryptoKey ImportSecretKeyFromRaw(
430 const std::vector<uint8_t>& key_raw,
431 const blink::WebCryptoAlgorithm& algorithm,
432 blink::WebCryptoKeyUsageMask usage) {
433 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
434 bool extractable = true;
435 EXPECT_EQ(Status::Success(),
436 ImportKey(blink::WebCryptoKeyFormatRaw,
437 CryptoData(key_raw),
438 algorithm,
439 extractable,
440 usage,
441 &key));
442
443 EXPECT_FALSE(key.isNull());
444 EXPECT_TRUE(key.handle());
445 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
446 EXPECT_EQ(algorithm.id(), key.algorithm().id());
447 EXPECT_EQ(extractable, key.extractable());
448 EXPECT_EQ(usage, key.usages());
449 return key;
450 }
451
452 void ImportRsaKeyPair(const std::vector<uint8_t>& spki_der,
453 const std::vector<uint8_t>& pkcs8_der,
454 const blink::WebCryptoAlgorithm& algorithm,
455 bool extractable,
456 blink::WebCryptoKeyUsageMask public_key_usage_mask,
457 blink::WebCryptoKeyUsageMask private_key_usage_mask,
458 blink::WebCryptoKey* public_key,
459 blink::WebCryptoKey* private_key) {
460 ASSERT_EQ(Status::Success(),
461 ImportKey(blink::WebCryptoKeyFormatSpki,
462 CryptoData(spki_der),
463 algorithm,
464 true,
465 public_key_usage_mask,
466 public_key));
467 EXPECT_FALSE(public_key->isNull());
468 EXPECT_TRUE(public_key->handle());
469 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key->type());
470 EXPECT_EQ(algorithm.id(), public_key->algorithm().id());
471 EXPECT_TRUE(public_key->extractable());
472 EXPECT_EQ(public_key_usage_mask, public_key->usages());
473
474 ASSERT_EQ(Status::Success(),
475 ImportKey(blink::WebCryptoKeyFormatPkcs8,
476 CryptoData(pkcs8_der),
477 algorithm,
478 extractable,
479 private_key_usage_mask,
480 private_key));
481 EXPECT_FALSE(private_key->isNull());
482 EXPECT_TRUE(private_key->handle());
483 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key->type());
484 EXPECT_EQ(algorithm.id(), private_key->algorithm().id());
485 EXPECT_EQ(extractable, private_key->extractable());
486 EXPECT_EQ(private_key_usage_mask, private_key->usages());
487 }
488
489 Status AesGcmEncrypt(const blink::WebCryptoKey& key,
490 const std::vector<uint8_t>& iv,
491 const std::vector<uint8_t>& additional_data,
492 unsigned int tag_length_bits,
493 const std::vector<uint8_t>& plain_text,
494 std::vector<uint8_t>* cipher_text,
495 std::vector<uint8_t>* authentication_tag) {
496 EXPECT_TRUE(SupportsAesGcm());
497 blink::WebCryptoAlgorithm algorithm =
498 CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
499
500 std::vector<uint8_t> output;
501 Status status = Encrypt(algorithm, key, CryptoData(plain_text), &output);
502 if (status.IsError())
503 return status;
504
505 if ((tag_length_bits % 8) != 0) {
506 EXPECT_TRUE(false) << "Encrypt should have failed.";
507 return Status::OperationError();
508 }
509
510 size_t tag_length_bytes = tag_length_bits / 8;
511
512 if (tag_length_bytes > output.size()) {
513 EXPECT_TRUE(false) << "tag length is larger than output";
514 return Status::OperationError();
515 }
516
517 // The encryption result is cipher text with authentication tag appended.
518 cipher_text->assign(output.begin(),
519 output.begin() + (output.size() - tag_length_bytes));
520 authentication_tag->assign(output.begin() + cipher_text->size(),
521 output.end());
522
523 return Status::Success();
524 }
525
526 Status AesGcmDecrypt(const blink::WebCryptoKey& key,
527 const std::vector<uint8_t>& iv,
528 const std::vector<uint8_t>& additional_data,
529 unsigned int tag_length_bits,
530 const std::vector<uint8_t>& cipher_text,
531 const std::vector<uint8_t>& authentication_tag,
532 std::vector<uint8_t>* plain_text) {
533 EXPECT_TRUE(SupportsAesGcm());
534 blink::WebCryptoAlgorithm algorithm =
535 CreateAesGcmAlgorithm(iv, additional_data, tag_length_bits);
536
537 // Join cipher text and authentication tag.
538 std::vector<uint8_t> cipher_text_with_tag;
539 cipher_text_with_tag.reserve(cipher_text.size() + authentication_tag.size());
540 cipher_text_with_tag.insert(
541 cipher_text_with_tag.end(), cipher_text.begin(), cipher_text.end());
542 cipher_text_with_tag.insert(cipher_text_with_tag.end(),
543 authentication_tag.begin(),
544 authentication_tag.end());
545
546 return Decrypt(algorithm, key, CryptoData(cipher_text_with_tag), plain_text);
547 }
548
549 Status ImportKeyJwk(const CryptoData& key_data,
550 const blink::WebCryptoAlgorithm& algorithm,
551 bool extractable,
552 blink::WebCryptoKeyUsageMask usage_mask,
553 blink::WebCryptoKey* key) {
554 return ImportKey(blink::WebCryptoKeyFormatJwk,
555 key_data,
556 algorithm,
557 extractable,
558 usage_mask,
559 key);
560 }
561
562 Status ImportKeyJwkFromDict(const base::DictionaryValue& dict,
563 const blink::WebCryptoAlgorithm& algorithm,
564 bool extractable,
565 blink::WebCryptoKeyUsageMask usage_mask,
566 blink::WebCryptoKey* key) {
567 return ImportKeyJwk(CryptoData(MakeJsonVector(dict)),
568 algorithm,
569 extractable,
570 usage_mask,
571 key);
572 }
573
574 // Parses a vector of JSON into a dictionary.
575 scoped_ptr<base::DictionaryValue> GetJwkDictionary(
576 const std::vector<uint8_t>& json) {
577 base::StringPiece json_string(
578 reinterpret_cast<const char*>(vector_as_array(&json)), json.size());
579 base::Value* value = base::JSONReader::Read(json_string);
580 EXPECT_TRUE(value);
581 base::DictionaryValue* dict_value = NULL;
582 value->GetAsDictionary(&dict_value);
583 return scoped_ptr<base::DictionaryValue>(dict_value);
584 }
585
586 // Verifies the input dictionary contains the expected values. Exact matches are
587 // required on the fields examined.
588 ::testing::AssertionResult VerifyJwk(
589 const scoped_ptr<base::DictionaryValue>& dict,
590 const std::string& kty_expected,
591 const std::string& alg_expected,
592 blink::WebCryptoKeyUsageMask use_mask_expected) {
593 // ---- kty
594 std::string value_string;
595 if (!dict->GetString("kty", &value_string))
596 return ::testing::AssertionFailure() << "Missing 'kty'";
597 if (value_string != kty_expected)
598 return ::testing::AssertionFailure() << "Expected 'kty' to be "
599 << kty_expected << "but found "
600 << value_string;
601
602 // ---- alg
603 if (!dict->GetString("alg", &value_string))
604 return ::testing::AssertionFailure() << "Missing 'alg'";
605 if (value_string != alg_expected)
606 return ::testing::AssertionFailure() << "Expected 'alg' to be "
607 << alg_expected << " but found "
608 << value_string;
609
610 // ---- ext
611 // always expect ext == true in this case
612 bool ext_value;
613 if (!dict->GetBoolean("ext", &ext_value))
614 return ::testing::AssertionFailure() << "Missing 'ext'";
615 if (!ext_value)
616 return ::testing::AssertionFailure()
617 << "Expected 'ext' to be true but found false";
618
619 // ---- key_ops
620 base::ListValue* key_ops;
621 if (!dict->GetList("key_ops", &key_ops))
622 return ::testing::AssertionFailure() << "Missing 'key_ops'";
623 blink::WebCryptoKeyUsageMask key_ops_mask = 0;
624 Status status = GetWebCryptoUsagesFromJwkKeyOps(key_ops, &key_ops_mask);
625 if (status.IsError())
626 return ::testing::AssertionFailure() << "Failure extracting 'key_ops'";
627 if (key_ops_mask != use_mask_expected)
628 return ::testing::AssertionFailure()
629 << "Expected 'key_ops' mask to be " << use_mask_expected
630 << " but found " << key_ops_mask << " (" << value_string << ")";
631
632 return ::testing::AssertionSuccess();
633 }
634
635 // Verifies that the JSON in the input vector contains the provided
636 // expected values. Exact matches are required on the fields examined.
637 ::testing::AssertionResult VerifySecretJwk(
638 const std::vector<uint8_t>& json,
639 const std::string& alg_expected,
640 const std::string& k_expected_hex,
641 blink::WebCryptoKeyUsageMask use_mask_expected) {
642 scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json);
643 if (!dict.get() || dict->empty())
644 return ::testing::AssertionFailure() << "JSON parsing failed";
645
646 // ---- k
647 std::string value_string;
648 if (!dict->GetString("k", &value_string))
649 return ::testing::AssertionFailure() << "Missing 'k'";
650 std::string k_value;
651 if (!Base64DecodeUrlSafe(value_string, &k_value))
652 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(k) failed";
653 if (!LowerCaseEqualsASCII(base::HexEncode(k_value.data(), k_value.size()),
654 k_expected_hex.c_str())) {
655 return ::testing::AssertionFailure() << "Expected 'k' to be "
656 << k_expected_hex
657 << " but found something different";
658 }
659
660 return VerifyJwk(dict, "oct", alg_expected, use_mask_expected);
661 }
662
663 // Verifies that the JSON in the input vector contains the provided
664 // expected values. Exact matches are required on the fields examined.
665 ::testing::AssertionResult VerifyPublicJwk(
666 const std::vector<uint8_t>& json,
667 const std::string& alg_expected,
668 const std::string& n_expected_hex,
669 const std::string& e_expected_hex,
670 blink::WebCryptoKeyUsageMask use_mask_expected) {
671 scoped_ptr<base::DictionaryValue> dict = GetJwkDictionary(json);
672 if (!dict.get() || dict->empty())
673 return ::testing::AssertionFailure() << "JSON parsing failed";
674
675 // ---- n
676 std::string value_string;
677 if (!dict->GetString("n", &value_string))
678 return ::testing::AssertionFailure() << "Missing 'n'";
679 std::string n_value;
680 if (!Base64DecodeUrlSafe(value_string, &n_value))
681 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(n) failed";
682 if (base::HexEncode(n_value.data(), n_value.size()) != n_expected_hex) {
683 return ::testing::AssertionFailure() << "'n' does not match the expected "
684 "value";
685 }
686 // TODO(padolph): LowerCaseEqualsASCII() does not work for above!
687
688 // ---- e
689 if (!dict->GetString("e", &value_string))
690 return ::testing::AssertionFailure() << "Missing 'e'";
691 std::string e_value;
692 if (!Base64DecodeUrlSafe(value_string, &e_value))
693 return ::testing::AssertionFailure() << "Base64DecodeUrlSafe(e) failed";
694 if (!LowerCaseEqualsASCII(base::HexEncode(e_value.data(), e_value.size()),
695 e_expected_hex.c_str())) {
696 return ::testing::AssertionFailure() << "Expected 'e' to be "
697 << e_expected_hex
698 << " but found something different";
699 }
700
701 return VerifyJwk(dict, "RSA", alg_expected, use_mask_expected);
702 }
703
704 // Tests several Status objects against their expected hard coded values, as
705 // well as ensuring that comparison of Status objects works.
706 // Comparison should take into account both the error details, as well as the
707 // error type.
708 TEST(WebCryptoStatusTest, Basic) {
709 // Even though the error message is the same, these should not be considered
710 // the same by the tests because the error type is different.
711 EXPECT_NE(Status::DataError(), Status::OperationError());
712 EXPECT_NE(Status::Success(), Status::OperationError());
713
714 EXPECT_EQ(Status::Success(), Status::Success());
715 EXPECT_EQ(Status::ErrorJwkPropertyWrongType("kty", "string"),
716 Status::ErrorJwkPropertyWrongType("kty", "string"));
717
718 Status status = Status::Success();
719
720 EXPECT_FALSE(status.IsError());
721 EXPECT_EQ("", status.error_details());
722
723 status = Status::OperationError();
724 EXPECT_TRUE(status.IsError());
725 EXPECT_EQ("", status.error_details());
726 EXPECT_EQ(blink::WebCryptoErrorTypeOperation, status.error_type());
727
728 status = Status::DataError();
729 EXPECT_TRUE(status.IsError());
730 EXPECT_EQ("", status.error_details());
731 EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
732
733 status = Status::ErrorUnsupported();
734 EXPECT_TRUE(status.IsError());
735 EXPECT_EQ("The requested operation is unsupported", status.error_details());
736 EXPECT_EQ(blink::WebCryptoErrorTypeNotSupported, status.error_type());
737
738 status = Status::ErrorJwkPropertyMissing("kty");
739 EXPECT_TRUE(status.IsError());
740 EXPECT_EQ("The required JWK property \"kty\" was missing",
741 status.error_details());
742 EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
743
744 status = Status::ErrorJwkPropertyWrongType("kty", "string");
745 EXPECT_TRUE(status.IsError());
746 EXPECT_EQ("The JWK property \"kty\" must be a string",
747 status.error_details());
748 EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
749
750 status = Status::ErrorJwkBase64Decode("n");
751 EXPECT_TRUE(status.IsError());
752 EXPECT_EQ("The JWK property \"n\" could not be base64 decoded",
753 status.error_details());
754 EXPECT_EQ(blink::WebCryptoErrorTypeData, status.error_type());
755 }
756
757 TEST(WebCryptoShaTest, DigestSampleSets) {
758 scoped_ptr<base::ListValue> tests;
759 // TODO(eroman): rename to sha.json
760 ASSERT_TRUE(ReadJsonTestFileToList("digest.json", &tests));
761
762 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
763 SCOPED_TRACE(test_index);
764 base::DictionaryValue* test;
765 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
766
767 blink::WebCryptoAlgorithm test_algorithm =
768 GetDigestAlgorithm(test, "algorithm");
769 std::vector<uint8_t> test_input = GetBytesFromHexString(test, "input");
770 std::vector<uint8_t> test_output = GetBytesFromHexString(test, "output");
771
772 std::vector<uint8_t> output;
773 ASSERT_EQ(Status::Success(),
774 Digest(test_algorithm, CryptoData(test_input), &output));
775 EXPECT_BYTES_EQ(test_output, output);
776 }
777 }
778
779 TEST(WebCryptoShaTest, DigestSampleSetsInChunks) {
780 scoped_ptr<base::ListValue> tests;
781 ASSERT_TRUE(ReadJsonTestFileToList("digest.json", &tests));
782
783 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
784 SCOPED_TRACE(test_index);
785 base::DictionaryValue* test;
786 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
787
788 blink::WebCryptoAlgorithm test_algorithm =
789 GetDigestAlgorithm(test, "algorithm");
790 std::vector<uint8_t> test_input = GetBytesFromHexString(test, "input");
791 std::vector<uint8_t> test_output = GetBytesFromHexString(test, "output");
792
793 // Test the chunk version of the digest functions. Test with 129 byte chunks
794 // because the SHA-512 chunk size is 128 bytes.
795 unsigned char* output;
796 unsigned int output_length;
797 static const size_t kChunkSizeBytes = 129;
798 size_t length = test_input.size();
799 scoped_ptr<blink::WebCryptoDigestor> digestor(
800 CreateDigestor(test_algorithm.id()));
801 std::vector<uint8_t>::iterator begin = test_input.begin();
802 size_t chunk_index = 0;
803 while (begin != test_input.end()) {
804 size_t chunk_length = std::min(kChunkSizeBytes, length - chunk_index);
805 std::vector<uint8_t> chunk(begin, begin + chunk_length);
806 ASSERT_TRUE(chunk.size() > 0);
807 EXPECT_TRUE(digestor->consume(&chunk.front(), chunk.size()));
808 chunk_index = chunk_index + chunk_length;
809 begin = begin + chunk_length;
810 }
811 EXPECT_TRUE(digestor->finish(output, output_length));
812 EXPECT_BYTES_EQ(test_output, CryptoData(output, output_length));
813 }
814 }
815
816 TEST(WebCryptoHmacTest, HMACSampleSets) {
817 scoped_ptr<base::ListValue> tests;
818 ASSERT_TRUE(ReadJsonTestFileToList("hmac.json", &tests));
819 // TODO(padolph): Missing known answer tests for HMAC SHA384, and SHA512.
820 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
821 SCOPED_TRACE(test_index);
822 base::DictionaryValue* test;
823 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
824
825 blink::WebCryptoAlgorithm test_hash = GetDigestAlgorithm(test, "hash");
826 const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
827 const std::vector<uint8_t> test_message =
828 GetBytesFromHexString(test, "message");
829 const std::vector<uint8_t> test_mac = GetBytesFromHexString(test, "mac");
830
831 blink::WebCryptoAlgorithm algorithm =
832 CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac);
833
834 blink::WebCryptoAlgorithm import_algorithm =
835 CreateHmacImportAlgorithm(test_hash.id());
836
837 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
838 test_key,
839 import_algorithm,
840 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify);
841
842 EXPECT_EQ(test_hash.id(), key.algorithm().hmacParams()->hash().id());
843 EXPECT_EQ(test_key.size() * 8, key.algorithm().hmacParams()->lengthBits());
844
845 // Verify exported raw key is identical to the imported data
846 std::vector<uint8_t> raw_key;
847 EXPECT_EQ(Status::Success(),
848 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
849 EXPECT_BYTES_EQ(test_key, raw_key);
850
851 std::vector<uint8_t> output;
852
853 ASSERT_EQ(Status::Success(),
854 Sign(algorithm, key, CryptoData(test_message), &output));
855
856 EXPECT_BYTES_EQ(test_mac, output);
857
858 bool signature_match = false;
859 EXPECT_EQ(Status::Success(),
860 Verify(algorithm,
861 key,
862 CryptoData(output),
863 CryptoData(test_message),
864 &signature_match));
865 EXPECT_TRUE(signature_match);
866
867 // Ensure truncated signature does not verify by passing one less byte.
868 EXPECT_EQ(Status::Success(),
869 Verify(algorithm,
870 key,
871 CryptoData(vector_as_array(&output), output.size() - 1),
872 CryptoData(test_message),
873 &signature_match));
874 EXPECT_FALSE(signature_match);
875
876 // Ensure truncated signature does not verify by passing no bytes.
877 EXPECT_EQ(Status::Success(),
878 Verify(algorithm,
879 key,
880 CryptoData(),
881 CryptoData(test_message),
882 &signature_match));
883 EXPECT_FALSE(signature_match);
884
885 // Ensure extra long signature does not cause issues and fails.
886 const unsigned char kLongSignature[1024] = {0};
887 EXPECT_EQ(Status::Success(),
888 Verify(algorithm,
889 key,
890 CryptoData(kLongSignature, sizeof(kLongSignature)),
891 CryptoData(test_message),
892 &signature_match));
893 EXPECT_FALSE(signature_match);
894 }
895 }
896
897 blink::WebCryptoKey GetTestAesCbcKey() {
898 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c";
899 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
900 HexStringToBytes(key_hex),
901 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
902 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
903
904 // Verify exported raw key is identical to the imported data
905 std::vector<uint8_t> raw_key;
906 EXPECT_EQ(Status::Success(),
907 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
908 EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
909 return key;
910 }
911
912 TEST(WebCryptoAesCbcTest, IvTooSmall) {
913 std::vector<uint8_t> output;
914
915 // Use an invalid |iv| (fewer than 16 bytes)
916 std::vector<uint8_t> input(32);
917 std::vector<uint8_t> iv;
918 EXPECT_EQ(Status::ErrorIncorrectSizeAesCbcIv(),
919 Encrypt(CreateAesCbcAlgorithm(iv),
920 GetTestAesCbcKey(),
921 CryptoData(input),
922 &output));
923 EXPECT_EQ(Status::ErrorIncorrectSizeAesCbcIv(),
924 Decrypt(CreateAesCbcAlgorithm(iv),
925 GetTestAesCbcKey(),
926 CryptoData(input),
927 &output));
928 }
929
930 TEST(WebCryptoAesCbcTest, IvTooLarge) {
931 std::vector<uint8_t> output;
932
933 // Use an invalid |iv| (more than 16 bytes)
934 std::vector<uint8_t> input(32);
935 std::vector<uint8_t> iv(17);
936 EXPECT_EQ(Status::ErrorIncorrectSizeAesCbcIv(),
937 Encrypt(CreateAesCbcAlgorithm(iv),
938 GetTestAesCbcKey(),
939 CryptoData(input),
940 &output));
941 EXPECT_EQ(Status::ErrorIncorrectSizeAesCbcIv(),
942 Decrypt(CreateAesCbcAlgorithm(iv),
943 GetTestAesCbcKey(),
944 CryptoData(input),
945 &output));
946 }
947
948 TEST(WebCryptoAesCbcTest, InputTooLarge) {
949 std::vector<uint8_t> output;
950
951 // Give an input that is too large (would cause integer overflow when
952 // narrowing to an int). Note that both OpenSSL and NSS operate on signed int
953 // lengths.
954 std::vector<uint8_t> iv(16);
955
956 // Pretend the input is large. Don't pass data pointer as NULL in case that
957 // is special cased; the implementation shouldn't actually dereference the
958 // data.
959 CryptoData input(&iv[0], INT_MAX - 3);
960
961 EXPECT_EQ(
962 Status::ErrorDataTooLarge(),
963 Encrypt(CreateAesCbcAlgorithm(iv), GetTestAesCbcKey(), input, &output));
964 EXPECT_EQ(
965 Status::ErrorDataTooLarge(),
966 Decrypt(CreateAesCbcAlgorithm(iv), GetTestAesCbcKey(), input, &output));
967 }
968
969 TEST(WebCryptoAesCbcTest, KeyTooSmall) {
970 std::vector<uint8_t> output;
971
972 // Fail importing the key (too few bytes specified)
973 std::vector<uint8_t> key_raw(1);
974 std::vector<uint8_t> iv(16);
975
976 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
977 EXPECT_EQ(Status::ErrorImportAesKeyLength(),
978 ImportKey(blink::WebCryptoKeyFormatRaw,
979 CryptoData(key_raw),
980 CreateAesCbcAlgorithm(iv),
981 true,
982 blink::WebCryptoKeyUsageEncrypt,
983 &key));
984 }
985
986 TEST(WebCryptoAesCbcTest, ExportKeyUnsupportedFormat) {
987 std::vector<uint8_t> output;
988
989 // Fail exporting the key in SPKI and PKCS#8 formats (not allowed for secret
990 // keys).
991 EXPECT_EQ(
992 Status::ErrorUnsupportedExportKeyFormat(),
993 ExportKey(blink::WebCryptoKeyFormatSpki, GetTestAesCbcKey(), &output));
994 EXPECT_EQ(
995 Status::ErrorUnsupportedExportKeyFormat(),
996 ExportKey(blink::WebCryptoKeyFormatPkcs8, GetTestAesCbcKey(), &output));
997 }
998
999 TEST(WebCryptoAesCbcTest, ImportKeyUnsupportedFormat) {
1000 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1001 ASSERT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
1002 ImportKey(blink::WebCryptoKeyFormatSpki,
1003 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
1004 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1005 true,
1006 blink::WebCryptoKeyUsageEncrypt,
1007 &key));
1008 ASSERT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
1009 ImportKey(blink::WebCryptoKeyFormatPkcs8,
1010 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
1011 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1012 true,
1013 blink::WebCryptoKeyUsageEncrypt,
1014 &key));
1015 }
1016
1017 TEST(WebCryptoAesCbcTest, KnownAnswerEncryptDecrypt) {
1018 scoped_ptr<base::ListValue> tests;
1019 ASSERT_TRUE(ReadJsonTestFileToList("aes_cbc.json", &tests));
1020
1021 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
1022 SCOPED_TRACE(test_index);
1023 base::DictionaryValue* test;
1024 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
1025
1026 std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
1027 std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
1028 std::vector<uint8_t> test_plain_text =
1029 GetBytesFromHexString(test, "plain_text");
1030 std::vector<uint8_t> test_cipher_text =
1031 GetBytesFromHexString(test, "cipher_text");
1032
1033 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
1034 test_key,
1035 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1036 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
1037
1038 EXPECT_EQ(test_key.size() * 8, key.algorithm().aesParams()->lengthBits());
1039
1040 // Verify exported raw key is identical to the imported data
1041 std::vector<uint8_t> raw_key;
1042 EXPECT_EQ(Status::Success(),
1043 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
1044 EXPECT_BYTES_EQ(test_key, raw_key);
1045
1046 std::vector<uint8_t> output;
1047
1048 // Test encryption.
1049 EXPECT_EQ(Status::Success(),
1050 Encrypt(CreateAesCbcAlgorithm(test_iv),
1051 key,
1052 CryptoData(test_plain_text),
1053 &output));
1054 EXPECT_BYTES_EQ(test_cipher_text, output);
1055
1056 // Test decryption.
1057 EXPECT_EQ(Status::Success(),
1058 Decrypt(CreateAesCbcAlgorithm(test_iv),
1059 key,
1060 CryptoData(test_cipher_text),
1061 &output));
1062 EXPECT_BYTES_EQ(test_plain_text, output);
1063 }
1064 }
1065
1066 TEST(WebCryptoAesCbcTest, DecryptTruncatedCipherText) {
1067 scoped_ptr<base::ListValue> tests;
1068 ASSERT_TRUE(ReadJsonTestFileToList("aes_cbc.json", &tests));
1069
1070 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
1071 SCOPED_TRACE(test_index);
1072 base::DictionaryValue* test;
1073 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
1074
1075 std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
1076 std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
1077 std::vector<uint8_t> test_cipher_text =
1078 GetBytesFromHexString(test, "cipher_text");
1079
1080 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
1081 test_key,
1082 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1083 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
1084
1085 std::vector<uint8_t> output;
1086
1087 const unsigned int kAesCbcBlockSize = 16;
1088
1089 // Decrypt with a padding error by stripping the last block. This also ends
1090 // up testing decryption over empty cipher text.
1091 if (test_cipher_text.size() >= kAesCbcBlockSize) {
1092 EXPECT_EQ(Status::OperationError(),
1093 Decrypt(CreateAesCbcAlgorithm(test_iv),
1094 key,
1095 CryptoData(&test_cipher_text[0],
1096 test_cipher_text.size() - kAesCbcBlockSize),
1097 &output));
1098 }
1099
1100 // Decrypt cipher text which is not a multiple of block size by stripping
1101 // a few bytes off the cipher text.
1102 if (test_cipher_text.size() > 3) {
1103 EXPECT_EQ(
1104 Status::OperationError(),
1105 Decrypt(CreateAesCbcAlgorithm(test_iv),
1106 key,
1107 CryptoData(&test_cipher_text[0], test_cipher_text.size() - 3),
1108 &output));
1109 }
1110 }
1111 }
1112
1113 // TODO(eroman): Do this same test for AES-GCM, AES-KW, AES-CTR ?
1114 TEST(WebCryptoAesCbcTest, GenerateKeyIsRandom) {
1115 // Check key generation for each allowed key length.
1116 std::vector<blink::WebCryptoAlgorithm> algorithm;
1117 const unsigned short kKeyLength[] = {128, 256};
1118 for (size_t key_length_i = 0; key_length_i < ARRAYSIZE_UNSAFE(kKeyLength);
1119 ++key_length_i) {
1120 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1121
1122 std::vector<std::vector<uint8_t> > keys;
1123 std::vector<uint8_t> key_bytes;
1124
1125 // Generate a small sample of keys.
1126 for (int j = 0; j < 16; ++j) {
1127 ASSERT_EQ(Status::Success(),
1128 GenerateSecretKey(
1129 CreateAesCbcKeyGenAlgorithm(kKeyLength[key_length_i]),
1130 true,
1131 0,
1132 &key));
1133 EXPECT_TRUE(key.handle());
1134 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
1135 ASSERT_EQ(Status::Success(),
1136 ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_bytes));
1137 EXPECT_EQ(key_bytes.size() * 8,
1138 key.algorithm().aesParams()->lengthBits());
1139 keys.push_back(key_bytes);
1140 }
1141 // Ensure all entries in the key sample set are unique. This is a simplistic
1142 // estimate of whether the generated keys appear random.
1143 EXPECT_FALSE(CopiesExist(keys));
1144 }
1145 }
1146
1147 TEST(WebCryptoAesCbcTest, GenerateKeyBadLength) {
1148 const unsigned short kKeyLen[] = {0, 127, 257};
1149 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1150 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
1151 SCOPED_TRACE(i);
1152 EXPECT_EQ(Status::ErrorGenerateKeyLength(),
1153 GenerateSecretKey(
1154 CreateAesCbcKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
1155 }
1156 }
1157
1158 TEST(WebCryptoAesKwTest, GenerateKeyBadLength) { 26 TEST(WebCryptoAesKwTest, GenerateKeyBadLength) {
1159 const unsigned short kKeyLen[] = {0, 127, 257}; 27 const unsigned short kKeyLen[] = {0, 127, 257};
1160 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 28 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1161 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) { 29 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
1162 SCOPED_TRACE(i); 30 SCOPED_TRACE(i);
1163 EXPECT_EQ(Status::ErrorGenerateKeyLength(), 31 EXPECT_EQ(Status::ErrorGenerateKeyLength(),
1164 GenerateSecretKey( 32 GenerateSecretKey(
1165 CreateAesKwKeyGenAlgorithm(kKeyLen[i]), true, 0, &key)); 33 CreateAesKwKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
1166 } 34 }
1167 } 35 }
1168 36
1169 TEST(WebCryptoAesGcmTest, GenerateKeyBadLength) {
1170 if (!SupportsAesGcm())
1171 return;
1172
1173 const unsigned short kKeyLen[] = {0, 127, 257};
1174 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1175 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
1176 SCOPED_TRACE(i);
1177 EXPECT_EQ(Status::ErrorGenerateKeyLength(),
1178 GenerateSecretKey(
1179 CreateAesGcmKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
1180 }
1181 }
1182
1183 TEST(WebCryptoHmacTest, GenerateKeyIsRandom) {
1184 // Generate a small sample of HMAC keys.
1185 std::vector<std::vector<uint8_t> > keys;
1186 for (int i = 0; i < 16; ++i) {
1187 std::vector<uint8_t> key_bytes;
1188 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1189 blink::WebCryptoAlgorithm algorithm =
1190 CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 512);
1191 ASSERT_EQ(Status::Success(), GenerateSecretKey(algorithm, true, 0, &key));
1192 EXPECT_FALSE(key.isNull());
1193 EXPECT_TRUE(key.handle());
1194 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
1195 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
1196 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
1197 key.algorithm().hmacParams()->hash().id());
1198 EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
1199
1200 std::vector<uint8_t> raw_key;
1201 ASSERT_EQ(Status::Success(),
1202 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
1203 EXPECT_EQ(64U, raw_key.size());
1204 keys.push_back(raw_key);
1205 }
1206 // Ensure all entries in the key sample set are unique. This is a simplistic
1207 // estimate of whether the generated keys appear random.
1208 EXPECT_FALSE(CopiesExist(keys));
1209 }
1210
1211 // If the key length is not provided, then the block size is used.
1212 TEST(WebCryptoHmacTest, GenerateKeyNoLengthSha1) {
1213 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1214 blink::WebCryptoAlgorithm algorithm =
1215 CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0);
1216 ASSERT_EQ(Status::Success(), GenerateSecretKey(algorithm, true, 0, &key));
1217 EXPECT_TRUE(key.handle());
1218 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
1219 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
1220 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
1221 key.algorithm().hmacParams()->hash().id());
1222 EXPECT_EQ(512u, key.algorithm().hmacParams()->lengthBits());
1223 std::vector<uint8_t> raw_key;
1224 ASSERT_EQ(Status::Success(),
1225 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
1226 EXPECT_EQ(64U, raw_key.size());
1227 }
1228
1229 // If the key length is not provided, then the block size is used.
1230 TEST(WebCryptoHmacTest, GenerateKeyNoLengthSha512) {
1231 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1232 blink::WebCryptoAlgorithm algorithm =
1233 CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha512, 0);
1234 ASSERT_EQ(Status::Success(), GenerateSecretKey(algorithm, true, 0, &key));
1235 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
1236 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha512,
1237 key.algorithm().hmacParams()->hash().id());
1238 EXPECT_EQ(1024u, key.algorithm().hmacParams()->lengthBits());
1239 std::vector<uint8_t> raw_key;
1240 ASSERT_EQ(Status::Success(),
1241 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
1242 EXPECT_EQ(128U, raw_key.size());
1243 }
1244
1245 // If key_ops is specified but empty, no key usages are allowed for the key.
1246 TEST(WebCryptoAesCbcTest, ImportKeyJwkEmptyKeyOps) {
1247 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1248 base::DictionaryValue dict;
1249 dict.SetString("kty", "oct");
1250 dict.SetBoolean("ext", false);
1251 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1252 dict.Set("key_ops", new base::ListValue); // Takes ownership.
1253
1254 EXPECT_EQ(
1255 Status::Success(),
1256 ImportKeyJwkFromDict(dict,
1257 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1258 false,
1259 0,
1260 &key));
1261
1262 EXPECT_EQ(0, key.usages());
1263
1264 // The JWK does not contain encrypt usages.
1265 EXPECT_EQ(
1266 Status::ErrorJwkKeyopsInconsistent(),
1267 ImportKeyJwkFromDict(dict,
1268 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1269 false,
1270 blink::WebCryptoKeyUsageEncrypt,
1271 &key));
1272
1273 // The JWK does not contain sign usage (nor is it applicable).
1274 EXPECT_EQ(
1275 Status::ErrorCreateKeyBadUsages(),
1276 ImportKeyJwkFromDict(dict,
1277 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1278 false,
1279 blink::WebCryptoKeyUsageSign,
1280 &key));
1281 }
1282
1283 // If key_ops is missing, then any key usages can be specified.
1284 TEST(WebCryptoAesCbcTest, ImportKeyJwkNoKeyOps) {
1285 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1286 base::DictionaryValue dict;
1287 dict.SetString("kty", "oct");
1288 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1289
1290 EXPECT_EQ(
1291 Status::Success(),
1292 ImportKeyJwkFromDict(dict,
1293 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1294 false,
1295 blink::WebCryptoKeyUsageEncrypt,
1296 &key));
1297
1298 EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
1299
1300 // The JWK does not contain sign usage (nor is it applicable).
1301 EXPECT_EQ(
1302 Status::ErrorCreateKeyBadUsages(),
1303 ImportKeyJwkFromDict(dict,
1304 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1305 false,
1306 blink::WebCryptoKeyUsageVerify,
1307 &key));
1308 }
1309
1310 TEST(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsEncryptDecrypt) {
1311 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1312 base::DictionaryValue dict;
1313 dict.SetString("kty", "oct");
1314 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1315 base::ListValue* key_ops = new base::ListValue;
1316 dict.Set("key_ops", key_ops); // Takes ownership.
1317
1318 key_ops->AppendString("encrypt");
1319
1320 EXPECT_EQ(
1321 Status::Success(),
1322 ImportKeyJwkFromDict(dict,
1323 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1324 false,
1325 blink::WebCryptoKeyUsageEncrypt,
1326 &key));
1327
1328 EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt, key.usages());
1329
1330 key_ops->AppendString("decrypt");
1331
1332 EXPECT_EQ(
1333 Status::Success(),
1334 ImportKeyJwkFromDict(dict,
1335 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1336 false,
1337 blink::WebCryptoKeyUsageDecrypt,
1338 &key));
1339
1340 EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt, key.usages());
1341
1342 EXPECT_EQ(
1343 Status::Success(),
1344 ImportKeyJwkFromDict(
1345 dict,
1346 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1347 false,
1348 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt,
1349 &key));
1350
1351 EXPECT_EQ(blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
1352 key.usages());
1353 }
1354
1355 // Test failure if input usage is NOT a strict subset of the JWK usage.
1356 TEST(WebCryptoAesCbcTest, ImportKeyJwkKeyOpsNotSuperset) {
1357 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1358 base::DictionaryValue dict;
1359 dict.SetString("kty", "oct");
1360 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1361 base::ListValue* key_ops = new base::ListValue;
1362 dict.Set("key_ops", key_ops); // Takes ownership.
1363
1364 key_ops->AppendString("encrypt");
1365
1366 EXPECT_EQ(
1367 Status::ErrorJwkKeyopsInconsistent(),
1368 ImportKeyJwkFromDict(
1369 dict,
1370 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1371 false,
1372 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
1373 &key));
1374 }
1375
1376 TEST(WebCryptoHmacTest, ImportKeyJwkKeyOpsSignVerify) {
1377 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1378 base::DictionaryValue dict;
1379 dict.SetString("kty", "oct");
1380 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1381 base::ListValue* key_ops = new base::ListValue;
1382 dict.Set("key_ops", key_ops); // Takes ownership.
1383
1384 key_ops->AppendString("sign");
1385
1386 EXPECT_EQ(Status::Success(),
1387 ImportKeyJwkFromDict(
1388 dict,
1389 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
1390 false,
1391 blink::WebCryptoKeyUsageSign,
1392 &key));
1393
1394 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
1395
1396 key_ops->AppendString("verify");
1397
1398 EXPECT_EQ(Status::Success(),
1399 ImportKeyJwkFromDict(
1400 dict,
1401 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
1402 false,
1403 blink::WebCryptoKeyUsageVerify,
1404 &key));
1405
1406 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
1407 }
1408
1409 TEST(WebCryptoAesKwTest, ImportKeyJwkKeyOpsWrapUnwrap) { 37 TEST(WebCryptoAesKwTest, ImportKeyJwkKeyOpsWrapUnwrap) {
1410 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 38 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1411 base::DictionaryValue dict; 39 base::DictionaryValue dict;
1412 dict.SetString("kty", "oct"); 40 dict.SetString("kty", "oct");
1413 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); 41 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1414 base::ListValue* key_ops = new base::ListValue; 42 base::ListValue* key_ops = new base::ListValue;
1415 dict.Set("key_ops", key_ops); // Takes ownership. 43 dict.Set("key_ops", key_ops); // Takes ownership.
1416 44
1417 key_ops->AppendString("wrapKey"); 45 key_ops->AppendString("wrapKey");
1418 46
(...skipping 13 matching lines...) Expand all
1432 Status::Success(), 60 Status::Success(),
1433 ImportKeyJwkFromDict(dict, 61 ImportKeyJwkFromDict(dict,
1434 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), 62 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
1435 false, 63 false,
1436 blink::WebCryptoKeyUsageUnwrapKey, 64 blink::WebCryptoKeyUsageUnwrapKey,
1437 &key)); 65 &key));
1438 66
1439 EXPECT_EQ(blink::WebCryptoKeyUsageUnwrapKey, key.usages()); 67 EXPECT_EQ(blink::WebCryptoKeyUsageUnwrapKey, key.usages());
1440 } 68 }
1441 69
1442 // Test 'use' inconsistent with 'key_ops'.
1443 TEST(WebCryptoHmacTest, ImportKeyJwkUseInconsisteWithKeyOps) {
1444 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1445 base::DictionaryValue dict;
1446 dict.SetString("kty", "oct");
1447 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1448 base::ListValue* key_ops = new base::ListValue;
1449 dict.Set("key_ops", key_ops); // Takes ownership.
1450
1451 dict.SetString("alg", "HS256");
1452 dict.SetString("use", "sig");
1453 key_ops->AppendString("sign");
1454 key_ops->AppendString("verify");
1455 key_ops->AppendString("encrypt");
1456 EXPECT_EQ(Status::ErrorJwkUseAndKeyopsInconsistent(),
1457 ImportKeyJwkFromDict(
1458 dict,
1459 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
1460 false,
1461 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
1462 &key));
1463 }
1464
1465 // Test JWK composite 'sig' use
1466 TEST(WebCryptoHmacTest, ImportKeyJwkUseSig) {
1467 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1468 base::DictionaryValue dict;
1469 dict.SetString("kty", "oct");
1470 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1471
1472 dict.SetString("use", "sig");
1473 EXPECT_EQ(Status::Success(),
1474 ImportKeyJwkFromDict(
1475 dict,
1476 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
1477 false,
1478 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
1479 &key));
1480
1481 EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
1482 key.usages());
1483 }
1484
1485 TEST(WebCryptoAesCbcTest, ImportKeyJwkUseEnc) {
1486 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1487 base::DictionaryValue dict;
1488 dict.SetString("kty", "oct");
1489 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1490
1491 // Test JWK composite use 'enc' usage
1492 dict.SetString("alg", "A128CBC");
1493 dict.SetString("use", "enc");
1494 EXPECT_EQ(
1495 Status::Success(),
1496 ImportKeyJwkFromDict(dict,
1497 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1498 false,
1499 blink::WebCryptoKeyUsageDecrypt |
1500 blink::WebCryptoKeyUsageEncrypt |
1501 blink::WebCryptoKeyUsageWrapKey |
1502 blink::WebCryptoKeyUsageUnwrapKey,
1503 &key));
1504 EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
1505 blink::WebCryptoKeyUsageWrapKey |
1506 blink::WebCryptoKeyUsageUnwrapKey,
1507 key.usages());
1508 }
1509
1510 TEST(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
1511 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1512 // Fail on empty JSON.
1513 EXPECT_EQ(Status::ErrorImportEmptyKeyData(),
1514 ImportKeyJwk(CryptoData(MakeJsonVector("")),
1515 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1516 false,
1517 blink::WebCryptoKeyUsageEncrypt,
1518 &key));
1519
1520 // Fail on invalid JSON.
1521 const std::vector<uint8_t> bad_json_vec = MakeJsonVector(
1522 "{"
1523 "\"kty\" : \"oct\","
1524 "\"alg\" : \"HS256\","
1525 "\"use\" : ");
1526 EXPECT_EQ(Status::ErrorJwkNotDictionary(),
1527 ImportKeyJwk(CryptoData(bad_json_vec),
1528 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1529 false,
1530 blink::WebCryptoKeyUsageEncrypt,
1531 &key));
1532 }
1533
1534 // Fail on JWK alg present but incorrect (expecting A128CBC).
1535 TEST(WebCryptoAesCbcTest, ImportJwkIncorrectAlg) {
1536 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1537
1538 base::DictionaryValue dict;
1539 dict.SetString("kty", "oct");
1540 dict.SetString("alg", "A127CBC"); // Not valid.
1541 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1542
1543 EXPECT_EQ(
1544 Status::ErrorJwkAlgorithmInconsistent(),
1545 ImportKeyJwkFromDict(dict,
1546 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1547 false,
1548 blink::WebCryptoKeyUsageEncrypt,
1549 &key));
1550 }
1551
1552 // Fail on invalid kty.
1553 TEST(WebCryptoAesCbcTest, ImportJwkInvalidKty) {
1554 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1555
1556 base::DictionaryValue dict;
1557 dict.SetString("kty", "foo");
1558 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1559 EXPECT_EQ(
1560 Status::ErrorJwkUnexpectedKty("oct"),
1561 ImportKeyJwkFromDict(dict,
1562 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1563 false,
1564 blink::WebCryptoKeyUsageEncrypt,
1565 &key));
1566 }
1567
1568 // Fail on missing kty.
1569 TEST(WebCryptoAesCbcTest, ImportJwkMissingKty) {
1570 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1571
1572 base::DictionaryValue dict;
1573 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1574 EXPECT_EQ(
1575 Status::ErrorJwkPropertyMissing("kty"),
1576 ImportKeyJwkFromDict(dict,
1577 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1578 false,
1579 blink::WebCryptoKeyUsageEncrypt,
1580 &key));
1581 }
1582
1583 // Fail on kty wrong type.
1584 TEST(WebCryptoAesCbcTest, ImportJwkKtyWrongType) {
1585 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1586
1587 base::DictionaryValue dict;
1588 dict.SetDouble("kty", 0.1);
1589 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1590
1591 EXPECT_EQ(
1592 Status::ErrorJwkPropertyWrongType("kty", "string"),
1593 ImportKeyJwkFromDict(dict,
1594 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1595 false,
1596 blink::WebCryptoKeyUsageEncrypt,
1597 &key));
1598 }
1599
1600 // Fail on invalid use.
1601 TEST(WebCryptoAesCbcTest, ImportJwkUnrecognizedUse) {
1602 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1603
1604 base::DictionaryValue dict;
1605 dict.SetString("kty", "oct");
1606 dict.SetString("use", "foo");
1607 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1608
1609 EXPECT_EQ(
1610 Status::ErrorJwkUnrecognizedUse(),
1611 ImportKeyJwkFromDict(dict,
1612 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1613 false,
1614 blink::WebCryptoKeyUsageEncrypt,
1615 &key));
1616 }
1617
1618 // Fail on invalid use (wrong type).
1619 TEST(WebCryptoAesCbcTest, ImportJwkUseWrongType) {
1620 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1621
1622 base::DictionaryValue dict;
1623 dict.SetString("kty", "oct");
1624 dict.SetBoolean("use", true);
1625 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1626
1627 EXPECT_EQ(
1628 Status::ErrorJwkPropertyWrongType("use", "string"),
1629 ImportKeyJwkFromDict(dict,
1630 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1631 false,
1632 blink::WebCryptoKeyUsageEncrypt,
1633 &key));
1634 }
1635
1636 // Fail on invalid extractable (wrong type).
1637 TEST(WebCryptoAesCbcTest, ImportJwkExtWrongType) {
1638 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1639
1640 base::DictionaryValue dict;
1641 dict.SetString("kty", "oct");
1642 dict.SetInteger("ext", 0);
1643 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1644
1645 EXPECT_EQ(
1646 Status::ErrorJwkPropertyWrongType("ext", "boolean"),
1647 ImportKeyJwkFromDict(dict,
1648 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1649 false,
1650 blink::WebCryptoKeyUsageEncrypt,
1651 &key));
1652 }
1653
1654 // Fail on invalid key_ops (wrong type).
1655 TEST(WebCryptoAesCbcTest, ImportJwkKeyOpsWrongType) {
1656 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1657
1658 base::DictionaryValue dict;
1659 dict.SetString("kty", "oct");
1660 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1661 dict.SetBoolean("key_ops", true);
1662
1663 EXPECT_EQ(
1664 Status::ErrorJwkPropertyWrongType("key_ops", "list"),
1665 ImportKeyJwkFromDict(dict,
1666 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1667 false,
1668 blink::WebCryptoKeyUsageEncrypt,
1669 &key));
1670 }
1671
1672 // Fail on inconsistent key_ops - asking for "encrypt" however JWK contains
1673 // only "foo".
1674 TEST(WebCryptoAesCbcTest, ImportJwkKeyOpsLacksUsages) {
1675 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1676
1677 base::DictionaryValue dict;
1678 dict.SetString("kty", "oct");
1679 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1680
1681 base::ListValue* key_ops = new base::ListValue;
1682 // Note: the following call makes dict assume ownership of key_ops.
1683 dict.Set("key_ops", key_ops);
1684 key_ops->AppendString("foo");
1685 EXPECT_EQ(
1686 Status::ErrorJwkKeyopsInconsistent(),
1687 ImportKeyJwkFromDict(dict,
1688 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1689 false,
1690 blink::WebCryptoKeyUsageEncrypt,
1691 &key));
1692 }
1693
1694 // Import a JWK with unrecognized values for "key_ops".
1695 TEST(WebCryptoAesCbcTest, ImportJwkUnrecognizedKeyOps) {
1696 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1697 blink::WebCryptoAlgorithm algorithm =
1698 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
1699 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt;
1700
1701 base::DictionaryValue dict;
1702 dict.SetString("kty", "oct");
1703 dict.SetString("alg", "A128CBC");
1704 dict.SetString("use", "enc");
1705 dict.SetBoolean("ext", false);
1706 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1707
1708 base::ListValue* key_ops = new base::ListValue;
1709 dict.Set("key_ops", key_ops);
1710 key_ops->AppendString("foo");
1711 key_ops->AppendString("bar");
1712 key_ops->AppendString("baz");
1713 key_ops->AppendString("encrypt");
1714 EXPECT_EQ(Status::Success(),
1715 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1716 }
1717
1718 // Import a JWK with a value in key_ops array that is not a string.
1719 TEST(WebCryptoAesCbcTest, ImportJwkNonStringKeyOp) {
1720 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1721 blink::WebCryptoAlgorithm algorithm =
1722 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
1723 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt;
1724
1725 base::DictionaryValue dict;
1726 dict.SetString("kty", "oct");
1727 dict.SetString("alg", "A128CBC");
1728 dict.SetString("use", "enc");
1729 dict.SetBoolean("ext", false);
1730 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1731
1732 base::ListValue* key_ops = new base::ListValue;
1733 dict.Set("key_ops", key_ops);
1734 key_ops->AppendString("encrypt");
1735 key_ops->AppendInteger(3);
1736 EXPECT_EQ(Status::ErrorJwkPropertyWrongType("key_ops[1]", "string"),
1737 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1738 }
1739
1740 // Fail on missing k.
1741 TEST(WebCryptoAesCbcTest, ImportJwkMissingK) {
1742 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1743
1744 base::DictionaryValue dict;
1745 dict.SetString("kty", "oct");
1746
1747 EXPECT_EQ(
1748 Status::ErrorJwkPropertyMissing("k"),
1749 ImportKeyJwkFromDict(dict,
1750 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1751 false,
1752 blink::WebCryptoKeyUsageEncrypt,
1753 &key));
1754 }
1755
1756 // Fail on bad b64 encoding for k.
1757 TEST(WebCryptoAesCbcTest, ImportJwkBadB64ForK) {
1758 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1759
1760 base::DictionaryValue dict;
1761 dict.SetString("kty", "oct");
1762 dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI=");
1763 EXPECT_EQ(
1764 Status::ErrorJwkBase64Decode("k"),
1765 ImportKeyJwkFromDict(dict,
1766 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1767 false,
1768 blink::WebCryptoKeyUsageEncrypt,
1769 &key));
1770 }
1771
1772 // Fail on empty k.
1773 TEST(WebCryptoAesCbcTest, ImportJwkEmptyK) {
1774 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1775
1776 base::DictionaryValue dict;
1777 dict.SetString("kty", "oct");
1778 dict.SetString("k", "");
1779
1780 EXPECT_EQ(
1781 Status::ErrorImportAesKeyLength(),
1782 ImportKeyJwkFromDict(dict,
1783 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1784 false,
1785 blink::WebCryptoKeyUsageEncrypt,
1786 &key));
1787 }
1788
1789 // Fail on empty k (with alg specified).
1790 TEST(WebCryptoAesCbcTest, ImportJwkEmptyK2) {
1791 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1792
1793 base::DictionaryValue dict;
1794 dict.SetString("kty", "oct");
1795 dict.SetString("alg", "A128CBC");
1796 dict.SetString("k", "");
1797
1798 EXPECT_EQ(
1799 Status::ErrorJwkIncorrectKeyLength(),
1800 ImportKeyJwkFromDict(dict,
1801 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1802 false,
1803 blink::WebCryptoKeyUsageEncrypt,
1804 &key));
1805 }
1806
1807 // Fail on k actual length (120 bits) inconsistent with the embedded JWK alg
1808 // value (128) for an AES key.
1809 TEST(WebCryptoAesCbcTest, ImportJwkInconsistentKLength) {
1810 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1811
1812 base::DictionaryValue dict;
1813 dict.SetString("kty", "oct");
1814 dict.SetString("alg", "A128CBC");
1815 dict.SetString("k", "AVj42h0Y5aqGtE3yluKL");
1816 EXPECT_EQ(
1817 Status::ErrorJwkIncorrectKeyLength(),
1818 ImportKeyJwkFromDict(dict,
1819 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1820 false,
1821 blink::WebCryptoKeyUsageEncrypt,
1822 &key));
1823 }
1824
1825 // Fail on k actual length (192 bits) inconsistent with the embedded JWK alg
1826 // value (128) for an AES key.
1827 TEST(WebCryptoAesCbcTest, ImportJwkInconsistentKLength2) {
1828 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1829
1830 base::DictionaryValue dict;
1831 dict.SetString("kty", "oct");
1832 dict.SetString("alg", "A128CBC");
1833 dict.SetString("k", "dGhpcyAgaXMgIDI0ICBieXRlcyBsb25n");
1834 EXPECT_EQ(
1835 Status::ErrorJwkIncorrectKeyLength(),
1836 ImportKeyJwkFromDict(dict,
1837 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1838 false,
1839 blink::WebCryptoKeyUsageEncrypt,
1840 &key));
1841 }
1842
1843 TEST(WebCryptoRsaSsaTest, ImportExportJwkRsaPublicKey) {
1844 struct TestCase {
1845 const blink::WebCryptoAlgorithmId hash;
1846 const blink::WebCryptoKeyUsageMask usage;
1847 const char* const jwk_alg;
1848 };
1849 const TestCase kTests[] = {
1850 {blink::WebCryptoAlgorithmIdSha1, blink::WebCryptoKeyUsageVerify, "RS1"},
1851 {blink::WebCryptoAlgorithmIdSha256, blink::WebCryptoKeyUsageVerify,
1852 "RS256"},
1853 {blink::WebCryptoAlgorithmIdSha384, blink::WebCryptoKeyUsageVerify,
1854 "RS384"},
1855 {blink::WebCryptoAlgorithmIdSha512, blink::WebCryptoKeyUsageVerify,
1856 "RS512"}};
1857
1858 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests);
1859 ++test_index) {
1860 SCOPED_TRACE(test_index);
1861 const TestCase& test = kTests[test_index];
1862
1863 const blink::WebCryptoAlgorithm import_algorithm =
1864 CreateRsaHashedImportAlgorithm(
1865 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, test.hash);
1866
1867 // Import the spki to create a public key
1868 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1869 ASSERT_EQ(Status::Success(),
1870 ImportKey(blink::WebCryptoKeyFormatSpki,
1871 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
1872 import_algorithm,
1873 true,
1874 test.usage,
1875 &public_key));
1876
1877 // Export the public key as JWK and verify its contents
1878 std::vector<uint8_t> jwk;
1879 ASSERT_EQ(Status::Success(),
1880 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
1881 EXPECT_TRUE(VerifyPublicJwk(jwk,
1882 test.jwk_alg,
1883 kPublicKeyModulusHex,
1884 kPublicKeyExponentHex,
1885 test.usage));
1886
1887 // Import the JWK back in to create a new key
1888 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull();
1889 ASSERT_EQ(
1890 Status::Success(),
1891 ImportKeyJwk(
1892 CryptoData(jwk), import_algorithm, true, test.usage, &public_key2));
1893 ASSERT_TRUE(public_key2.handle());
1894 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
1895 EXPECT_TRUE(public_key2.extractable());
1896 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
1897
1898 // Export the new key as spki and compare to the original.
1899 std::vector<uint8_t> spki;
1900 ASSERT_EQ(Status::Success(),
1901 ExportKey(blink::WebCryptoKeyFormatSpki, public_key2, &spki));
1902 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, CryptoData(spki));
1903 }
1904 }
1905
1906 TEST(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) {
1907 if (!SupportsRsaOaep()) {
1908 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
1909 return;
1910 }
1911
1912 struct TestCase {
1913 const blink::WebCryptoAlgorithmId hash;
1914 const blink::WebCryptoKeyUsageMask usage;
1915 const char* const jwk_alg;
1916 };
1917 const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1,
1918 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP"},
1919 {blink::WebCryptoAlgorithmIdSha256,
1920 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-256"},
1921 {blink::WebCryptoAlgorithmIdSha384,
1922 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-384"},
1923 {blink::WebCryptoAlgorithmIdSha512,
1924 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-512"}};
1925
1926 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests);
1927 ++test_index) {
1928 SCOPED_TRACE(test_index);
1929 const TestCase& test = kTests[test_index];
1930
1931 const blink::WebCryptoAlgorithm import_algorithm =
1932 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep,
1933 test.hash);
1934
1935 // Import the spki to create a public key
1936 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
1937 ASSERT_EQ(Status::Success(),
1938 ImportKey(blink::WebCryptoKeyFormatSpki,
1939 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
1940 import_algorithm,
1941 true,
1942 test.usage,
1943 &public_key));
1944
1945 // Export the public key as JWK and verify its contents
1946 std::vector<uint8_t> jwk;
1947 ASSERT_EQ(Status::Success(),
1948 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
1949 EXPECT_TRUE(VerifyPublicJwk(jwk,
1950 test.jwk_alg,
1951 kPublicKeyModulusHex,
1952 kPublicKeyExponentHex,
1953 test.usage));
1954
1955 // Import the JWK back in to create a new key
1956 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull();
1957 ASSERT_EQ(
1958 Status::Success(),
1959 ImportKeyJwk(
1960 CryptoData(jwk), import_algorithm, true, test.usage, &public_key2));
1961 ASSERT_TRUE(public_key2.handle());
1962 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
1963 EXPECT_TRUE(public_key2.extractable());
1964 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
1965
1966 // TODO(eroman): Export the SPKI and verify matches.
1967 }
1968 }
1969
1970 TEST(WebCryptoRsaSsaTest, ImportJwkRsaFailures) {
1971 base::DictionaryValue dict;
1972 RestoreJwkRsaDictionary(&dict);
1973 blink::WebCryptoAlgorithm algorithm =
1974 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
1975 blink::WebCryptoAlgorithmIdSha256);
1976 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageVerify;
1977 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1978
1979 // An RSA public key JWK _must_ have an "n" (modulus) and an "e" (exponent)
1980 // entry, while an RSA private key must have those plus at least a "d"
1981 // (private exponent) entry.
1982 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
1983 // section 6.3.
1984
1985 // Baseline pass.
1986 EXPECT_EQ(Status::Success(),
1987 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
1988 EXPECT_EQ(algorithm.id(), key.algorithm().id());
1989 EXPECT_FALSE(key.extractable());
1990 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
1991 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
1992
1993 // The following are specific failure cases for when kty = "RSA".
1994
1995 // Fail if either "n" or "e" is not present or malformed.
1996 const std::string kKtyParmName[] = {"n", "e"};
1997 for (size_t idx = 0; idx < ARRAYSIZE_UNSAFE(kKtyParmName); ++idx) {
1998 // Fail on missing parameter.
1999 dict.Remove(kKtyParmName[idx], NULL);
2000 EXPECT_NE(Status::Success(),
2001 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
2002 RestoreJwkRsaDictionary(&dict);
2003
2004 // Fail on bad b64 parameter encoding.
2005 dict.SetString(kKtyParmName[idx], "Qk3f0DsytU8lfza2au #$% Htaw2xpop9yTuH0");
2006 EXPECT_NE(Status::Success(),
2007 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
2008 RestoreJwkRsaDictionary(&dict);
2009
2010 // Fail on empty parameter.
2011 dict.SetString(kKtyParmName[idx], "");
2012 EXPECT_EQ(Status::ErrorJwkEmptyBigInteger(kKtyParmName[idx]),
2013 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
2014 RestoreJwkRsaDictionary(&dict);
2015 }
2016 }
2017
2018 TEST(WebCryptoHmacTest, ImportJwkInputConsistency) {
2019 // The Web Crypto spec says that if a JWK value is present, but is
2020 // inconsistent with the input value, the operation must fail.
2021
2022 // Consistency rules when JWK value is not present: Inputs should be used.
2023 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2024 bool extractable = false;
2025 blink::WebCryptoAlgorithm algorithm =
2026 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256);
2027 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageVerify;
2028 base::DictionaryValue dict;
2029 dict.SetString("kty", "oct");
2030 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
2031 std::vector<uint8_t> json_vec = MakeJsonVector(dict);
2032 EXPECT_EQ(
2033 Status::Success(),
2034 ImportKeyJwk(
2035 CryptoData(json_vec), algorithm, extractable, usage_mask, &key));
2036 EXPECT_TRUE(key.handle());
2037 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
2038 EXPECT_EQ(extractable, key.extractable());
2039 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
2040 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
2041 key.algorithm().hmacParams()->hash().id());
2042 EXPECT_EQ(320u, key.algorithm().hmacParams()->lengthBits());
2043 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
2044 key = blink::WebCryptoKey::createNull();
2045
2046 // Consistency rules when JWK value exists: Fail if inconsistency is found.
2047
2048 // Pass: All input values are consistent with the JWK values.
2049 dict.Clear();
2050 dict.SetString("kty", "oct");
2051 dict.SetString("alg", "HS256");
2052 dict.SetString("use", "sig");
2053 dict.SetBoolean("ext", false);
2054 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
2055 json_vec = MakeJsonVector(dict);
2056 EXPECT_EQ(
2057 Status::Success(),
2058 ImportKeyJwk(
2059 CryptoData(json_vec), algorithm, extractable, usage_mask, &key));
2060
2061 // Extractable cases:
2062 // 1. input=T, JWK=F ==> fail (inconsistent)
2063 // 4. input=F, JWK=F ==> pass, result extractable is F
2064 // 2. input=T, JWK=T ==> pass, result extractable is T
2065 // 3. input=F, JWK=T ==> pass, result extractable is F
2066 EXPECT_EQ(
2067 Status::ErrorJwkExtInconsistent(),
2068 ImportKeyJwk(CryptoData(json_vec), algorithm, true, usage_mask, &key));
2069 EXPECT_EQ(
2070 Status::Success(),
2071 ImportKeyJwk(CryptoData(json_vec), algorithm, false, usage_mask, &key));
2072 EXPECT_FALSE(key.extractable());
2073 dict.SetBoolean("ext", true);
2074 EXPECT_EQ(Status::Success(),
2075 ImportKeyJwkFromDict(dict, algorithm, true, usage_mask, &key));
2076 EXPECT_TRUE(key.extractable());
2077 EXPECT_EQ(Status::Success(),
2078 ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
2079 EXPECT_FALSE(key.extractable());
2080 dict.SetBoolean("ext", true); // restore previous value
2081
2082 // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value
2083 // (HMAC SHA256).
2084 dict.Clear();
2085 dict.SetString("kty", "oct");
2086 dict.SetString("alg", "HS256");
2087 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
2088 EXPECT_EQ(
2089 Status::ErrorJwkAlgorithmInconsistent(),
2090 ImportKeyJwkFromDict(dict,
2091 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
2092 extractable,
2093 blink::WebCryptoKeyUsageEncrypt,
2094 &key));
2095 // Fail: Input usage (encrypt) is inconsistent with JWK value (use=sig).
2096 EXPECT_EQ(Status::ErrorJwkUseInconsistent(),
2097 ImportKeyJwk(CryptoData(json_vec),
2098 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
2099 extractable,
2100 blink::WebCryptoKeyUsageEncrypt,
2101 &key));
2102
2103 // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value
2104 // (HMAC SHA256).
2105 EXPECT_EQ(
2106 Status::ErrorJwkAlgorithmInconsistent(),
2107 ImportKeyJwk(CryptoData(json_vec),
2108 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1),
2109 extractable,
2110 usage_mask,
2111 &key));
2112
2113 // Pass: JWK alg missing but input algorithm specified: use input value
2114 dict.Remove("alg", NULL);
2115 EXPECT_EQ(Status::Success(),
2116 ImportKeyJwkFromDict(
2117 dict,
2118 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
2119 extractable,
2120 usage_mask,
2121 &key));
2122 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id());
2123 dict.SetString("alg", "HS256");
2124
2125 // Fail: Input usage_mask (encrypt) is not a subset of the JWK value
2126 // (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
2127 EXPECT_EQ(Status::ErrorCreateKeyBadUsages(),
2128 ImportKeyJwk(CryptoData(json_vec),
2129 algorithm,
2130 extractable,
2131 blink::WebCryptoKeyUsageEncrypt,
2132 &key));
2133
2134 // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK
2135 // value (sign|verify). Moreover "encrypt" is not a valid usage for HMAC.
2136 usage_mask = blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageSign |
2137 blink::WebCryptoKeyUsageVerify;
2138 EXPECT_EQ(
2139 Status::ErrorCreateKeyBadUsages(),
2140 ImportKeyJwk(
2141 CryptoData(json_vec), algorithm, extractable, usage_mask, &key));
2142
2143 // TODO(padolph): kty vs alg consistency tests: Depending on the kty value,
2144 // only certain alg values are permitted. For example, when kty = "RSA" alg
2145 // must be of the RSA family, or when kty = "oct" alg must be symmetric
2146 // algorithm.
2147
2148 // TODO(padolph): key_ops consistency tests
2149 }
2150
2151 TEST(WebCryptoHmacTest, ImportJwkHappy) {
2152 // This test verifies the happy path of JWK import, including the application
2153 // of the imported key material.
2154
2155 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2156 bool extractable = false;
2157 blink::WebCryptoAlgorithm algorithm =
2158 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256);
2159 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageSign;
2160
2161 // Import a symmetric key JWK and HMAC-SHA256 sign()
2162 // Uses the first SHA256 test vector from the HMAC sample set above.
2163
2164 base::DictionaryValue dict;
2165 dict.SetString("kty", "oct");
2166 dict.SetString("alg", "HS256");
2167 dict.SetString("use", "sig");
2168 dict.SetBoolean("ext", false);
2169 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg");
2170
2171 ASSERT_EQ(
2172 Status::Success(),
2173 ImportKeyJwkFromDict(dict, algorithm, extractable, usage_mask, &key));
2174
2175 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
2176 key.algorithm().hmacParams()->hash().id());
2177
2178 const std::vector<uint8_t> message_raw = HexStringToBytes(
2179 "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a"
2180 "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92"
2181 "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f"
2182 "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e");
2183
2184 std::vector<uint8_t> output;
2185
2186 ASSERT_EQ(Status::Success(),
2187 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac),
2188 key,
2189 CryptoData(message_raw),
2190 &output));
2191
2192 const std::string mac_raw =
2193 "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b";
2194
2195 EXPECT_BYTES_EQ_HEX(mac_raw, output);
2196
2197 // TODO(padolph): Import an RSA public key JWK and use it
2198 }
2199
2200 void ImportExportJwkSymmetricKey(
2201 int key_len_bits,
2202 const blink::WebCryptoAlgorithm& import_algorithm,
2203 blink::WebCryptoKeyUsageMask usages,
2204 const std::string& jwk_alg) {
2205 std::vector<uint8_t> json;
2206 std::string key_hex;
2207
2208 // Hardcoded pseudo-random bytes to use for keys of different lengths.
2209 switch (key_len_bits) {
2210 case 128:
2211 key_hex = "3f1e7cd4f6f8543f6b1e16002e688623";
2212 break;
2213 case 256:
2214 key_hex =
2215 "bd08286b81a74783fd1ccf46b7e05af84ee25ae021210074159e0c4d9d907692";
2216 break;
2217 case 384:
2218 key_hex =
2219 "a22c5441c8b185602283d64c7221de1d0951e706bfc09539435ec0e0ed614e1d40"
2220 "6623f2b31d31819fec30993380dd82";
2221 break;
2222 case 512:
2223 key_hex =
2224 "5834f639000d4cf82de124fbfd26fb88d463e99f839a76ba41ac88967c80a3f61e"
2225 "1239a452e573dba0750e988152988576efd75b8d0229b7aca2ada2afd392ee";
2226 break;
2227 default:
2228 FAIL() << "Unexpected key_len_bits" << key_len_bits;
2229 }
2230
2231 // Import a raw key.
2232 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
2233 HexStringToBytes(key_hex), import_algorithm, usages);
2234
2235 // Export the key in JWK format and validate.
2236 ASSERT_EQ(Status::Success(),
2237 ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
2238 EXPECT_TRUE(VerifySecretJwk(json, jwk_alg, key_hex, usages));
2239
2240 // Import the JWK-formatted key.
2241 ASSERT_EQ(
2242 Status::Success(),
2243 ImportKeyJwk(CryptoData(json), import_algorithm, true, usages, &key));
2244 EXPECT_TRUE(key.handle());
2245 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
2246 EXPECT_EQ(import_algorithm.id(), key.algorithm().id());
2247 EXPECT_EQ(true, key.extractable());
2248 EXPECT_EQ(usages, key.usages());
2249
2250 // Export the key in raw format and compare to the original.
2251 std::vector<uint8_t> key_raw_out;
2252 ASSERT_EQ(Status::Success(),
2253 ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
2254 EXPECT_BYTES_EQ_HEX(key_hex, key_raw_out);
2255 }
2256
2257 TEST(WebCryptoAesCbcTest, ImportExportJwk) {
2258 const blink::WebCryptoAlgorithm algorithm =
2259 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
2260
2261 // AES-CBC 128
2262 ImportExportJwkSymmetricKey(
2263 128,
2264 algorithm,
2265 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
2266 "A128CBC");
2267
2268 // AES-CBC 256
2269 ImportExportJwkSymmetricKey(
2270 256, algorithm, blink::WebCryptoKeyUsageDecrypt, "A256CBC");
2271
2272 // Large usage value
2273 ImportExportJwkSymmetricKey(
2274 256,
2275 algorithm,
2276 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
2277 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2278 "A256CBC");
2279 }
2280
2281 TEST(WebCryptoAesGcmTest, ImportExportJwk) {
2282 // Some Linux test runners may not have a new enough version of NSS.
2283 if (!SupportsAesGcm()) {
2284 LOG(WARNING) << "AES GCM not supported, skipping tests";
2285 return;
2286 }
2287
2288 const blink::WebCryptoAlgorithm algorithm =
2289 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm);
2290
2291 // AES-GCM 128
2292 ImportExportJwkSymmetricKey(
2293 128,
2294 algorithm,
2295 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
2296 "A128GCM");
2297
2298 // AES-GCM 256
2299 ImportExportJwkSymmetricKey(
2300 256, algorithm, blink::WebCryptoKeyUsageDecrypt, "A256GCM");
2301 }
2302
2303 TEST(WebCryptoAesKwTest, ImportExportJwk) { 70 TEST(WebCryptoAesKwTest, ImportExportJwk) {
2304 const blink::WebCryptoAlgorithm algorithm = 71 const blink::WebCryptoAlgorithm algorithm =
2305 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw); 72 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
2306 73
2307 // AES-KW 128 74 // AES-KW 128
2308 ImportExportJwkSymmetricKey( 75 ImportExportJwkSymmetricKey(
2309 128, 76 128,
2310 algorithm, 77 algorithm,
2311 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey, 78 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2312 "A128KW"); 79 "A128KW");
2313 80
2314 // AES-KW 256 81 // AES-KW 256
2315 ImportExportJwkSymmetricKey( 82 ImportExportJwkSymmetricKey(
2316 256, 83 256,
2317 algorithm, 84 algorithm,
2318 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey, 85 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2319 "A256KW"); 86 "A256KW");
2320 } 87 }
2321 88
2322 TEST(WebCryptoHmacTest, ImportExportJwk) {
2323 // HMAC SHA-1
2324 ImportExportJwkSymmetricKey(
2325 256,
2326 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1),
2327 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
2328 "HS1");
2329
2330 // HMAC SHA-384
2331 ImportExportJwkSymmetricKey(
2332 384,
2333 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha384),
2334 blink::WebCryptoKeyUsageSign,
2335 "HS384");
2336
2337 // HMAC SHA-512
2338 ImportExportJwkSymmetricKey(
2339 512,
2340 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha512),
2341 blink::WebCryptoKeyUsageVerify,
2342 "HS512");
2343
2344 // Zero usage value
2345 ImportExportJwkSymmetricKey(
2346 512,
2347 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha512),
2348 0,
2349 "HS512");
2350 }
2351
2352 TEST(WebCryptoHmacTest, ExportJwkEmptyKey) {
2353 const blink::WebCryptoAlgorithm import_algorithm =
2354 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1);
2355
2356 blink::WebCryptoKeyUsageMask usages = blink::WebCryptoKeyUsageSign;
2357 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2358
2359 // Import a zero-byte HMAC key.
2360 const char key_data_hex[] = "";
2361 key = ImportSecretKeyFromRaw(
2362 HexStringToBytes(key_data_hex), import_algorithm, usages);
2363 EXPECT_EQ(0u, key.algorithm().hmacParams()->lengthBits());
2364
2365 // Export the key in JWK format and validate.
2366 std::vector<uint8_t> json;
2367 ASSERT_EQ(Status::Success(),
2368 ExportKey(blink::WebCryptoKeyFormatJwk, key, &json));
2369 EXPECT_TRUE(VerifySecretJwk(json, "HS1", key_data_hex, usages));
2370
2371 // Now try re-importing the JWK key.
2372 key = blink::WebCryptoKey::createNull();
2373 EXPECT_EQ(Status::Success(),
2374 ImportKey(blink::WebCryptoKeyFormatJwk,
2375 CryptoData(json),
2376 import_algorithm,
2377 true,
2378 usages,
2379 &key));
2380
2381 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
2382 EXPECT_EQ(0u, key.algorithm().hmacParams()->lengthBits());
2383
2384 std::vector<uint8_t> exported_key_data;
2385 EXPECT_EQ(Status::Success(),
2386 ExportKey(blink::WebCryptoKeyFormatRaw, key, &exported_key_data));
2387
2388 EXPECT_EQ(0u, exported_key_data.size());
2389 }
2390
2391 TEST(WebCryptoRsaSsaTest, ImportExportSpki) {
2392 // Passing case: Import a valid RSA key in SPKI format.
2393 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2394 ASSERT_EQ(Status::Success(),
2395 ImportKey(blink::WebCryptoKeyFormatSpki,
2396 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
2397 CreateRsaHashedImportAlgorithm(
2398 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2399 blink::WebCryptoAlgorithmIdSha256),
2400 true,
2401 blink::WebCryptoKeyUsageVerify,
2402 &key));
2403 EXPECT_TRUE(key.handle());
2404 EXPECT_EQ(blink::WebCryptoKeyTypePublic, key.type());
2405 EXPECT_TRUE(key.extractable());
2406 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages());
2407 EXPECT_EQ(kModulusLengthBits,
2408 key.algorithm().rsaHashedParams()->modulusLengthBits());
2409 EXPECT_BYTES_EQ_HEX(
2410 "010001",
2411 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
2412
2413 // Failing case: Empty SPKI data
2414 EXPECT_EQ(
2415 Status::ErrorImportEmptyKeyData(),
2416 ImportKey(blink::WebCryptoKeyFormatSpki,
2417 CryptoData(std::vector<uint8_t>()),
2418 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
2419 true,
2420 blink::WebCryptoKeyUsageVerify,
2421 &key));
2422
2423 // Failing case: Bad DER encoding.
2424 EXPECT_EQ(
2425 Status::DataError(),
2426 ImportKey(blink::WebCryptoKeyFormatSpki,
2427 CryptoData(HexStringToBytes("618333c4cb")),
2428 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
2429 true,
2430 blink::WebCryptoKeyUsageVerify,
2431 &key));
2432
2433 // Failing case: Import RSA key but provide an inconsistent input algorithm.
2434 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
2435 ImportKey(blink::WebCryptoKeyFormatSpki,
2436 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
2437 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
2438 true,
2439 blink::WebCryptoKeyUsageEncrypt,
2440 &key));
2441
2442 // Passing case: Export a previously imported RSA public key in SPKI format
2443 // and compare to original data.
2444 std::vector<uint8_t> output;
2445 ASSERT_EQ(Status::Success(),
2446 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
2447 EXPECT_BYTES_EQ_HEX(kPublicKeySpkiDerHex, output);
2448
2449 // Failing case: Try to export a previously imported RSA public key in raw
2450 // format (not allowed for a public key).
2451 EXPECT_EQ(Status::ErrorUnsupportedExportKeyFormat(),
2452 ExportKey(blink::WebCryptoKeyFormatRaw, key, &output));
2453
2454 // Failing case: Try to export a non-extractable key
2455 ASSERT_EQ(Status::Success(),
2456 ImportKey(blink::WebCryptoKeyFormatSpki,
2457 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
2458 CreateRsaHashedImportAlgorithm(
2459 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2460 blink::WebCryptoAlgorithmIdSha256),
2461 false,
2462 blink::WebCryptoKeyUsageVerify,
2463 &key));
2464 EXPECT_TRUE(key.handle());
2465 EXPECT_FALSE(key.extractable());
2466 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
2467 ExportKey(blink::WebCryptoKeyFormatSpki, key, &output));
2468
2469 // TODO(eroman): Failing test: Import a SPKI with an unrecognized hash OID
2470 // TODO(eroman): Failing test: Import a SPKI with invalid algorithm params
2471 // TODO(eroman): Failing test: Import a SPKI with inconsistent parameters
2472 // (e.g. SHA-1 in OID, SHA-256 in params)
2473 // TODO(eroman): Failing test: Import a SPKI for RSA-SSA, but with params
2474 // as OAEP/PSS
2475 }
2476
2477 TEST(WebCryptoRsaSsaTest, ImportExportPkcs8) {
2478 if (!SupportsRsaPrivateKeyImport())
2479 return;
2480
2481 // Passing case: Import a valid RSA key in PKCS#8 format.
2482 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2483 ASSERT_EQ(Status::Success(),
2484 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2485 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
2486 CreateRsaHashedImportAlgorithm(
2487 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2488 blink::WebCryptoAlgorithmIdSha1),
2489 true,
2490 blink::WebCryptoKeyUsageSign,
2491 &key));
2492 EXPECT_TRUE(key.handle());
2493 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, key.type());
2494 EXPECT_TRUE(key.extractable());
2495 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
2496 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
2497 key.algorithm().rsaHashedParams()->hash().id());
2498 EXPECT_EQ(kModulusLengthBits,
2499 key.algorithm().rsaHashedParams()->modulusLengthBits());
2500 EXPECT_BYTES_EQ_HEX(
2501 "010001",
2502 CryptoData(key.algorithm().rsaHashedParams()->publicExponent()));
2503
2504 std::vector<uint8_t> exported_key;
2505 ASSERT_EQ(Status::Success(),
2506 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key));
2507 EXPECT_BYTES_EQ_HEX(kPrivateKeyPkcs8DerHex, exported_key);
2508
2509 // Failing case: Empty PKCS#8 data
2510 EXPECT_EQ(Status::ErrorImportEmptyKeyData(),
2511 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2512 CryptoData(std::vector<uint8_t>()),
2513 CreateRsaHashedImportAlgorithm(
2514 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2515 blink::WebCryptoAlgorithmIdSha1),
2516 true,
2517 blink::WebCryptoKeyUsageSign,
2518 &key));
2519
2520 // Failing case: Bad DER encoding.
2521 EXPECT_EQ(
2522 Status::DataError(),
2523 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2524 CryptoData(HexStringToBytes("618333c4cb")),
2525 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
2526 true,
2527 blink::WebCryptoKeyUsageSign,
2528 &key));
2529
2530 // Failing case: Import RSA key but provide an inconsistent input algorithm
2531 // and usage. Several issues here:
2532 // * AES-CBC doesn't support PKCS8 key format
2533 // * AES-CBC doesn't support "sign" usage
2534 EXPECT_EQ(Status::ErrorUnsupportedImportKeyFormat(),
2535 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2536 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
2537 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
2538 true,
2539 blink::WebCryptoKeyUsageSign,
2540 &key));
2541 }
2542
2543 // Tests importing of PKCS8 data that does not define a valid RSA key.
2544 TEST(WebCryptoRsaSsaTest, ImportInvalidPkcs8) {
2545 if (!SupportsRsaPrivateKeyImport())
2546 return;
2547
2548 // kPrivateKeyPkcs8DerHex defines an RSA private key in PKCS8 format, whose
2549 // parameters appear at the following offsets:
2550 //
2551 // n: (offset=36, len=129)
2552 // e: (offset=167, len=3)
2553 // d: (offset=173, len=128)
2554 // p: (offset=303, len=65)
2555 // q: (offset=370, len=65)
2556 // dp: (offset=437, len=64)
2557 // dq; (offset=503, len=64)
2558 // qi: (offset=569, len=64)
2559
2560 // Do several tests, each of which invert a single byte within the input.
2561 const unsigned int kOffsetsToCorrupt[] = {
2562 50, // inside n
2563 168, // inside e
2564 175, // inside d
2565 333, // inside p
2566 373, // inside q
2567 450, // inside dp
2568 550, // inside dq
2569 600, // inside qi
2570 };
2571
2572 for (size_t test_index = 0; test_index < arraysize(kOffsetsToCorrupt);
2573 ++test_index) {
2574 SCOPED_TRACE(test_index);
2575
2576 unsigned int i = kOffsetsToCorrupt[test_index];
2577 std::vector<uint8_t> corrupted_data =
2578 HexStringToBytes(kPrivateKeyPkcs8DerHex);
2579 corrupted_data[i] = ~corrupted_data[i];
2580
2581 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2582 EXPECT_EQ(Status::DataError(),
2583 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2584 CryptoData(corrupted_data),
2585 CreateRsaHashedImportAlgorithm(
2586 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2587 blink::WebCryptoAlgorithmIdSha1),
2588 true,
2589 blink::WebCryptoKeyUsageSign,
2590 &key));
2591 }
2592 }
2593
2594 // Tests JWK import and export by doing a roundtrip key conversion and ensuring
2595 // it was lossless:
2596 //
2597 // PKCS8 --> JWK --> PKCS8
2598 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkToPkcs8RoundTrip) {
2599 if (!SupportsRsaPrivateKeyImport())
2600 return;
2601
2602 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2603 ASSERT_EQ(Status::Success(),
2604 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2605 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
2606 CreateRsaHashedImportAlgorithm(
2607 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2608 blink::WebCryptoAlgorithmIdSha1),
2609 true,
2610 blink::WebCryptoKeyUsageSign,
2611 &key));
2612
2613 std::vector<uint8_t> exported_key_jwk;
2614 ASSERT_EQ(Status::Success(),
2615 ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
2616
2617 // All of the optional parameters (p, q, dp, dq, qi) should be present in the
2618 // output.
2619 const char* expected_jwk =
2620 "{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
2621 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
2622 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
2623 "\"KPoTk4ZVvh-"
2624 "KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
2625 "gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
2626 "RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
2627 "ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
2628 "\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
2629 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
2630 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
2631 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
2632 "s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
2633 "ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
2634 "\"JxVqukEm0kqB86Uoy_sn9WiG-"
2635 "ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
2636
2637 ASSERT_EQ(CryptoData(std::string(expected_jwk)),
2638 CryptoData(exported_key_jwk));
2639
2640 ASSERT_EQ(Status::Success(),
2641 ImportKey(blink::WebCryptoKeyFormatJwk,
2642 CryptoData(exported_key_jwk),
2643 CreateRsaHashedImportAlgorithm(
2644 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2645 blink::WebCryptoAlgorithmIdSha1),
2646 true,
2647 blink::WebCryptoKeyUsageSign,
2648 &key));
2649
2650 std::vector<uint8_t> exported_key_pkcs8;
2651 ASSERT_EQ(
2652 Status::Success(),
2653 ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8));
2654
2655 ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
2656 CryptoData(exported_key_pkcs8));
2657 }
2658
2659 // Tests importing multiple RSA private keys from JWK, and then exporting to
2660 // PKCS8.
2661 //
2662 // This is a regression test for http://crbug.com/378315, for which importing
2663 // a sequence of keys from JWK could yield the wrong key. The first key would
2664 // be imported correctly, however every key after that would actually import
2665 // the first key.
2666 TEST(WebCryptoRsaSsaTest, ImportMultipleRSAPrivateKeysJwk) {
2667 if (!SupportsRsaPrivateKeyImport())
2668 return;
2669
2670 scoped_ptr<base::ListValue> key_list;
2671 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
2672
2673 // For this test to be meaningful the keys MUST be kept alive before importing
2674 // new keys.
2675 std::vector<blink::WebCryptoKey> live_keys;
2676
2677 for (size_t key_index = 0; key_index < key_list->GetSize(); ++key_index) {
2678 SCOPED_TRACE(key_index);
2679
2680 base::DictionaryValue* key_values;
2681 ASSERT_TRUE(key_list->GetDictionary(key_index, &key_values));
2682
2683 // Get the JWK representation of the key.
2684 base::DictionaryValue* key_jwk;
2685 ASSERT_TRUE(key_values->GetDictionary("jwk", &key_jwk));
2686
2687 // Get the PKCS8 representation of the key.
2688 std::string pkcs8_hex_string;
2689 ASSERT_TRUE(key_values->GetString("pkcs8", &pkcs8_hex_string));
2690 std::vector<uint8_t> pkcs8_bytes = HexStringToBytes(pkcs8_hex_string);
2691
2692 // Get the modulus length for the key.
2693 int modulus_length_bits = 0;
2694 ASSERT_TRUE(key_values->GetInteger("modulusLength", &modulus_length_bits));
2695
2696 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
2697
2698 // Import the key from JWK.
2699 ASSERT_EQ(
2700 Status::Success(),
2701 ImportKeyJwkFromDict(*key_jwk,
2702 CreateRsaHashedImportAlgorithm(
2703 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2704 blink::WebCryptoAlgorithmIdSha256),
2705 true,
2706 blink::WebCryptoKeyUsageSign,
2707 &private_key));
2708
2709 live_keys.push_back(private_key);
2710
2711 EXPECT_EQ(
2712 modulus_length_bits,
2713 static_cast<int>(
2714 private_key.algorithm().rsaHashedParams()->modulusLengthBits()));
2715
2716 // Export to PKCS8 and verify that it matches expectation.
2717 std::vector<uint8_t> exported_key_pkcs8;
2718 ASSERT_EQ(
2719 Status::Success(),
2720 ExportKey(
2721 blink::WebCryptoKeyFormatPkcs8, private_key, &exported_key_pkcs8));
2722
2723 EXPECT_BYTES_EQ(pkcs8_bytes, exported_key_pkcs8);
2724 }
2725 }
2726
2727 // Import an RSA private key using JWK. Next import a JWK containing the same
2728 // modulus, but mismatched parameters for the rest. It should NOT be possible
2729 // that the second import retrieves the first key. See http://crbug.com/378315
2730 // for how that could happen.
2731 TEST(WebCryptoRsaSsaTest, ImportJwkExistingModulusAndInvalid) {
2732 #if defined(USE_NSS)
2733 if (!NSS_VersionCheck("3.16.2")) {
2734 LOG(WARNING) << "Skipping test because lacks NSS support";
2735 return;
2736 }
2737 #endif
2738
2739 scoped_ptr<base::ListValue> key_list;
2740 ASSERT_TRUE(ReadJsonTestFileToList("rsa_private_keys.json", &key_list));
2741
2742 // Import a 1024-bit private key.
2743 base::DictionaryValue* key1_props;
2744 ASSERT_TRUE(key_list->GetDictionary(1, &key1_props));
2745 base::DictionaryValue* key1_jwk;
2746 ASSERT_TRUE(key1_props->GetDictionary("jwk", &key1_jwk));
2747
2748 blink::WebCryptoKey key1 = blink::WebCryptoKey::createNull();
2749 ASSERT_EQ(Status::Success(),
2750 ImportKeyJwkFromDict(*key1_jwk,
2751 CreateRsaHashedImportAlgorithm(
2752 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2753 blink::WebCryptoAlgorithmIdSha256),
2754 true,
2755 blink::WebCryptoKeyUsageSign,
2756 &key1));
2757
2758 ASSERT_EQ(1024u, key1.algorithm().rsaHashedParams()->modulusLengthBits());
2759
2760 // Construct a JWK using the modulus of key1, but all the other fields from
2761 // another key (also a 1024-bit private key).
2762 base::DictionaryValue* key2_props;
2763 ASSERT_TRUE(key_list->GetDictionary(5, &key2_props));
2764 base::DictionaryValue* key2_jwk;
2765 ASSERT_TRUE(key2_props->GetDictionary("jwk", &key2_jwk));
2766 std::string modulus;
2767 key1_jwk->GetString("n", &modulus);
2768 key2_jwk->SetString("n", modulus);
2769
2770 // This should fail, as the n,e,d parameters are not consistent. It MUST NOT
2771 // somehow return the key created earlier.
2772 blink::WebCryptoKey key2 = blink::WebCryptoKey::createNull();
2773 ASSERT_EQ(Status::OperationError(),
2774 ImportKeyJwkFromDict(*key2_jwk,
2775 CreateRsaHashedImportAlgorithm(
2776 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2777 blink::WebCryptoAlgorithmIdSha256),
2778 true,
2779 blink::WebCryptoKeyUsageSign,
2780 &key2));
2781 }
2782
2783 // Import a JWK RSA private key with some optional parameters missing (q, dp,
2784 // dq, qi).
2785 //
2786 // The only optional parameter included is "p".
2787 //
2788 // This fails because JWA says that producers must include either ALL optional
2789 // parameters or NONE.
2790 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkMissingOptionalParams) {
2791 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2792
2793 base::DictionaryValue dict;
2794 dict.SetString("kty", "RSA");
2795 dict.SetString("alg", "RS1");
2796
2797 dict.SetString(
2798 "n",
2799 "pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
2800 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
2801 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
2802 dict.SetString("e", "AQAB");
2803 dict.SetString(
2804 "d",
2805 "M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
2806 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
2807 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
2808
2809 dict.SetString("p",
2810 "5-"
2811 "iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31W"
2812 "hU1vZs8w0Fgs7bc0-2o5kQw");
2813
2814 ASSERT_EQ(Status::ErrorJwkPropertyMissing("q"),
2815 ImportKeyJwkFromDict(dict,
2816 CreateRsaHashedImportAlgorithm(
2817 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2818 blink::WebCryptoAlgorithmIdSha1),
2819 true,
2820 blink::WebCryptoKeyUsageSign,
2821 &key));
2822 }
2823
2824 // Import a JWK RSA private key, without any of the optional parameters.
2825 //
2826 // According to JWA, such keys are valid, but applications SHOULD
2827 // include all the parameters when sending, and recipients MAY
2828 // accept them, but are not required to. Chromium's WebCrypto does
2829 // not allow such degenerate keys.
2830 TEST(WebCryptoRsaSsaTest, ImportRsaPrivateKeyJwkIncorrectOptionalEmpty) {
2831 if (!SupportsRsaPrivateKeyImport())
2832 return;
2833
2834 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2835
2836 base::DictionaryValue dict;
2837 dict.SetString("kty", "RSA");
2838 dict.SetString("alg", "RS1");
2839
2840 dict.SetString(
2841 "n",
2842 "pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
2843 "1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
2844 "DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
2845 dict.SetString("e", "AQAB");
2846 dict.SetString(
2847 "d",
2848 "M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
2849 "kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
2850 "GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
2851
2852 ASSERT_EQ(Status::ErrorJwkPropertyMissing("p"),
2853 ImportKeyJwkFromDict(dict,
2854 CreateRsaHashedImportAlgorithm(
2855 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2856 blink::WebCryptoAlgorithmIdSha1),
2857 true,
2858 blink::WebCryptoKeyUsageSign,
2859 &key));
2860 }
2861
2862 // Tries importing a public RSA key whose exponent contains leading zeros.
2863 TEST(WebCryptoRsaSsaTest, ImportJwkRsaNonMinimalExponent) {
2864 base::DictionaryValue dict;
2865
2866 dict.SetString("kty", "RSA");
2867 dict.SetString("e", "AAEAAQ"); // 00 01 00 01
2868 dict.SetString(
2869 "n",
2870 "qLOyhK-OtQs4cDSoYPFGxJGfMYdjzWxVmMiuSBGh4KvEx-CwgtaTpef87Wdc9GaFEncsDLxk"
2871 "p0LGxjD1M8jMcvYq6DPEC_JYQumEu3i9v5fAEH1VvbZi9cTg-rmEXLUUjvc5LdOq_5OuHmtm"
2872 "e7PUJHYW1PW6ENTP0ibeiNOfFvs");
2873
2874 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
2875
2876 EXPECT_EQ(Status::ErrorJwkBigIntegerHasLeadingZero("e"),
2877 ImportKeyJwkFromDict(dict,
2878 CreateRsaHashedImportAlgorithm(
2879 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2880 blink::WebCryptoAlgorithmIdSha256),
2881 false,
2882 blink::WebCryptoKeyUsageVerify,
2883 &key));
2884 }
2885
2886 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsa) {
2887 // Note: using unrealistic short key lengths here to avoid bogging down tests.
2888
2889 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha256)
2890 const unsigned int modulus_length = 256;
2891 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
2892 blink::WebCryptoAlgorithm algorithm =
2893 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2894 blink::WebCryptoAlgorithmIdSha256,
2895 modulus_length,
2896 public_exponent);
2897 bool extractable = true;
2898 const blink::WebCryptoKeyUsageMask usage_mask = 0;
2899 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
2900 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
2901
2902 EXPECT_EQ(Status::Success(),
2903 GenerateKeyPair(
2904 algorithm, extractable, usage_mask, &public_key, &private_key));
2905 EXPECT_FALSE(public_key.isNull());
2906 EXPECT_FALSE(private_key.isNull());
2907 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
2908 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
2909 EXPECT_EQ(modulus_length,
2910 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
2911 EXPECT_EQ(modulus_length,
2912 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
2913 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
2914 public_key.algorithm().rsaHashedParams()->hash().id());
2915 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
2916 private_key.algorithm().rsaHashedParams()->hash().id());
2917 EXPECT_TRUE(public_key.extractable());
2918 EXPECT_EQ(extractable, private_key.extractable());
2919 EXPECT_EQ(usage_mask, public_key.usages());
2920 EXPECT_EQ(usage_mask, private_key.usages());
2921
2922 // Try exporting the generated key pair, and then re-importing to verify that
2923 // the exported data was valid.
2924 std::vector<uint8_t> public_key_spki;
2925 EXPECT_EQ(
2926 Status::Success(),
2927 ExportKey(blink::WebCryptoKeyFormatSpki, public_key, &public_key_spki));
2928
2929 if (SupportsRsaPrivateKeyImport()) {
2930 public_key = blink::WebCryptoKey::createNull();
2931 EXPECT_EQ(Status::Success(),
2932 ImportKey(blink::WebCryptoKeyFormatSpki,
2933 CryptoData(public_key_spki),
2934 CreateRsaHashedImportAlgorithm(
2935 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2936 blink::WebCryptoAlgorithmIdSha256),
2937 true,
2938 usage_mask,
2939 &public_key));
2940 EXPECT_EQ(modulus_length,
2941 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
2942
2943 std::vector<uint8_t> private_key_pkcs8;
2944 EXPECT_EQ(
2945 Status::Success(),
2946 ExportKey(
2947 blink::WebCryptoKeyFormatPkcs8, private_key, &private_key_pkcs8));
2948 private_key = blink::WebCryptoKey::createNull();
2949 EXPECT_EQ(Status::Success(),
2950 ImportKey(blink::WebCryptoKeyFormatPkcs8,
2951 CryptoData(private_key_pkcs8),
2952 CreateRsaHashedImportAlgorithm(
2953 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2954 blink::WebCryptoAlgorithmIdSha256),
2955 true,
2956 usage_mask,
2957 &private_key));
2958 EXPECT_EQ(modulus_length,
2959 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
2960 }
2961
2962 // Fail with bad modulus.
2963 algorithm =
2964 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2965 blink::WebCryptoAlgorithmIdSha256,
2966 0,
2967 public_exponent);
2968 EXPECT_EQ(Status::ErrorGenerateRsaUnsupportedModulus(),
2969 GenerateKeyPair(
2970 algorithm, extractable, usage_mask, &public_key, &private_key));
2971
2972 // Fail with bad exponent: larger than unsigned long.
2973 unsigned int exponent_length = sizeof(unsigned long) + 1; // NOLINT
2974 const std::vector<uint8_t> long_exponent(exponent_length, 0x01);
2975 algorithm =
2976 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2977 blink::WebCryptoAlgorithmIdSha256,
2978 modulus_length,
2979 long_exponent);
2980 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
2981 GenerateKeyPair(
2982 algorithm, extractable, usage_mask, &public_key, &private_key));
2983
2984 // Fail with bad exponent: empty.
2985 const std::vector<uint8_t> empty_exponent;
2986 algorithm =
2987 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2988 blink::WebCryptoAlgorithmIdSha256,
2989 modulus_length,
2990 empty_exponent);
2991 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
2992 GenerateKeyPair(
2993 algorithm, extractable, usage_mask, &public_key, &private_key));
2994
2995 // Fail with bad exponent: all zeros.
2996 std::vector<uint8_t> exponent_with_leading_zeros(15, 0x00);
2997 algorithm =
2998 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
2999 blink::WebCryptoAlgorithmIdSha256,
3000 modulus_length,
3001 exponent_with_leading_zeros);
3002 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
3003 GenerateKeyPair(
3004 algorithm, extractable, usage_mask, &public_key, &private_key));
3005
3006 // Key generation success using exponent with leading zeros.
3007 exponent_with_leading_zeros.insert(exponent_with_leading_zeros.end(),
3008 public_exponent.begin(),
3009 public_exponent.end());
3010 algorithm =
3011 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3012 blink::WebCryptoAlgorithmIdSha256,
3013 modulus_length,
3014 exponent_with_leading_zeros);
3015 EXPECT_EQ(Status::Success(),
3016 GenerateKeyPair(
3017 algorithm, extractable, usage_mask, &public_key, &private_key));
3018 EXPECT_FALSE(public_key.isNull());
3019 EXPECT_FALSE(private_key.isNull());
3020 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
3021 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
3022 EXPECT_TRUE(public_key.extractable());
3023 EXPECT_EQ(extractable, private_key.extractable());
3024 EXPECT_EQ(usage_mask, public_key.usages());
3025 EXPECT_EQ(usage_mask, private_key.usages());
3026
3027 // Successful WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 key generation (sha1)
3028 algorithm =
3029 CreateRsaHashedKeyGenAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3030 blink::WebCryptoAlgorithmIdSha1,
3031 modulus_length,
3032 public_exponent);
3033 EXPECT_EQ(
3034 Status::Success(),
3035 GenerateKeyPair(algorithm, false, usage_mask, &public_key, &private_key));
3036 EXPECT_FALSE(public_key.isNull());
3037 EXPECT_FALSE(private_key.isNull());
3038 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key.type());
3039 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type());
3040 EXPECT_EQ(modulus_length,
3041 public_key.algorithm().rsaHashedParams()->modulusLengthBits());
3042 EXPECT_EQ(modulus_length,
3043 private_key.algorithm().rsaHashedParams()->modulusLengthBits());
3044 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
3045 public_key.algorithm().rsaHashedParams()->hash().id());
3046 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
3047 private_key.algorithm().rsaHashedParams()->hash().id());
3048 // Even though "extractable" was set to false, the public key remains
3049 // extractable.
3050 EXPECT_TRUE(public_key.extractable());
3051 EXPECT_FALSE(private_key.extractable());
3052 EXPECT_EQ(usage_mask, public_key.usages());
3053 EXPECT_EQ(usage_mask, private_key.usages());
3054
3055 // Exporting a private key as SPKI format doesn't make sense. However this
3056 // will first fail because the key is not extractable.
3057 std::vector<uint8_t> output;
3058 EXPECT_EQ(Status::ErrorKeyNotExtractable(),
3059 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
3060
3061 // Re-generate an extractable private_key and try to export it as SPKI format.
3062 // This should fail since spki is for public keys.
3063 EXPECT_EQ(
3064 Status::Success(),
3065 GenerateKeyPair(algorithm, true, usage_mask, &public_key, &private_key));
3066 EXPECT_EQ(Status::ErrorUnexpectedKeyType(),
3067 ExportKey(blink::WebCryptoKeyFormatSpki, private_key, &output));
3068 }
3069
3070 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadModulusLength) {
3071 const unsigned int kBadModulusBits[] = {
3072 0,
3073 248, // Too small.
3074 257, // Not a multiple of 8.
3075 1023, // Not a multiple of 8.
3076 0xFFFFFFFF, // Too big.
3077 16384 + 8, // 16384 is the maxmimum length that NSS succeeds for.
3078 };
3079
3080 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
3081
3082 for (size_t i = 0; i < arraysize(kBadModulusBits); ++i) {
3083 const unsigned int modulus_length_bits = kBadModulusBits[i];
3084 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
3085 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3086 blink::WebCryptoAlgorithmIdSha256,
3087 modulus_length_bits,
3088 public_exponent);
3089 bool extractable = true;
3090 const blink::WebCryptoKeyUsageMask usage_mask = 0;
3091 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3092 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
3093
3094 EXPECT_EQ(
3095 Status::ErrorGenerateRsaUnsupportedModulus(),
3096 GenerateKeyPair(
3097 algorithm, extractable, usage_mask, &public_key, &private_key));
3098 }
3099 }
3100
3101 // Try generating RSA key pairs using unsupported public exponents. Only
3102 // exponents of 3 and 65537 are supported. While both OpenSSL and NSS can
3103 // support other values, OpenSSL hangs when given invalid exponents, so use a
3104 // whitelist to validate the parameters.
3105 TEST(WebCryptoRsaSsaTest, GenerateKeyPairRsaBadExponent) {
3106 const unsigned int modulus_length = 1024;
3107
3108 const char* const kPublicExponents[] = {
3109 "11", // 17 - This is a valid public exponent, but currently disallowed.
3110 "00",
3111 "01",
3112 "02",
3113 "010000", // 65536
3114 };
3115
3116 for (size_t i = 0; i < arraysize(kPublicExponents); ++i) {
3117 SCOPED_TRACE(i);
3118 blink::WebCryptoAlgorithm algorithm = CreateRsaHashedKeyGenAlgorithm(
3119 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3120 blink::WebCryptoAlgorithmIdSha256,
3121 modulus_length,
3122 HexStringToBytes(kPublicExponents[i]));
3123
3124 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3125 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
3126
3127 EXPECT_EQ(Status::ErrorGenerateKeyPublicExponent(),
3128 GenerateKeyPair(algorithm, true, 0, &public_key, &private_key));
3129 }
3130 }
3131
3132 TEST(WebCryptoRsaSsaTest, SignVerifyFailures) {
3133 if (!SupportsRsaPrivateKeyImport())
3134 return;
3135
3136 // Import a key pair.
3137 blink::WebCryptoAlgorithm import_algorithm =
3138 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3139 blink::WebCryptoAlgorithmIdSha1);
3140 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3141 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
3142 ASSERT_NO_FATAL_FAILURE(
3143 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
3144 HexStringToBytes(kPrivateKeyPkcs8DerHex),
3145 import_algorithm,
3146 false,
3147 blink::WebCryptoKeyUsageVerify,
3148 blink::WebCryptoKeyUsageSign,
3149 &public_key,
3150 &private_key));
3151
3152 blink::WebCryptoAlgorithm algorithm =
3153 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
3154
3155 std::vector<uint8_t> signature;
3156 bool signature_match;
3157
3158 // Compute a signature.
3159 const std::vector<uint8_t> data = HexStringToBytes("010203040506070809");
3160 ASSERT_EQ(Status::Success(),
3161 Sign(algorithm, private_key, CryptoData(data), &signature));
3162
3163 // Ensure truncated signature does not verify by passing one less byte.
3164 EXPECT_EQ(
3165 Status::Success(),
3166 Verify(algorithm,
3167 public_key,
3168 CryptoData(vector_as_array(&signature), signature.size() - 1),
3169 CryptoData(data),
3170 &signature_match));
3171 EXPECT_FALSE(signature_match);
3172
3173 // Ensure truncated signature does not verify by passing no bytes.
3174 EXPECT_EQ(Status::Success(),
3175 Verify(algorithm,
3176 public_key,
3177 CryptoData(),
3178 CryptoData(data),
3179 &signature_match));
3180 EXPECT_FALSE(signature_match);
3181
3182 // Ensure corrupted signature does not verify.
3183 std::vector<uint8_t> corrupt_sig = signature;
3184 corrupt_sig[corrupt_sig.size() / 2] ^= 0x1;
3185 EXPECT_EQ(Status::Success(),
3186 Verify(algorithm,
3187 public_key,
3188 CryptoData(corrupt_sig),
3189 CryptoData(data),
3190 &signature_match));
3191 EXPECT_FALSE(signature_match);
3192
3193 // Ensure signatures that are greater than the modulus size fail.
3194 const unsigned int long_message_size_bytes = 1024;
3195 DCHECK_GT(long_message_size_bytes, kModulusLengthBits / 8);
3196 const unsigned char kLongSignature[long_message_size_bytes] = {0};
3197 EXPECT_EQ(Status::Success(),
3198 Verify(algorithm,
3199 public_key,
3200 CryptoData(kLongSignature, sizeof(kLongSignature)),
3201 CryptoData(data),
3202 &signature_match));
3203 EXPECT_FALSE(signature_match);
3204
3205 // Ensure that signing and verifying with an incompatible algorithm fails.
3206 algorithm = CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep);
3207
3208 EXPECT_EQ(Status::ErrorUnexpected(),
3209 Sign(algorithm, private_key, CryptoData(data), &signature));
3210 EXPECT_EQ(Status::ErrorUnexpected(),
3211 Verify(algorithm,
3212 public_key,
3213 CryptoData(signature),
3214 CryptoData(data),
3215 &signature_match));
3216
3217 // Some crypto libraries (NSS) can automatically select the RSA SSA inner hash
3218 // based solely on the contents of the input signature data. In the Web Crypto
3219 // implementation, the inner hash should be specified uniquely by the key
3220 // algorithm parameter. To validate this behavior, call Verify with a computed
3221 // signature that used one hash type (SHA-1), but pass in a key with a
3222 // different inner hash type (SHA-256). If the hash type is determined by the
3223 // signature itself (undesired), the verify will pass, while if the hash type
3224 // is specified by the key algorithm (desired), the verify will fail.
3225
3226 // Compute a signature using SHA-1 as the inner hash.
3227 EXPECT_EQ(Status::Success(),
3228 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
3229 private_key,
3230 CryptoData(data),
3231 &signature));
3232
3233 blink::WebCryptoKey public_key_256 = blink::WebCryptoKey::createNull();
3234 EXPECT_EQ(Status::Success(),
3235 ImportKey(blink::WebCryptoKeyFormatSpki,
3236 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
3237 CreateRsaHashedImportAlgorithm(
3238 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3239 blink::WebCryptoAlgorithmIdSha256),
3240 true,
3241 blink::WebCryptoKeyUsageVerify,
3242 &public_key_256));
3243
3244 // Now verify using an algorithm whose inner hash is SHA-256, not SHA-1. The
3245 // signature should not verify.
3246 // NOTE: public_key was produced by generateKey, and so its associated
3247 // algorithm has WebCryptoRsaKeyGenParams and not WebCryptoRsaSsaParams. Thus
3248 // it has no inner hash to conflict with the input algorithm.
3249 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha1,
3250 private_key.algorithm().rsaHashedParams()->hash().id());
3251 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
3252 public_key_256.algorithm().rsaHashedParams()->hash().id());
3253
3254 bool is_match;
3255 EXPECT_EQ(Status::Success(),
3256 Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5),
3257 public_key_256,
3258 CryptoData(signature),
3259 CryptoData(data),
3260 &is_match));
3261 EXPECT_FALSE(is_match);
3262 }
3263
3264 TEST(WebCryptoRsaSsaTest, SignVerifyKnownAnswer) {
3265 if (!SupportsRsaPrivateKeyImport())
3266 return;
3267
3268 scoped_ptr<base::ListValue> tests;
3269 ASSERT_TRUE(ReadJsonTestFileToList("pkcs1v15_sign.json", &tests));
3270
3271 // Import the key pair.
3272 blink::WebCryptoAlgorithm import_algorithm =
3273 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
3274 blink::WebCryptoAlgorithmIdSha1);
3275 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3276 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
3277 ASSERT_NO_FATAL_FAILURE(
3278 ImportRsaKeyPair(HexStringToBytes(kPublicKeySpkiDerHex),
3279 HexStringToBytes(kPrivateKeyPkcs8DerHex),
3280 import_algorithm,
3281 false,
3282 blink::WebCryptoKeyUsageVerify,
3283 blink::WebCryptoKeyUsageSign,
3284 &public_key,
3285 &private_key));
3286
3287 blink::WebCryptoAlgorithm algorithm =
3288 CreateAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5);
3289
3290 // Validate the signatures are computed and verified as expected.
3291 std::vector<uint8_t> signature;
3292 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
3293 SCOPED_TRACE(test_index);
3294
3295 base::DictionaryValue* test;
3296 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
3297
3298 std::vector<uint8_t> test_message =
3299 GetBytesFromHexString(test, "message_hex");
3300 std::vector<uint8_t> test_signature =
3301 GetBytesFromHexString(test, "signature_hex");
3302
3303 signature.clear();
3304 ASSERT_EQ(
3305 Status::Success(),
3306 Sign(algorithm, private_key, CryptoData(test_message), &signature));
3307 EXPECT_BYTES_EQ(test_signature, signature);
3308
3309 bool is_match = false;
3310 ASSERT_EQ(Status::Success(),
3311 Verify(algorithm,
3312 public_key,
3313 CryptoData(test_signature),
3314 CryptoData(test_message),
3315 &is_match));
3316 EXPECT_TRUE(is_match);
3317 }
3318 }
3319
3320 TEST(WebCryptoAesKwTest, AesKwKeyImport) { 89 TEST(WebCryptoAesKwTest, AesKwKeyImport) {
3321 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 90 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3322 blink::WebCryptoAlgorithm algorithm = 91 blink::WebCryptoAlgorithm algorithm =
3323 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw); 92 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3324 93
3325 // Import a 128-bit Key Encryption Key (KEK) 94 // Import a 128-bit Key Encryption Key (KEK)
3326 std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939"; 95 std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
3327 ASSERT_EQ(Status::Success(), 96 ASSERT_EQ(Status::Success(),
3328 ImportKey(blink::WebCryptoKeyFormatRaw, 97 ImportKey(blink::WebCryptoKeyFormatRaw,
3329 CryptoData(HexStringToBytes(key_raw_hex_in)), 98 CryptoData(HexStringToBytes(key_raw_hex_in)),
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
3686 EXPECT_EQ(true, unwrapped_key.extractable()); 455 EXPECT_EQ(true, unwrapped_key.extractable());
3687 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, unwrapped_key.usages()); 456 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, unwrapped_key.usages());
3688 457
3689 // Export the new key's raw data and compare to the known original. 458 // Export the new key's raw data and compare to the known original.
3690 std::vector<uint8_t> raw_key; 459 std::vector<uint8_t> raw_key;
3691 EXPECT_EQ(Status::Success(), 460 EXPECT_EQ(Status::Success(),
3692 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); 461 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
3693 EXPECT_BYTES_EQ(key_data, raw_key); 462 EXPECT_BYTES_EQ(key_data, raw_key);
3694 } 463 }
3695 464
3696 // TODO(eroman):
3697 // * Test decryption when the tag length exceeds input size
3698 // * Test decryption with empty input
3699 // * Test decryption with tag length of 0.
3700 TEST(WebCryptoAesGcmTest, SampleSets) {
3701 // Some Linux test runners may not have a new enough version of NSS.
3702 if (!SupportsAesGcm()) {
3703 LOG(WARNING) << "AES GCM not supported, skipping tests";
3704 return;
3705 }
3706
3707 scoped_ptr<base::ListValue> tests;
3708 ASSERT_TRUE(ReadJsonTestFileToList("aes_gcm.json", &tests));
3709
3710 // Note that WebCrypto appends the authentication tag to the ciphertext.
3711 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
3712 SCOPED_TRACE(test_index);
3713 base::DictionaryValue* test;
3714 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
3715
3716 const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
3717 const std::vector<uint8_t> test_iv = GetBytesFromHexString(test, "iv");
3718 const std::vector<uint8_t> test_additional_data =
3719 GetBytesFromHexString(test, "additional_data");
3720 const std::vector<uint8_t> test_plain_text =
3721 GetBytesFromHexString(test, "plain_text");
3722 const std::vector<uint8_t> test_authentication_tag =
3723 GetBytesFromHexString(test, "authentication_tag");
3724 const unsigned int test_tag_size_bits = test_authentication_tag.size() * 8;
3725 const std::vector<uint8_t> test_cipher_text =
3726 GetBytesFromHexString(test, "cipher_text");
3727
3728 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
3729 test_key,
3730 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesGcm),
3731 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
3732
3733 // Verify exported raw key is identical to the imported data
3734 std::vector<uint8_t> raw_key;
3735 EXPECT_EQ(Status::Success(),
3736 ExportKey(blink::WebCryptoKeyFormatRaw, key, &raw_key));
3737
3738 EXPECT_BYTES_EQ(test_key, raw_key);
3739
3740 // Test encryption.
3741 std::vector<uint8_t> cipher_text;
3742 std::vector<uint8_t> authentication_tag;
3743 EXPECT_EQ(Status::Success(),
3744 AesGcmEncrypt(key,
3745 test_iv,
3746 test_additional_data,
3747 test_tag_size_bits,
3748 test_plain_text,
3749 &cipher_text,
3750 &authentication_tag));
3751
3752 EXPECT_BYTES_EQ(test_cipher_text, cipher_text);
3753 EXPECT_BYTES_EQ(test_authentication_tag, authentication_tag);
3754
3755 // Test decryption.
3756 std::vector<uint8_t> plain_text;
3757 EXPECT_EQ(Status::Success(),
3758 AesGcmDecrypt(key,
3759 test_iv,
3760 test_additional_data,
3761 test_tag_size_bits,
3762 test_cipher_text,
3763 test_authentication_tag,
3764 &plain_text));
3765 EXPECT_BYTES_EQ(test_plain_text, plain_text);
3766
3767 // Decryption should fail if any of the inputs are tampered with.
3768 EXPECT_EQ(Status::OperationError(),
3769 AesGcmDecrypt(key,
3770 Corrupted(test_iv),
3771 test_additional_data,
3772 test_tag_size_bits,
3773 test_cipher_text,
3774 test_authentication_tag,
3775 &plain_text));
3776 EXPECT_EQ(Status::OperationError(),
3777 AesGcmDecrypt(key,
3778 test_iv,
3779 Corrupted(test_additional_data),
3780 test_tag_size_bits,
3781 test_cipher_text,
3782 test_authentication_tag,
3783 &plain_text));
3784 EXPECT_EQ(Status::OperationError(),
3785 AesGcmDecrypt(key,
3786 test_iv,
3787 test_additional_data,
3788 test_tag_size_bits,
3789 Corrupted(test_cipher_text),
3790 test_authentication_tag,
3791 &plain_text));
3792 EXPECT_EQ(Status::OperationError(),
3793 AesGcmDecrypt(key,
3794 test_iv,
3795 test_additional_data,
3796 test_tag_size_bits,
3797 test_cipher_text,
3798 Corrupted(test_authentication_tag),
3799 &plain_text));
3800
3801 // Try different incorrect tag lengths
3802 uint8_t kAlternateTagLengths[] = {0, 8, 96, 120, 128, 160, 255};
3803 for (size_t tag_i = 0; tag_i < arraysize(kAlternateTagLengths); ++tag_i) {
3804 unsigned int wrong_tag_size_bits = kAlternateTagLengths[tag_i];
3805 if (test_tag_size_bits == wrong_tag_size_bits)
3806 continue;
3807 EXPECT_NE(Status::Success(),
3808 AesGcmDecrypt(key,
3809 test_iv,
3810 test_additional_data,
3811 wrong_tag_size_bits,
3812 test_cipher_text,
3813 test_authentication_tag,
3814 &plain_text));
3815 }
3816 }
3817 }
3818
3819 // AES 192-bit is not allowed: http://crbug.com/381829
3820 TEST(WebCryptoAesCbcTest, ImportAesCbc192Raw) {
3821 std::vector<uint8_t> key_raw(24, 0);
3822 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3823 Status status = ImportKey(blink::WebCryptoKeyFormatRaw,
3824 CryptoData(key_raw),
3825 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3826 true,
3827 blink::WebCryptoKeyUsageEncrypt,
3828 &key);
3829 ASSERT_EQ(Status::ErrorAes192BitUnsupported(), status);
3830 }
3831
3832 // AES 192-bit is not allowed: http://crbug.com/381829
3833 TEST(WebCryptoAesCbcTest, ImportAesCbc192Jwk) {
3834 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3835
3836 base::DictionaryValue dict;
3837 dict.SetString("kty", "oct");
3838 dict.SetString("alg", "A192CBC");
3839 dict.SetString("k", "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh");
3840
3841 EXPECT_EQ(
3842 Status::ErrorAes192BitUnsupported(),
3843 ImportKeyJwkFromDict(dict,
3844 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3845 false,
3846 blink::WebCryptoKeyUsageEncrypt,
3847 &key));
3848 }
3849
3850 // AES 192-bit is not allowed: http://crbug.com/381829
3851 TEST(WebCryptoAesCbcTest, GenerateAesCbc192) {
3852 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3853 Status status = GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(192),
3854 true,
3855 blink::WebCryptoKeyUsageEncrypt,
3856 &key);
3857 ASSERT_EQ(Status::ErrorAes192BitUnsupported(), status);
3858 }
3859
3860 // AES 192-bit is not allowed: http://crbug.com/381829
3861 TEST(WebCryptoAesCbcTest, UnwrapAesCbc192) {
3862 std::vector<uint8_t> wrapping_key_data(16, 0);
3863 std::vector<uint8_t> wrapped_key = HexStringToBytes(
3864 "1A07ACAB6C906E50883173C29441DB1DE91D34F45C435B5F99C822867FB3956F");
3865
3866 blink::WebCryptoKey wrapping_key =
3867 ImportSecretKeyFromRaw(wrapping_key_data,
3868 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
3869 blink::WebCryptoKeyUsageUnwrapKey);
3870
3871 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3872 ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
3873 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3874 CryptoData(wrapped_key),
3875 wrapping_key,
3876 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
3877 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3878 true,
3879 blink::WebCryptoKeyUsageEncrypt,
3880 &unwrapped_key));
3881 }
3882
3883 // TODO(eroman): move into RSA-OAEP specific file or change name.
3884 scoped_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() {
3885 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
3886 jwk->SetString("kty", "RSA");
3887 jwk->SetString("n",
3888 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex)));
3889 jwk->SetString("e",
3890 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex)));
3891 return jwk.Pass();
3892 }
3893
3894 // Import a PKCS#8 private key that uses RSAPrivateKey with the
3895 // id-rsaEncryption OID.
3896 TEST(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) {
3897 if (!SupportsRsaOaep()) {
3898 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3899 return;
3900 }
3901
3902 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
3903 ASSERT_EQ(Status::Success(),
3904 ImportKey(blink::WebCryptoKeyFormatPkcs8,
3905 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
3906 CreateRsaHashedImportAlgorithm(
3907 blink::WebCryptoAlgorithmIdRsaOaep,
3908 blink::WebCryptoAlgorithmIdSha1),
3909 true,
3910 blink::WebCryptoKeyUsageDecrypt,
3911 &private_key));
3912 }
3913
3914 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
3915 if (!SupportsRsaOaep()) {
3916 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3917 return;
3918 }
3919
3920 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
3921
3922 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3923 ASSERT_EQ(Status::Success(),
3924 ImportKeyJwkFromDict(*jwk.get(),
3925 CreateRsaHashedImportAlgorithm(
3926 blink::WebCryptoAlgorithmIdRsaOaep,
3927 blink::WebCryptoAlgorithmIdSha1),
3928 true,
3929 blink::WebCryptoKeyUsageEncrypt,
3930 &public_key));
3931 }
3932
3933 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
3934 if (!SupportsRsaOaep()) {
3935 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3936 return;
3937 }
3938
3939 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
3940 jwk->SetString("alg", "RSA-OAEP");
3941
3942 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3943 ASSERT_EQ(Status::Success(),
3944 ImportKeyJwkFromDict(*jwk.get(),
3945 CreateRsaHashedImportAlgorithm(
3946 blink::WebCryptoAlgorithmIdRsaOaep,
3947 blink::WebCryptoAlgorithmIdSha1),
3948 true,
3949 blink::WebCryptoKeyUsageEncrypt,
3950 &public_key));
3951 }
3952
3953 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
3954 if (!SupportsRsaOaep()) {
3955 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3956 return;
3957 }
3958
3959 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
3960 jwk->SetString("alg", "RSA-OAEP-512");
3961
3962 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3963 ASSERT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
3964 ImportKeyJwkFromDict(*jwk.get(),
3965 CreateRsaHashedImportAlgorithm(
3966 blink::WebCryptoAlgorithmIdRsaOaep,
3967 blink::WebCryptoAlgorithmIdSha1),
3968 true,
3969 blink::WebCryptoKeyUsageEncrypt,
3970 &public_key));
3971 }
3972
3973 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
3974 if (!SupportsRsaOaep()) {
3975 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3976 return;
3977 }
3978
3979 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
3980 jwk->SetString("kty", "oct");
3981 jwk->SetString("alg", "RSA-OAEP");
3982
3983 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
3984 ASSERT_EQ(Status::ErrorJwkUnexpectedKty("RSA"),
3985 ImportKeyJwkFromDict(*jwk.get(),
3986 CreateRsaHashedImportAlgorithm(
3987 blink::WebCryptoAlgorithmIdRsaOaep,
3988 blink::WebCryptoAlgorithmIdSha1),
3989 true,
3990 blink::WebCryptoKeyUsageEncrypt,
3991 &public_key));
3992 }
3993
3994 TEST(WebCryptoRsaOaepTest, ExportPublicJwk) {
3995 if (!SupportsRsaOaep()) {
3996 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
3997 return;
3998 }
3999
4000 struct TestData {
4001 blink::WebCryptoAlgorithmId hash_alg;
4002 const char* expected_jwk_alg;
4003 } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"},
4004 {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"},
4005 {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"},
4006 {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}};
4007 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestData); ++i) {
4008 const TestData& test_data = kTestData[i];
4009 SCOPED_TRACE(test_data.expected_jwk_alg);
4010
4011 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
4012 jwk->SetString("alg", test_data.expected_jwk_alg);
4013
4014 // Import the key in a known-good format
4015 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4016 ASSERT_EQ(Status::Success(),
4017 ImportKeyJwkFromDict(
4018 *jwk.get(),
4019 CreateRsaHashedImportAlgorithm(
4020 blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
4021 true,
4022 blink::WebCryptoKeyUsageEncrypt,
4023 &public_key));
4024
4025 // Now export the key as JWK and verify its contents
4026 std::vector<uint8_t> jwk_data;
4027 ASSERT_EQ(Status::Success(),
4028 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data));
4029 EXPECT_TRUE(VerifyPublicJwk(jwk_data,
4030 test_data.expected_jwk_alg,
4031 kPublicKeyModulusHex,
4032 kPublicKeyExponentHex,
4033 blink::WebCryptoKeyUsageEncrypt));
4034 }
4035 }
4036
4037 TEST(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
4038 if (!SupportsRsaOaep()) {
4039 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4040 return;
4041 }
4042
4043 scoped_ptr<base::ListValue> tests;
4044 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests));
4045
4046 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
4047 SCOPED_TRACE(test_index);
4048
4049 base::DictionaryValue* test = NULL;
4050 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
4051
4052 blink::WebCryptoAlgorithm digest_algorithm =
4053 GetDigestAlgorithm(test, "hash");
4054 ASSERT_FALSE(digest_algorithm.isNull());
4055 std::vector<uint8_t> public_key_der =
4056 GetBytesFromHexString(test, "public_key");
4057 std::vector<uint8_t> private_key_der =
4058 GetBytesFromHexString(test, "private_key");
4059 std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext");
4060 std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext");
4061 std::vector<uint8_t> label = GetBytesFromHexString(test, "label");
4062
4063 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
4064 blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id());
4065 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4066 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4067
4068 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(public_key_der,
4069 private_key_der,
4070 import_algorithm,
4071 false,
4072 blink::WebCryptoKeyUsageEncrypt,
4073 blink::WebCryptoKeyUsageDecrypt,
4074 &public_key,
4075 &private_key));
4076
4077 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
4078 std::vector<uint8_t> decrypted_data;
4079 ASSERT_EQ(Status::Success(),
4080 Decrypt(op_algorithm,
4081 private_key,
4082 CryptoData(ciphertext),
4083 &decrypted_data));
4084 EXPECT_BYTES_EQ(plaintext, decrypted_data);
4085 std::vector<uint8_t> encrypted_data;
4086 ASSERT_EQ(
4087 Status::Success(),
4088 Encrypt(
4089 op_algorithm, public_key, CryptoData(plaintext), &encrypted_data));
4090 std::vector<uint8_t> redecrypted_data;
4091 ASSERT_EQ(Status::Success(),
4092 Decrypt(op_algorithm,
4093 private_key,
4094 CryptoData(encrypted_data),
4095 &redecrypted_data));
4096 EXPECT_BYTES_EQ(plaintext, redecrypted_data);
4097 }
4098 }
4099
4100 TEST(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
4101 if (!SupportsRsaOaep()) {
4102 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4103 return;
4104 }
4105
4106 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1;
4107 const size_t kHashSize = 20;
4108
4109 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
4110
4111 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4112 ASSERT_EQ(Status::Success(),
4113 ImportKeyJwkFromDict(*jwk.get(),
4114 CreateRsaHashedImportAlgorithm(
4115 blink::WebCryptoAlgorithmIdRsaOaep, kHash),
4116 true,
4117 blink::WebCryptoKeyUsageEncrypt,
4118 &public_key));
4119
4120 // The maximum size of an encrypted message is:
4121 // modulus length
4122 // - 1 (leading octet)
4123 // - hash size (maskedSeed)
4124 // - hash size (lHash portion of maskedDB)
4125 // - 1 (at least one octet for the padding string)
4126 size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize);
4127
4128 // The label has no influence on the maximum message size. For simplicity,
4129 // use the empty string.
4130 std::vector<uint8_t> label;
4131 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
4132
4133 // Test that a message just before the boundary succeeds.
4134 std::string large_message;
4135 large_message.resize(kMaxMessageSize - 1, 'A');
4136
4137 std::vector<uint8_t> ciphertext;
4138 ASSERT_EQ(
4139 Status::Success(),
4140 Encrypt(
4141 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
4142
4143 // Test that a message at the boundary succeeds.
4144 large_message.resize(kMaxMessageSize, 'A');
4145 ciphertext.clear();
4146
4147 ASSERT_EQ(
4148 Status::Success(),
4149 Encrypt(
4150 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
4151
4152 // Test that a message greater than the largest size fails.
4153 large_message.resize(kMaxMessageSize + 1, 'A');
4154 ciphertext.clear();
4155
4156 ASSERT_EQ(
4157 Status::OperationError(),
4158 Encrypt(
4159 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
4160 }
4161
4162 // Ensures that if the selected hash algorithm for the RSA-OAEP message is too
4163 // large, then it is rejected, independent of the actual message to be
4164 // encrypted.
4165 // For example, a 1024-bit RSA key is too small to accomodate a message that
4166 // uses OAEP with SHA-512, since it requires 1040 bits to encode
4167 // (2 * hash size + 2 padding bytes).
4168 TEST(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
4169 if (!SupportsRsaOaep()) {
4170 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4171 return;
4172 }
4173
4174 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512;
4175
4176 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
4177
4178 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4179 ASSERT_EQ(Status::Success(),
4180 ImportKeyJwkFromDict(*jwk.get(),
4181 CreateRsaHashedImportAlgorithm(
4182 blink::WebCryptoAlgorithmIdRsaOaep, kHash),
4183 true,
4184 blink::WebCryptoKeyUsageEncrypt,
4185 &public_key));
4186
4187 // The label has no influence on the maximum message size. For simplicity,
4188 // use the empty string.
4189 std::vector<uint8_t> label;
4190 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
4191
4192 std::string small_message("A");
4193 std::vector<uint8_t> ciphertext;
4194 // This is an operation error, as the internal consistency checking of the
4195 // algorithm parameters is up to the implementation.
4196 ASSERT_EQ(
4197 Status::OperationError(),
4198 Encrypt(
4199 op_algorithm, public_key, CryptoData(small_message), &ciphertext));
4200 }
4201
4202 TEST(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) {
4203 if (!SupportsRsaOaep()) {
4204 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4205 return;
4206 }
4207
4208 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4209 ASSERT_EQ(Status::Success(),
4210 ImportKey(blink::WebCryptoKeyFormatPkcs8,
4211 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
4212 CreateRsaHashedImportAlgorithm(
4213 blink::WebCryptoAlgorithmIdRsaOaep,
4214 blink::WebCryptoAlgorithmIdSha1),
4215 true,
4216 blink::WebCryptoKeyUsageDecrypt,
4217 &private_key));
4218
4219 // The label has no influence on the maximum message size. For simplicity,
4220 // use the empty string.
4221 std::vector<uint8_t> label;
4222 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
4223
4224 std::string large_dummy_message(kModulusLengthBits / 8, 'A');
4225 std::vector<uint8_t> plaintext;
4226
4227 ASSERT_EQ(Status::OperationError(),
4228 Decrypt(op_algorithm,
4229 private_key,
4230 CryptoData(large_dummy_message),
4231 &plaintext));
4232 }
4233
4234 TEST(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
4235 if (!SupportsRsaOaep()) {
4236 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4237 return;
4238 }
4239
4240 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
4241 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
4242 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4243 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4244
4245 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
4246 HexStringToBytes(kPublicKeySpkiDerHex),
4247 HexStringToBytes(kPrivateKeyPkcs8DerHex),
4248 import_algorithm,
4249 false,
4250 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
4251 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
4252 &public_key,
4253 &private_key));
4254
4255 std::vector<uint8_t> label;
4256 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
4257
4258 const std::string key_hex = "000102030405060708090A0B0C0D0E0F";
4259 const blink::WebCryptoAlgorithm key_algorithm =
4260 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
4261
4262 blink::WebCryptoKey key =
4263 ImportSecretKeyFromRaw(HexStringToBytes(key_hex),
4264 key_algorithm,
4265 blink::WebCryptoKeyUsageEncrypt);
4266 ASSERT_FALSE(key.isNull());
4267
4268 std::vector<uint8_t> wrapped_key;
4269 ASSERT_EQ(Status::Success(),
4270 WrapKey(blink::WebCryptoKeyFormatRaw,
4271 key,
4272 public_key,
4273 wrapping_algorithm,
4274 &wrapped_key));
4275
4276 // Verify that |wrapped_key| can be decrypted and yields the key data.
4277 // Because |private_key| supports both decrypt and unwrap, this is valid.
4278 std::vector<uint8_t> decrypted_key;
4279 ASSERT_EQ(Status::Success(),
4280 Decrypt(wrapping_algorithm,
4281 private_key,
4282 CryptoData(wrapped_key),
4283 &decrypted_key));
4284 EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key);
4285
4286 // Now attempt to unwrap the key, which should also decrypt the data.
4287 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
4288 ASSERT_EQ(Status::Success(),
4289 UnwrapKey(blink::WebCryptoKeyFormatRaw,
4290 CryptoData(wrapped_key),
4291 private_key,
4292 wrapping_algorithm,
4293 key_algorithm,
4294 true,
4295 blink::WebCryptoKeyUsageEncrypt,
4296 &unwrapped_key));
4297 ASSERT_FALSE(unwrapped_key.isNull());
4298
4299 std::vector<uint8_t> raw_key;
4300 ASSERT_EQ(Status::Success(),
4301 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
4302 EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
4303 }
4304
4305 TEST(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
4306 if (!SupportsRsaOaep()) {
4307 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
4308 return;
4309 }
4310
4311 // The public and private portions of a 2048-bit RSA key with the
4312 // id-rsaEncryption OID
4313 const char kPublicKey2048SpkiDerHex[] =
4314 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce"
4315 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764"
4316 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68"
4317 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f"
4318 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08"
4319 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606"
4320 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca"
4321 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d"
4322 "5d0203010001";
4323 const char kPrivateKey2048Pkcs8DerHex[] =
4324 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201"
4325 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30"
4326 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448"
4327 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872"
4328 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34"
4329 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936"
4330 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7"
4331 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b"
4332 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3"
4333 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c"
4334 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42"
4335 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4"
4336 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62"
4337 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a"
4338 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339"
4339 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c"
4340 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3"
4341 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a"
4342 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c"
4343 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133"
4344 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622"
4345 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277"
4346 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5"
4347 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945"
4348 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b"
4349 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb"
4350 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af"
4351 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562"
4352 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792"
4353 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab"
4354 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0"
4355 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca"
4356 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0"
4357 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b";
4358 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
4359 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
4360 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4361 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4362
4363 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
4364 HexStringToBytes(kPublicKey2048SpkiDerHex),
4365 HexStringToBytes(kPrivateKey2048Pkcs8DerHex),
4366 import_algorithm,
4367 false,
4368 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
4369 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
4370 &public_key,
4371 &private_key));
4372
4373 std::vector<uint8_t> label;
4374 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
4375
4376 const std::string key_hex = "000102030405060708090a0b0c0d0e0f";
4377 const blink::WebCryptoAlgorithm key_algorithm =
4378 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
4379
4380 blink::WebCryptoKey key =
4381 ImportSecretKeyFromRaw(HexStringToBytes(key_hex),
4382 key_algorithm,
4383 blink::WebCryptoKeyUsageEncrypt);
4384 ASSERT_FALSE(key.isNull());
4385
4386 std::vector<uint8_t> wrapped_key;
4387 ASSERT_EQ(Status::Success(),
4388 WrapKey(blink::WebCryptoKeyFormatJwk,
4389 key,
4390 public_key,
4391 wrapping_algorithm,
4392 &wrapped_key));
4393
4394 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object.
4395 // Because |private_key| supports both decrypt and unwrap, this is valid.
4396 std::vector<uint8_t> decrypted_jwk;
4397 ASSERT_EQ(Status::Success(),
4398 Decrypt(wrapping_algorithm,
4399 private_key,
4400 CryptoData(wrapped_key),
4401 &decrypted_jwk));
4402 EXPECT_TRUE(VerifySecretJwk(
4403 decrypted_jwk, "A128CBC", key_hex, blink::WebCryptoKeyUsageEncrypt));
4404
4405 // Now attempt to unwrap the key, which should also decrypt the data.
4406 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
4407 ASSERT_EQ(Status::Success(),
4408 UnwrapKey(blink::WebCryptoKeyFormatJwk,
4409 CryptoData(wrapped_key),
4410 private_key,
4411 wrapping_algorithm,
4412 key_algorithm,
4413 true,
4414 blink::WebCryptoKeyUsageEncrypt,
4415 &unwrapped_key));
4416 ASSERT_FALSE(unwrapped_key.isNull());
4417
4418 std::vector<uint8_t> raw_key;
4419 ASSERT_EQ(Status::Success(),
4420 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
4421 EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
4422 }
4423
4424 // Try importing an RSA-SSA public key with unsupported key usages using SPKI
4425 // format. RSA-SSA public keys only support the 'verify' usage.
4426 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_SPKI) {
4427 const blink::WebCryptoAlgorithm algorithm =
4428 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4429 blink::WebCryptoAlgorithmIdSha256);
4430
4431 blink::WebCryptoKeyUsageMask bad_usages[] = {
4432 blink::WebCryptoKeyUsageSign,
4433 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
4434 blink::WebCryptoKeyUsageEncrypt,
4435 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
4436 };
4437
4438 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4439 SCOPED_TRACE(i);
4440
4441 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4442 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4443 ImportKey(blink::WebCryptoKeyFormatSpki,
4444 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
4445 algorithm,
4446 false,
4447 bad_usages[i],
4448 &public_key));
4449 }
4450 }
4451
4452 // Try importing an RSA-SSA public key with unsupported key usages using JWK
4453 // format. RSA-SSA public keys only support the 'verify' usage.
4454 TEST(WebCryptoRsaSsaTest, ImportRsaSsaPublicKeyBadUsage_JWK) {
4455 const blink::WebCryptoAlgorithm algorithm =
4456 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4457 blink::WebCryptoAlgorithmIdSha256);
4458
4459 blink::WebCryptoKeyUsageMask bad_usages[] = {
4460 blink::WebCryptoKeyUsageSign,
4461 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
4462 blink::WebCryptoKeyUsageEncrypt,
4463 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
4464 };
4465
4466 base::DictionaryValue dict;
4467 RestoreJwkRsaDictionary(&dict);
4468 dict.Remove("use", NULL);
4469 dict.SetString("alg", "RS256");
4470
4471 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4472 SCOPED_TRACE(i);
4473
4474 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4475 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4476 ImportKeyJwkFromDict(
4477 dict, algorithm, false, bad_usages[i], &public_key));
4478 }
4479 }
4480
4481 // Try importing an AES-CBC key with unsupported key usages using raw
4482 // format. AES-CBC keys support the following usages:
4483 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
4484 TEST(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
4485 const blink::WebCryptoAlgorithm algorithm =
4486 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
4487
4488 blink::WebCryptoKeyUsageMask bad_usages[] = {
4489 blink::WebCryptoKeyUsageSign,
4490 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageDecrypt,
4491 blink::WebCryptoKeyUsageDeriveBits,
4492 blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
4493 };
4494
4495 std::vector<uint8_t> key_bytes(16);
4496
4497 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4498 SCOPED_TRACE(i);
4499
4500 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4501 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4502 ImportKey(blink::WebCryptoKeyFormatRaw,
4503 CryptoData(key_bytes),
4504 algorithm,
4505 true,
4506 bad_usages[i],
4507 &key));
4508 }
4509 }
4510
4511 // Try importing an AES-KW key with unsupported key usages using raw 465 // Try importing an AES-KW key with unsupported key usages using raw
4512 // format. AES-KW keys support the following usages: 466 // format. AES-KW keys support the following usages:
4513 // 'wrapKey', 'unwrapKey' 467 // 'wrapKey', 'unwrapKey'
4514 TEST(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) { 468 TEST(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
4515 const blink::WebCryptoAlgorithm algorithm = 469 const blink::WebCryptoAlgorithm algorithm =
4516 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw); 470 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
4517 471
4518 blink::WebCryptoKeyUsageMask bad_usages[] = { 472 blink::WebCryptoKeyUsageMask bad_usages[] = {
4519 blink::WebCryptoKeyUsageEncrypt, 473 blink::WebCryptoKeyUsageEncrypt,
4520 blink::WebCryptoKeyUsageDecrypt, 474 blink::WebCryptoKeyUsageDecrypt,
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
4639 unwrap_algorithm, 593 unwrap_algorithm,
4640 CreateRsaHashedImportAlgorithm( 594 CreateRsaHashedImportAlgorithm(
4641 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, 595 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4642 blink::WebCryptoAlgorithmIdSha256), 596 blink::WebCryptoAlgorithmIdSha256),
4643 true, 597 true,
4644 bad_usages[i], 598 bad_usages[i],
4645 &key)); 599 &key));
4646 } 600 }
4647 } 601 }
4648 602
4649 // Generate an AES-CBC key with invalid usages. AES-CBC supports:
4650 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
4651 TEST(WebCryptoAesCbcTest, GenerateKeyBadUsages) {
4652 blink::WebCryptoKeyUsageMask bad_usages[] = {
4653 blink::WebCryptoKeyUsageSign, blink::WebCryptoKeyUsageVerify,
4654 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageVerify,
4655 };
4656
4657 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4658 SCOPED_TRACE(i);
4659
4660 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4661
4662 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4663 GenerateSecretKey(
4664 CreateAesCbcKeyGenAlgorithm(128), true, bad_usages[i], &key));
4665 }
4666 }
4667
4668 // Generate an RSA-SSA key pair with invalid usages. RSA-SSA supports:
4669 // 'sign', 'verify'
4670 TEST(WebCryptoRsaSsaTest, GenerateKeyBadUsages) {
4671 blink::WebCryptoKeyUsageMask bad_usages[] = {
4672 blink::WebCryptoKeyUsageDecrypt,
4673 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDecrypt,
4674 blink::WebCryptoKeyUsageWrapKey,
4675 };
4676
4677 const unsigned int modulus_length = 256;
4678 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
4679
4680 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4681 SCOPED_TRACE(i);
4682
4683 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4684 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4685
4686 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4687 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
4688 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4689 blink::WebCryptoAlgorithmIdSha256,
4690 modulus_length,
4691 public_exponent),
4692 true,
4693 bad_usages[i],
4694 &public_key,
4695 &private_key));
4696 }
4697 }
4698
4699 // Generate an RSA-SSA key pair. The public and private keys should select the
4700 // key usages which are applicable, and not have the exact same usages as was
4701 // specified to GenerateKey
4702 TEST(WebCryptoRsaSsaTest, GenerateKeyPairIntersectUsages) {
4703 const unsigned int modulus_length = 256;
4704 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
4705
4706 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4707 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4708
4709 ASSERT_EQ(Status::Success(),
4710 GenerateKeyPair(
4711 CreateRsaHashedKeyGenAlgorithm(
4712 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4713 blink::WebCryptoAlgorithmIdSha256,
4714 modulus_length,
4715 public_exponent),
4716 true,
4717 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
4718 &public_key,
4719 &private_key));
4720
4721 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, public_key.usages());
4722 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
4723
4724 // Try again but this time without the Verify usages.
4725 ASSERT_EQ(Status::Success(),
4726 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
4727 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4728 blink::WebCryptoAlgorithmIdSha256,
4729 modulus_length,
4730 public_exponent),
4731 true,
4732 blink::WebCryptoKeyUsageSign,
4733 &public_key,
4734 &private_key));
4735
4736 EXPECT_EQ(0, public_key.usages());
4737 EXPECT_EQ(blink::WebCryptoKeyUsageSign, private_key.usages());
4738 }
4739
4740 // Generate an AES-CBC key and an RSA key pair. Use the AES-CBC key to wrap the
4741 // key pair (using SPKI format for public key, PKCS8 format for private key).
4742 // Then unwrap the wrapped key pair and verify that the key data is the same.
4743 TEST(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
4744 if (!SupportsRsaPrivateKeyImport())
4745 return;
4746
4747 // Generate the wrapping key.
4748 blink::WebCryptoKey wrapping_key = blink::WebCryptoKey::createNull();
4749 ASSERT_EQ(Status::Success(),
4750 GenerateSecretKey(CreateAesCbcKeyGenAlgorithm(128),
4751 true,
4752 blink::WebCryptoKeyUsageWrapKey |
4753 blink::WebCryptoKeyUsageUnwrapKey,
4754 &wrapping_key));
4755
4756 // Generate an RSA key pair to be wrapped.
4757 const unsigned int modulus_length = 256;
4758 const std::vector<uint8_t> public_exponent = HexStringToBytes("010001");
4759
4760 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
4761 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
4762 ASSERT_EQ(Status::Success(),
4763 GenerateKeyPair(CreateRsaHashedKeyGenAlgorithm(
4764 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4765 blink::WebCryptoAlgorithmIdSha256,
4766 modulus_length,
4767 public_exponent),
4768 true,
4769 0,
4770 &public_key,
4771 &private_key));
4772
4773 // Export key pair as SPKI + PKCS8
4774 std::vector<uint8_t> public_key_spki;
4775 ASSERT_EQ(
4776 Status::Success(),
4777 ExportKey(blink::WebCryptoKeyFormatSpki, public_key, &public_key_spki));
4778
4779 std::vector<uint8_t> private_key_pkcs8;
4780 ASSERT_EQ(
4781 Status::Success(),
4782 ExportKey(
4783 blink::WebCryptoKeyFormatPkcs8, private_key, &private_key_pkcs8));
4784
4785 // Wrap the key pair.
4786 blink::WebCryptoAlgorithm wrap_algorithm =
4787 CreateAesCbcAlgorithm(std::vector<uint8_t>(16, 0));
4788
4789 std::vector<uint8_t> wrapped_public_key;
4790 ASSERT_EQ(Status::Success(),
4791 WrapKey(blink::WebCryptoKeyFormatSpki,
4792 public_key,
4793 wrapping_key,
4794 wrap_algorithm,
4795 &wrapped_public_key));
4796
4797 std::vector<uint8_t> wrapped_private_key;
4798 ASSERT_EQ(Status::Success(),
4799 WrapKey(blink::WebCryptoKeyFormatPkcs8,
4800 private_key,
4801 wrapping_key,
4802 wrap_algorithm,
4803 &wrapped_private_key));
4804
4805 // Unwrap the key pair.
4806 blink::WebCryptoAlgorithm rsa_import_algorithm =
4807 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4808 blink::WebCryptoAlgorithmIdSha256);
4809
4810 blink::WebCryptoKey unwrapped_public_key = blink::WebCryptoKey::createNull();
4811
4812 ASSERT_EQ(Status::Success(),
4813 UnwrapKey(blink::WebCryptoKeyFormatSpki,
4814 CryptoData(wrapped_public_key),
4815 wrapping_key,
4816 wrap_algorithm,
4817 rsa_import_algorithm,
4818 true,
4819 0,
4820 &unwrapped_public_key));
4821
4822 blink::WebCryptoKey unwrapped_private_key = blink::WebCryptoKey::createNull();
4823
4824 ASSERT_EQ(Status::Success(),
4825 UnwrapKey(blink::WebCryptoKeyFormatPkcs8,
4826 CryptoData(wrapped_private_key),
4827 wrapping_key,
4828 wrap_algorithm,
4829 rsa_import_algorithm,
4830 true,
4831 0,
4832 &unwrapped_private_key));
4833
4834 // Export unwrapped key pair as SPKI + PKCS8
4835 std::vector<uint8_t> unwrapped_public_key_spki;
4836 ASSERT_EQ(Status::Success(),
4837 ExportKey(blink::WebCryptoKeyFormatSpki,
4838 unwrapped_public_key,
4839 &unwrapped_public_key_spki));
4840
4841 std::vector<uint8_t> unwrapped_private_key_pkcs8;
4842 ASSERT_EQ(Status::Success(),
4843 ExportKey(blink::WebCryptoKeyFormatPkcs8,
4844 unwrapped_private_key,
4845 &unwrapped_private_key_pkcs8));
4846
4847 EXPECT_EQ(public_key_spki, unwrapped_public_key_spki);
4848 EXPECT_EQ(private_key_pkcs8, unwrapped_private_key_pkcs8);
4849
4850 EXPECT_NE(public_key_spki, wrapped_public_key);
4851 EXPECT_NE(private_key_pkcs8, wrapped_private_key);
4852 }
4853
4854 } // namespace 603 } // namespace
4855 604
4856 } // namespace webcrypto 605 } // namespace webcrypto
4857 606
4858 } // namespace content 607 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/test/aes_gcm_unittest.cc ('k') | content/child/webcrypto/test/hmac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698