Skip to content

Commit

Permalink
src: move more openssl api detail behind ncrypto
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Mar 3, 2025
1 parent 1030f85 commit c5839c9
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 95 deletions.
48 changes: 32 additions & 16 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,7 @@ X509View X509View::From(const SSLCtxPointer& ctx) {
}

std::optional<std::string> X509View::getFingerprint(
const EVP_MD* method) const {
const Digest& method) const {
unsigned int md_size;
unsigned char md[EVP_MAX_MD_SIZE];
static constexpr char hex[] = "0123456789ABCDEF";
Expand Down Expand Up @@ -1692,8 +1692,11 @@ DataPointer hkdf(const Digest& md,
}

auto ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_HKDF);
// OpenSSL < 3.0.0 accepted only a void* as the argument of
// EVP_PKEY_CTX_set_hkdf_md.
const EVP_MD* md_ptr = md;
if (!ctx || !EVP_PKEY_derive_init(ctx.get()) ||
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), md) ||
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), md_ptr) ||
!EVP_PKEY_CTX_add1_hkdf_info(ctx.get(), info.data, info.len)) {
return {};
}
Expand Down Expand Up @@ -1776,7 +1779,7 @@ DataPointer scrypt(const Buffer<const char>& pass,
return {};
}

DataPointer pbkdf2(const EVP_MD* md,
DataPointer pbkdf2(const Digest& md,
const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
uint32_t iterations,
Expand Down Expand Up @@ -2728,6 +2731,17 @@ bool SSLCtxPointer::setGroups(const char* groups) {
return SSL_CTX_set1_groups_list(get(), groups) == 1;
}

bool SSLCtxPointer::setCipherSuites(std::string_view ciphers) {
#ifndef OPENSSL_IS_BORINGSSL
if (!ctx_) return false;
return SSL_CTX_set_ciphersuites(ctx_.get(), ciphers.data());
#else
// BoringSSL does not allow API config of TLS 1.3 cipher suites.
// We treat this as a non-op.
return true;
#endif
}

// ============================================================================

const Cipher Cipher::FromName(std::string_view name) {
Expand Down Expand Up @@ -3335,13 +3349,13 @@ bool EVPKeyCtxPointer::setEcParameters(int curve, int encoding) {
EVP_PKEY_CTX_set_ec_param_enc(ctx_.get(), encoding) == 1;
}

bool EVPKeyCtxPointer::setRsaOaepMd(const EVP_MD* md) {
if (md == nullptr || !ctx_) return false;
bool EVPKeyCtxPointer::setRsaOaepMd(const Digest& md) {
if (!md || !ctx_) return false;
return EVP_PKEY_CTX_set_rsa_oaep_md(ctx_.get(), md) > 0;
}

bool EVPKeyCtxPointer::setRsaMgf1Md(const EVP_MD* md) {
if (md == nullptr || !ctx_) return false;
bool EVPKeyCtxPointer::setRsaMgf1Md(const Digest& md) {
if (!md || !ctx_) return false;
return EVP_PKEY_CTX_set_rsa_mgf1_md(ctx_.get(), md) > 0;
}

Expand Down Expand Up @@ -3377,13 +3391,15 @@ bool EVPKeyCtxPointer::setRsaKeygenPubExp(BignumPointer&& e) {
return false;
}

bool EVPKeyCtxPointer::setRsaPssKeygenMd(const EVP_MD* md) {
if (md == nullptr || !ctx_) return false;
return EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx_.get(), md) > 0;
bool EVPKeyCtxPointer::setRsaPssKeygenMd(const Digest& md) {
if (!md || !ctx_) return false;
// OpenSSL < 3 accepts a void* for the md parameter.
const EVP_MD* md_ptr = md;
return EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx_.get(), md_ptr) > 0;
}

bool EVPKeyCtxPointer::setRsaPssKeygenMgf1Md(const EVP_MD* md) {
if (md == nullptr || !ctx_) return false;
bool EVPKeyCtxPointer::setRsaPssKeygenMgf1Md(const Digest& md) {
if (!md || !ctx_) return false;
return EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx_.get(), md) > 0;
}

Expand Down Expand Up @@ -3858,7 +3874,7 @@ EVP_MD_CTX* EVPMDCtxPointer::release() {
return ctx_.release();
}

bool EVPMDCtxPointer::digestInit(const EVP_MD* digest) {
bool EVPMDCtxPointer::digestInit(const Digest& digest) {
if (!ctx_) return false;
return EVP_DigestInit_ex(ctx_.get(), digest, nullptr) > 0;
}
Expand Down Expand Up @@ -3924,7 +3940,7 @@ bool EVPMDCtxPointer::copyTo(const EVPMDCtxPointer& other) const {
}

std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInit(const EVPKeyPointer& key,
const EVP_MD* digest) {
const Digest& digest) {
EVP_PKEY_CTX* ctx = nullptr;
if (!EVP_DigestSignInit(ctx_.get(), &ctx, digest, nullptr, key.get())) {
return std::nullopt;
Expand All @@ -3933,7 +3949,7 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInit(const EVPKeyPointer& key,
}

std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInit(
const EVPKeyPointer& key, const EVP_MD* digest) {
const EVPKeyPointer& key, const Digest& digest) {
EVP_PKEY_CTX* ctx = nullptr;
if (!EVP_DigestVerifyInit(ctx_.get(), &ctx, digest, nullptr, key.get())) {
return std::nullopt;
Expand Down Expand Up @@ -4030,7 +4046,7 @@ HMAC_CTX* HMACCtxPointer::release() {
return ctx_.release();
}

bool HMACCtxPointer::init(const Buffer<const void>& buf, const EVP_MD* md) {
bool HMACCtxPointer::init(const Buffer<const void>& buf, const Digest& md) {
if (!ctx_) return false;
return HMAC_Init_ex(ctx_.get(), buf.data, buf.len, md, nullptr) == 1;
}
Expand Down
25 changes: 14 additions & 11 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ struct Buffer {

class Digest final {
public:
static constexpr size_t MAX_SIZE = EVP_MAX_MD_SIZE;
Digest() = default;
Digest(const EVP_MD* md) : md_(md) {}
Digest(const Digest&) = default;
Expand Down Expand Up @@ -353,7 +354,7 @@ class Cipher final {

struct CipherParams {
int padding;
const EVP_MD* digest;
Digest digest;
const Buffer<const void> label;
};

Expand Down Expand Up @@ -723,13 +724,13 @@ class EVPKeyCtxPointer final {
bool setDsaParameters(uint32_t bits, std::optional<int> q_bits);
bool setEcParameters(int curve, int encoding);

bool setRsaOaepMd(const EVP_MD* md);
bool setRsaMgf1Md(const EVP_MD* md);
bool setRsaOaepMd(const Digest& md);
bool setRsaMgf1Md(const Digest& md);
bool setRsaPadding(int padding);
bool setRsaKeygenPubExp(BignumPointer&& e);
bool setRsaKeygenBits(int bits);
bool setRsaPssKeygenMd(const EVP_MD* md);
bool setRsaPssKeygenMgf1Md(const EVP_MD* md);
bool setRsaPssKeygenMd(const Digest& md);
bool setRsaPssKeygenMgf1Md(const Digest& md);
bool setRsaPssSaltlen(int salt_len);
bool setRsaImplicitRejection();
bool setRsaOaepLabel(DataPointer&& data);
Expand Down Expand Up @@ -1003,6 +1004,8 @@ class SSLCtxPointer final {
SSL_CTX_set_tlsext_status_arg(get(), nullptr);
}

bool setCipherSuites(std::string_view ciphers);

static SSLCtxPointer NewServer();
static SSLCtxPointer NewClient();
static SSLCtxPointer New(const SSL_METHOD* method = TLS_method());
Expand Down Expand Up @@ -1131,7 +1134,7 @@ class X509View final {
bool checkPrivateKey(const EVPKeyPointer& pkey) const;
bool checkPublicKey(const EVPKeyPointer& pkey) const;

std::optional<std::string> getFingerprint(const EVP_MD* method) const;
std::optional<std::string> getFingerprint(const Digest& method) const;

X509Pointer clone() const;

Expand Down Expand Up @@ -1327,16 +1330,16 @@ class EVPMDCtxPointer final {
void reset(EVP_MD_CTX* ctx = nullptr);
EVP_MD_CTX* release();

bool digestInit(const EVP_MD* digest);
bool digestInit(const Digest& digest);
bool digestUpdate(const Buffer<const void>& in);
DataPointer digestFinal(size_t length);
bool digestFinalInto(Buffer<void>* buf);
size_t getExpectedSize();

std::optional<EVP_PKEY_CTX*> signInit(const EVPKeyPointer& key,
const EVP_MD* digest);
const Digest& digest);
std::optional<EVP_PKEY_CTX*> verifyInit(const EVPKeyPointer& key,
const EVP_MD* digest);
const Digest& digest);

DataPointer signOneShot(const Buffer<const unsigned char>& buf) const;
DataPointer sign(const Buffer<const unsigned char>& buf) const;
Expand Down Expand Up @@ -1371,7 +1374,7 @@ class HMACCtxPointer final {
void reset(HMAC_CTX* ctx = nullptr);
HMAC_CTX* release();

bool init(const Buffer<const void>& buf, const EVP_MD* md);
bool init(const Buffer<const void>& buf, const Digest& md);
bool update(const Buffer<const void>& buf);
DataPointer digest();
bool digestInto(Buffer<void>* buf);
Expand Down Expand Up @@ -1486,7 +1489,7 @@ DataPointer scrypt(const Buffer<const char>& pass,
uint64_t maxmem,
size_t length);

DataPointer pbkdf2(const EVP_MD* md,
DataPointer pbkdf2(const Digest& md,
const Buffer<const char>& pass,
const Buffer<const unsigned char>& salt,
uint32_t iterations,
Expand Down
42 changes: 17 additions & 25 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ namespace node {

using ncrypto::BignumPointer;
using ncrypto::BIOPointer;
using ncrypto::Cipher;
using ncrypto::ClearErrorOnReturn;
using ncrypto::CryptoErrorList;
using ncrypto::DHPointer;
using ncrypto::Digest;
#ifndef OPENSSL_NO_ENGINE
using ncrypto::EnginePointer;
#endif // !OPENSSL_NO_ENGINE
Expand Down Expand Up @@ -1440,8 +1442,6 @@ void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) {
}

void SecureContext::SetCipherSuites(const FunctionCallbackInfo<Value>& args) {
// BoringSSL doesn't allow API config of TLS1.3 cipher suites.
#ifndef OPENSSL_IS_BORINGSSL
SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, args.This());
Environment* env = sc->env();
Expand All @@ -1451,9 +1451,9 @@ void SecureContext::SetCipherSuites(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());

const Utf8Value ciphers(env->isolate(), args[0]);
if (!SSL_CTX_set_ciphersuites(sc->ctx_.get(), *ciphers))
if (!sc->ctx_.setCipherSuites(ciphers.ToStringView())) {
return ThrowCryptoError(env, ERR_get_error(), "Failed to set ciphers");
#endif
}
}

void SecureContext::SetCiphers(const FunctionCallbackInfo<Value>& args) {
Expand Down Expand Up @@ -1932,25 +1932,14 @@ int SecureContext::TicketKeyCallback(SSL* ssl,
}

ArrayBufferViewContents<unsigned char> hmac_buf(hmac);
HMAC_Init_ex(hctx,
hmac_buf.data(),
hmac_buf.length(),
EVP_sha256(),
nullptr);
HMAC_Init_ex(
hctx, hmac_buf.data(), hmac_buf.length(), Digest::SHA256, nullptr);

ArrayBufferViewContents<unsigned char> aes_key(aes.As<ArrayBufferView>());
if (enc) {
EVP_EncryptInit_ex(ectx,
EVP_aes_128_cbc(),
nullptr,
aes_key.data(),
iv);
EVP_EncryptInit_ex(ectx, Cipher::AES_128_CBC, nullptr, aes_key.data(), iv);
} else {
EVP_DecryptInit_ex(ectx,
EVP_aes_128_cbc(),
nullptr,
aes_key.data(),
iv);
EVP_DecryptInit_ex(ectx, Cipher::AES_128_CBC, nullptr, aes_key.data(), iv);
}

return r;
Expand All @@ -1969,11 +1958,11 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_));
if (!ncrypto::CSPRNG(iv, 16) ||
EVP_EncryptInit_ex(
ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, iv) <= 0 ||
ectx, Cipher::AES_128_CBC, nullptr, sc->ticket_key_aes_, iv) <= 0 ||
HMAC_Init_ex(hctx,
sc->ticket_key_hmac_,
sizeof(sc->ticket_key_hmac_),
EVP_sha256(),
Digest::SHA256,
nullptr) <= 0) {
return -1;
}
Expand All @@ -1985,10 +1974,13 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
return 0;
}

if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_,
iv) <= 0 ||
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_),
EVP_sha256(), nullptr) <= 0) {
if (EVP_DecryptInit_ex(
ectx, Cipher::AES_128_CBC, nullptr, sc->ticket_key_aes_, iv) <= 0 ||
HMAC_Init_ex(hctx,
sc->ticket_key_hmac_,
sizeof(sc->ticket_key_hmac_),
Digest::SHA256,
nullptr) <= 0) {
return -1;
}
return 1;
Expand Down
11 changes: 6 additions & 5 deletions src/crypto/crypto_hmac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace node {

using ncrypto::Digest;
using ncrypto::HMACCtxPointer;
using v8::Boolean;
using v8::FunctionCallbackInfo;
Expand Down Expand Up @@ -70,8 +71,8 @@ void Hmac::New(const FunctionCallbackInfo<Value>& args) {
void Hmac::HmacInit(const char* hash_type, const char* key, int key_len) {
HandleScope scope(env()->isolate());

const EVP_MD* md = ncrypto::getDigestByName(hash_type);
if (md == nullptr) [[unlikely]] {
Digest md = Digest::FromName(hash_type);
if (!md) [[unlikely]] {
return THROW_ERR_CRYPTO_INVALID_DIGEST(
env(), "Invalid digest: %s", hash_type);
}
Expand Down Expand Up @@ -130,7 +131,7 @@ void Hmac::HmacDigest(const FunctionCallbackInfo<Value>& args) {
encoding = ParseEncoding(env->isolate(), args[0], BUFFER);
}

unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned char md_value[Digest::MAX_SIZE];
ncrypto::Buffer<void> buf{
.data = md_value,
.len = sizeof(md_value),
Expand Down Expand Up @@ -199,8 +200,8 @@ Maybe<void> HmacTraits::AdditionalConfig(
CHECK(args[offset + 2]->IsObject()); // Key

Utf8Value digest(env->isolate(), args[offset + 1]);
params->digest = ncrypto::getDigestByName(digest.ToStringView());
if (params->digest == nullptr) [[unlikely]] {
params->digest = Digest::FromName(digest.ToStringView());
if (!params->digest) [[unlikely]] {
THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest);
return Nothing<void>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/crypto_hmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ struct HmacConfig final : public MemoryRetainer {
KeyObjectData key;
ByteSource data;
ByteSource signature;
const EVP_MD* digest;
ncrypto::Digest digest;

HmacConfig() = default;

Expand Down
5 changes: 3 additions & 2 deletions src/crypto/crypto_pbkdf2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

namespace node {

using ncrypto::Digest;
using v8::FunctionCallbackInfo;
using v8::Int32;
using v8::JustVoid;
Expand Down Expand Up @@ -100,8 +101,8 @@ Maybe<void> PBKDF2Traits::AdditionalConfig(
}

Utf8Value name(args.GetIsolate(), args[offset + 4]);
params->digest = ncrypto::getDigestByName(name.ToStringView());
if (params->digest == nullptr) [[unlikely]] {
params->digest = Digest::FromName(name.ToStringView());
if (!params->digest) [[unlikely]] {
THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *name);
return Nothing<void>();
}
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/crypto_pbkdf2.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct PBKDF2Config final : public MemoryRetainer {
ByteSource salt;
int32_t iterations;
int32_t length;
const EVP_MD* digest = nullptr;
ncrypto::Digest digest;

PBKDF2Config() = default;

Expand Down
Loading

0 comments on commit c5839c9

Please sign in to comment.