@@ -79,7 +79,7 @@ std::optional<std::string> CryptoErrorList::pop_front() {
7979
8080// ============================================================================
8181DataPointer DataPointer::Alloc (size_t len) {
82- return DataPointer (OPENSSL_malloc (len), len);
82+ return DataPointer (OPENSSL_zalloc (len), len);
8383}
8484
8585DataPointer::DataPointer (void * data, size_t length)
@@ -1427,6 +1427,33 @@ DataPointer pbkdf2(const EVP_MD* md,
14271427
14281428// ============================================================================
14291429
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+
14301457EVPKeyPointer EVPKeyPointer::New () {
14311458 return EVPKeyPointer (EVP_PKEY_new ());
14321459}
@@ -1660,41 +1687,61 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM(
16601687}
16611688
16621689EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey (
1663- PKFormatType format,
1664- PKEncodingType encoding,
1690+ const PublicKeyEncodingConfig& config,
16651691 const Buffer<const unsigned char >& buffer) {
1666- if (format == PKFormatType::PEM) {
1692+ if (config. format == PKFormatType::PEM) {
16671693 return TryParsePublicKeyPEM (buffer);
16681694 }
16691695
1670- if (format != PKFormatType::DER) {
1696+ if (config. format != PKFormatType::DER) {
16711697 return ParseKeyResult (PKParseError::FAILED);
16721698 }
16731699
16741700 const unsigned char * start = buffer.data ;
16751701
16761702 EVP_PKEY* key = nullptr ;
16771703
1678- if (encoding == PKEncodingType::PKCS1 &&
1704+ if (config. type == PKEncodingType::PKCS1 &&
16791705 (key = d2i_PublicKey (EVP_PKEY_RSA, nullptr , &start, buffer.len ))) {
16801706 return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
16811707 }
16821708
1683- if (encoding == PKEncodingType::SPKI &&
1709+ if (config. type == PKEncodingType::SPKI &&
16841710 (key = d2i_PUBKEY (nullptr , &start, buffer.len ))) {
16851711 return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
16861712 }
16871713
16881714 return ParseKeyResult (PKParseError::FAILED);
16891715}
16901716
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+
16911740EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey (
1692- PKFormatType format,
1693- PKEncodingType encoding,
1694- std::optional<Buffer<char >> maybe_passphrase,
1741+ const PrivateKeyEncodingConfig& config,
16951742 const Buffer<const unsigned char >& buffer) {
16961743
1697- static auto keyOrError = [& ](EVPKeyPointer pkey, bool had_passphrase = false ) {
1744+ static constexpr auto keyOrError = [](EVPKeyPointer pkey, bool had_passphrase = false ) {
16981745 if (int err = ERR_peek_error ()) {
16991746 if (ERR_GET_LIB (err) == ERR_LIB_PEM &&
17001747 ERR_GET_REASON (err) == PEM_R_BAD_PASSWORD_READ &&
@@ -1707,24 +1754,23 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17071754 return ParseKeyResult (std::move (pkey));
17081755 };
17091756
1710- Buffer<char >* passphrase = nullptr ;
1711- if (maybe_passphrase.has_value ()) {
1712- passphrase = &maybe_passphrase.value ();
1713- }
17141757
17151758 auto bio = BIOPointer::New (buffer);
17161759 if (!bio) return ParseKeyResult (PKParseError::FAILED);
17171760
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 ());
17211767 }
17221768
1723- if (format != PKFormatType::DER) {
1769+ if (config. format != PKFormatType::DER) {
17241770 return ParseKeyResult (PKParseError::FAILED);
17251771 }
17261772
1727- switch (encoding ) {
1773+ switch (config. type ) {
17281774 case PKEncodingType::PKCS1: {
17291775 auto key = d2i_PrivateKey_bio (bio.get (), nullptr );
17301776 return keyOrError (EVPKeyPointer (key));
@@ -1734,8 +1780,8 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17341780 auto key = d2i_PKCS8PrivateKey_bio (bio.get (),
17351781 nullptr ,
17361782 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 ());
17391785 }
17401786
17411787 PKCS8Pointer p8inf (d2i_PKCS8_PRIV_KEY_INFO_bio (bio.get (), nullptr ));
@@ -1754,4 +1800,162 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17541800 };
17551801}
17561802
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+
17571961} // namespace ncrypto
0 commit comments