mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00
src,test: support dynamically linking OpenSSL 3.0
This commit enables node to dynamically link against OpenSSL 3.0. The motivation for opening this PR even though OpenSSL 3.0 has not been released yet is to allow a nightly CI job to be created. This will allow us stay on top of changes required for OpenSSL 3.0, and also to make sure that changes to node crypto do not cause issues when linking to OpenSSL 3.0. PR-URL: https://github.com/nodejs/node/pull/37669 Refs: https://github.com/nodejs/node/issues/29817 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <midawson@redhat.com>
This commit is contained in:
parent
6527e041f7
commit
640fe94354
47 changed files with 509 additions and 293 deletions
|
@ -361,7 +361,11 @@
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
}]]
|
}, {
|
||||||
|
# Set 1.0.0 as the API compability level to avoid the
|
||||||
|
# deprecation warnings when using OpenSSL 3.0.
|
||||||
|
'defines': ['OPENSSL_API_COMPAT=0x10000000L'],
|
||||||
|
}]]
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
'defines': [ 'HAVE_OPENSSL=0' ]
|
'defines': [ 'HAVE_OPENSSL=0' ]
|
||||||
|
|
|
@ -342,8 +342,11 @@ void CipherBase::Init(const char* cipher_type,
|
||||||
unsigned int auth_tag_len) {
|
unsigned int auth_tag_len) {
|
||||||
HandleScope scope(env()->isolate());
|
HandleScope scope(env()->isolate());
|
||||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (EVP_default_properties_is_fips_enabled(nullptr)) {
|
||||||
|
#else
|
||||||
if (FIPS_mode()) {
|
if (FIPS_mode()) {
|
||||||
|
#endif
|
||||||
return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
|
return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
|
||||||
"crypto.createCipher() is not supported in FIPS mode.");
|
"crypto.createCipher() is not supported in FIPS mode.");
|
||||||
}
|
}
|
||||||
|
@ -527,7 +530,13 @@ bool CipherBase::InitAuthenticated(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(tniessen) Support CCM decryption in FIPS mode
|
// TODO(tniessen) Support CCM decryption in FIPS mode
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher &&
|
||||||
|
EVP_default_properties_is_fips_enabled(nullptr)) {
|
||||||
|
#else
|
||||||
if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && FIPS_mode()) {
|
if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && FIPS_mode()) {
|
||||||
|
#endif
|
||||||
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
|
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
|
||||||
"CCM encryption not supported in FIPS mode");
|
"CCM encryption not supported in FIPS mode");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -138,7 +138,7 @@ Maybe<bool> GetDsaKeyDetail(
|
||||||
int type = EVP_PKEY_id(m_pkey.get());
|
int type = EVP_PKEY_id(m_pkey.get());
|
||||||
CHECK(type == EVP_PKEY_DSA);
|
CHECK(type == EVP_PKEY_DSA);
|
||||||
|
|
||||||
DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get());
|
const DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get());
|
||||||
CHECK_NOT_NULL(dsa);
|
CHECK_NOT_NULL(dsa);
|
||||||
|
|
||||||
DSA_get0_pqg(dsa, &p, &q, nullptr);
|
DSA_get0_pqg(dsa, &p, &q, nullptr);
|
||||||
|
|
|
@ -463,19 +463,22 @@ bool ECDHBitsTraits::DeriveBits(
|
||||||
|
|
||||||
char* data = nullptr;
|
char* data = nullptr;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
ManagedEVPPKey m_privkey = params.private_->GetAsymmetricKey();
|
||||||
|
ManagedEVPPKey m_pubkey = params.public_->GetAsymmetricKey();
|
||||||
|
|
||||||
switch (params.id_) {
|
switch (params.id_) {
|
||||||
case EVP_PKEY_X25519:
|
case EVP_PKEY_X25519:
|
||||||
// Fall through
|
// Fall through
|
||||||
case EVP_PKEY_X448: {
|
case EVP_PKEY_X448: {
|
||||||
EVPKeyCtxPointer ctx(
|
EVPKeyCtxPointer ctx = nullptr;
|
||||||
EVP_PKEY_CTX_new(
|
{
|
||||||
params.private_->GetAsymmetricKey().get(),
|
ctx.reset(EVP_PKEY_CTX_new(m_privkey.get(), nullptr));
|
||||||
nullptr));
|
}
|
||||||
|
Mutex::ScopedLock pub_lock(*m_pubkey.mutex());
|
||||||
if (EVP_PKEY_derive_init(ctx.get()) <= 0 ||
|
if (EVP_PKEY_derive_init(ctx.get()) <= 0 ||
|
||||||
EVP_PKEY_derive_set_peer(
|
EVP_PKEY_derive_set_peer(
|
||||||
ctx.get(),
|
ctx.get(),
|
||||||
params.public_->GetAsymmetricKey().get()) <= 0 ||
|
m_pubkey.get()) <= 0 ||
|
||||||
EVP_PKEY_derive(ctx.get(), nullptr, &len) <= 0) {
|
EVP_PKEY_derive(ctx.get(), nullptr, &len) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -492,10 +495,14 @@ bool ECDHBitsTraits::DeriveBits(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
const EC_KEY* private_key =
|
const EC_KEY* private_key;
|
||||||
EVP_PKEY_get0_EC_KEY(params.private_->GetAsymmetricKey().get());
|
{
|
||||||
const EC_KEY* public_key =
|
Mutex::ScopedLock priv_lock(*m_privkey.mutex());
|
||||||
EVP_PKEY_get0_EC_KEY(params.public_->GetAsymmetricKey().get());
|
private_key = EVP_PKEY_get0_EC_KEY(m_privkey.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
Mutex::ScopedLock pub_lock(*m_pubkey.mutex());
|
||||||
|
const EC_KEY* public_key = EVP_PKEY_get0_EC_KEY(m_pubkey.get());
|
||||||
|
|
||||||
const EC_GROUP* group = EC_KEY_get0_group(private_key);
|
const EC_GROUP* group = EC_KEY_get0_group(private_key);
|
||||||
if (group == nullptr)
|
if (group == nullptr)
|
||||||
|
@ -607,7 +614,7 @@ WebCryptoKeyExportStatus EC_Raw_Export(
|
||||||
CHECK(m_pkey);
|
CHECK(m_pkey);
|
||||||
Mutex::ScopedLock lock(*m_pkey.mutex());
|
Mutex::ScopedLock lock(*m_pkey.mutex());
|
||||||
|
|
||||||
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||||
|
|
||||||
unsigned char* data;
|
unsigned char* data;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -627,10 +634,10 @@ WebCryptoKeyExportStatus EC_Raw_Export(
|
||||||
}
|
}
|
||||||
CHECK_NOT_NULL(fn);
|
CHECK_NOT_NULL(fn);
|
||||||
// Get the size of the raw key data
|
// Get the size of the raw key data
|
||||||
if (fn(key_data->GetAsymmetricKey().get(), nullptr, &len) == 0)
|
if (fn(m_pkey.get(), nullptr, &len) == 0)
|
||||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||||
data = MallocOpenSSL<unsigned char>(len);
|
data = MallocOpenSSL<unsigned char>(len);
|
||||||
if (fn(key_data->GetAsymmetricKey().get(), data, &len) == 0)
|
if (fn(m_pkey.get(), data, &len) == 0)
|
||||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||||
} else {
|
} else {
|
||||||
if (key_data->GetKeyType() != kKeyTypePublic)
|
if (key_data->GetKeyType() != kKeyTypePublic)
|
||||||
|
@ -696,7 +703,7 @@ Maybe<bool> ExportJWKEcKey(
|
||||||
Mutex::ScopedLock lock(*m_pkey.mutex());
|
Mutex::ScopedLock lock(*m_pkey.mutex());
|
||||||
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
||||||
|
|
||||||
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||||
CHECK_NOT_NULL(ec);
|
CHECK_NOT_NULL(ec);
|
||||||
|
|
||||||
const EC_POINT* pub = EC_KEY_get0_public_key(ec);
|
const EC_POINT* pub = EC_KEY_get0_public_key(ec);
|
||||||
|
@ -751,6 +758,7 @@ Maybe<bool> ExportJWKEdKey(
|
||||||
std::shared_ptr<KeyObjectData> key,
|
std::shared_ptr<KeyObjectData> key,
|
||||||
Local<Object> target) {
|
Local<Object> target) {
|
||||||
ManagedEVPPKey pkey = key->GetAsymmetricKey();
|
ManagedEVPPKey pkey = key->GetAsymmetricKey();
|
||||||
|
Mutex::ScopedLock lock(*pkey.mutex());
|
||||||
|
|
||||||
const char* curve = nullptr;
|
const char* curve = nullptr;
|
||||||
switch (EVP_PKEY_id(pkey.get())) {
|
switch (EVP_PKEY_id(pkey.get())) {
|
||||||
|
@ -902,7 +910,7 @@ Maybe<bool> GetEcKeyDetail(
|
||||||
Mutex::ScopedLock lock(*m_pkey.mutex());
|
Mutex::ScopedLock lock(*m_pkey.mutex());
|
||||||
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
||||||
|
|
||||||
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||||
CHECK_NOT_NULL(ec);
|
CHECK_NOT_NULL(ec);
|
||||||
|
|
||||||
const EC_GROUP* group = EC_KEY_get0_group(ec);
|
const EC_GROUP* group = EC_KEY_get0_group(ec);
|
||||||
|
@ -919,8 +927,8 @@ Maybe<bool> GetEcKeyDetail(
|
||||||
// implementation here is a adapted from Chromium's impl here:
|
// implementation here is a adapted from Chromium's impl here:
|
||||||
// https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc
|
// https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/ecdsa.cc
|
||||||
|
|
||||||
size_t GroupOrderSize(ManagedEVPPKey key) {
|
size_t GroupOrderSize(const ManagedEVPPKey& key) {
|
||||||
EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get());
|
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(key.get());
|
||||||
CHECK_NOT_NULL(ec);
|
CHECK_NOT_NULL(ec);
|
||||||
const EC_GROUP* group = EC_KEY_get0_group(ec);
|
const EC_GROUP* group = EC_KEY_get0_group(ec);
|
||||||
BignumPointer order(BN_new());
|
BignumPointer order(BN_new());
|
||||||
|
|
|
@ -110,15 +110,15 @@ bool HKDFTraits::DeriveBits(
|
||||||
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), params.digest) ||
|
!EVP_PKEY_CTX_set_hkdf_md(ctx.get(), params.digest) ||
|
||||||
!EVP_PKEY_CTX_set1_hkdf_salt(
|
!EVP_PKEY_CTX_set1_hkdf_salt(
|
||||||
ctx.get(),
|
ctx.get(),
|
||||||
params.salt.get(),
|
reinterpret_cast<const unsigned char*>(params.salt.get()),
|
||||||
params.salt.size()) ||
|
params.salt.size()) ||
|
||||||
!EVP_PKEY_CTX_set1_hkdf_key(
|
!EVP_PKEY_CTX_set1_hkdf_key(
|
||||||
ctx.get(),
|
ctx.get(),
|
||||||
params.key->GetSymmetricKey(),
|
reinterpret_cast<const unsigned char*>(params.key->GetSymmetricKey()),
|
||||||
params.key->GetSymmetricKeySize()) ||
|
params.key->GetSymmetricKeySize()) ||
|
||||||
!EVP_PKEY_CTX_add1_hkdf_info(
|
!EVP_PKEY_CTX_add1_hkdf_info(
|
||||||
ctx.get(),
|
ctx.get(),
|
||||||
params.info.get(),
|
reinterpret_cast<const unsigned char*>(params.info.get()),
|
||||||
params.info.size())) {
|
params.info.size())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,9 @@ struct KeyPairGenConfig final : public MemoryRetainer {
|
||||||
AlgorithmParams params;
|
AlgorithmParams params;
|
||||||
|
|
||||||
KeyPairGenConfig() = default;
|
KeyPairGenConfig() = default;
|
||||||
|
~KeyPairGenConfig() {
|
||||||
|
Mutex::ScopedLock priv_lock(*key.mutex());
|
||||||
|
}
|
||||||
|
|
||||||
explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept
|
explicit KeyPairGenConfig(KeyPairGenConfig&& other) noexcept
|
||||||
: public_key_encoding(other.public_key_encoding),
|
: public_key_encoding(other.public_key_encoding),
|
||||||
|
|
|
@ -559,6 +559,8 @@ ManagedEVPPKey::ManagedEVPPKey(const ManagedEVPPKey& that) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) {
|
ManagedEVPPKey& ManagedEVPPKey::operator=(const ManagedEVPPKey& that) {
|
||||||
|
Mutex::ScopedLock lock(*that.mutex_);
|
||||||
|
|
||||||
pkey_.reset(that.get());
|
pkey_.reset(that.get());
|
||||||
|
|
||||||
if (pkey_)
|
if (pkey_)
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
|
||||||
// use.
|
// use.
|
||||||
class ManagedEVPPKey : public MemoryRetainer {
|
class ManagedEVPPKey : public MemoryRetainer {
|
||||||
public:
|
public:
|
||||||
ManagedEVPPKey() = default;
|
ManagedEVPPKey() : mutex_(std::make_shared<Mutex>()) {}
|
||||||
explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
|
explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
|
||||||
ManagedEVPPKey(const ManagedEVPPKey& that);
|
ManagedEVPPKey(const ManagedEVPPKey& that);
|
||||||
ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
|
ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
|
||||||
|
|
|
@ -371,11 +371,11 @@ Maybe<bool> ExportJWKRsaKey(
|
||||||
|
|
||||||
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
||||||
// versions older than 1.1.1e via FIPS / dynamic linking.
|
// versions older than 1.1.1e via FIPS / dynamic linking.
|
||||||
RSA* rsa;
|
const RSA* rsa;
|
||||||
if (OpenSSL_version_num() >= 0x1010105fL) {
|
if (OpenSSL_version_num() >= 0x1010105fL) {
|
||||||
rsa = EVP_PKEY_get0_RSA(m_pkey.get());
|
rsa = EVP_PKEY_get0_RSA(m_pkey.get());
|
||||||
} else {
|
} else {
|
||||||
rsa = static_cast<RSA*>(EVP_PKEY_get0(m_pkey.get()));
|
rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
|
||||||
}
|
}
|
||||||
CHECK_NOT_NULL(rsa);
|
CHECK_NOT_NULL(rsa);
|
||||||
|
|
||||||
|
@ -520,11 +520,11 @@ Maybe<bool> GetRsaKeyDetail(
|
||||||
|
|
||||||
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
||||||
// versions older than 1.1.1e via FIPS / dynamic linking.
|
// versions older than 1.1.1e via FIPS / dynamic linking.
|
||||||
RSA* rsa;
|
const RSA* rsa;
|
||||||
if (OpenSSL_version_num() >= 0x1010105fL) {
|
if (OpenSSL_version_num() >= 0x1010105fL) {
|
||||||
rsa = EVP_PKEY_get0_RSA(m_pkey.get());
|
rsa = EVP_PKEY_get0_RSA(m_pkey.get());
|
||||||
} else {
|
} else {
|
||||||
rsa = static_cast<RSA*>(EVP_PKEY_get0(m_pkey.get()));
|
rsa = static_cast<const RSA*>(EVP_PKEY_get0(m_pkey.get()));
|
||||||
}
|
}
|
||||||
CHECK_NOT_NULL(rsa);
|
CHECK_NOT_NULL(rsa);
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,13 @@ namespace crypto {
|
||||||
namespace {
|
namespace {
|
||||||
bool ValidateDSAParameters(EVP_PKEY* key) {
|
bool ValidateDSAParameters(EVP_PKEY* key) {
|
||||||
/* Validate DSA2 parameters from FIPS 186-4 */
|
/* Validate DSA2 parameters from FIPS 186-4 */
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (EVP_default_properties_is_fips_enabled(nullptr) &&
|
||||||
|
EVP_PKEY_DSA == EVP_PKEY_base_id(key)) {
|
||||||
|
#else
|
||||||
if (FIPS_mode() && EVP_PKEY_DSA == EVP_PKEY_base_id(key)) {
|
if (FIPS_mode() && EVP_PKEY_DSA == EVP_PKEY_base_id(key)) {
|
||||||
DSA* dsa = EVP_PKEY_get0_DSA(key);
|
#endif
|
||||||
|
const DSA* dsa = EVP_PKEY_get0_DSA(key);
|
||||||
const BIGNUM* p;
|
const BIGNUM* p;
|
||||||
DSA_get0_pqg(dsa, &p, nullptr, nullptr);
|
DSA_get0_pqg(dsa, &p, nullptr, nullptr);
|
||||||
size_t L = BN_num_bits(p);
|
size_t L = BN_num_bits(p);
|
||||||
|
@ -103,11 +108,11 @@ unsigned int GetBytesOfRS(const ManagedEVPPKey& pkey) {
|
||||||
int bits, base_id = EVP_PKEY_base_id(pkey.get());
|
int bits, base_id = EVP_PKEY_base_id(pkey.get());
|
||||||
|
|
||||||
if (base_id == EVP_PKEY_DSA) {
|
if (base_id == EVP_PKEY_DSA) {
|
||||||
DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get());
|
const DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get());
|
||||||
// Both r and s are computed mod q, so their width is limited by that of q.
|
// Both r and s are computed mod q, so their width is limited by that of q.
|
||||||
bits = BN_num_bits(DSA_get0_q(dsa_key));
|
bits = BN_num_bits(DSA_get0_q(dsa_key));
|
||||||
} else if (base_id == EVP_PKEY_EC) {
|
} else if (base_id == EVP_PKEY_EC) {
|
||||||
EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
|
const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
|
||||||
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
|
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
|
||||||
bits = EC_GROUP_order_bits(ec_group);
|
bits = EC_GROUP_order_bits(ec_group);
|
||||||
} else {
|
} else {
|
||||||
|
@ -873,7 +878,7 @@ bool SignTraits::DeriveBits(
|
||||||
case SignConfiguration::kSign: {
|
case SignConfiguration::kSign: {
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char* data = nullptr;
|
unsigned char* data = nullptr;
|
||||||
if (IsOneShot(params.key->GetAsymmetricKey())) {
|
if (IsOneShot(m_pkey)) {
|
||||||
EVP_DigestSign(
|
EVP_DigestSign(
|
||||||
context.get(),
|
context.get(),
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -905,10 +910,7 @@ bool SignTraits::DeriveBits(
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (UseP1363Encoding(m_pkey, params.dsa_encoding)) {
|
if (UseP1363Encoding(m_pkey, params.dsa_encoding)) {
|
||||||
*out = ConvertSignatureToP1363(
|
*out = ConvertSignatureToP1363(env, m_pkey, buf);
|
||||||
env,
|
|
||||||
params.key->GetAsymmetricKey(),
|
|
||||||
buf);
|
|
||||||
} else {
|
} else {
|
||||||
buf.Resize(len);
|
buf.Resize(len);
|
||||||
*out = std::move(buf);
|
*out = std::move(buf);
|
||||||
|
|
|
@ -137,7 +137,12 @@ void InitCryptoOnce() {
|
||||||
unsigned long err = 0; // NOLINT(runtime/int)
|
unsigned long err = 0; // NOLINT(runtime/int)
|
||||||
if (per_process::cli_options->enable_fips_crypto ||
|
if (per_process::cli_options->enable_fips_crypto ||
|
||||||
per_process::cli_options->force_fips_crypto) {
|
per_process::cli_options->force_fips_crypto) {
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (0 == EVP_default_properties_is_fips_enabled(nullptr) &&
|
||||||
|
!EVP_default_properties_enable_fips(nullptr, 1)) {
|
||||||
|
#else
|
||||||
if (0 == FIPS_mode() && !FIPS_mode_set(1)) {
|
if (0 == FIPS_mode() && !FIPS_mode_set(1)) {
|
||||||
|
#endif
|
||||||
err = ERR_get_error();
|
err = ERR_get_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +165,12 @@ void InitCryptoOnce() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
args.GetReturnValue().Set(EVP_default_properties_is_fips_enabled(nullptr) ?
|
||||||
|
1 : 0);
|
||||||
|
#else
|
||||||
args.GetReturnValue().Set(FIPS_mode() ? 1 : 0);
|
args.GetReturnValue().Set(FIPS_mode() ? 1 : 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
@ -168,10 +178,18 @@ void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
bool enable = args[0]->BooleanValue(env->isolate());
|
bool enable = args[0]->BooleanValue(env->isolate());
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (enable == EVP_default_properties_is_fips_enabled(nullptr))
|
||||||
|
#else
|
||||||
if (enable == FIPS_mode())
|
if (enable == FIPS_mode())
|
||||||
|
#endif
|
||||||
return; // No action needed.
|
return; // No action needed.
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (!EVP_default_properties_enable_fips(nullptr, enable)) {
|
||||||
|
#else
|
||||||
if (!FIPS_mode_set(enable)) {
|
if (!FIPS_mode_set(enable)) {
|
||||||
|
#endif
|
||||||
unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
|
unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
|
||||||
return ThrowCryptoError(env, err);
|
return ThrowCryptoError(env, err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1015,8 +1015,12 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
// In the case of FIPS builds we should make sure
|
// In the case of FIPS builds we should make sure
|
||||||
// the random source is properly initialized first.
|
// the random source is properly initialized first.
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (EVP_default_properties_is_fips_enabled(nullptr)) {
|
||||||
|
#else
|
||||||
if (FIPS_mode()) {
|
if (FIPS_mode()) {
|
||||||
OPENSSL_init();
|
OPENSSL_init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
// V8 on Windows doesn't have a good source of entropy. Seed it from
|
// V8 on Windows doesn't have a good source of entropy. Seed it from
|
||||||
// OpenSSL's pool.
|
// OpenSSL's pool.
|
||||||
|
|
|
@ -51,6 +51,9 @@ const noop = () => {};
|
||||||
const hasCrypto = Boolean(process.versions.openssl) &&
|
const hasCrypto = Boolean(process.versions.openssl) &&
|
||||||
!process.env.NODE_SKIP_CRYPTO;
|
!process.env.NODE_SKIP_CRYPTO;
|
||||||
|
|
||||||
|
const hasOpenSSL3 = hasCrypto &&
|
||||||
|
require('crypto').constants.OPENSSL_VERSION_NUMBER >= 805306368;
|
||||||
|
|
||||||
// Check for flags. Skip this for workers (both, the `cluster` module and
|
// Check for flags. Skip this for workers (both, the `cluster` module and
|
||||||
// `worker_threads`) and child processes.
|
// `worker_threads`) and child processes.
|
||||||
// If the binary was built without-ssl then the crypto flags are
|
// If the binary was built without-ssl then the crypto flags are
|
||||||
|
@ -726,6 +729,7 @@ const common = {
|
||||||
getTTYfd,
|
getTTYfd,
|
||||||
hasIntl,
|
hasIntl,
|
||||||
hasCrypto,
|
hasCrypto,
|
||||||
|
hasOpenSSL3,
|
||||||
hasMultiLocalhost,
|
hasMultiLocalhost,
|
||||||
invalidArgTypeHelper,
|
invalidArgTypeHelper,
|
||||||
isAIX,
|
isAIX,
|
||||||
|
|
|
@ -583,7 +583,8 @@ assert.throws(
|
||||||
// Test Diffie-Hellman with two parties sharing a secret,
|
// Test Diffie-Hellman with two parties sharing a secret,
|
||||||
// using various encodings as we go along
|
// using various encodings as we go along
|
||||||
{
|
{
|
||||||
const dh1 = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256);
|
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
|
||||||
|
const dh1 = crypto.createDiffieHellman(size);
|
||||||
const p1 = dh1.getPrime('buffer');
|
const p1 = dh1.getPrime('buffer');
|
||||||
const dh2 = crypto.createDiffieHellman(p1, 'base64');
|
const dh2 = crypto.createDiffieHellman(p1, 'base64');
|
||||||
const key1 = dh1.generateKeys();
|
const key1 = dh1.generateKeys();
|
||||||
|
|
|
@ -193,7 +193,9 @@ assert.throws(
|
||||||
errMessage);
|
errMessage);
|
||||||
|
|
||||||
// But all other IV lengths should be accepted.
|
// But all other IV lengths should be accepted.
|
||||||
for (let n = 1; n < 256; n += 1) {
|
const minIvLength = common.hasOpenSSL3 ? 8 : 1;
|
||||||
|
const maxIvLength = common.hasOpenSSL3 ? 64 : 256;
|
||||||
|
for (let n = minIvLength; n < maxIvLength; n += 1) {
|
||||||
if (common.hasFipsCrypto && n < 12) continue;
|
if (common.hasFipsCrypto && n < 12) continue;
|
||||||
crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), Buffer.alloc(n));
|
crypto.createCipheriv('aes-128-gcm', Buffer.alloc(16), Buffer.alloc(n));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const TEST_CASES = {
|
||||||
if (!common.hasFipsCrypto) {
|
if (!common.hasFipsCrypto) {
|
||||||
TEST_CASES.Cipher = ['aes192', 'secret'];
|
TEST_CASES.Cipher = ['aes192', 'secret'];
|
||||||
TEST_CASES.Decipher = ['aes192', 'secret'];
|
TEST_CASES.Decipher = ['aes192', 'secret'];
|
||||||
TEST_CASES.DiffieHellman = [256];
|
TEST_CASES.DiffieHellman = [common.hasOpenSSL3 ? 1024 : 256];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [clazz, args] of Object.entries(TEST_CASES)) {
|
for (const [clazz, args] of Object.entries(TEST_CASES)) {
|
||||||
|
|
|
@ -12,7 +12,8 @@ const crypto = require('crypto');
|
||||||
|
|
||||||
const before = process.memoryUsage.rss();
|
const before = process.memoryUsage.rss();
|
||||||
{
|
{
|
||||||
const dh = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256);
|
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
|
||||||
|
const dh = crypto.createDiffieHellman(size);
|
||||||
const publicKey = dh.generateKeys();
|
const publicKey = dh.generateKeys();
|
||||||
const privateKey = dh.getPrivateKey();
|
const privateKey = dh.getPrivateKey();
|
||||||
for (let i = 0; i < 5e4; i += 1) {
|
for (let i = 0; i < 5e4; i += 1) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ const crypto = require('crypto');
|
||||||
function test() {
|
function test() {
|
||||||
const odd = Buffer.alloc(39, 'A');
|
const odd = Buffer.alloc(39, 'A');
|
||||||
|
|
||||||
const c = crypto.createDiffieHellman(32);
|
const c = crypto.createDiffieHellman(common.hasOpenSSL3 ? 1024 : 32);
|
||||||
c.setPrivateKey(odd);
|
c.setPrivateKey(odd);
|
||||||
c.generateKeys();
|
c.generateKeys();
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ const alicePrivateKey = crypto.createPrivateKey({
|
||||||
'-----END PRIVATE KEY-----',
|
'-----END PRIVATE KEY-----',
|
||||||
format: 'pem'
|
format: 'pem'
|
||||||
});
|
});
|
||||||
|
|
||||||
const alicePublicKey = crypto.createPublicKey({
|
const alicePublicKey = crypto.createPublicKey({
|
||||||
key: '-----BEGIN PUBLIC KEY-----\n' +
|
key: '-----BEGIN PUBLIC KEY-----\n' +
|
||||||
'MIIBnzCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' +
|
'MIIBnzCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' +
|
||||||
|
@ -135,7 +134,6 @@ const dh = crypto.createDiffieHellman(group.getPrime(), group.getGenerator());
|
||||||
dh.setPrivateKey(privateKey);
|
dh.setPrivateKey(privateKey);
|
||||||
|
|
||||||
// Test simple Diffie-Hellman, no curves involved.
|
// Test simple Diffie-Hellman, no curves involved.
|
||||||
|
|
||||||
test({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
|
test({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
|
||||||
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
|
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
|
||||||
dh.computeSecret(publicKey));
|
dh.computeSecret(publicKey));
|
||||||
|
@ -146,23 +144,31 @@ test(crypto.generateKeyPairSync('dh', { group: 'modp5' }),
|
||||||
test(crypto.generateKeyPairSync('dh', { group: 'modp5' }),
|
test(crypto.generateKeyPairSync('dh', { group: 'modp5' }),
|
||||||
crypto.generateKeyPairSync('dh', { prime: group.getPrime() }));
|
crypto.generateKeyPairSync('dh', { prime: group.getPrime() }));
|
||||||
|
|
||||||
for (const [params1, params2] of [
|
const list = [
|
||||||
// Same generator, but different primes.
|
// Same generator, but different primes.
|
||||||
[{ group: 'modp5' }, { group: 'modp18' }],
|
[{ group: 'modp5' }, { group: 'modp18' }]];
|
||||||
|
|
||||||
|
// TODO(danbev): Take a closer look if there should be a check in OpenSSL3
|
||||||
|
// when the dh parameters differ.
|
||||||
|
if (!common.hasOpenSSL3) {
|
||||||
// Same primes, but different generator.
|
// Same primes, but different generator.
|
||||||
[{ group: 'modp5' }, { prime: group.getPrime(), generator: 5 }],
|
list.push([{ group: 'modp5' }, { prime: group.getPrime(), generator: 5 }]);
|
||||||
// Same generator, but different primes.
|
// Same generator, but different primes.
|
||||||
[{ primeLength: 1024 }, { primeLength: 1024 }]
|
list.push([{ primeLength: 1024 }, { primeLength: 1024 }]);
|
||||||
]) {
|
}
|
||||||
|
|
||||||
|
for (const [params1, params2] of list) {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
test(crypto.generateKeyPairSync('dh', params1),
|
test(crypto.generateKeyPairSync('dh', params1),
|
||||||
crypto.generateKeyPairSync('dh', params2));
|
crypto.generateKeyPairSync('dh', params2));
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
name: 'Error',
|
||||||
|
code: 'ERR_OSSL_DH_INVALID_PUBLIC_KEY'
|
||||||
|
} : {
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
|
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const privateKey = crypto.createPrivateKey({
|
const privateKey = crypto.createPrivateKey({
|
||||||
key: '-----BEGIN PRIVATE KEY-----\n' +
|
key: '-----BEGIN PRIVATE KEY-----\n' +
|
||||||
|
@ -214,7 +220,10 @@ const not256k1 = crypto.getCurves().find((c) => /^sec.*(224|384|512)/.test(c));
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
test(crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }),
|
test(crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }),
|
||||||
crypto.generateKeyPairSync('ec', { namedCurve: not256k1 }));
|
crypto.generateKeyPairSync('ec', { namedCurve: not256k1 }));
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
name: 'Error',
|
||||||
|
code: 'ERR_OSSL_EC_INCOMPATIBLE_OBJECTS'
|
||||||
|
} : {
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
|
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,7 +8,8 @@ const crypto = require('crypto');
|
||||||
|
|
||||||
// Test Diffie-Hellman with two parties sharing a secret,
|
// Test Diffie-Hellman with two parties sharing a secret,
|
||||||
// using various encodings as we go along
|
// using various encodings as we go along
|
||||||
const dh1 = crypto.createDiffieHellman(common.hasFipsCrypto ? 1024 : 256);
|
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
|
||||||
|
const dh1 = crypto.createDiffieHellman(size);
|
||||||
const p1 = dh1.getPrime('buffer');
|
const p1 = dh1.getPrime('buffer');
|
||||||
const dh2 = crypto.createDiffieHellman(p1, 'buffer');
|
const dh2 = crypto.createDiffieHellman(p1, 'buffer');
|
||||||
let key1 = dh1.generateKeys();
|
let key1 = dh1.generateKeys();
|
||||||
|
@ -38,11 +39,19 @@ assert.throws(() => crypto.createDiffieHellman('abcdef', 13.37), {
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const bits of [-1, 0, 1]) {
|
for (const bits of [-1, 0, 1]) {
|
||||||
assert.throws(() => crypto.createDiffieHellman(bits), {
|
if (common.hasOpenSSL3) {
|
||||||
code: 'ERR_OSSL_BN_BITS_TOO_SMALL',
|
assert.throws(() => crypto.createDiffieHellman(bits), {
|
||||||
name: 'Error',
|
code: 'ERR_OSSL_DH_MODULUS_TOO_SMALL',
|
||||||
message: /bits too small/,
|
name: 'Error',
|
||||||
});
|
message: /modulus too small/,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
assert.throws(() => crypto.createDiffieHellman(bits), {
|
||||||
|
code: 'ERR_OSSL_BN_BITS_TOO_SMALL',
|
||||||
|
name: 'Error',
|
||||||
|
message: /bits too small/,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Through a fluke of history, g=0 defaults to DH_GENERATOR (2).
|
// Through a fluke of history, g=0 defaults to DH_GENERATOR (2).
|
||||||
|
@ -143,13 +152,23 @@ const secret4 = dh4.computeSecret(key2, 'hex', 'base64');
|
||||||
|
|
||||||
assert.strictEqual(secret1, secret4);
|
assert.strictEqual(secret1, secret4);
|
||||||
|
|
||||||
const wrongBlockLength = {
|
let wrongBlockLength;
|
||||||
message: 'error:0606506D:digital envelope' +
|
if (common.hasOpenSSL3) {
|
||||||
' routines:EVP_DecryptFinal_ex:wrong final block length',
|
wrongBlockLength = {
|
||||||
code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH',
|
message: 'error:1C80006B:Provider routines::wrong final block length',
|
||||||
library: 'digital envelope routines',
|
code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH',
|
||||||
reason: 'wrong final block length'
|
library: 'Provider routines',
|
||||||
};
|
reason: 'wrong final block length'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
wrongBlockLength = {
|
||||||
|
message: 'error:0606506D:digital envelope' +
|
||||||
|
' routines:EVP_DecryptFinal_ex:wrong final block length',
|
||||||
|
code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH',
|
||||||
|
library: 'digital envelope routines',
|
||||||
|
reason: 'wrong final block length'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Run this one twice to make sure that the dh3 clears its error properly
|
// Run this one twice to make sure that the dh3 clears its error properly
|
||||||
{
|
{
|
||||||
|
@ -168,7 +187,9 @@ const wrongBlockLength = {
|
||||||
|
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
dh3.computeSecret('');
|
dh3.computeSecret('');
|
||||||
}, { message: 'Supplied key is too small' });
|
}, { message: common.hasOpenSSL3 ?
|
||||||
|
'error:02800066:Diffie-Hellman routines::invalid public key' :
|
||||||
|
'Supplied key is too small' });
|
||||||
|
|
||||||
// Create a shared using a DH group.
|
// Create a shared using a DH group.
|
||||||
const alice = crypto.createDiffieHellmanGroup('modp5');
|
const alice = crypto.createDiffieHellmanGroup('modp5');
|
||||||
|
|
|
@ -27,6 +27,10 @@ if (!common.hasCrypto)
|
||||||
if (common.hasFipsCrypto)
|
if (common.hasFipsCrypto)
|
||||||
common.skip('BF-ECB is not FIPS 140-2 compatible');
|
common.skip('BF-ECB is not FIPS 140-2 compatible');
|
||||||
|
|
||||||
|
if (common.hasOpenSSL3)
|
||||||
|
common.skip('Blowfish is only available with the legacy provider in ' +
|
||||||
|
'OpenSSl 3.x');
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
|
|
@ -66,21 +66,6 @@ testHelper(
|
||||||
'require("crypto").getFips()',
|
'require("crypto").getFips()',
|
||||||
{ ...process.env, 'OPENSSL_CONF': '' });
|
{ ...process.env, 'OPENSSL_CONF': '' });
|
||||||
|
|
||||||
// --enable-fips should turn FIPS mode on
|
|
||||||
testHelper(
|
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
|
||||||
['--enable-fips'],
|
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
|
||||||
'require("crypto").getFips()',
|
|
||||||
process.env);
|
|
||||||
|
|
||||||
// --force-fips should turn FIPS mode on
|
|
||||||
testHelper(
|
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
|
||||||
['--force-fips'],
|
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
|
||||||
'require("crypto").getFips()',
|
|
||||||
process.env);
|
|
||||||
|
|
||||||
// If Node was configured using --shared-openssl fips support might be
|
// If Node was configured using --shared-openssl fips support might be
|
||||||
// available depending on how OpenSSL was built. If fips support is
|
// available depending on how OpenSSL was built. If fips support is
|
||||||
|
@ -120,120 +105,140 @@ if (!sharedOpenSSL()) {
|
||||||
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
||||||
}
|
}
|
||||||
|
|
||||||
testHelper(
|
// OpenSSL 3.x has changed the configuration files so the following tests
|
||||||
'stdout',
|
// will not work as expected with that version.
|
||||||
[`--openssl-config=${CNF_FIPS_OFF}`],
|
// TODO(danbev) Revisit these test once FIPS support is available in
|
||||||
FIPS_DISABLED,
|
// OpenSSL 3.x.
|
||||||
'require("crypto").getFips()',
|
if (!common.hasOpenSSL3) {
|
||||||
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
|
testHelper(
|
||||||
|
'stdout',
|
||||||
|
[`--openssl-config=${CNF_FIPS_OFF}`],
|
||||||
|
FIPS_DISABLED,
|
||||||
|
'require("crypto").getFips()',
|
||||||
|
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_ON }));
|
||||||
|
|
||||||
// --enable-fips should take precedence over OpenSSL config file
|
// --enable-fips should take precedence over OpenSSL config file
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`],
|
['--enable-fips', `--openssl-config=${CNF_FIPS_OFF}`],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").getFips()',
|
'require("crypto").getFips()',
|
||||||
process.env);
|
process.env);
|
||||||
|
// --force-fips should take precedence over OpenSSL config file
|
||||||
|
testHelper(
|
||||||
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
|
['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`],
|
||||||
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
|
'require("crypto").getFips()',
|
||||||
|
process.env);
|
||||||
|
// --enable-fips should turn FIPS mode on
|
||||||
|
testHelper(
|
||||||
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
|
['--enable-fips'],
|
||||||
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
|
'require("crypto").getFips()',
|
||||||
|
process.env);
|
||||||
|
|
||||||
// OPENSSL_CONF should _not_ make a difference to --enable-fips
|
// --force-fips should turn FIPS mode on
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--enable-fips'],
|
['--force-fips'],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").getFips()',
|
'require("crypto").getFips()',
|
||||||
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
process.env);
|
||||||
|
|
||||||
// --force-fips should take precedence over OpenSSL config file
|
// OPENSSL_CONF should _not_ make a difference to --enable-fips
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--force-fips', `--openssl-config=${CNF_FIPS_OFF}`],
|
['--enable-fips'],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").getFips()',
|
'require("crypto").getFips()',
|
||||||
process.env);
|
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
||||||
|
|
||||||
// Using OPENSSL_CONF should not make a difference to --force-fips
|
// Using OPENSSL_CONF should not make a difference to --force-fips
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--force-fips'],
|
['--force-fips'],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").getFips()',
|
'require("crypto").getFips()',
|
||||||
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
Object.assign({}, process.env, { 'OPENSSL_CONF': CNF_FIPS_OFF }));
|
||||||
|
|
||||||
// setFipsCrypto should be able to turn FIPS mode on
|
// setFipsCrypto should be able to turn FIPS mode on
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
[],
|
[],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'(require("crypto").setFips(true),' +
|
'(require("crypto").setFips(true),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// setFipsCrypto should be able to turn FIPS mode on and off
|
// setFipsCrypto should be able to turn FIPS mode on and off
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
[],
|
[],
|
||||||
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'(require("crypto").setFips(true),' +
|
'(require("crypto").setFips(true),' +
|
||||||
'require("crypto").setFips(false),' +
|
'require("crypto").setFips(false),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// setFipsCrypto takes precedence over OpenSSL config file, FIPS on
|
// setFipsCrypto takes precedence over OpenSSL config file, FIPS on
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
[`--openssl-config=${CNF_FIPS_OFF}`],
|
[`--openssl-config=${CNF_FIPS_OFF}`],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'(require("crypto").setFips(true),' +
|
'(require("crypto").setFips(true),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// setFipsCrypto takes precedence over OpenSSL config file, FIPS off
|
// setFipsCrypto takes precedence over OpenSSL config file, FIPS off
|
||||||
testHelper(
|
testHelper(
|
||||||
'stdout',
|
'stdout',
|
||||||
[`--openssl-config=${CNF_FIPS_ON}`],
|
[`--openssl-config=${CNF_FIPS_ON}`],
|
||||||
FIPS_DISABLED,
|
FIPS_DISABLED,
|
||||||
'(require("crypto").setFips(false),' +
|
'(require("crypto").setFips(false),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// --enable-fips does not prevent use of setFipsCrypto API
|
// --enable-fips does not prevent use of setFipsCrypto API
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--enable-fips'],
|
['--enable-fips'],
|
||||||
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_DISABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'(require("crypto").setFips(false),' +
|
'(require("crypto").setFips(false),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// --force-fips prevents use of setFipsCrypto API
|
// --force-fips prevents use of setFipsCrypto API
|
||||||
testHelper(
|
testHelper(
|
||||||
'stderr',
|
'stderr',
|
||||||
['--force-fips'],
|
['--force-fips'],
|
||||||
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").setFips(false)',
|
'require("crypto").setFips(false)',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// --force-fips makes setFipsCrypto enable a no-op (FIPS stays on)
|
// --force-fips makes setFipsCrypto enable a no-op (FIPS stays on)
|
||||||
testHelper(
|
testHelper(
|
||||||
testFipsCrypto() ? 'stdout' : 'stderr',
|
testFipsCrypto() ? 'stdout' : 'stderr',
|
||||||
['--force-fips'],
|
['--force-fips'],
|
||||||
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ENABLED : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'(require("crypto").setFips(true),' +
|
'(require("crypto").setFips(true),' +
|
||||||
'require("crypto").getFips())',
|
'require("crypto").getFips())',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// --force-fips and --enable-fips order does not matter
|
// --force-fips and --enable-fips order does not matter
|
||||||
testHelper(
|
testHelper(
|
||||||
'stderr',
|
'stderr',
|
||||||
['--force-fips', '--enable-fips'],
|
['--force-fips', '--enable-fips'],
|
||||||
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").setFips(false)',
|
'require("crypto").setFips(false)',
|
||||||
process.env);
|
process.env);
|
||||||
|
|
||||||
// --enable-fips and --force-fips order does not matter
|
// --enable-fips and --force-fips order does not matter
|
||||||
testHelper(
|
testHelper(
|
||||||
'stderr',
|
'stderr',
|
||||||
['--enable-fips', '--force-fips'],
|
['--enable-fips', '--force-fips'],
|
||||||
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
testFipsCrypto() ? FIPS_ERROR_STRING2 : FIPS_UNSUPPORTED_ERROR_STRING,
|
||||||
'require("crypto").setFips(false)',
|
'require("crypto").setFips(false)',
|
||||||
process.env);
|
process.env);
|
||||||
|
}
|
||||||
|
|
|
@ -113,11 +113,14 @@ const {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[
|
const algorithms = [
|
||||||
['sha256', 'secret', 'salt', 'info', 10],
|
['sha256', 'secret', 'salt', 'info', 10],
|
||||||
['sha512', 'secret', 'salt', '', 15],
|
['sha512', 'secret', 'salt', '', 15],
|
||||||
['whirlpool', 'secret', '', 'info', 20],
|
];
|
||||||
].forEach(([ hash, secret, salt, info, length ]) => {
|
if (!common.hasOpenSSL3)
|
||||||
|
algorithms.push(['whirlpool', 'secret', '', 'info', 20]);
|
||||||
|
|
||||||
|
algorithms.forEach(([ hash, secret, salt, info, length ]) => {
|
||||||
{
|
{
|
||||||
const syncResult = hkdfSync(hash, secret, salt, info, length);
|
const syncResult = hkdfSync(hash, secret, salt, info, length);
|
||||||
assert(syncResult instanceof ArrayBuffer);
|
assert(syncResult instanceof ArrayBuffer);
|
||||||
|
@ -204,7 +207,8 @@ const {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
|
||||||
|
if (!common.hasOpenSSL3) {
|
||||||
const kKnownUnsupported = ['shake128', 'shake256'];
|
const kKnownUnsupported = ['shake128', 'shake256'];
|
||||||
getHashes()
|
getHashes()
|
||||||
.filter((hash) => !kKnownUnsupported.includes(hash))
|
.filter((hash) => !kKnownUnsupported.includes(hash))
|
||||||
|
|
|
@ -292,7 +292,9 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||||
// This should not cause a crash: https://github.com/nodejs/node/issues/25247
|
// This should not cause a crash: https://github.com/nodejs/node/issues/25247
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
createPrivateKey({ key: '' });
|
createPrivateKey({ key: '' });
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
message: 'Failed to read private key',
|
||||||
|
} : {
|
||||||
message: 'error:0909006C:PEM routines:get_name:no start line',
|
message: 'error:0909006C:PEM routines:get_name:no start line',
|
||||||
code: 'ERR_OSSL_PEM_NO_START_LINE',
|
code: 'ERR_OSSL_PEM_NO_START_LINE',
|
||||||
reason: 'no start line',
|
reason: 'no start line',
|
||||||
|
@ -500,7 +502,10 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||||
|
|
||||||
{
|
{
|
||||||
// Reading an encrypted key without a passphrase should fail.
|
// Reading an encrypted key without a passphrase should fail.
|
||||||
assert.throws(() => createPrivateKey(privateDsa), {
|
assert.throws(() => createPrivateKey(privateDsa), common.hasOpenSSL3 ? {
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Failed to read private key',
|
||||||
|
} : {
|
||||||
name: 'TypeError',
|
name: 'TypeError',
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
message: 'Passphrase required for encrypted key'
|
message: 'Passphrase required for encrypted key'
|
||||||
|
@ -512,7 +517,7 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||||
key: privateDsa,
|
key: privateDsa,
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
passphrase: Buffer.alloc(1025, 'a')
|
passphrase: Buffer.alloc(1025, 'a')
|
||||||
}), {
|
}), common.hasOpenSSL3 ? { name: 'Error' } : {
|
||||||
code: 'ERR_OSSL_PEM_BAD_PASSWORD_READ',
|
code: 'ERR_OSSL_PEM_BAD_PASSWORD_READ',
|
||||||
name: 'Error'
|
name: 'Error'
|
||||||
});
|
});
|
||||||
|
@ -524,7 +529,9 @@ const privateDsa = fixtures.readKey('dsa_private_encrypted_1025.pem',
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
passphrase: Buffer.alloc(1024, 'a')
|
passphrase: Buffer.alloc(1024, 'a')
|
||||||
}), {
|
}), {
|
||||||
message: /bad decrypt/
|
message: common.hasOpenSSL3 ?
|
||||||
|
'Failed to read private key' :
|
||||||
|
/bad decrypt/
|
||||||
});
|
});
|
||||||
|
|
||||||
const publicKey = createPublicKey(publicDsa);
|
const publicKey = createPublicKey(publicDsa);
|
||||||
|
|
|
@ -192,7 +192,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
|
|
||||||
// Now do the same with an encrypted private key.
|
// Now do the same with an encrypted private key.
|
||||||
generateKeyPair('rsa', {
|
generateKeyPair('rsa', {
|
||||||
publicExponent: 0x1001,
|
publicExponent: 0x10001,
|
||||||
modulusLength: 512,
|
modulusLength: 512,
|
||||||
publicKeyEncoding,
|
publicKeyEncoding,
|
||||||
privateKeyEncoding: {
|
privateKeyEncoding: {
|
||||||
|
@ -210,11 +210,15 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
const publicKey = { key: publicKeyDER, ...publicKeyEncoding };
|
const publicKey = { key: publicKeyDER, ...publicKeyEncoding };
|
||||||
assert.throws(() => testSignVerify(publicKey, privateKey), {
|
const expectedError = common.hasOpenSSL3 ? {
|
||||||
|
name: 'Error',
|
||||||
|
message: 'Failed to read private key'
|
||||||
|
} : {
|
||||||
name: 'TypeError',
|
name: 'TypeError',
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
message: 'Passphrase required for encrypted key'
|
message: 'Passphrase required for encrypted key'
|
||||||
});
|
};
|
||||||
|
assert.throws(() => testSignVerify(publicKey, privateKey), expectedError);
|
||||||
|
|
||||||
const key = { key: privateKey, passphrase: 'secret' };
|
const key = { key: privateKey, passphrase: 'secret' };
|
||||||
testEncryptDecrypt(publicKey, key);
|
testEncryptDecrypt(publicKey, key);
|
||||||
|
@ -342,7 +346,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
|
|
||||||
// Test async DSA key generation.
|
// Test async DSA key generation.
|
||||||
generateKeyPair('dsa', {
|
generateKeyPair('dsa', {
|
||||||
modulusLength: 512,
|
modulusLength: common.hasOpenSSL3 ? 2048 : 512,
|
||||||
divisorLength: 256,
|
divisorLength: 256,
|
||||||
publicKeyEncoding: {
|
publicKeyEncoding: {
|
||||||
type: 'spki',
|
type: 'spki',
|
||||||
|
@ -359,8 +363,8 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
// The private key is DER-encoded.
|
// The private key is DER-encoded.
|
||||||
assert(Buffer.isBuffer(privateKeyDER));
|
assert(Buffer.isBuffer(privateKeyDER));
|
||||||
|
|
||||||
assertApproximateSize(publicKey, 440);
|
assertApproximateSize(publicKey, common.hasOpenSSL3 ? 1194 : 440);
|
||||||
assertApproximateSize(privateKeyDER, 336);
|
assertApproximateSize(privateKeyDER, common.hasOpenSSL3 ? 721 : 336);
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
|
@ -382,7 +386,6 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test async DSA key object generation.
|
// Test async DSA key object generation.
|
||||||
generateKeyPair('dsa', {
|
generateKeyPair('dsa', {
|
||||||
|
@ -471,11 +474,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
assert(sec1EncExp('AES-128-CBC').test(privateKey));
|
assert(sec1EncExp('AES-128-CBC').test(privateKey));
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
assert.throws(() => testSignVerify(publicKey, privateKey), {
|
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||||
name: 'TypeError',
|
common.hasOpenSSL3 ? {
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
message: 'Failed to read private key'
|
||||||
message: 'Passphrase required for encrypted key'
|
} : {
|
||||||
});
|
name: 'TypeError',
|
||||||
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
|
message: 'Passphrase required for encrypted key'
|
||||||
|
});
|
||||||
|
|
||||||
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
||||||
}));
|
}));
|
||||||
|
@ -501,11 +507,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
assert(sec1EncExp('AES-128-CBC').test(privateKey));
|
assert(sec1EncExp('AES-128-CBC').test(privateKey));
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
assert.throws(() => testSignVerify(publicKey, privateKey), {
|
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||||
name: 'TypeError',
|
common.hasOpenSSL3 ? {
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
message: 'Failed to read private key'
|
||||||
message: 'Passphrase required for encrypted key'
|
} : {
|
||||||
});
|
name: 'TypeError',
|
||||||
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
|
message: 'Passphrase required for encrypted key'
|
||||||
|
});
|
||||||
|
|
||||||
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
testSignVerify(publicKey, { key: privateKey, passphrase: 'secret' });
|
||||||
}));
|
}));
|
||||||
|
@ -534,11 +543,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
assert(pkcs8EncExp.test(privateKey));
|
assert(pkcs8EncExp.test(privateKey));
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
assert.throws(() => testSignVerify(publicKey, privateKey), {
|
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||||
name: 'TypeError',
|
common.hasOpenSSL3 ? {
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
message: 'Failed to read private key'
|
||||||
message: 'Passphrase required for encrypted key'
|
} : {
|
||||||
});
|
name: 'TypeError',
|
||||||
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
|
message: 'Passphrase required for encrypted key'
|
||||||
|
});
|
||||||
|
|
||||||
testSignVerify(publicKey, {
|
testSignVerify(publicKey, {
|
||||||
key: privateKey,
|
key: privateKey,
|
||||||
|
@ -568,11 +580,14 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
assert(pkcs8EncExp.test(privateKey));
|
assert(pkcs8EncExp.test(privateKey));
|
||||||
|
|
||||||
// Since the private key is encrypted, signing shouldn't work anymore.
|
// Since the private key is encrypted, signing shouldn't work anymore.
|
||||||
assert.throws(() => testSignVerify(publicKey, privateKey), {
|
assert.throws(() => testSignVerify(publicKey, privateKey),
|
||||||
name: 'TypeError',
|
common.hasOpenSSL3 ? {
|
||||||
code: 'ERR_MISSING_PASSPHRASE',
|
message: 'Failed to read private key'
|
||||||
message: 'Passphrase required for encrypted key'
|
} : {
|
||||||
});
|
name: 'TypeError',
|
||||||
|
code: 'ERR_MISSING_PASSPHRASE',
|
||||||
|
message: 'Passphrase required for encrypted key'
|
||||||
|
});
|
||||||
|
|
||||||
testSignVerify(publicKey, {
|
testSignVerify(publicKey, {
|
||||||
key: privateKey,
|
key: privateKey,
|
||||||
|
@ -1246,7 +1261,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (!common.hasOpenSSL3) {
|
||||||
// Passing an empty passphrase string should not cause OpenSSL's default
|
// Passing an empty passphrase string should not cause OpenSSL's default
|
||||||
// passphrase prompt in the terminal.
|
// passphrase prompt in the terminal.
|
||||||
// See https://github.com/nodejs/node/issues/35898.
|
// See https://github.com/nodejs/node/issues/35898.
|
||||||
|
|
|
@ -82,12 +82,17 @@ assert.strictEqual(enc(EVEN_LENGTH_PLAIN, true), EVEN_LENGTH_ENCRYPTED);
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
// Input must have block length %.
|
// Input must have block length %.
|
||||||
enc(ODD_LENGTH_PLAIN, false);
|
enc(ODD_LENGTH_PLAIN, false);
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
message: 'error:1C80006B:Provider routines::wrong final block length',
|
||||||
|
code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH',
|
||||||
|
reason: 'wrong final block length',
|
||||||
|
} : {
|
||||||
message: 'error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:' +
|
message: 'error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:' +
|
||||||
'data not multiple of block length',
|
'data not multiple of block length',
|
||||||
code: 'ERR_OSSL_EVP_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH',
|
code: 'ERR_OSSL_EVP_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH',
|
||||||
reason: 'data not multiple of block length',
|
reason: 'data not multiple of block length',
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
enc(EVEN_LENGTH_PLAIN, false), EVEN_LENGTH_ENCRYPTED_NOPAD
|
enc(EVEN_LENGTH_PLAIN, false), EVEN_LENGTH_ENCRYPTED_NOPAD
|
||||||
|
@ -104,7 +109,11 @@ assert.strictEqual(dec(EVEN_LENGTH_ENCRYPTED, false).length, 48);
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
// Must have at least 1 byte of padding (PKCS):
|
// Must have at least 1 byte of padding (PKCS):
|
||||||
assert.strictEqual(dec(EVEN_LENGTH_ENCRYPTED_NOPAD, true), EVEN_LENGTH_PLAIN);
|
assert.strictEqual(dec(EVEN_LENGTH_ENCRYPTED_NOPAD, true), EVEN_LENGTH_PLAIN);
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
message: 'error:1C800064:Provider routines::bad decrypt',
|
||||||
|
reason: 'bad decrypt',
|
||||||
|
code: 'ERR_OSSL_BAD_DECRYPT',
|
||||||
|
} : {
|
||||||
message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' +
|
message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' +
|
||||||
'bad decrypt',
|
'bad decrypt',
|
||||||
reason: 'bad decrypt',
|
reason: 'bad decrypt',
|
||||||
|
|
|
@ -223,9 +223,11 @@ assert.throws(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const kNotPBKDF2Supported = ['shake128', 'shake256'];
|
if (!common.hasOpenSSL3) {
|
||||||
crypto.getHashes()
|
const kNotPBKDF2Supported = ['shake128', 'shake256'];
|
||||||
.filter((hash) => !kNotPBKDF2Supported.includes(hash))
|
crypto.getHashes()
|
||||||
.forEach((hash) => {
|
.filter((hash) => !kNotPBKDF2Supported.includes(hash))
|
||||||
runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash);
|
.forEach((hash) => {
|
||||||
});
|
runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -34,5 +34,7 @@ function decrypt(key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypt(pkey);
|
decrypt(pkey);
|
||||||
assert.throws(() => decrypt(pkeyEncrypted), { code: 'ERR_MISSING_PASSPHRASE' });
|
assert.throws(() => decrypt(pkeyEncrypted), common.hasOpenSSL3 ?
|
||||||
|
{ message: 'Failed to read asymmetric key' } :
|
||||||
|
{ code: 'ERR_MISSING_PASSPHRASE' });
|
||||||
decrypt(pkey); // Should not throw.
|
decrypt(pkey); // Should not throw.
|
||||||
|
|
|
@ -27,7 +27,7 @@ const dsaPkcs8KeyPem = fixtures.readKey('dsa_private_pkcs8.pem');
|
||||||
|
|
||||||
const ec = new TextEncoder();
|
const ec = new TextEncoder();
|
||||||
|
|
||||||
const decryptError = {
|
const openssl1DecryptError = {
|
||||||
message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' +
|
message: 'error:06065064:digital envelope routines:EVP_DecryptFinal_ex:' +
|
||||||
'bad decrypt',
|
'bad decrypt',
|
||||||
code: 'ERR_OSSL_EVP_BAD_DECRYPT',
|
code: 'ERR_OSSL_EVP_BAD_DECRYPT',
|
||||||
|
@ -36,6 +36,13 @@ const decryptError = {
|
||||||
library: 'digital envelope routines',
|
library: 'digital envelope routines',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const decryptError = common.hasOpenSSL3 ?
|
||||||
|
{ message: 'Failed to read asymmetric key' } : openssl1DecryptError;
|
||||||
|
|
||||||
|
const decryptPrivateKeyError = common.hasOpenSSL3 ? {
|
||||||
|
message: 'Failed to read private key',
|
||||||
|
} : openssl1DecryptError;
|
||||||
|
|
||||||
function getBufferCopy(buf) {
|
function getBufferCopy(buf) {
|
||||||
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
||||||
}
|
}
|
||||||
|
@ -136,19 +143,25 @@ function getBufferCopy(buf) {
|
||||||
assert.strictEqual(decryptedBufferWithPassword.toString(), input);
|
assert.strictEqual(decryptedBufferWithPassword.toString(), input);
|
||||||
|
|
||||||
// Now with RSA_NO_PADDING. Plaintext needs to match key size.
|
// Now with RSA_NO_PADDING. Plaintext needs to match key size.
|
||||||
const plaintext = 'x'.repeat(rsaKeySize / 8);
|
// OpenSSL 3.x has a rsa_check_padding that will cause an error if
|
||||||
encryptedBuffer = crypto.privateEncrypt({
|
// RSA_NO_PADDING is used.
|
||||||
padding: crypto.constants.RSA_NO_PADDING,
|
if (!common.hasOpenSSL3) {
|
||||||
key: rsaKeyPemEncrypted,
|
{
|
||||||
passphrase: bufferPassword
|
const plaintext = 'x'.repeat(rsaKeySize / 8);
|
||||||
}, Buffer.from(plaintext));
|
encryptedBuffer = crypto.privateEncrypt({
|
||||||
|
padding: crypto.constants.RSA_NO_PADDING,
|
||||||
|
key: rsaKeyPemEncrypted,
|
||||||
|
passphrase: bufferPassword
|
||||||
|
}, Buffer.from(plaintext));
|
||||||
|
|
||||||
decryptedBufferWithPassword = crypto.publicDecrypt({
|
decryptedBufferWithPassword = crypto.publicDecrypt({
|
||||||
padding: crypto.constants.RSA_NO_PADDING,
|
padding: crypto.constants.RSA_NO_PADDING,
|
||||||
key: rsaKeyPemEncrypted,
|
key: rsaKeyPemEncrypted,
|
||||||
passphrase: bufferPassword
|
passphrase: bufferPassword
|
||||||
}, encryptedBuffer);
|
}, encryptedBuffer);
|
||||||
assert.strictEqual(decryptedBufferWithPassword.toString(), plaintext);
|
assert.strictEqual(decryptedBufferWithPassword.toString(), plaintext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encryptedBuffer = crypto.publicEncrypt(certPem, bufferToEncrypt);
|
encryptedBuffer = crypto.publicEncrypt(certPem, bufferToEncrypt);
|
||||||
|
|
||||||
|
@ -343,7 +356,7 @@ rsaSign.update(rsaPubPem);
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const signOptions = { key: rsaKeyPemEncrypted, passphrase: 'wrong' };
|
const signOptions = { key: rsaKeyPemEncrypted, passphrase: 'wrong' };
|
||||||
rsaSign.sign(signOptions, 'hex');
|
rsaSign.sign(signOptions, 'hex');
|
||||||
}, decryptError);
|
}, decryptPrivateKeyError);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Test RSA signing and verification
|
// Test RSA signing and verification
|
||||||
|
@ -442,7 +455,7 @@ const input = 'I AM THE WALRUS';
|
||||||
sign.update(input);
|
sign.update(input);
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
sign.sign({ key: dsaKeyPemEncrypted, passphrase: 'wrong' }, 'hex');
|
sign.sign({ key: dsaKeyPemEncrypted, passphrase: 'wrong' }, 'hex');
|
||||||
}, decryptError);
|
}, decryptPrivateKeyError);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,7 +29,8 @@ if (process.argv[2] === 'child') {
|
||||||
assert.strictEqual(a.used, 0);
|
assert.strictEqual(a.used, 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
const dh1 = createDiffieHellman(common.hasFipsCrypto ? 1024 : 256);
|
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
|
||||||
|
const dh1 = createDiffieHellman(size);
|
||||||
const p1 = dh1.getPrime('buffer');
|
const p1 = dh1.getPrime('buffer');
|
||||||
const dh2 = createDiffieHellman(p1, 'buffer');
|
const dh2 = createDiffieHellman(p1, 'buffer');
|
||||||
const key1 = dh1.generateKeys();
|
const key1 = dh1.generateKeys();
|
||||||
|
|
|
@ -44,7 +44,9 @@ const keySize = 2048;
|
||||||
`-----BEGIN RSA PRIVATE KEY-----
|
`-----BEGIN RSA PRIVATE KEY-----
|
||||||
AAAAAAAAAAAA
|
AAAAAAAAAAAA
|
||||||
-----END RSA PRIVATE KEY-----`);
|
-----END RSA PRIVATE KEY-----`);
|
||||||
}, { message: 'bye, bye, library' });
|
}, { message: common.hasOpenSSL3 ?
|
||||||
|
'Failed to read private key' :
|
||||||
|
'bye, bye, library' });
|
||||||
|
|
||||||
delete Object.prototype.library;
|
delete Object.prototype.library;
|
||||||
|
|
||||||
|
@ -63,7 +65,9 @@ const keySize = 2048;
|
||||||
key: keyPem,
|
key: keyPem,
|
||||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
||||||
});
|
});
|
||||||
}, { message: 'bye, bye, error stack' });
|
}, { message: common.hasOpenSSL3 ?
|
||||||
|
'error:1C8000A5:Provider routines::illegal or unsupported padding mode' :
|
||||||
|
'bye, bye, error stack' });
|
||||||
|
|
||||||
delete Object.prototype.opensslErrorStack;
|
delete Object.prototype.opensslErrorStack;
|
||||||
}
|
}
|
||||||
|
@ -339,7 +343,10 @@ assert.throws(
|
||||||
key: keyPem,
|
key: keyPem,
|
||||||
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
|
||||||
});
|
});
|
||||||
}, {
|
}, common.hasOpenSSL3 ? {
|
||||||
|
code: 'ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE',
|
||||||
|
message: /illegal or unsupported padding mode/,
|
||||||
|
} : {
|
||||||
code: 'ERR_OSSL_RSA_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE',
|
code: 'ERR_OSSL_RSA_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE',
|
||||||
message: /illegal or unsupported padding mode/,
|
message: /illegal or unsupported padding mode/,
|
||||||
opensslErrorStack: [
|
opensslErrorStack: [
|
||||||
|
|
|
@ -71,7 +71,11 @@ const cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
|
||||||
const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv);
|
const decipher = crypto.createDecipheriv('aes-128-cbc', badkey, iv);
|
||||||
|
|
||||||
cipher.pipe(decipher)
|
cipher.pipe(decipher)
|
||||||
.on('error', common.expectsError({
|
.on('error', common.expectsError(common.hasOpenSSL3 ? {
|
||||||
|
message: /bad decrypt/,
|
||||||
|
library: 'Provider routines',
|
||||||
|
reason: 'bad decrypt',
|
||||||
|
} : {
|
||||||
message: /bad decrypt/,
|
message: /bad decrypt/,
|
||||||
function: 'EVP_DecryptFinal_ex',
|
function: 'EVP_DecryptFinal_ex',
|
||||||
library: 'digital envelope routines',
|
library: 'digital envelope routines',
|
||||||
|
|
|
@ -46,9 +46,10 @@ OU=Node.js
|
||||||
CN=ca1
|
CN=ca1
|
||||||
emailAddress=ry@tinyclouds.org`;
|
emailAddress=ry@tinyclouds.org`;
|
||||||
|
|
||||||
const infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/
|
let infoAccessCheck = `OCSP - URI:http://ocsp.nodejs.org/
|
||||||
CA Issuers - URI:http://ca.nodejs.org/ca.cert
|
CA Issuers - URI:http://ca.nodejs.org/ca.cert`;
|
||||||
`;
|
if (!common.hasOpenSSL3)
|
||||||
|
infoAccessCheck += '\n';
|
||||||
|
|
||||||
const der = Buffer.from(
|
const der = Buffer.from(
|
||||||
'308202d830820241a003020102020900ecc9b856270da9a830' +
|
'308202d830820241a003020102020900ecc9b856270da9a830' +
|
||||||
|
@ -207,8 +208,11 @@ const der = Buffer.from(
|
||||||
'CN=ca1\n' +
|
'CN=ca1\n' +
|
||||||
'emailAddress=ry@tinyclouds.org',
|
'emailAddress=ry@tinyclouds.org',
|
||||||
infoAccess:
|
infoAccess:
|
||||||
'OCSP - URI:http://ocsp.nodejs.org/\n' +
|
common.hasOpenSSL3 ?
|
||||||
'CA Issuers - URI:http://ca.nodejs.org/ca.cert\n',
|
'OCSP - URI:http://ocsp.nodejs.org/\n' +
|
||||||
|
'CA Issuers - URI:http://ca.nodejs.org/ca.cert' :
|
||||||
|
'OCSP - URI:http://ocsp.nodejs.org/\n' +
|
||||||
|
'CA Issuers - URI:http://ca.nodejs.org/ca.cert\n',
|
||||||
modulus: 'EF5440701637E28ABB038E5641F828D834C342A9D25EDBB86A2BF' +
|
modulus: 'EF5440701637E28ABB038E5641F828D834C342A9D25EDBB86A2BF' +
|
||||||
'6FBD809CB8E037A98B71708E001242E4DEB54C6164885F599DD87' +
|
'6FBD809CB8E037A98B71708E001242E4DEB54C6164885F599DD87' +
|
||||||
'A23215745955BE20417E33C4D0D1B80C9DA3DE419A2607195D2FB' +
|
'A23215745955BE20417E33C4D0D1B80C9DA3DE419A2607195D2FB' +
|
||||||
|
|
|
@ -216,8 +216,13 @@ assert.throws(() => {
|
||||||
].join('\n');
|
].join('\n');
|
||||||
crypto.createSign('SHA256').update('test').sign(priv);
|
crypto.createSign('SHA256').update('test').sign(priv);
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
assert.ok(!('opensslErrorStack' in err));
|
if (!common.hasOpenSSL3)
|
||||||
assert.throws(() => { throw err; }, {
|
assert.ok(!('opensslErrorStack' in err));
|
||||||
|
assert.throws(() => { throw err; }, common.hasOpenSSL3 ? {
|
||||||
|
name: 'Error',
|
||||||
|
message: 'error:02000070:rsa routines::digest too big for rsa key',
|
||||||
|
library: 'rsa routines',
|
||||||
|
} : {
|
||||||
name: 'Error',
|
name: 'Error',
|
||||||
message: /routines:RSA_sign:digest too big for rsa key$/,
|
message: /routines:RSA_sign:digest too big for rsa key$/,
|
||||||
library: 'rsa routines',
|
library: 'rsa routines',
|
||||||
|
@ -228,30 +233,33 @@ assert.throws(() => {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.throws(() => {
|
if (!common.hasOpenSSL3) {
|
||||||
// The correct header inside `rsa_private_pkcs8_bad.pem` should have been
|
assert.throws(() => {
|
||||||
// -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
|
// The correct header inside `rsa_private_pkcs8_bad.pem` should have been
|
||||||
// instead of
|
// -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----
|
||||||
// -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----
|
// instead of
|
||||||
const sha1_privateKey = fixtures.readKey('rsa_private_pkcs8_bad.pem',
|
// -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----
|
||||||
'ascii');
|
const sha1_privateKey = fixtures.readKey('rsa_private_pkcs8_bad.pem',
|
||||||
// This would inject errors onto OpenSSL's error stack
|
'ascii');
|
||||||
crypto.createSign('sha1').sign(sha1_privateKey);
|
// This would inject errors onto OpenSSL's error stack
|
||||||
}, (err) => {
|
crypto.createSign('sha1').sign(sha1_privateKey);
|
||||||
// Do the standard checks, but then do some custom checks afterwards.
|
}, (err) => {
|
||||||
assert.throws(() => { throw err; }, {
|
// Do the standard checks, but then do some custom checks afterwards.
|
||||||
message: 'error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag',
|
assert.throws(() => { throw err; }, {
|
||||||
library: 'asn1 encoding routines',
|
message: 'error:0D0680A8:asn1 encoding routines:asn1_check_tlen:' +
|
||||||
function: 'asn1_check_tlen',
|
'wrong tag',
|
||||||
reason: 'wrong tag',
|
library: 'asn1 encoding routines',
|
||||||
code: 'ERR_OSSL_ASN1_WRONG_TAG',
|
function: 'asn1_check_tlen',
|
||||||
|
reason: 'wrong tag',
|
||||||
|
code: 'ERR_OSSL_ASN1_WRONG_TAG',
|
||||||
|
});
|
||||||
|
// Throws crypto error, so there is an opensslErrorStack property.
|
||||||
|
// The openSSL stack should have content.
|
||||||
|
assert(Array.isArray(err.opensslErrorStack));
|
||||||
|
assert(err.opensslErrorStack.length > 0);
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
// Throws crypto error, so there is an opensslErrorStack property.
|
}
|
||||||
// The openSSL stack should have content.
|
|
||||||
assert(Array.isArray(err.opensslErrorStack));
|
|
||||||
assert(err.opensslErrorStack.length > 0);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make sure memory isn't released before being returned
|
// Make sure memory isn't released before being returned
|
||||||
console.log(crypto.randomBytes(16));
|
console.log(crypto.randomBytes(16));
|
||||||
|
|
|
@ -13,6 +13,7 @@ const options = {
|
||||||
cert: fixtures.readKey('agent1-cert.pem'),
|
cert: fixtures.readKey('agent1-cert.pem'),
|
||||||
ca: fixtures.readKey('ca1-cert.pem'),
|
ca: fixtures.readKey('ca1-cert.pem'),
|
||||||
minVersion: 'TLSv1.1',
|
minVersion: 'TLSv1.1',
|
||||||
|
ciphers: 'ALL@SECLEVEL=0'
|
||||||
};
|
};
|
||||||
|
|
||||||
const server = https.Server(options, (req, res) => {
|
const server = https.Server(options, (req, res) => {
|
||||||
|
@ -27,6 +28,7 @@ function getBaseOptions(port) {
|
||||||
ca: options.ca,
|
ca: options.ca,
|
||||||
rejectUnauthorized: true,
|
rejectUnauthorized: true,
|
||||||
servername: 'agent1',
|
servername: 'agent1',
|
||||||
|
ciphers: 'ALL@SECLEVEL=0'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ const { SSL_OP_NO_TICKET } = require('crypto').constants;
|
||||||
const options = {
|
const options = {
|
||||||
key: readKey('agent1-key.pem'),
|
key: readKey('agent1-key.pem'),
|
||||||
cert: readKey('agent1-cert.pem'),
|
cert: readKey('agent1-cert.pem'),
|
||||||
secureOptions: SSL_OP_NO_TICKET
|
secureOptions: SSL_OP_NO_TICKET,
|
||||||
|
ciphers: 'RSA@SECLEVEL=0'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create TLS1.2 server
|
// Create TLS1.2 server
|
||||||
|
|
|
@ -35,7 +35,13 @@ assert(/^\d+\.\d+\.\d+(?:\.\d+)?-node\.\d+(?: \(candidate\))?$/
|
||||||
assert(/^\d+$/.test(process.versions.modules));
|
assert(/^\d+$/.test(process.versions.modules));
|
||||||
|
|
||||||
if (common.hasCrypto) {
|
if (common.hasCrypto) {
|
||||||
assert(/^\d+\.\d+\.\d+[a-z]?(\+quic)?(-fips)?$/.test(process.versions.openssl));
|
const versionRegex = common.hasOpenSSL3 ?
|
||||||
|
// The following also matches a development version of OpenSSL 3.x which
|
||||||
|
// can be in the format '3.0.0-alpha4-dev'. This can be handy when building
|
||||||
|
// and linking against the main development branch of OpenSSL.
|
||||||
|
/^\d+\.\d+\.\d+(-[-a-z0-9]+)?$/ :
|
||||||
|
/^\d+\.\d+\.\d+[a-z]?(\+quic)?(-fips)?$/;
|
||||||
|
assert(versionRegex.test(process.versions.openssl));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < expected_keys.length; i++) {
|
for (let i = 0; i < expected_keys.length; i++) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ let iter = 0;
|
||||||
const errorHandler = common.mustCall((err) => {
|
const errorHandler = common.mustCall((err) => {
|
||||||
assert.strictEqual(err.code, 'ERR_SSL_WRONG_VERSION_NUMBER');
|
assert.strictEqual(err.code, 'ERR_SSL_WRONG_VERSION_NUMBER');
|
||||||
assert.strictEqual(err.library, 'SSL routines');
|
assert.strictEqual(err.library, 'SSL routines');
|
||||||
assert.strictEqual(err.function, 'ssl3_get_record');
|
if (!common.hasOpenSSL3) assert.strictEqual(err.function, 'ssl3_get_record');
|
||||||
assert.strictEqual(err.reason, 'wrong version number');
|
assert.strictEqual(err.reason, 'wrong version number');
|
||||||
errorReceived = true;
|
errorReceived = true;
|
||||||
if (canCloseServer())
|
if (canCloseServer())
|
||||||
|
@ -89,7 +89,8 @@ function sendBADTLSRecord() {
|
||||||
client.on('error', common.mustCall((err) => {
|
client.on('error', common.mustCall((err) => {
|
||||||
assert.strictEqual(err.code, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION');
|
assert.strictEqual(err.code, 'ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION');
|
||||||
assert.strictEqual(err.library, 'SSL routines');
|
assert.strictEqual(err.library, 'SSL routines');
|
||||||
assert.strictEqual(err.function, 'ssl3_read_bytes');
|
if (!common.hasOpenSSL3)
|
||||||
|
assert.strictEqual(err.function, 'ssl3_read_bytes');
|
||||||
assert.strictEqual(err.reason, 'tlsv1 alert protocol version');
|
assert.strictEqual(err.reason, 'tlsv1 alert protocol version');
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,16 @@ const common = require('../common');
|
||||||
if (!common.hasCrypto)
|
if (!common.hasCrypto)
|
||||||
common.skip('missing crypto');
|
common.skip('missing crypto');
|
||||||
|
|
||||||
|
if (common.hasOpenSSL3)
|
||||||
|
// TODO(danbev) This test fails with the following error:
|
||||||
|
// error:0D00008F:asn1 encoding routines::no matching choice type
|
||||||
|
//
|
||||||
|
// I've not been able to figure out the reason for this but there
|
||||||
|
// is a note in https://wiki.openssl.org/index.php/OpenSSL_3.0 which
|
||||||
|
// indicates that this might not work at the moment:
|
||||||
|
// "OCSP, PEM, ASN.1 have some very limited library context support"
|
||||||
|
common.skip('when using OpenSSL 3.x');
|
||||||
|
|
||||||
// NOTE: This certificate is hand-generated, hence it is not located in
|
// NOTE: This certificate is hand-generated, hence it is not located in
|
||||||
// `test/fixtures/keys` to avoid confusion.
|
// `test/fixtures/keys` to avoid confusion.
|
||||||
//
|
//
|
||||||
|
|
|
@ -29,7 +29,9 @@ connect({
|
||||||
|
|
||||||
const ok = client.renegotiate({}, common.mustCall((err) => {
|
const ok = client.renegotiate({}, common.mustCall((err) => {
|
||||||
assert.throws(() => { throw err; }, {
|
assert.throws(() => { throw err; }, {
|
||||||
message: 'error:1420410A:SSL routines:SSL_renegotiate:wrong ssl version',
|
message: common.hasOpenSSL3 ?
|
||||||
|
'error:0A00010A:SSL routines::wrong ssl version' :
|
||||||
|
'error:1420410A:SSL routines:SSL_renegotiate:wrong ssl version',
|
||||||
code: 'ERR_SSL_WRONG_SSL_VERSION',
|
code: 'ERR_SSL_WRONG_SSL_VERSION',
|
||||||
library: 'SSL routines',
|
library: 'SSL routines',
|
||||||
reason: 'wrong ssl version',
|
reason: 'wrong ssl version',
|
||||||
|
|
|
@ -18,6 +18,7 @@ const clientConfigs = [
|
||||||
|
|
||||||
const serverConfig = {
|
const serverConfig = {
|
||||||
secureProtocol: 'TLS_method',
|
secureProtocol: 'TLS_method',
|
||||||
|
ciphers: 'RSA@SECLEVEL=0',
|
||||||
key: fixtures.readKey('agent2-key.pem'),
|
key: fixtures.readKey('agent2-key.pem'),
|
||||||
cert: fixtures.readKey('agent2-cert.pem')
|
cert: fixtures.readKey('agent2-cert.pem')
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,8 @@ const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const tls = require('tls');
|
const tls = require('tls');
|
||||||
const errorMessageRegex =
|
const errorMessageRegex = common.hasOpenSSL3 ?
|
||||||
|
/^Error: error:05800074:x509 certificate routines::key values mismatch$/ :
|
||||||
/^Error: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch$/;
|
/^Error: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch$/;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
|
|
|
@ -14,6 +14,14 @@ const DEFAULT_MAX_VERSION = tls.DEFAULT_MAX_VERSION;
|
||||||
|
|
||||||
function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
|
function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
|
||||||
assert(proto || cerr || serr, 'test missing any expectations');
|
assert(proto || cerr || serr, 'test missing any expectations');
|
||||||
|
|
||||||
|
let ciphers;
|
||||||
|
if (common.hasOpenSSL3 && (proto === 'TLSv1' || proto === 'TLSv1.1' ||
|
||||||
|
proto === 'TLSv1_1_method' || proto === 'TLSv1_method' ||
|
||||||
|
sprot === 'TLSv1_1_method' || sprot === 'TLSv1_method')) {
|
||||||
|
if (serr !== 'ERR_SSL_UNSUPPORTED_PROTOCOL')
|
||||||
|
ciphers = 'ALL@SECLEVEL=0';
|
||||||
|
}
|
||||||
// Report where test was called from. Strip leading garbage from
|
// Report where test was called from. Strip leading garbage from
|
||||||
// at Object.<anonymous> (file:line)
|
// at Object.<anonymous> (file:line)
|
||||||
// from the stack location, we only want the file:line part.
|
// from the stack location, we only want the file:line part.
|
||||||
|
@ -25,6 +33,7 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
|
||||||
minVersion: cmin,
|
minVersion: cmin,
|
||||||
maxVersion: cmax,
|
maxVersion: cmax,
|
||||||
secureProtocol: cprot,
|
secureProtocol: cprot,
|
||||||
|
ciphers: ciphers
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
cert: keys.agent6.cert,
|
cert: keys.agent6.cert,
|
||||||
|
@ -32,11 +41,12 @@ function test(cmin, cmax, cprot, smin, smax, sprot, proto, cerr, serr) {
|
||||||
minVersion: smin,
|
minVersion: smin,
|
||||||
maxVersion: smax,
|
maxVersion: smax,
|
||||||
secureProtocol: sprot,
|
secureProtocol: sprot,
|
||||||
|
ciphers: ciphers
|
||||||
},
|
},
|
||||||
}, common.mustCall((err, pair, cleanup) => {
|
}, common.mustCall((err, pair, cleanup) => {
|
||||||
function u(_) { return _ === undefined ? 'U' : _; }
|
function u(_) { return _ === undefined ? 'U' : _; }
|
||||||
console.log('test:', u(cmin), u(cmax), u(cprot), u(smin), u(smax), u(sprot),
|
console.log('test:', u(cmin), u(cmax), u(cprot), u(smin), u(smax), u(sprot),
|
||||||
'expect', u(proto), u(cerr), u(serr));
|
u(ciphers), 'expect', u(proto), u(cerr), u(serr));
|
||||||
console.log(' ', where);
|
console.log(' ', where);
|
||||||
if (!proto) {
|
if (!proto) {
|
||||||
console.log('client', pair.client.err ? pair.client.err.code : undefined);
|
console.log('client', pair.client.err ? pair.client.err.code : undefined);
|
||||||
|
@ -109,16 +119,19 @@ test(U, U, 'TLS_method', U, U, 'TLSv1_method', 'TLSv1');
|
||||||
// minimum (which is configurable via command line).
|
// minimum (which is configurable via command line).
|
||||||
if (DEFAULT_MIN_VERSION === 'TLSv1.3') {
|
if (DEFAULT_MIN_VERSION === 'TLSv1.3') {
|
||||||
test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method',
|
test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method',
|
||||||
U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR');
|
U, 'ECONNRESET', common.hasOpenSSL3 ?
|
||||||
|
'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR');
|
||||||
} else {
|
} else {
|
||||||
test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method', 'TLSv1.2');
|
test(U, U, 'TLSv1_2_method', U, U, 'SSLv23_method', 'TLSv1.2');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DEFAULT_MIN_VERSION === 'TLSv1.3') {
|
if (DEFAULT_MIN_VERSION === 'TLSv1.3') {
|
||||||
test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method',
|
test(U, U, 'TLSv1_1_method', U, U, 'SSLv23_method',
|
||||||
U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR');
|
U, 'ECONNRESET', common.hasOpenSSL3 ?
|
||||||
|
'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR');
|
||||||
test(U, U, 'TLSv1_method', U, U, 'SSLv23_method',
|
test(U, U, 'TLSv1_method', U, U, 'SSLv23_method',
|
||||||
U, 'ECONNRESET', 'ERR_SSL_INTERNAL_ERROR');
|
U, 'ECONNRESET', common.hasOpenSSL3 ?
|
||||||
|
'ERR_SSL_NO_PROTOCOLS_AVAILABLE' : 'ERR_SSL_INTERNAL_ERROR');
|
||||||
test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method',
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_1_method',
|
||||||
U, 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 'ERR_SSL_UNEXPECTED_MESSAGE');
|
U, 'ERR_SSL_NO_PROTOCOLS_AVAILABLE', 'ERR_SSL_UNEXPECTED_MESSAGE');
|
||||||
test(U, U, 'SSLv23_method', U, U, 'TLSv1_method',
|
test(U, U, 'SSLv23_method', U, U, 'TLSv1_method',
|
||||||
|
|
|
@ -223,7 +223,8 @@ server.listen(0, common.mustCall(function() {
|
||||||
}, onSecureConnect());
|
}, onSecureConnect());
|
||||||
})).unref();
|
})).unref();
|
||||||
|
|
||||||
const errMessagePassword = /bad decrypt/;
|
const errMessagePassword = common.hasOpenSSL3 ?
|
||||||
|
/processing error/ : /bad decrypt/;
|
||||||
|
|
||||||
// Missing passphrase
|
// Missing passphrase
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
|
|
|
@ -50,6 +50,7 @@ function doTest(testOptions, callback) {
|
||||||
requestCert: true,
|
requestCert: true,
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
secureProtocol: 'TLS_method',
|
secureProtocol: 'TLS_method',
|
||||||
|
ciphers: 'RSA@SECLEVEL=0'
|
||||||
};
|
};
|
||||||
let requestCount = 0;
|
let requestCount = 0;
|
||||||
let resumeCount = 0;
|
let resumeCount = 0;
|
||||||
|
|
|
@ -53,9 +53,12 @@ server.listen(0, common.mustCall(() => {
|
||||||
|
|
||||||
server.setSecureContext(credentialOptions[1]);
|
server.setSecureContext(credentialOptions[1]);
|
||||||
firstResponse.write('request-');
|
firstResponse.write('request-');
|
||||||
|
const errorMessageRegex = common.hasOpenSSL3 ?
|
||||||
|
/^Error: self-signed certificate$/ :
|
||||||
|
/^Error: self signed certificate$/;
|
||||||
await assert.rejects(async () => {
|
await assert.rejects(async () => {
|
||||||
await makeRequest(port, 3);
|
await makeRequest(port, 3);
|
||||||
}, /^Error: self signed certificate$/);
|
}, errorMessageRegex);
|
||||||
|
|
||||||
server.setSecureContext(credentialOptions[0]);
|
server.setSecureContext(credentialOptions[0]);
|
||||||
assert.strictEqual(await makeRequest(port, 4), 'success');
|
assert.strictEqual(await makeRequest(port, 4), 'success');
|
||||||
|
@ -64,7 +67,7 @@ server.listen(0, common.mustCall(() => {
|
||||||
firstResponse.end('fun!');
|
firstResponse.end('fun!');
|
||||||
await assert.rejects(async () => {
|
await assert.rejects(async () => {
|
||||||
await makeRequest(port, 5);
|
await makeRequest(port, 5);
|
||||||
}, /^Error: self signed certificate$/);
|
}, errorMessageRegex);
|
||||||
|
|
||||||
assert.strictEqual(await firstRequest, 'multi-request-success-fun!');
|
assert.strictEqual(await firstRequest, 'multi-request-success-fun!');
|
||||||
server.close();
|
server.close();
|
||||||
|
|
|
@ -16,7 +16,8 @@ const server_cert = fixtures.readKey('agent1-cert.pem');
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
key: server_key,
|
key: server_key,
|
||||||
cert: server_cert
|
cert: server_cert,
|
||||||
|
ciphers: 'ALL@SECLEVEL=0'
|
||||||
};
|
};
|
||||||
|
|
||||||
const server = https.createServer(opts, (req, res) => {
|
const server = https.createServer(opts, (req, res) => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue