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

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl.cc

Issue 141853006: [webcrypto] Validate JWK import of AES keys: key length must match algorithm. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 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
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 {
50 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)( 44 public:
51 blink::WebCryptoAlgorithmId); 45 JwkAlgorithmInfo()
52 template <AlgFactoryFuncWithWebCryptoAlgIdArg func, 46 : creation_func_(NULL),
53 blink::WebCryptoAlgorithmId algorithm_id> 47 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
54 blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() {
55 return func(algorithm_id);
56 }
57 48
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:
65 JwkAlgorithmFactoryMap() {
66 map_["HS256"] =
67 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
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 } 49 }
110 50
111 blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id) 51 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func)
112 const { 52 : creation_func_(algorithm_creation_func),
113 const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id); 53 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
114 if (pos == map_.end()) 54 }
115 return blink::WebCryptoAlgorithm::createNull(); 55
116 return pos->second(); 56 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func,
57 unsigned int required_key_length_bits)
58 : creation_func_(algorithm_creation_func),
59 required_key_length_bytes_(required_key_length_bits / 8) {
60 DCHECK((required_key_length_bits % 8) == 0);
61 }
62
63 bool CreateAlgorithm(blink::WebCryptoAlgorithm* algorithm) const {
64 *algorithm = creation_func_();
65 return !algorithm->isNull();
66 }
67
68 bool IsInvalidKeyByteLength(size_t byte_length) const {
69 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT)
70 return false;
71 return required_key_length_bytes_ != byte_length;
117 } 72 }
118 73
119 private: 74 private:
120 JwkAlgFactoryMap map_; 75 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX };
76
77 AlgorithmCreationFunc creation_func_;
78
79 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT.
80 unsigned int required_key_length_bytes_;
81
121 }; 82 };
122 83
123 base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory = 84 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap;
85
86 class JwkAlgorithmRegistry {
87 public:
88 JwkAlgorithmRegistry() {
89 // TODO(eroman):
90 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20
91 // says HMAC with SHA-2 should have a key size at least as large as the
92 // hash output.
93 alg_to_info_["HS256"] = JwkAlgorithmInfo(
94 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
95 blink::WebCryptoAlgorithmIdSha256>);
96 alg_to_info_["HS384"] = JwkAlgorithmInfo(
97 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
98 blink::WebCryptoAlgorithmIdSha384>);
99 alg_to_info_["HS512"] = JwkAlgorithmInfo(
100 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
101 blink::WebCryptoAlgorithmIdSha512>);
102 alg_to_info_["RS256"] = JwkAlgorithmInfo(
103 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
104 blink::WebCryptoAlgorithmIdSha256>);
105 alg_to_info_["RS384"] = JwkAlgorithmInfo(
106 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
107 blink::WebCryptoAlgorithmIdSha384>);
108 alg_to_info_["RS512"] = JwkAlgorithmInfo(
109 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
110 blink::WebCryptoAlgorithmIdSha512>);
111 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo(
112 &BindAlgorithmId<webcrypto::CreateAlgorithm,
113 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>);
114 alg_to_info_["RSA-OAEP"] = JwkAlgorithmInfo(
115 &BindAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
116 blink::WebCryptoAlgorithmIdSha1>);
117 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
118 alg_to_info_["A128KW"] =
119 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128);
120 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
121 alg_to_info_["A256KW"] =
122 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256);
123 alg_to_info_["A128GCM"] = JwkAlgorithmInfo(
124 &BindAlgorithmId<webcrypto::CreateAlgorithm,
125 blink::WebCryptoAlgorithmIdAesGcm>, 128);
126 alg_to_info_["A256GCM"] = JwkAlgorithmInfo(
127 &BindAlgorithmId<webcrypto::CreateAlgorithm,
128 blink::WebCryptoAlgorithmIdAesGcm>, 256);
129 alg_to_info_["A128CBC"] = JwkAlgorithmInfo(
130 &BindAlgorithmId<webcrypto::CreateAlgorithm,
131 blink::WebCryptoAlgorithmIdAesCbc>, 128);
132 alg_to_info_["A192CBC"] = JwkAlgorithmInfo(
133 &BindAlgorithmId<webcrypto::CreateAlgorithm,
134 blink::WebCryptoAlgorithmIdAesCbc>, 192);
135 alg_to_info_["A256CBC"] = JwkAlgorithmInfo(
136 &BindAlgorithmId<webcrypto::CreateAlgorithm,
137 blink::WebCryptoAlgorithmIdAesCbc>, 256);
138 }
139
140 // Returns NULL if the algorithm name was not registered.
141 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const {
142 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg);
143 if (pos == alg_to_info_.end())
144 return NULL;
145 return &pos->second;
146 }
147
148 private:
149 // Binds a WebCryptoAlgorithmId value to a compatible factory function.
150 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)(
151 blink::WebCryptoAlgorithmId);
152 template <FuncWithWebCryptoAlgIdArg func,
153 blink::WebCryptoAlgorithmId algorithm_id>
154 static blink::WebCryptoAlgorithm BindAlgorithmId() {
155 return func(algorithm_id);
156 }
157
158 JwkAlgorithmInfoMap alg_to_info_;
159 };
160
161 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry =
124 LAZY_INSTANCE_INITIALIZER; 162 LAZY_INSTANCE_INITIALIZER;
125 163
126 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, 164 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
127 const blink::WebCryptoAlgorithm& alg2) { 165 const blink::WebCryptoAlgorithm& alg2) {
128 DCHECK(!alg1.isNull()); 166 DCHECK(!alg1.isNull());
129 DCHECK(!alg2.isNull()); 167 DCHECK(!alg2.isNull());
130 if (alg1.id() != alg2.id()) 168 if (alg1.id() != alg2.id())
131 return false; 169 return false;
132 switch (alg1.id()) { 170 switch (alg1.id()) {
133 case blink::WebCryptoAlgorithmIdHmac: 171 case blink::WebCryptoAlgorithmIdHmac:
(...skipping 20 matching lines...) Expand all
154 break; 192 break;
155 } 193 }
156 return false; 194 return false;
157 } 195 }
158 196
159 bool GetDecodedUrl64ValueByKey( 197 bool GetDecodedUrl64ValueByKey(
160 const base::DictionaryValue& dict, 198 const base::DictionaryValue& dict,
161 const std::string& key, 199 const std::string& key,
162 std::string* decoded) { 200 std::string* decoded) {
163 std::string value_url64; 201 std::string value_url64;
164 if (!dict.GetString(key, &value_url64) || 202 return dict.GetString(key, &value_url64) &&
165 !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) || 203 webcrypto::Base64DecodeUrlSafe(value_url64, decoded);
166 !decoded->size()) {
167 return false;
168 }
169 return true;
170 } 204 }
171 205
172 } // namespace 206 } // namespace
173 207
174 WebCryptoImpl::WebCryptoImpl() { 208 WebCryptoImpl::WebCryptoImpl() {
175 Init(); 209 Init();
176 } 210 }
177 211
178 void WebCryptoImpl::encrypt( 212 void WebCryptoImpl::encrypt(
179 const blink::WebCryptoAlgorithm& algorithm, 213 const blink::WebCryptoAlgorithm& algorithm,
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 // 1. JWK alg present but unrecognized: error 557 // 1. JWK alg present but unrecognized: error
524 // 2. JWK alg valid AND input algorithm isNull: use JWK value 558 // 2. JWK alg valid AND input algorithm isNull: use JWK value
525 // 3. JWK alg valid AND input algorithm specified, but JWK value 559 // 3. JWK alg valid AND input algorithm specified, but JWK value
526 // inconsistent with input: error 560 // inconsistent with input: error
527 // 4. JWK alg valid AND input algorithm specified, both consistent: use 561 // 4. JWK alg valid AND input algorithm specified, both consistent: use
528 // input value (because it has potentially more details) 562 // input value (because it has potentially more details)
529 // 5. JWK alg missing AND input algorithm isNull: error 563 // 5. JWK alg missing AND input algorithm isNull: error
530 // 6. JWK alg missing AND input algorithm specified: use input value 564 // 6. JWK alg missing AND input algorithm specified: use input value
531 // TODO(eroman): Should error if "alg" was specified but not a string. 565 // TODO(eroman): Should error if "alg" was specified but not a string.
532 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); 566 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
567 const JwkAlgorithmInfo* algorithm_info = NULL;
533 std::string jwk_alg_value; 568 std::string jwk_alg_value;
534 if (dict_value->GetString("alg", &jwk_alg_value)) { 569 if (dict_value->GetString("alg", &jwk_alg_value)) {
535 // JWK alg present 570 // JWK alg present
536 571
537 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can 572 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
538 // only be from the RSA family. 573 // only be from the RSA family.
539 574
540 const blink::WebCryptoAlgorithm jwk_algorithm = 575 blink::WebCryptoAlgorithm jwk_algorithm =
541 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); 576 blink::WebCryptoAlgorithm::createNull();
542 if (jwk_algorithm.isNull()) { 577 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value);
543 // JWK alg unrecognized 578 if (!algorithm_info || !algorithm_info->CreateAlgorithm(&jwk_algorithm))
544 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 579 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1
545 } 580
546 // JWK alg valid 581 // JWK alg valid
547 if (algorithm_or_null.isNull()) { 582 if (algorithm_or_null.isNull()) {
548 // input algorithm not specified 583 // input algorithm not specified
549 algorithm = jwk_algorithm; // case 2 584 algorithm = jwk_algorithm; // case 2
550 } else { 585 } else {
551 // input algorithm specified 586 // input algorithm specified
552 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) 587 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
553 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 588 return Status::ErrorJwkAlgorithmInconsistent(); // case 3
554 algorithm = algorithm_or_null; // case 4 589 algorithm = algorithm_or_null; // case 4
555 } 590 }
(...skipping 28 matching lines...) Expand all
584 } 619 }
585 } 620 }
586 621
587 // JWK keying material --> ImportKeyInternal() 622 // JWK keying material --> ImportKeyInternal()
588 if (jwk_kty_value == "oct") { 623 if (jwk_kty_value == "oct") {
589 624
590 std::string jwk_k_value; 625 std::string jwk_k_value;
591 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) 626 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value))
592 return Status::ErrorJwkDecodeK(); 627 return Status::ErrorJwkDecodeK();
593 628
594 // TODO(padolph): Some JWK alg ID's embed information about the key length 629 // Some JWK alg ID's embed information about the key length in the alg ID
595 // in the alg ID string. For example "A128" implies the JWK carries 128 bits 630 // string. For example "A128CBC" implies the JWK carries 128 bits
596 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits 631 // of key material. For such keys validate that enough bytes were provided.
597 // of key material. For such keys validate the actual key length against the 632 // If this validation is not done, then it would be possible to select a
598 // value in the ID. 633 // different algorithm by passing a different lengthed key, since that is
634 // how WebCrypto interprets things.
635 if (algorithm_info &&
636 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) {
637 return Status::ErrorJwkIncorrectKeyLength();
638 }
599 639
600 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, 640 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
601 reinterpret_cast<const uint8*>(jwk_k_value.data()), 641 reinterpret_cast<const uint8*>(jwk_k_value.data()),
602 jwk_k_value.size(), 642 jwk_k_value.size(),
603 algorithm, 643 algorithm,
604 extractable, 644 extractable,
605 usage_mask, 645 usage_mask,
606 key); 646 key);
607 } else if (jwk_kty_value == "RSA") { 647 } else if (jwk_kty_value == "RSA") {
608 648
(...skipping 27 matching lines...) Expand all
636 key); 676 key);
637 677
638 } else { 678 } else {
639 return Status::ErrorJwkUnrecognizedKty(); 679 return Status::ErrorJwkUnrecognizedKty();
640 } 680 }
641 681
642 return Status::Success(); 682 return Status::Success();
643 } 683 }
644 684
645 } // namespace content 685 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698