| 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> |
| (...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 CK_FLAGS* flags) { | 577 CK_FLAGS* flags) { |
| 578 // Flags are verified at the Blink layer; here the flags are set to all | 578 // Flags are verified at the Blink layer; here the flags are set to all |
| 579 // possible operations of a key for the input algorithm type. | 579 // possible operations of a key for the input algorithm type. |
| 580 switch (algorithm.id()) { | 580 switch (algorithm.id()) { |
| 581 case blink::WebCryptoAlgorithmIdHmac: { | 581 case blink::WebCryptoAlgorithmIdHmac: { |
| 582 const blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm); | 582 const blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm); |
| 583 *mechanism = WebCryptoHashToHMACMechanism(hash); | 583 *mechanism = WebCryptoHashToHMACMechanism(hash); |
| 584 if (*mechanism == CKM_INVALID_MECHANISM) | 584 if (*mechanism == CKM_INVALID_MECHANISM) |
| 585 return Status::ErrorUnsupported(); | 585 return Status::ErrorUnsupported(); |
| 586 *flags = CKF_SIGN | CKF_VERIFY; | 586 *flags = CKF_SIGN | CKF_VERIFY; |
| 587 break; | 587 return Status::Success(); |
| 588 } | 588 } |
| 589 case blink::WebCryptoAlgorithmIdAesCbc: { | 589 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 590 *mechanism = CKM_AES_CBC; | 590 *mechanism = CKM_AES_CBC; |
| 591 *flags = CKF_ENCRYPT | CKF_DECRYPT; | 591 *flags = CKF_ENCRYPT | CKF_DECRYPT; |
| 592 break; | 592 return Status::Success(); |
| 593 } | 593 } |
| 594 case blink::WebCryptoAlgorithmIdAesKw: { | 594 case blink::WebCryptoAlgorithmIdAesKw: { |
| 595 *mechanism = CKM_NSS_AES_KEY_WRAP; | 595 *mechanism = CKM_NSS_AES_KEY_WRAP; |
| 596 *flags = CKF_WRAP | CKF_WRAP; | 596 *flags = CKF_WRAP | CKF_WRAP; |
| 597 break; | 597 return Status::Success(); |
| 598 } | 598 } |
| 599 case blink::WebCryptoAlgorithmIdAesGcm: { | 599 case blink::WebCryptoAlgorithmIdAesGcm: { |
| 600 if (!g_nss_runtime_support.Get().IsAesGcmSupported()) | 600 if (!g_nss_runtime_support.Get().IsAesGcmSupported()) |
| 601 return Status::ErrorUnsupported(); | 601 return Status::ErrorUnsupported(); |
| 602 *mechanism = CKM_AES_GCM; | 602 *mechanism = CKM_AES_GCM; |
| 603 *flags = CKF_ENCRYPT | CKF_DECRYPT; | 603 *flags = CKF_ENCRYPT | CKF_DECRYPT; |
| 604 break; | 604 return Status::Success(); |
| 605 } | 605 } |
| 606 default: | 606 default: |
| 607 return Status::ErrorUnsupported(); | 607 return Status::ErrorUnsupported(); |
| 608 } | 608 } |
| 609 return Status::Success(); | |
| 610 } | 609 } |
| 611 | 610 |
| 612 Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, | 611 Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, |
| 613 SymKey* wrapping_key, | 612 SymKey* wrapping_key, |
| 614 CK_MECHANISM_TYPE mechanism, | 613 CK_MECHANISM_TYPE mechanism, |
| 615 CK_FLAGS flags, | 614 CK_FLAGS flags, |
| 616 crypto::ScopedPK11SymKey* unwrapped_key) { | 615 crypto::ScopedPK11SymKey* unwrapped_key) { |
| 617 DCHECK_GE(wrapped_key_data.byte_length(), 24u); | 616 DCHECK_GE(wrapped_key_data.byte_length(), 24u); |
| 618 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u); | 617 DCHECK_EQ(wrapped_key_data.byte_length() % 8, 0u); |
| 619 | 618 |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 unsigned char result_[HASH_LENGTH_MAX]; | 875 unsigned char result_[HASH_LENGTH_MAX]; |
| 877 }; | 876 }; |
| 878 | 877 |
| 879 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 878 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
| 880 const CryptoData& key_data, | 879 const CryptoData& key_data, |
| 881 bool extractable, | 880 bool extractable, |
| 882 blink::WebCryptoKeyUsageMask usage_mask, | 881 blink::WebCryptoKeyUsageMask usage_mask, |
| 883 blink::WebCryptoKey* key) { | 882 blink::WebCryptoKey* key) { |
| 884 DCHECK(!algorithm.isNull()); | 883 DCHECK(!algorithm.isNull()); |
| 885 | 884 |
| 886 CK_MECHANISM_TYPE mechanism; | 885 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; |
| 887 CK_FLAGS flags; | 886 CK_FLAGS flags = 0; |
| 888 Status status = | 887 Status status = |
| 889 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); | 888 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); |
| 890 if (status.IsError()) | 889 if (status.IsError()) |
| 891 return status; | 890 return status; |
| 892 | 891 |
| 893 SECItem key_item = MakeSECItemForBuffer(key_data); | 892 SECItem key_item = MakeSECItemForBuffer(key_data); |
| 894 | 893 |
| 895 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 894 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
| 896 crypto::ScopedPK11SymKey pk11_sym_key( | 895 crypto::ScopedPK11SymKey pk11_sym_key( |
| 897 PK11_ImportSymKeyWithFlags(slot.get(), | 896 PK11_ImportSymKeyWithFlags(slot.get(), |
| (...skipping 859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1757 return status; | 1756 return status; |
| 1758 | 1757 |
| 1759 *key = blink::WebCryptoKey::create(key_handle.release(), | 1758 *key = blink::WebCryptoKey::create(key_handle.release(), |
| 1760 blink::WebCryptoKeyTypePrivate, | 1759 blink::WebCryptoKeyTypePrivate, |
| 1761 extractable, | 1760 extractable, |
| 1762 key_algorithm, | 1761 key_algorithm, |
| 1763 usage_mask); | 1762 usage_mask); |
| 1764 return Status::Success(); | 1763 return Status::Success(); |
| 1765 } | 1764 } |
| 1766 | 1765 |
| 1767 Status WrapSymKeyAesKw(SymKey* key, | 1766 Status WrapSymKeyAesKw(PK11SymKey* key, |
| 1768 SymKey* wrapping_key, | 1767 SymKey* wrapping_key, |
| 1769 std::vector<uint8>* buffer) { | 1768 std::vector<uint8>* buffer) { |
| 1770 // The data size must be at least 16 bytes and a multiple of 8 bytes. | 1769 // The data size must be at least 16 bytes and a multiple of 8 bytes. |
| 1771 // RFC 3394 does not specify a maximum allowed data length, but since only | 1770 // RFC 3394 does not specify a maximum allowed data length, but since only |
| 1772 // keys are being wrapped in this application (which are small), a reasonable | 1771 // keys are being wrapped in this application (which are small), a reasonable |
| 1773 // max limit is whatever will fit into an unsigned. For the max size test, | 1772 // max limit is whatever will fit into an unsigned. For the max size test, |
| 1774 // note that AES Key Wrap always adds 8 bytes to the input data size. | 1773 // note that AES Key Wrap always adds 8 bytes to the input data size. |
| 1775 const unsigned int input_length = PK11_GetKeyLength(key->key()); | 1774 const unsigned int input_length = PK11_GetKeyLength(key); |
| 1776 if (input_length < 16) | 1775 DCHECK_GE(input_length, 16u); |
| 1777 return Status::ErrorDataTooSmall(); | 1776 DCHECK((input_length % 8) == 0); |
| 1778 if (input_length > UINT_MAX - 8) | 1777 if (input_length > UINT_MAX - 8) |
| 1779 return Status::ErrorDataTooLarge(); | 1778 return Status::ErrorDataTooLarge(); |
| 1780 if (input_length % 8) | |
| 1781 return Status::ErrorInvalidAesKwDataLength(); | |
| 1782 | 1779 |
| 1783 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); | 1780 SECItem iv_item = MakeSECItemForBuffer(CryptoData(kAesIv, sizeof(kAesIv))); |
| 1784 crypto::ScopedSECItem param_item( | 1781 crypto::ScopedSECItem param_item( |
| 1785 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); | 1782 PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP, &iv_item)); |
| 1786 if (!param_item) | 1783 if (!param_item) |
| 1787 return Status::ErrorUnexpected(); | 1784 return Status::ErrorUnexpected(); |
| 1788 | 1785 |
| 1789 const unsigned int output_length = input_length + 8; | 1786 const unsigned int output_length = input_length + 8; |
| 1790 buffer->resize(output_length); | 1787 buffer->resize(output_length); |
| 1791 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer)); | 1788 SECItem wrapped_key_item = MakeSECItemForBuffer(CryptoData(*buffer)); |
| 1792 | 1789 |
| 1793 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, | 1790 if (SECSuccess != PK11_WrapSymKey(CKM_NSS_AES_KEY_WRAP, |
| 1794 param_item.get(), | 1791 param_item.get(), |
| 1795 wrapping_key->key(), | 1792 wrapping_key->key(), |
| 1796 key->key(), | 1793 key, |
| 1797 &wrapped_key_item)) { | 1794 &wrapped_key_item)) { |
| 1798 return Status::OperationError(); | 1795 return Status::OperationError(); |
| 1799 } | 1796 } |
| 1800 if (output_length != wrapped_key_item.len) | 1797 if (output_length != wrapped_key_item.len) |
| 1801 return Status::ErrorUnexpected(); | 1798 return Status::ErrorUnexpected(); |
| 1802 | 1799 |
| 1803 return Status::Success(); | 1800 return Status::Success(); |
| 1804 } | 1801 } |
| 1805 | 1802 |
| 1806 Status UnwrapSymKeyAesKw(const CryptoData& wrapped_key_data, | |
| 1807 SymKey* wrapping_key, | |
| 1808 const blink::WebCryptoAlgorithm& algorithm, | |
| 1809 bool extractable, | |
| 1810 blink::WebCryptoKeyUsageMask usage_mask, | |
| 1811 blink::WebCryptoKey* key) { | |
| 1812 // Determine the proper NSS key properties from the input algorithm. | |
| 1813 CK_MECHANISM_TYPE mechanism; | |
| 1814 CK_FLAGS flags; | |
| 1815 Status status = | |
| 1816 WebCryptoAlgorithmToNssMechFlags(algorithm, &mechanism, &flags); | |
| 1817 if (status.IsError()) | |
| 1818 return status; | |
| 1819 | |
| 1820 crypto::ScopedPK11SymKey unwrapped_key; | |
| 1821 status = DoUnwrapSymKeyAesKw( | |
| 1822 wrapped_key_data, wrapping_key, mechanism, flags, &unwrapped_key); | |
| 1823 if (status.IsError()) | |
| 1824 return status; | |
| 1825 | |
| 1826 blink::WebCryptoKeyAlgorithm key_algorithm; | |
| 1827 if (!CreateSecretKeyAlgorithm( | |
| 1828 algorithm, PK11_GetKeyLength(unwrapped_key.get()), &key_algorithm)) | |
| 1829 return Status::ErrorUnexpected(); | |
| 1830 | |
| 1831 scoped_ptr<SymKey> key_handle; | |
| 1832 status = SymKey::Create(unwrapped_key.Pass(), &key_handle); | |
| 1833 if (status.IsError()) | |
| 1834 return status; | |
| 1835 | |
| 1836 *key = blink::WebCryptoKey::create(key_handle.release(), | |
| 1837 blink::WebCryptoKeyTypeSecret, | |
| 1838 extractable, | |
| 1839 key_algorithm, | |
| 1840 usage_mask); | |
| 1841 return Status::Success(); | |
| 1842 } | |
| 1843 | |
| 1844 Status DecryptAesKw(SymKey* wrapping_key, | 1803 Status DecryptAesKw(SymKey* wrapping_key, |
| 1845 const CryptoData& data, | 1804 const CryptoData& data, |
| 1846 std::vector<uint8>* buffer) { | 1805 std::vector<uint8>* buffer) { |
| 1847 // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be | 1806 // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be |
| 1848 // temporarily viewed as a symmetric key to be unwrapped (decrypted). | 1807 // temporarily viewed as a symmetric key to be unwrapped (decrypted). |
| 1849 crypto::ScopedPK11SymKey decrypted; | 1808 crypto::ScopedPK11SymKey decrypted; |
| 1850 Status status = DoUnwrapSymKeyAesKw( | 1809 Status status = DoUnwrapSymKeyAesKw( |
| 1851 data, wrapping_key, CKK_GENERIC_SECRET, 0, &decrypted); | 1810 data, wrapping_key, CKK_GENERIC_SECRET, 0, &decrypted); |
| 1852 if (status.IsError()) | 1811 if (status.IsError()) |
| 1853 return status; | 1812 return status; |
| 1854 | 1813 |
| 1855 // Once the decrypt is complete, extract the resultant raw bytes from NSS and | 1814 // Once the decrypt is complete, extract the resultant raw bytes from NSS and |
| 1856 // return them to the caller. | 1815 // return them to the caller. |
| 1857 if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess) | 1816 if (PK11_ExtractKeyValue(decrypted.get()) != SECSuccess) |
| 1858 return Status::OperationError(); | 1817 return Status::OperationError(); |
| 1859 const SECItem* const key_data = PK11_GetKeyData(decrypted.get()); | 1818 const SECItem* const key_data = PK11_GetKeyData(decrypted.get()); |
| 1860 if (!key_data) | 1819 if (!key_data) |
| 1861 return Status::OperationError(); | 1820 return Status::OperationError(); |
| 1862 buffer->assign(key_data->data, key_data->data + key_data->len); | 1821 buffer->assign(key_data->data, key_data->data + key_data->len); |
| 1863 | 1822 |
| 1864 return Status::Success(); | 1823 return Status::Success(); |
| 1865 } | 1824 } |
| 1866 | 1825 |
| 1826 Status EncryptAesKw(SymKey* wrapping_key, |
| 1827 const CryptoData& data, |
| 1828 std::vector<uint8>* buffer) { |
| 1829 // Due to limitations in the NSS API for the AES-KW algorithm, |data| must be |
| 1830 // temporarily viewed as a symmetric key to be wrapped (encrypted). |
| 1831 SECItem data_item = MakeSECItemForBuffer(data); |
| 1832 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
| 1833 crypto::ScopedPK11SymKey data_as_sym_key(PK11_ImportSymKey(slot.get(), |
| 1834 CKK_GENERIC_SECRET, |
| 1835 PK11_OriginUnwrap, |
| 1836 CKA_SIGN, |
| 1837 &data_item, |
| 1838 NULL)); |
| 1839 if (!data_as_sym_key) |
| 1840 return Status::OperationError(); |
| 1841 |
| 1842 return WrapSymKeyAesKw(data_as_sym_key.get(), wrapping_key, buffer); |
| 1843 } |
| 1844 |
| 1845 Status EncryptDecryptAesKw(EncryptOrDecrypt mode, |
| 1846 SymKey* wrapping_key, |
| 1847 const CryptoData& data, |
| 1848 std::vector<uint8>* buffer) { |
| 1849 return mode == ENCRYPT ? EncryptAesKw(wrapping_key, data, buffer) |
| 1850 : DecryptAesKw(wrapping_key, data, buffer); |
| 1851 } |
| 1852 |
| 1867 } // namespace platform | 1853 } // namespace platform |
| 1868 | 1854 |
| 1869 } // namespace webcrypto | 1855 } // namespace webcrypto |
| 1870 | 1856 |
| 1871 } // namespace content | 1857 } // namespace content |
| OLD | NEW |