OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <map> | 9 #include <map> |
10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 } | 31 } |
32 | 32 |
33 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { | 33 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { |
34 // TODO(padolph): include all other asymmetric algorithms once they are | 34 // TODO(padolph): include all other asymmetric algorithms once they are |
35 // defined, e.g. EC and DH. | 35 // defined, e.g. EC and DH. |
36 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 36 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
37 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || | 37 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || |
38 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); | 38 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); |
39 } | 39 } |
40 | 40 |
41 // Binds a specific key length value to a compatible factory function. | 41 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); |
42 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)( | |
43 unsigned short); | |
44 template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length> | |
45 blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() { | |
46 return func(key_length); | |
47 } | |
48 | 42 |
49 // Binds a WebCryptoAlgorithmId value to a compatible factory function. | 43 class JwkAlgorithmInfo { |
Ryan Sleevi
2014/01/31 20:55:59
Can we not avoid having to create this class by ma
eroman
2014/01/31 21:02:50
Not sure I follow, can u explain further?
Ryan Sleevi
2014/01/31 21:15:09
Well, I was thinking you could smuggle required_ke
eroman
2014/01/31 21:51:24
I am open to moving more JWK to the blink side, so
| |
50 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)( | |
51 blink::WebCryptoAlgorithmId); | |
52 template <AlgFactoryFuncWithWebCryptoAlgIdArg func, | |
53 blink::WebCryptoAlgorithmId algorithm_id> | |
54 blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() { | |
55 return func(algorithm_id); | |
56 } | |
57 | |
58 // Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto | |
59 // factory function. | |
60 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)(); | |
61 typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap; | |
62 | |
63 class JwkAlgorithmFactoryMap { | |
64 public: | 44 public: |
65 JwkAlgorithmFactoryMap() { | 45 JwkAlgorithmInfo() : |
66 map_["HS256"] = | 46 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT), |
67 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | 47 creation_func_(NULL) { |
68 blink::WebCryptoAlgorithmIdSha256>; | |
69 map_["HS384"] = | |
70 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | |
71 blink::WebCryptoAlgorithmIdSha384>; | |
72 map_["HS512"] = | |
73 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | |
74 blink::WebCryptoAlgorithmIdSha512>; | |
75 map_["RS256"] = | |
76 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
77 blink::WebCryptoAlgorithmIdSha256>; | |
78 map_["RS384"] = | |
79 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
80 blink::WebCryptoAlgorithmIdSha384>; | |
81 map_["RS512"] = | |
82 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
83 blink::WebCryptoAlgorithmIdSha512>; | |
84 map_["RSA1_5"] = | |
85 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
86 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>; | |
87 map_["RSA-OAEP"] = | |
88 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm, | |
89 blink::WebCryptoAlgorithmIdSha1>; | |
90 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet | |
91 map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull; | |
92 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet | |
93 map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull; | |
94 map_["A128GCM"] = | |
95 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
96 blink::WebCryptoAlgorithmIdAesGcm>; | |
97 map_["A256GCM"] = | |
98 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
99 blink::WebCryptoAlgorithmIdAesGcm>; | |
100 map_["A128CBC"] = | |
101 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
102 blink::WebCryptoAlgorithmIdAesCbc>; | |
103 map_["A192CBC"] = | |
104 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
105 blink::WebCryptoAlgorithmIdAesCbc>; | |
106 map_["A256CBC"] = | |
107 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, | |
108 blink::WebCryptoAlgorithmIdAesCbc>; | |
109 } | 48 } |
110 | 49 |
111 blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id) | 50 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) |
112 const { | 51 : required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT), |
113 const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id); | 52 creation_func_(algorithm_creation_func) { |
114 if (pos == map_.end()) | 53 } |
115 return blink::WebCryptoAlgorithm::createNull(); | 54 |
116 return pos->second(); | 55 JwkAlgorithmInfo(unsigned int required_key_length_bits, |
56 AlgorithmCreationFunc algorithm_creation_func) | |
57 : required_key_length_bytes_(required_key_length_bits / 8), | |
58 creation_func_(algorithm_creation_func) { | |
59 DCHECK((required_key_length_bits % 8) == 0); | |
60 } | |
61 | |
62 bool CreateAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { | |
63 *algorithm = creation_func_(); | |
64 return !algorithm->isNull(); | |
65 } | |
66 | |
67 bool IsInvalidKeyByteLength(size_t byte_length) const { | |
68 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) | |
69 return false; | |
70 return required_key_length_bytes_ != byte_length; | |
Ryan Sleevi
2014/01/31 21:15:09
nit: delete extra " "
| |
117 } | 71 } |
118 | 72 |
119 private: | 73 private: |
120 JwkAlgFactoryMap map_; | 74 enum {NO_KEY_SIZE_REQUIREMENT = UINT_MAX}; |
75 | |
76 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT. | |
77 unsigned int required_key_length_bytes_; | |
78 | |
79 AlgorithmCreationFunc creation_func_; | |
Ryan Sleevi
2014/01/31 21:15:09
pedantic nit: It seems a little structurally clean
| |
121 }; | 80 }; |
122 | 81 |
123 base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory = | 82 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap; |
83 | |
84 class JwkAlgorithmRegistry { | |
85 public: | |
86 JwkAlgorithmRegistry() { | |
87 // TODO(eroman): | |
88 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20 | |
89 // says HMAC with SHA-2 should have a key size at least as large as the | |
90 // hash output. | |
91 alg_to_info_["HS256"] = JwkAlgorithmInfo( | |
92 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | |
93 blink::WebCryptoAlgorithmIdSha256>); | |
94 alg_to_info_["HS384"] = JwkAlgorithmInfo( | |
95 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | |
96 blink::WebCryptoAlgorithmIdSha384>); | |
97 alg_to_info_["HS512"] = JwkAlgorithmInfo( | |
98 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId, | |
99 blink::WebCryptoAlgorithmIdSha512>); | |
100 alg_to_info_["RS256"] = JwkAlgorithmInfo( | |
101 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
102 blink::WebCryptoAlgorithmIdSha256>); | |
103 alg_to_info_["RS384"] = JwkAlgorithmInfo( | |
104 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
105 blink::WebCryptoAlgorithmIdSha384>); | |
106 alg_to_info_["RS512"] = JwkAlgorithmInfo( | |
107 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, | |
108 blink::WebCryptoAlgorithmIdSha512>); | |
109 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo( | |
110 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
111 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>); | |
112 alg_to_info_["RSA-OAEP"] = JwkAlgorithmInfo( | |
113 &BindAlgorithmId<webcrypto::CreateRsaOaepAlgorithm, | |
114 blink::WebCryptoAlgorithmIdSha1>); | |
115 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet | |
116 alg_to_info_["A128KW"] = | |
117 JwkAlgorithmInfo(128, &blink::WebCryptoAlgorithm::createNull); | |
118 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet | |
119 alg_to_info_["A256KW"] = | |
120 JwkAlgorithmInfo(256, &blink::WebCryptoAlgorithm::createNull); | |
121 alg_to_info_["A128GCM"] = JwkAlgorithmInfo( | |
122 128, | |
123 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
124 blink::WebCryptoAlgorithmIdAesGcm>); | |
125 alg_to_info_["A256GCM"] = JwkAlgorithmInfo( | |
126 256, | |
127 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
128 blink::WebCryptoAlgorithmIdAesGcm>); | |
129 alg_to_info_["A128CBC"] = JwkAlgorithmInfo( | |
130 128, | |
131 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
132 blink::WebCryptoAlgorithmIdAesCbc>); | |
133 alg_to_info_["A192CBC"] = JwkAlgorithmInfo( | |
134 192, | |
135 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
136 blink::WebCryptoAlgorithmIdAesCbc>); | |
137 alg_to_info_["A256CBC"] = JwkAlgorithmInfo( | |
138 256, | |
139 &BindAlgorithmId<webcrypto::CreateAlgorithm, | |
140 blink::WebCryptoAlgorithmIdAesCbc>); | |
141 } | |
142 | |
143 // Returns NULL if the algorithm name was not registered. | |
144 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const { | |
145 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg); | |
146 if (pos == alg_to_info_.end()) | |
147 return NULL; | |
148 return &pos->second; | |
149 } | |
150 | |
151 private: | |
152 // Binds a WebCryptoAlgorithmId value to a compatible factory function. | |
153 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)( | |
154 blink::WebCryptoAlgorithmId); | |
155 template <FuncWithWebCryptoAlgIdArg func, | |
156 blink::WebCryptoAlgorithmId algorithm_id> | |
157 static blink::WebCryptoAlgorithm BindAlgorithmId() { | |
158 return func(algorithm_id); | |
159 } | |
160 | |
161 JwkAlgorithmInfoMap alg_to_info_; | |
162 }; | |
163 | |
164 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry = | |
124 LAZY_INSTANCE_INITIALIZER; | 165 LAZY_INSTANCE_INITIALIZER; |
125 | 166 |
126 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, | 167 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, |
127 const blink::WebCryptoAlgorithm& alg2) { | 168 const blink::WebCryptoAlgorithm& alg2) { |
128 DCHECK(!alg1.isNull()); | 169 DCHECK(!alg1.isNull()); |
129 DCHECK(!alg2.isNull()); | 170 DCHECK(!alg2.isNull()); |
130 if (alg1.id() != alg2.id()) | 171 if (alg1.id() != alg2.id()) |
131 return false; | 172 return false; |
132 switch (alg1.id()) { | 173 switch (alg1.id()) { |
133 case blink::WebCryptoAlgorithmIdHmac: | 174 case blink::WebCryptoAlgorithmIdHmac: |
(...skipping 20 matching lines...) Expand all Loading... | |
154 break; | 195 break; |
155 } | 196 } |
156 return false; | 197 return false; |
157 } | 198 } |
158 | 199 |
159 bool GetDecodedUrl64ValueByKey( | 200 bool GetDecodedUrl64ValueByKey( |
160 const base::DictionaryValue& dict, | 201 const base::DictionaryValue& dict, |
161 const std::string& key, | 202 const std::string& key, |
162 std::string* decoded) { | 203 std::string* decoded) { |
163 std::string value_url64; | 204 std::string value_url64; |
164 if (!dict.GetString(key, &value_url64) || | 205 return dict.GetString(key, &value_url64) && |
165 !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) || | 206 webcrypto::Base64DecodeUrlSafe(value_url64, decoded); |
166 !decoded->size()) { | |
167 return false; | |
168 } | |
169 return true; | |
170 } | 207 } |
171 | 208 |
172 } // namespace | 209 } // namespace |
173 | 210 |
174 WebCryptoImpl::WebCryptoImpl() { | 211 WebCryptoImpl::WebCryptoImpl() { |
175 Init(); | 212 Init(); |
176 } | 213 } |
177 | 214 |
178 void WebCryptoImpl::encrypt( | 215 void WebCryptoImpl::encrypt( |
179 const blink::WebCryptoAlgorithm& algorithm, | 216 const blink::WebCryptoAlgorithm& algorithm, |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
529 // 1. JWK alg present but unrecognized: error | 566 // 1. JWK alg present but unrecognized: error |
530 // 2. JWK alg valid AND input algorithm isNull: use JWK value | 567 // 2. JWK alg valid AND input algorithm isNull: use JWK value |
531 // 3. JWK alg valid AND input algorithm specified, but JWK value | 568 // 3. JWK alg valid AND input algorithm specified, but JWK value |
532 // inconsistent with input: error | 569 // inconsistent with input: error |
533 // 4. JWK alg valid AND input algorithm specified, both consistent: use | 570 // 4. JWK alg valid AND input algorithm specified, both consistent: use |
534 // input value (because it has potentially more details) | 571 // input value (because it has potentially more details) |
535 // 5. JWK alg missing AND input algorithm isNull: error | 572 // 5. JWK alg missing AND input algorithm isNull: error |
536 // 6. JWK alg missing AND input algorithm specified: use input value | 573 // 6. JWK alg missing AND input algorithm specified: use input value |
537 // TODO(eroman): Should error if "alg" was specified but not a string. | 574 // TODO(eroman): Should error if "alg" was specified but not a string. |
538 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); | 575 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); |
576 const JwkAlgorithmInfo* algorithm_info = NULL; | |
539 std::string jwk_alg_value; | 577 std::string jwk_alg_value; |
540 if (dict_value->GetString("alg", &jwk_alg_value)) { | 578 if (dict_value->GetString("alg", &jwk_alg_value)) { |
541 // JWK alg present | 579 // JWK alg present |
542 | 580 |
543 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can | 581 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can |
544 // only be from the RSA family. | 582 // only be from the RSA family. |
545 | 583 |
546 const blink::WebCryptoAlgorithm jwk_algorithm = | 584 blink::WebCryptoAlgorithm jwk_algorithm = |
547 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); | 585 blink::WebCryptoAlgorithm::createNull(); |
548 if (jwk_algorithm.isNull()) { | 586 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value); |
549 // JWK alg unrecognized | 587 if (!algorithm_info || !algorithm_info->CreateAlgorithm(&jwk_algorithm)) |
550 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 | 588 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 |
551 } | 589 |
552 // JWK alg valid | 590 // JWK alg valid |
553 if (algorithm_or_null.isNull()) { | 591 if (algorithm_or_null.isNull()) { |
554 // input algorithm not specified | 592 // input algorithm not specified |
555 algorithm = jwk_algorithm; // case 2 | 593 algorithm = jwk_algorithm; // case 2 |
556 } else { | 594 } else { |
557 // input algorithm specified | 595 // input algorithm specified |
558 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) | 596 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) |
559 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 | 597 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 |
560 algorithm = algorithm_or_null; // case 4 | 598 algorithm = algorithm_or_null; // case 4 |
561 } | 599 } |
(...skipping 28 matching lines...) Expand all Loading... | |
590 } | 628 } |
591 } | 629 } |
592 | 630 |
593 // JWK keying material --> ImportKeyInternal() | 631 // JWK keying material --> ImportKeyInternal() |
594 if (jwk_kty_value == "oct") { | 632 if (jwk_kty_value == "oct") { |
595 | 633 |
596 std::string jwk_k_value; | 634 std::string jwk_k_value; |
597 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) | 635 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) |
598 return Status::ErrorJwkDecodeK(); | 636 return Status::ErrorJwkDecodeK(); |
599 | 637 |
600 // TODO(padolph): Some JWK alg ID's embed information about the key length | 638 // Some JWK alg ID's embed information about the key length in the alg ID |
601 // in the alg ID string. For example "A128" implies the JWK carries 128 bits | 639 // string. For example "A128CBC" implies the JWK carries 128 bits |
602 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits | 640 // of key material. For such keys validate that enough bytes were provided. |
603 // of key material. For such keys validate the actual key length against the | 641 // If this validation is not done, then it would be possible to select a |
604 // value in the ID. | 642 // different algorithm by passing a different lengthed key, since that is |
643 // how WebCrypto interprets things. | |
644 if (algorithm_info && | |
645 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { | |
646 return Status::ErrorJwkIncorrectKeyLength(); | |
647 } | |
605 | 648 |
606 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, | 649 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, |
607 reinterpret_cast<const uint8*>(jwk_k_value.data()), | 650 reinterpret_cast<const uint8*>(jwk_k_value.data()), |
608 jwk_k_value.size(), | 651 jwk_k_value.size(), |
609 algorithm, | 652 algorithm, |
610 extractable, | 653 extractable, |
611 usage_mask, | 654 usage_mask, |
612 key); | 655 key); |
613 } else if (jwk_kty_value == "RSA") { | 656 } else if (jwk_kty_value == "RSA") { |
614 | 657 |
(...skipping 27 matching lines...) Expand all Loading... | |
642 key); | 685 key); |
643 | 686 |
644 } else { | 687 } else { |
645 return Status::ErrorJwkUnrecognizedKty(); | 688 return Status::ErrorJwkUnrecognizedKty(); |
646 } | 689 } |
647 | 690 |
648 return Status::Success(); | 691 return Status::Success(); |
649 } | 692 } |
650 | 693 |
651 } // namespace content | 694 } // namespace content |
OLD | NEW |