Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(109)

Side by Side Diff: content/child/webcrypto/shared_crypto.cc

Issue 282133002: [webcryto] Validate key usages during key creation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase on master Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/webcrypto/shared_crypto.h" 5 #include "content/child/webcrypto/shared_crypto.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "content/child/webcrypto/crypto_data.h" 8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/jwk.h" 9 #include "content/child/webcrypto/jwk.h"
10 #include "content/child/webcrypto/platform_crypto.h" 10 #include "content/child/webcrypto/platform_crypto.h"
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 const blink::WebCryptoAlgorithm& wrapping_algorithm, 431 const blink::WebCryptoAlgorithm& wrapping_algorithm,
432 const blink::WebCryptoAlgorithm& algorithm, 432 const blink::WebCryptoAlgorithm& algorithm,
433 bool extractable, 433 bool extractable,
434 blink::WebCryptoKeyUsageMask usage_mask, 434 blink::WebCryptoKeyUsageMask usage_mask,
435 blink::WebCryptoKey* key) { 435 blink::WebCryptoKey* key) {
436 std::vector<uint8> buffer; 436 std::vector<uint8> buffer;
437 Status status = DecryptDontCheckKeyUsage( 437 Status status = DecryptDontCheckKeyUsage(
438 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); 438 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
439 if (status.IsError()) 439 if (status.IsError())
440 return status; 440 return status;
441 status = ImportKey( 441 // NOTE that returning the details of ImportKey() failures may leak
442 // information about the plaintext of the encrypted key (for instance the JWK
443 // key_ops). As long as the ImportKey error messages don't describe actual
444 // key bytes however this should be OK. For more discussion see
445 // http://crubg.com/372040
446 return ImportKey(
442 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); 447 format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
443 // NOTE! Returning the details of any ImportKey() failure here would leak
444 // information about the plaintext internals of the encrypted key. Instead,
445 // collapse any error into the generic Status::OperationError().
446 return status.IsError() ? Status::OperationError() : Status::Success();
447 } 448 }
448 449
449 Status WrapKeyExportAndEncrypt( 450 Status WrapKeyExportAndEncrypt(
450 blink::WebCryptoKeyFormat format, 451 blink::WebCryptoKeyFormat format,
451 const blink::WebCryptoKey& key_to_wrap, 452 const blink::WebCryptoKey& key_to_wrap,
452 const blink::WebCryptoKey& wrapping_key, 453 const blink::WebCryptoKey& wrapping_key,
453 const blink::WebCryptoAlgorithm& wrapping_algorithm, 454 const blink::WebCryptoAlgorithm& wrapping_algorithm,
454 std::vector<uint8>* buffer) { 455 std::vector<uint8>* buffer) {
455 std::vector<uint8> exported_data; 456 std::vector<uint8> exported_data;
456 Status status = ExportKey(format, key_to_wrap, &exported_data); 457 Status status = ExportKey(format, key_to_wrap, &exported_data);
(...skipping 11 matching lines...) Expand all
468 return 64; 469 return 64;
469 case blink::WebCryptoAlgorithmIdSha384: 470 case blink::WebCryptoAlgorithmIdSha384:
470 case blink::WebCryptoAlgorithmIdSha512: 471 case blink::WebCryptoAlgorithmIdSha512:
471 return 128; 472 return 128;
472 default: 473 default:
473 NOTREACHED(); 474 NOTREACHED();
474 return 0; 475 return 0;
475 } 476 }
476 } 477 }
477 478
479 // Returns the mask of all key usages that are possible for |algorithm| and
480 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make
481 // sense, then returns 0 (no usages).
482 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType(
483 blink::WebCryptoAlgorithmId algorithm,
484 blink::WebCryptoKeyType key_type) {
485 if (IsAlgorithmAsymmetric(algorithm) ==
486 (key_type == blink::WebCryptoKeyTypeSecret))
487 return 0;
488
489 switch (algorithm) {
490 case blink::WebCryptoAlgorithmIdAesCbc:
491 case blink::WebCryptoAlgorithmIdAesGcm:
492 case blink::WebCryptoAlgorithmIdAesCtr:
493 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
494 blink::WebCryptoKeyUsageWrapKey |
495 blink::WebCryptoKeyUsageUnwrapKey;
496 case blink::WebCryptoAlgorithmIdAesKw:
497 return blink::WebCryptoKeyUsageWrapKey |
498 blink::WebCryptoKeyUsageUnwrapKey;
499 case blink::WebCryptoAlgorithmIdHmac:
500 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
501 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
502 switch (key_type) {
503 case blink::WebCryptoKeyTypePublic:
504 return blink::WebCryptoKeyUsageVerify;
505 case blink::WebCryptoKeyTypePrivate:
506 return blink::WebCryptoKeyUsageSign;
507 default:
508 return 0;
509 }
510 case blink::WebCryptoAlgorithmIdRsaOaep:
511 switch (key_type) {
512 case blink::WebCryptoKeyTypePublic:
513 return blink::WebCryptoKeyUsageEncrypt |
514 blink::WebCryptoKeyUsageWrapKey;
515 case blink::WebCryptoKeyTypePrivate:
516 return blink::WebCryptoKeyUsageDecrypt |
517 blink::WebCryptoKeyUsageUnwrapKey;
518 default:
519 return 0;
520 }
521 default:
522 return 0;
523 }
524 }
525
526 // Returns Status::Success() if |usages| is a valid set of key usages for
527 // |algorithm| and |key_type|. Otherwise returns an error.
528 // In the case of JWK format the check is incomplete for asymmetric algorithms.
529 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm,
530 blink::WebCryptoKeyFormat format,
531 blink::WebCryptoKeyUsageMask usages) {
532 if (!IsAlgorithmAsymmetric(algorithm))
533 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages);
534
535 // Try to infer the key type given the import format.
536 blink::WebCryptoKeyType key_type;
537 bool key_type_known = false;
538
539 switch (format) {
540 case blink::WebCryptoKeyFormatRaw:
541 // TODO(eroman): The spec defines Diffie-Hellman raw import for public
542 // keys, so this will need to be updated in the future when DH is
543 // implemented.
544 return Status::ErrorUnexpected();
545 case blink::WebCryptoKeyFormatSpki:
546 key_type = blink::WebCryptoKeyTypePublic;
547 key_type_known = true;
548 break;
549 case blink::WebCryptoKeyFormatPkcs8:
550 key_type = blink::WebCryptoKeyTypePrivate;
551 key_type_known = true;
552 break;
553 case blink::WebCryptoKeyFormatJwk:
554 key_type_known = false;
555 break;
556 default:
557 return Status::ErrorUnexpected();
558 }
559
560 if (key_type_known)
561 return CheckKeyUsages(algorithm, key_type, usages);
562
563 // If the key type is not known, then the algorithm is asymmetric. Whether the
564 // key data describes a public or private key isn't known yet. But it must at
565 // least be ONE of those two.
566 DCHECK(IsAlgorithmAsymmetric(algorithm));
567
568 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages)
569 .IsError() &&
570 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages)
571 .IsError()) {
572 return Status::ErrorCreateKeyBadUsages();
573 }
574
575 return Status::Success();
576 }
577
578 // Returns an error if |combined_usage_mask| is invalid for generating a key
579 // pair for |algorithm|. Otherwise returns Status::Success(), and fills
580 // |public_key_usages| with the usages for the public key, and
581 // |private_key_usages| with those for the private key.
582 Status CheckKeyUsagesForGenerateKeyPair(
583 blink::WebCryptoAlgorithmId algorithm,
584 blink::WebCryptoKeyUsageMask combined_usage_mask,
585 blink::WebCryptoKeyUsageMask* public_key_usages,
586 blink::WebCryptoKeyUsageMask* private_key_usages) {
587 DCHECK(IsAlgorithmAsymmetric(algorithm));
588
589 blink::WebCryptoKeyUsageMask all_public_key_usages =
590 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic);
591 blink::WebCryptoKeyUsageMask all_private_key_usages =
592 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate);
593
594 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages,
595 combined_usage_mask))
596 return Status::ErrorCreateKeyBadUsages();
597
598 *public_key_usages = combined_usage_mask & all_public_key_usages;
599 *private_key_usages = combined_usage_mask & all_private_key_usages;
600
601 return Status::Success();
602 }
603
478 } // namespace 604 } // namespace
479 605
480 void Init() { platform::Init(); } 606 void Init() { platform::Init(); }
481 607
482 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 608 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
483 const blink::WebCryptoKey& key, 609 const blink::WebCryptoKey& key,
484 const CryptoData& data, 610 const CryptoData& data,
485 std::vector<uint8>* buffer) { 611 std::vector<uint8>* buffer) {
486 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 612 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
487 return Status::ErrorUnexpected(); 613 return Status::ErrorUnexpected();
(...skipping 25 matching lines...) Expand all
513 639
514 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( 640 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
515 blink::WebCryptoAlgorithmId algorithm) { 641 blink::WebCryptoAlgorithmId algorithm) {
516 return platform::CreateDigestor(algorithm); 642 return platform::CreateDigestor(algorithm);
517 } 643 }
518 644
519 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, 645 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
520 bool extractable, 646 bool extractable,
521 blink::WebCryptoKeyUsageMask usage_mask, 647 blink::WebCryptoKeyUsageMask usage_mask,
522 blink::WebCryptoKey* key) { 648 blink::WebCryptoKey* key) {
649 Status status =
650 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask);
651 if (status.IsError())
652 return status;
653
523 unsigned int keylen_bytes = 0; 654 unsigned int keylen_bytes = 0;
524 655
525 // Get the secret key length in bytes from generation parameters. 656 // Get the secret key length in bytes from generation parameters.
526 // This resolves any defaults. 657 // This resolves any defaults.
527 switch (algorithm.id()) { 658 switch (algorithm.id()) {
528 case blink::WebCryptoAlgorithmIdAesCbc: 659 case blink::WebCryptoAlgorithmIdAesCbc:
529 case blink::WebCryptoAlgorithmIdAesGcm: 660 case blink::WebCryptoAlgorithmIdAesGcm:
530 case blink::WebCryptoAlgorithmIdAesKw: { 661 case blink::WebCryptoAlgorithmIdAesKw: {
531 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) 662 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits()))
532 return Status::ErrorGenerateKeyLength(); 663 return Status::ErrorGenerateKeyLength();
(...skipping 24 matching lines...) Expand all
557 // probably be able to allowed to generate them too. 688 // probably be able to allowed to generate them too.
558 if (keylen_bytes == 0) 689 if (keylen_bytes == 0)
559 return Status::ErrorGenerateKeyLength(); 690 return Status::ErrorGenerateKeyLength();
560 691
561 return platform::GenerateSecretKey( 692 return platform::GenerateSecretKey(
562 algorithm, extractable, usage_mask, keylen_bytes, key); 693 algorithm, extractable, usage_mask, keylen_bytes, key);
563 } 694 }
564 695
565 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, 696 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
566 bool extractable, 697 bool extractable,
567 blink::WebCryptoKeyUsageMask usage_mask, 698 blink::WebCryptoKeyUsageMask combined_usage_mask,
568 blink::WebCryptoKey* public_key, 699 blink::WebCryptoKey* public_key,
569 blink::WebCryptoKey* private_key) { 700 blink::WebCryptoKey* private_key) {
701 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0;
702 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0;
703
704 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(),
705 combined_usage_mask,
706 &public_key_usage_mask,
707 &private_key_usage_mask);
708 if (status.IsError())
709 return status;
710
570 // TODO(padolph): Handle other asymmetric algorithm key generation. 711 // TODO(padolph): Handle other asymmetric algorithm key generation.
571 switch (algorithm.paramsType()) { 712 switch (algorithm.paramsType()) {
572 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: { 713 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: {
573 const blink::WebCryptoRsaHashedKeyGenParams* params = 714 const blink::WebCryptoRsaHashedKeyGenParams* params =
574 algorithm.rsaHashedKeyGenParams(); 715 algorithm.rsaHashedKeyGenParams();
575 716
576 if (!params->modulusLengthBits()) 717 if (!params->modulusLengthBits())
577 return Status::ErrorGenerateRsaZeroModulus(); 718 return Status::ErrorGenerateRsaZeroModulus();
578 719
579 CryptoData publicExponent(params->publicExponent()); 720 CryptoData publicExponent(params->publicExponent());
580 if (!publicExponent.byte_length()) 721 if (!publicExponent.byte_length())
581 return Status::ErrorGenerateKeyPublicExponent(); 722 return Status::ErrorGenerateKeyPublicExponent();
582 723
583 return platform::GenerateRsaKeyPair(algorithm, 724 return platform::GenerateRsaKeyPair(algorithm,
584 extractable, 725 extractable,
585 usage_mask, 726 public_key_usage_mask,
727 private_key_usage_mask,
586 params->modulusLengthBits(), 728 params->modulusLengthBits(),
587 publicExponent, 729 publicExponent,
588 public_key, 730 public_key,
589 private_key); 731 private_key);
590 } 732 }
591 default: 733 default:
592 return Status::ErrorUnsupported(); 734 return Status::ErrorUnsupported();
593 } 735 }
594 } 736 }
595 737
596 // Note that this function may be called from the target Blink thread. 738 // Note that this function may be called from the target Blink thread.
597 Status ImportKey(blink::WebCryptoKeyFormat format, 739 Status ImportKey(blink::WebCryptoKeyFormat format,
598 const CryptoData& key_data, 740 const CryptoData& key_data,
599 const blink::WebCryptoAlgorithm& algorithm, 741 const blink::WebCryptoAlgorithm& algorithm,
600 bool extractable, 742 bool extractable,
601 blink::WebCryptoKeyUsageMask usage_mask, 743 blink::WebCryptoKeyUsageMask usage_mask,
602 blink::WebCryptoKey* key) { 744 blink::WebCryptoKey* key) {
745 // This is "best effort" because it is incomplete for JWK (for which the key
746 // type is not yet known). ImportKeyJwk() does extra checks on key usage once
747 // the key type has been determined.
748 Status status =
749 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
750 if (status.IsError())
751 return status;
752
603 switch (format) { 753 switch (format) {
604 case blink::WebCryptoKeyFormatRaw: 754 case blink::WebCryptoKeyFormatRaw:
605 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key); 755 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key);
606 case blink::WebCryptoKeyFormatSpki: 756 case blink::WebCryptoKeyFormatSpki:
607 return platform::ImportKeySpki( 757 return platform::ImportKeySpki(
608 algorithm, key_data, extractable, usage_mask, key); 758 algorithm, key_data, extractable, usage_mask, key);
609 case blink::WebCryptoKeyFormatPkcs8: 759 case blink::WebCryptoKeyFormatPkcs8:
610 return platform::ImportKeyPkcs8( 760 return platform::ImportKeyPkcs8(
611 algorithm, key_data, extractable, usage_mask, key); 761 algorithm, key_data, extractable, usage_mask, key);
612 case blink::WebCryptoKeyFormatJwk: 762 case blink::WebCryptoKeyFormatJwk:
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 const blink::WebCryptoAlgorithm& wrapping_algorithm, 893 const blink::WebCryptoAlgorithm& wrapping_algorithm,
744 const blink::WebCryptoAlgorithm& algorithm, 894 const blink::WebCryptoAlgorithm& algorithm,
745 bool extractable, 895 bool extractable,
746 blink::WebCryptoKeyUsageMask usage_mask, 896 blink::WebCryptoKeyUsageMask usage_mask,
747 blink::WebCryptoKey* key) { 897 blink::WebCryptoKey* key) {
748 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 898 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
749 return Status::ErrorUnexpected(); 899 return Status::ErrorUnexpected();
750 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 900 if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
751 return Status::ErrorUnexpected(); 901 return Status::ErrorUnexpected();
752 902
903 // Fail-fast if the key usages don't make sense. This avoids decrypting the
904 // key only to then have import fail. It is "best effort" because when
905 // unwrapping JWK for asymmetric algorithms the key type isn't known yet.
906 Status status =
907 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
908 if (status.IsError())
909 return status;
910
753 switch (format) { 911 switch (format) {
754 case blink::WebCryptoKeyFormatRaw: 912 case blink::WebCryptoKeyFormatRaw:
755 if (wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { 913 if (wrapping_algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
756 // AES-KW is a special case, due to NSS's implementation only 914 // AES-KW is a special case, due to NSS's implementation only
757 // supporting C_Wrap/C_Unwrap with AES-KW 915 // supporting C_Wrap/C_Unwrap with AES-KW
758 return UnwrapKeyRaw(wrapped_key_data, 916 return UnwrapKeyRaw(wrapped_key_data,
759 wrapping_key, 917 wrapping_key,
760 wrapping_algorithm, 918 wrapping_algorithm,
761 algorithm, 919 algorithm,
762 extractable, 920 extractable,
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
839 } 997 }
840 998
841 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key, 999 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
842 platform::PrivateKey** out) { 1000 platform::PrivateKey** out) {
843 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey(); 1001 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
844 if (!*out) 1002 if (!*out)
845 return Status::ErrorUnexpectedKeyType(); 1003 return Status::ErrorUnexpectedKeyType();
846 return Status::Success(); 1004 return Status::Success();
847 } 1005 }
848 1006
1007 // Returns Status::Success() if |usages| is a valid set of key usages for
1008 // |algorithm| and |key_type|. Otherwise returns an error.
1009 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm,
1010 blink::WebCryptoKeyType key_type,
1011 blink::WebCryptoKeyUsageMask usages) {
1012 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type),
1013 usages))
1014 return Status::ErrorCreateKeyBadUsages();
1015
1016 return Status::Success();
1017 }
1018
849 } // namespace webcrypto 1019 } // namespace webcrypto
850 1020
851 } // namespace content 1021 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/shared_crypto.h ('k') | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698