@@ -80,7 +80,7 @@ std::optional<std::string> CryptoErrorList::pop_front() {
80
80
81
81
// ============================================================================
82
82
DataPointer DataPointer::Alloc (size_t len) {
83
- return DataPointer (OPENSSL_malloc (len), len);
83
+ return DataPointer (OPENSSL_zalloc (len), len);
84
84
}
85
85
86
86
DataPointer::DataPointer (void * data, size_t length)
@@ -1428,6 +1428,33 @@ DataPointer pbkdf2(const EVP_MD* md,
1428
1428
1429
1429
// ============================================================================
1430
1430
1431
+ EVPKeyPointer::PrivateKeyEncodingConfig::PrivateKeyEncodingConfig (
1432
+ const PrivateKeyEncodingConfig& other)
1433
+ : PrivateKeyEncodingConfig(other.output_key_object, other.format, other.type) {
1434
+ cipher = other.cipher ;
1435
+ if (other.passphrase .has_value ()) {
1436
+ auto & otherPassphrase = other.passphrase .value ();
1437
+ auto newPassphrase = DataPointer::Alloc (otherPassphrase.size ());
1438
+ memcpy (newPassphrase.get (), otherPassphrase.get (), otherPassphrase.size ());
1439
+ passphrase = std::move (newPassphrase);
1440
+ }
1441
+ }
1442
+
1443
+ EVPKeyPointer::AsymmetricKeyEncodingConfig::AsymmetricKeyEncodingConfig (
1444
+ bool output_key_object,
1445
+ PKFormatType format,
1446
+ PKEncodingType type)
1447
+ : output_key_object(output_key_object),
1448
+ format (format),
1449
+ type(type) {}
1450
+
1451
+ EVPKeyPointer::PrivateKeyEncodingConfig& EVPKeyPointer::PrivateKeyEncodingConfig::operator =(
1452
+ const PrivateKeyEncodingConfig& other) {
1453
+ if (this == &other) return *this ;
1454
+ this ->~PrivateKeyEncodingConfig ();
1455
+ return *new (this ) PrivateKeyEncodingConfig (other);
1456
+ }
1457
+
1431
1458
EVPKeyPointer EVPKeyPointer::New () {
1432
1459
return EVPKeyPointer (EVP_PKEY_new ());
1433
1460
}
@@ -1661,41 +1688,61 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM(
1661
1688
}
1662
1689
1663
1690
EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey (
1664
- PKFormatType format,
1665
- PKEncodingType encoding,
1691
+ const PublicKeyEncodingConfig& config,
1666
1692
const Buffer<const unsigned char >& buffer) {
1667
- if (format == PKFormatType::PEM) {
1693
+ if (config. format == PKFormatType::PEM) {
1668
1694
return TryParsePublicKeyPEM (buffer);
1669
1695
}
1670
1696
1671
- if (format != PKFormatType::DER) {
1697
+ if (config. format != PKFormatType::DER) {
1672
1698
return ParseKeyResult (PKParseError::FAILED);
1673
1699
}
1674
1700
1675
1701
const unsigned char * start = buffer.data ;
1676
1702
1677
1703
EVP_PKEY* key = nullptr ;
1678
1704
1679
- if (encoding == PKEncodingType::PKCS1 &&
1705
+ if (config. type == PKEncodingType::PKCS1 &&
1680
1706
(key = d2i_PublicKey (EVP_PKEY_RSA, nullptr , &start, buffer.len ))) {
1681
1707
return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
1682
1708
}
1683
1709
1684
- if (encoding == PKEncodingType::SPKI &&
1710
+ if (config. type == PKEncodingType::SPKI &&
1685
1711
(key = d2i_PUBKEY (nullptr , &start, buffer.len ))) {
1686
1712
return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
1687
1713
}
1688
1714
1689
1715
return ParseKeyResult (PKParseError::FAILED);
1690
1716
}
1691
1717
1718
+ namespace {
1719
+ Buffer<char > GetPassphrase (const EVPKeyPointer::PrivateKeyEncodingConfig& config) {
1720
+ Buffer<char > pass {
1721
+ // OpenSSL will not actually dereference this pointer, so it can be any
1722
+ // non-null pointer. We cannot assert that directly, which is why we
1723
+ // intentionally use a pointer that will likely cause a segmentation fault
1724
+ // when dereferenced.
1725
+ .data = reinterpret_cast <char *>(-1 ),
1726
+ .len = 0 ,
1727
+ };
1728
+ if (config.passphrase .has_value ()) {
1729
+ auto & passphrase = config.passphrase .value ();
1730
+ // The pass.data can't be a nullptr, even if the len is zero or else
1731
+ // openssl will prompt for a password and we really don't want that.
1732
+ if (passphrase.get () != nullptr ) {
1733
+ pass.data = static_cast <char *>(passphrase.get ());
1734
+ }
1735
+ pass.len = passphrase.size ();
1736
+ }
1737
+ return pass;
1738
+ }
1739
+ } // namespace
1740
+
1692
1741
EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey (
1693
- PKFormatType format,
1694
- PKEncodingType encoding,
1695
- std::optional<Buffer<char >> maybe_passphrase,
1742
+ const PrivateKeyEncodingConfig& config,
1696
1743
const Buffer<const unsigned char >& buffer) {
1697
1744
1698
- static auto keyOrError = [& ](EVPKeyPointer pkey, bool had_passphrase = false ) {
1745
+ static constexpr auto keyOrError = [](EVPKeyPointer pkey, bool had_passphrase = false ) {
1699
1746
if (int err = ERR_peek_error ()) {
1700
1747
if (ERR_GET_LIB (err) == ERR_LIB_PEM &&
1701
1748
ERR_GET_REASON (err) == PEM_R_BAD_PASSWORD_READ &&
@@ -1708,24 +1755,23 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
1708
1755
return ParseKeyResult (std::move (pkey));
1709
1756
};
1710
1757
1711
- Buffer<char >* passphrase = nullptr ;
1712
- if (maybe_passphrase.has_value ()) {
1713
- passphrase = &maybe_passphrase.value ();
1714
- }
1715
1758
1716
1759
auto bio = BIOPointer::New (buffer);
1717
1760
if (!bio) return ParseKeyResult (PKParseError::FAILED);
1718
1761
1719
- if (format == PKFormatType::PEM) {
1720
- auto key = PEM_read_bio_PrivateKey (bio.get (), nullptr , PasswordCallback, passphrase);
1721
- return keyOrError (EVPKeyPointer (key), maybe_passphrase.has_value ());
1762
+ auto passphrase = GetPassphrase (config);
1763
+
1764
+ if (config.format == PKFormatType::PEM) {
1765
+ auto key = PEM_read_bio_PrivateKey (bio.get (), nullptr , PasswordCallback,
1766
+ config.passphrase .has_value () ? &passphrase : nullptr );
1767
+ return keyOrError (EVPKeyPointer (key), config.passphrase .has_value ());
1722
1768
}
1723
1769
1724
- if (format != PKFormatType::DER) {
1770
+ if (config. format != PKFormatType::DER) {
1725
1771
return ParseKeyResult (PKParseError::FAILED);
1726
1772
}
1727
1773
1728
- switch (encoding ) {
1774
+ switch (config. type ) {
1729
1775
case PKEncodingType::PKCS1: {
1730
1776
auto key = d2i_PrivateKey_bio (bio.get (), nullptr );
1731
1777
return keyOrError (EVPKeyPointer (key));
@@ -1735,8 +1781,8 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
1735
1781
auto key = d2i_PKCS8PrivateKey_bio (bio.get (),
1736
1782
nullptr ,
1737
1783
PasswordCallback,
1738
- passphrase);
1739
- return keyOrError (EVPKeyPointer (key), maybe_passphrase .has_value ());
1784
+ config. passphrase . has_value () ? &passphrase : nullptr );
1785
+ return keyOrError (EVPKeyPointer (key), config. passphrase .has_value ());
1740
1786
}
1741
1787
1742
1788
PKCS8Pointer p8inf (d2i_PKCS8_PRIV_KEY_INFO_bio (bio.get (), nullptr ));
@@ -1755,4 +1801,166 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
1755
1801
};
1756
1802
}
1757
1803
1804
+ Result<BIOPointer, bool > EVPKeyPointer::writePrivateKey (
1805
+ const PrivateKeyEncodingConfig& config) const {
1806
+ if (config.format == PKFormatType::JWK) {
1807
+ return Result<BIOPointer, bool >(false );
1808
+ }
1809
+
1810
+ auto bio = BIOPointer::NewMem ();
1811
+ if (!bio) {
1812
+ return Result<BIOPointer, bool >(false );
1813
+ }
1814
+
1815
+ auto passphrase = GetPassphrase (config);
1816
+ MarkPopErrorOnReturn mark_pop_error_on_return;
1817
+ bool err;
1818
+
1819
+ switch (config.type ) {
1820
+ case PKEncodingType::PKCS1: {
1821
+ // PKCS1 is only permitted for RSA keys.
1822
+ if (id () != EVP_PKEY_RSA) return Result<BIOPointer, bool >(false );
1823
+
1824
+ #if OPENSSL_VERSION_MAJOR >= 3
1825
+ const RSA* rsa = EVP_PKEY_get0_RSA (get ());
1826
+ #else
1827
+ RSA* rsa = EVP_PKEY_get0_RSA (get ());
1828
+ #endif
1829
+ switch (config.format ) {
1830
+ case PKFormatType::PEM: {
1831
+ err = PEM_write_bio_RSAPrivateKey (bio.get (), rsa, config.cipher ,
1832
+ reinterpret_cast <unsigned char *>(passphrase.data ),
1833
+ passphrase.len , nullptr , nullptr ) != 1 ;
1834
+ break ;
1835
+ }
1836
+ case PKFormatType::DER: {
1837
+ // Encoding PKCS1 as DER. This variation does not permit encryption.
1838
+ err = i2d_RSAPrivateKey_bio (bio.get (), rsa) != 1 ;
1839
+ break ;
1840
+ }
1841
+ default : {
1842
+ // Should never get here.
1843
+ return Result<BIOPointer, bool >(false );
1844
+ }
1845
+ }
1846
+ break ;
1847
+ }
1848
+ case PKEncodingType::PKCS8: {
1849
+ switch (config.format ) {
1850
+ case PKFormatType::PEM: {
1851
+ // Encode PKCS#8 as PEM.
1852
+ err = PEM_write_bio_PKCS8PrivateKey (
1853
+ bio.get (), get (),
1854
+ config.cipher ,
1855
+ passphrase.data ,
1856
+ passphrase.len ,
1857
+ nullptr , nullptr ) != 1 ;
1858
+ break ;
1859
+ }
1860
+ case PKFormatType::DER: {
1861
+ err = i2d_PKCS8PrivateKey_bio (
1862
+ bio.get (), get (),
1863
+ config.cipher ,
1864
+ passphrase.data ,
1865
+ passphrase.len ,
1866
+ nullptr , nullptr ) != 1 ;
1867
+ break ;
1868
+ }
1869
+ default : {
1870
+ // Should never get here.
1871
+ return Result<BIOPointer, bool >(false );
1872
+ }
1873
+ }
1874
+ break ;
1875
+ }
1876
+ case PKEncodingType::SEC1: {
1877
+ // SEC1 is only permitted for EC keys
1878
+ if (id () != EVP_PKEY_EC) return Result<BIOPointer, bool >(false );
1879
+
1880
+ #if OPENSSL_VERSION_MAJOR >= 3
1881
+ const EC_KEY* ec = EVP_PKEY_get0_EC_KEY (get ());
1882
+ #else
1883
+ EC_KEY* ec = EVP_PKEY_get0_EC_KEY (get ());
1884
+ #endif
1885
+ switch (config.format ) {
1886
+ case PKFormatType::PEM: {
1887
+ err = PEM_write_bio_ECPrivateKey (bio.get (),
1888
+ ec,
1889
+ config.cipher ,
1890
+ reinterpret_cast <unsigned char *>(passphrase.data ),
1891
+ passphrase.len ,
1892
+ nullptr ,
1893
+ nullptr ) != 1 ;
1894
+ break ;
1895
+ }
1896
+ case PKFormatType::DER: {
1897
+ // Encoding SEC1 as DER. This variation does not permit encryption.
1898
+ err = i2d_ECPrivateKey_bio (bio.get (), ec) != 1 ;
1899
+ break ;
1900
+ }
1901
+ default : {
1902
+ // Should never get here.
1903
+ return Result<BIOPointer, bool >(false );
1904
+ }
1905
+ }
1906
+ break ;
1907
+ }
1908
+ default : {
1909
+ // Not a valid private key encoding
1910
+ return Result<BIOPointer, bool >(false );
1911
+ }
1912
+ }
1913
+
1914
+ if (err) {
1915
+ // Failed to encode the private key.
1916
+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1917
+ }
1918
+
1919
+ return bio;
1920
+ }
1921
+
1922
+ Result<BIOPointer, bool > EVPKeyPointer::writePublicKey (
1923
+ const ncrypto::EVPKeyPointer::PublicKeyEncodingConfig& config) const {
1924
+ auto bio = BIOPointer::NewMem ();
1925
+ if (!bio) return Result<BIOPointer, bool >(false );
1926
+
1927
+ MarkPopErrorOnReturn mark_pop_error_on_return;
1928
+
1929
+ if (config.type == ncrypto::EVPKeyPointer::PKEncodingType::PKCS1) {
1930
+ // PKCS#1 is only valid for RSA keys.
1931
+ #if OPENSSL_VERSION_MAJOR >= 3
1932
+ const RSA* rsa = EVP_PKEY_get0_RSA (get ());
1933
+ #else
1934
+ RSA* rsa = EVP_PKEY_get0_RSA (get ());
1935
+ #endif
1936
+ if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
1937
+ // Encode PKCS#1 as PEM.
1938
+ if (PEM_write_bio_RSAPublicKey (bio.get (), rsa) != 1 ) {
1939
+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1940
+ }
1941
+ return bio;
1942
+ }
1943
+
1944
+ // Encode PKCS#1 as DER.
1945
+ if (i2d_RSAPublicKey_bio (bio.get (), rsa) != 1 ) {
1946
+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1947
+ }
1948
+ return bio;
1949
+ }
1950
+
1951
+ if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
1952
+ // Encode SPKI as PEM.
1953
+ if (PEM_write_bio_PUBKEY (bio.get (), get ()) != 1 ) {
1954
+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1955
+ }
1956
+ return bio;
1957
+ }
1958
+
1959
+ // Encode SPKI as DER.
1960
+ if (i2d_PUBKEY_bio (bio.get (), get ()) != 1 ) {
1961
+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1962
+ }
1963
+ return bio;
1964
+ }
1965
+
1758
1966
} // namespace ncrypto
0 commit comments