Skip to content

Commit 3329efe

Browse files
committed
src: refine ncrypto more
An eventual goal for ncrypto is to completely abstract away details of working directly with openssl in order to make it easier to work with multiple different openssl/boringssl versions. As part of that we want to move away from direct reliance on specific openssl APIs in the runtime and instead go through the ncrypto abstractions. Not only does this help other runtimes trying to be compatible with Node.js, but it helps Node.js also by reducing the complexity of the crypto code in Node.js itself. PR-URL: nodejs#57300 Reviewed-By: Yagiz Nizipli <[email protected]>
1 parent 8f693f8 commit 3329efe

19 files changed

+486
-306
lines changed

deps/ncrypto/ncrypto.cc

+210-27
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ X509View X509View::From(const SSLCtxPointer& ctx) {
11641164
}
11651165

11661166
std::optional<std::string> X509View::getFingerprint(
1167-
const EVP_MD* method) const {
1167+
const Digest& method) const {
11681168
unsigned int md_size;
11691169
unsigned char md[EVP_MAX_MD_SIZE];
11701170
static constexpr char hex[] = "0123456789ABCDEF";
@@ -1669,17 +1669,17 @@ const EVP_CIPHER* getCipherByName(const std::string_view name) {
16691669
return EVP_get_cipherbyname(name.data());
16701670
}
16711671

1672-
bool checkHkdfLength(const EVP_MD* md, size_t length) {
1672+
bool checkHkdfLength(const Digest& md, size_t length) {
16731673
// HKDF-Expand computes up to 255 HMAC blocks, each having as many bits as
16741674
// the output of the hash function. 255 is a hard limit because HKDF appends
16751675
// an 8-bit counter to each HMAC'd message, starting at 1.
16761676
static constexpr size_t kMaxDigestMultiplier = 255;
1677-
size_t max_length = EVP_MD_size(md) * kMaxDigestMultiplier;
1677+
size_t max_length = md.size() * kMaxDigestMultiplier;
16781678
if (length > max_length) return false;
16791679
return true;
16801680
}
16811681

1682-
DataPointer hkdf(const EVP_MD* md,
1682+
DataPointer hkdf(const Digest& md,
16831683
const Buffer<const unsigned char>& key,
16841684
const Buffer<const unsigned char>& info,
16851685
const Buffer<const unsigned char>& salt,
@@ -1692,8 +1692,11 @@ DataPointer hkdf(const EVP_MD* md,
16921692
}
16931693

16941694
auto ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_HKDF);
1695+
// OpenSSL < 3.0.0 accepted only a void* as the argument of
1696+
// EVP_PKEY_CTX_set_hkdf_md.
1697+
const EVP_MD* md_ptr = md;
16951698
if (!ctx || !EVP_PKEY_derive_init(ctx.get()) ||
1696-
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), md) ||
1699+
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), md_ptr) ||
16971700
!EVP_PKEY_CTX_add1_hkdf_info(ctx.get(), info.data, info.len)) {
16981701
return {};
16991702
}
@@ -1703,7 +1706,7 @@ DataPointer hkdf(const EVP_MD* md,
17031706
if (salt.len > 0) {
17041707
actual_salt = {reinterpret_cast<const char*>(salt.data), salt.len};
17051708
} else {
1706-
actual_salt = {default_salt, static_cast<unsigned>(EVP_MD_size(md))};
1709+
actual_salt = {default_salt, static_cast<unsigned>(md.size())};
17071710
}
17081711

17091712
// We do not use EVP_PKEY_HKDF_MODE_EXTRACT_AND_EXPAND because and instead
@@ -1776,7 +1779,7 @@ DataPointer scrypt(const Buffer<const char>& pass,
17761779
return {};
17771780
}
17781781

1779-
DataPointer pbkdf2(const EVP_MD* md,
1782+
DataPointer pbkdf2(const Digest& md,
17801783
const Buffer<const char>& pass,
17811784
const Buffer<const unsigned char>& salt,
17821785
uint32_t iterations,
@@ -1788,12 +1791,13 @@ DataPointer pbkdf2(const EVP_MD* md,
17881791
}
17891792

17901793
auto dp = DataPointer::Alloc(length);
1794+
const EVP_MD* md_ptr = md;
17911795
if (dp && PKCS5_PBKDF2_HMAC(pass.data,
17921796
pass.len,
17931797
salt.data,
17941798
salt.len,
17951799
iterations,
1796-
md,
1800+
md_ptr,
17971801
length,
17981802
reinterpret_cast<unsigned char*>(dp.get()))) {
17991803
return dp;
@@ -2728,6 +2732,17 @@ bool SSLCtxPointer::setGroups(const char* groups) {
27282732
return SSL_CTX_set1_groups_list(get(), groups) == 1;
27292733
}
27302734

2735+
bool SSLCtxPointer::setCipherSuites(std::string_view ciphers) {
2736+
#ifndef OPENSSL_IS_BORINGSSL
2737+
if (!ctx_) return false;
2738+
return SSL_CTX_set_ciphersuites(ctx_.get(), ciphers.data());
2739+
#else
2740+
// BoringSSL does not allow API config of TLS 1.3 cipher suites.
2741+
// We treat this as a non-op.
2742+
return true;
2743+
#endif
2744+
}
2745+
27312746
// ============================================================================
27322747

27332748
const Cipher Cipher::FromName(std::string_view name) {
@@ -2742,6 +2757,55 @@ const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) {
27422757
return Cipher(EVP_CIPHER_CTX_cipher(ctx.get()));
27432758
}
27442759

2760+
const Cipher Cipher::EMPTY = Cipher();
2761+
const Cipher Cipher::AES_128_CBC = Cipher::FromNid(NID_aes_128_cbc);
2762+
const Cipher Cipher::AES_192_CBC = Cipher::FromNid(NID_aes_192_cbc);
2763+
const Cipher Cipher::AES_256_CBC = Cipher::FromNid(NID_aes_256_cbc);
2764+
const Cipher Cipher::AES_128_CTR = Cipher::FromNid(NID_aes_128_ctr);
2765+
const Cipher Cipher::AES_192_CTR = Cipher::FromNid(NID_aes_192_ctr);
2766+
const Cipher Cipher::AES_256_CTR = Cipher::FromNid(NID_aes_256_ctr);
2767+
const Cipher Cipher::AES_128_GCM = Cipher::FromNid(NID_aes_128_gcm);
2768+
const Cipher Cipher::AES_192_GCM = Cipher::FromNid(NID_aes_192_gcm);
2769+
const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm);
2770+
const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap);
2771+
const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap);
2772+
const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap);
2773+
2774+
bool Cipher::isGcmMode() const {
2775+
if (!cipher_) return false;
2776+
return getMode() == EVP_CIPH_GCM_MODE;
2777+
}
2778+
2779+
bool Cipher::isWrapMode() const {
2780+
if (!cipher_) return false;
2781+
return getMode() == EVP_CIPH_WRAP_MODE;
2782+
}
2783+
2784+
bool Cipher::isCtrMode() const {
2785+
if (!cipher_) return false;
2786+
return getMode() == EVP_CIPH_CTR_MODE;
2787+
}
2788+
2789+
bool Cipher::isCcmMode() const {
2790+
if (!cipher_) return false;
2791+
return getMode() == EVP_CIPH_CCM_MODE;
2792+
}
2793+
2794+
bool Cipher::isOcbMode() const {
2795+
if (!cipher_) return false;
2796+
return getMode() == EVP_CIPH_OCB_MODE;
2797+
}
2798+
2799+
bool Cipher::isStreamMode() const {
2800+
if (!cipher_) return false;
2801+
return getMode() == EVP_CIPH_STREAM_CIPHER;
2802+
}
2803+
2804+
bool Cipher::isChaCha20Poly1305() const {
2805+
if (!cipher_) return false;
2806+
return getNid() == NID_chacha20_poly1305;
2807+
}
2808+
27452809
int Cipher::getMode() const {
27462810
if (!cipher_) return 0;
27472811
return EVP_CIPHER_mode(cipher_);
@@ -2818,6 +2882,14 @@ bool Cipher::isSupportedAuthenticatedMode() const {
28182882
}
28192883
}
28202884

2885+
int Cipher::bytesToKey(const Digest& digest,
2886+
const Buffer<const unsigned char>& input,
2887+
unsigned char* key,
2888+
unsigned char* iv) const {
2889+
return EVP_BytesToKey(
2890+
*this, Digest::MD5, nullptr, input.data, input.len, 1, key, iv);
2891+
}
2892+
28212893
// ============================================================================
28222894

28232895
CipherCtxPointer CipherCtxPointer::New() {
@@ -2851,9 +2923,9 @@ EVP_CIPHER_CTX* CipherCtxPointer::release() {
28512923
return ctx_.release();
28522924
}
28532925

2854-
void CipherCtxPointer::setFlags(int flags) {
2926+
void CipherCtxPointer::setAllowWrap() {
28552927
if (!ctx_) return;
2856-
EVP_CIPHER_CTX_set_flags(ctx_.get(), flags);
2928+
EVP_CIPHER_CTX_set_flags(ctx_.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
28572929
}
28582930

28592931
bool CipherCtxPointer::setKeyLength(size_t length) {
@@ -2894,6 +2966,26 @@ int CipherCtxPointer::getMode() const {
28942966
return EVP_CIPHER_CTX_mode(ctx_.get());
28952967
}
28962968

2969+
bool CipherCtxPointer::isGcmMode() const {
2970+
if (!ctx_) return false;
2971+
return getMode() == EVP_CIPH_GCM_MODE;
2972+
}
2973+
2974+
bool CipherCtxPointer::isCcmMode() const {
2975+
if (!ctx_) return false;
2976+
return getMode() == EVP_CIPH_CCM_MODE;
2977+
}
2978+
2979+
bool CipherCtxPointer::isWrapMode() const {
2980+
if (!ctx_) return false;
2981+
return getMode() == EVP_CIPH_WRAP_MODE;
2982+
}
2983+
2984+
bool CipherCtxPointer::isChaCha20Poly1305() const {
2985+
if (!ctx_) return false;
2986+
return getNid() == NID_chacha20_poly1305;
2987+
}
2988+
28972989
int CipherCtxPointer::getNid() const {
28982990
if (!ctx_) return 0;
28992991
return EVP_CIPHER_CTX_nid(ctx_.get());
@@ -3258,14 +3350,16 @@ bool EVPKeyCtxPointer::setEcParameters(int curve, int encoding) {
32583350
EVP_PKEY_CTX_set_ec_param_enc(ctx_.get(), encoding) == 1;
32593351
}
32603352

3261-
bool EVPKeyCtxPointer::setRsaOaepMd(const EVP_MD* md) {
3262-
if (md == nullptr || !ctx_) return false;
3263-
return EVP_PKEY_CTX_set_rsa_oaep_md(ctx_.get(), md) > 0;
3353+
bool EVPKeyCtxPointer::setRsaOaepMd(const Digest& md) {
3354+
if (!md || !ctx_) return false;
3355+
const EVP_MD* md_ptr = md;
3356+
return EVP_PKEY_CTX_set_rsa_oaep_md(ctx_.get(), md_ptr) > 0;
32643357
}
32653358

3266-
bool EVPKeyCtxPointer::setRsaMgf1Md(const EVP_MD* md) {
3267-
if (md == nullptr || !ctx_) return false;
3268-
return EVP_PKEY_CTX_set_rsa_mgf1_md(ctx_.get(), md) > 0;
3359+
bool EVPKeyCtxPointer::setRsaMgf1Md(const Digest& md) {
3360+
if (!md || !ctx_) return false;
3361+
const EVP_MD* md_ptr = md;
3362+
return EVP_PKEY_CTX_set_rsa_mgf1_md(ctx_.get(), md_ptr) > 0;
32693363
}
32703364

32713365
bool EVPKeyCtxPointer::setRsaPadding(int padding) {
@@ -3300,14 +3394,17 @@ bool EVPKeyCtxPointer::setRsaKeygenPubExp(BignumPointer&& e) {
33003394
return false;
33013395
}
33023396

3303-
bool EVPKeyCtxPointer::setRsaPssKeygenMd(const EVP_MD* md) {
3304-
if (md == nullptr || !ctx_) return false;
3305-
return EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx_.get(), md) > 0;
3397+
bool EVPKeyCtxPointer::setRsaPssKeygenMd(const Digest& md) {
3398+
if (!md || !ctx_) return false;
3399+
// OpenSSL < 3 accepts a void* for the md parameter.
3400+
const EVP_MD* md_ptr = md;
3401+
return EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx_.get(), md_ptr) > 0;
33063402
}
33073403

3308-
bool EVPKeyCtxPointer::setRsaPssKeygenMgf1Md(const EVP_MD* md) {
3309-
if (md == nullptr || !ctx_) return false;
3310-
return EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx_.get(), md) > 0;
3404+
bool EVPKeyCtxPointer::setRsaPssKeygenMgf1Md(const Digest& md) {
3405+
if (!md || !ctx_) return false;
3406+
const EVP_MD* md_ptr = md;
3407+
return EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx_.get(), md_ptr) > 0;
33113408
}
33123409

33133410
bool EVPKeyCtxPointer::setRsaPssSaltlen(int salt_len) {
@@ -3673,6 +3770,74 @@ DataPointer Cipher::recover(const EVPKeyPointer& key,
36733770
key, params, in);
36743771
}
36753772

3773+
namespace {
3774+
struct CipherCallbackContext {
3775+
Cipher::CipherNameCallback cb;
3776+
void operator()(std::string_view name) { cb(name); }
3777+
};
3778+
3779+
#if OPENSSL_VERSION_MAJOR >= 3
3780+
template <class TypeName,
3781+
TypeName* fetch_type(OSSL_LIB_CTX*, const char*, const char*),
3782+
void free_type(TypeName*),
3783+
const TypeName* getbyname(const char*),
3784+
const char* getname(const TypeName*)>
3785+
void array_push_back(const TypeName* evp_ref,
3786+
const char* from,
3787+
const char* to,
3788+
void* arg) {
3789+
if (from == nullptr) return;
3790+
3791+
const TypeName* real_instance = getbyname(from);
3792+
if (!real_instance) return;
3793+
3794+
const char* real_name = getname(real_instance);
3795+
if (!real_name) return;
3796+
3797+
// EVP_*_fetch() does not support alias names, so we need to pass it the
3798+
// real/original algorithm name.
3799+
// We use EVP_*_fetch() as a filter here because it will only return an
3800+
// instance if the algorithm is supported by the public OpenSSL APIs (some
3801+
// algorithms are used internally by OpenSSL and are also passed to this
3802+
// callback).
3803+
TypeName* fetched = fetch_type(nullptr, real_name, nullptr);
3804+
if (fetched == nullptr) return;
3805+
3806+
free_type(fetched);
3807+
auto& cb = *(static_cast<CipherCallbackContext*>(arg));
3808+
cb(from);
3809+
}
3810+
#else
3811+
template <class TypeName>
3812+
void array_push_back(const TypeName* evp_ref,
3813+
const char* from,
3814+
const char* to,
3815+
void* arg) {
3816+
if (!from) return;
3817+
auto& cb = *(static_cast<CipherCallbackContext*>(arg));
3818+
cb(from);
3819+
}
3820+
#endif
3821+
} // namespace
3822+
3823+
void Cipher::ForEach(Cipher::CipherNameCallback callback) {
3824+
ClearErrorOnReturn clearErrorOnReturn;
3825+
CipherCallbackContext context;
3826+
context.cb = std::move(callback);
3827+
3828+
EVP_CIPHER_do_all_sorted(
3829+
#if OPENSSL_VERSION_MAJOR >= 3
3830+
array_push_back<EVP_CIPHER,
3831+
EVP_CIPHER_fetch,
3832+
EVP_CIPHER_free,
3833+
EVP_get_cipherbyname,
3834+
EVP_CIPHER_get0_name>,
3835+
#else
3836+
array_push_back<EVP_CIPHER>,
3837+
#endif
3838+
&context);
3839+
}
3840+
36763841
// ============================================================================
36773842

36783843
Ec::Ec() : ec_(nullptr) {}
@@ -3713,7 +3878,7 @@ EVP_MD_CTX* EVPMDCtxPointer::release() {
37133878
return ctx_.release();
37143879
}
37153880

3716-
bool EVPMDCtxPointer::digestInit(const EVP_MD* digest) {
3881+
bool EVPMDCtxPointer::digestInit(const Digest& digest) {
37173882
if (!ctx_) return false;
37183883
return EVP_DigestInit_ex(ctx_.get(), digest, nullptr) > 0;
37193884
}
@@ -3779,7 +3944,7 @@ bool EVPMDCtxPointer::copyTo(const EVPMDCtxPointer& other) const {
37793944
}
37803945

37813946
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInit(const EVPKeyPointer& key,
3782-
const EVP_MD* digest) {
3947+
const Digest& digest) {
37833948
EVP_PKEY_CTX* ctx = nullptr;
37843949
if (!EVP_DigestSignInit(ctx_.get(), &ctx, digest, nullptr, key.get())) {
37853950
return std::nullopt;
@@ -3788,7 +3953,7 @@ std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::signInit(const EVPKeyPointer& key,
37883953
}
37893954

37903955
std::optional<EVP_PKEY_CTX*> EVPMDCtxPointer::verifyInit(
3791-
const EVPKeyPointer& key, const EVP_MD* digest) {
3956+
const EVPKeyPointer& key, const Digest& digest) {
37923957
EVP_PKEY_CTX* ctx = nullptr;
37933958
if (!EVP_DigestVerifyInit(ctx_.get(), &ctx, digest, nullptr, key.get())) {
37943959
return std::nullopt;
@@ -3885,9 +4050,10 @@ HMAC_CTX* HMACCtxPointer::release() {
38854050
return ctx_.release();
38864051
}
38874052

3888-
bool HMACCtxPointer::init(const Buffer<const void>& buf, const EVP_MD* md) {
4053+
bool HMACCtxPointer::init(const Buffer<const void>& buf, const Digest& md) {
38894054
if (!ctx_) return false;
3890-
return HMAC_Init_ex(ctx_.get(), buf.data, buf.len, md, nullptr) == 1;
4055+
const EVP_MD* md_ptr = md;
4056+
return HMAC_Init_ex(ctx_.get(), buf.data, buf.len, md_ptr, nullptr) == 1;
38914057
}
38924058

38934059
bool HMACCtxPointer::update(const Buffer<const void>& buf) {
@@ -4029,4 +4195,21 @@ size_t Dsa::getDivisorLength() const {
40294195
return BignumPointer::GetBitCount(getQ());
40304196
}
40314197

4198+
// ============================================================================
4199+
4200+
size_t Digest::size() const {
4201+
if (md_ == nullptr) return 0;
4202+
return EVP_MD_size(md_);
4203+
}
4204+
4205+
const Digest Digest::MD5 = Digest(EVP_md5());
4206+
const Digest Digest::SHA1 = Digest(EVP_sha1());
4207+
const Digest Digest::SHA256 = Digest(EVP_sha256());
4208+
const Digest Digest::SHA384 = Digest(EVP_sha384());
4209+
const Digest Digest::SHA512 = Digest(EVP_sha512());
4210+
4211+
const Digest Digest::FromName(std::string_view name) {
4212+
return ncrypto::getDigestByName(name);
4213+
}
4214+
40324215
} // namespace ncrypto

0 commit comments

Comments
 (0)