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 "webcrypto_impl.h" | 5 #include "webcrypto_impl.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/json/json_writer.h" | |
8 #include "base/logging.h" | 9 #include "base/logging.h" |
9 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
10 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
11 #include "content/public/renderer/content_renderer_client.h" | 12 #include "content/public/renderer/content_renderer_client.h" |
12 #include "content/renderer/renderer_webkitplatformsupport_impl.h" | 13 #include "content/renderer/renderer_webkitplatformsupport_impl.h" |
13 #include "content/renderer/webcrypto/webcrypto_impl.h" | 14 #include "content/renderer/webcrypto/webcrypto_impl.h" |
15 #include "content/renderer/webcrypto/webcrypto_util.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 17 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
18 | 20 |
19 namespace { | 21 namespace { |
20 | 22 |
21 std::vector<uint8> HexStringToBytes(const std::string& hex) { | 23 std::vector<uint8> HexStringToBytes(const std::string& hex) { |
22 std::vector<uint8> bytes; | 24 std::vector<uint8> bytes; |
23 base::HexStringToBytes(hex, &bytes); | 25 base::HexStringToBytes(hex, &bytes); |
24 return bytes; | 26 return bytes; |
25 } | 27 } |
26 | 28 |
27 void ExpectArrayBufferMatchesHex(const std::string& expected_hex, | 29 void ExpectArrayBufferMatchesHex(const std::string& expected_hex, |
28 const WebKit::WebArrayBuffer& array_buffer) { | 30 const WebKit::WebArrayBuffer& array_buffer) { |
29 EXPECT_STRCASEEQ( | 31 EXPECT_STRCASEEQ( |
30 expected_hex.c_str(), | 32 expected_hex.c_str(), |
31 base::HexEncode( | 33 base::HexEncode( |
32 array_buffer.data(), array_buffer.byteLength()).c_str()); | 34 array_buffer.data(), array_buffer.byteLength()).c_str()); |
33 } | 35 } |
34 | 36 |
35 WebKit::WebCryptoAlgorithm CreateAlgorithm(WebKit::WebCryptoAlgorithmId id) { | 37 std::vector<uint8> MakeJsonVector(const std::string& json_string) { |
36 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | 38 return std::vector<uint8>(json_string.begin(), json_string.end()); |
37 } | 39 } |
38 | 40 |
39 WebKit::WebCryptoAlgorithm CreateHmacAlgorithm( | 41 std::vector<uint8> MakeJsonVector(const base::DictionaryValue& dict) { |
40 WebKit::WebCryptoAlgorithmId hashId) { | 42 std::string json; |
41 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | 43 base::JSONWriter::Write(&dict, &json); |
42 WebKit::WebCryptoAlgorithmIdHmac, | 44 return MakeJsonVector(json); |
43 new WebKit::WebCryptoHmacParams(CreateAlgorithm(hashId))); | |
44 } | 45 } |
45 | 46 |
46 WebKit::WebCryptoAlgorithm CreateHmacKeyAlgorithm( | 47 // Helper for ImportJwkBadJwk; restores JWK JSON dictionary to a good state |
47 WebKit::WebCryptoAlgorithmId hashId, | 48 void RestoreDictionary(base::DictionaryValue* dict) { |
eroman
2013/11/01 20:59:58
nit: can you give it a more specific name?
padolph
2013/11/01 23:08:50
Done.
| |
48 unsigned hash_length) { | 49 dict->SetString("kty", "oct"); |
eroman
2013/11/01 20:59:58
How about calling dict->Clear() first, to remove a
padolph
2013/11/01 23:08:50
Done.
| |
49 // hash_length < 0 means unspecified | 50 dict->SetString("alg", "HS256"); |
50 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | 51 dict->SetString("use", "sig"); |
51 WebKit::WebCryptoAlgorithmIdHmac, | 52 dict->SetBoolean("extractable", false); |
52 new WebKit::WebCryptoHmacKeyParams(CreateAlgorithm(hashId), | 53 dict->SetString("k", "Qk3f0DsytU8lfza2auHtaw2xpop9GYyTuH0p5GghxTI="); |
53 (hash_length != 0), | |
54 hash_length)); | |
55 } | |
56 | |
57 // Returns a pointer to the start of |data|, or NULL if it is empty. This is a | |
58 // convenience function for getting the pointer, and should not be used beyond | |
59 // the expected lifetime of |data|. | |
60 const uint8* Start(const std::vector<uint8>& data) { | |
61 if (data.empty()) | |
62 return NULL; | |
63 return &data[0]; | |
64 } | |
65 | |
66 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( | |
67 const std::vector<uint8>& iv) { | |
68 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
69 WebKit::WebCryptoAlgorithmIdAesCbc, | |
70 new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size())); | |
71 } | |
72 | |
73 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( | |
74 unsigned short key_length_bits) { | |
75 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | |
76 WebKit::WebCryptoAlgorithmIdAesCbc, | |
77 new WebKit::WebCryptoAesKeyGenParams(key_length_bits)); | |
78 } | 54 } |
79 | 55 |
80 } // namespace | 56 } // namespace |
81 | 57 |
82 namespace content { | 58 namespace content { |
83 | 59 |
84 class WebCryptoImplTest : public testing::Test { | 60 class WebCryptoImplTest : public testing::Test { |
85 protected: | 61 protected: |
86 WebKit::WebCryptoKey ImportSecretKeyFromRawHexString( | 62 WebKit::WebCryptoKey ImportSecretKeyFromRawHexString( |
87 const std::string& key_hex, | 63 const std::string& key_hex, |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 | 168 |
193 bool DecryptInternal( | 169 bool DecryptInternal( |
194 const WebKit::WebCryptoAlgorithm& algorithm, | 170 const WebKit::WebCryptoAlgorithm& algorithm, |
195 const WebKit::WebCryptoKey& key, | 171 const WebKit::WebCryptoKey& key, |
196 const std::vector<uint8>& data, | 172 const std::vector<uint8>& data, |
197 WebKit::WebArrayBuffer* buffer) { | 173 WebKit::WebArrayBuffer* buffer) { |
198 return crypto_.DecryptInternal( | 174 return crypto_.DecryptInternal( |
199 algorithm, key, Start(data), data.size(), buffer); | 175 algorithm, key, Start(data), data.size(), buffer); |
200 } | 176 } |
201 | 177 |
178 bool ImportKeyJwk( | |
179 const std::vector<uint8>& key_data, | |
180 const WebKit::WebCryptoAlgorithm& algorithm, | |
181 bool extractable, | |
182 WebKit::WebCryptoKeyUsageMask usage_mask, | |
183 WebKit::WebCryptoKey* key) { | |
184 return crypto_.ImportKeyJwk(Start(key_data), | |
185 key_data.size(), | |
186 algorithm, | |
187 extractable, | |
188 usage_mask, | |
189 key); | |
190 } | |
191 | |
202 private: | 192 private: |
203 WebCryptoImpl crypto_; | 193 WebCryptoImpl crypto_; |
204 }; | 194 }; |
205 | 195 |
206 TEST_F(WebCryptoImplTest, DigestSampleSets) { | 196 TEST_F(WebCryptoImplTest, DigestSampleSets) { |
207 // The results are stored here in hex format for readability. | 197 // The results are stored here in hex format for readability. |
208 // | 198 // |
209 // TODO(bryaneyler): Eventually, all these sample test sets should be replaced | 199 // TODO(bryaneyler): Eventually, all these sample test sets should be replaced |
210 // with the sets here: http://csrc.nist.gov/groups/STM/cavp/index.html#03 | 200 // with the sets here: http://csrc.nist.gov/groups/STM/cavp/index.html#03 |
211 // | 201 // |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
370 // mac | 360 // mac |
371 "4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b", | 361 "4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b", |
372 }, | 362 }, |
373 }; | 363 }; |
374 | 364 |
375 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); | 365 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); |
376 ++test_index) { | 366 ++test_index) { |
377 SCOPED_TRACE(test_index); | 367 SCOPED_TRACE(test_index); |
378 const TestCase& test = kTests[test_index]; | 368 const TestCase& test = kTests[test_index]; |
379 | 369 |
380 WebKit::WebCryptoAlgorithm algorithm = CreateHmacAlgorithm(test.algorithm); | 370 WebKit::WebCryptoAlgorithm algorithm = |
371 CreateHmacAlgorithmByHashId(test.algorithm); | |
381 | 372 |
382 WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 373 WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
383 test.key, algorithm, WebKit::WebCryptoKeyUsageSign); | 374 test.key, algorithm, WebKit::WebCryptoKeyUsageSign); |
384 | 375 |
385 std::vector<uint8> message_raw = HexStringToBytes(test.message); | 376 std::vector<uint8> message_raw = HexStringToBytes(test.message); |
386 | 377 |
387 WebKit::WebArrayBuffer output; | 378 WebKit::WebArrayBuffer output; |
388 | 379 |
389 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | 380 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
390 | 381 |
(...skipping 25 matching lines...) Expand all Loading... | |
416 algorithm, | 407 algorithm, |
417 key, | 408 key, |
418 kLongSignature, | 409 kLongSignature, |
419 sizeof(kLongSignature), | 410 sizeof(kLongSignature), |
420 message_raw, | 411 message_raw, |
421 &signature_match)); | 412 &signature_match)); |
422 EXPECT_FALSE(signature_match); | 413 EXPECT_FALSE(signature_match); |
423 } | 414 } |
424 } | 415 } |
425 | 416 |
417 #if !defined(USE_OPENSSL) | |
418 | |
426 TEST_F(WebCryptoImplTest, AesCbcFailures) { | 419 TEST_F(WebCryptoImplTest, AesCbcFailures) { |
427 WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( | 420 WebKit::WebCryptoKey key = ImportSecretKeyFromRawHexString( |
428 "2b7e151628aed2a6abf7158809cf4f3c", | 421 "2b7e151628aed2a6abf7158809cf4f3c", |
429 CreateAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc), | 422 CreateAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc), |
430 WebKit::WebCryptoKeyUsageEncrypt | WebKit::WebCryptoKeyUsageDecrypt); | 423 WebKit::WebCryptoKeyUsageEncrypt | WebKit::WebCryptoKeyUsageDecrypt); |
431 | 424 |
432 WebKit::WebArrayBuffer output; | 425 WebKit::WebArrayBuffer output; |
433 | 426 |
434 // Use an invalid |iv| (fewer than 16 bytes) | 427 // Use an invalid |iv| (fewer than 16 bytes) |
435 { | 428 { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
611 &output)); | 604 &output)); |
612 } | 605 } |
613 } | 606 } |
614 } | 607 } |
615 | 608 |
616 // TODO (padolph): Add test to verify generated symmetric keys appear random. | 609 // TODO (padolph): Add test to verify generated symmetric keys appear random. |
617 | 610 |
618 | 611 |
619 TEST_F(WebCryptoImplTest, GenerateKeyAes) { | 612 TEST_F(WebCryptoImplTest, GenerateKeyAes) { |
620 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | 613 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
621 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcAlgorithm(128), &key)); | 614 ASSERT_TRUE(GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(128), &key)); |
622 EXPECT_TRUE(key.handle()); | 615 EXPECT_TRUE(key.handle()); |
623 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | 616 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
624 } | 617 } |
625 | 618 |
626 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { | 619 TEST_F(WebCryptoImplTest, GenerateKeyAesBadLength) { |
627 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | 620 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
628 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(0), &key)); | 621 EXPECT_FALSE( |
629 EXPECT_FALSE(GenerateKeyInternal(CreateAesCbcAlgorithm(129), &key)); | 622 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); |
623 EXPECT_FALSE( | |
624 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(0), &key)); | |
625 EXPECT_FALSE( | |
626 GenerateKeyInternal(CreateAesCbcKeyGenAlgorithm(129), &key)); | |
630 } | 627 } |
631 | 628 |
629 | |
632 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { | 630 TEST_F(WebCryptoImplTest, GenerateKeyHmac) { |
633 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | 631 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
634 WebKit::WebCryptoAlgorithm algorithm = | 632 WebKit::WebCryptoAlgorithm algorithm = |
635 CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); | 633 CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 128); |
636 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 634 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
637 EXPECT_TRUE(key.handle()); | 635 EXPECT_TRUE(key.handle()); |
638 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | 636 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
639 } | 637 } |
640 | 638 |
641 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { | 639 TEST_F(WebCryptoImplTest, GenerateKeyHmacNoLength) { |
642 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | 640 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
643 WebKit::WebCryptoAlgorithm algorithm = | 641 WebKit::WebCryptoAlgorithm algorithm = |
644 CreateHmacKeyAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); | 642 CreateHmacKeyGenAlgorithm(WebKit::WebCryptoAlgorithmIdSha1, 0); |
eroman
2013/11/01 20:59:58
thanks, that is a better name.
| |
645 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); | 643 ASSERT_TRUE(GenerateKeyInternal(algorithm, &key)); |
646 EXPECT_TRUE(key.handle()); | 644 EXPECT_TRUE(key.handle()); |
647 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | 645 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); |
648 } | 646 } |
649 | 647 |
650 TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { | 648 TEST_F(WebCryptoImplTest, ImportSecretKeyNoAlgorithm) { |
651 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | 649 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); |
652 | 650 |
653 // This fails because the algorithm is null. | 651 // This fails because the algorithm is null. |
654 EXPECT_FALSE(ImportKeyInternal( | 652 EXPECT_FALSE(ImportKeyInternal( |
655 WebKit::WebCryptoKeyFormatRaw, | 653 WebKit::WebCryptoKeyFormatRaw, |
656 HexStringToBytes("00000000000000000000"), | 654 HexStringToBytes("00000000000000000000"), |
657 WebKit::WebCryptoAlgorithm::createNull(), | 655 WebKit::WebCryptoAlgorithm::createNull(), |
658 WebKit::WebCryptoKeyUsageSign, | 656 WebKit::WebCryptoKeyUsageSign, |
659 &key)); | 657 &key)); |
660 } | 658 } |
661 | 659 |
660 #endif //#if !defined(USE_OPENSSL) | |
661 | |
662 TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { | |
663 | |
664 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | |
eroman
2013/11/01 20:59:58
please use WebKit::WebCryptoKey::createNull()
padolph
2013/11/01 23:08:50
Done.
| |
665 WebKit::WebCryptoAlgorithm algorithm = CreateHmacAlgorithmByDigestLen(256); | |
666 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; | |
667 | |
668 // Baseline pass: each test below breaks a single item, so we start with a | |
669 // passing case to make sure each failure caused by the isolated break. Each | |
670 // breaking subtest below resets the dictionary to this passing case when | |
671 // complete. | |
eroman
2013/11/01 20:59:58
useful comment, thanks
| |
672 base::DictionaryValue dict; | |
673 RestoreDictionary(&dict); | |
674 std::vector<uint8> json_vec = MakeJsonVector(dict); | |
675 EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
676 | |
677 // Fail on empty JSON. | |
678 EXPECT_FALSE(ImportKeyJwk( | |
679 MakeJsonVector(""), algorithm, false, usage_mask, &key)); | |
680 | |
681 // Fail on invalid JSON. | |
682 const std::vector<uint8> bad_json_vec = MakeJsonVector( | |
683 "{" | |
684 "\"kty\" : \"oct\"," | |
685 "\"alg\" : \"HS256\"," | |
686 "\"use\" : " | |
687 ); | |
688 EXPECT_FALSE(ImportKeyJwk(bad_json_vec, algorithm, false, usage_mask, &key)); | |
689 | |
690 // Fail on JWK alg present but unrecognized. | |
691 dict.SetString("alg", "foo"); | |
692 json_vec = MakeJsonVector(dict); | |
693 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
694 RestoreDictionary(&dict); | |
695 | |
696 // Fail on both JWK and input algorithm missing. | |
697 dict.Remove("alg", NULL); | |
698 json_vec = MakeJsonVector(dict); | |
699 EXPECT_FALSE(ImportKeyJwk(json_vec, | |
700 WebKit::WebCryptoAlgorithm::createNull(), | |
701 false, | |
702 usage_mask, | |
703 &key)); | |
704 RestoreDictionary(&dict); | |
705 | |
706 // Fail on invalid kty. | |
707 dict.SetString("kty", "foo"); | |
708 json_vec = MakeJsonVector(dict); | |
709 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
710 RestoreDictionary(&dict); | |
711 | |
712 // Fail on missing kty. | |
713 dict.Remove("kty", NULL); | |
714 json_vec = MakeJsonVector(dict); | |
715 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
716 RestoreDictionary(&dict); | |
717 | |
718 // Fail on invalid use. | |
719 dict.SetString("use", "foo"); | |
720 json_vec = MakeJsonVector(dict); | |
721 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
722 RestoreDictionary(&dict); | |
723 | |
724 // Fail on missing k when kty = "oct". | |
725 dict.Remove("k", NULL); | |
726 json_vec = MakeJsonVector(dict); | |
727 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
728 RestoreDictionary(&dict); | |
729 | |
730 // Fail on bad b64 encoding for k. | |
731 dict.SetString("k", "Qk3f0DsytU8lfza2au #$% Htaw2xpop9GYyTuH0p5GghxTI="); | |
732 json_vec = MakeJsonVector(dict); | |
733 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
734 RestoreDictionary(&dict); | |
735 | |
736 // Fail on empty k. | |
737 dict.SetString("k", ""); | |
738 json_vec = MakeJsonVector(dict); | |
739 EXPECT_FALSE(ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
740 RestoreDictionary(&dict); | |
741 | |
742 // TODO(padolph) RSA public key bad data: | |
743 // Missing n or e when kty = "RSA" | |
744 // Bad encoding for n or e | |
745 // Size check on n?? | |
746 // Value check on e?? | |
747 } | |
748 | |
749 TEST_F(WebCryptoImplTest, ImportJwkInputInconsistent) { | |
750 // The Web Crypto spec says that if a JWK value is present, but is | |
751 // inconsistent with the input value, the operation must fail. | |
752 | |
753 // Consistency rules when JWK value is not present: Inputs should be used. | |
754 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | |
eroman
2013/11/01 20:59:58
WebCryptoKey::createNull()
padolph
2013/11/01 23:08:50
Done.
| |
755 bool extractable = true; | |
756 WebKit::WebCryptoAlgorithm algorithm = | |
757 CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256); | |
758 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageVerify; | |
759 base::DictionaryValue dict; | |
760 dict.SetString("kty", "oct"); | |
761 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); | |
762 std::vector<uint8> json_vec = MakeJsonVector(dict); | |
763 EXPECT_TRUE(ImportKeyJwk(json_vec, algorithm, extractable, usage_mask, &key)); | |
764 EXPECT_TRUE(key.handle()); | |
765 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, key.type()); | |
766 EXPECT_EQ(extractable, key.extractable()); | |
767 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, key.algorithm().id()); | |
768 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdSha256, | |
769 key.algorithm().hmacParams()->hash().id()); | |
770 EXPECT_EQ(WebKit::WebCryptoKeyUsageVerify, key.usages()); | |
771 key = WebCryptoImpl::NullKey(); | |
772 | |
773 // Consistency rules when JWK value exists: Fail if inconsistency is found. | |
774 // Happy path: all input values are consistent with the JWK values | |
775 dict.Clear(); | |
776 dict.SetString("kty", "oct"); | |
777 dict.SetString("alg", "HS256"); | |
778 dict.SetString("use", "sig"); | |
779 dict.SetBoolean("extractable", true); | |
780 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); | |
781 json_vec = MakeJsonVector(dict); | |
782 EXPECT_TRUE(ImportKeyJwk( | |
783 json_vec, algorithm, extractable, usage_mask, &key)); | |
784 | |
785 // Fail: Input extractable (false) is inconsistent with JWK value (true). | |
786 EXPECT_FALSE( | |
787 ImportKeyJwk(json_vec, algorithm, false, usage_mask, &key)); | |
788 | |
789 // Fail: Input algorithm (AES-CBC) is inconsistent with JWK value | |
790 // (HMAC SHA256). | |
791 EXPECT_FALSE(ImportKeyJwk(json_vec, | |
792 CreateAlgorithm(WebKit::WebCryptoAlgorithmIdAesCbc), | |
793 extractable, | |
794 usage_mask, | |
795 &key)); | |
796 | |
797 // Fail: Input algorithm (HMAC SHA1) is inconsistent with JWK value | |
798 // (HMAC SHA256). | |
799 EXPECT_FALSE(ImportKeyJwk( | |
800 json_vec, | |
801 CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha1), | |
802 extractable, | |
803 usage_mask, | |
804 &key)); | |
805 | |
806 // Pass: JWK alg valid but input algorithm isNull: use JWK algorithm value. | |
807 EXPECT_TRUE(ImportKeyJwk(json_vec, | |
808 WebKit::WebCryptoAlgorithm::createNull(), | |
809 extractable, | |
810 usage_mask, | |
811 &key)); | |
812 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); | |
813 | |
814 // Pass: JWK alg missing but input algorithm specified: use input value | |
815 dict.Remove("alg", NULL); | |
816 EXPECT_TRUE(ImportKeyJwk( | |
817 MakeJsonVector(dict), | |
818 CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256), | |
819 extractable, | |
820 usage_mask, | |
821 &key)); | |
822 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); | |
823 dict.SetString("alg", "HS256"); | |
824 | |
825 // Fail: Input usage_mask (encrypt) is not a subset of the JWK value | |
826 // (sign|verify) | |
827 EXPECT_FALSE(ImportKeyJwk(json_vec, | |
828 algorithm, | |
829 extractable, | |
830 WebKit::WebCryptoKeyUsageEncrypt, | |
831 &key)); | |
832 | |
833 // Fail: Input usage_mask (encrypt|sign|verify) is not a subset of the JWK | |
834 // value (sign|verify) | |
835 usage_mask = WebKit::WebCryptoKeyUsageEncrypt | | |
836 WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; | |
837 EXPECT_FALSE(ImportKeyJwk( | |
838 json_vec, algorithm, extractable, usage_mask, &key)); | |
839 usage_mask = WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify; | |
840 } | |
841 | |
842 TEST_F(WebCryptoImplTest, ImportJwkHappy) { | |
843 | |
844 // This test verifies the happy path of JWK import, including the application | |
845 // of the imported key material. | |
846 | |
847 WebKit::WebCryptoKey key = WebCryptoImpl::NullKey(); | |
848 bool extractable = false; | |
849 WebKit::WebCryptoAlgorithm algorithm = | |
850 CreateHmacAlgorithmByHashId(WebKit::WebCryptoAlgorithmIdSha256); | |
851 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; | |
852 | |
853 // Import a symmetric key JWK and HMAC-SHA256 sign() | |
854 // Uses the first SHA256 test vector from the HMAC sample set above. | |
855 | |
856 base::DictionaryValue dict; | |
857 dict.SetString("kty", "oct"); | |
858 dict.SetString("alg", "HS256"); | |
859 dict.SetString("use", "sig"); | |
860 dict.SetBoolean("extractable", false); | |
861 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); | |
862 std::vector<uint8> json_vec = MakeJsonVector(dict); | |
863 | |
864 ASSERT_TRUE(ImportKeyJwk( | |
865 json_vec, algorithm, extractable, usage_mask, &key)); | |
866 | |
867 const std::vector<uint8> message_raw = HexStringToBytes( | |
868 "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a" | |
869 "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92" | |
870 "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f" | |
871 "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e"); | |
872 | |
873 WebKit::WebArrayBuffer output; | |
874 | |
875 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); | |
876 | |
877 const std::string mac_raw = | |
878 "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b"; | |
879 | |
880 ExpectArrayBufferMatchesHex(mac_raw, output); | |
881 | |
882 // TODO(padolph) | |
883 // Import an RSA public key JWK and use it | |
884 } | |
885 | |
662 } // namespace content | 886 } // namespace content |
OLD | NEW |