Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
0ea74f3
test,crypto: make crypto tests work with BoringSSL
codebytere Oct 24, 2024
69dd1e1
module: add module.stripTypeScriptTypes
marco-ippolito Oct 24, 2024
9dcca54
doc: add jazelly to collaborators
jazelly Oct 25, 2024
2d19614
test: increase test coverage for `http.OutgoingMessage.appendHeader()`
juanarbol Oct 25, 2024
adda37f
module: add `findPackageJSON` util
JakobJingleheimer Oct 25, 2024
88c7f5b
sqlite: refactor open options
tniessen Oct 26, 2024
53a7d8e
test,crypto: update WebCryptoAPI WPT
panva Oct 26, 2024
1b82013
deps: update undici to 6.20.1
nodejs-github-bot Oct 26, 2024
71cc20a
test: avoid `apply()` calls with large amount of elements
LiviaMedeiros Oct 26, 2024
f00ad27
doc: add esm examples to node:string_decoder
mfdebian Oct 26, 2024
649d767
test: increase coverage of `pathToFileURL`
aduh95 Oct 27, 2024
bb78904
build: fix GN build for sqlite and nghttp2
codebytere Oct 27, 2024
f77bf65
doc: add suggested tsconfig for type stripping
marco-ippolito Oct 27, 2024
fa61dce
doc: move typescript support to active development
marco-ippolito Oct 27, 2024
f628fc4
fs: make `dirent.path` writable
aduh95 Oct 28, 2024
f8df27a
build: fix GN arg used in generate_config_gypi.py
codebytere Oct 28, 2024
a9e08cf
module: allow ESM that failed to be required to be re-imported
joyeecheung Oct 28, 2024
f92f20b
http: don't emit error after destroy
ronag Oct 28, 2024
efa142c
src: migrate `String::Value` to `String::ValueView`
avivkeller Oct 29, 2024
50552fd
deps: update acorn to 8.13.0
nodejs-github-bot Oct 29, 2024
3a1d490
deps: update nghttp2 to 1.64.0
nodejs-github-bot Oct 29, 2024
016baae
src: do not run IsWindowsBatchFile on non-windows
anonrig Oct 29, 2024
b3971bb
module: trim off internal stack frames for require(esm) warnings
joyeecheung Oct 18, 2024
d3be3da
module: fix error thrown from require(esm) hitting TLA repeatedly
joyeecheung Oct 29, 2024
6aa797d
test: remove unneeded listeners
lpinca Oct 29, 2024
4887214
build: fix building with system icu 76
cho-m Oct 29, 2024
815e252
test: split up test-runner-mock-timers test
badkeyy Oct 30, 2024
f355054
doc: capitalize "MIT License"
avivkeller Oct 30, 2024
0906004
dns: stop using deprecated `ares_query`
avivkeller Oct 30, 2024
4676184
src: use NewFromUtf8Literal in NODE_DEFINE_CONSTANT
ckerr Oct 31, 2024
2ec4ae7
sqlite: add readOnly option
tniessen Oct 31, 2024
25b1422
http: add diagnostic channel `http.client.request.created`
marco-ippolito Oct 31, 2024
56c46ab
module: unify TypeScript and .mjs handling in CommonJS
joyeecheung Oct 31, 2024
137aa5c
http2: fix client async storage persistence
orgads Oct 31, 2024
2b99285
url: refactor `pathToFileURL` to native
aduh95 Oct 31, 2024
4c34891
src: fix dns crash when failed to create NodeAresTask
theanarkh Nov 1, 2024
5de2567
doc: improve c++ embedder API doc
gireeshpunathil Nov 1, 2024
3477492
deps: update amaro to 0.2.0
nodejs-github-bot Nov 1, 2024
3234dc6
test_runner: pass `options` directly to `TestCoverage`
avivkeller Nov 1, 2024
cfa4d96
src,lib: optimize nodeTiming.uvMetricsInfo
RafaelGSS Oct 30, 2024
34483a2
benchmark: add nodeTiming.uvmetricsinfo bench
RafaelGSS Oct 31, 2024
b1ca7ab
meta: show PR/issue title on review-wanted
avivkeller Nov 1, 2024
7ab1f46
build: stop pre-compiling `lint-md`
avivkeller Nov 1, 2024
b79e483
build: use rclone instead of aws CLI
targos Nov 2, 2024
d26dedf
src: refactor ECDHBitsJob signature
panva Nov 2, 2024
9743fa4
doc: remove mention of ECDH-ES in crypto.diffieHellman
panva Nov 2, 2024
6662752
doc: add a note on console stream behavior
gireeshpunathil Nov 2, 2024
8d0526f
http: add diagnostic channel `http.server.response.created`
marco-ippolito Nov 2, 2024
7ce7eab
tools: lint README lists more strictly
aduh95 Nov 2, 2024
0302efe
src: move more key related stuff to ncrypto
jasnell Nov 2, 2024
6ab59c8
os: improve path check with direct index access
mertcanaltin Nov 2, 2024
7af76ef
assert: fix the string length check for printing the simple diff
Nov 2, 2024
869e88c
module: simplify `findPackageJSON` implementation
aduh95 Nov 2, 2024
d0ea981
meta: make review-wanted message minimal
avivkeller Nov 2, 2024
dd9b683
Revert "fs,win: fix bug in paths with trailing slashes"
rvagg Nov 2, 2024
c2fcda4
typings: fix `ModulesBinding` types
aduh95 Nov 2, 2024
b8ca9d8
doc: add write flag when open file as the demo code's intention
robberfree Nov 2, 2024
505ff19
doc: broken `PerformanceObserver` code sample
domharrington Nov 2, 2024
cba05cd
tools: run daily WPT.fyi report on all supported releases
panva Nov 2, 2024
d0b2d6b
tools: compact jq output in daily-wpt-fyi.yml action
panva Nov 2, 2024
dfb764c
deps: update sqlite to 3.47.0
nodejs-github-bot Nov 2, 2024
9b351b0
crypto: fix `RSA_PKCS1_PADDING` error message
richardlau Nov 3, 2024
19b1edf
module: simplify --inspect-brk handling
joyeecheung Nov 3, 2024
d79c8bf
meta: bump github/codeql-action from 3.26.10 to 3.27.0
dependabot[bot] Nov 3, 2024
5c2e472
meta: bump actions/checkout from 4.2.0 to 4.2.2
dependabot[bot] Nov 3, 2024
9042e9a
meta: bump actions/cache from 4.0.2 to 4.1.2
dependabot[bot] Nov 3, 2024
42e6c47
meta: bump actions/upload-artifact from 4.4.0 to 4.4.3
dependabot[bot] Nov 3, 2024
2ae8d3b
meta: bump rtCamp/action-slack-notify from 2.3.0 to 2.3.2
dependabot[bot] Nov 3, 2024
21e3b7b
meta: bump actions/setup-node from 4.0.4 to 4.1.0
dependabot[bot] Nov 3, 2024
7bfd295
meta: bump actions/setup-python from 5.2.0 to 5.3.0
dependabot[bot] Nov 3, 2024
8fc962f
tools: fix root certificate updater
richardlau Nov 1, 2024
535f1b0
crypto: update root certificates to NSS 3.104
richardlau Nov 1, 2024
7aa250a
sqlite: improve error handling using MaybeLocal
tniessen Nov 4, 2024
961cbc9
tools: use `util.parseArgs` in `lint-md`
avivkeller Nov 4, 2024
4b192da
deps: update acorn to 8.14.0
nodejs-github-bot Nov 5, 2024
aebf676
test,crypto: update WebCryptoAPI WPT
panva Nov 5, 2024
bf552fa
lib: prefer number to string in webidl `type` function
jazelly Oct 24, 2024
d1965f9
lib: implement webidl dictionary converter and use it in structuredClone
jazelly Oct 20, 2024
bffbaa1
doc: update `--max-semi-space-size` description
joebowbeer Nov 5, 2024
038ac01
path,win: fix bug in resolve and normalize
huseyinacacak-janea Nov 5, 2024
15028dd
tools: update ESLint to 9.14.0
dependabot[bot] Nov 5, 2024
7d93c0c
test: refactor some esm tests
aduh95 Nov 5, 2024
9dbb255
assert: fix `deepStrictEqual` on errors when `cause` is not undefined
geeksilva97 Nov 5, 2024
10b68ed
test: ignore unrelated events in FW watch tests
Ceres6 Nov 6, 2024
7853462
src: provide workaround for container-overflow
lemire Nov 6, 2024
20cb52d
doc: clarity to available addon options
preveen-stack Nov 6, 2024
4129bc7
util: do not catch on circular `@@toStringTag` errors
avivkeller Nov 6, 2024
19da4de
test: update `performance-timeline` wpt
avivkeller Sep 30, 2024
ee12431
doc: consistent use of word child process
gireeshpunathil Nov 6, 2024
89aa838
doc: add esm example in `path.md`
avivkeller Nov 8, 2024
cbe09b5
doc: add path aliases typescript doc
Ceres6 Nov 8, 2024
355af0f
doc: consolidate history table of `CustomEvent`
geeksilva97 Nov 9, 2024
a83fbdb
2024-11-11, Version 23.2.0 (Current)
aduh95 Nov 6, 2024
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
Prev Previous commit
Next Next commit
src: move more key related stuff to ncrypto
PR-URL: #55368
Reviewed-By: Yagiz Nizipli <[email protected]>
  • Loading branch information
jasnell authored and aduh95 committed Nov 5, 2024
commit 0302efe4b2e1a21b3b1d9b82b263383e36e9b9bc
252 changes: 230 additions & 22 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ std::optional<std::string> CryptoErrorList::pop_front() {

// ============================================================================
DataPointer DataPointer::Alloc(size_t len) {
return DataPointer(OPENSSL_malloc(len), len);
return DataPointer(OPENSSL_zalloc(len), len);
}

DataPointer::DataPointer(void* data, size_t length)
Expand Down Expand Up @@ -1428,6 +1428,33 @@ DataPointer pbkdf2(const EVP_MD* md,

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

EVPKeyPointer::PrivateKeyEncodingConfig::PrivateKeyEncodingConfig(
const PrivateKeyEncodingConfig& other)
: PrivateKeyEncodingConfig(other.output_key_object, other.format, other.type) {
cipher = other.cipher;
if (other.passphrase.has_value()) {
auto& otherPassphrase = other.passphrase.value();
auto newPassphrase = DataPointer::Alloc(otherPassphrase.size());
memcpy(newPassphrase.get(), otherPassphrase.get(), otherPassphrase.size());
passphrase = std::move(newPassphrase);
}
}

EVPKeyPointer::AsymmetricKeyEncodingConfig::AsymmetricKeyEncodingConfig(
bool output_key_object,
PKFormatType format,
PKEncodingType type)
: output_key_object(output_key_object),
format(format),
type(type) {}

EVPKeyPointer::PrivateKeyEncodingConfig& EVPKeyPointer::PrivateKeyEncodingConfig::operator=(
const PrivateKeyEncodingConfig& other) {
if (this == &other) return *this;
this->~PrivateKeyEncodingConfig();
return *new (this) PrivateKeyEncodingConfig(other);
}

EVPKeyPointer EVPKeyPointer::New() {
return EVPKeyPointer(EVP_PKEY_new());
}
Expand Down Expand Up @@ -1661,41 +1688,61 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKeyPEM(
}

EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey(
PKFormatType format,
PKEncodingType encoding,
const PublicKeyEncodingConfig& config,
const Buffer<const unsigned char>& buffer) {
if (format == PKFormatType::PEM) {
if (config.format == PKFormatType::PEM) {
return TryParsePublicKeyPEM(buffer);
}

if (format != PKFormatType::DER) {
if (config.format != PKFormatType::DER) {
return ParseKeyResult(PKParseError::FAILED);
}

const unsigned char* start = buffer.data;

EVP_PKEY* key = nullptr;

if (encoding == PKEncodingType::PKCS1 &&
if (config.type == PKEncodingType::PKCS1 &&
(key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &start, buffer.len))) {
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
}

if (encoding == PKEncodingType::SPKI &&
if (config.type == PKEncodingType::SPKI &&
(key = d2i_PUBKEY(nullptr, &start, buffer.len))) {
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
}

return ParseKeyResult(PKParseError::FAILED);
}

namespace {
Buffer<char> GetPassphrase(const EVPKeyPointer::PrivateKeyEncodingConfig& config) {
Buffer<char> pass {
// OpenSSL will not actually dereference this pointer, so it can be any
// non-null pointer. We cannot assert that directly, which is why we
// intentionally use a pointer that will likely cause a segmentation fault
// when dereferenced.
.data = reinterpret_cast<char*>(-1),
.len = 0,
};
if (config.passphrase.has_value()) {
auto& passphrase = config.passphrase.value();
// The pass.data can't be a nullptr, even if the len is zero or else
// openssl will prompt for a password and we really don't want that.
if (passphrase.get() != nullptr) {
pass.data = static_cast<char*>(passphrase.get());
}
pass.len = passphrase.size();
}
return pass;
}
} // namespace

EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
PKFormatType format,
PKEncodingType encoding,
std::optional<Buffer<char>> maybe_passphrase,
const PrivateKeyEncodingConfig& config,
const Buffer<const unsigned char>& buffer) {

static auto keyOrError = [&](EVPKeyPointer pkey, bool had_passphrase = false) {
static constexpr auto keyOrError = [](EVPKeyPointer pkey, bool had_passphrase = false) {
if (int err = ERR_peek_error()) {
if (ERR_GET_LIB(err) == ERR_LIB_PEM &&
ERR_GET_REASON(err) == PEM_R_BAD_PASSWORD_READ &&
Expand All @@ -1708,24 +1755,23 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
return ParseKeyResult(std::move(pkey));
};

Buffer<char>* passphrase = nullptr;
if (maybe_passphrase.has_value()) {
passphrase = &maybe_passphrase.value();
}

auto bio = BIOPointer::New(buffer);
if (!bio) return ParseKeyResult(PKParseError::FAILED);

if (format == PKFormatType::PEM) {
auto key = PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback, passphrase);
return keyOrError(EVPKeyPointer(key), maybe_passphrase.has_value());
auto passphrase = GetPassphrase(config);

if (config.format == PKFormatType::PEM) {
auto key = PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback,
config.passphrase.has_value() ? &passphrase : nullptr);
return keyOrError(EVPKeyPointer(key), config.passphrase.has_value());
}

if (format != PKFormatType::DER) {
if (config.format != PKFormatType::DER) {
return ParseKeyResult(PKParseError::FAILED);
}

switch (encoding) {
switch (config.type) {
case PKEncodingType::PKCS1: {
auto key = d2i_PrivateKey_bio(bio.get(), nullptr);
return keyOrError(EVPKeyPointer(key));
Expand All @@ -1735,8 +1781,8 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
auto key = d2i_PKCS8PrivateKey_bio(bio.get(),
nullptr,
PasswordCallback,
passphrase);
return keyOrError(EVPKeyPointer(key), maybe_passphrase.has_value());
config.passphrase.has_value() ? &passphrase : nullptr);
return keyOrError(EVPKeyPointer(key), config.passphrase.has_value());
}

PKCS8Pointer p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr));
Expand All @@ -1755,4 +1801,166 @@ EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePrivateKey(
};
}

Result<BIOPointer, bool> EVPKeyPointer::writePrivateKey(
const PrivateKeyEncodingConfig& config) const {
if (config.format == PKFormatType::JWK) {
return Result<BIOPointer, bool>(false);
}

auto bio = BIOPointer::NewMem();
if (!bio) {
return Result<BIOPointer, bool>(false);
}

auto passphrase = GetPassphrase(config);
MarkPopErrorOnReturn mark_pop_error_on_return;
bool err;

switch (config.type) {
case PKEncodingType::PKCS1: {
// PKCS1 is only permitted for RSA keys.
if (id() != EVP_PKEY_RSA) return Result<BIOPointer, bool>(false);

#if OPENSSL_VERSION_MAJOR >= 3
const RSA* rsa = EVP_PKEY_get0_RSA(get());
#else
RSA* rsa = EVP_PKEY_get0_RSA(get());
#endif
switch (config.format) {
case PKFormatType::PEM: {
err = PEM_write_bio_RSAPrivateKey(bio.get(), rsa, config.cipher,
reinterpret_cast<unsigned char*>(passphrase.data),
passphrase.len, nullptr, nullptr) != 1;
break;
}
case PKFormatType::DER: {
// Encoding PKCS1 as DER. This variation does not permit encryption.
err = i2d_RSAPrivateKey_bio(bio.get(), rsa) != 1;
break;
}
default: {
// Should never get here.
return Result<BIOPointer, bool>(false);
}
}
break;
}
case PKEncodingType::PKCS8: {
switch (config.format) {
case PKFormatType::PEM: {
// Encode PKCS#8 as PEM.
err = PEM_write_bio_PKCS8PrivateKey(
bio.get(), get(),
config.cipher,
passphrase.data,
passphrase.len,
nullptr, nullptr) != 1;
break;
}
case PKFormatType::DER: {
err = i2d_PKCS8PrivateKey_bio(
bio.get(), get(),
config.cipher,
passphrase.data,
passphrase.len,
nullptr, nullptr) != 1;
break;
}
default: {
// Should never get here.
return Result<BIOPointer, bool>(false);
}
}
break;
}
case PKEncodingType::SEC1: {
// SEC1 is only permitted for EC keys
if (id() != EVP_PKEY_EC) return Result<BIOPointer, bool>(false);

#if OPENSSL_VERSION_MAJOR >= 3
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(get());
#else
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(get());
#endif
switch (config.format) {
case PKFormatType::PEM: {
err = PEM_write_bio_ECPrivateKey(bio.get(),
ec,
config.cipher,
reinterpret_cast<unsigned char*>(passphrase.data),
passphrase.len,
nullptr,
nullptr) != 1;
break;
}
case PKFormatType::DER: {
// Encoding SEC1 as DER. This variation does not permit encryption.
err = i2d_ECPrivateKey_bio(bio.get(), ec) != 1;
break;
}
default: {
// Should never get here.
return Result<BIOPointer, bool>(false);
}
}
break;
}
default: {
// Not a valid private key encoding
return Result<BIOPointer, bool>(false);
}
}

if (err) {
// Failed to encode the private key.
return Result<BIOPointer, bool>(false, mark_pop_error_on_return.peekError());
}

return bio;
}

Result<BIOPointer, bool> EVPKeyPointer::writePublicKey(
const ncrypto::EVPKeyPointer::PublicKeyEncodingConfig& config) const {
auto bio = BIOPointer::NewMem();
if (!bio) return Result<BIOPointer, bool>(false);

MarkPopErrorOnReturn mark_pop_error_on_return;

if (config.type == ncrypto::EVPKeyPointer::PKEncodingType::PKCS1) {
// PKCS#1 is only valid for RSA keys.
#if OPENSSL_VERSION_MAJOR >= 3
const RSA* rsa = EVP_PKEY_get0_RSA(get());
#else
RSA* rsa = EVP_PKEY_get0_RSA(get());
#endif
if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
// Encode PKCS#1 as PEM.
if (PEM_write_bio_RSAPublicKey(bio.get(), rsa) != 1) {
return Result<BIOPointer, bool>(false, mark_pop_error_on_return.peekError());
}
return bio;
}

// Encode PKCS#1 as DER.
if (i2d_RSAPublicKey_bio(bio.get(), rsa) != 1) {
return Result<BIOPointer, bool>(false, mark_pop_error_on_return.peekError());
}
return bio;
}

if (config.format == ncrypto::EVPKeyPointer::PKFormatType::PEM) {
// Encode SPKI as PEM.
if (PEM_write_bio_PUBKEY(bio.get(), get()) != 1) {
return Result<BIOPointer, bool>(false, mark_pop_error_on_return.peekError());
}
return bio;
}

// Encode SPKI as DER.
if (i2d_PUBKEY_bio(bio.get(), get()) != 1) {
return Result<BIOPointer, bool>(false, mark_pop_error_on_return.peekError());
}
return bio;
}

} // namespace ncrypto
36 changes: 28 additions & 8 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,13 +386,13 @@ class EVPKeyPointer final {
// SubjectPublicKeyInfo according to X.509.
SPKI,
// ECPrivateKey according to SEC1.
SEC1
SEC1,
};

enum class PKFormatType {
DER,
PEM,
JWK
JWK,
};

enum class PKParseError {
Expand All @@ -402,18 +402,36 @@ class EVPKeyPointer final {
};
using ParseKeyResult = Result<EVPKeyPointer, PKParseError>;

struct AsymmetricKeyEncodingConfig {
bool output_key_object = false;
PKFormatType format = PKFormatType::DER;
PKEncodingType type = PKEncodingType::PKCS8;
AsymmetricKeyEncodingConfig() = default;
AsymmetricKeyEncodingConfig(bool output_key_object, PKFormatType format, PKEncodingType type);
AsymmetricKeyEncodingConfig(const AsymmetricKeyEncodingConfig&) = default;
AsymmetricKeyEncodingConfig& operator=(const AsymmetricKeyEncodingConfig&) = default;
};
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;

struct PrivateKeyEncodingConfig: public AsymmetricKeyEncodingConfig {
const EVP_CIPHER* cipher = nullptr;
std::optional<DataPointer> passphrase = std::nullopt;
PrivateKeyEncodingConfig() = default;
PrivateKeyEncodingConfig(bool output_key_object, PKFormatType format, PKEncodingType type)
: AsymmetricKeyEncodingConfig(output_key_object, format, type) {}
PrivateKeyEncodingConfig(const PrivateKeyEncodingConfig&);
PrivateKeyEncodingConfig& operator=(const PrivateKeyEncodingConfig&);
};

static ParseKeyResult TryParsePublicKey(
PKFormatType format,
PKEncodingType encoding,
const PublicKeyEncodingConfig& config,
const Buffer<const unsigned char>& buffer);

static ParseKeyResult TryParsePublicKeyPEM(
const Buffer<const unsigned char>& buffer);

static ParseKeyResult TryParsePrivateKey(
PKFormatType format,
PKEncodingType encoding,
std::optional<Buffer<char>> passphrase,
const PrivateKeyEncodingConfig& config,
const Buffer<const unsigned char>& buffer);

EVPKeyPointer() = default;
Expand Down Expand Up @@ -441,9 +459,11 @@ class EVPKeyPointer final {
size_t rawPrivateKeySize() const;
DataPointer rawPublicKey() const;
DataPointer rawPrivateKey() const;

BIOPointer derPublicKey() const;

Result<BIOPointer, bool> writePrivateKey(const PrivateKeyEncodingConfig& config) const;
Result<BIOPointer, bool> writePublicKey(const PublicKeyEncodingConfig& config) const;

EVPKeyCtxPointer newCtx() const;

static bool IsRSAPrivateKey(const Buffer<const unsigned char>& buffer);
Expand Down
Loading