Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4486,26 +4486,40 @@ const Cipher Cipher::FromCtx(const CipherCtxPointer& ctx) {
}

const Cipher Cipher::EMPTY = Cipher();
const Cipher Cipher::AES_128_CBC = Cipher::FromNid(NID_aes_128_cbc);
const Cipher Cipher::AES_192_CBC = Cipher::FromNid(NID_aes_192_cbc);
const Cipher Cipher::AES_256_CBC = Cipher::FromNid(NID_aes_256_cbc);
const Cipher Cipher::AES_128_CTR = Cipher::FromNid(NID_aes_128_ctr);
const Cipher Cipher::AES_192_CTR = Cipher::FromNid(NID_aes_192_ctr);
const Cipher Cipher::AES_256_CTR = Cipher::FromNid(NID_aes_256_ctr);
const Cipher Cipher::AES_128_GCM = Cipher::FromNid(NID_aes_128_gcm);
const Cipher Cipher::AES_192_GCM = Cipher::FromNid(NID_aes_192_gcm);
const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm);
const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap);
const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap);
const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap);

// The well-known ciphers are resolved lazily rather than in static
// initializers: EVP_get_cipherbynid() triggers OPENSSL_init_crypto(), and
// doing that while the executable is still being loaded adds the full cost
// of OpenSSL initialization to every process startup, even when crypto is
// never used.
#define NCRYPTO_LAZY_CIPHER(name, nid) \
const Cipher& Cipher::name() { \
static const Cipher cipher = Cipher::FromNid(nid); \
return cipher; \
}

NCRYPTO_LAZY_CIPHER(AES_128_CBC, NID_aes_128_cbc)
NCRYPTO_LAZY_CIPHER(AES_192_CBC, NID_aes_192_cbc)
NCRYPTO_LAZY_CIPHER(AES_256_CBC, NID_aes_256_cbc)
NCRYPTO_LAZY_CIPHER(AES_128_CTR, NID_aes_128_ctr)
NCRYPTO_LAZY_CIPHER(AES_192_CTR, NID_aes_192_ctr)
NCRYPTO_LAZY_CIPHER(AES_256_CTR, NID_aes_256_ctr)
NCRYPTO_LAZY_CIPHER(AES_128_GCM, NID_aes_128_gcm)
NCRYPTO_LAZY_CIPHER(AES_192_GCM, NID_aes_192_gcm)
NCRYPTO_LAZY_CIPHER(AES_256_GCM, NID_aes_256_gcm)
NCRYPTO_LAZY_CIPHER(AES_128_KW, NID_id_aes128_wrap)
NCRYPTO_LAZY_CIPHER(AES_192_KW, NID_id_aes192_wrap)
NCRYPTO_LAZY_CIPHER(AES_256_KW, NID_id_aes256_wrap)

#ifndef OPENSSL_IS_BORINGSSL
const Cipher Cipher::AES_128_OCB = Cipher::FromNid(NID_aes_128_ocb);
const Cipher Cipher::AES_192_OCB = Cipher::FromNid(NID_aes_192_ocb);
const Cipher Cipher::AES_256_OCB = Cipher::FromNid(NID_aes_256_ocb);
NCRYPTO_LAZY_CIPHER(AES_128_OCB, NID_aes_128_ocb)
NCRYPTO_LAZY_CIPHER(AES_192_OCB, NID_aes_192_ocb)
NCRYPTO_LAZY_CIPHER(AES_256_OCB, NID_aes_256_ocb)
#endif

const Cipher Cipher::CHACHA20_POLY1305 = Cipher::FromNid(NID_chacha20_poly1305);
NCRYPTO_LAZY_CIPHER(CHACHA20_POLY1305, NID_chacha20_poly1305)

#undef NCRYPTO_LAZY_CIPHER

bool Cipher::isGcmMode() const {
if (!cipher_) return false;
Expand Down
35 changes: 18 additions & 17 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,25 +502,26 @@ class Cipher final {
// Utilities to get various ciphers by type. If the underlying
// implementation does not support the requested cipher, then
// the result will be an empty Cipher object whose bool operator
// will return false.
// will return false. The ciphers are looked up lazily on first use so
// that merely loading the library does not initialize OpenSSL.

static const Cipher EMPTY;
static const Cipher AES_128_CBC;
static const Cipher AES_192_CBC;
static const Cipher AES_256_CBC;
static const Cipher AES_128_CTR;
static const Cipher AES_192_CTR;
static const Cipher AES_256_CTR;
static const Cipher AES_128_GCM;
static const Cipher AES_192_GCM;
static const Cipher AES_256_GCM;
static const Cipher AES_128_KW;
static const Cipher AES_192_KW;
static const Cipher AES_256_KW;
static const Cipher AES_128_OCB;
static const Cipher AES_192_OCB;
static const Cipher AES_256_OCB;
static const Cipher CHACHA20_POLY1305;
static const Cipher& AES_128_CBC();
static const Cipher& AES_192_CBC();
static const Cipher& AES_256_CBC();
static const Cipher& AES_128_CTR();
static const Cipher& AES_192_CTR();
static const Cipher& AES_256_CTR();
static const Cipher& AES_128_GCM();
static const Cipher& AES_192_GCM();
static const Cipher& AES_256_GCM();
static const Cipher& AES_128_KW();
static const Cipher& AES_192_KW();
static const Cipher& AES_256_KW();
static const Cipher& AES_128_OCB();
static const Cipher& AES_192_OCB();
static const Cipher& AES_256_OCB();
static const Cipher& CHACHA20_POLY1305();

struct CipherParams {
int padding;
Expand Down
30 changes: 15 additions & 15 deletions src/crypto/crypto_aes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ namespace node::crypto {
constexpr unsigned kNoAuthTagLength = static_cast<unsigned>(-1);

#define VARIANTS_COMMON(V) \
V(CTR_128, AES_CTR_Cipher, ncrypto::Cipher::AES_128_CTR) \
V(CTR_192, AES_CTR_Cipher, ncrypto::Cipher::AES_192_CTR) \
V(CTR_256, AES_CTR_Cipher, ncrypto::Cipher::AES_256_CTR) \
V(CBC_128, AES_Cipher, ncrypto::Cipher::AES_128_CBC) \
V(CBC_192, AES_Cipher, ncrypto::Cipher::AES_192_CBC) \
V(CBC_256, AES_Cipher, ncrypto::Cipher::AES_256_CBC) \
V(GCM_128, AES_Cipher, ncrypto::Cipher::AES_128_GCM) \
V(GCM_192, AES_Cipher, ncrypto::Cipher::AES_192_GCM) \
V(GCM_256, AES_Cipher, ncrypto::Cipher::AES_256_GCM) \
V(CTR_128, AES_CTR_Cipher, ncrypto::Cipher::AES_128_CTR()) \
V(CTR_192, AES_CTR_Cipher, ncrypto::Cipher::AES_192_CTR()) \
V(CTR_256, AES_CTR_Cipher, ncrypto::Cipher::AES_256_CTR()) \
V(CBC_128, AES_Cipher, ncrypto::Cipher::AES_128_CBC()) \
V(CBC_192, AES_Cipher, ncrypto::Cipher::AES_192_CBC()) \
V(CBC_256, AES_Cipher, ncrypto::Cipher::AES_256_CBC()) \
V(GCM_128, AES_Cipher, ncrypto::Cipher::AES_128_GCM()) \
V(GCM_192, AES_Cipher, ncrypto::Cipher::AES_192_GCM()) \
V(GCM_256, AES_Cipher, ncrypto::Cipher::AES_256_GCM()) \
VARIANTS_KW(V)

#ifdef OPENSSL_IS_BORINGSSL
Expand All @@ -33,16 +33,16 @@ constexpr unsigned kNoAuthTagLength = static_cast<unsigned>(-1);
V(KW_256, AES_KW_Cipher, static_cast<const EVP_CIPHER*>(nullptr))
#else
#define VARIANTS_KW(V) \
V(KW_128, AES_Cipher, ncrypto::Cipher::AES_128_KW) \
V(KW_192, AES_Cipher, ncrypto::Cipher::AES_192_KW) \
V(KW_256, AES_Cipher, ncrypto::Cipher::AES_256_KW)
V(KW_128, AES_Cipher, ncrypto::Cipher::AES_128_KW()) \
V(KW_192, AES_Cipher, ncrypto::Cipher::AES_192_KW()) \
V(KW_256, AES_Cipher, ncrypto::Cipher::AES_256_KW())
#endif

#if OPENSSL_WITH_AES_OCB
#define VARIANTS_OCB(V) \
V(OCB_128, AES_Cipher, ncrypto::Cipher::AES_128_OCB) \
V(OCB_192, AES_Cipher, ncrypto::Cipher::AES_192_OCB) \
V(OCB_256, AES_Cipher, ncrypto::Cipher::AES_256_OCB)
V(OCB_128, AES_Cipher, ncrypto::Cipher::AES_128_OCB()) \
V(OCB_192, AES_Cipher, ncrypto::Cipher::AES_192_OCB()) \
V(OCB_256, AES_Cipher, ncrypto::Cipher::AES_256_OCB())
#else
#define VARIANTS_OCB(V)
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/crypto_chacha20_poly1305.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Maybe<void> ChaCha20Poly1305CipherTraits::AdditionalConfig(
ChaCha20Poly1305CipherConfig* params) {
Environment* env = Environment::GetCurrent(args);

params->cipher = ncrypto::Cipher::CHACHA20_POLY1305;
params->cipher = ncrypto::Cipher::CHACHA20_POLY1305();

#ifndef OPENSSL_IS_BORINGSSL
// On BoringSSL, ChaCha20-Poly1305 is not exposed via the EVP_CIPHER registry
Expand Down
15 changes: 10 additions & 5 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2507,9 +2507,11 @@ int SecureContext::TicketKeyCallback(SSL* ssl,

ArrayBufferViewContents<unsigned char> aes_key(aes.As<ArrayBufferView>());
if (enc) {
EVP_EncryptInit_ex(ectx, Cipher::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, Cipher::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 @@ -2531,8 +2533,11 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
if (enc) {
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_));
if (!ncrypto::CSPRNG(iv, 16) ||
EVP_EncryptInit_ex(
ectx, Cipher::AES_128_CBC, nullptr, sc->ticket_key_aes_, iv) <= 0 ||
EVP_EncryptInit_ex(ectx,
Cipher::AES_128_CBC(),
nullptr,
sc->ticket_key_aes_,
iv) <= 0 ||
!InitTicketHmac(
hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_))) {
return -1;
Expand All @@ -2546,7 +2551,7 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
}

if (EVP_DecryptInit_ex(
ectx, Cipher::AES_128_CBC, nullptr, sc->ticket_key_aes_, iv) <= 0 ||
ectx, Cipher::AES_128_CBC(), nullptr, sc->ticket_key_aes_, iv) <= 0 ||
!InitTicketHmac(
hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_))) {
return -1;
Expand Down
21 changes: 19 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,17 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) {
init_process_flags.store(flags);

if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
atexit(ResetStdio);
// Arrange for ResetStdio() to run at exit. A function-local static with a
// destructor is used instead of atexit() because on macOS atexit() calls
// dladdr() to locate the image that owns the callback, which does a linear
// scan of the (very large) symbol table and costs about a millisecond of
// startup time. Static destructors and atexit() handlers are registered in
// the same list and run in reverse order of registration, so the ordering
// relative to other handlers is unchanged.
static const struct ResetStdioAtExit {
~ResetStdioAtExit() { ResetStdio(); }
} reset_stdio_at_exit;
(void)reset_stdio_at_exit;
}

#ifdef __POSIX__
Expand Down Expand Up @@ -1214,7 +1224,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
OPENSSL_INIT_set_config_file_flags(settings,
CONF_MFLAGS_IGNORE_MISSING_FILE);

OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
// OPENSSL_INIT_NO_ATEXIT: do not let OpenSSL register OPENSSL_cleanup()
// with atexit(). Nothing needs OpenSSL to be torn down when the process
// exits, and on macOS atexit() itself is expensive: it calls dladdr(),
// which linearly scans the executable's (very large) symbol table and
// costs about a millisecond on every process start. This must be part of
// the first OPENSSL_init_crypto() call in the process to take effect.
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG | OPENSSL_INIT_NO_ATEXIT,
settings);
OPENSSL_INIT_free(settings);

if (ERR_peek_error() != 0) {
Expand Down
Loading