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 { |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |