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

Side by Side Diff: content/child/webcrypto/test/aes_cbc_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, 4 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. 20 // Creates an AES-CBC algorithm.
165 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( 21 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(
166 const std::vector<uint8_t>& iv) { 22 const std::vector<uint8_t>& iv) {
167 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( 23 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
168 blink::WebCryptoAlgorithmIdAesCbc, 24 blink::WebCryptoAlgorithmIdAesCbc,
169 new blink::WebCryptoAesCbcParams(vector_as_array(&iv), iv.size())); 25 new blink::WebCryptoAesCbcParams(vector_as_array(&iv), iv.size()));
170 } 26 }
171 27
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( 28 blink::WebCryptoAlgorithm CreateAesCbcKeyGenAlgorithm(
368 unsigned short key_length_bits) { 29 unsigned short key_length_bits) {
369 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc, 30 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesCbc,
370 key_length_bits); 31 key_length_bits);
371 } 32 }
372 33
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(
381 unsigned short key_length_bits) {
382 return CreateAesKeyGenAlgorithm(blink::WebCryptoAlgorithmIdAesKw,
383 key_length_bits);
384 }
385
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() { 34 blink::WebCryptoKey GetTestAesCbcKey() {
898 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c"; 35 const std::string key_hex = "2b7e151628aed2a6abf7158809cf4f3c";
899 blink::WebCryptoKey key = ImportSecretKeyFromRaw( 36 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
900 HexStringToBytes(key_hex), 37 HexStringToBytes(key_hex),
901 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 38 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
902 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); 39 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt);
903 40
904 // Verify exported raw key is identical to the imported data 41 // Verify exported raw key is identical to the imported data
905 std::vector<uint8_t> raw_key; 42 std::vector<uint8_t> raw_key;
906 EXPECT_EQ(Status::Success(), 43 EXPECT_EQ(Status::Success(),
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
1148 const unsigned short kKeyLen[] = {0, 127, 257}; 285 const unsigned short kKeyLen[] = {0, 127, 257};
1149 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 286 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1150 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) { 287 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
1151 SCOPED_TRACE(i); 288 SCOPED_TRACE(i);
1152 EXPECT_EQ(Status::ErrorGenerateKeyLength(), 289 EXPECT_EQ(Status::ErrorGenerateKeyLength(),
1153 GenerateSecretKey( 290 GenerateSecretKey(
1154 CreateAesCbcKeyGenAlgorithm(kKeyLen[i]), true, 0, &key)); 291 CreateAesCbcKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
1155 } 292 }
1156 } 293 }
1157 294
1158 TEST(WebCryptoAesKwTest, GenerateKeyBadLength) {
1159 const unsigned short kKeyLen[] = {0, 127, 257};
1160 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1161 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kKeyLen); ++i) {
1162 SCOPED_TRACE(i);
1163 EXPECT_EQ(Status::ErrorGenerateKeyLength(),
1164 GenerateSecretKey(
1165 CreateAesKwKeyGenAlgorithm(kKeyLen[i]), true, 0, &key));
1166 }
1167 }
1168
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. 295 // If key_ops is specified but empty, no key usages are allowed for the key.
1246 TEST(WebCryptoAesCbcTest, ImportKeyJwkEmptyKeyOps) { 296 TEST(WebCryptoAesCbcTest, ImportKeyJwkEmptyKeyOps) {
1247 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 297 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1248 base::DictionaryValue dict; 298 base::DictionaryValue dict;
1249 dict.SetString("kty", "oct"); 299 dict.SetString("kty", "oct");
1250 dict.SetBoolean("ext", false); 300 dict.SetBoolean("ext", false);
1251 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); 301 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1252 dict.Set("key_ops", new base::ListValue); // Takes ownership. 302 dict.Set("key_ops", new base::ListValue); // Takes ownership.
1253 303
1254 EXPECT_EQ( 304 EXPECT_EQ(
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1366 EXPECT_EQ( 416 EXPECT_EQ(
1367 Status::ErrorJwkKeyopsInconsistent(), 417 Status::ErrorJwkKeyopsInconsistent(),
1368 ImportKeyJwkFromDict( 418 ImportKeyJwkFromDict(
1369 dict, 419 dict,
1370 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 420 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1371 false, 421 false,
1372 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt, 422 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
1373 &key)); 423 &key));
1374 } 424 }
1375 425
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) {
1410 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1411 base::DictionaryValue dict;
1412 dict.SetString("kty", "oct");
1413 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1414 base::ListValue* key_ops = new base::ListValue;
1415 dict.Set("key_ops", key_ops); // Takes ownership.
1416
1417 key_ops->AppendString("wrapKey");
1418
1419 EXPECT_EQ(
1420 Status::Success(),
1421 ImportKeyJwkFromDict(dict,
1422 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
1423 false,
1424 blink::WebCryptoKeyUsageWrapKey,
1425 &key));
1426
1427 EXPECT_EQ(blink::WebCryptoKeyUsageWrapKey, key.usages());
1428
1429 key_ops->AppendString("unwrapKey");
1430
1431 EXPECT_EQ(
1432 Status::Success(),
1433 ImportKeyJwkFromDict(dict,
1434 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
1435 false,
1436 blink::WebCryptoKeyUsageUnwrapKey,
1437 &key));
1438
1439 EXPECT_EQ(blink::WebCryptoKeyUsageUnwrapKey, key.usages());
1440 }
1441
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) { 426 TEST(WebCryptoAesCbcTest, ImportKeyJwkUseEnc) {
1486 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 427 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1487 base::DictionaryValue dict; 428 base::DictionaryValue dict;
1488 dict.SetString("kty", "oct"); 429 dict.SetString("kty", "oct");
1489 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); 430 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
1490 431
1491 // Test JWK composite use 'enc' usage 432 // Test JWK composite use 'enc' usage
1492 dict.SetString("alg", "A128CBC"); 433 dict.SetString("alg", "A128CBC");
1493 dict.SetString("use", "enc"); 434 dict.SetString("use", "enc");
1494 EXPECT_EQ( 435 EXPECT_EQ(
1495 Status::Success(), 436 Status::Success(),
1496 ImportKeyJwkFromDict(dict, 437 ImportKeyJwkFromDict(dict,
1497 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 438 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1498 false, 439 false,
1499 blink::WebCryptoKeyUsageDecrypt | 440 blink::WebCryptoKeyUsageDecrypt |
1500 blink::WebCryptoKeyUsageEncrypt | 441 blink::WebCryptoKeyUsageEncrypt |
1501 blink::WebCryptoKeyUsageWrapKey | 442 blink::WebCryptoKeyUsageWrapKey |
1502 blink::WebCryptoKeyUsageUnwrapKey, 443 blink::WebCryptoKeyUsageUnwrapKey,
1503 &key)); 444 &key));
1504 EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt | 445 EXPECT_EQ(blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageEncrypt |
1505 blink::WebCryptoKeyUsageWrapKey | 446 blink::WebCryptoKeyUsageWrapKey |
1506 blink::WebCryptoKeyUsageUnwrapKey, 447 blink::WebCryptoKeyUsageUnwrapKey,
1507 key.usages()); 448 key.usages());
1508 } 449 }
1509 450
1510 TEST(WebCryptoAesCbcTest, ImportJwkInvalidJson) { 451 TEST(WebCryptoAesCbcTest, ImportJwkInvalidJson) {
1511 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 452 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1512 // Fail on empty JSON. 453 // Fail on empty JSON.
1513 EXPECT_EQ(Status::ErrorImportEmptyKeyData(), 454 EXPECT_EQ(Status::ErrorImportEmptyKeyData(),
1514 ImportKeyJwk(CryptoData(MakeJsonVector("")), 455 ImportKey(blink::WebCryptoKeyFormatJwk,
1515 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 456 CryptoData(MakeJsonVector("")),
1516 false, 457 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1517 blink::WebCryptoKeyUsageEncrypt, 458 false,
1518 &key)); 459 blink::WebCryptoKeyUsageEncrypt,
460 &key));
1519 461
1520 // Fail on invalid JSON. 462 // Fail on invalid JSON.
1521 const std::vector<uint8_t> bad_json_vec = MakeJsonVector( 463 const std::vector<uint8_t> bad_json_vec = MakeJsonVector(
1522 "{" 464 "{"
1523 "\"kty\" : \"oct\"," 465 "\"kty\" : \"oct\","
1524 "\"alg\" : \"HS256\"," 466 "\"alg\" : \"HS256\","
1525 "\"use\" : "); 467 "\"use\" : ");
1526 EXPECT_EQ(Status::ErrorJwkNotDictionary(), 468 EXPECT_EQ(Status::ErrorJwkNotDictionary(),
1527 ImportKeyJwk(CryptoData(bad_json_vec), 469 ImportKey(blink::WebCryptoKeyFormatJwk,
1528 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 470 CryptoData(bad_json_vec),
1529 false, 471 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1530 blink::WebCryptoKeyUsageEncrypt, 472 false,
1531 &key)); 473 blink::WebCryptoKeyUsageEncrypt,
474 &key));
1532 } 475 }
1533 476
1534 // Fail on JWK alg present but incorrect (expecting A128CBC). 477 // Fail on JWK alg present but incorrect (expecting A128CBC).
1535 TEST(WebCryptoAesCbcTest, ImportJwkIncorrectAlg) { 478 TEST(WebCryptoAesCbcTest, ImportJwkIncorrectAlg) {
1536 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 479 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
1537 480
1538 base::DictionaryValue dict; 481 base::DictionaryValue dict;
1539 dict.SetString("kty", "oct"); 482 dict.SetString("kty", "oct");
1540 dict.SetString("alg", "A127CBC"); // Not valid. 483 dict.SetString("alg", "A127CBC"); // Not valid.
1541 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); 484 dict.SetString("k", "GADWrMRHwQfoNaXU5fZvTg==");
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1833 dict.SetString("k", "dGhpcyAgaXMgIDI0ICBieXRlcyBsb25n"); 776 dict.SetString("k", "dGhpcyAgaXMgIDI0ICBieXRlcyBsb25n");
1834 EXPECT_EQ( 777 EXPECT_EQ(
1835 Status::ErrorJwkIncorrectKeyLength(), 778 Status::ErrorJwkIncorrectKeyLength(),
1836 ImportKeyJwkFromDict(dict, 779 ImportKeyJwkFromDict(dict,
1837 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 780 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
1838 false, 781 false,
1839 blink::WebCryptoKeyUsageEncrypt, 782 blink::WebCryptoKeyUsageEncrypt,
1840 &key)); 783 &key));
1841 } 784 }
1842 785
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) { 786 TEST(WebCryptoAesCbcTest, ImportExportJwk) {
2258 const blink::WebCryptoAlgorithm algorithm = 787 const blink::WebCryptoAlgorithm algorithm =
2259 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); 788 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
2260 789
2261 // AES-CBC 128 790 // AES-CBC 128
2262 ImportExportJwkSymmetricKey( 791 ImportExportJwkSymmetricKey(
2263 128, 792 128,
2264 algorithm, 793 algorithm,
2265 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt, 794 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt,
2266 "A128CBC"); 795 "A128CBC");
2267 796
2268 // AES-CBC 256 797 // AES-CBC 256
2269 ImportExportJwkSymmetricKey( 798 ImportExportJwkSymmetricKey(
2270 256, algorithm, blink::WebCryptoKeyUsageDecrypt, "A256CBC"); 799 256, algorithm, blink::WebCryptoKeyUsageDecrypt, "A256CBC");
2271 800
2272 // Large usage value 801 // Large usage value
2273 ImportExportJwkSymmetricKey( 802 ImportExportJwkSymmetricKey(
2274 256, 803 256,
2275 algorithm, 804 algorithm,
2276 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | 805 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
2277 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey, 806 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2278 "A256CBC"); 807 "A256CBC");
2279 } 808 }
2280 809
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) {
2304 const blink::WebCryptoAlgorithm algorithm =
2305 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
2306
2307 // AES-KW 128
2308 ImportExportJwkSymmetricKey(
2309 128,
2310 algorithm,
2311 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2312 "A128KW");
2313
2314 // AES-KW 256
2315 ImportExportJwkSymmetricKey(
2316 256,
2317 algorithm,
2318 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey,
2319 "A256KW");
2320 }
2321
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) {
3321 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3322 blink::WebCryptoAlgorithm algorithm =
3323 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3324
3325 // Import a 128-bit Key Encryption Key (KEK)
3326 std::string key_raw_hex_in = "025a8cf3f08b4f6c5f33bbc76a471939";
3327 ASSERT_EQ(Status::Success(),
3328 ImportKey(blink::WebCryptoKeyFormatRaw,
3329 CryptoData(HexStringToBytes(key_raw_hex_in)),
3330 algorithm,
3331 true,
3332 blink::WebCryptoKeyUsageWrapKey,
3333 &key));
3334 std::vector<uint8_t> key_raw_out;
3335 EXPECT_EQ(Status::Success(),
3336 ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
3337 EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
3338
3339 // Import a 192-bit KEK
3340 key_raw_hex_in = "c0192c6466b2370decbb62b2cfef4384544ffeb4d2fbc103";
3341 ASSERT_EQ(Status::ErrorAes192BitUnsupported(),
3342 ImportKey(blink::WebCryptoKeyFormatRaw,
3343 CryptoData(HexStringToBytes(key_raw_hex_in)),
3344 algorithm,
3345 true,
3346 blink::WebCryptoKeyUsageWrapKey,
3347 &key));
3348
3349 // Import a 256-bit Key Encryption Key (KEK)
3350 key_raw_hex_in =
3351 "e11fe66380d90fa9ebefb74e0478e78f95664d0c67ca20ce4a0b5842863ac46f";
3352 ASSERT_EQ(Status::Success(),
3353 ImportKey(blink::WebCryptoKeyFormatRaw,
3354 CryptoData(HexStringToBytes(key_raw_hex_in)),
3355 algorithm,
3356 true,
3357 blink::WebCryptoKeyUsageWrapKey,
3358 &key));
3359 EXPECT_EQ(Status::Success(),
3360 ExportKey(blink::WebCryptoKeyFormatRaw, key, &key_raw_out));
3361 EXPECT_BYTES_EQ_HEX(key_raw_hex_in, key_raw_out);
3362
3363 // Fail import of 0 length key
3364 EXPECT_EQ(Status::ErrorImportAesKeyLength(),
3365 ImportKey(blink::WebCryptoKeyFormatRaw,
3366 CryptoData(HexStringToBytes("")),
3367 algorithm,
3368 true,
3369 blink::WebCryptoKeyUsageWrapKey,
3370 &key));
3371
3372 // Fail import of 124-bit KEK
3373 key_raw_hex_in = "3e4566a2bdaa10cb68134fa66c15ddb";
3374 EXPECT_EQ(Status::ErrorImportAesKeyLength(),
3375 ImportKey(blink::WebCryptoKeyFormatRaw,
3376 CryptoData(HexStringToBytes(key_raw_hex_in)),
3377 algorithm,
3378 true,
3379 blink::WebCryptoKeyUsageWrapKey,
3380 &key));
3381
3382 // Fail import of 200-bit KEK
3383 key_raw_hex_in = "0a1d88608a5ad9fec64f1ada269ebab4baa2feeb8d95638c0e";
3384 EXPECT_EQ(Status::ErrorImportAesKeyLength(),
3385 ImportKey(blink::WebCryptoKeyFormatRaw,
3386 CryptoData(HexStringToBytes(key_raw_hex_in)),
3387 algorithm,
3388 true,
3389 blink::WebCryptoKeyUsageWrapKey,
3390 &key));
3391
3392 // Fail import of 260-bit KEK
3393 key_raw_hex_in =
3394 "72d4e475ff34215416c9ad9c8281247a4d730c5f275ac23f376e73e3bce8d7d5a";
3395 EXPECT_EQ(Status::ErrorImportAesKeyLength(),
3396 ImportKey(blink::WebCryptoKeyFormatRaw,
3397 CryptoData(HexStringToBytes(key_raw_hex_in)),
3398 algorithm,
3399 true,
3400 blink::WebCryptoKeyUsageWrapKey,
3401 &key));
3402 }
3403
3404 TEST(WebCryptoAesKwTest, UnwrapFailures) {
3405 // This test exercises the code path common to all unwrap operations.
3406 scoped_ptr<base::ListValue> tests;
3407 ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
3408 base::DictionaryValue* test;
3409 ASSERT_TRUE(tests->GetDictionary(0, &test));
3410 const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
3411 const std::vector<uint8_t> test_ciphertext =
3412 GetBytesFromHexString(test, "ciphertext");
3413
3414 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3415
3416 // Using a wrapping algorithm that does not match the wrapping key algorithm
3417 // should fail.
3418 blink::WebCryptoKey wrapping_key =
3419 ImportSecretKeyFromRaw(test_kek,
3420 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
3421 blink::WebCryptoKeyUsageUnwrapKey);
3422 EXPECT_EQ(Status::ErrorUnexpected(),
3423 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3424 CryptoData(test_ciphertext),
3425 wrapping_key,
3426 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3427 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3428 true,
3429 blink::WebCryptoKeyUsageEncrypt,
3430 &unwrapped_key));
3431 }
3432
3433 TEST(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapKnownAnswer) {
3434 scoped_ptr<base::ListValue> tests;
3435 ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
3436
3437 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
3438 SCOPED_TRACE(test_index);
3439 base::DictionaryValue* test;
3440 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
3441 const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
3442 const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
3443 const std::vector<uint8_t> test_ciphertext =
3444 GetBytesFromHexString(test, "ciphertext");
3445 const blink::WebCryptoAlgorithm wrapping_algorithm =
3446 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3447
3448 // Import the wrapping key.
3449 blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
3450 test_kek,
3451 wrapping_algorithm,
3452 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
3453
3454 // Import the key to be wrapped.
3455 blink::WebCryptoKey key = ImportSecretKeyFromRaw(
3456 test_key,
3457 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1),
3458 blink::WebCryptoKeyUsageSign);
3459
3460 // Wrap the key and verify the ciphertext result against the known answer.
3461 std::vector<uint8_t> wrapped_key;
3462 ASSERT_EQ(Status::Success(),
3463 WrapKey(blink::WebCryptoKeyFormatRaw,
3464 key,
3465 wrapping_key,
3466 wrapping_algorithm,
3467 &wrapped_key));
3468 EXPECT_BYTES_EQ(test_ciphertext, wrapped_key);
3469
3470 // Unwrap the known ciphertext to get a new test_key.
3471 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3472 ASSERT_EQ(
3473 Status::Success(),
3474 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3475 CryptoData(test_ciphertext),
3476 wrapping_key,
3477 wrapping_algorithm,
3478 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1),
3479 true,
3480 blink::WebCryptoKeyUsageSign,
3481 &unwrapped_key));
3482 EXPECT_FALSE(key.isNull());
3483 EXPECT_TRUE(key.handle());
3484 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
3485 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
3486 EXPECT_EQ(true, key.extractable());
3487 EXPECT_EQ(blink::WebCryptoKeyUsageSign, key.usages());
3488
3489 // Export the new key and compare its raw bytes with the original known key.
3490 std::vector<uint8_t> raw_key;
3491 EXPECT_EQ(Status::Success(),
3492 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
3493 EXPECT_BYTES_EQ(test_key, raw_key);
3494 }
3495 }
3496
3497 // Unwrap a HMAC key using AES-KW, and then try doing a sign/verify with the
3498 // unwrapped key
3499 TEST(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapSignVerifyHmac) {
3500 scoped_ptr<base::ListValue> tests;
3501 ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
3502
3503 base::DictionaryValue* test;
3504 ASSERT_TRUE(tests->GetDictionary(0, &test));
3505 const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
3506 const std::vector<uint8_t> test_ciphertext =
3507 GetBytesFromHexString(test, "ciphertext");
3508 const blink::WebCryptoAlgorithm wrapping_algorithm =
3509 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3510
3511 // Import the wrapping key.
3512 blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
3513 test_kek, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
3514
3515 // Unwrap the known ciphertext.
3516 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3517 ASSERT_EQ(
3518 Status::Success(),
3519 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3520 CryptoData(test_ciphertext),
3521 wrapping_key,
3522 wrapping_algorithm,
3523 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha1),
3524 false,
3525 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
3526 &key));
3527
3528 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type());
3529 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id());
3530 EXPECT_FALSE(key.extractable());
3531 EXPECT_EQ(blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify,
3532 key.usages());
3533
3534 // Sign an empty message and ensure it is verified.
3535 std::vector<uint8_t> test_message;
3536 std::vector<uint8_t> signature;
3537
3538 ASSERT_EQ(Status::Success(),
3539 Sign(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac),
3540 key,
3541 CryptoData(test_message),
3542 &signature));
3543
3544 EXPECT_GT(signature.size(), 0u);
3545
3546 bool verify_result;
3547 ASSERT_EQ(Status::Success(),
3548 Verify(CreateAlgorithm(blink::WebCryptoAlgorithmIdHmac),
3549 key,
3550 CryptoData(signature),
3551 CryptoData(test_message),
3552 &verify_result));
3553 }
3554
3555 TEST(WebCryptoAesKwTest, AesKwRawSymkeyWrapUnwrapErrors) {
3556 scoped_ptr<base::ListValue> tests;
3557 ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
3558 base::DictionaryValue* test;
3559 // Use 256 bits of data with a 256-bit KEK
3560 ASSERT_TRUE(tests->GetDictionary(3, &test));
3561 const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
3562 const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
3563 const std::vector<uint8_t> test_ciphertext =
3564 GetBytesFromHexString(test, "ciphertext");
3565 const blink::WebCryptoAlgorithm wrapping_algorithm =
3566 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3567 const blink::WebCryptoAlgorithm key_algorithm =
3568 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
3569 // Import the wrapping key.
3570 blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
3571 test_kek,
3572 wrapping_algorithm,
3573 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
3574 // Import the key to be wrapped.
3575 blink::WebCryptoKey key =
3576 ImportSecretKeyFromRaw(test_key,
3577 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3578 blink::WebCryptoKeyUsageEncrypt);
3579
3580 // Unwrap with wrapped data too small must fail.
3581 const std::vector<uint8_t> small_data(test_ciphertext.begin(),
3582 test_ciphertext.begin() + 23);
3583 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3584 EXPECT_EQ(Status::ErrorDataTooSmall(),
3585 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3586 CryptoData(small_data),
3587 wrapping_key,
3588 wrapping_algorithm,
3589 key_algorithm,
3590 true,
3591 blink::WebCryptoKeyUsageEncrypt,
3592 &unwrapped_key));
3593
3594 // Unwrap with wrapped data size not a multiple of 8 bytes must fail.
3595 const std::vector<uint8_t> unaligned_data(test_ciphertext.begin(),
3596 test_ciphertext.end() - 2);
3597 EXPECT_EQ(Status::ErrorInvalidAesKwDataLength(),
3598 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3599 CryptoData(unaligned_data),
3600 wrapping_key,
3601 wrapping_algorithm,
3602 key_algorithm,
3603 true,
3604 blink::WebCryptoKeyUsageEncrypt,
3605 &unwrapped_key));
3606 }
3607
3608 TEST(WebCryptoAesKwTest, AesKwRawSymkeyUnwrapCorruptData) {
3609 scoped_ptr<base::ListValue> tests;
3610 ASSERT_TRUE(ReadJsonTestFileToList("aes_kw.json", &tests));
3611 base::DictionaryValue* test;
3612 // Use 256 bits of data with a 256-bit KEK
3613 ASSERT_TRUE(tests->GetDictionary(3, &test));
3614 const std::vector<uint8_t> test_kek = GetBytesFromHexString(test, "kek");
3615 const std::vector<uint8_t> test_key = GetBytesFromHexString(test, "key");
3616 const std::vector<uint8_t> test_ciphertext =
3617 GetBytesFromHexString(test, "ciphertext");
3618 const blink::WebCryptoAlgorithm wrapping_algorithm =
3619 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3620
3621 // Import the wrapping key.
3622 blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
3623 test_kek,
3624 wrapping_algorithm,
3625 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey);
3626
3627 // Unwrap of a corrupted version of the known ciphertext should fail, due to
3628 // AES-KW's built-in integrity check.
3629 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3630 EXPECT_EQ(Status::OperationError(),
3631 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3632 CryptoData(Corrupted(test_ciphertext)),
3633 wrapping_key,
3634 wrapping_algorithm,
3635 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3636 true,
3637 blink::WebCryptoKeyUsageEncrypt,
3638 &unwrapped_key));
3639 }
3640
3641 TEST(WebCryptoAesKwTest, AesKwJwkSymkeyUnwrapKnownData) {
3642 // The following data lists a known HMAC SHA-256 key, then a JWK
3643 // representation of this key which was encrypted ("wrapped") using AES-KW and
3644 // the following wrapping key.
3645 // For reference, the intermediate clear JWK is
3646 // {"alg":"HS256","ext":true,"k":<b64urlKey>,"key_ops":["verify"],"kty":"oct"}
3647 // (Not shown is space padding to ensure the cleartext meets the size
3648 // requirements of the AES-KW algorithm.)
3649 const std::vector<uint8_t> key_data = HexStringToBytes(
3650 "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F");
3651 const std::vector<uint8_t> wrapped_key_data = HexStringToBytes(
3652 "14E6380B35FDC5B72E1994764B6CB7BFDD64E7832894356AAEE6C3768FC3D0F115E6B0"
3653 "6729756225F999AA99FDF81FD6A359F1576D3D23DE6CB69C3937054EB497AC1E8C38D5"
3654 "5E01B9783A20C8D930020932CF25926103002213D0FC37279888154FEBCEDF31832158"
3655 "97938C5CFE5B10B4254D0C399F39D0");
3656 const std::vector<uint8_t> wrapping_key_data =
3657 HexStringToBytes("000102030405060708090A0B0C0D0E0F");
3658 const blink::WebCryptoAlgorithm wrapping_algorithm =
3659 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
3660
3661 // Import the wrapping key.
3662 blink::WebCryptoKey wrapping_key = ImportSecretKeyFromRaw(
3663 wrapping_key_data, wrapping_algorithm, blink::WebCryptoKeyUsageUnwrapKey);
3664
3665 // Unwrap the known wrapped key data to produce a new key
3666 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
3667 ASSERT_EQ(
3668 Status::Success(),
3669 UnwrapKey(blink::WebCryptoKeyFormatJwk,
3670 CryptoData(wrapped_key_data),
3671 wrapping_key,
3672 wrapping_algorithm,
3673 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
3674 true,
3675 blink::WebCryptoKeyUsageVerify,
3676 &unwrapped_key));
3677
3678 // Validate the new key's attributes.
3679 EXPECT_FALSE(unwrapped_key.isNull());
3680 EXPECT_TRUE(unwrapped_key.handle());
3681 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, unwrapped_key.type());
3682 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, unwrapped_key.algorithm().id());
3683 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256,
3684 unwrapped_key.algorithm().hmacParams()->hash().id());
3685 EXPECT_EQ(256u, unwrapped_key.algorithm().hmacParams()->lengthBits());
3686 EXPECT_EQ(true, unwrapped_key.extractable());
3687 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, unwrapped_key.usages());
3688
3689 // Export the new key's raw data and compare to the known original.
3690 std::vector<uint8_t> raw_key;
3691 EXPECT_EQ(Status::Success(),
3692 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
3693 EXPECT_BYTES_EQ(key_data, raw_key);
3694 }
3695
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 810 // AES 192-bit is not allowed: http://crbug.com/381829
3820 TEST(WebCryptoAesCbcTest, ImportAesCbc192Raw) { 811 TEST(WebCryptoAesCbcTest, ImportAesCbc192Raw) {
3821 std::vector<uint8_t> key_raw(24, 0); 812 std::vector<uint8_t> key_raw(24, 0);
3822 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 813 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
3823 Status status = ImportKey(blink::WebCryptoKeyFormatRaw, 814 Status status = ImportKey(blink::WebCryptoKeyFormatRaw,
3824 CryptoData(key_raw), 815 CryptoData(key_raw),
3825 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 816 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3826 true, 817 true,
3827 blink::WebCryptoKeyUsageEncrypt, 818 blink::WebCryptoKeyUsageEncrypt,
3828 &key); 819 &key);
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
3873 UnwrapKey(blink::WebCryptoKeyFormatRaw, 864 UnwrapKey(blink::WebCryptoKeyFormatRaw,
3874 CryptoData(wrapped_key), 865 CryptoData(wrapped_key),
3875 wrapping_key, 866 wrapping_key,
3876 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw), 867 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw),
3877 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), 868 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc),
3878 true, 869 true,
3879 blink::WebCryptoKeyUsageEncrypt, 870 blink::WebCryptoKeyUsageEncrypt,
3880 &unwrapped_key)); 871 &unwrapped_key));
3881 } 872 }
3882 873
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 874 // Try importing an AES-CBC key with unsupported key usages using raw
4482 // format. AES-CBC keys support the following usages: 875 // format. AES-CBC keys support the following usages:
4483 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey' 876 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
4484 TEST(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) { 877 TEST(WebCryptoAesCbcTest, ImportKeyBadUsage_Raw) {
4485 const blink::WebCryptoAlgorithm algorithm = 878 const blink::WebCryptoAlgorithm algorithm =
4486 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); 879 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
4487 880
4488 blink::WebCryptoKeyUsageMask bad_usages[] = { 881 blink::WebCryptoKeyUsageMask bad_usages[] = {
4489 blink::WebCryptoKeyUsageSign, 882 blink::WebCryptoKeyUsageSign,
4490 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageDecrypt, 883 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageDecrypt,
(...skipping 10 matching lines...) Expand all
4501 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(), 894 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4502 ImportKey(blink::WebCryptoKeyFormatRaw, 895 ImportKey(blink::WebCryptoKeyFormatRaw,
4503 CryptoData(key_bytes), 896 CryptoData(key_bytes),
4504 algorithm, 897 algorithm,
4505 true, 898 true,
4506 bad_usages[i], 899 bad_usages[i],
4507 &key)); 900 &key));
4508 } 901 }
4509 } 902 }
4510 903
4511 // Try importing an AES-KW key with unsupported key usages using raw
4512 // format. AES-KW keys support the following usages:
4513 // 'wrapKey', 'unwrapKey'
4514 TEST(WebCryptoAesKwTest, ImportKeyBadUsage_Raw) {
4515 const blink::WebCryptoAlgorithm algorithm =
4516 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
4517
4518 blink::WebCryptoKeyUsageMask bad_usages[] = {
4519 blink::WebCryptoKeyUsageEncrypt,
4520 blink::WebCryptoKeyUsageDecrypt,
4521 blink::WebCryptoKeyUsageSign,
4522 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageUnwrapKey,
4523 blink::WebCryptoKeyUsageDeriveBits,
4524 blink::WebCryptoKeyUsageUnwrapKey | blink::WebCryptoKeyUsageVerify,
4525 };
4526
4527 std::vector<uint8_t> key_bytes(16);
4528
4529 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4530 SCOPED_TRACE(i);
4531
4532 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4533 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4534 ImportKey(blink::WebCryptoKeyFormatRaw,
4535 CryptoData(key_bytes),
4536 algorithm,
4537 true,
4538 bad_usages[i],
4539 &key));
4540 }
4541 }
4542
4543 // Try unwrapping an HMAC key with unsupported usages using JWK format and
4544 // AES-KW. HMAC keys support the following usages:
4545 // 'sign', 'verify'
4546 TEST(WebCryptoAesKwTest, UnwrapHmacKeyBadUsage_JWK) {
4547 const blink::WebCryptoAlgorithm unwrap_algorithm =
4548 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
4549
4550 blink::WebCryptoKeyUsageMask bad_usages[] = {
4551 blink::WebCryptoKeyUsageEncrypt,
4552 blink::WebCryptoKeyUsageDecrypt,
4553 blink::WebCryptoKeyUsageWrapKey,
4554 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
4555 blink::WebCryptoKeyUsageVerify | blink::WebCryptoKeyUsageDeriveKey,
4556 };
4557
4558 // Import the wrapping key.
4559 blink::WebCryptoKey wrapping_key = blink::WebCryptoKey::createNull();
4560 ASSERT_EQ(Status::Success(),
4561 ImportKey(blink::WebCryptoKeyFormatRaw,
4562 CryptoData(std::vector<uint8_t>(16)),
4563 unwrap_algorithm,
4564 true,
4565 blink::WebCryptoKeyUsageUnwrapKey,
4566 &wrapping_key));
4567
4568 // The JWK plain text is:
4569 // { "kty": "oct","alg": "HS256","k": "GADWrMRHwQfoNaXU5fZvTg=="}
4570 const char* kWrappedJwk =
4571 "0AA245F17064FFB2A7A094436A39BEBFC962C627303D1327EA750CE9F917688C2782A943"
4572 "7AE7586547AC490E8AE7D5B02D63868D5C3BB57D36C4C8C5BF3962ACEC6F42E767E5706"
4573 "4";
4574
4575 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4576 SCOPED_TRACE(i);
4577
4578 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4579
4580 ASSERT_EQ(
4581 Status::ErrorCreateKeyBadUsages(),
4582 UnwrapKey(blink::WebCryptoKeyFormatJwk,
4583 CryptoData(HexStringToBytes(kWrappedJwk)),
4584 wrapping_key,
4585 unwrap_algorithm,
4586 CreateHmacImportAlgorithm(blink::WebCryptoAlgorithmIdSha256),
4587 true,
4588 bad_usages[i],
4589 &key));
4590 }
4591 }
4592
4593 // Try unwrapping an RSA-SSA public key with unsupported usages using JWK format
4594 // and AES-KW. RSA-SSA public keys support the following usages:
4595 // 'verify'
4596 TEST(WebCryptoAesKwTest, UnwrapRsaSsaPublicKeyBadUsage_JWK) {
4597 const blink::WebCryptoAlgorithm unwrap_algorithm =
4598 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesKw);
4599
4600 blink::WebCryptoKeyUsageMask bad_usages[] = {
4601 blink::WebCryptoKeyUsageEncrypt,
4602 blink::WebCryptoKeyUsageSign,
4603 blink::WebCryptoKeyUsageDecrypt,
4604 blink::WebCryptoKeyUsageWrapKey,
4605 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageWrapKey,
4606 };
4607
4608 // Import the wrapping key.
4609 blink::WebCryptoKey wrapping_key = blink::WebCryptoKey::createNull();
4610 ASSERT_EQ(Status::Success(),
4611 ImportKey(blink::WebCryptoKeyFormatRaw,
4612 CryptoData(std::vector<uint8_t>(16)),
4613 unwrap_algorithm,
4614 true,
4615 blink::WebCryptoKeyUsageUnwrapKey,
4616 &wrapping_key));
4617
4618 // The JWK plaintext is:
4619 // { "kty": "RSA","alg": "RS256","n": "...","e": "AQAB"}
4620
4621 const char* kWrappedJwk =
4622 "CE8DAEF99E977EE58958B8C4494755C846E883B2ECA575C5366622839AF71AB30875F152"
4623 "E8E33E15A7817A3A2874EB53EFE05C774D98BC936BA9BA29BEB8BB3F3C3CE2323CB3359D"
4624 "E3F426605CF95CCF0E01E870ABD7E35F62E030B5FB6E520A5885514D1D850FB64B57806D"
4625 "1ADA57C6E27DF345D8292D80F6B074F1BE51C4CF3D76ECC8886218551308681B44FAC60B"
4626 "8CF6EA439BC63239103D0AE81ADB96F908680586C6169284E32EB7DD09D31103EBDAC0C2"
4627 "40C72DCF0AEA454113CC47457B13305B25507CBEAB9BDC8D8E0F867F9167F9DCEF0D9F9B"
4628 "30F2EE83CEDFD51136852C8A5939B768";
4629
4630 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4631 SCOPED_TRACE(i);
4632
4633 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4634
4635 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4636 UnwrapKey(blink::WebCryptoKeyFormatJwk,
4637 CryptoData(HexStringToBytes(kWrappedJwk)),
4638 wrapping_key,
4639 unwrap_algorithm,
4640 CreateRsaHashedImportAlgorithm(
4641 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
4642 blink::WebCryptoAlgorithmIdSha256),
4643 true,
4644 bad_usages[i],
4645 &key));
4646 }
4647 }
4648
4649 // Generate an AES-CBC key with invalid usages. AES-CBC supports: 904 // Generate an AES-CBC key with invalid usages. AES-CBC supports:
4650 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey' 905 // 'encrypt', 'decrypt', 'wrapKey', 'unwrapKey'
4651 TEST(WebCryptoAesCbcTest, GenerateKeyBadUsages) { 906 TEST(WebCryptoAesCbcTest, GenerateKeyBadUsages) {
4652 blink::WebCryptoKeyUsageMask bad_usages[] = { 907 blink::WebCryptoKeyUsageMask bad_usages[] = {
4653 blink::WebCryptoKeyUsageSign, blink::WebCryptoKeyUsageVerify, 908 blink::WebCryptoKeyUsageSign, blink::WebCryptoKeyUsageVerify,
4654 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageVerify, 909 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageVerify,
4655 }; 910 };
4656 911
4657 for (size_t i = 0; i < arraysize(bad_usages); ++i) { 912 for (size_t i = 0; i < arraysize(bad_usages); ++i) {
4658 SCOPED_TRACE(i); 913 SCOPED_TRACE(i);
4659 914
4660 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 915 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
4661 916
4662 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(), 917 ASSERT_EQ(Status::ErrorCreateKeyBadUsages(),
4663 GenerateSecretKey( 918 GenerateSecretKey(
4664 CreateAesCbcKeyGenAlgorithm(128), true, bad_usages[i], &key)); 919 CreateAesCbcKeyGenAlgorithm(128), true, bad_usages[i], &key));
4665 } 920 }
4666 } 921 }
4667 922
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 923 // 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). 924 // 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. 925 // Then unwrap the wrapped key pair and verify that the key data is the same.
4743 TEST(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) { 926 TEST(WebCryptoAesCbcTest, WrapUnwrapRoundtripSpkiPkcs8) {
4744 if (!SupportsRsaPrivateKeyImport()) 927 if (!SupportsRsaPrivateKeyImport())
4745 return; 928 return;
4746 929
4747 // Generate the wrapping key. 930 // Generate the wrapping key.
4748 blink::WebCryptoKey wrapping_key = blink::WebCryptoKey::createNull(); 931 blink::WebCryptoKey wrapping_key = blink::WebCryptoKey::createNull();
4749 ASSERT_EQ(Status::Success(), 932 ASSERT_EQ(Status::Success(),
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
4849 1032
4850 EXPECT_NE(public_key_spki, wrapped_public_key); 1033 EXPECT_NE(public_key_spki, wrapped_public_key);
4851 EXPECT_NE(private_key_pkcs8, wrapped_private_key); 1034 EXPECT_NE(private_key_pkcs8, wrapped_private_key);
4852 } 1035 }
4853 1036
4854 } // namespace 1037 } // namespace
4855 1038
4856 } // namespace webcrypto 1039 } // namespace webcrypto
4857 1040
4858 } // namespace content 1041 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/shared_crypto_unittest.cc ('k') | content/child/webcrypto/test/aes_gcm_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698