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
3 // found in the LICENSE file.
5 #include "content/renderer/webcrypto/webcrypto_impl.h"
10 #include "base/json/json_reader.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_piece.h"
15 #include "base/values.h"
16 #include "content/renderer/webcrypto/webcrypto_util.h"
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
19 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
24 using webcrypto::Status;
28 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
29 DCHECK(status.IsError());
30 if (status.HasErrorDetails())
31 result->completeWithError(blink::WebString::fromUTF8(status.ToString()));
33 result->completeWithError();
36 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
37 // TODO(padolph): include all other asymmetric algorithms once they are
38 // defined, e.g. EC and DH.
39 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
40 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
41 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
44 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)();
46 class JwkAlgorithmInfo {
49 : creation_func_(NULL),
50 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
54 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func)
55 : creation_func_(algorithm_creation_func),
56 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
59 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func,
60 unsigned int required_key_length_bits)
61 : creation_func_(algorithm_creation_func),
62 required_key_length_bytes_(required_key_length_bits / 8) {
63 DCHECK((required_key_length_bits % 8) == 0);
66 bool CreateAlgorithm(blink::WebCryptoAlgorithm* algorithm) const {
67 *algorithm = creation_func_();
68 return !algorithm->isNull();
71 bool IsInvalidKeyByteLength(size_t byte_length) const {
72 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT)
74 return required_key_length_bytes_ != byte_length;
78 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX };
80 AlgorithmCreationFunc creation_func_;
82 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT.
83 unsigned int required_key_length_bytes_;
87 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap;
89 class JwkAlgorithmRegistry {
91 JwkAlgorithmRegistry() {
93 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20
94 // says HMAC with SHA-2 should have a key size at least as large as the
96 alg_to_info_["HS256"] = JwkAlgorithmInfo(
97 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
98 blink::WebCryptoAlgorithmIdSha256>);
99 alg_to_info_["HS384"] = JwkAlgorithmInfo(
100 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
101 blink::WebCryptoAlgorithmIdSha384>);
102 alg_to_info_["HS512"] = JwkAlgorithmInfo(
103 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
104 blink::WebCryptoAlgorithmIdSha512>);
105 alg_to_info_["RS256"] = JwkAlgorithmInfo(
106 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
107 blink::WebCryptoAlgorithmIdSha256>);
108 alg_to_info_["RS384"] = JwkAlgorithmInfo(
109 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
110 blink::WebCryptoAlgorithmIdSha384>);
111 alg_to_info_["RS512"] = JwkAlgorithmInfo(
112 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
113 blink::WebCryptoAlgorithmIdSha512>);
114 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo(
115 &BindAlgorithmId<webcrypto::CreateAlgorithm,
116 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>);
117 alg_to_info_["RSA-OAEP"] = JwkAlgorithmInfo(
118 &BindAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
119 blink::WebCryptoAlgorithmIdSha1>);
120 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
121 alg_to_info_["A128KW"] =
122 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128);
123 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
124 alg_to_info_["A256KW"] =
125 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256);
126 alg_to_info_["A128GCM"] = JwkAlgorithmInfo(
127 &BindAlgorithmId<webcrypto::CreateAlgorithm,
128 blink::WebCryptoAlgorithmIdAesGcm>, 128);
129 alg_to_info_["A256GCM"] = JwkAlgorithmInfo(
130 &BindAlgorithmId<webcrypto::CreateAlgorithm,
131 blink::WebCryptoAlgorithmIdAesGcm>, 256);
132 alg_to_info_["A128CBC"] = JwkAlgorithmInfo(
133 &BindAlgorithmId<webcrypto::CreateAlgorithm,
134 blink::WebCryptoAlgorithmIdAesCbc>, 128);
135 alg_to_info_["A192CBC"] = JwkAlgorithmInfo(
136 &BindAlgorithmId<webcrypto::CreateAlgorithm,
137 blink::WebCryptoAlgorithmIdAesCbc>, 192);
138 alg_to_info_["A256CBC"] = JwkAlgorithmInfo(
139 &BindAlgorithmId<webcrypto::CreateAlgorithm,
140 blink::WebCryptoAlgorithmIdAesCbc>, 256);
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())
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);
161 JwkAlgorithmInfoMap alg_to_info_;
164 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry =
165 LAZY_INSTANCE_INITIALIZER;
167 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
168 const blink::WebCryptoAlgorithm& alg2) {
169 DCHECK(!alg1.isNull());
170 DCHECK(!alg2.isNull());
171 if (alg1.id() != alg2.id())
174 case blink::WebCryptoAlgorithmIdHmac:
175 case blink::WebCryptoAlgorithmIdRsaOaep:
176 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
177 if (WebCryptoAlgorithmsConsistent(
178 webcrypto::GetInnerHashAlgorithm(alg1),
179 webcrypto::GetInnerHashAlgorithm(alg2))) {
183 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
184 case blink::WebCryptoAlgorithmIdSha1:
185 case blink::WebCryptoAlgorithmIdSha224:
186 case blink::WebCryptoAlgorithmIdSha256:
187 case blink::WebCryptoAlgorithmIdSha384:
188 case blink::WebCryptoAlgorithmIdSha512:
189 case blink::WebCryptoAlgorithmIdAesCbc:
190 case blink::WebCryptoAlgorithmIdAesGcm:
191 case blink::WebCryptoAlgorithmIdAesCtr:
194 NOTREACHED(); // Not a supported algorithm.
200 // Extracts the required string property with key |path| from |dict| and saves
201 // the result to |*result|. If the property does not exist or is not a string,
203 Status GetJwkString(base::DictionaryValue* dict,
204 const std::string& path,
205 std::string* result) {
206 base::Value* value = NULL;
207 if (!dict->Get(path, &value))
208 return Status::ErrorJwkPropertyMissing(path);
209 if (!value->GetAsString(result))
210 return Status::ErrorJwkPropertyWrongType(path, "string");
211 return Status::Success();
214 // Extracts the optional string property with key |path| from |dict| and saves
215 // the result to |*result| if it was found. If the property exists and is not a
216 // string, returns an error. Otherwise returns success, and sets
217 // |*property_exists| if it was found.
218 Status GetOptionalJwkString(base::DictionaryValue* dict,
219 const std::string& path,
221 bool* property_exists) {
222 *property_exists = false;
223 base::Value* value = NULL;
224 if (!dict->Get(path, &value))
225 return Status::Success();
227 if (!value->GetAsString(result))
228 return Status::ErrorJwkPropertyWrongType(path, "string");
230 *property_exists = true;
231 return Status::Success();
234 // Extracts the required string property with key |path| from |dict| and saves
235 // the base64-decoded bytes to |*result|. If the property does not exist or is
236 // not a string, or could not be base64-decoded, returns an error.
237 Status GetJwkBytes(base::DictionaryValue* dict,
238 const std::string& path,
239 std::string* result) {
240 std::string base64_string;
241 Status status = GetJwkString(dict, path, &base64_string);
242 if (status.IsError())
245 if (!webcrypto::Base64DecodeUrlSafe(base64_string, result))
246 return Status::ErrorJwkBase64Decode(path);
248 return Status::Success();
251 // Extracts the optional boolean property with key |path| from |dict| and saves
252 // the result to |*result| if it was found. If the property exists and is not a
253 // boolean, returns an error. Otherwise returns success, and sets
254 // |*property_exists| if it was found.
255 Status GetOptionalJwkBool(base::DictionaryValue* dict,
256 const std::string& path,
258 bool* property_exists) {
259 *property_exists = false;
260 base::Value* value = NULL;
261 if (!dict->Get(path, &value))
262 return Status::Success();
264 if (!value->GetAsBoolean(result))
265 return Status::ErrorJwkPropertyWrongType(path, "boolean");
267 *property_exists = true;
268 return Status::Success();
273 WebCryptoImpl::WebCryptoImpl() {
277 void WebCryptoImpl::encrypt(
278 const blink::WebCryptoAlgorithm& algorithm,
279 const blink::WebCryptoKey& key,
280 const unsigned char* data,
281 unsigned int data_size,
282 blink::WebCryptoResult result) {
283 DCHECK(!algorithm.isNull());
284 blink::WebArrayBuffer buffer;
285 Status status = EncryptInternal(algorithm, key, data, data_size, &buffer);
286 if (status.IsError())
287 CompleteWithError(status, &result);
289 result.completeWithBuffer(buffer);
292 void WebCryptoImpl::decrypt(
293 const blink::WebCryptoAlgorithm& algorithm,
294 const blink::WebCryptoKey& key,
295 const unsigned char* data,
296 unsigned int data_size,
297 blink::WebCryptoResult result) {
298 DCHECK(!algorithm.isNull());
299 blink::WebArrayBuffer buffer;
300 Status status = DecryptInternal(algorithm, key, data, data_size, &buffer);
301 if (status.IsError())
302 CompleteWithError(status, &result);
304 result.completeWithBuffer(buffer);
307 void WebCryptoImpl::digest(
308 const blink::WebCryptoAlgorithm& algorithm,
309 const unsigned char* data,
310 unsigned int data_size,
311 blink::WebCryptoResult result) {
312 DCHECK(!algorithm.isNull());
313 blink::WebArrayBuffer buffer;
314 Status status = DigestInternal(algorithm, data, data_size, &buffer);
315 if (status.IsError())
316 CompleteWithError(status, &result);
318 result.completeWithBuffer(buffer);
321 void WebCryptoImpl::generateKey(
322 const blink::WebCryptoAlgorithm& algorithm,
324 blink::WebCryptoKeyUsageMask usage_mask,
325 blink::WebCryptoResult result) {
326 DCHECK(!algorithm.isNull());
327 if (IsAlgorithmAsymmetric(algorithm)) {
328 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
329 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
330 Status status = GenerateKeyPairInternal(
331 algorithm, extractable, usage_mask, &public_key, &private_key);
332 if (status.IsError()) {
333 CompleteWithError(status, &result);
335 DCHECK(public_key.handle());
336 DCHECK(private_key.handle());
337 DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
338 DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
339 DCHECK_EQ(true, public_key.extractable());
340 DCHECK_EQ(extractable, private_key.extractable());
341 DCHECK_EQ(usage_mask, public_key.usages());
342 DCHECK_EQ(usage_mask, private_key.usages());
343 result.completeWithKeyPair(public_key, private_key);
346 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
347 Status status = GenerateSecretKeyInternal(
348 algorithm, extractable, usage_mask, &key);
349 if (status.IsError()) {
350 CompleteWithError(status, &result);
352 DCHECK(key.handle());
353 DCHECK_EQ(algorithm.id(), key.algorithm().id());
354 DCHECK_EQ(extractable, key.extractable());
355 DCHECK_EQ(usage_mask, key.usages());
356 result.completeWithKey(key);
361 void WebCryptoImpl::importKey(
362 blink::WebCryptoKeyFormat format,
363 const unsigned char* key_data,
364 unsigned int key_data_size,
365 const blink::WebCryptoAlgorithm& algorithm_or_null,
367 blink::WebCryptoKeyUsageMask usage_mask,
368 blink::WebCryptoResult result) {
369 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
370 Status status = Status::Error();
371 if (format == blink::WebCryptoKeyFormatJwk) {
372 status = ImportKeyJwk(key_data,
379 status = ImportKeyInternal(format,
387 if (status.IsError()) {
388 CompleteWithError(status, &result);
390 DCHECK(key.handle());
391 DCHECK(!key.algorithm().isNull());
392 DCHECK_EQ(extractable, key.extractable());
393 result.completeWithKey(key);
397 void WebCryptoImpl::exportKey(
398 blink::WebCryptoKeyFormat format,
399 const blink::WebCryptoKey& key,
400 blink::WebCryptoResult result) {
401 blink::WebArrayBuffer buffer;
402 Status status = ExportKeyInternal(format, key, &buffer);
403 if (status.IsError())
404 CompleteWithError(status, &result);
406 result.completeWithBuffer(buffer);
409 void WebCryptoImpl::sign(
410 const blink::WebCryptoAlgorithm& algorithm,
411 const blink::WebCryptoKey& key,
412 const unsigned char* data,
413 unsigned int data_size,
414 blink::WebCryptoResult result) {
415 DCHECK(!algorithm.isNull());
416 blink::WebArrayBuffer buffer;
417 Status status = SignInternal(algorithm, key, data, data_size, &buffer);
418 if (status.IsError())
419 CompleteWithError(status, &result);
421 result.completeWithBuffer(buffer);
424 void WebCryptoImpl::verifySignature(
425 const blink::WebCryptoAlgorithm& algorithm,
426 const blink::WebCryptoKey& key,
427 const unsigned char* signature,
428 unsigned int signature_size,
429 const unsigned char* data,
430 unsigned int data_size,
431 blink::WebCryptoResult result) {
432 DCHECK(!algorithm.isNull());
433 bool signature_match = false;
434 Status status = VerifySignatureInternal(algorithm,
441 if (status.IsError())
442 CompleteWithError(status, &result);
444 result.completeWithBoolean(signature_match);
447 Status WebCryptoImpl::ImportKeyJwk(
448 const unsigned char* key_data,
449 unsigned int key_data_size,
450 const blink::WebCryptoAlgorithm& algorithm_or_null,
452 blink::WebCryptoKeyUsageMask usage_mask,
453 blink::WebCryptoKey* key) {
455 // The goal of this method is to extract key material and meta data from the
456 // incoming JWK, combine them with the input parameters, and ultimately import
459 // JSON Web Key Format (JWK)
460 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
461 // TODO(padolph): Not all possible values are handled by this code right now
463 // A JWK is a simple JSON dictionary with the following entries
464 // - "kty" (Key Type) Parameter, REQUIRED
465 // - <kty-specific parameters, see below>, REQUIRED
466 // - "use" (Key Use) Parameter, OPTIONAL
467 // - "alg" (Algorithm) Parameter, OPTIONAL
468 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
469 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
470 // (all other entries are ignored)
472 // OPTIONAL here means that this code does not require the entry to be present
473 // in the incoming JWK, because the method input parameters contain similar
474 // information. If the optional JWK entry is present, it will be validated
475 // against the corresponding input parameter for consistency and combined with
476 // it according to rules defined below. A special case is that the method
477 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
478 // value (if present) is used as a fallback.
480 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
481 // values are parsed out and combined with the method input parameters to
482 // build a Web Crypto Key:
483 // Web Crypto Key type <-- (deduced)
484 // Web Crypto Key extractable <-- JWK extractable + input extractable
485 // Web Crypto Key algorithm <-- JWK alg + input algorithm
486 // Web Crypto Key keyUsage <-- JWK use + input usage_mask
487 // Web Crypto Key keying material <-- kty-specific parameters
489 // Values for each JWK entry are case-sensitive and defined in
490 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
491 // Note that not all values specified by JOSE are handled by this code. Only
492 // handled values are listed.
494 // +-------+--------------------------------------------------------------+
495 // | "RSA" | RSA [RFC3447] |
496 // | "oct" | Octet sequence (used to represent symmetric keys) |
497 // +-------+--------------------------------------------------------------+
499 // +-------+--------------------------------------------------------------+
500 // | "enc" | encrypt and decrypt operations |
501 // | "sig" | sign and verify (MAC) operations |
502 // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
503 // +-------+--------------------------------------------------------------+
504 // - extractable (Key Exportability)
505 // +-------+--------------------------------------------------------------+
506 // | true | Key may be exported from the trusted environment |
507 // | false | Key cannot exit the trusted environment |
508 // +-------+--------------------------------------------------------------+
510 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
511 // +--------------+-------------------------------------------------------+
512 // | Digital Signature or MAC Algorithm |
513 // +--------------+-------------------------------------------------------+
514 // | "HS256" | HMAC using SHA-256 hash algorithm |
515 // | "HS384" | HMAC using SHA-384 hash algorithm |
516 // | "HS512" | HMAC using SHA-512 hash algorithm |
517 // | "RS256" | RSASSA using SHA-256 hash algorithm |
518 // | "RS384" | RSASSA using SHA-384 hash algorithm |
519 // | "RS512" | RSASSA using SHA-512 hash algorithm |
520 // +--------------+-------------------------------------------------------|
521 // | Key Management Algorithm |
522 // +--------------+-------------------------------------------------------+
523 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
524 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
525 // | | (OAEP) [RFC3447], with the default parameters |
526 // | | specified by RFC3447 in Section A.2.1 |
527 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
528 // | | [RFC3394] using 128 bit keys |
529 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
530 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
531 // | | 128 bit keys |
532 // | "A256GCM" | AES GCM using 256 bit keys |
533 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
534 // | | padding [NIST.800-38A] [not yet part of JOSE, see |
535 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
536 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
537 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
538 // +--------------+-------------------------------------------------------+
540 // kty-specific parameters
541 // The value of kty determines the type and content of the keying material
542 // carried in the JWK to be imported. Currently only two possibilities are
543 // supported: a raw key or an RSA public key. RSA private keys are not
544 // supported because typical applications seldom need to import a private key,
545 // and the large number of JWK parameters required to describe one.
546 // - kty == "oct" (symmetric or other raw key)
547 // +-------+--------------------------------------------------------------+
548 // | "k" | Contains the value of the symmetric (or other single-valued) |
549 // | | key. It is represented as the base64url encoding of the |
550 // | | octet sequence containing the key value. |
551 // +-------+--------------------------------------------------------------+
552 // - kty == "RSA" (RSA public key)
553 // +-------+--------------------------------------------------------------+
554 // | "n" | Contains the modulus value for the RSA public key. It is |
555 // | | represented as the base64url encoding of the value's |
556 // | | unsigned big endian representation as an octet sequence. |
557 // +-------+--------------------------------------------------------------+
558 // | "e" | Contains the exponent value for the RSA public key. It is |
559 // | | represented as the base64url encoding of the value's |
560 // | | unsigned big endian representation as an octet sequence. |
561 // +-------+--------------------------------------------------------------+
563 // Consistency and conflict resolution
564 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
565 // may be different than the corresponding values inside the JWK. The Web
566 // Crypto spec says that if a JWK value is present but is inconsistent with
567 // the input value, it is an error and the operation must fail. If no
568 // inconsistency is found, the input and JWK values are combined as follows:
571 // If an algorithm is provided by both the input parameter and the JWK,
572 // consistency between the two is based only on algorithm ID's (including an
573 // inner hash algorithm if present). In this case if the consistency
574 // check is passed, the input algorithm is used. If only one of either the
575 // input algorithm and JWK alg is provided, it is used as the final
579 // If the JWK extractable is true but the input parameter is false, make the
580 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
581 // false but the input parameter is true, it is an inconsistency. If both
582 // are true or both are false, use that value.
585 // The input usage_mask must be a strict subset of the interpreted JWK use
586 // value, else it is judged inconsistent. In all cases the input usage_mask
587 // is used as the final usage_mask.
591 return Status::ErrorImportEmptyKeyData();
594 // Parse the incoming JWK JSON.
595 base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
597 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
598 // Note, bare pointer dict_value is ok since it points into scoped value.
599 base::DictionaryValue* dict_value = NULL;
600 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
601 return Status::ErrorJwkNotDictionary();
603 // JWK "kty". Exit early if this required JWK parameter is missing.
604 std::string jwk_kty_value;
605 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value);
606 if (status.IsError())
609 // JWK "extractable" (optional) --> extractable parameter
611 bool jwk_extractable_value = false;
612 bool has_jwk_extractable;
613 status = GetOptionalJwkBool(dict_value,
615 &jwk_extractable_value,
616 &has_jwk_extractable);
617 if (status.IsError())
619 if (has_jwk_extractable && !jwk_extractable_value && extractable)
620 return Status::ErrorJwkExtractableInconsistent();
623 // JWK "alg" (optional) --> algorithm parameter
624 // Note: input algorithm is also optional, so we have six cases to handle.
625 // 1. JWK alg present but unrecognized: error
626 // 2. JWK alg valid AND input algorithm isNull: use JWK value
627 // 3. JWK alg valid AND input algorithm specified, but JWK value
628 // inconsistent with input: error
629 // 4. JWK alg valid AND input algorithm specified, both consistent: use
630 // input value (because it has potentially more details)
631 // 5. JWK alg missing AND input algorithm isNull: error
632 // 6. JWK alg missing AND input algorithm specified: use input value
633 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
634 const JwkAlgorithmInfo* algorithm_info = NULL;
635 std::string jwk_alg_value;
638 GetOptionalJwkString(dict_value, "alg", &jwk_alg_value, &has_jwk_alg);
639 if (status.IsError())
645 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
646 // only be from the RSA family.
648 blink::WebCryptoAlgorithm jwk_algorithm =
649 blink::WebCryptoAlgorithm::createNull();
650 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value);
651 if (!algorithm_info || !algorithm_info->CreateAlgorithm(&jwk_algorithm))
652 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1
655 if (algorithm_or_null.isNull()) {
656 // input algorithm not specified
657 algorithm = jwk_algorithm; // case 2
659 // input algorithm specified
660 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
661 return Status::ErrorJwkAlgorithmInconsistent(); // case 3
662 algorithm = algorithm_or_null; // case 4
666 if (algorithm_or_null.isNull())
667 return Status::ErrorJwkAlgorithmMissing(); // case 5
668 algorithm = algorithm_or_null; // case 6
670 DCHECK(!algorithm.isNull());
672 // JWK "use" (optional) --> usage_mask parameter
673 std::string jwk_use_value;
676 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use);
677 if (status.IsError())
680 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
681 if (jwk_use_value == "enc") {
683 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
684 } else if (jwk_use_value == "sig") {
686 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
687 } else if (jwk_use_value == "wrap") {
689 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
691 return Status::ErrorJwkUnrecognizedUsage();
693 if ((jwk_usage_mask & usage_mask) != usage_mask) {
694 // A usage_mask must be a subset of jwk_usage_mask.
695 return Status::ErrorJwkUsageInconsistent();
699 // JWK keying material --> ImportKeyInternal()
700 if (jwk_kty_value == "oct") {
702 std::string jwk_k_value;
703 status = GetJwkBytes(dict_value, "k", &jwk_k_value);
704 if (status.IsError())
707 // Some JWK alg ID's embed information about the key length in the alg ID
708 // string. For example "A128CBC" implies the JWK carries 128 bits
709 // of key material. For such keys validate that enough bytes were provided.
710 // If this validation is not done, then it would be possible to select a
711 // different algorithm by passing a different lengthed key, since that is
712 // how WebCrypto interprets things.
713 if (algorithm_info &&
714 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) {
715 return Status::ErrorJwkIncorrectKeyLength();
718 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
719 reinterpret_cast<const uint8*>(jwk_k_value.data()),
725 } else if (jwk_kty_value == "RSA") {
727 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
728 // in the JWK, while an RSA private key must have those, plus at least a "d"
729 // (private exponent) entry.
730 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
733 // RSA private key import is not currently supported, so fail here if a "d"
735 // TODO(padolph): Support RSA private key import.
736 if (dict_value->HasKey("d"))
737 return Status::ErrorJwkRsaPrivateKeyUnsupported();
739 std::string jwk_n_value;
740 status = GetJwkBytes(dict_value, "n", &jwk_n_value);
741 if (status.IsError())
743 std::string jwk_e_value;
744 status = GetJwkBytes(dict_value, "e", &jwk_e_value);
745 if (status.IsError())
748 return ImportRsaPublicKeyInternal(
749 reinterpret_cast<const uint8*>(jwk_n_value.data()),
751 reinterpret_cast<const uint8*>(jwk_e_value.data()),
759 return Status::ErrorJwkUnrecognizedKty();
762 return Status::Success();
765 } // namespace content