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. 4 5 #include "content/renderer/webcrypto/webcrypto_impl.h" 6 7 #include <algorithm> 8 #include <functional> 9 #include <map> 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 21 namespace content { 22 23 namespace { 24 25 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { 26 // TODO(padolph): include all other asymmetric algorithms once they are 27 // defined, e.g. EC and DH. 28 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || 29 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || 30 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); 31 } 32 33 // Binds a specific key length value to a compatible factory function. 34 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)( 35 unsigned short); 36 template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length> 37 blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() { 38 return func(key_length); 39 } 40 41 // Binds a WebCryptoAlgorithmId value to a compatible factory function. 42 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)( 43 blink::WebCryptoAlgorithmId); 44 template <AlgFactoryFuncWithWebCryptoAlgIdArg func, 45 blink::WebCryptoAlgorithmId algorithm_id> 46 blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() { 47 return func(algorithm_id); 48 } 49 50 // Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto 51 // factory function. 52 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)(); 53 typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap; 54 55 class JwkAlgorithmFactoryMap { 56 public: 57 JwkAlgorithmFactoryMap() { 58 map_["HS256"] = 59 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen, 60 256>; 61 map_["HS384"] = 62 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen, 63 384>; 64 map_["HS512"] = 65 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen, 66 512>; 67 map_["RS256"] = 68 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, 69 blink::WebCryptoAlgorithmIdSha256>; 70 map_["RS384"] = 71 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, 72 blink::WebCryptoAlgorithmIdSha384>; 73 map_["RS512"] = 74 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm, 75 blink::WebCryptoAlgorithmIdSha512>; 76 map_["RSA1_5"] = 77 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 78 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>; 79 map_["RSA-OAEP"] = 80 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm, 81 blink::WebCryptoAlgorithmIdSha1>; 82 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet 83 map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull; 84 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet 85 map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull; 86 map_["A128GCM"] = 87 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 88 blink::WebCryptoAlgorithmIdAesGcm>; 89 map_["A256GCM"] = 90 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 91 blink::WebCryptoAlgorithmIdAesGcm>; 92 map_["A128CBC"] = 93 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 94 blink::WebCryptoAlgorithmIdAesCbc>; 95 map_["A192CBC"] = 96 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 97 blink::WebCryptoAlgorithmIdAesCbc>; 98 map_["A256CBC"] = 99 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm, 100 blink::WebCryptoAlgorithmIdAesCbc>; 101 } 102 103 blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id) 104 const { 105 const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id); 106 if (pos == map_.end()) 107 return blink::WebCryptoAlgorithm::createNull(); 108 return pos->second(); 109 } 110 111 private: 112 JwkAlgFactoryMap map_; 113 }; 114 115 base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory = 116 LAZY_INSTANCE_INITIALIZER; 117 118 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, 119 const blink::WebCryptoAlgorithm& alg2) { 120 DCHECK(!alg1.isNull()); 121 DCHECK(!alg2.isNull()); 122 if (alg1.id() != alg2.id()) 123 return false; 124 switch (alg1.id()) { 125 case blink::WebCryptoAlgorithmIdHmac: 126 case blink::WebCryptoAlgorithmIdRsaOaep: 127 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 128 if (WebCryptoAlgorithmsConsistent( 129 webcrypto::GetInnerHashAlgorithm(alg1), 130 webcrypto::GetInnerHashAlgorithm(alg2))) { 131 return true; 132 } 133 break; 134 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: 135 case blink::WebCryptoAlgorithmIdSha1: 136 case blink::WebCryptoAlgorithmIdSha224: 137 case blink::WebCryptoAlgorithmIdSha256: 138 case blink::WebCryptoAlgorithmIdSha384: 139 case blink::WebCryptoAlgorithmIdSha512: 140 case blink::WebCryptoAlgorithmIdAesCbc: 141 case blink::WebCryptoAlgorithmIdAesGcm: 142 case blink::WebCryptoAlgorithmIdAesCtr: 143 return true; 144 default: 145 NOTREACHED(); // Not a supported algorithm. 146 break; 147 } 148 return false; 149 } 150 151 bool GetDecodedUrl64ValueByKey( 152 const base::DictionaryValue& dict, 153 const std::string& key, 154 std::string* decoded) { 155 std::string value_url64; 156 if (!dict.GetString(key, &value_url64) || 157 !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) || 158 !decoded->size()) { 159 return false; 160 } 161 return true; 162 } 163 164 } // namespace 165 166 WebCryptoImpl::WebCryptoImpl() { 167 Init(); 168 } 169 170 void WebCryptoImpl::encrypt( 171 const blink::WebCryptoAlgorithm& algorithm, 172 const blink::WebCryptoKey& key, 173 const unsigned char* data, 174 unsigned data_size, 175 blink::WebCryptoResult result) { 176 DCHECK(!algorithm.isNull()); 177 blink::WebArrayBuffer buffer; 178 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) { 179 result.completeWithError(); 180 } else { 181 result.completeWithBuffer(buffer); 182 } 183 } 184 185 void WebCryptoImpl::decrypt( 186 const blink::WebCryptoAlgorithm& algorithm, 187 const blink::WebCryptoKey& key, 188 const unsigned char* data, 189 unsigned data_size, 190 blink::WebCryptoResult result) { 191 DCHECK(!algorithm.isNull()); 192 blink::WebArrayBuffer buffer; 193 if (!DecryptInternal(algorithm, key, data, data_size, &buffer)) { 194 result.completeWithError(); 195 } else { 196 result.completeWithBuffer(buffer); 197 } 198 } 199 200 void WebCryptoImpl::digest( 201 const blink::WebCryptoAlgorithm& algorithm, 202 const unsigned char* data, 203 unsigned data_size, 204 blink::WebCryptoResult result) { 205 DCHECK(!algorithm.isNull()); 206 blink::WebArrayBuffer buffer; 207 if (!DigestInternal(algorithm, data, data_size, &buffer)) { 208 result.completeWithError(); 209 } else { 210 result.completeWithBuffer(buffer); 211 } 212 } 213 214 void WebCryptoImpl::generateKey( 215 const blink::WebCryptoAlgorithm& algorithm, 216 bool extractable, 217 blink::WebCryptoKeyUsageMask usage_mask, 218 blink::WebCryptoResult result) { 219 DCHECK(!algorithm.isNull()); 220 if (IsAlgorithmAsymmetric(algorithm)) { 221 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 222 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 223 if (!GenerateKeyPairInternal( 224 algorithm, extractable, usage_mask, &public_key, &private_key)) { 225 result.completeWithError(); 226 } else { 227 DCHECK(public_key.handle()); 228 DCHECK(private_key.handle()); 229 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); 230 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); 231 DCHECK_EQ(true, public_key.extractable()); 232 DCHECK_EQ(extractable, private_key.extractable()); 233 DCHECK_EQ(usage_mask, public_key.usages()); 234 DCHECK_EQ(usage_mask, private_key.usages()); 235 result.completeWithKeyPair(public_key, private_key); 236 } 237 } else { 238 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 239 if (!GenerateKeyInternal(algorithm, extractable, usage_mask, &key)) { 240 result.completeWithError(); 241 } else { 242 DCHECK(key.handle()); 243 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 244 DCHECK_EQ(extractable, key.extractable()); 245 DCHECK_EQ(usage_mask, key.usages()); 246 result.completeWithKey(key); 247 } 248 } 249 } 250 251 void WebCryptoImpl::importKey( 252 blink::WebCryptoKeyFormat format, 253 const unsigned char* key_data, 254 unsigned key_data_size, 255 const blink::WebCryptoAlgorithm& algorithm_or_null, 256 bool extractable, 257 blink::WebCryptoKeyUsageMask usage_mask, 258 blink::WebCryptoResult result) { 259 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 260 if (format == blink::WebCryptoKeyFormatJwk) { 261 if (!ImportKeyJwk(key_data, 262 key_data_size, 263 algorithm_or_null, 264 extractable, 265 usage_mask, 266 &key)) { 267 result.completeWithError(); 268 return; 269 } 270 } else { 271 if (!ImportKeyInternal(format, 272 key_data, 273 key_data_size, 274 algorithm_or_null, 275 extractable, 276 usage_mask, 277 &key)) { 278 result.completeWithError(); 279 return; 280 } 281 } 282 DCHECK(key.handle()); 283 DCHECK(!key.algorithm().isNull()); 284 DCHECK_EQ(extractable, key.extractable()); 285 result.completeWithKey(key); 286 } 287 288 void WebCryptoImpl::exportKey( 289 blink::WebCryptoKeyFormat format, 290 const blink::WebCryptoKey& key, 291 blink::WebCryptoResult result) { 292 blink::WebArrayBuffer buffer; 293 if (!ExportKeyInternal(format, key, &buffer)) { 294 result.completeWithError(); 295 return; 296 } 297 result.completeWithBuffer(buffer); 298 } 299 300 void WebCryptoImpl::sign( 301 const blink::WebCryptoAlgorithm& algorithm, 302 const blink::WebCryptoKey& key, 303 const unsigned char* data, 304 unsigned data_size, 305 blink::WebCryptoResult result) { 306 DCHECK(!algorithm.isNull()); 307 blink::WebArrayBuffer buffer; 308 if (!SignInternal(algorithm, key, data, data_size, &buffer)) { 309 result.completeWithError(); 310 } else { 311 result.completeWithBuffer(buffer); 312 } 313 } 314 315 void WebCryptoImpl::verifySignature( 316 const blink::WebCryptoAlgorithm& algorithm, 317 const blink::WebCryptoKey& key, 318 const unsigned char* signature, 319 unsigned signature_size, 320 const unsigned char* data, 321 unsigned data_size, 322 blink::WebCryptoResult result) { 323 DCHECK(!algorithm.isNull()); 324 bool signature_match = false; 325 if (!VerifySignatureInternal(algorithm, 326 key, 327 signature, 328 signature_size, 329 data, 330 data_size, 331 &signature_match)) { 332 result.completeWithError(); 333 } else { 334 result.completeWithBoolean(signature_match); 335 } 336 } 337 338 bool WebCryptoImpl::ImportKeyJwk( 339 const unsigned char* key_data, 340 unsigned key_data_size, 341 const blink::WebCryptoAlgorithm& algorithm_or_null, 342 bool extractable, 343 blink::WebCryptoKeyUsageMask usage_mask, 344 blink::WebCryptoKey* key) { 345 346 // The goal of this method is to extract key material and meta data from the 347 // incoming JWK, combine them with the input parameters, and ultimately import 348 // a Web Crypto Key. 349 // 350 // JSON Web Key Format (JWK) 351 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16 352 // TODO(padolph): Not all possible values are handled by this code right now 353 // 354 // A JWK is a simple JSON dictionary with the following entries 355 // - "kty" (Key Type) Parameter, REQUIRED 356 // - <kty-specific parameters, see below>, REQUIRED 357 // - "use" (Key Use) Parameter, OPTIONAL 358 // - "alg" (Algorithm) Parameter, OPTIONAL 359 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE, 360 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796] 361 // (all other entries are ignored) 362 // 363 // OPTIONAL here means that this code does not require the entry to be present 364 // in the incoming JWK, because the method input parameters contain similar 365 // information. If the optional JWK entry is present, it will be validated 366 // against the corresponding input parameter for consistency and combined with 367 // it according to rules defined below. A special case is that the method 368 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg' 369 // value (if present) is used as a fallback. 370 // 371 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK 372 // values are parsed out and combined with the method input parameters to 373 // build a Web Crypto Key: 374 // Web Crypto Key type <-- (deduced) 375 // Web Crypto Key extractable <-- JWK extractable + input extractable 376 // Web Crypto Key algorithm <-- JWK alg + input algorithm 377 // Web Crypto Key keyUsage <-- JWK use + input usage_mask 378 // Web Crypto Key keying material <-- kty-specific parameters 379 // 380 // Values for each JWK entry are case-sensitive and defined in 381 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. 382 // Note that not all values specified by JOSE are handled by this code. Only 383 // handled values are listed. 384 // - kty (Key Type) 385 // +-------+--------------------------------------------------------------+ 386 // | "RSA" | RSA [RFC3447] | 387 // | "oct" | Octet sequence (used to represent symmetric keys) | 388 // +-------+--------------------------------------------------------------+ 389 // - use (Key Use) 390 // +-------+--------------------------------------------------------------+ 391 // | "enc" | encrypt and decrypt operations | 392 // | "sig" | sign and verify (MAC) operations | 393 // | "wrap"| key wrap and unwrap [not yet part of JOSE] | 394 // +-------+--------------------------------------------------------------+ 395 // - extractable (Key Exportability) 396 // +-------+--------------------------------------------------------------+ 397 // | true | Key may be exported from the trusted environment | 398 // | false | Key cannot exit the trusted environment | 399 // +-------+--------------------------------------------------------------+ 400 // - alg (Algorithm) 401 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 402 // +--------------+-------------------------------------------------------+ 403 // | Digital Signature or MAC Algorithm | 404 // +--------------+-------------------------------------------------------+ 405 // | "HS256" | HMAC using SHA-256 hash algorithm | 406 // | "HS384" | HMAC using SHA-384 hash algorithm | 407 // | "HS512" | HMAC using SHA-512 hash algorithm | 408 // | "RS256" | RSASSA using SHA-256 hash algorithm | 409 // | "RS384" | RSASSA using SHA-384 hash algorithm | 410 // | "RS512" | RSASSA using SHA-512 hash algorithm | 411 // +--------------+-------------------------------------------------------| 412 // | Key Management Algorithm | 413 // +--------------+-------------------------------------------------------+ 414 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | 415 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | 416 // | | (OAEP) [RFC3447], with the default parameters | 417 // | | specified by RFC3447 in Section A.2.1 | 418 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | 419 // | | [RFC3394] using 128 bit keys | 420 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | 421 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | 422 // | | 128 bit keys | 423 // | "A256GCM" | AES GCM using 256 bit keys | 424 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | 425 // | | padding [NIST.800-38A] [not yet part of JOSE, see | 426 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 | 427 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] | 428 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | 429 // +--------------+-------------------------------------------------------+ 430 // 431 // kty-specific parameters 432 // The value of kty determines the type and content of the keying material 433 // carried in the JWK to be imported. Currently only two possibilities are 434 // supported: a raw key or an RSA public key. RSA private keys are not 435 // supported because typical applications seldom need to import a private key, 436 // and the large number of JWK parameters required to describe one. 437 // - kty == "oct" (symmetric or other raw key) 438 // +-------+--------------------------------------------------------------+ 439 // | "k" | Contains the value of the symmetric (or other single-valued) | 440 // | | key. It is represented as the base64url encoding of the | 441 // | | octet sequence containing the key value. | 442 // +-------+--------------------------------------------------------------+ 443 // - kty == "RSA" (RSA public key) 444 // +-------+--------------------------------------------------------------+ 445 // | "n" | Contains the modulus value for the RSA public key. It is | 446 // | | represented as the base64url encoding of the value's | 447 // | | unsigned big endian representation as an octet sequence. | 448 // +-------+--------------------------------------------------------------+ 449 // | "e" | Contains the exponent value for the RSA public key. It is | 450 // | | represented as the base64url encoding of the value's | 451 // | | unsigned big endian representation as an octet sequence. | 452 // +-------+--------------------------------------------------------------+ 453 // 454 // Consistency and conflict resolution 455 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters 456 // may be different than the corresponding values inside the JWK. The Web 457 // Crypto spec says that if a JWK value is present but is inconsistent with 458 // the input value, it is an error and the operation must fail. If no 459 // inconsistency is found, the input and JWK values are combined as follows: 460 // 461 // algorithm 462 // If an algorithm is provided by both the input parameter and the JWK, 463 // consistency between the two is based only on algorithm ID's (including an 464 // inner hash algorithm if present). In this case if the consistency 465 // check is passed, the input algorithm is used. If only one of either the 466 // input algorithm and JWK alg is provided, it is used as the final 467 // algorithm. 468 // 469 // extractable 470 // If the JWK extractable is true but the input parameter is false, make the 471 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is 472 // false but the input parameter is true, it is an inconsistency. If both 473 // are true or both are false, use that value. 474 // 475 // usage_mask 476 // The input usage_mask must be a strict subset of the interpreted JWK use 477 // value, else it is judged inconsistent. In all cases the input usage_mask 478 // is used as the final usage_mask. 479 // 480 481 if (!key_data_size) 482 return false; 483 DCHECK(key); 484 485 // Parse the incoming JWK JSON. 486 base::StringPiece json_string(reinterpret_cast<const char*>(key_data), 487 key_data_size); 488 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); 489 // Note, bare pointer dict_value is ok since it points into scoped value. 490 base::DictionaryValue* dict_value = NULL; 491 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) 492 return false; 493 494 // JWK "kty". Exit early if this required JWK parameter is missing. 495 std::string jwk_kty_value; 496 if (!dict_value->GetString("kty", &jwk_kty_value)) 497 return false; 498 499 // JWK "extractable" (optional) --> extractable parameter 500 { 501 bool jwk_extractable_value; 502 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) { 503 if (!jwk_extractable_value && extractable) 504 return false; 505 extractable = extractable && jwk_extractable_value; 506 } 507 } 508 509 // JWK "alg" (optional) --> algorithm parameter 510 // Note: input algorithm is also optional, so we have six cases to handle. 511 // 1. JWK alg present but unrecognized: error 512 // 2. JWK alg valid AND input algorithm isNull: use JWK value 513 // 3. JWK alg valid AND input algorithm specified, but JWK value 514 // inconsistent with input: error 515 // 4. JWK alg valid AND input algorithm specified, both consistent: use 516 // input value (because it has potentially more details) 517 // 5. JWK alg missing AND input algorithm isNull: error 518 // 6. JWK alg missing AND input algorithm specified: use input value 519 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); 520 std::string jwk_alg_value; 521 if (dict_value->GetString("alg", &jwk_alg_value)) { 522 // JWK alg present 523 524 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can 525 // only be from the RSA family. 526 527 const blink::WebCryptoAlgorithm jwk_algorithm = 528 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value); 529 if (jwk_algorithm.isNull()) { 530 // JWK alg unrecognized 531 return false; // case 1 532 } 533 // JWK alg valid 534 if (algorithm_or_null.isNull()) { 535 // input algorithm not specified 536 algorithm = jwk_algorithm; // case 2 537 } else { 538 // input algorithm specified 539 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) 540 return false; // case 3 541 algorithm = algorithm_or_null; // case 4 542 } 543 } else { 544 // JWK alg missing 545 if (algorithm_or_null.isNull()) 546 return false; // case 5 547 algorithm = algorithm_or_null; // case 6 548 } 549 DCHECK(!algorithm.isNull()); 550 551 // JWK "use" (optional) --> usage_mask parameter 552 std::string jwk_use_value; 553 if (dict_value->GetString("use", &jwk_use_value)) { 554 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0; 555 if (jwk_use_value == "enc") { 556 jwk_usage_mask = 557 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; 558 } else if (jwk_use_value == "sig") { 559 jwk_usage_mask = 560 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; 561 } else if (jwk_use_value == "wrap") { 562 jwk_usage_mask = 563 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; 564 } else { 565 return false; 566 } 567 if ((jwk_usage_mask & usage_mask) != usage_mask) { 568 // A usage_mask must be a subset of jwk_usage_mask. 569 return false; 570 } 571 } 572 573 // JWK keying material --> ImportKeyInternal() 574 if (jwk_kty_value == "oct") { 575 576 std::string jwk_k_value; 577 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value)) 578 return false; 579 580 // TODO(padolph): Some JWK alg ID's embed information about the key length 581 // in the alg ID string. For example "A128" implies the JWK carries 128 bits 582 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits 583 // of key material. For such keys validate the actual key length against the 584 // value in the ID. 585 586 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw, 587 reinterpret_cast<const uint8*>(jwk_k_value.data()), 588 jwk_k_value.size(), 589 algorithm, 590 extractable, 591 usage_mask, 592 key); 593 } else if (jwk_kty_value == "RSA") { 594 595 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry 596 // in the JWK, while an RSA private key must have those, plus at least a "d" 597 // (private exponent) entry. 598 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, 599 // section 6.3. 600 601 // RSA private key import is not currently supported, so fail here if a "d" 602 // entry is found. 603 // TODO(padolph): Support RSA private key import. 604 if (dict_value->HasKey("d")) 605 return false; 606 607 std::string jwk_n_value; 608 if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value)) 609 return false; 610 std::string jwk_e_value; 611 if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value)) 612 return false; 613 614 return ImportRsaPublicKeyInternal( 615 reinterpret_cast<const uint8*>(jwk_n_value.data()), 616 jwk_n_value.size(), 617 reinterpret_cast<const uint8*>(jwk_e_value.data()), 618 jwk_e_value.size(), 619 algorithm, 620 extractable, 621 usage_mask, 622 key); 623 624 } else { 625 return false; 626 } 627 628 return true; 629 } 630 631 } // namespace content 632