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 "content/child/webcrypto/shared_crypto.h" 6 7 #include "base/logging.h" 8 #include "content/child/webcrypto/crypto_data.h" 9 #include "content/child/webcrypto/jwk.h" 10 #include "content/child/webcrypto/platform_crypto.h" 11 #include "content/child/webcrypto/status.h" 12 #include "content/child/webcrypto/webcrypto_util.h" 13 #include "crypto/secure_util.h" 14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" 15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 16 #include "third_party/WebKit/public/platform/WebCryptoKey.h" 17 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 18 19 namespace content { 20 21 namespace webcrypto { 22 23 // ------------ 24 // Threading: 25 // ------------ 26 // 27 // All functions in this file are called from the webcrypto worker pool except 28 // for: 29 // 30 // * SerializeKeyForClone() 31 // * DeserializeKeyForClone() 32 // * ImportKey() // TODO(eroman): Change this. 33 34 namespace { 35 36 // TODO(eroman): Move this helper to WebCryptoKey. 37 bool KeyUsageAllows(const blink::WebCryptoKey& key, 38 const blink::WebCryptoKeyUsage usage) { 39 return ((key.usages() & usage) != 0); 40 } 41 42 bool IsValidAesKeyLengthBits(unsigned int length_bits) { 43 // 192-bit AES is disallowed. 44 return length_bits == 128 || length_bits == 256; 45 } 46 47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) { 48 // 192-bit AES is disallowed. 49 return length_bytes == 16 || length_bytes == 32; 50 } 51 52 const size_t kAesBlockSizeBytes = 16; 53 54 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, 55 const blink::WebCryptoAlgorithm& algorithm, 56 const blink::WebCryptoKey& key, 57 const CryptoData& data, 58 std::vector<uint8>* buffer) { 59 platform::SymKey* sym_key; 60 Status status = ToPlatformSymKey(key, &sym_key); 61 if (status.IsError()) 62 return status; 63 64 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); 65 if (!params) 66 return Status::ErrorUnexpected(); 67 68 CryptoData iv(params->iv().data(), params->iv().size()); 69 if (iv.byte_length() != kAesBlockSizeBytes) 70 return Status::ErrorIncorrectSizeAesCbcIv(); 71 72 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer); 73 } 74 75 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, 76 const blink::WebCryptoAlgorithm& algorithm, 77 const blink::WebCryptoKey& key, 78 const CryptoData& data, 79 std::vector<uint8>* buffer) { 80 platform::SymKey* sym_key; 81 Status status = ToPlatformSymKey(key, &sym_key); 82 if (status.IsError()) 83 return status; 84 85 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); 86 if (!params) 87 return Status::ErrorUnexpected(); 88 89 unsigned int tag_length_bits = 128; 90 if (params->hasTagLengthBits()) 91 tag_length_bits = params->optionalTagLengthBits(); 92 93 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 && 94 tag_length_bits != 104 && tag_length_bits != 112 && 95 tag_length_bits != 120 && tag_length_bits != 128) 96 return Status::ErrorInvalidAesGcmTagLength(); 97 98 return platform::EncryptDecryptAesGcm( 99 mode, 100 sym_key, 101 data, 102 CryptoData(params->iv()), 103 CryptoData(params->optionalAdditionalData()), 104 tag_length_bits, 105 buffer); 106 } 107 108 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, 109 const blink::WebCryptoKey& key, 110 const CryptoData& data, 111 std::vector<uint8>* buffer) { 112 platform::PublicKey* public_key; 113 Status status = ToPlatformPublicKey(key, &public_key); 114 if (status.IsError()) 115 return status; 116 117 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); 118 if (!params) 119 return Status::ErrorUnexpected(); 120 121 return platform::EncryptRsaOaep(public_key, 122 key.algorithm().rsaHashedParams()->hash(), 123 CryptoData(params->optionalLabel()), 124 data, 125 buffer); 126 } 127 128 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, 129 const blink::WebCryptoKey& key, 130 const CryptoData& data, 131 std::vector<uint8>* buffer) { 132 platform::PrivateKey* private_key; 133 Status status = ToPlatformPrivateKey(key, &private_key); 134 if (status.IsError()) 135 return status; 136 137 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); 138 if (!params) 139 return Status::ErrorUnexpected(); 140 141 return platform::DecryptRsaOaep(private_key, 142 key.algorithm().rsaHashedParams()->hash(), 143 CryptoData(params->optionalLabel()), 144 data, 145 buffer); 146 } 147 148 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm, 149 const blink::WebCryptoKey& key, 150 const CryptoData& data, 151 std::vector<uint8>* buffer) { 152 platform::SymKey* sym_key; 153 Status status = ToPlatformSymKey(key, &sym_key); 154 if (status.IsError()) 155 return status; 156 157 return platform::SignHmac( 158 sym_key, key.algorithm().hmacParams()->hash(), data, buffer); 159 } 160 161 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm, 162 const blink::WebCryptoKey& key, 163 const CryptoData& signature, 164 const CryptoData& data, 165 bool* signature_match) { 166 std::vector<uint8> result; 167 Status status = SignHmac(algorithm, key, data, &result); 168 if (status.IsError()) 169 return status; 170 171 // Do not allow verification of truncated MACs. 172 *signature_match = 173 result.size() == signature.byte_length() && 174 crypto::SecureMemEqual( 175 Uint8VectorStart(result), signature.bytes(), signature.byte_length()); 176 177 return Status::Success(); 178 } 179 180 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, 181 const blink::WebCryptoKey& key, 182 const CryptoData& data, 183 std::vector<uint8>* buffer) { 184 platform::PrivateKey* private_key; 185 Status status = ToPlatformPrivateKey(key, &private_key); 186 if (status.IsError()) 187 return status; 188 189 return platform::SignRsaSsaPkcs1v1_5( 190 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer); 191 } 192 193 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, 194 const blink::WebCryptoKey& key, 195 const CryptoData& signature, 196 const CryptoData& data, 197 bool* signature_match) { 198 platform::PublicKey* public_key; 199 Status status = ToPlatformPublicKey(key, &public_key); 200 if (status.IsError()) 201 return status; 202 203 return platform::VerifyRsaSsaPkcs1v1_5( 204 public_key, 205 key.algorithm().rsaHashedParams()->hash(), 206 signature, 207 data, 208 signature_match); 209 } 210 211 // Note that this function may be called from the target Blink thread. 212 Status ImportKeyRaw(const CryptoData& key_data, 213 const blink::WebCryptoAlgorithm& algorithm, 214 bool extractable, 215 blink::WebCryptoKeyUsageMask usage_mask, 216 blink::WebCryptoKey* key) { 217 switch (algorithm.id()) { 218 case blink::WebCryptoAlgorithmIdAesCtr: 219 case blink::WebCryptoAlgorithmIdAesCbc: 220 case blink::WebCryptoAlgorithmIdAesGcm: 221 case blink::WebCryptoAlgorithmIdAesKw: 222 if (!IsValidAesKeyLengthBytes(key_data.byte_length())) { 223 return key_data.byte_length() == 24 224 ? Status::ErrorAes192BitUnsupported() 225 : Status::ErrorImportAesKeyLength(); 226 } 227 // Fallthrough intentional! 228 case blink::WebCryptoAlgorithmIdHmac: 229 return platform::ImportKeyRaw( 230 algorithm, key_data, extractable, usage_mask, key); 231 default: 232 return Status::ErrorUnsupported(); 233 } 234 } 235 236 // Returns the key format to use for structured cloning. 237 blink::WebCryptoKeyFormat GetCloneFormatForKeyType( 238 blink::WebCryptoKeyType type) { 239 switch (type) { 240 case blink::WebCryptoKeyTypeSecret: 241 return blink::WebCryptoKeyFormatRaw; 242 case blink::WebCryptoKeyTypePublic: 243 return blink::WebCryptoKeyFormatSpki; 244 case blink::WebCryptoKeyTypePrivate: 245 return blink::WebCryptoKeyFormatPkcs8; 246 } 247 248 NOTREACHED(); 249 return blink::WebCryptoKeyFormatRaw; 250 } 251 252 // Converts a KeyAlgorithm into an equivalent Algorithm for import. 253 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( 254 const blink::WebCryptoKeyAlgorithm& algorithm) { 255 switch (algorithm.paramsType()) { 256 case blink::WebCryptoKeyAlgorithmParamsTypeAes: 257 return CreateAlgorithm(algorithm.id()); 258 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: 259 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); 260 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: 261 return CreateRsaHashedImportAlgorithm( 262 algorithm.id(), algorithm.rsaHashedParams()->hash().id()); 263 case blink::WebCryptoKeyAlgorithmParamsTypeNone: 264 break; 265 default: 266 break; 267 } 268 return blink::WebCryptoAlgorithm::createNull(); 269 } 270 271 // There is some duplicated information in the serialized format used by 272 // structured clone (since the KeyAlgorithm is serialized separately from the 273 // key data). Use this extra information to further validate what was 274 // deserialized from the key data. 275 // 276 // A failure here implies either a bug in the code, or that the serialized data 277 // was corrupted. 278 bool ValidateDeserializedKey(const blink::WebCryptoKey& key, 279 const blink::WebCryptoKeyAlgorithm& algorithm, 280 blink::WebCryptoKeyType type) { 281 if (algorithm.id() != key.algorithm().id()) 282 return false; 283 284 if (key.type() != type) 285 return false; 286 287 switch (algorithm.paramsType()) { 288 case blink::WebCryptoKeyAlgorithmParamsTypeAes: 289 if (algorithm.aesParams()->lengthBits() != 290 key.algorithm().aesParams()->lengthBits()) 291 return false; 292 break; 293 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: 294 if (algorithm.rsaHashedParams()->modulusLengthBits() != 295 key.algorithm().rsaHashedParams()->modulusLengthBits()) 296 return false; 297 if (algorithm.rsaHashedParams()->publicExponent().size() != 298 key.algorithm().rsaHashedParams()->publicExponent().size()) 299 return false; 300 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(), 301 key.algorithm().rsaHashedParams()->publicExponent().data(), 302 key.algorithm().rsaHashedParams()->publicExponent().size()) != 303 0) 304 return false; 305 break; 306 case blink::WebCryptoKeyAlgorithmParamsTypeNone: 307 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: 308 break; 309 default: 310 return false; 311 } 312 313 return true; 314 } 315 316 Status EncryptDecryptAesKw(EncryptOrDecrypt mode, 317 const blink::WebCryptoAlgorithm& algorithm, 318 const blink::WebCryptoKey& key, 319 const CryptoData& data, 320 std::vector<uint8>* buffer) { 321 platform::SymKey* sym_key; 322 Status status = ToPlatformSymKey(key, &sym_key); 323 if (status.IsError()) 324 return status; 325 326 unsigned int min_length = mode == ENCRYPT ? 16 : 24; 327 328 if (data.byte_length() < min_length) 329 return Status::ErrorDataTooSmall(); 330 if (data.byte_length() % 8) 331 return Status::ErrorInvalidAesKwDataLength(); 332 333 if (status.IsError()) 334 return status; 335 return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer); 336 } 337 338 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, 339 const blink::WebCryptoKey& key, 340 const CryptoData& data, 341 std::vector<uint8>* buffer) { 342 if (algorithm.id() != key.algorithm().id()) 343 return Status::ErrorUnexpected(); 344 switch (algorithm.id()) { 345 case blink::WebCryptoAlgorithmIdAesCbc: 346 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); 347 case blink::WebCryptoAlgorithmIdAesGcm: 348 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); 349 case blink::WebCryptoAlgorithmIdRsaOaep: 350 return DecryptRsaOaep(algorithm, key, data, buffer); 351 case blink::WebCryptoAlgorithmIdAesKw: 352 return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer); 353 default: 354 return Status::ErrorUnsupported(); 355 } 356 } 357 358 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, 359 const blink::WebCryptoKey& key, 360 const CryptoData& data, 361 std::vector<uint8>* buffer) { 362 if (algorithm.id() != key.algorithm().id()) 363 return Status::ErrorUnexpected(); 364 switch (algorithm.id()) { 365 case blink::WebCryptoAlgorithmIdAesCbc: 366 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); 367 case blink::WebCryptoAlgorithmIdAesGcm: 368 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); 369 case blink::WebCryptoAlgorithmIdAesKw: 370 return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer); 371 case blink::WebCryptoAlgorithmIdRsaOaep: 372 return EncryptRsaOaep(algorithm, key, data, buffer); 373 default: 374 return Status::ErrorUnsupported(); 375 } 376 } 377 378 Status UnwrapKeyDecryptAndImport( 379 blink::WebCryptoKeyFormat format, 380 const CryptoData& wrapped_key_data, 381 const blink::WebCryptoKey& wrapping_key, 382 const blink::WebCryptoAlgorithm& wrapping_algorithm, 383 const blink::WebCryptoAlgorithm& algorithm, 384 bool extractable, 385 blink::WebCryptoKeyUsageMask usage_mask, 386 blink::WebCryptoKey* key) { 387 std::vector<uint8> buffer; 388 Status status = DecryptDontCheckKeyUsage( 389 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); 390 if (status.IsError()) 391 return status; 392 // NOTE that returning the details of ImportKey() failures may leak 393 // information about the plaintext of the encrypted key (for instance the JWK 394 // key_ops). As long as the ImportKey error messages don't describe actual 395 // key bytes however this should be OK. For more discussion see 396 // http://crubg.com/372040 397 return ImportKey( 398 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); 399 } 400 401 Status WrapKeyExportAndEncrypt( 402 blink::WebCryptoKeyFormat format, 403 const blink::WebCryptoKey& key_to_wrap, 404 const blink::WebCryptoKey& wrapping_key, 405 const blink::WebCryptoAlgorithm& wrapping_algorithm, 406 std::vector<uint8>* buffer) { 407 std::vector<uint8> exported_data; 408 Status status = ExportKey(format, key_to_wrap, &exported_data); 409 if (status.IsError()) 410 return status; 411 return EncryptDontCheckUsage( 412 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); 413 } 414 415 // Returns the internal block size for SHA-* 416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { 417 switch (hash_id) { 418 case blink::WebCryptoAlgorithmIdSha1: 419 case blink::WebCryptoAlgorithmIdSha256: 420 return 64; 421 case blink::WebCryptoAlgorithmIdSha384: 422 case blink::WebCryptoAlgorithmIdSha512: 423 return 128; 424 default: 425 NOTREACHED(); 426 return 0; 427 } 428 } 429 430 // Returns the mask of all key usages that are possible for |algorithm| and 431 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make 432 // sense, then returns 0 (no usages). 433 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType( 434 blink::WebCryptoAlgorithmId algorithm, 435 blink::WebCryptoKeyType key_type) { 436 if (IsAlgorithmAsymmetric(algorithm) == 437 (key_type == blink::WebCryptoKeyTypeSecret)) 438 return 0; 439 440 switch (algorithm) { 441 case blink::WebCryptoAlgorithmIdAesCbc: 442 case blink::WebCryptoAlgorithmIdAesGcm: 443 case blink::WebCryptoAlgorithmIdAesCtr: 444 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | 445 blink::WebCryptoKeyUsageWrapKey | 446 blink::WebCryptoKeyUsageUnwrapKey; 447 case blink::WebCryptoAlgorithmIdAesKw: 448 return blink::WebCryptoKeyUsageWrapKey | 449 blink::WebCryptoKeyUsageUnwrapKey; 450 case blink::WebCryptoAlgorithmIdHmac: 451 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; 452 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 453 switch (key_type) { 454 case blink::WebCryptoKeyTypePublic: 455 return blink::WebCryptoKeyUsageVerify; 456 case blink::WebCryptoKeyTypePrivate: 457 return blink::WebCryptoKeyUsageSign; 458 default: 459 return 0; 460 } 461 case blink::WebCryptoAlgorithmIdRsaOaep: 462 switch (key_type) { 463 case blink::WebCryptoKeyTypePublic: 464 return blink::WebCryptoKeyUsageEncrypt | 465 blink::WebCryptoKeyUsageWrapKey; 466 case blink::WebCryptoKeyTypePrivate: 467 return blink::WebCryptoKeyUsageDecrypt | 468 blink::WebCryptoKeyUsageUnwrapKey; 469 default: 470 return 0; 471 } 472 default: 473 return 0; 474 } 475 } 476 477 // Returns Status::Success() if |usages| is a valid set of key usages for 478 // |algorithm| and |key_type|. Otherwise returns an error. 479 // In the case of JWK format the check is incomplete for asymmetric algorithms. 480 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm, 481 blink::WebCryptoKeyFormat format, 482 blink::WebCryptoKeyUsageMask usages) { 483 if (!IsAlgorithmAsymmetric(algorithm)) 484 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages); 485 486 // Try to infer the key type given the import format. 487 blink::WebCryptoKeyType key_type; 488 bool key_type_known = false; 489 490 switch (format) { 491 case blink::WebCryptoKeyFormatRaw: 492 // TODO(eroman): The spec defines Diffie-Hellman raw import for public 493 // keys, so this will need to be updated in the future when DH is 494 // implemented. 495 return Status::ErrorUnexpected(); 496 case blink::WebCryptoKeyFormatSpki: 497 key_type = blink::WebCryptoKeyTypePublic; 498 key_type_known = true; 499 break; 500 case blink::WebCryptoKeyFormatPkcs8: 501 key_type = blink::WebCryptoKeyTypePrivate; 502 key_type_known = true; 503 break; 504 case blink::WebCryptoKeyFormatJwk: 505 key_type_known = false; 506 break; 507 default: 508 return Status::ErrorUnexpected(); 509 } 510 511 if (key_type_known) 512 return CheckKeyUsages(algorithm, key_type, usages); 513 514 // If the key type is not known, then the algorithm is asymmetric. Whether the 515 // key data describes a public or private key isn't known yet. But it must at 516 // least be ONE of those two. 517 DCHECK(IsAlgorithmAsymmetric(algorithm)); 518 519 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages) 520 .IsError() && 521 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages) 522 .IsError()) { 523 return Status::ErrorCreateKeyBadUsages(); 524 } 525 526 return Status::Success(); 527 } 528 529 // Returns an error if |combined_usage_mask| is invalid for generating a key 530 // pair for |algorithm|. Otherwise returns Status::Success(), and fills 531 // |public_key_usages| with the usages for the public key, and 532 // |private_key_usages| with those for the private key. 533 Status CheckKeyUsagesForGenerateKeyPair( 534 blink::WebCryptoAlgorithmId algorithm, 535 blink::WebCryptoKeyUsageMask combined_usage_mask, 536 blink::WebCryptoKeyUsageMask* public_key_usages, 537 blink::WebCryptoKeyUsageMask* private_key_usages) { 538 DCHECK(IsAlgorithmAsymmetric(algorithm)); 539 540 blink::WebCryptoKeyUsageMask all_public_key_usages = 541 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic); 542 blink::WebCryptoKeyUsageMask all_private_key_usages = 543 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate); 544 545 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages, 546 combined_usage_mask)) 547 return Status::ErrorCreateKeyBadUsages(); 548 549 *public_key_usages = combined_usage_mask & all_public_key_usages; 550 *private_key_usages = combined_usage_mask & all_private_key_usages; 551 552 return Status::Success(); 553 } 554 555 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, 556 // to unsigned long. 557 bool BigIntegerToLong(const uint8* data, 558 unsigned int data_size, 559 unsigned long* result) { 560 // TODO(padolph): Is it correct to say that empty data is an error, or does it 561 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655 562 if (data_size == 0) 563 return false; 564 565 *result = 0; 566 for (size_t i = 0; i < data_size; ++i) { 567 size_t reverse_i = data_size - i - 1; 568 569 if (reverse_i >= sizeof(unsigned long) && data[i]) 570 return false; // Too large for a long. 571 572 *result |= data[i] << 8 * reverse_i; 573 } 574 return true; 575 } 576 577 578 } // namespace 579 580 void Init() { platform::Init(); } 581 582 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 583 const blink::WebCryptoKey& key, 584 const CryptoData& data, 585 std::vector<uint8>* buffer) { 586 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 587 return Status::ErrorUnexpected(); 588 return EncryptDontCheckUsage(algorithm, key, data, buffer); 589 } 590 591 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 592 const blink::WebCryptoKey& key, 593 const CryptoData& data, 594 std::vector<uint8>* buffer) { 595 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) 596 return Status::ErrorUnexpected(); 597 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); 598 } 599 600 Status Digest(const blink::WebCryptoAlgorithm& algorithm, 601 const CryptoData& data, 602 std::vector<uint8>* buffer) { 603 switch (algorithm.id()) { 604 case blink::WebCryptoAlgorithmIdSha1: 605 case blink::WebCryptoAlgorithmIdSha256: 606 case blink::WebCryptoAlgorithmIdSha384: 607 case blink::WebCryptoAlgorithmIdSha512: 608 return platform::DigestSha(algorithm.id(), data, buffer); 609 default: 610 return Status::ErrorUnsupported(); 611 } 612 } 613 614 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( 615 blink::WebCryptoAlgorithmId algorithm) { 616 return platform::CreateDigestor(algorithm); 617 } 618 619 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, 620 bool extractable, 621 blink::WebCryptoKeyUsageMask usage_mask, 622 blink::WebCryptoKey* key) { 623 Status status = 624 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask); 625 if (status.IsError()) 626 return status; 627 628 unsigned int keylen_bytes = 0; 629 630 // Get the secret key length in bytes from generation parameters. 631 // This resolves any defaults. 632 switch (algorithm.id()) { 633 case blink::WebCryptoAlgorithmIdAesCbc: 634 case blink::WebCryptoAlgorithmIdAesGcm: 635 case blink::WebCryptoAlgorithmIdAesKw: { 636 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) { 637 return algorithm.aesKeyGenParams()->lengthBits() == 192 638 ? Status::ErrorAes192BitUnsupported() 639 : Status::ErrorGenerateKeyLength(); 640 } 641 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8; 642 break; 643 } 644 case blink::WebCryptoAlgorithmIdHmac: { 645 const blink::WebCryptoHmacKeyGenParams* params = 646 algorithm.hmacKeyGenParams(); 647 DCHECK(params); 648 if (params->hasLengthBits()) { 649 if (params->optionalLengthBits() % 8) 650 return Status::ErrorGenerateKeyLength(); 651 keylen_bytes = params->optionalLengthBits() / 8; 652 } else { 653 keylen_bytes = ShaBlockSizeBytes(params->hash().id()); 654 if (keylen_bytes == 0) 655 return Status::ErrorUnsupported(); 656 } 657 break; 658 } 659 660 default: 661 return Status::ErrorUnsupported(); 662 } 663 664 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should 665 // probably be able to allowed to generate them too. 666 if (keylen_bytes == 0) 667 return Status::ErrorGenerateKeyLength(); 668 669 return platform::GenerateSecretKey( 670 algorithm, extractable, usage_mask, keylen_bytes, key); 671 } 672 673 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, 674 bool extractable, 675 blink::WebCryptoKeyUsageMask combined_usage_mask, 676 blink::WebCryptoKey* public_key, 677 blink::WebCryptoKey* private_key) { 678 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0; 679 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0; 680 681 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(), 682 combined_usage_mask, 683 &public_key_usage_mask, 684 &private_key_usage_mask); 685 if (status.IsError()) 686 return status; 687 688 // TODO(padolph): Handle other asymmetric algorithm key generation. 689 switch (algorithm.paramsType()) { 690 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: { 691 const blink::WebCryptoRsaHashedKeyGenParams* params = 692 algorithm.rsaHashedKeyGenParams(); 693 694 if (!params->modulusLengthBits()) 695 return Status::ErrorGenerateRsaZeroModulus(); 696 697 unsigned long public_exponent = 0; 698 if (!BigIntegerToLong(params->publicExponent().data(), 699 params->publicExponent().size(), 700 &public_exponent) || 701 (public_exponent != 3 && public_exponent != 65537)) { 702 return Status::ErrorGenerateKeyPublicExponent(); 703 } 704 705 return platform::GenerateRsaKeyPair(algorithm, 706 extractable, 707 public_key_usage_mask, 708 private_key_usage_mask, 709 params->modulusLengthBits(), 710 public_exponent, 711 public_key, 712 private_key); 713 } 714 default: 715 return Status::ErrorUnsupported(); 716 } 717 } 718 719 // Note that this function may be called from the target Blink thread. 720 Status ImportKey(blink::WebCryptoKeyFormat format, 721 const CryptoData& key_data, 722 const blink::WebCryptoAlgorithm& algorithm, 723 bool extractable, 724 blink::WebCryptoKeyUsageMask usage_mask, 725 blink::WebCryptoKey* key) { 726 // This is "best effort" because it is incomplete for JWK (for which the key 727 // type is not yet known). ImportKeyJwk() does extra checks on key usage once 728 // the key type has been determined. 729 Status status = 730 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); 731 if (status.IsError()) 732 return status; 733 734 switch (format) { 735 case blink::WebCryptoKeyFormatRaw: 736 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key); 737 case blink::WebCryptoKeyFormatSpki: 738 return platform::ImportKeySpki( 739 algorithm, key_data, extractable, usage_mask, key); 740 case blink::WebCryptoKeyFormatPkcs8: 741 return platform::ImportKeyPkcs8( 742 algorithm, key_data, extractable, usage_mask, key); 743 case blink::WebCryptoKeyFormatJwk: 744 return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key); 745 default: 746 return Status::ErrorUnsupported(); 747 } 748 } 749 750 // TODO(eroman): Move this to anonymous namespace. 751 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, 752 const blink::WebCryptoKey& key, 753 std::vector<uint8>* buffer) { 754 switch (format) { 755 case blink::WebCryptoKeyFormatRaw: { 756 platform::SymKey* sym_key; 757 Status status = ToPlatformSymKey(key, &sym_key); 758 if (status.IsError()) 759 return status; 760 return platform::ExportKeyRaw(sym_key, buffer); 761 } 762 case blink::WebCryptoKeyFormatSpki: { 763 platform::PublicKey* public_key; 764 Status status = ToPlatformPublicKey(key, &public_key); 765 if (status.IsError()) 766 return status; 767 return platform::ExportKeySpki(public_key, buffer); 768 } 769 case blink::WebCryptoKeyFormatPkcs8: { 770 platform::PrivateKey* private_key; 771 Status status = ToPlatformPrivateKey(key, &private_key); 772 if (status.IsError()) 773 return status; 774 return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer); 775 } 776 case blink::WebCryptoKeyFormatJwk: 777 return ExportKeyJwk(key, buffer); 778 default: 779 return Status::ErrorUnsupported(); 780 } 781 } 782 783 Status ExportKey(blink::WebCryptoKeyFormat format, 784 const blink::WebCryptoKey& key, 785 std::vector<uint8>* buffer) { 786 if (!key.extractable()) 787 return Status::ErrorKeyNotExtractable(); 788 return ExportKeyDontCheckExtractability(format, key, buffer); 789 } 790 791 Status Sign(const blink::WebCryptoAlgorithm& algorithm, 792 const blink::WebCryptoKey& key, 793 const CryptoData& data, 794 std::vector<uint8>* buffer) { 795 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) 796 return Status::ErrorUnexpected(); 797 if (algorithm.id() != key.algorithm().id()) 798 return Status::ErrorUnexpected(); 799 800 switch (algorithm.id()) { 801 case blink::WebCryptoAlgorithmIdHmac: 802 return SignHmac(algorithm, key, data, buffer); 803 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 804 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer); 805 default: 806 return Status::ErrorUnsupported(); 807 } 808 } 809 810 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm, 811 const blink::WebCryptoKey& key, 812 const CryptoData& signature, 813 const CryptoData& data, 814 bool* signature_match) { 815 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) 816 return Status::ErrorUnexpected(); 817 if (algorithm.id() != key.algorithm().id()) 818 return Status::ErrorUnexpected(); 819 820 if (!signature.byte_length()) { 821 // None of the algorithms generate valid zero-length signatures so this 822 // will necessarily fail verification. Early return to protect 823 // implementations from dealing with a NULL signature pointer. 824 *signature_match = false; 825 return Status::Success(); 826 } 827 828 switch (algorithm.id()) { 829 case blink::WebCryptoAlgorithmIdHmac: 830 return VerifyHmac(algorithm, key, signature, data, signature_match); 831 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: 832 return VerifyRsaSsaPkcs1v1_5( 833 algorithm, key, signature, data, signature_match); 834 default: 835 return Status::ErrorUnsupported(); 836 } 837 } 838 839 Status WrapKey(blink::WebCryptoKeyFormat format, 840 const blink::WebCryptoKey& key_to_wrap, 841 const blink::WebCryptoKey& wrapping_key, 842 const blink::WebCryptoAlgorithm& wrapping_algorithm, 843 std::vector<uint8>* buffer) { 844 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) 845 return Status::ErrorUnexpected(); 846 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 847 return Status::ErrorUnexpected(); 848 849 return WrapKeyExportAndEncrypt( 850 format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer); 851 } 852 853 Status UnwrapKey(blink::WebCryptoKeyFormat format, 854 const CryptoData& wrapped_key_data, 855 const blink::WebCryptoKey& wrapping_key, 856 const blink::WebCryptoAlgorithm& wrapping_algorithm, 857 const blink::WebCryptoAlgorithm& algorithm, 858 bool extractable, 859 blink::WebCryptoKeyUsageMask usage_mask, 860 blink::WebCryptoKey* key) { 861 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 862 return Status::ErrorUnexpected(); 863 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 864 return Status::ErrorUnexpected(); 865 866 // Fail-fast if the key usages don't make sense. This avoids decrypting the 867 // key only to then have import fail. It is "best effort" because when 868 // unwrapping JWK for asymmetric algorithms the key type isn't known yet. 869 Status status = 870 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); 871 if (status.IsError()) 872 return status; 873 874 return UnwrapKeyDecryptAndImport(format, 875 wrapped_key_data, 876 wrapping_key, 877 wrapping_algorithm, 878 algorithm, 879 extractable, 880 usage_mask, 881 key); 882 } 883 884 // Note that this function is called from the target Blink thread. 885 bool SerializeKeyForClone(const blink::WebCryptoKey& key, 886 blink::WebVector<uint8>* key_data) { 887 return static_cast<webcrypto::platform::Key*>(key.handle()) 888 ->ThreadSafeSerializeForClone(key_data); 889 } 890 891 // Note that this function is called from the target Blink thread. 892 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, 893 blink::WebCryptoKeyType type, 894 bool extractable, 895 blink::WebCryptoKeyUsageMask usage_mask, 896 const CryptoData& key_data, 897 blink::WebCryptoKey* key) { 898 // TODO(eroman): This should not call into the platform crypto layer. 899 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks 900 // are held. 901 // 902 // An alternate approach is to defer the key import until the key is used. 903 // However this means that any deserialization errors would have to be 904 // surfaced as WebCrypto errors, leading to slightly different behaviors. For 905 // instance you could clone a key which fails to be deserialized. 906 Status status = ImportKey(GetCloneFormatForKeyType(type), 907 key_data, 908 KeyAlgorithmToImportAlgorithm(algorithm), 909 extractable, 910 usage_mask, 911 key); 912 if (status.IsError()) 913 return false; 914 return ValidateDeserializedKey(*key, algorithm, type); 915 } 916 917 Status ToPlatformSymKey(const blink::WebCryptoKey& key, 918 platform::SymKey** out) { 919 *out = static_cast<platform::Key*>(key.handle())->AsSymKey(); 920 if (!*out) 921 return Status::ErrorUnexpectedKeyType(); 922 return Status::Success(); 923 } 924 925 Status ToPlatformPublicKey(const blink::WebCryptoKey& key, 926 platform::PublicKey** out) { 927 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey(); 928 if (!*out) 929 return Status::ErrorUnexpectedKeyType(); 930 return Status::Success(); 931 } 932 933 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key, 934 platform::PrivateKey** out) { 935 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey(); 936 if (!*out) 937 return Status::ErrorUnexpectedKeyType(); 938 return Status::Success(); 939 } 940 941 // Returns Status::Success() if |usages| is a valid set of key usages for 942 // |algorithm| and |key_type|. Otherwise returns an error. 943 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm, 944 blink::WebCryptoKeyType key_type, 945 blink::WebCryptoKeyUsageMask usages) { 946 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type), 947 usages)) 948 return Status::ErrorCreateKeyBadUsages(); 949 950 return Status::Success(); 951 } 952 953 } // namespace webcrypto 954 955 } // namespace content 956