OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 #include <functional> | |
7 #include <map> | |
8 #include "base/json/json_reader.h" | |
9 #include "base/lazy_instance.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/strings/string_piece.h" | |
13 #include "base/values.h" | |
14 #include "content/renderer/webcrypto/crypto_data.h" | |
15 #include "content/renderer/webcrypto/platform_crypto.h" | |
16 #include "content/renderer/webcrypto/shared_crypto.h" | |
17 #include "content/renderer/webcrypto/webcrypto_util.h" | |
18 | |
19 namespace content { | |
20 | |
21 namespace webcrypto { | |
22 | |
23 namespace { | |
24 | |
25 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); | |
26 | |
27 class JwkAlgorithmInfo { | |
28 public: | |
29 JwkAlgorithmInfo() | |
30 : creation_func_(NULL), | |
31 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} | |
32 | |
33 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) | |
34 : creation_func_(algorithm_creation_func), | |
35 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} | |
36 | |
37 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func, | |
38 unsigned int required_key_length_bits) | |
39 : creation_func_(algorithm_creation_func), | |
40 required_key_length_bytes_(required_key_length_bits / 8) { | |
41 DCHECK((required_key_length_bits % 8) == 0); | |
42 } | |
43 | |
44 bool CreateImportAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { | |
45 *algorithm = creation_func_(); | |
46 return !algorithm->isNull(); | |
47 } | |
48 | |
49 bool IsInvalidKeyByteLength(size_t byte_length) const { | |
50 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) | |
51 return false; | |
52 return required_key_length_bytes_ != byte_length; | |
53 } | |
54 | |
55 private: | |
56 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX }; | |
57 | |
58 AlgorithmCreationFunc creation_func_; | |
59 | |
60 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT. | |
61 unsigned int required_key_length_bytes_; | |
62 }; | |
63 | |
64 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap; | |
65 | |
66 class JwkAlgorithmRegistry { | |
67 public: | |
68 JwkAlgorithmRegistry() { | |
69 // TODO(eroman): | |
70 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20 | |
71 // says HMAC with SHA-2 should have a key size at least as large as the | |
72 // hash output. | |
73 alg_to_info_["HS256"] = | |
74 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
75 blink::WebCryptoAlgorithmIdSha256>); | |
76 alg_to_info_["HS384"] = | |
77 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
78 blink::WebCryptoAlgorithmIdSha384>); | |
79 alg_to_info_["HS512"] = | |
80 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
81 blink::WebCryptoAlgorithmIdSha512>); | |
82 alg_to_info_["RS256"] = | |
83 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
84 blink::WebCryptoAlgorithmIdSha256>); | |
85 alg_to_info_["RS384"] = | |
86 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
87 blink::WebCryptoAlgorithmIdSha384>); | |
88 alg_to_info_["RS512"] = | |
89 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
90 blink::WebCryptoAlgorithmIdSha512>); | |
91 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo( | |
92 &BindAlgorithmId<CreateAlgorithm, | |
93 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>); | |
94 alg_to_info_["RSA-OAEP"] = | |
95 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm, | |
96 blink::WebCryptoAlgorithmIdSha1>); | |
97 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet | |
98 alg_to_info_["A128KW"] = | |
99 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128); | |
100 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet | |
101 alg_to_info_["A256KW"] = | |
102 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256); | |
103 alg_to_info_["A128GCM"] = JwkAlgorithmInfo( | |
104 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, | |
105 128); | |
106 alg_to_info_["A256GCM"] = JwkAlgorithmInfo( | |
107 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, | |
108 256); | |
109 alg_to_info_["A128CBC"] = JwkAlgorithmInfo( | |
110 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
111 128); | |
112 alg_to_info_["A192CBC"] = JwkAlgorithmInfo( | |
113 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
114 192); | |
115 alg_to_info_["A256CBC"] = JwkAlgorithmInfo( | |
116 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
117 256); | |
118 } | |
119 | |
120 // Returns NULL if the algorithm name was not registered. | |
121 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const { | |
122 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg); | |
123 if (pos == alg_to_info_.end()) | |
124 return NULL; | |
125 return &pos->second; | |
126 } | |
127 | |
128 private: | |
129 // Binds a WebCryptoAlgorithmId value to a compatible factory function. | |
130 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)( | |
131 blink::WebCryptoAlgorithmId); | |
132 template <FuncWithWebCryptoAlgIdArg func, | |
133 blink::WebCryptoAlgorithmId algorithm_id> | |
134 static blink::WebCryptoAlgorithm BindAlgorithmId() { | |
135 return func(algorithm_id); | |
136 } | |
137 | |
138 JwkAlgorithmInfoMap alg_to_info_; | |
139 }; | |
140 | |
141 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry = | |
142 LAZY_INSTANCE_INITIALIZER; | |
143 | |
144 bool ImportAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, | |
145 const blink::WebCryptoAlgorithm& alg2) { | |
146 DCHECK(!alg1.isNull()); | |
147 DCHECK(!alg2.isNull()); | |
148 if (alg1.id() != alg2.id()) | |
149 return false; | |
150 if (alg1.paramsType() != alg2.paramsType()) | |
151 return false; | |
152 switch (alg1.paramsType()) { | |
153 case blink::WebCryptoAlgorithmParamsTypeNone: | |
154 return true; | |
155 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams: | |
156 return ImportAlgorithmsConsistent(alg1.rsaHashedImportParams()->hash(), | |
157 alg2.rsaHashedImportParams()->hash()); | |
158 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams: | |
159 return ImportAlgorithmsConsistent(alg1.hmacImportParams()->hash(), | |
160 alg2.hmacImportParams()->hash()); | |
161 default: | |
162 return false; | |
163 } | |
164 } | |
165 | |
166 // Extracts the required string property with key |path| from |dict| and saves | |
167 // the result to |*result|. If the property does not exist or is not a string, | |
168 // returns an error. | |
169 Status GetJwkString(base::DictionaryValue* dict, | |
170 const std::string& path, | |
171 std::string* result) { | |
172 base::Value* value = NULL; | |
173 if (!dict->Get(path, &value)) | |
174 return Status::ErrorJwkPropertyMissing(path); | |
175 if (!value->GetAsString(result)) | |
176 return Status::ErrorJwkPropertyWrongType(path, "string"); | |
177 return Status::Success(); | |
178 } | |
179 | |
180 // Extracts the optional string property with key |path| from |dict| and saves | |
181 // the result to |*result| if it was found. If the property exists and is not a | |
182 // string, returns an error. Otherwise returns success, and sets | |
183 // |*property_exists| if it was found. | |
184 Status GetOptionalJwkString(base::DictionaryValue* dict, | |
185 const std::string& path, | |
186 std::string* result, | |
187 bool* property_exists) { | |
188 *property_exists = false; | |
189 base::Value* value = NULL; | |
190 if (!dict->Get(path, &value)) | |
191 return Status::Success(); | |
192 | |
193 if (!value->GetAsString(result)) | |
194 return Status::ErrorJwkPropertyWrongType(path, "string"); | |
195 | |
196 *property_exists = true; | |
197 return Status::Success(); | |
198 } | |
199 | |
200 // Extracts the required string property with key |path| from |dict| and saves | |
201 // the base64-decoded bytes to |*result|. If the property does not exist or is | |
202 // not a string, or could not be base64-decoded, returns an error. | |
203 Status GetJwkBytes(base::DictionaryValue* dict, | |
204 const std::string& path, | |
205 std::string* result) { | |
206 std::string base64_string; | |
207 Status status = GetJwkString(dict, path, &base64_string); | |
208 if (status.IsError()) | |
209 return status; | |
210 | |
211 if (!Base64DecodeUrlSafe(base64_string, result)) | |
212 return Status::ErrorJwkBase64Decode(path); | |
213 | |
214 return Status::Success(); | |
215 } | |
216 | |
217 // Extracts the optional boolean property with key |path| from |dict| and saves | |
218 // the result to |*result| if it was found. If the property exists and is not a | |
219 // boolean, returns an error. Otherwise returns success, and sets | |
220 // |*property_exists| if it was found. | |
221 Status GetOptionalJwkBool(base::DictionaryValue* dict, | |
222 const std::string& path, | |
223 bool* result, | |
224 bool* property_exists) { | |
225 *property_exists = false; | |
226 base::Value* value = NULL; | |
227 if (!dict->Get(path, &value)) | |
228 return Status::Success(); | |
229 | |
230 if (!value->GetAsBoolean(result)) | |
231 return Status::ErrorJwkPropertyWrongType(path, "boolean"); | |
232 | |
233 *property_exists = true; | |
234 return Status::Success(); | |
235 } | |
236 | |
237 } // namespace | |
238 | |
239 Status ImportKeyJwk(const CryptoData& key_data, | |
240 const blink::WebCryptoAlgorithm& algorithm_or_null, | |
241 bool extractable, | |
242 blink::WebCryptoKeyUsageMask usage_mask, | |
243 blink::WebCryptoKey* key) { | |
244 | |
245 // The goal of this method is to extract key material and meta data from the | |
246 // incoming JWK, combine them with the input parameters, and ultimately import | |
247 // a Web Crypto Key. | |
248 // | |
249 // JSON Web Key Format (JWK) | |
250 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16 | |
251 // TODO(padolph): Not all possible values are handled by this code right now | |
252 // | |
253 // A JWK is a simple JSON dictionary with the following entries | |
254 // - "kty" (Key Type) Parameter, REQUIRED | |
255 // - <kty-specific parameters, see below>, REQUIRED | |
256 // - "use" (Key Use) Parameter, OPTIONAL | |
257 // - "alg" (Algorithm) Parameter, OPTIONAL | |
258 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE, | |
259 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796] | |
260 // (all other entries are ignored) | |
261 // | |
262 // OPTIONAL here means that this code does not require the entry to be present | |
263 // in the incoming JWK, because the method input parameters contain similar | |
264 // information. If the optional JWK entry is present, it will be validated | |
265 // against the corresponding input parameter for consistency and combined with | |
266 // it according to rules defined below. A special case is that the method | |
267 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg' | |
268 // value (if present) is used as a fallback. | |
269 // | |
270 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK | |
271 // values are parsed out and combined with the method input parameters to | |
272 // build a Web Crypto Key: | |
273 // Web Crypto Key type <-- (deduced) | |
274 // Web Crypto Key extractable <-- JWK extractable + input extractable | |
275 // Web Crypto Key algorithm <-- JWK alg + input algorithm | |
276 // Web Crypto Key keyUsage <-- JWK use + input usage_mask | |
277 // Web Crypto Key keying material <-- kty-specific parameters | |
278 // | |
279 // Values for each JWK entry are case-sensitive and defined in | |
280 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. | |
281 // Note that not all values specified by JOSE are handled by this code. Only | |
282 // handled values are listed. | |
283 // - kty (Key Type) | |
284 // +-------+--------------------------------------------------------------+ | |
285 // | "RSA" | RSA [RFC3447] | | |
286 // | "oct" | Octet sequence (used to represent symmetric keys) | | |
287 // +-------+--------------------------------------------------------------+ | |
288 // - use (Key Use) | |
289 // +-------+--------------------------------------------------------------+ | |
290 // | "enc" | encrypt and decrypt operations | | |
291 // | "sig" | sign and verify (MAC) operations | | |
292 // | "wrap"| key wrap and unwrap [not yet part of JOSE] | | |
293 // +-------+--------------------------------------------------------------+ | |
294 // - extractable (Key Exportability) | |
295 // +-------+--------------------------------------------------------------+ | |
296 // | true | Key may be exported from the trusted environment | | |
297 // | false | Key cannot exit the trusted environment | | |
298 // +-------+--------------------------------------------------------------+ | |
299 // - alg (Algorithm) | |
300 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
301 // +--------------+-------------------------------------------------------+ | |
302 // | Digital Signature or MAC Algorithm | | |
303 // +--------------+-------------------------------------------------------+ | |
304 // | "HS256" | HMAC using SHA-256 hash algorithm | | |
305 // | "HS384" | HMAC using SHA-384 hash algorithm | | |
306 // | "HS512" | HMAC using SHA-512 hash algorithm | | |
307 // | "RS256" | RSASSA using SHA-256 hash algorithm | | |
308 // | "RS384" | RSASSA using SHA-384 hash algorithm | | |
309 // | "RS512" | RSASSA using SHA-512 hash algorithm | | |
310 // +--------------+-------------------------------------------------------| | |
311 // | Key Management Algorithm | | |
312 // +--------------+-------------------------------------------------------+ | |
313 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | | |
314 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | | |
315 // | | (OAEP) [RFC3447], with the default parameters | | |
316 // | | specified by RFC3447 in Section A.2.1 | | |
317 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | | |
318 // | | [RFC3394] using 128 bit keys | | |
319 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | | |
320 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | | |
321 // | | 128 bit keys | | |
322 // | "A256GCM" | AES GCM using 256 bit keys | | |
323 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | | |
324 // | | padding [NIST.800-38A] [not yet part of JOSE, see | | |
325 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 | | |
326 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] | | |
327 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | | |
328 // +--------------+-------------------------------------------------------+ | |
329 // | |
330 // kty-specific parameters | |
331 // The value of kty determines the type and content of the keying material | |
332 // carried in the JWK to be imported. Currently only two possibilities are | |
333 // supported: a raw key or an RSA public key. RSA private keys are not | |
334 // supported because typical applications seldom need to import a private key, | |
335 // and the large number of JWK parameters required to describe one. | |
336 // - kty == "oct" (symmetric or other raw key) | |
337 // +-------+--------------------------------------------------------------+ | |
338 // | "k" | Contains the value of the symmetric (or other single-valued) | | |
339 // | | key. It is represented as the base64url encoding of the | | |
340 // | | octet sequence containing the key value. | | |
341 // +-------+--------------------------------------------------------------+ | |
342 // - kty == "RSA" (RSA public key) | |
343 // +-------+--------------------------------------------------------------+ | |
344 // | "n" | Contains the modulus value for the RSA public key. It is | | |
345 // | | represented as the base64url encoding of the value's | | |
346 // | | unsigned big endian representation as an octet sequence. | | |
347 // +-------+--------------------------------------------------------------+ | |
348 // | "e" | Contains the exponent value for the RSA public key. It is | | |
349 // | | represented as the base64url encoding of the value's | | |
350 // | | unsigned big endian representation as an octet sequence. | | |
351 // +-------+--------------------------------------------------------------+ | |
352 // | |
353 // Consistency and conflict resolution | |
354 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters | |
355 // may be different than the corresponding values inside the JWK. The Web | |
356 // Crypto spec says that if a JWK value is present but is inconsistent with | |
357 // the input value, it is an error and the operation must fail. If no | |
358 // inconsistency is found, the input and JWK values are combined as follows: | |
359 // | |
360 // algorithm | |
361 // If an algorithm is provided by both the input parameter and the JWK, | |
362 // consistency between the two is based only on algorithm ID's (including an | |
363 // inner hash algorithm if present). In this case if the consistency | |
364 // check is passed, the input algorithm is used. If only one of either the | |
365 // input algorithm and JWK alg is provided, it is used as the final | |
366 // algorithm. | |
367 // | |
368 // extractable | |
369 // If the JWK extractable is true but the input parameter is false, make the | |
370 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is | |
371 // false but the input parameter is true, it is an inconsistency. If both | |
372 // are true or both are false, use that value. | |
373 // | |
374 // usage_mask | |
375 // The input usage_mask must be a strict subset of the interpreted JWK use | |
376 // value, else it is judged inconsistent. In all cases the input usage_mask | |
377 // is used as the final usage_mask. | |
378 // | |
379 | |
380 if (!key_data.byte_length()) | |
381 return Status::ErrorImportEmptyKeyData(); | |
382 DCHECK(key); | |
383 | |
384 // Parse the incoming JWK JSON. | |
385 base::StringPiece json_string(reinterpret_cast<const char*>(key_data.bytes()), | |
386 key_data.byte_length()); | |
387 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
388 // Note, bare pointer dict_value is ok since it points into scoped value. | |
389 base::DictionaryValue* dict_value = NULL; | |
390 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
391 return Status::ErrorJwkNotDictionary(); | |
392 | |
393 // JWK "kty". Exit early if this required JWK parameter is missing. | |
394 std::string jwk_kty_value; | |
395 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value); | |
396 if (status.IsError()) | |
397 return status; | |
398 | |
399 // JWK "extractable" (optional) --> extractable parameter | |
400 { | |
401 bool jwk_extractable_value = false; | |
402 bool has_jwk_extractable; | |
403 status = GetOptionalJwkBool(dict_value, | |
404 "extractable", | |
405 &jwk_extractable_value, | |
406 &has_jwk_extractable); | |
407 if (status.IsError()) | |
408 return status; | |
409 if (has_jwk_extractable && !jwk_extractable_value && extractable) | |
410 return Status::ErrorJwkExtractableInconsistent(); | |
411 } | |
412 | |
413 // JWK "alg" (optional) --> algorithm parameter | |
414 // Note: input algorithm is also optional, so we have six cases to handle. | |
415 // 1. JWK alg present but unrecognized: error | |
416 // 2. JWK alg valid AND input algorithm isNull: use JWK value | |
417 // 3. JWK alg valid AND input algorithm specified, but JWK value | |
418 // inconsistent with input: error | |
419 // 4. JWK alg valid AND input algorithm specified, both consistent: use | |
420 // input value (because it has potentially more details) | |
421 // 5. JWK alg missing AND input algorithm isNull: error | |
422 // 6. JWK alg missing AND input algorithm specified: use input value | |
423 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); | |
424 const JwkAlgorithmInfo* algorithm_info = NULL; | |
425 std::string jwk_alg_value; | |
426 bool has_jwk_alg; | |
427 status = | |
428 GetOptionalJwkString(dict_value, "alg", &jwk_alg_value, &has_jwk_alg); | |
429 if (status.IsError()) | |
430 return status; | |
431 | |
432 if (has_jwk_alg) { | |
433 // JWK alg present | |
434 | |
435 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can | |
436 // only be from the RSA family. | |
437 | |
438 blink::WebCryptoAlgorithm jwk_algorithm = | |
439 blink::WebCryptoAlgorithm::createNull(); | |
440 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value); | |
441 if (!algorithm_info || | |
442 !algorithm_info->CreateImportAlgorithm(&jwk_algorithm)) | |
443 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 | |
444 | |
445 // JWK alg valid | |
446 if (algorithm_or_null.isNull()) { | |
447 // input algorithm not specified | |
448 algorithm = jwk_algorithm; // case 2 | |
449 } else { | |
450 // input algorithm specified | |
451 if (!ImportAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) | |
452 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 | |
453 algorithm = algorithm_or_null; // case 4 | |
454 } | |
455 } else { | |
456 // JWK alg missing | |
457 if (algorithm_or_null.isNull()) | |
458 return Status::ErrorJwkAlgorithmMissing(); // case 5 | |
459 algorithm = algorithm_or_null; // case 6 | |
460 } | |
461 DCHECK(!algorithm.isNull()); | |
462 | |
463 // JWK "use" (optional) --> usage_mask parameter | |
464 std::string jwk_use_value; | |
465 bool has_jwk_use; | |
466 status = | |
467 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use); | |
468 if (status.IsError()) | |
469 return status; | |
470 if (has_jwk_use) { | |
471 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0; | |
472 if (jwk_use_value == "enc") { | |
473 jwk_usage_mask = | |
474 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; | |
475 } else if (jwk_use_value == "sig") { | |
476 jwk_usage_mask = | |
477 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
478 } else if (jwk_use_value == "wrap") { | |
479 jwk_usage_mask = | |
480 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; | |
481 } else { | |
482 return Status::ErrorJwkUnrecognizedUsage(); | |
483 } | |
484 if ((jwk_usage_mask & usage_mask) != usage_mask) { | |
485 // A usage_mask must be a subset of jwk_usage_mask. | |
486 return Status::ErrorJwkUsageInconsistent(); | |
487 } | |
488 } | |
489 | |
490 // JWK keying material --> ImportKeyInternal() | |
491 if (jwk_kty_value == "oct") { | |
492 | |
493 std::string jwk_k_value; | |
494 status = GetJwkBytes(dict_value, "k", &jwk_k_value); | |
495 if (status.IsError()) | |
496 return status; | |
497 | |
498 // Some JWK alg ID's embed information about the key length in the alg ID | |
499 // string. For example "A128CBC" implies the JWK carries 128 bits | |
500 // of key material. For such keys validate that enough bytes were provided. | |
501 // If this validation is not done, then it would be possible to select a | |
502 // different algorithm by passing a different lengthed key, since that is | |
503 // how WebCrypto interprets things. | |
504 if (algorithm_info && | |
505 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { | |
506 return Status::ErrorJwkIncorrectKeyLength(); | |
507 } | |
508 | |
509 return ImportKey(blink::WebCryptoKeyFormatRaw, | |
510 CryptoData(jwk_k_value), | |
511 algorithm, | |
512 extractable, | |
513 usage_mask, | |
514 key); | |
515 } else if (jwk_kty_value == "RSA") { | |
516 | |
517 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | |
518 // in the JWK, while an RSA private key must have those, plus at least a "d" | |
519 // (private exponent) entry. | |
520 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | |
521 // section 6.3. | |
522 | |
523 // RSA private key import is not currently supported, so fail here if a "d" | |
524 // entry is found. | |
525 // TODO(padolph): Support RSA private key import. | |
526 if (dict_value->HasKey("d")) | |
527 return Status::ErrorJwkRsaPrivateKeyUnsupported(); | |
528 | |
529 std::string jwk_n_value; | |
530 status = GetJwkBytes(dict_value, "n", &jwk_n_value); | |
531 if (status.IsError()) | |
532 return status; | |
533 std::string jwk_e_value; | |
534 status = GetJwkBytes(dict_value, "e", &jwk_e_value); | |
535 if (status.IsError()) | |
536 return status; | |
537 | |
538 return platform::ImportRsaPublicKey(algorithm, | |
539 extractable, | |
540 usage_mask, | |
541 CryptoData(jwk_n_value), | |
542 CryptoData(jwk_e_value), | |
543 key); | |
544 | |
545 } else { | |
546 return Status::ErrorJwkUnrecognizedKty(); | |
547 } | |
548 | |
549 return Status::Success(); | |
550 } | |
551 | |
552 } // namespace webcrypto | |
553 | |
554 } // namespace content | |
OLD | NEW |