@@ -80,7 +80,7 @@ std::optional<std::string> CryptoErrorList::pop_front() {
8080
8181// ============================================================================
8282DataPointer DataPointer::Alloc (size_t len) {
83- return DataPointer (OPENSSL_malloc (len), len);
83+ return DataPointer (OPENSSL_zalloc (len), len);
8484}
8585
8686DataPointer::DataPointer (void * data, size_t length)
@@ -1428,6 +1428,33 @@ DataPointer pbkdf2(const EVP_MD* md,
14281428
14291429// ============================================================================
14301430
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+
14311458EVPKeyPointer EVPKeyPointer::New () {
14321459 return EVPKeyPointer (EVP_PKEY_new ());
14331460}
@@ -1661,41 +1688,61 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM(
16611688}
16621689
16631690EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey (
1664- PKFormatType format,
1665- PKEncodingType encoding,
1691+ const PublicKeyEncodingConfig& config,
16661692 const Buffer<const unsigned char >& buffer) {
1667- if (format == PKFormatType::PEM) {
1693+ if (config. format == PKFormatType::PEM) {
16681694 return TryParsePublicKeyPEM (buffer);
16691695 }
16701696
1671- if (format != PKFormatType::DER) {
1697+ if (config. format != PKFormatType::DER) {
16721698 return ParseKeyResult (PKParseError::FAILED);
16731699 }
16741700
16751701 const unsigned char * start = buffer.data ;
16761702
16771703 EVP_PKEY* key = nullptr ;
16781704
1679- if (encoding == PKEncodingType::PKCS1 &&
1705+ if (config. type == PKEncodingType::PKCS1 &&
16801706 (key = d2i_PublicKey (EVP_PKEY_RSA, nullptr , &start, buffer.len ))) {
16811707 return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
16821708 }
16831709
1684- if (encoding == PKEncodingType::SPKI &&
1710+ if (config. type == PKEncodingType::SPKI &&
16851711 (key = d2i_PUBKEY (nullptr , &start, buffer.len ))) {
16861712 return EVPKeyPointer::ParseKeyResult (EVPKeyPointer (key));
16871713 }
16881714
16891715 return ParseKeyResult (PKParseError::FAILED);
16901716}
16911717
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+
16921741EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey (
1693- PKFormatType format,
1694- PKEncodingType encoding,
1695- std::optional<Buffer<char >> maybe_passphrase,
1742+ const PrivateKeyEncodingConfig& config,
16961743 const Buffer<const unsigned char >& buffer) {
16971744
1698- static auto keyOrError = [& ](EVPKeyPointer pkey, bool had_passphrase = false ) {
1745+ static constexpr auto keyOrError = [](EVPKeyPointer pkey, bool had_passphrase = false ) {
16991746 if (int err = ERR_peek_error ()) {
17001747 if (ERR_GET_LIB (err) == ERR_LIB_PEM &&
17011748 ERR_GET_REASON (err) == PEM_R_BAD_PASSWORD_READ &&
@@ -1708,24 +1755,23 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17081755 return ParseKeyResult (std::move (pkey));
17091756 };
17101757
1711- Buffer<char >* passphrase = nullptr ;
1712- if (maybe_passphrase.has_value ()) {
1713- passphrase = &maybe_passphrase.value ();
1714- }
17151758
17161759 auto bio = BIOPointer::New (buffer);
17171760 if (!bio) return ParseKeyResult (PKParseError::FAILED);
17181761
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 ());
17221768 }
17231769
1724- if (format != PKFormatType::DER) {
1770+ if (config. format != PKFormatType::DER) {
17251771 return ParseKeyResult (PKParseError::FAILED);
17261772 }
17271773
1728- switch (encoding ) {
1774+ switch (config. type ) {
17291775 case PKEncodingType::PKCS1: {
17301776 auto key = d2i_PrivateKey_bio (bio.get (), nullptr );
17311777 return keyOrError (EVPKeyPointer (key));
@@ -1735,8 +1781,8 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17351781 auto key = d2i_PKCS8PrivateKey_bio (bio.get (),
17361782 nullptr ,
17371783 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 ());
17401786 }
17411787
17421788 PKCS8Pointer p8inf (d2i_PKCS8_PRIV_KEY_INFO_bio (bio.get (), nullptr ));
@@ -1755,4 +1801,166 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
17551801 };
17561802}
17571803
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+
17581966} // namespace ncrypto
0 commit comments