OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 11 #include "base/json/json_writer.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
13 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
14 #include "content/public/renderer/content_renderer_client.h" | 15 #include "content/public/renderer/content_renderer_client.h" |
15 #include "content/renderer/renderer_webkitplatformsupport_impl.h" | 16 #include "content/renderer/renderer_webkitplatformsupport_impl.h" |
| 17 #include "content/renderer/webcrypto/webcrypto_util.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
20 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | 22 #include "third_party/WebKit/public/platform/WebCryptoKey.h" |
21 | 23 |
| 24 namespace content { |
| 25 |
22 namespace { | 26 namespace { |
23 | 27 |
24 std::vector<uint8> HexStringToBytes(const std::string& hex) { | 28 std::vector<uint8> HexStringToBytes(const std::string& hex) { |
25 std::vector<uint8> bytes; | 29 std::vector<uint8> bytes; |
26 base::HexStringToBytes(hex, &bytes); | 30 base::HexStringToBytes(hex, &bytes); |
27 return bytes; | 31 return bytes; |
28 } | 32 } |
29 | 33 |
30 void ExpectArrayBufferMatchesHex(const std::string& expected_hex, | 34 void ExpectArrayBufferMatchesHex(const std::string& expected_hex, |
31 const blink::WebArrayBuffer& array_buffer) { | 35 const blink::WebArrayBuffer& array_buffer) { |
32 EXPECT_STRCASEEQ( | 36 EXPECT_STRCASEEQ( |
33 expected_hex.c_str(), | 37 expected_hex.c_str(), |
34 base::HexEncode( | 38 base::HexEncode( |
35 array_buffer.data(), array_buffer.byteLength()).c_str()); | 39 array_buffer.data(), array_buffer.byteLength()).c_str()); |
36 } | 40 } |
37 | 41 |
38 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | 42 std::vector<uint8> MakeJsonVector(const std::string& json_string) { |
39 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | 43 return std::vector<uint8>(json_string.begin(), json_string.end()); |
40 } | 44 } |
41 | 45 |
42 blink::WebCryptoAlgorithm CreateHmacAlgorithm( | 46 std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) { |
43 blink::WebCryptoAlgorithmId hashId) { | 47 std::string json; |
44 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 48 base::JSONWriter::Write(&dict, &json); |
45 blink::WebCryptoAlgorithmIdHmac, | 49 return MakeJsonVector(json); |
46 new blink::WebCryptoHmacParams(CreateAlgorithm(hashId))); | |
47 } | 50 } |
48 | 51 |
49 blink::WebCryptoAlgorithm CreateHmacKeyAlgorithm( | 52 // Helper for ImportJwkBadJwk; restores JWK JSON dictionary to a good state |
50 blink::WebCryptoAlgorithmId hashId, | 53 void RestoreDictionaryForImportBadJwkTest(base::DictionaryValue* dict) { |
51 unsigned hash_length) { | 54 dict->Clear(); |
52 // hash_length < 0 means unspecified | 55 dict->SetString("kty", "oct"); |
53 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 56 dict->SetString("alg", "A128CBC"); |
54 blink::WebCryptoAlgorithmIdHmac, | 57 dict->SetString("use", "enc"); |
55 new blink::WebCryptoHmacKeyParams(CreateAlgorithm(hashId), | 58 dict->SetBoolean("extractable", false); |
56 (hash_length != 0), | 59 dict->SetString("k", "GADWrMRHwQfoNaXU5fZvTg=="); |
57 hash_length)); | |
58 } | |
59 | |
60 // Returns a pointer to the start of |data|, or NULL if it is empty. This is a | |
61 // convenience function for getting the pointer, and should not be used beyond | |
62 // the expected lifetime of |data|. | |
63 const uint8* Start(const std::vector<uint8>& data) { | |
64 if (data.empty()) | |
65 return NULL; | |
66 return &data[0]; | |
67 } | |
68 | |
69 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( | |
70 const std::vector<uint8>& iv) { | |
71 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
72 blink::WebCryptoAlgorithmIdAesCbc, | |
73 new blink::WebCryptoAesCbcParams(Start(iv), iv.size())); | |
74 } | |
75 | |
76 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm( | |
77 unsigned short key_length_bits) { // NOLINT | |
78 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
79 blink::WebCryptoAlgorithmIdAesCbc, | |
80 new blink::WebCryptoAesKeyGenParams(key_length_bits)); | |
81 } | 60 } |
82 | 61 |
83 blink::WebCryptoAlgorithm CreateRsaAlgorithm( | 62 blink::WebCryptoAlgorithm CreateRsaAlgorithm( |
84 blink::WebCryptoAlgorithmId algorithm_id, | 63 blink::WebCryptoAlgorithmId algorithm_id, |
85 unsigned modulus_length, | 64 unsigned modulus_length, |
86 const std::vector<uint8>& public_exponent) { | 65 const std::vector<uint8>& public_exponent) { |
87 DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 66 DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
88 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 67 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
89 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep); | 68 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep); |
90 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 69 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
91 algorithm_id, | 70 algorithm_id, |
92 new blink::WebCryptoRsaKeyGenParams( | 71 new blink::WebCryptoRsaKeyGenParams( |
93 modulus_length, Start(public_exponent), public_exponent.size())); | 72 modulus_length, |
| 73 Start(public_exponent), |
| 74 public_exponent.size())); |
94 } | 75 } |
95 | 76 |
96 } // namespace | 77 } // namespace |
97 | 78 |
98 namespace content { | |
99 | |
100 class WebCryptoImplTest : public testing::Test { | 79 class WebCryptoImplTest : public testing::Test { |
101 protected: | 80 protected: |
102 blink::WebCryptoKey ImportSecretKeyFromRawHexString( | 81 blink::WebCryptoKey ImportSecretKeyFromRawHexString( |
103 const std::string& key_hex, | 82 const std::string& key_hex, |
104 const blink::WebCryptoAlgorithm& algorithm, | 83 const blink::WebCryptoAlgorithm& algorithm, |
105 blink::WebCryptoKeyUsageMask usage) { | 84 blink::WebCryptoKeyUsageMask usage) { |
106 std::vector<uint8> key_raw = HexStringToBytes(key_hex); | 85 std::vector<uint8> key_raw = HexStringToBytes(key_hex); |
107 | 86 |
108 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 87 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
109 bool extractable = true; | 88 bool extractable = true; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 | 198 |
220 bool DecryptInternal( | 199 bool DecryptInternal( |
221 const blink::WebCryptoAlgorithm& algorithm, | 200 const blink::WebCryptoAlgorithm& algorithm, |
222 const blink::WebCryptoKey& key, | 201 const blink::WebCryptoKey& key, |
223 const std::vector<uint8>& data, | 202 const std::vector<uint8>& data, |
224 blink::WebArrayBuffer* buffer) { | 203 blink::WebArrayBuffer* buffer) { |
225 return crypto_.DecryptInternal( | 204 return crypto_.DecryptInternal( |
226 algorithm, key, Start(data), data.size(), buffer); | 205 algorithm, key, Start(data), data.size(), buffer); |
227 } | 206 } |
228 | 207 |
| 208 bool ImportKeyJwk( |
| 209 const std::vector<uint8>& key_data, |
| 210 const blink::WebCryptoAlgorithm& algorithm, |
| 211 bool extractable, |
| 212 blink::WebCryptoKeyUsageMask usage_mask, |
| 213 blink::WebCryptoKey* key) { |
| 214 return crypto_.ImportKeyJwk(Start(key_data), |
| 215 key_data.size(), |
| 216 algorithm, |
| 217 extractable, |
| 218 usage_mask, |
| 219 key); |
| 220 } |
| 221 |
229 private: | 222 private: |
230 WebCryptoImpl crypto_; | 223 WebCryptoImpl crypto_; |
231 }; | 224 }; |
232 | 225 |
233 TEST_F(WebCryptoImplTest, DigestSampleSets) { | 226 TEST_F(WebCryptoImplTest, DigestSampleSets) { |
234 // The results are stored here in hex format for readability. | 227 // The results are stored here in hex format for readability. |
235 // | 228 // |
236 // TODO(bryaneyler): Eventually, all these sample test sets should be replaced | 229 // TODO(bryaneyler): Eventually, all these sample test sets should be replaced |
237 // with the sets here: http://csrc.nist.gov/groups/STM/cavp/index.html#03 | 230 // with the sets here: http://csrc.nist.gov/groups/STM/cavp/index.html#03 |
238 // | 231 // |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 // mac | 390 // mac |
398 "4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b", | 391 "4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b", |
399 }, | 392 }, |
400 }; | 393 }; |
401 | 394 |
402 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); | 395 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); |
403 ++test_index) { | 396 ++test_index) { |
404 SCOPED_TRACE(test_index); | 397 SCOPED_TRACE(test_index); |
405 const TestCase& test = kTests[test_index]; | 398 const TestCase& test = kTests[test_index]; |
406 | 399 |
407 blink::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); | 400 blink::WebCryptoAlgorithm algorithm = |
| 401 CreateHmacAlgorithmByHashId(test.algorithm); |
408 | 402 |
409 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 403 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
410 test.key, algorithm, blink::WebCryptoKeyUsageSign); | 404 test.key, algorithm, blink::WebCryptoKeyUsageSign); |
411 | 405 |
412 std::vector<uint8> message_raw = HexStringToBytes(test.message); | 406 std::vector<uint8> message_raw = HexStringToBytes(test.message); |
413 | 407 |
414 blink::WebArrayBuffer output; | 408 blink::WebArrayBuffer output; |
415 | 409 |
416 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | 410 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
417 | 411 |
(...skipping 25 matching lines...) Expand all Loading... |
443 algorithm, | 437 algorithm, |
444 key, | 438 key, |
445 kLongSignature, | 439 kLongSignature, |
446 sizeof(kLongSignature), | 440 sizeof(kLongSignature), |
447 message_raw, | 441 message_raw, |
448 &signature_match)); | 442 &signature_match)); |
449 EXPECT_FALSE(signature_match); | 443 EXPECT_FALSE(signature_match); |
450 } | 444 } |
451 } | 445 } |
452 | 446 |
| 447 #if !defined(USE_OPENSSL) |
| 448 |
453 TEST_F(WebCryptoImplTest, AesCbcFailures) { | 449 TEST_F(WebCryptoImplTest, AesCbcFailures) { |
454 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 450 blink::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
455 "2b7e151628aed2a6abf7158809cf4f3c", | 451 "2b7e151628aed2a6abf7158809cf4f3c", |
456 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), | 452 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
457 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); | 453 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt); |
458 | 454 |
459 blink::WebArrayBuffer output; | 455 blink::WebArrayBuffer output; |
460 | 456 |
461 // Use an invalid |iv| (fewer than 16 bytes) | 457 // Use an invalid |iv| (fewer than 16 bytes) |
462 { | 458 { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
637 cipher_text.size() - 3, | 633 cipher_text.size() - 3, |
638 &output)); | 634 &output)); |
639 } | 635 } |
640 } | 636 } |
641 } | 637 } |
642 | 638 |
643 // TODO(padolph): Add test to verify generated symmetric keys appear random. | 639 // TODO(padolph): Add test to verify generated symmetric keys appear random. |
644 | 640 |
645 TEST_F(WebCryptoImplTest, GenerateKeyAes) { | 641 TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
646 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 642 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
647 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); | 643 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(128), &key)); |
648 EXPECT_TRUE(key.handle()); | 644 EXPECT_TRUE(key.handle()); |
649 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 645 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
650 } | 646 } |
651 | 647 |
652 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { | 648 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
653 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 649 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
654 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); | 650 EXPECT_FALSE( |
655 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); | 651 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); |
| 652 EXPECT_FALSE( |
| 653 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); |
| 654 EXPECT_FALSE( |
| 655 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(129), &key)); |
656 } | 656 } |
657 | 657 |
| 658 |
658 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { | 659 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
659 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 660 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
660 blink::WebCryptoAlgorithm algorithm = | 661 blink::WebCryptoAlgorithm algorithm = |
661 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128); | 662 CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 128); |
662 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 663 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
663 EXPECT_FALSE(key.isNull()); | 664 EXPECT_FALSE(key.isNull()); |
664 EXPECT_TRUE(key.handle()); | 665 EXPECT_TRUE(key.handle()); |
665 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 666 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
666 } | 667 } |
667 | 668 |
668 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { | 669 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
669 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 670 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
670 blink::WebCryptoAlgorithm algorithm = | 671 blink::WebCryptoAlgorithm algorithm = |
671 CreateHmacKeyAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); | 672 CreateHmacKeyGenAlgorithm(blink::WebCryptoAlgorithmIdSha1, 0); |
672 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 673 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
673 EXPECT_TRUE(key.handle()); | 674 EXPECT_TRUE(key.handle()); |
674 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 675 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
675 } | 676 } |
676 | 677 |
677 TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { | 678 TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { |
678 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); | 679 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
679 | 680 |
680 // This fails because the algorithm is null. | 681 // This fails because the algorithm is null. |
681 EXPECT_FALSE(ImportKeyInternal( | 682 EXPECT_FALSE(ImportKeyInternal( |
682 blink::WebCryptoKeyFormatRaw, | 683 blink::WebCryptoKeyFormatRaw, |
683 HexStringToBytes("00000000000000000000"), | 684 HexStringToBytes("00000000000000000000"), |
684 blink::WebCryptoAlgorithm::createNull(), | 685 blink::WebCryptoAlgorithm::createNull(), |
685 blink::WebCryptoKeyUsageSign, | 686 blink::WebCryptoKeyUsageSign, |
686 &key)); | 687 &key)); |
687 } | 688 } |
688 | 689 |
| 690 #endif //#if !defined(USE_OPENSSL) |
| 691 |
| 692 TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
| 693 |
| 694 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 695 blink::WebCryptoAlgorithm algorithm = |
| 696 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); |
| 697 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageEncrypt; |
| 698 |
| 699 // Baseline pass: each test below breaks a single item, so we start with a |
| 700 // passing case to make sure each failure is caused by the isolated break. |
| 701 // Each breaking subtest below resets the dictionary to this passing case when |
| 702 // complete. |
| 703 base::DictionaryValue dict; |
| 704 RestoreDictionaryForImportBadJwkTest(&dict); |
| 705 std::vector<uint8> json_vec = MakeJsonVector(dict); |
| 706 EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 707 |
| 708 // Fail on empty JSON. |
| 709 EXPECT_FALSE(ImportKeyJwk( |
| 710 MakeJsonVector(""), algorithm, false, usage_mask, &key)); |
| 711 |
| 712 // Fail on invalid JSON. |
| 713 const std::vector<uint8> bad_json_vec = MakeJsonVector( |
| 714 "{" |
| 715 "\"kty\" : \"oct\"," |
| 716 "\"alg\" : \"HS256\"," |
| 717 "\"use\" : " |
| 718 ); |
| 719 EXPECT_FALSE(ImportKeyJwk(bad_json_vec, algorithm, false, usage_mask, &key)); |
| 720 |
| 721 // Fail on JWK alg present but unrecognized. |
| 722 dict.SetString("alg", "A127CBC"); |
| 723 json_vec = MakeJsonVector(dict); |
| 724 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 725 RestoreDictionaryForImportBadJwkTest(&dict); |
| 726 |
| 727 // Fail on both JWK and input algorithm missing. |
| 728 dict.Remove("alg", NULL); |
| 729 json_vec = MakeJsonVector(dict); |
| 730 EXPECT_FALSE(ImportKeyJwk(json_vec, |
| 731 blink::WebCryptoAlgorithm::createNull(), |
| 732 false, |
| 733 usage_mask, |
| 734 &key)); |
| 735 RestoreDictionaryForImportBadJwkTest(&dict); |
| 736 |
| 737 // Fail on invalid kty. |
| 738 dict.SetString("kty", "foo"); |
| 739 json_vec = MakeJsonVector(dict); |
| 740 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 741 RestoreDictionaryForImportBadJwkTest(&dict); |
| 742 |
| 743 // Fail on missing kty. |
| 744 dict.Remove("kty", NULL); |
| 745 json_vec = MakeJsonVector(dict); |
| 746 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 747 RestoreDictionaryForImportBadJwkTest(&dict); |
| 748 |
| 749 // Fail on invalid use. |
| 750 dict.SetString("use", "foo"); |
| 751 json_vec = MakeJsonVector(dict); |
| 752 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 753 RestoreDictionaryForImportBadJwkTest(&dict); |
| 754 |
| 755 // Fail on missing k when kty = "oct". |
| 756 dict.Remove("k", NULL); |
| 757 json_vec = MakeJsonVector(dict); |
| 758 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 759 RestoreDictionaryForImportBadJwkTest(&dict); |
| 760 |
| 761 // Fail on bad b64 encoding for k. |
| 762 dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI="); |
| 763 json_vec = MakeJsonVector(dict); |
| 764 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 765 RestoreDictionaryForImportBadJwkTest(&dict); |
| 766 |
| 767 // Fail on empty k. |
| 768 dict.SetString("k", ""); |
| 769 json_vec = MakeJsonVector(dict); |
| 770 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 771 RestoreDictionaryForImportBadJwkTest(&dict); |
| 772 |
| 773 // Fail on k actual length (120 bits) inconsistent with the embedded JWK alg |
| 774 // value (128) for an AES key. |
| 775 dict.SetString("k", "AVj42h0Y5aqGtE3yluKL"); |
| 776 json_vec = MakeJsonVector(dict); |
| 777 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 778 RestoreDictionaryForImportBadJwkTest(&dict); |
| 779 |
| 780 // TODO(padolph) RSA public key bad data: |
| 781 // Missing n or e when kty = "RSA" |
| 782 // Bad encoding for n or e |
| 783 // Size check on n?? |
| 784 // Value check on e?? |
| 785 } |
| 786 |
| 787 TEST_F(WebCryptoImplTest, ImportJwkInputConsistency) { |
| 788 // The Web Crypto spec says that if a JWK value is present, but is |
| 789 // inconsistent with the input value, the operation must fail. |
| 790 |
| 791 // Consistency rules when JWK value is not present: Inputs should be used. |
| 792 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 793 bool extractable = false; |
| 794 blink::WebCryptoAlgorithm algorithm = |
| 795 CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256); |
| 796 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageVerify; |
| 797 base::DictionaryValue dict; |
| 798 dict.SetString("kty", "oct"); |
| 799 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 800 std::vector<uint8> json_vec = MakeJsonVector(dict); |
| 801 EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key)); |
| 802 EXPECT_TRUE(key.handle()); |
| 803 EXPECT_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
| 804 EXPECT_EQ(extractable, key.extractable()); |
| 805 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, key.algorithm().id()); |
| 806 EXPECT_EQ(blink::WebCryptoAlgorithmIdSha256, |
| 807 key.algorithm().hmacParams()->hash().id()); |
| 808 EXPECT_EQ(blink::WebCryptoKeyUsageVerify, key.usages()); |
| 809 key = blink::WebCryptoKey::createNull(); |
| 810 |
| 811 // Consistency rules when JWK value exists: Fail if inconsistency is found. |
| 812 |
| 813 // Pass: All input values are consistent with the JWK values. |
| 814 dict.Clear(); |
| 815 dict.SetString("kty", "oct"); |
| 816 dict.SetString("alg", "HS256"); |
| 817 dict.SetString("use", "sig"); |
| 818 dict.SetBoolean("extractable", false); |
| 819 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 820 json_vec = MakeJsonVector(dict); |
| 821 EXPECT_TRUE(ImportKeyJwk( |
| 822 json_vec, algorithm, extractable, usage_mask, &key)); |
| 823 |
| 824 // Extractable cases: |
| 825 // 1. input=T, JWK=F ==> fail (inconsistent) |
| 826 // 4. input=F, JWK=F ==> pass, result extractable is F |
| 827 // 2. input=T, JWK=T ==> pass, result extractable is T |
| 828 // 3. input=F, JWK=T ==> pass, result extractable is F |
| 829 EXPECT_FALSE( |
| 830 ImportKeyJwk(json_vec, algorithm, true, usage_mask, &key)); |
| 831 EXPECT_TRUE( |
| 832 ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); |
| 833 EXPECT_FALSE(key.extractable()); |
| 834 dict.SetBoolean("extractable", true); |
| 835 EXPECT_TRUE( |
| 836 ImportKeyJwk(MakeJsonVector(dict), algorithm, true, usage_mask, &key)); |
| 837 EXPECT_TRUE(key.extractable()); |
| 838 EXPECT_TRUE( |
| 839 ImportKeyJwk(MakeJsonVector(dict), algorithm, false, usage_mask, &key)); |
| 840 EXPECT_FALSE(key.extractable()); |
| 841 dict.SetBoolean("extractable", true); // restore previous value |
| 842 |
| 843 // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value |
| 844 // (HMAC SHA256). |
| 845 EXPECT_FALSE(ImportKeyJwk(json_vec, |
| 846 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc), |
| 847 extractable, |
| 848 usage_mask, |
| 849 &key)); |
| 850 |
| 851 // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value |
| 852 // (HMAC SHA256). |
| 853 EXPECT_FALSE(ImportKeyJwk( |
| 854 json_vec, |
| 855 CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha1), |
| 856 extractable, |
| 857 usage_mask, |
| 858 &key)); |
| 859 |
| 860 // Pass: JWK alg valid but input algorithm isNull: use JWK algorithm value. |
| 861 EXPECT_TRUE(ImportKeyJwk(json_vec, |
| 862 blink::WebCryptoAlgorithm::createNull(), |
| 863 extractable, |
| 864 usage_mask, |
| 865 &key)); |
| 866 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); |
| 867 |
| 868 // Pass: JWK alg missing but input algorithm specified: use input value |
| 869 dict.Remove("alg", NULL); |
| 870 EXPECT_TRUE(ImportKeyJwk( |
| 871 MakeJsonVector(dict), |
| 872 CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256), |
| 873 extractable, |
| 874 usage_mask, |
| 875 &key)); |
| 876 EXPECT_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); |
| 877 dict.SetString("alg", "HS256"); |
| 878 |
| 879 // Fail: Input usage_mask (encrypt) is not a subset of the JWK value |
| 880 // (sign|verify) |
| 881 EXPECT_FALSE(ImportKeyJwk(json_vec, |
| 882 algorithm, |
| 883 extractable, |
| 884 blink::WebCryptoKeyUsageEncrypt, |
| 885 &key)); |
| 886 |
| 887 // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK |
| 888 // value (sign|verify) |
| 889 usage_mask = blink::WebCryptoKeyUsageEncrypt | |
| 890 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; |
| 891 EXPECT_FALSE(ImportKeyJwk( |
| 892 json_vec, algorithm, extractable, usage_mask, &key)); |
| 893 usage_mask = blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; |
| 894 } |
| 895 |
| 896 TEST_F(WebCryptoImplTest, ImportJwkHappy) { |
| 897 |
| 898 // This test verifies the happy path of JWK import, including the application |
| 899 // of the imported key material. |
| 900 |
| 901 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); |
| 902 bool extractable = false; |
| 903 blink::WebCryptoAlgorithm algorithm = |
| 904 CreateHmacAlgorithmByHashId(blink::WebCryptoAlgorithmIdSha256); |
| 905 blink::WebCryptoKeyUsageMask usage_mask = blink::WebCryptoKeyUsageSign; |
| 906 |
| 907 // Import a symmetric key JWK and HMAC-SHA256 sign() |
| 908 // Uses the first SHA256 test vector from the HMAC sample set above. |
| 909 |
| 910 base::DictionaryValue dict; |
| 911 dict.SetString("kty", "oct"); |
| 912 dict.SetString("alg", "HS256"); |
| 913 dict.SetString("use", "sig"); |
| 914 dict.SetBoolean("extractable", false); |
| 915 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 916 std::vector<uint8> json_vec = MakeJsonVector(dict); |
| 917 |
| 918 ASSERT_TRUE(ImportKeyJwk( |
| 919 json_vec, algorithm, extractable, usage_mask, &key)); |
| 920 |
| 921 const std::vector<uint8> message_raw = HexStringToBytes( |
| 922 "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a" |
| 923 "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92" |
| 924 "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f" |
| 925 "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e"); |
| 926 |
| 927 blink::WebArrayBuffer output; |
| 928 |
| 929 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
| 930 |
| 931 const std::string mac_raw = |
| 932 "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b"; |
| 933 |
| 934 ExpectArrayBufferMatchesHex(mac_raw, output); |
| 935 |
| 936 // TODO(padolph) |
| 937 // Import an RSA public key JWK and use it |
| 938 } |
| 939 |
689 #if !defined(USE_OPENSSL) | 940 #if !defined(USE_OPENSSL) |
690 | 941 |
691 TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { | 942 TEST_F(WebCryptoImplTest, GenerateKeyPairRsa) { |
692 // Note: using unrealistic short key lengths here to avoid bogging down tests. | 943 // Note: using unrealistic short key lengths here to avoid bogging down tests. |
693 | 944 |
694 // Successful WebCryptoAlgorithmIdRsaEsPkcs1v1_5 key generation. | 945 // Successful WebCryptoAlgorithmIdRsaEsPkcs1v1_5 key generation. |
695 const unsigned modulus_length = 256; | 946 const unsigned modulus_length = 256; |
696 const std::vector<uint8> public_exponent = HexStringToBytes("010001"); | 947 const std::vector<uint8> public_exponent = HexStringToBytes("010001"); |
697 blink::WebCryptoAlgorithm algorithm = | 948 blink::WebCryptoAlgorithm algorithm = |
698 CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, | 949 CreateRsaAlgorithm(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type()); | 1039 EXPECT_EQ(blink::WebCryptoKeyTypePrivate, private_key.type()); |
789 EXPECT_EQ(extractable, public_key.extractable()); | 1040 EXPECT_EQ(extractable, public_key.extractable()); |
790 EXPECT_EQ(extractable, private_key.extractable()); | 1041 EXPECT_EQ(extractable, private_key.extractable()); |
791 EXPECT_EQ(usage_mask, public_key.usages()); | 1042 EXPECT_EQ(usage_mask, public_key.usages()); |
792 EXPECT_EQ(usage_mask, private_key.usages()); | 1043 EXPECT_EQ(usage_mask, private_key.usages()); |
793 } | 1044 } |
794 | 1045 |
795 #endif // #if !defined(USE_OPENSSL) | 1046 #endif // #if !defined(USE_OPENSSL) |
796 | 1047 |
797 } // namespace content | 1048 } // namespace content |
OLD | NEW |