Skip to content

Commit 143b9f4

Browse files
committed
src: move evp stuff to ncrypto
1 parent 6cc4d5f commit 143b9f4

File tree

11 files changed

+492
-261
lines changed

11 files changed

+492
-261
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,4 +1384,213 @@ DataPointer pbkdf2(const EVP_MD* md,
13841384
return {};
13851385
}
13861386

1387+
// ============================================================================
1388+
1389+
EVPKeyPointer EVPKeyPointer::New() {
1390+
return EVPKeyPointer(EVP_PKEY_new());
1391+
}
1392+
1393+
EVPKeyPointer EVPKeyPointer::NewRawPublic(int id, const Buffer<const unsigned char>& data) {
1394+
if (id == 0) return {};
1395+
return EVPKeyPointer(EVP_PKEY_new_raw_public_key(id, nullptr, data.data, data.len));
1396+
}
1397+
1398+
EVPKeyPointer EVPKeyPointer::NewRawPrivate(int id, const Buffer<const unsigned char>& data) {
1399+
if (id == 0) return {};
1400+
return EVPKeyPointer(EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len));
1401+
}
1402+
1403+
EVPKeyPointer::EVPKeyPointer(EVP_PKEY* pkey) : pkey_(pkey) {}
1404+
1405+
EVPKeyPointer::EVPKeyPointer(EVPKeyPointer&& other) noexcept
1406+
: pkey_(other.release()) {}
1407+
1408+
EVPKeyPointer& EVPKeyPointer::operator=(EVPKeyPointer&& other) noexcept {
1409+
if (this == &other) return *this;
1410+
this->~EVPKeyPointer();
1411+
return *new (this) EVPKeyPointer(std::move(other));
1412+
}
1413+
1414+
EVPKeyPointer::~EVPKeyPointer() { reset(); }
1415+
1416+
void EVPKeyPointer::reset(EVP_PKEY* pkey) {
1417+
pkey_.reset(pkey);
1418+
}
1419+
1420+
EVP_PKEY* EVPKeyPointer::release() {
1421+
return pkey_.release();
1422+
}
1423+
1424+
int EVPKeyPointer::id(const EVP_PKEY* key) {
1425+
if (key == nullptr) return 0;
1426+
return EVP_PKEY_id(key);
1427+
}
1428+
1429+
int EVPKeyPointer::base_id(const EVP_PKEY* key) {
1430+
if (key == nullptr) return 0;
1431+
return EVP_PKEY_base_id(key);
1432+
}
1433+
1434+
int EVPKeyPointer::id() const {
1435+
return id(get());
1436+
}
1437+
1438+
int EVPKeyPointer::base_id() const {
1439+
return base_id(get());
1440+
}
1441+
1442+
int EVPKeyPointer::bits() const {
1443+
if (get() == nullptr) return 0;
1444+
return EVP_PKEY_bits(get());
1445+
}
1446+
1447+
size_t EVPKeyPointer::size() const {
1448+
if (get() == nullptr) return 0;
1449+
return EVP_PKEY_size(get());
1450+
}
1451+
1452+
EVPKeyCtxPointer EVPKeyPointer::newCtx() const {
1453+
if (!pkey_) return {};
1454+
return EVPKeyCtxPointer(EVP_PKEY_CTX_new(get(), nullptr));
1455+
}
1456+
1457+
size_t EVPKeyPointer::rawPublicKeySize() const {
1458+
if (!pkey_) return 0;
1459+
size_t len = 0;
1460+
if (EVP_PKEY_get_raw_public_key(get(), nullptr, &len) == 1) return len;
1461+
return 0;
1462+
}
1463+
1464+
size_t EVPKeyPointer::rawPrivateKeySize() const {
1465+
if (!pkey_) return 0;
1466+
size_t len = 0;
1467+
if (EVP_PKEY_get_raw_private_key(get(), nullptr, &len) == 1) return len;
1468+
return 0;
1469+
}
1470+
1471+
DataPointer EVPKeyPointer::rawPublicKey() const {
1472+
if (!pkey_) return {};
1473+
if (auto data = DataPointer::Alloc(rawPublicKeySize())) {
1474+
const Buffer<unsigned char> buf = data;
1475+
size_t len = data.size();
1476+
if (EVP_PKEY_get_raw_public_key(get(),
1477+
buf.data,
1478+
&len) != 1) return {};
1479+
return data;
1480+
}
1481+
return {};
1482+
}
1483+
1484+
DataPointer EVPKeyPointer::rawPrivateKey() const {
1485+
if (!pkey_) return {};
1486+
if (auto data = DataPointer::Alloc(rawPrivateKeySize())) {
1487+
const Buffer<unsigned char> buf = data;
1488+
size_t len = data.size();
1489+
if (EVP_PKEY_get_raw_private_key(get(),
1490+
buf.data,
1491+
&len) != 1) return {};
1492+
return data;
1493+
}
1494+
return {};
1495+
}
1496+
1497+
BIOPointer EVPKeyPointer::derPublicKey() const {
1498+
if (!pkey_) return {};
1499+
auto bio = BIOPointer::NewMem();
1500+
if (!bio) return {};
1501+
if (!i2d_PUBKEY_bio(bio.get(), get())) return {};
1502+
return bio;
1503+
}
1504+
1505+
namespace {
1506+
EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(
1507+
const BIOPointer& bp,
1508+
const char* name,
1509+
auto&& parse) {
1510+
if (!bp.resetBio()) {
1511+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1512+
}
1513+
unsigned char* der_data;
1514+
long der_len;
1515+
1516+
// This skips surrounding data and decodes PEM to DER.
1517+
{
1518+
MarkPopErrorOnReturn mark_pop_error_on_return;
1519+
if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name,
1520+
bp.get(), nullptr, nullptr) != 1)
1521+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
1522+
}
1523+
DataPointer data(der_data, der_len);
1524+
1525+
// OpenSSL might modify the pointer, so we need to make a copy before parsing.
1526+
const unsigned char* p = der_data;
1527+
EVPKeyPointer pkey(parse(&p, der_len));
1528+
if (!pkey) return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1529+
return EVPKeyPointer::ParseKeyResult(std::move(pkey));
1530+
}
1531+
1532+
EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM(
1533+
const Buffer<const unsigned char>& buffer) {
1534+
auto bp = BIOPointer::New(buffer.data, buffer.len);
1535+
if (!bp)
1536+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
1537+
1538+
// Try parsing as SubjectPublicKeyInfo (SPKI) first.
1539+
if (auto ret = TryParsePublicKeyInner(bp, "PUBLIC KEY",
1540+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1541+
return d2i_PUBKEY(nullptr, p, l);
1542+
})) {
1543+
return ret;
1544+
}
1545+
1546+
// Maybe it is PKCS#1.
1547+
if (auto ret = TryParsePublicKeyInner(bp, "RSA PUBLIC KEY",
1548+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1549+
return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l);
1550+
})) {
1551+
return ret;
1552+
}
1553+
1554+
// X.509 fallback.
1555+
if (auto ret = TryParsePublicKeyInner(bp, "CERTIFICATE",
1556+
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
1557+
X509Pointer x509(d2i_X509(nullptr, p, l));
1558+
return x509 ? X509_get_pubkey(x509.get()) : nullptr;
1559+
})) {
1560+
return ret;
1561+
};
1562+
1563+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
1564+
}
1565+
} // namespace
1566+
1567+
EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey(
1568+
PKFormatType format,
1569+
PKEncodingType encoding,
1570+
const Buffer<const unsigned char>& buffer) {
1571+
if (format == PKFormatType::PEM) {
1572+
return TryParsePublicKeyPEM(buffer);
1573+
}
1574+
1575+
if (format != PKFormatType::DER) {
1576+
return ParseKeyResult(PKParseError::FAILED);
1577+
}
1578+
1579+
const unsigned char* start = buffer.data;
1580+
1581+
EVP_PKEY* key = nullptr;
1582+
1583+
if (encoding == PKEncodingType::PKCS1 &&
1584+
(key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &start, buffer.len))) {
1585+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
1586+
}
1587+
1588+
if (encoding == PKEncodingType::SPKI &&
1589+
(key = d2i_PUBKEY(nullptr, &start, buffer.len))) {
1590+
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
1591+
}
1592+
1593+
return ParseKeyResult(PKParseError::FAILED);
1594+
}
1595+
13871596
} // 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
@@ -995,7 +995,7 @@ bool PublicKeyCipher::Cipher(
995995
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
996996
const ArrayBufferOrViewContents<unsigned char>& data,
997997
std::unique_ptr<BackingStore>* out) {
998-
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
998+
EVPKeyCtxPointer ctx = pkey.newCtx();
999999
if (!ctx)
10001000
return false;
10011001
if (EVP_PKEY_cipher_init(ctx.get()) <= 0)
@@ -1071,7 +1071,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
10711071

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

10771077
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)