OLD | NEW |
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/nss/rsa_key_nss.h" | 5 #include "content/child/webcrypto/nss/rsa_key_nss.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/nss/key_nss.h" | 10 #include "content/child/webcrypto/nss/key_nss.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 } | 48 } |
49 | 49 |
50 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | 50 bool CreatePrivateKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, |
51 SECKEYPrivateKey* key, | 51 SECKEYPrivateKey* key, |
52 blink::WebCryptoKeyAlgorithm* key_algorithm) { | 52 blink::WebCryptoKeyAlgorithm* key_algorithm) { |
53 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); | 53 crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key)); |
54 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); | 54 return CreatePublicKeyAlgorithm(algorithm, public_key.get(), key_algorithm); |
55 } | 55 } |
56 | 56 |
57 #if defined(USE_NSS) && !defined(OS_CHROMEOS) | 57 #if defined(USE_NSS) && !defined(OS_CHROMEOS) |
58 Status ErrorRsaKeyImportNotSupported() { | 58 Status ErrorRsaPrivateKeyImportNotSupported() { |
59 return Status::ErrorUnsupported( | 59 return Status::ErrorUnsupported( |
60 "NSS version must be at least 3.16.2 for RSA key import. See " | 60 "NSS version must be at least 3.16.2 for RSA private key import. See " |
61 "http://crbug.com/380424"); | 61 "http://crbug.com/380424"); |
62 } | 62 } |
63 | 63 |
64 // Prior to NSS 3.16.2 RSA key parameters were not validated. This is | 64 // Prior to NSS 3.16.2 RSA key parameters were not validated. This is |
65 // a security problem for RSA private key import from JWK which uses a | 65 // a security problem for RSA private key import from JWK which uses a |
66 // CKA_ID based on the public modulus to retrieve the private key. | 66 // CKA_ID based on the public modulus to retrieve the private key. |
67 Status NssSupportsRsaKeyImport() { | 67 Status NssSupportsRsaPrivateKeyImport() { |
68 if (!NSS_VersionCheck("3.16.2")) | 68 if (!NSS_VersionCheck("3.16.2")) |
69 return ErrorRsaKeyImportNotSupported(); | 69 return ErrorRsaPrivateKeyImportNotSupported(); |
70 | 70 |
71 // Also ensure that the version of Softoken is 3.16.2 or later. | 71 // Also ensure that the version of Softoken is 3.16.2 or later. |
72 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 72 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
73 CK_SLOT_INFO info = {}; | 73 CK_SLOT_INFO info = {}; |
74 if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess) | 74 if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess) |
75 return ErrorRsaKeyImportNotSupported(); | 75 return ErrorRsaPrivateKeyImportNotSupported(); |
76 | 76 |
77 // CK_SLOT_INFO.hardwareVersion contains the major.minor | 77 // CK_SLOT_INFO.hardwareVersion contains the major.minor |
78 // version info for Softoken in the corresponding .major/.minor | 78 // version info for Softoken in the corresponding .major/.minor |
79 // fields, and .firmwareVersion contains the patch.build | 79 // fields, and .firmwareVersion contains the patch.build |
80 // version info (in the .major/.minor fields) | 80 // version info (in the .major/.minor fields) |
81 if ((info.hardwareVersion.major > 3) || | 81 if ((info.hardwareVersion.major > 3) || |
82 (info.hardwareVersion.major == 3 && | 82 (info.hardwareVersion.major == 3 && |
83 (info.hardwareVersion.minor > 16 || | 83 (info.hardwareVersion.minor > 16 || |
84 (info.hardwareVersion.minor == 16 && | 84 (info.hardwareVersion.minor == 16 && |
85 info.firmwareVersion.major >= 2)))) { | 85 info.firmwareVersion.major >= 2)))) { |
86 return Status::Success(); | 86 return Status::Success(); |
87 } | 87 } |
88 | 88 |
89 return ErrorRsaKeyImportNotSupported(); | 89 return ErrorRsaPrivateKeyImportNotSupported(); |
90 } | 90 } |
91 #else | 91 #else |
92 Status NssSupportsRsaKeyImport() { | 92 Status NssSupportsRsaPrivateKeyImport() { |
93 return Status::Success(); | 93 return Status::Success(); |
94 } | 94 } |
95 #endif | 95 #endif |
96 | 96 |
97 bool CreateRsaHashedPublicKeyAlgorithm( | 97 bool CreateRsaHashedPublicKeyAlgorithm( |
98 const blink::WebCryptoAlgorithm& algorithm, | 98 const blink::WebCryptoAlgorithm& algorithm, |
99 SECKEYPublicKey* key, | 99 SECKEYPublicKey* key, |
100 blink::WebCryptoKeyAlgorithm* key_algorithm) { | 100 blink::WebCryptoKeyAlgorithm* key_algorithm) { |
101 // TODO(eroman): What about other key types rsaPss, rsaOaep. | 101 // TODO(eroman): What about other key types rsaPss, rsaOaep. |
102 if (!key || key->keyType != rsaKey) | 102 if (!key || key->keyType != rsaKey) |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 | 339 |
340 buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len); | 340 buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len); |
341 return Status::Success(); | 341 return Status::Success(); |
342 } | 342 } |
343 | 343 |
344 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, | 344 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, |
345 bool extractable, | 345 bool extractable, |
346 blink::WebCryptoKeyUsageMask usage_mask, | 346 blink::WebCryptoKeyUsageMask usage_mask, |
347 const JwkRsaInfo& params, | 347 const JwkRsaInfo& params, |
348 blink::WebCryptoKey* key) { | 348 blink::WebCryptoKey* key) { |
349 Status status = NssSupportsRsaKeyImport(); | 349 Status status = NssSupportsRsaPrivateKeyImport(); |
350 if (status.IsError()) | 350 if (status.IsError()) |
351 return status; | 351 return status; |
352 | 352 |
353 CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY; | 353 CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY; |
354 CK_KEY_TYPE key_type = CKK_RSA; | 354 CK_KEY_TYPE key_type = CKK_RSA; |
355 CK_BBOOL ck_false = CK_FALSE; | 355 CK_BBOOL ck_false = CK_FALSE; |
356 | 356 |
357 std::vector<CK_ATTRIBUTE> key_template; | 357 std::vector<CK_ATTRIBUTE> key_template; |
358 | 358 |
359 AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template); | 359 AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template); |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 return Status::ErrorUnsupportedImportKeyFormat(); | 642 return Status::ErrorUnsupportedImportKeyFormat(); |
643 } | 643 } |
644 } | 644 } |
645 | 645 |
646 Status RsaHashedAlgorithm::ImportKeyPkcs8( | 646 Status RsaHashedAlgorithm::ImportKeyPkcs8( |
647 const CryptoData& key_data, | 647 const CryptoData& key_data, |
648 const blink::WebCryptoAlgorithm& algorithm, | 648 const blink::WebCryptoAlgorithm& algorithm, |
649 bool extractable, | 649 bool extractable, |
650 blink::WebCryptoKeyUsageMask usage_mask, | 650 blink::WebCryptoKeyUsageMask usage_mask, |
651 blink::WebCryptoKey* key) const { | 651 blink::WebCryptoKey* key) const { |
652 Status status = NssSupportsRsaKeyImport(); | 652 Status status = NssSupportsRsaPrivateKeyImport(); |
653 if (status.IsError()) | 653 if (status.IsError()) |
654 return status; | 654 return status; |
655 | 655 |
656 if (!key_data.byte_length()) | 656 if (!key_data.byte_length()) |
657 return Status::ErrorImportEmptyKeyData(); | 657 return Status::ErrorImportEmptyKeyData(); |
658 | 658 |
659 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 | 659 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 |
660 // private key info object. | 660 // private key info object. |
661 SECItem pki_der = MakeSECItemForBuffer(key_data); | 661 SECItem pki_der = MakeSECItemForBuffer(key_data); |
662 | 662 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
702 | 702 |
703 return Status::Success(); | 703 return Status::Success(); |
704 } | 704 } |
705 | 705 |
706 Status RsaHashedAlgorithm::ImportKeySpki( | 706 Status RsaHashedAlgorithm::ImportKeySpki( |
707 const CryptoData& key_data, | 707 const CryptoData& key_data, |
708 const blink::WebCryptoAlgorithm& algorithm, | 708 const blink::WebCryptoAlgorithm& algorithm, |
709 bool extractable, | 709 bool extractable, |
710 blink::WebCryptoKeyUsageMask usage_mask, | 710 blink::WebCryptoKeyUsageMask usage_mask, |
711 blink::WebCryptoKey* key) const { | 711 blink::WebCryptoKey* key) const { |
712 Status status = NssSupportsRsaKeyImport(); | |
713 if (status.IsError()) | |
714 return status; | |
715 | |
716 if (!key_data.byte_length()) | 712 if (!key_data.byte_length()) |
717 return Status::ErrorImportEmptyKeyData(); | 713 return Status::ErrorImportEmptyKeyData(); |
718 | 714 |
719 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject | 715 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject |
720 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. | 716 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. |
721 SECItem spki_item = MakeSECItemForBuffer(key_data); | 717 SECItem spki_item = MakeSECItemForBuffer(key_data); |
722 const ScopedCERTSubjectPublicKeyInfo spki( | 718 const ScopedCERTSubjectPublicKeyInfo spki( |
723 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); | 719 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); |
724 if (!spki) | 720 if (!spki) |
725 return Status::DataError(); | 721 return Status::DataError(); |
726 | 722 |
727 crypto::ScopedSECKEYPublicKey sec_public_key( | 723 crypto::ScopedSECKEYPublicKey sec_public_key( |
728 SECKEY_ExtractPublicKey(spki.get())); | 724 SECKEY_ExtractPublicKey(spki.get())); |
729 if (!sec_public_key) | 725 if (!sec_public_key) |
730 return Status::DataError(); | 726 return Status::DataError(); |
731 | 727 |
732 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); | 728 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); |
733 if (sec_key_type != rsaKey) | 729 if (sec_key_type != rsaKey) |
734 return Status::DataError(); | 730 return Status::DataError(); |
735 | 731 |
736 blink::WebCryptoKeyAlgorithm key_algorithm; | 732 blink::WebCryptoKeyAlgorithm key_algorithm; |
737 if (!CreateRsaHashedPublicKeyAlgorithm( | 733 if (!CreateRsaHashedPublicKeyAlgorithm( |
738 algorithm, sec_public_key.get(), &key_algorithm)) | 734 algorithm, sec_public_key.get(), &key_algorithm)) |
739 return Status::ErrorUnexpected(); | 735 return Status::ErrorUnexpected(); |
740 | 736 |
741 // TODO(eroman): This is probably going to be the same as the input. | 737 // TODO(eroman): This is probably going to be the same as the input. |
742 std::vector<uint8_t> spki_data; | 738 std::vector<uint8_t> spki_data; |
743 status = ExportKeySpkiNss(sec_public_key.get(), &spki_data); | 739 Status status = ExportKeySpkiNss(sec_public_key.get(), &spki_data); |
744 if (status.IsError()) | 740 if (status.IsError()) |
745 return status; | 741 return status; |
746 | 742 |
747 scoped_ptr<PublicKeyNss> key_handle( | 743 scoped_ptr<PublicKeyNss> key_handle( |
748 new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data))); | 744 new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data))); |
749 | 745 |
750 *key = blink::WebCryptoKey::create(key_handle.release(), | 746 *key = blink::WebCryptoKey::create(key_handle.release(), |
751 blink::WebCryptoKeyTypePublic, | 747 blink::WebCryptoKeyTypePublic, |
752 extractable, | 748 extractable, |
753 key_algorithm, | 749 key_algorithm, |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 return Status::Success(); | 851 return Status::Success(); |
856 } | 852 } |
857 default: | 853 default: |
858 return Status::ErrorUnexpected(); | 854 return Status::ErrorUnexpected(); |
859 } | 855 } |
860 } | 856 } |
861 | 857 |
862 } // namespace webcrypto | 858 } // namespace webcrypto |
863 | 859 |
864 } // namespace content | 860 } // namespace content |
OLD | NEW |