Skip to content

Commit 3a1485a

Browse files
jasnelltargos
authored andcommitted
src: move evp stuff to ncrypto
PR-URL: #54911 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent d99ae54 commit 3a1485a

File tree

11 files changed

+492
-262
lines changed

11 files changed

+492
-262
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,4 +1425,213 @@ DataPointer pbkdf2(const EVP_MD* md,
14251425
return {};
14261426
}
14271427

1428+
// ============================================================================
1429+
1430+
EVPKeyPointer EVPKeyPointer::New() {
1431+
return EVPKeyPointer(EVP_PKEY_new());
1432+
}
1433+
1434+
EVPKeyPointer EVPKeyPointer::NewRawPublic(int id, const Buffer<const unsigned char>& data) {
1435+
if (id == 0) return {};
1436+
return EVPKeyPointer(EVP_PKEY_new_raw_public_key(id, nullptr, data.data, data.len));
1437+
}
1438+
1439+
EVPKeyPointer EVPKeyPointer::NewRawPrivate(int id, const Buffer<const unsigned char>& data) {
1440+
if (id == 0) return {};
1441+
return EVPKeyPointer(EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len));
1442+
}
1443+
1444+
EVPKeyPointer::EVPKeyPointer(EVP_PKEY* pkey) : pkey_(pkey) {}
1445+
1446+
EVPKeyPointer::EVPKeyPointer(EVPKeyPointer&& other) noexcept
1447+
: pkey_(other.release()) {}
1448+
1449+
EVPKeyPointer& EVPKeyPointer::operator=(EVPKeyPointer&& other) noexcept {
1450+
if (this == &other) return *this;
1451+
this->~EVPKeyPointer();
1452+
return *new (this) EVPKeyPointer(std::move(other));
1453+
}
1454+
1455+
EVPKeyPointer::~EVPKeyPointer() { reset(); }
1456+
1457+
void EVPKeyPointer::reset(EVP_PKEY* pkey) {
1458+
pkey_.reset(pkey);
1459+
}
1460+
1461+
EVP_PKEY* EVPKeyPointer::release() {
1462+
return pkey_.release();
1463+
}
1464+
1465+
int EVPKeyPointer::id(const EVP_PKEY* key) {
1466+
if (key == nullptr) return 0;
1467+
return EVP_PKEY_id(key);
1468+
}
1469+
1470+
int EVPKeyPointer::base_id(const EVP_PKEY* key) {
1471+
if (key == nullptr) return 0;
1472+
return EVP_PKEY_base_id(key);
1473+
}
1474+
1475+
int EVPKeyPointer::id() const {
1476+
return id(get());
1477+
}
1478+
1479+
int EVPKeyPointer::base_id() const {
1480+
return base_id(get());
1481+
}
1482+
1483+
int EVPKeyPointer::bits() const {
1484+
if (get() == nullptr) return 0;
1485+
return EVP_PKEY_bits(get());
1486+
}
1487+
1488+
size_t EVPKeyPointer::size() const {
1489+
if (get() == nullptr) return 0;
1490+
return EVP_PKEY_size(get());
1491+
}
1492+
1493+
EVPKeyCtxPointer EVPKeyPointer::newCtx() const {
1494+
if (!pkey_) return {};
1495+
return EVPKeyCtxPointer(EVP_PKEY_CTX_new(get(), nullptr));
1496+
}
1497+
1498+
size_t EVPKeyPointer::rawPublicKeySize() const {
1499+
if (!pkey_) return 0;
1500+
size_t len = 0;
1501+
if (EVP_PKEY_get_raw_public_key(get(), nullptr, &len) == 1) return len;
1502+
return 0;
1503+
}
1504+
1505+
size_t EVPKeyPointer::rawPrivateKeySize() const {
1506+
if (!pkey_) return 0;
1507+
size_t len = 0;
1508+
if (EVP_PKEY_get_raw_private_key(get(), nullptr, &len) == 1) return len;
1509+
return 0;
1510+
}
1511+
1512+
DataPointer EVPKeyPointer::rawPublicKey() const {
1513+
if (!pkey_) return {};
1514+
if (auto data = DataPointer::Alloc(rawPublicKeySize())) {
1515+
const Buffer<unsigned char> buf = data;
1516+
size_t len = data.size();
1517+
if (EVP_PKEY_get_raw_public_key(get(),
1518+
buf.data,
1519+
&len) != 1) return {};
1520+
return data;
1521+
}
1522+
return {};
1523+
}
1524+
1525+
DataPointer EVPKeyPointer::rawPrivateKey() const {
1526+
if (!pkey_) return {};
1527+
if (auto data = DataPointer::Alloc(rawPrivateKeySize())) {
1528+
const Buffer<unsigned char> buf = data;
1529+
size_t len = data.size();
1530+
if (EVP_PKEY_get_raw_private_key(get(),
1531+
buf.data,
1532+
&len) != 1) return {};
1533+
return data;
1534+
}
1535+
return {};
1536+
}
1537+
1538+
BIOPointer EVPKeyPointer::derPublicKey() const {
1539+
if (!pkey_) return {};
1540+
auto bio = BIOPointer::NewMem();
1541+
if (!bio) return {};
1542+
if (!i2d_PUBKEY_bio(bio.get(), get())) return {};
1543+
return bio;
1544+
}
1545+
1546+
namespace {
1547+
EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(
1548+
const BIOPointer& bp,
1549+
const char* name,
1550+
auto&& parse) {
1551+
if (!bp.resetBio()) {
1552+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1553+
}
1554+
unsigned char* der_data;
1555+
long der_len;
1556+
1557+
// This skips surrounding data and decodes PEM to DER.
1558+
{
1559+
MarkPopErrorOnReturn mark_pop_error_on_return;
1560+
if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name,
1561+
bp.get(), nullptr, nullptr) != 1)
1562+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
1563+
}
1564+
DataPointer data(der_data, der_len);
1565+
1566+
// OpenSSL might modify the pointer, so we need to make a copy before parsing.
1567+
const unsigned char* p = der_data;
1568+
EVPKeyPointer pkey(parse(&p, der_len));
1569+
if (!pkey) return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1570+
return EVPKeyPointer::ParseKeyResult(std::move(pkey));
1571+
}
1572+
1573+
EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM(
1574+
const Buffer<const unsigned char>& buffer) {
1575+
auto bp = BIOPointer::New(buffer.data, buffer.len);
1576+
if (!bp)
1577+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1578+
1579+
// Try parsing as SubjectPublicKeyInfo (SPKI) first.
1580+
if (auto ret = TryParsePublicKeyInner(bp, "PUBLIC KEY",
1581+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1582+
return d2i_PUBKEY(nullptr, p, l);
1583+
})) {
1584+
return ret;
1585+
}
1586+
1587+
// Maybe it is PKCS#1.
1588+
if (auto ret = TryParsePublicKeyInner(bp, "RSA PUBLIC KEY",
1589+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1590+
return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l);
1591+
})) {
1592+
return ret;
1593+
}
1594+
1595+
// X.509 fallback.
1596+
if (auto ret = TryParsePublicKeyInner(bp, "CERTIFICATE",
1597+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1598+
X509Pointer x509(d2i_X509(nullptr, p, l));
1599+
return x509 ? X509_get_pubkey(x509.get()) : nullptr;
1600+
})) {
1601+
return ret;
1602+
};
1603+
1604+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
1605+
}
1606+
} // namespace
1607+
1608+
EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey(
1609+
PKFormatType format,
1610+
PKEncodingType encoding,
1611+
const Buffer<const unsigned char>& buffer) {
1612+
if (format == PKFormatType::PEM) {
1613+
return TryParsePublicKeyPEM(buffer);
1614+
}
1615+
1616+
if (format != PKFormatType::DER) {
1617+
return ParseKeyResult(PKParseError::FAILED);
1618+
}
1619+
1620+
const unsigned char* start = buffer.data;
1621+
1622+
EVP_PKEY* key = nullptr;
1623+
1624+
if (encoding == PKEncodingType::PKCS1 &&
1625+
(key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &start, buffer.len))) {
1626+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
1627+
}
1628+
1629+
if (encoding == PKEncodingType::SPKI &&
1630+
(key = d2i_PUBKEY(nullptr, &start, buffer.len))) {
1631+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
1632+
}
1633+
1634+
return ParseKeyResult(PKParseError::FAILED);
1635+
}
1636+
14281637
} // namespace ncrypto

deps/ncrypto/ncrypto.h

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,16 @@ class MarkPopErrorOnReturn final {
172172
CryptoErrorList* errors_;
173173
};
174174

175+
// TODO(@jasnell): Eventually replace with std::expected when we are able to
176+
// bump up to c++23.
175177
template <typename T, typename E>
176178
struct Result final {
179+
const bool has_value;
177180
T value;
178181
std::optional<E> error;
179-
Result(T&& value) : value(std::move(value)) {}
180-
Result(E&& error) : error(std::move(error)) {}
182+
Result(T&& value) : has_value(true), value(std::move(value)) {}
183+
Result(E&& error) : has_value(false), error(std::move(error)) {}
184+
inline operator bool() const { return has_value; }
181185
};
182186

183187
// ============================================================================
@@ -202,7 +206,6 @@ using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
202206
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
203207
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
204208
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
205-
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
206209
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
207210
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
208211
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
@@ -252,9 +255,10 @@ class DataPointer final {
252255
Buffer<void> release();
253256

254257
// Returns a Buffer struct that is a view of the underlying data.
255-
inline operator const Buffer<void>() const {
258+
template <typename T = void>
259+
inline operator const Buffer<T>() const {
256260
return {
257-
.data = data_,
261+
.data = static_cast<T*>(data_),
258262
.len = len_,
259263
};
260264
}
@@ -359,6 +363,75 @@ class BignumPointer final {
359363
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
360364
};
361365

366+
class EVPKeyPointer final {
367+
public:
368+
static EVPKeyPointer New();
369+
static EVPKeyPointer NewRawPublic(int id, const Buffer<const unsigned char>& data);
370+
static EVPKeyPointer NewRawPrivate(int id, const Buffer<const unsigned char>& data);
371+
372+
enum class PKEncodingType {
373+
// RSAPublicKey / RSAPrivateKey according to PKCS#1.
374+
PKCS1,
375+
// PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
376+
PKCS8,
377+
// SubjectPublicKeyInfo according to X.509.
378+
SPKI,
379+
// ECPrivateKey according to SEC1.
380+
SEC1
381+
};
382+
383+
enum class PKFormatType {
384+
DER,
385+
PEM,
386+
JWK
387+
};
388+
389+
enum class PKParseError {
390+
NOT_RECOGNIZED,
391+
NEED_PASSPHRASE,
392+
FAILED
393+
};
394+
using ParseKeyResult = Result<EVPKeyPointer, PKParseError>;
395+
396+
static ParseKeyResult TryParsePublicKey(
397+
PKFormatType format,
398+
PKEncodingType encoding,
399+
const Buffer<const unsigned char>& buffer);
400+
401+
EVPKeyPointer() = default;
402+
explicit EVPKeyPointer(EVP_PKEY* pkey);
403+
EVPKeyPointer(EVPKeyPointer&& other) noexcept;
404+
EVPKeyPointer& operator=(EVPKeyPointer&& other) noexcept;
405+
NCRYPTO_DISALLOW_COPY(EVPKeyPointer)
406+
~EVPKeyPointer();
407+
408+
inline bool operator==(std::nullptr_t) const noexcept { return pkey_ == nullptr; }
409+
inline operator bool() const { return pkey_ != nullptr; }
410+
inline EVP_PKEY* get() const { return pkey_.get(); }
411+
void reset(EVP_PKEY* pkey = nullptr);
412+
EVP_PKEY* release();
413+
414+
static int id(const EVP_PKEY* key);
415+
static int base_id(const EVP_PKEY* key);
416+
417+
int id() const;
418+
int base_id() const;
419+
int bits() const;
420+
size_t size() const;
421+
422+
size_t rawPublicKeySize() const;
423+
size_t rawPrivateKeySize() const;
424+
DataPointer rawPublicKey() const;
425+
DataPointer rawPrivateKey() const;
426+
427+
BIOPointer derPublicKey() const;
428+
429+
EVPKeyCtxPointer newCtx() const;
430+
431+
private:
432+
DeleteFnPtr<EVP_PKEY, EVP_PKEY_free> pkey_;
433+
};
434+
362435
class DHPointer final {
363436
public:
364437

src/crypto/crypto_cipher.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,7 @@ bool PublicKeyCipher::Cipher(
996996
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
997997
const ArrayBufferOrViewContents<unsigned char>& data,
998998
std::unique_ptr<BackingStore>* out) {
999-
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
999+
EVPKeyCtxPointer ctx = pkey.newCtx();
10001000
if (!ctx)
10011001
return false;
10021002
if (EVP_PKEY_cipher_init(ctx.get()) <= 0)
@@ -1072,7 +1072,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
10721072

10731073
if (EVP_PKEY_cipher == EVP_PKEY_decrypt &&
10741074
operation == PublicKeyCipher::kPrivate && padding == RSA_PKCS1_PADDING) {
1075-
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
1075+
EVPKeyCtxPointer ctx = pkey.newCtx();
10761076
CHECK(ctx);
10771077

10781078
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {

src/crypto/crypto_common.cc

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -449,15 +449,14 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
449449
Local<Context> context = env->context();
450450
crypto::EVPKeyPointer key(raw_key);
451451

452-
int kid = EVP_PKEY_id(key.get());
453-
int bits = EVP_PKEY_bits(key.get());
452+
int kid = key.id();
454453
switch (kid) {
455454
case EVP_PKEY_DH:
456455
if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
457456
!Set<Integer>(context,
458-
info,
459-
env->size_string(),
460-
Integer::New(env->isolate(), bits))) {
457+
info,
458+
env->size_string(),
459+
Integer::New(env->isolate(), key.bits()))) {
461460
return MaybeLocal<Object>();
462461
}
463462
break;
@@ -473,18 +472,16 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
473472
} else {
474473
curve_name = OBJ_nid2sn(kid);
475474
}
476-
if (!Set<String>(context,
477-
info,
478-
env->type_string(),
479-
env->ecdh_string()) ||
475+
if (!Set<String>(
476+
context, info, env->type_string(), env->ecdh_string()) ||
480477
!Set<String>(context,
481-
info,
482-
env->name_string(),
483-
OneByteString(env->isolate(), curve_name)) ||
478+
info,
479+
env->name_string(),
480+
OneByteString(env->isolate(), curve_name)) ||
484481
!Set<Integer>(context,
485-
info,
486-
env->size_string(),
487-
Integer::New(env->isolate(), bits))) {
482+
info,
483+
env->size_string(),
484+
Integer::New(env->isolate(), key.bits()))) {
488485
return MaybeLocal<Object>();
489486
}
490487
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy