@@ -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,154 @@ 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+ const RSA* rsa = EVP_PKEY_get0_RSA (get ());
1824+ switch (config.format ) {
1825+ case PKFormatType::PEM: {
1826+ err = PEM_write_bio_RSAPrivateKey (bio.get (), rsa, config.cipher ,
1827+ reinterpret_cast <unsigned char *>(passphrase.data ),
1828+ passphrase.len , nullptr , nullptr ) != 1 ;
1829+ break ;
1830+ }
1831+ case PKFormatType::DER: {
1832+ // Encoding PKCS1 as DER. This variation does not permit encryption.
1833+ err = i2d_RSAPrivateKey_bio (bio.get (), rsa) != 1 ;
1834+ break ;
1835+ }
1836+ default : {
1837+ // Should never get here.
1838+ return Result<BIOPointer, bool >(false );
1839+ }
1840+ }
1841+ break ;
1842+ }
1843+ case PKEncodingType::PKCS8: {
1844+ switch (config.format ) {
1845+ case PKFormatType::PEM: {
1846+ // Encode PKCS#8 as PEM.
1847+ err = PEM_write_bio_PKCS8PrivateKey (
1848+ bio.get (), get (),
1849+ config.cipher ,
1850+ passphrase.data ,
1851+ passphrase.len ,
1852+ nullptr , nullptr ) != 1 ;
1853+ break ;
1854+ }
1855+ case PKFormatType::DER: {
1856+ err = i2d_PKCS8PrivateKey_bio (
1857+ bio.get (), get (),
1858+ config.cipher ,
1859+ passphrase.data ,
1860+ passphrase.len ,
1861+ nullptr , nullptr ) != 1 ;
1862+ break ;
1863+ }
1864+ default : {
1865+ // Should never get here.
1866+ return Result<BIOPointer, bool >(false );
1867+ }
1868+ }
1869+ break ;
1870+ }
1871+ case PKEncodingType::SEC1: {
1872+ // SEC1 is only permitted for EC keys
1873+ if (id () != EVP_PKEY_EC) return Result<BIOPointer, bool >(false );
1874+
1875+ const EC_KEY* ec = EVP_PKEY_get0_EC_KEY (get ());
1876+ switch (config.format ) {
1877+ case PKFormatType::PEM: {
1878+ err = PEM_write_bio_ECPrivateKey (bio.get (),
1879+ ec,
1880+ config.cipher ,
1881+ reinterpret_cast <unsigned char *>(passphrase.data ),
1882+ passphrase.len ,
1883+ nullptr ,
1884+ nullptr ) != 1 ;
1885+ break ;
1886+ }
1887+ case PKFormatType::DER: {
1888+ // Encoding SEC1 as DER. This variation does not permit encryption.
1889+ err = i2d_ECPrivateKey_bio (bio.get (), ec) != 1 ;
1890+ break ;
1891+ }
1892+ default : {
1893+ // Should never get here.
1894+ return Result<BIOPointer, bool >(false );
1895+ }
1896+ }
1897+ break ;
1898+ }
1899+ default : {
1900+ // Not a valid private key encoding
1901+ return Result<BIOPointer, bool >(false );
1902+ }
1903+ }
1904+
1905+ if (err) {
1906+ // Failed to encode the private key.
1907+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1908+ }
1909+
1910+ return bio;
1911+ }
1912+
1913+ Result<BIOPointer, bool > EVPKeyPointer::writePublicKey (
1914+ const ncrypto::EVPKeyPointer::PublicKeyEncodingConfig& config) const {
1915+ auto bio = BIOPointer::NewMem ();
1916+ if (!bio) return Result<BIOPointer, bool >(false );
1917+
1918+ MarkPopErrorOnReturn mark_pop_error_on_return;
1919+
1920+ if (config.type == ncrypto::EVPKeyPointer::PKEncodingType::PKCS1) {
1921+ // PKCS#1 is only valid for RSA keys.
1922+ const RSA* rsa = EVP_PKEY_get0_RSA (get ());
1923+ if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
1924+ // Encode PKCS#1 as PEM.
1925+ if (PEM_write_bio_RSAPublicKey (bio.get (), rsa) != 1 ) {
1926+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1927+ }
1928+ return bio;
1929+ }
1930+
1931+ // Encode PKCS#1 as DER.
1932+ if (i2d_RSAPublicKey_bio (bio.get (), rsa) != 1 ) {
1933+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1934+ }
1935+ return bio;
1936+ }
1937+
1938+ if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
1939+ // Encode SPKI as PEM.
1940+ if (PEM_write_bio_PUBKEY (bio.get (), get ()) != 1 ) {
1941+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1942+ }
1943+ return bio;
1944+ }
1945+
1946+ // Encode SPKI as DER.
1947+ if (i2d_PUBKEY_bio (bio.get (), get ()) != 1 ) {
1948+ return Result<BIOPointer, bool >(false , mark_pop_error_on_return.peekError ());
1949+ }
1950+ return bio;
1951+ }
1952+
17571953} // namespace ncrypto
0 commit comments