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" |
14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
15 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 16 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
52 return &data[0]; | 53 return &data[0]; |
53 } | 54 } |
54 | 55 |
55 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( | 56 WebKit::WebCryptoAlgorithm CreateAesCbcAlgorithm( |
56 const std::vector<uint8>& iv) { | 57 const std::vector<uint8>& iv) { |
57 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( | 58 return WebKit::WebCryptoAlgorithm::adoptParamsAndCreate( |
58 WebKit::WebCryptoAlgorithmIdAesCbc, | 59 WebKit::WebCryptoAlgorithmIdAesCbc, |
59 new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size())); | 60 new WebKit::WebCryptoAesCbcParams(Start(iv), iv.size())); |
60 } | 61 } |
61 | 62 |
| 63 std::vector<unsigned char> MakeJsonVector(const std::string& json_string) { |
| 64 return std::vector<unsigned char>(json_string.begin(), json_string.end()); |
| 65 } |
| 66 |
| 67 std::vector<unsigned char> MakeJsonVector(const base::DictionaryValue& dict) { |
| 68 std::string json; |
| 69 base::JSONWriter::Write(&dict, &json); |
| 70 return MakeJsonVector(json); |
| 71 } |
| 72 |
62 } // namespace | 73 } // namespace |
63 | 74 |
64 namespace content { | 75 namespace content { |
65 | 76 |
66 class WebCryptoImplTest : public testing::Test { | 77 class WebCryptoImplTest : public testing::Test { |
67 protected: | 78 protected: |
68 WebKit::WebCryptoKey ImportSecretKeyFromRawHexString( | 79 WebKit::WebCryptoKey ImportSecretKeyFromRawHexString( |
69 const std::string& key_hex, | 80 const std::string& key_hex, |
70 const WebKit::WebCryptoAlgorithm& algorithm, | 81 const WebKit::WebCryptoAlgorithm& algorithm, |
71 WebKit::WebCryptoKeyUsageMask usage) { | 82 WebKit::WebCryptoKeyUsageMask usage) { |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 | 180 |
170 bool DecryptInternal( | 181 bool DecryptInternal( |
171 const WebKit::WebCryptoAlgorithm& algorithm, | 182 const WebKit::WebCryptoAlgorithm& algorithm, |
172 const WebKit::WebCryptoKey& key, | 183 const WebKit::WebCryptoKey& key, |
173 const std::vector<uint8>& data, | 184 const std::vector<uint8>& data, |
174 WebKit::WebArrayBuffer* buffer) { | 185 WebKit::WebArrayBuffer* buffer) { |
175 return crypto_.DecryptInternal( | 186 return crypto_.DecryptInternal( |
176 algorithm, key, Start(data), data.size(), buffer); | 187 algorithm, key, Start(data), data.size(), buffer); |
177 } | 188 } |
178 | 189 |
| 190 bool ImportKeyJwk( |
| 191 const unsigned char* key_data, |
| 192 unsigned key_data_size, |
| 193 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
| 194 WebKit::WebCryptoKeyType* type, |
| 195 bool* extractable, |
| 196 WebKit::WebCryptoAlgorithm* algorithm, |
| 197 WebKit::WebCryptoKeyUsageMask* usage_mask) { |
| 198 return crypto_.ImportKeyJwk(key_data, |
| 199 key_data_size, |
| 200 handle, |
| 201 type, |
| 202 extractable, |
| 203 algorithm, |
| 204 usage_mask); |
| 205 } |
| 206 |
179 private: | 207 private: |
180 WebCryptoImpl crypto_; | 208 WebCryptoImpl crypto_; |
181 }; | 209 }; |
182 | 210 |
183 // TODO(padolph) Enable these tests for OpenSSL once matching impl is available | 211 // TODO(padolph) Enable these tests for OpenSSL once matching impl is available |
184 #if !defined(USE_OPENSSL) | 212 #if !defined(USE_OPENSSL) |
185 | 213 |
186 TEST_F(WebCryptoImplTest, DigestSampleSets) { | 214 TEST_F(WebCryptoImplTest, DigestSampleSets) { |
187 // The results are stored here in hex format for readability. | 215 // The results are stored here in hex format for readability. |
188 // | 216 // |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 | 285 |
258 WebKit::WebCryptoAlgorithm algorithm = CreateAlgorithm(test.algorithm); | 286 WebKit::WebCryptoAlgorithm algorithm = CreateAlgorithm(test.algorithm); |
259 std::vector<uint8> input = HexStringToBytes(test.hex_input); | 287 std::vector<uint8> input = HexStringToBytes(test.hex_input); |
260 | 288 |
261 WebKit::WebArrayBuffer output; | 289 WebKit::WebArrayBuffer output; |
262 ASSERT_TRUE(DigestInternal(algorithm, input, &output)); | 290 ASSERT_TRUE(DigestInternal(algorithm, input, &output)); |
263 ExpectArrayBufferMatchesHex(test.hex_result, output); | 291 ExpectArrayBufferMatchesHex(test.hex_result, output); |
264 } | 292 } |
265 } | 293 } |
266 | 294 |
267 #endif // #if !defined(USE_OPENSSL) | 295 #endif // #if !defined(USE_OPENSSL) |
268 | 296 |
269 TEST_F(WebCryptoImplTest, HMACSampleSets) { | 297 TEST_F(WebCryptoImplTest, HMACSampleSets) { |
270 struct TestCase { | 298 struct TestCase { |
271 WebKit::WebCryptoAlgorithmId algorithm; | 299 WebKit::WebCryptoAlgorithmId algorithm; |
272 const char* key; | 300 const char* key; |
273 const char* message; | 301 const char* message; |
274 const char* mac; | 302 const char* mac; |
275 }; | 303 }; |
276 | 304 |
277 const TestCase kTests[] = { | 305 const TestCase kTests[] = { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 if (cipher_text.size() > 3) { | 622 if (cipher_text.size() > 3) { |
595 EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), | 623 EXPECT_FALSE(DecryptInternal(CreateAesCbcAlgorithm(iv), |
596 key, | 624 key, |
597 &cipher_text[0], | 625 &cipher_text[0], |
598 cipher_text.size() - 3, | 626 cipher_text.size() - 3, |
599 &output)); | 627 &output)); |
600 } | 628 } |
601 } | 629 } |
602 } | 630 } |
603 | 631 |
604 #endif // !defined(USE_OPENSSL) | 632 #endif // !defined(USE_OPENSSL) |
| 633 |
| 634 TEST_F(WebCryptoImplTest, ImportJwkBadJwk) { |
| 635 |
| 636 WebKit::WebCryptoKeyType type; |
| 637 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| 638 std::vector<uint8> iv(16); |
| 639 WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
| 640 bool extractable = false; |
| 641 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
| 642 |
| 643 // Empty JSON |
| 644 std::vector<unsigned char> json_vec = MakeJsonVector(""); |
| 645 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 646 json_vec.size(), |
| 647 &handle, |
| 648 &type, |
| 649 &extractable, |
| 650 &algorithm, |
| 651 &usage_mask)); |
| 652 |
| 653 // Bad JSON |
| 654 json_vec = MakeJsonVector( |
| 655 "{" |
| 656 "\"kty\" : \"oct\"," |
| 657 "\"alg\" : \"HS256\"," |
| 658 "\"use\" : " |
| 659 ); |
| 660 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 661 json_vec.size(), |
| 662 &handle, |
| 663 &type, |
| 664 &extractable, |
| 665 &algorithm, |
| 666 &usage_mask)); |
| 667 |
| 668 // Note, each subtest below resets the dictionary so there is less chance of |
| 669 // failure if they happen to be reordered. |
| 670 |
| 671 // Invalid kty |
| 672 base::DictionaryValue dict; |
| 673 dict.SetString("kty", "foo"); |
| 674 dict.SetString("alg", "HS256"); |
| 675 dict.SetString("use", "sig"); |
| 676 dict.SetBoolean("extractable", true); |
| 677 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 678 json_vec = MakeJsonVector(dict); |
| 679 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 680 json_vec.size(), |
| 681 &handle, |
| 682 &type, |
| 683 &extractable, |
| 684 &algorithm, |
| 685 &usage_mask)); |
| 686 dict.SetString("kty", "oct"); |
| 687 |
| 688 // Missing kty |
| 689 dict.Remove("kty", NULL); |
| 690 json_vec = MakeJsonVector(dict); |
| 691 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 692 json_vec.size(), |
| 693 &handle, |
| 694 &type, |
| 695 &extractable, |
| 696 &algorithm, |
| 697 &usage_mask)); |
| 698 dict.SetString("kty", "oct"); |
| 699 |
| 700 // Invalid alg |
| 701 dict.SetString("alg", "foo"); |
| 702 json_vec = MakeJsonVector(dict); |
| 703 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 704 json_vec.size(), |
| 705 &handle, |
| 706 &type, |
| 707 &extractable, |
| 708 &algorithm, |
| 709 &usage_mask)); |
| 710 dict.SetString("alg", "HS256"); |
| 711 |
| 712 // Invalid use |
| 713 dict.SetString("use", "foo"); |
| 714 json_vec = MakeJsonVector(dict); |
| 715 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 716 json_vec.size(), |
| 717 &handle, |
| 718 &type, |
| 719 &extractable, |
| 720 &algorithm, |
| 721 &usage_mask)); |
| 722 dict.SetString("use", "sig"); |
| 723 |
| 724 // Missing k when kty = "oct" |
| 725 dict.Remove("k", NULL); |
| 726 json_vec = MakeJsonVector(dict); |
| 727 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 728 json_vec.size(), |
| 729 &handle, |
| 730 &type, |
| 731 &extractable, |
| 732 &algorithm, |
| 733 &usage_mask)); |
| 734 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 735 |
| 736 // Bad encoding for k |
| 737 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3r #$% jhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 738 json_vec = MakeJsonVector(dict); |
| 739 EXPECT_FALSE(ImportKeyJwk(Start(json_vec), |
| 740 json_vec.size(), |
| 741 &handle, |
| 742 &type, |
| 743 &extractable, |
| 744 &algorithm, |
| 745 &usage_mask)); |
| 746 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 747 |
| 748 // TODO(padolph) RSA public key bad data: |
| 749 // Missing n or e when kty = "RSA" |
| 750 // Bad encoding for n or e |
| 751 // Size check on n?? |
| 752 // Value check on e?? |
| 753 } |
| 754 |
| 755 TEST_F(WebCryptoImplTest, ImportJwkCollision) { |
| 756 |
| 757 WebKit::WebCryptoKeyType type; |
| 758 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| 759 std::vector<uint8> iv(16); |
| 760 WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
| 761 bool extractable = false; |
| 762 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
| 763 |
| 764 // Collision rules when JWK value exists: |
| 765 // Input _type_ should be ignored. |
| 766 // Input _algorithm_ should be overridden by the JWK value. |
| 767 // Output _extractable_ should be AND of input and JWK value. |
| 768 // Input _usage_mask_ should be overridden by the JWK value. |
| 769 type = WebKit::WebCryptoKeyTypePublic; |
| 770 algorithm = CreateAesCbcAlgorithm(iv); |
| 771 extractable = true; |
| 772 usage_mask = WebKit::WebCryptoKeyUsageWrapKey; |
| 773 |
| 774 base::DictionaryValue dict; |
| 775 dict.SetString("kty", "oct"); |
| 776 dict.SetString("alg", "HS256"); |
| 777 dict.SetString("use", "sig"); |
| 778 dict.SetBoolean("extractable", false); |
| 779 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 780 std::vector<unsigned char> json_vec = MakeJsonVector(dict); |
| 781 |
| 782 EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
| 783 json_vec.size(), |
| 784 &handle, |
| 785 &type, |
| 786 &extractable, |
| 787 &algorithm, |
| 788 &usage_mask)); |
| 789 EXPECT_EQ(WebKit::WebCryptoKeyTypeSecret, type); |
| 790 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
| 791 const WebKit::WebCryptoHmacParams* const hmac_params = algorithm.hmacParams(); |
| 792 ASSERT_TRUE(hmac_params != NULL); |
| 793 EXPECT_EQ(hmac_params->hash().id(), WebKit::WebCryptoAlgorithmIdSha256); |
| 794 EXPECT_FALSE(extractable); |
| 795 EXPECT_EQ(WebKit::WebCryptoKeyUsageSign | WebKit::WebCryptoKeyUsageVerify, |
| 796 usage_mask); |
| 797 |
| 798 // Collision rules when JWK value is not present: |
| 799 // Inputs should be unmodified. |
| 800 algorithm = CreateHmacAlgorithm(WebKit::WebCryptoAlgorithmIdSha256); |
| 801 extractable = true; |
| 802 usage_mask = WebKit::WebCryptoKeyUsageSign; |
| 803 |
| 804 dict.Clear(); |
| 805 dict.SetString("kty", "oct"); |
| 806 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 807 json_vec = MakeJsonVector(dict); |
| 808 |
| 809 EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
| 810 json_vec.size(), |
| 811 &handle, |
| 812 &type, |
| 813 &extractable, |
| 814 &algorithm, |
| 815 &usage_mask)); |
| 816 EXPECT_EQ(WebKit::WebCryptoAlgorithmIdHmac, algorithm.id()); |
| 817 EXPECT_TRUE(extractable); |
| 818 EXPECT_EQ(WebKit::WebCryptoKeyUsageSign, usage_mask); |
| 819 } |
| 820 |
| 821 TEST_F(WebCryptoImplTest, ImportJwkHappy) { |
| 822 |
| 823 WebKit::WebCryptoKeyType type; |
| 824 scoped_ptr<WebKit::WebCryptoKeyHandle> handle; |
| 825 std::vector<uint8> iv(16); |
| 826 WebKit::WebCryptoAlgorithm algorithm = CreateAesCbcAlgorithm(iv); |
| 827 bool extractable = false; |
| 828 WebKit::WebCryptoKeyUsageMask usage_mask = WebKit::WebCryptoKeyUsageSign; |
| 829 |
| 830 // Import a symmetric key JWK and HMAC-SHA256 sign() |
| 831 // Uses the first SHA256 test vector from the HMAC sample set above. |
| 832 |
| 833 base::DictionaryValue dict; |
| 834 dict.SetString("kty", "oct"); |
| 835 dict.SetString("alg", "HS256"); |
| 836 dict.SetString("use", "sig"); |
| 837 dict.SetBoolean("extractable", true); |
| 838 dict.SetString("k", "l3nZEgZCeX8XRwJdWyK3rGB8qwjhdY8vOkbIvh4lxTuMao9Y_--hdg"); |
| 839 std::vector<unsigned char> json_vec = MakeJsonVector(dict); |
| 840 |
| 841 EXPECT_TRUE(ImportKeyJwk(Start(json_vec), |
| 842 json_vec.size(), |
| 843 &handle, |
| 844 &type, |
| 845 &extractable, |
| 846 &algorithm, |
| 847 &usage_mask)); |
| 848 |
| 849 WebKit::WebCryptoKey key = WebKit::WebCryptoKey::create(handle.release(), |
| 850 type, extractable, algorithm, usage_mask); |
| 851 |
| 852 const std::vector<uint8> message_raw = HexStringToBytes( |
| 853 "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a" |
| 854 "92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92" |
| 855 "d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f" |
| 856 "22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e"); |
| 857 |
| 858 WebKit::WebArrayBuffer output; |
| 859 |
| 860 ASSERT_TRUE(SignInternal(algorithm, key, message_raw, &output)); |
| 861 |
| 862 const std::string mac_raw = |
| 863 "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b"; |
| 864 |
| 865 ExpectArrayBufferMatchesHex(mac_raw, output); |
| 866 |
| 867 // TODO(padolph) |
| 868 // Import an RSA public key JWK and use it |
| 869 } |
605 | 870 |
606 } // namespace content | 871 } // namespace content |
OLD | NEW |