 Chromium Code Reviews
 Chromium Code Reviews Issue 308523003:
  [webcrypto] Fix a bug with JWK private key import.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 308523003:
  [webcrypto] Fix a bug with JWK private key import.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| 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/platform_crypto.h" | 5 #include "content/child/webcrypto/platform_crypto.h" | 
| 6 | 6 | 
| 7 #include <cryptohi.h> | 7 #include <cryptohi.h> | 
| 8 #include <pk11pub.h> | 8 #include <pk11pub.h> | 
| 9 #include <secerr.h> | 9 #include <secerr.h> | 
| 10 #include <sechash.h> | 10 #include <sechash.h> | 
| 11 | 11 | 
| 12 #include <vector> | 12 #include <vector> | 
| 13 | 13 | 
| 14 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" | 
| 15 #include "base/logging.h" | 15 #include "base/logging.h" | 
| 16 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" | 
| 17 #include "content/child/webcrypto/crypto_data.h" | 17 #include "content/child/webcrypto/crypto_data.h" | 
| 18 #include "content/child/webcrypto/status.h" | 18 #include "content/child/webcrypto/status.h" | 
| 19 #include "content/child/webcrypto/webcrypto_util.h" | 19 #include "content/child/webcrypto/webcrypto_util.h" | 
| 20 #include "crypto/nss_util.h" | 20 #include "crypto/nss_util.h" | 
| 21 #include "crypto/random.h" | |
| 21 #include "crypto/scoped_nss_types.h" | 22 #include "crypto/scoped_nss_types.h" | 
| 22 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 23 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 
| 23 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 24 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 
| 24 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 25 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 
| 25 | 26 | 
| 26 #if defined(USE_NSS) | 27 #if defined(USE_NSS) | 
| 27 #include <dlfcn.h> | 28 #include <dlfcn.h> | 
| 28 #include <secoid.h> | 29 #include <secoid.h> | 
| 29 #endif | 30 #endif | 
| 30 | 31 | 
| (...skipping 1679 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1710 AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template); | 1711 AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template); | 
| 1711 AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template); | 1712 AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template); | 
| 1712 AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template); | 1713 AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template); | 
| 1713 AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template); | 1714 AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template); | 
| 1714 | 1715 | 
| 1715 // Required properties. | 1716 // Required properties. | 
| 1716 AddOptionalAttribute(CKA_MODULUS, modulus, &key_template); | 1717 AddOptionalAttribute(CKA_MODULUS, modulus, &key_template); | 
| 1717 AddOptionalAttribute(CKA_PUBLIC_EXPONENT, public_exponent, &key_template); | 1718 AddOptionalAttribute(CKA_PUBLIC_EXPONENT, public_exponent, &key_template); | 
| 1718 AddOptionalAttribute(CKA_PRIVATE_EXPONENT, private_exponent, &key_template); | 1719 AddOptionalAttribute(CKA_PRIVATE_EXPONENT, private_exponent, &key_template); | 
| 1719 | 1720 | 
| 1721 // Manufacture a CKA_ID so the created key can be retrieved later as a | |
| 1722 // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more | |
| 1723 // direct way to do this in NSS. | |
| 1724 // | |
| 1725 // A randomly generated value is used for the ID. | |
| 1726 // | |
| 1727 // NSS assigns the CKA_ID to PK11_MakeIDFromPubKey() for the other key | |
| 1728 // creation paths. However it is incorrect to try and use that as the CKA_ID | |
| 1729 // here because: | |
| 1730 // | |
| 1731 // (1) CreateGenericObject does not validate its parameters. It is therefore | |
| 1732 // possible to construct a key using the known public modulus, and all | |
| 1733 // the other parameters are bogus. FindKeyByKeyID() returns the first | |
| 1734 // key matching the ID. So this would effectively allow an attacker to | |
| 1735 // retrieve a private key of their choice. | |
| 1736 // NSS 3.16.2 does validate parameters. | |
| 1737 // | |
| 1738 // (2) The ID space is shared by different key types. So even if parameters | |
| 1739 // were validated by NSS, FindKeyByKeyID() could still return the wrong | |
| 1740 // key. For instance it might return a DH key that happens to have same | |
| 1741 // values for its public data. | |
| 1742 // Ryan says this isn't possible in practice, because matching values for | |
| 
Ryan Sleevi
2014/06/02 23:55:57
We don't do this in comments :)
But I'm glad Rya
 | |
| 1743 // valid keys can't be easily guessed. | |
| 1744 // | |
| 1745 // (3) Even if the above two problems were non-issues, there is no guarantee | |
| 1746 // that FindKeyByKeyID() returns the object just created. If the same | |
| 1747 // private key were imported multiple times, with different flags, using | |
| 1748 // the wrong one could lead to problems. | |
| 1749 std::vector<uint8> cka_id(20); | |
| 1750 crypto::RandBytes(&cka_id[0], cka_id.size()); | |
| 1751 AddOptionalAttribute(CKA_ID, CryptoData(cka_id), &key_template); | |
| 1752 SECItem object_id = MakeSECItemForBuffer(CryptoData(cka_id)); | |
| 1753 | |
| 1720 // Optional properties (all of these will have been specified or none). | 1754 // Optional properties (all of these will have been specified or none). | 
| 1721 AddOptionalAttribute(CKA_PRIME_1, prime1, &key_template); | 1755 AddOptionalAttribute(CKA_PRIME_1, prime1, &key_template); | 
| 1722 AddOptionalAttribute(CKA_PRIME_2, prime2, &key_template); | 1756 AddOptionalAttribute(CKA_PRIME_2, prime2, &key_template); | 
| 1723 AddOptionalAttribute(CKA_EXPONENT_1, exponent1, &key_template); | 1757 AddOptionalAttribute(CKA_EXPONENT_1, exponent1, &key_template); | 
| 1724 AddOptionalAttribute(CKA_EXPONENT_2, exponent2, &key_template); | 1758 AddOptionalAttribute(CKA_EXPONENT_2, exponent2, &key_template); | 
| 1725 AddOptionalAttribute(CKA_COEFFICIENT, coefficient, &key_template); | 1759 AddOptionalAttribute(CKA_COEFFICIENT, coefficient, &key_template); | 
| 1726 | 1760 | 
| 1727 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 1761 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 
| 1728 | 1762 | 
| 1729 ScopedPK11GenericObject key_object(PK11_CreateGenericObject( | 1763 ScopedPK11GenericObject key_object(PK11_CreateGenericObject( | 
| 1730 slot.get(), &key_template[0], key_template.size(), PR_FALSE)); | 1764 slot.get(), &key_template[0], key_template.size(), PR_FALSE)); | 
| 1731 | 1765 | 
| 1732 if (!key_object) | 1766 if (!key_object) | 
| 1733 return Status::OperationError(); | 1767 return Status::OperationError(); | 
| 1734 | 1768 | 
| 1735 // The ID isn't guaranteed to be set by PKCS#11. However it is by softtoken so | |
| 1736 // this should work. | |
| 1737 SECItem object_id = {}; | |
| 1738 if (PK11_ReadRawAttribute( | |
| 1739 PK11_TypeGeneric, key_object.get(), CKA_ID, &object_id) != SECSuccess) | |
| 1740 return Status::OperationError(); | |
| 1741 | |
| 1742 crypto::ScopedSECKEYPrivateKey private_key( | 1769 crypto::ScopedSECKEYPrivateKey private_key( | 
| 1743 PK11_FindKeyByKeyID(slot.get(), &object_id, NULL)); | 1770 PK11_FindKeyByKeyID(slot.get(), &object_id, NULL)); | 
| 1744 | 1771 | 
| 1745 SECITEM_FreeItem(&object_id, PR_FALSE); | |
| 1746 | |
| 1747 if (!private_key) | 1772 if (!private_key) | 
| 1748 return Status::OperationError(); | 1773 return Status::OperationError(); | 
| 1749 | 1774 | 
| 1750 blink::WebCryptoKeyAlgorithm key_algorithm; | 1775 blink::WebCryptoKeyAlgorithm key_algorithm; | 
| 1751 if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm)) | 1776 if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm)) | 
| 1752 return Status::ErrorUnexpected(); | 1777 return Status::ErrorUnexpected(); | 
| 1753 | 1778 | 
| 1754 scoped_ptr<PrivateKey> key_handle; | 1779 scoped_ptr<PrivateKey> key_handle; | 
| 1755 Status status = | 1780 Status status = | 
| 1756 PrivateKey::Create(private_key.Pass(), key_algorithm, &key_handle); | 1781 PrivateKey::Create(private_key.Pass(), key_algorithm, &key_handle); | 
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1863 buffer->assign(key_data->data, key_data->data + key_data->len); | 1888 buffer->assign(key_data->data, key_data->data + key_data->len); | 
| 1864 | 1889 | 
| 1865 return Status::Success(); | 1890 return Status::Success(); | 
| 1866 } | 1891 } | 
| 1867 | 1892 | 
| 1868 } // namespace platform | 1893 } // namespace platform | 
| 1869 | 1894 | 
| 1870 } // namespace webcrypto | 1895 } // namespace webcrypto | 
| 1871 | 1896 | 
| 1872 } // namespace content | 1897 } // namespace content | 
| OLD | NEW |