Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0302efe

Browse filesBrowse files
jasnelladuh95
authored andcommitted
src: move more key related stuff to ncrypto
PR-URL: #55368 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 7ce7eab commit 0302efe
Copy full SHA for 0302efe

File tree

Expand file treeCollapse file tree

7 files changed

+467
-375
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

7 files changed

+467
-375
lines changed
Open diff view settings
Collapse file

‎deps/ncrypto/ncrypto.cc‎

Copy file name to clipboardExpand all lines: deps/ncrypto/ncrypto.cc
+230-22Lines changed: 230 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ std::optional<std::string> CryptoErrorList::pop_front() {
8080

8181
// ============================================================================
8282
DataPointer DataPointer::Alloc(size_t len) {
83-
return DataPointer(OPENSSL_malloc(len), len);
83+
return DataPointer(OPENSSL_zalloc(len), len);
8484
}
8585

8686
DataPointer::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+
14311458
EVPKeyPointer EVPKeyPointer::New() {
14321459
return EVPKeyPointer(EVP_PKEY_new());
14331460
}
@@ -1661,41 +1688,61 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM(
16611688
}
16621689

16631690
EVPKeyPointer::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+
16921741
EVPKeyPointer::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
Collapse file

‎deps/ncrypto/ncrypto.h‎

Copy file name to clipboardExpand all lines: deps/ncrypto/ncrypto.h
+28-8Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -386,13 +386,13 @@ class EVPKeyPointer final {
386386
// SubjectPublicKeyInfo according to X.509.
387387
SPKI,
388388
// ECPrivateKey according to SEC1.
389-
SEC1
389+
SEC1,
390390
};
391391

392392
enum class PKFormatType {
393393
DER,
394394
PEM,
395-
JWK
395+
JWK,
396396
};
397397

398398
enum class PKParseError {
@@ -402,18 +402,36 @@ class EVPKeyPointer final {
402402
};
403403
using ParseKeyResult = Result<EVPKeyPointer, PKParseError>;
404404

405+
struct AsymmetricKeyEncodingConfig {
406+
bool output_key_object = false;
407+
PKFormatType format = PKFormatType::DER;
408+
PKEncodingType type = PKEncodingType::PKCS8;
409+
AsymmetricKeyEncodingConfig() = default;
410+
AsymmetricKeyEncodingConfig(bool output_key_object, PKFormatType format, PKEncodingType type);
411+
AsymmetricKeyEncodingConfig(const AsymmetricKeyEncodingConfig&) = default;
412+
AsymmetricKeyEncodingConfig& operator=(const AsymmetricKeyEncodingConfig&) = default;
413+
};
414+
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
415+
416+
struct PrivateKeyEncodingConfig: public AsymmetricKeyEncodingConfig {
417+
const EVP_CIPHER* cipher = nullptr;
418+
std::optional<DataPointer> passphrase = std::nullopt;
419+
PrivateKeyEncodingConfig() = default;
420+
PrivateKeyEncodingConfig(bool output_key_object, PKFormatType format, PKEncodingType type)
421+
: AsymmetricKeyEncodingConfig(output_key_object, format, type) {}
422+
PrivateKeyEncodingConfig(const PrivateKeyEncodingConfig&);
423+
PrivateKeyEncodingConfig& operator=(const PrivateKeyEncodingConfig&);
424+
};
425+
405426
static ParseKeyResult TryParsePublicKey(
406-
PKFormatType format,
407-
PKEncodingType encoding,
427+
const PublicKeyEncodingConfig& config,
408428
const Buffer<const unsigned char>& buffer);
409429

410430
static ParseKeyResult TryParsePublicKeyPEM(
411431
const Buffer<const unsigned char>& buffer);
412432

413433
static ParseKeyResult TryParsePrivateKey(
414-
PKFormatType format,
415-
PKEncodingType encoding,
416-
std::optional<Buffer<char>> passphrase,
434+
const PrivateKeyEncodingConfig& config,
417435
const Buffer<const unsigned char>& buffer);
418436

419437
EVPKeyPointer() = default;
@@ -441,9 +459,11 @@ class EVPKeyPointer final {
441459
size_t rawPrivateKeySize() const;
442460
DataPointer rawPublicKey() const;
443461
DataPointer rawPrivateKey() const;
444-
445462
BIOPointer derPublicKey() const;
446463

464+
Result<BIOPointer, bool> writePrivateKey(const PrivateKeyEncodingConfig& config) const;
465+
Result<BIOPointer, bool> writePublicKey(const PublicKeyEncodingConfig& config) const;
466+
447467
EVPKeyCtxPointer newCtx() const;
448468

449469
static bool IsRSAPrivateKey(const Buffer<const unsigned char>& buffer);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.