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 |