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