mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
tls,quic: commonize TLS cert handling between tls, dtls & quic
Signed-off-by: Tim Perry <pimterry@gmail.com> PR-URL: https://github.com/nodejs/node/pull/64711 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
8c8190f453
commit
e79c6b31cc
8 files changed
+242
-158
No files matched your search
@@ -407,6 +407,7 @@
|
||||
'src/crypto/crypto_timing.cc',
|
||||
'src/crypto/crypto_cipher.cc',
|
||||
'src/crypto/crypto_context.cc',
|
||||
'src/crypto/crypto_tls_certificates.cc',
|
||||
'src/crypto/crypto_ec.cc',
|
||||
'src/crypto/crypto_pqc.cc',
|
||||
'src/crypto/crypto_kem.cc',
|
||||
@@ -442,6 +443,7 @@
|
||||
'src/crypto/crypto_scrypt.h',
|
||||
'src/crypto/crypto_tls.h',
|
||||
'src/crypto/crypto_context.h',
|
||||
'src/crypto/crypto_tls_certificates.h',
|
||||
'src/crypto/crypto_ec.h',
|
||||
'src/crypto/crypto_pqc.h',
|
||||
'src/crypto/crypto_hkdf.h',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "base_object-inl.h"
|
||||
#include "crypto/crypto_bio.h"
|
||||
#include "crypto/crypto_common.h"
|
||||
#include "crypto/crypto_tls_certificates.h"
|
||||
#include "crypto/crypto_util.h"
|
||||
#include "env-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
@@ -1739,22 +1740,14 @@ void SecureContext::SetKey(const FunctionCallbackInfo<Value>& args) {
|
||||
ByteSource passphrase;
|
||||
if (args[1]->IsString())
|
||||
passphrase = ByteSource::FromString(env, args[1].As<String>());
|
||||
// This redirection is necessary because the PasswordCallback expects a
|
||||
// pointer to a pointer to the passphrase ByteSource to allow passing in
|
||||
// const ByteSources.
|
||||
const ByteSource* pass_ptr = &passphrase;
|
||||
|
||||
EVPKeyPointer key(
|
||||
PEM_read_bio_PrivateKey(bio.get(),
|
||||
nullptr,
|
||||
PasswordCallback,
|
||||
&pass_ptr));
|
||||
|
||||
if (!key)
|
||||
return ThrowCryptoError(env, ERR_get_error(), "PEM_read_bio_PrivateKey");
|
||||
|
||||
if (!SSL_CTX_use_PrivateKey(sc->ctx_.get(), key.get()))
|
||||
return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey");
|
||||
switch (UsePrivateKey(sc->ctx_.get(), bio, &passphrase)) {
|
||||
case PrivateKeyResult::kSuccess:
|
||||
break;
|
||||
case PrivateKeyResult::kParseError:
|
||||
return ThrowCryptoError(env, ERR_get_error(), "PEM_read_bio_PrivateKey");
|
||||
case PrivateKeyResult::kApplyError:
|
||||
return ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey");
|
||||
}
|
||||
}
|
||||
|
||||
void SecureContext::SetSigalgs(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -1857,16 +1850,7 @@ void SecureContext::SetX509StoreFlag(unsigned long flags) {
|
||||
}
|
||||
|
||||
X509_STORE* SecureContext::GetCertStoreOwnedByThisSecureContext() {
|
||||
Environment* env = this->env();
|
||||
if (own_cert_store_cache_ != nullptr) return own_cert_store_cache_;
|
||||
|
||||
X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx_.get());
|
||||
if (cert_store == GetOrCreateRootCertStore(env)) {
|
||||
cert_store = NewRootCertStore(env);
|
||||
SSL_CTX_set_cert_store(ctx_.get(), cert_store);
|
||||
}
|
||||
|
||||
return own_cert_store_cache_ = cert_store;
|
||||
return GetOrCreateOwnedCertStore(env(), ctx_.get(), &own_cert_store_cache_);
|
||||
}
|
||||
|
||||
void SecureContext::SetAllowPartialTrustChain(
|
||||
@@ -1878,13 +1862,7 @@ void SecureContext::SetAllowPartialTrustChain(
|
||||
|
||||
void SecureContext::SetCACert(const BIOPointer& bio) {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
if (!bio) return;
|
||||
while (X509Pointer x509 = X509Pointer(PEM_read_bio_X509_AUX(
|
||||
bio.get(), nullptr, NoPasswordCallback, nullptr))) {
|
||||
CHECK_EQ(1,
|
||||
X509_STORE_add_cert(GetCertStoreOwnedByThisSecureContext(), x509));
|
||||
CHECK_EQ(1, SSL_CTX_add_client_CA(ctx_.get(), x509));
|
||||
}
|
||||
AddCACertificates(env(), ctx_.get(), bio, &own_cert_store_cache_);
|
||||
}
|
||||
|
||||
void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -1904,20 +1882,11 @@ Maybe<void> SecureContext::SetCRL(Environment* env, const BIOPointer& bio) {
|
||||
// TODO(tniessen): this should be checked by the caller and not treated as ok
|
||||
if (!bio) return JustVoid();
|
||||
|
||||
DeleteFnPtr<X509_CRL, X509_CRL_free> crl(
|
||||
PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr));
|
||||
|
||||
if (!crl) {
|
||||
if (!crypto::AddCRL(env, ctx_.get(), bio, &own_cert_store_cache_)) {
|
||||
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to parse CRL");
|
||||
return Nothing<void>();
|
||||
}
|
||||
|
||||
X509_STORE* cert_store = GetCertStoreOwnedByThisSecureContext();
|
||||
|
||||
CHECK_EQ(1, X509_STORE_add_crl(cert_store, crl.get()));
|
||||
CHECK_EQ(1,
|
||||
X509_STORE_set_flags(
|
||||
cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL));
|
||||
return JustVoid();
|
||||
}
|
||||
|
||||
@@ -1935,12 +1904,7 @@ void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
void SecureContext::SetRootCerts() {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
Environment* env = this->env();
|
||||
auto store = GetOrCreateRootCertStore(env);
|
||||
|
||||
// Increment reference count so global store is not deleted along with CTX.
|
||||
X509_STORE_up_ref(store);
|
||||
SSL_CTX_set_cert_store(ctx_.get(), store);
|
||||
UseDefaultRootCertStore(env(), ctx_.get());
|
||||
}
|
||||
|
||||
void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
@@ -207,11 +207,6 @@ class SecureContext final : public BaseObject {
|
||||
#endif
|
||||
};
|
||||
|
||||
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
|
||||
ncrypto::BIOPointer&& in,
|
||||
ncrypto::X509Pointer* cert,
|
||||
ncrypto::X509Pointer* issuer);
|
||||
|
||||
} // namespace crypto
|
||||
} // namespace node
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "crypto/crypto_tls_certificates.h"
|
||||
|
||||
#include "crypto/crypto_context.h"
|
||||
#include "crypto/crypto_keys.h"
|
||||
#include "crypto/crypto_util.h"
|
||||
|
||||
namespace node::crypto {
|
||||
|
||||
using ncrypto::DeleteFnPtr;
|
||||
using ncrypto::EVPKeyPointer;
|
||||
using ncrypto::X509Pointer;
|
||||
|
||||
X509_STORE* GetOrCreateOwnedCertStore(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
X509_STORE** cache) {
|
||||
if (cache != nullptr && *cache != nullptr) return *cache;
|
||||
|
||||
X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx);
|
||||
if (cert_store == GetOrCreateRootCertStore(env)) {
|
||||
cert_store = NewRootCertStore(env);
|
||||
SSL_CTX_set_cert_store(ctx, cert_store);
|
||||
}
|
||||
|
||||
if (cache != nullptr) *cache = cert_store;
|
||||
return cert_store;
|
||||
}
|
||||
|
||||
void UseDefaultRootCertStore(Environment* env, SSL_CTX* ctx) {
|
||||
X509_STORE* store = GetOrCreateRootCertStore(env);
|
||||
|
||||
// Increment reference count so global store is not deleted along with CTX.
|
||||
X509_STORE_up_ref(store);
|
||||
SSL_CTX_set_cert_store(ctx, store);
|
||||
}
|
||||
|
||||
size_t AddCACertificates(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
X509_STORE** cache) {
|
||||
if (!bio) return 0;
|
||||
|
||||
size_t count = 0;
|
||||
while (X509Pointer x509 = X509Pointer(PEM_read_bio_X509_AUX(
|
||||
bio.get(), nullptr, NoPasswordCallback, nullptr))) {
|
||||
CHECK_EQ(1,
|
||||
X509_STORE_add_cert(GetOrCreateOwnedCertStore(env, ctx, cache),
|
||||
x509.get()));
|
||||
CHECK_EQ(1, SSL_CTX_add_client_CA(ctx, x509.get()));
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool AddCRL(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
X509_STORE** cache) {
|
||||
if (!bio) return false;
|
||||
|
||||
DeleteFnPtr<X509_CRL, X509_CRL_free> crl(
|
||||
PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr));
|
||||
if (!crl) return false;
|
||||
|
||||
X509_STORE* cert_store = GetOrCreateOwnedCertStore(env, ctx, cache);
|
||||
CHECK_EQ(1, X509_STORE_add_crl(cert_store, crl.get()));
|
||||
CHECK_EQ(1,
|
||||
X509_STORE_set_flags(
|
||||
cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL));
|
||||
return true;
|
||||
}
|
||||
|
||||
PrivateKeyResult UsePrivateKey(SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
const ByteSource* passphrase) {
|
||||
if (!bio) return PrivateKeyResult::kParseError;
|
||||
|
||||
ByteSource empty_passphrase;
|
||||
if (passphrase == nullptr) passphrase = &empty_passphrase;
|
||||
// This redirection is necessary because the PasswordCallback expects a
|
||||
// pointer to a pointer to the passphrase ByteSource to allow passing in
|
||||
// const ByteSources.
|
||||
const ByteSource* pass_ptr = passphrase;
|
||||
EVPKeyPointer key(
|
||||
PEM_read_bio_PrivateKey(bio.get(), nullptr, PasswordCallback, &pass_ptr));
|
||||
if (!key) return PrivateKeyResult::kParseError;
|
||||
if (!SSL_CTX_use_PrivateKey(ctx, key.get()))
|
||||
return PrivateKeyResult::kApplyError;
|
||||
return PrivateKeyResult::kSuccess;
|
||||
}
|
||||
|
||||
bool UsePrivateKey(SSL_CTX* ctx, const KeyObjectData& key) {
|
||||
if (key.GetKeyType() != KeyType::kKeyTypePrivate) return false;
|
||||
return SSL_CTX_use_PrivateKey(ctx, key.GetAsymmetricKey().get());
|
||||
}
|
||||
|
||||
} // namespace node::crypto
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef SRC_CRYPTO_CRYPTO_TLS_CERTIFICATES_H_
|
||||
#define SRC_CRYPTO_CRYPTO_TLS_CERTIFICATES_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "ncrypto.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
class Environment;
|
||||
|
||||
namespace crypto {
|
||||
|
||||
class ByteSource;
|
||||
class KeyObjectData;
|
||||
|
||||
// Return a store that may be modified by this SSL_CTX. If the context uses
|
||||
// Node's shared root store, replace it with a private copy first.
|
||||
X509_STORE* GetOrCreateOwnedCertStore(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
X509_STORE** cache = nullptr);
|
||||
|
||||
// Attach Node's process-wide default root store to the SSL_CTX.
|
||||
void UseDefaultRootCertStore(Environment* env, SSL_CTX* ctx);
|
||||
|
||||
// Add every PEM certificate in |bio| to the context's certificate store and
|
||||
// acceptable-client-CA list. Returns the number of certificates read.
|
||||
size_t AddCACertificates(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
X509_STORE** cache = nullptr);
|
||||
|
||||
// Add one PEM CRL and enable CRL checking.
|
||||
bool AddCRL(Environment* env,
|
||||
SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
X509_STORE** cache = nullptr);
|
||||
|
||||
enum class PrivateKeyResult {
|
||||
kSuccess,
|
||||
kParseError,
|
||||
kApplyError,
|
||||
};
|
||||
|
||||
PrivateKeyResult UsePrivateKey(SSL_CTX* ctx,
|
||||
const ncrypto::BIOPointer& bio,
|
||||
const ByteSource* passphrase = nullptr);
|
||||
|
||||
bool UsePrivateKey(SSL_CTX* ctx, const KeyObjectData& key);
|
||||
|
||||
int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
|
||||
ncrypto::BIOPointer&& in,
|
||||
ncrypto::X509Pointer* cert,
|
||||
ncrypto::X509Pointer* issuer);
|
||||
|
||||
} // namespace crypto
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
#endif // SRC_CRYPTO_CRYPTO_TLS_CERTIFICATES_H_
|
||||
+27
-59
@@ -4,6 +4,8 @@
|
||||
#if HAVE_OPENSSL && HAVE_DTLS
|
||||
|
||||
#include <base_object-inl.h>
|
||||
#include <crypto/crypto_bio.h>
|
||||
#include <crypto/crypto_tls_certificates.h>
|
||||
#include <crypto/crypto_util.h>
|
||||
#include <env-inl.h>
|
||||
#include <memory_tracker-inl.h>
|
||||
@@ -186,35 +188,17 @@ void DTLSContext::SetCert(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
Utf8Value cert_pem(env->isolate(), args[0]);
|
||||
|
||||
BIO* bio = BIO_new_mem_buf(*cert_pem, cert_pem.length());
|
||||
if (bio == nullptr) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "BIO_new_mem_buf failed");
|
||||
auto bio = crypto::NodeBIO::NewFixed(*cert_pem, cert_pem.length());
|
||||
if (!bio) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to create BIO");
|
||||
}
|
||||
|
||||
X509* x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||
if (x509 == nullptr) {
|
||||
BIO_free(bio);
|
||||
ncrypto::X509Pointer cert;
|
||||
ncrypto::X509Pointer issuer;
|
||||
if (crypto::SSL_CTX_use_certificate_chain(
|
||||
ctx->ctx_.get(), std::move(bio), &cert, &issuer) != 1) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "PEM_read_bio_X509 failed");
|
||||
}
|
||||
|
||||
int ret = SSL_CTX_use_certificate(ctx->ctx_.get(), x509);
|
||||
X509_free(x509);
|
||||
|
||||
// Read any additional chain certificates.
|
||||
while ((x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) !=
|
||||
nullptr) {
|
||||
SSL_CTX_add_extra_chain_cert(ctx->ctx_.get(), x509);
|
||||
// Note: SSL_CTX_add_extra_chain_cert takes ownership, don't free x509.
|
||||
}
|
||||
|
||||
// Clear any error from the chain reading loop (expected EOF).
|
||||
ERR_clear_error();
|
||||
BIO_free(bio);
|
||||
|
||||
if (ret != 1) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
|
||||
"SSL_CTX_use_certificate failed");
|
||||
}
|
||||
}
|
||||
|
||||
void DTLSContext::SetKey(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -228,25 +212,20 @@ void DTLSContext::SetKey(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
Utf8Value key_pem(env->isolate(), args[0]);
|
||||
|
||||
BIO* bio = BIO_new_mem_buf(*key_pem, key_pem.length());
|
||||
if (bio == nullptr) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "BIO_new_mem_buf failed");
|
||||
auto bio = crypto::NodeBIO::NewFixed(*key_pem, key_pem.length());
|
||||
if (!bio) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to create BIO");
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
|
||||
BIO_free(bio);
|
||||
|
||||
if (pkey == nullptr) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
|
||||
"PEM_read_bio_PrivateKey failed");
|
||||
}
|
||||
|
||||
int ret = SSL_CTX_use_PrivateKey(ctx->ctx_.get(), pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
if (ret != 1) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
|
||||
"SSL_CTX_use_PrivateKey failed");
|
||||
switch (crypto::UsePrivateKey(ctx->ctx_.get(), bio)) {
|
||||
case crypto::PrivateKeyResult::kSuccess:
|
||||
break;
|
||||
case crypto::PrivateKeyResult::kParseError:
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(
|
||||
env, "PEM_read_bio_PrivateKey failed");
|
||||
case crypto::PrivateKeyResult::kApplyError:
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
|
||||
"SSL_CTX_use_PrivateKey failed");
|
||||
}
|
||||
|
||||
// Verify that the private key matches the certificate.
|
||||
@@ -267,24 +246,13 @@ void DTLSContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
Utf8Value ca_pem(env->isolate(), args[0]);
|
||||
|
||||
BIO* bio = BIO_new_mem_buf(*ca_pem, ca_pem.length());
|
||||
if (bio == nullptr) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "BIO_new_mem_buf failed");
|
||||
auto bio = crypto::NodeBIO::NewFixed(*ca_pem, ca_pem.length());
|
||||
if (!bio) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to create BIO");
|
||||
}
|
||||
|
||||
X509_STORE* store = SSL_CTX_get_cert_store(ctx->ctx_.get());
|
||||
X509* x509;
|
||||
int count = 0;
|
||||
while ((x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) !=
|
||||
nullptr) {
|
||||
X509_STORE_add_cert(store, x509);
|
||||
X509_free(x509);
|
||||
count++;
|
||||
}
|
||||
ERR_clear_error();
|
||||
BIO_free(bio);
|
||||
|
||||
if (count == 0) {
|
||||
ncrypto::ClearErrorOnReturn clear_error_on_return;
|
||||
if (crypto::AddCACertificates(env, ctx->ctx_.get(), bio) == 0) {
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(
|
||||
env, "No CA certificates found in PEM data");
|
||||
}
|
||||
@@ -358,7 +326,7 @@ void DTLSContext::SetVerifyMode(const FunctionCallbackInfo<Value>& args) {
|
||||
void DTLSContext::LoadDefaultCAs(const FunctionCallbackInfo<Value>& args) {
|
||||
DTLSContext* ctx;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This());
|
||||
SSL_CTX_set_default_verify_paths(ctx->ctx_.get());
|
||||
crypto::UseDefaultRootCertStore(ctx->env(), ctx->ctx_.get());
|
||||
}
|
||||
|
||||
void DTLSContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
+6
-45
@@ -3,6 +3,7 @@
|
||||
#ifndef OPENSSL_NO_QUIC
|
||||
#include <async_wrap-inl.h>
|
||||
#include <base_object-inl.h>
|
||||
#include <crypto/crypto_tls_certificates.h>
|
||||
#include <crypto/crypto_util.h>
|
||||
#include <debug_utils-inl.h>
|
||||
#include <env-inl.h>
|
||||
@@ -32,7 +33,6 @@ using ncrypto::MarkPopErrorOnReturn;
|
||||
using ncrypto::SSLCtxPointer;
|
||||
using ncrypto::SSLPointer;
|
||||
using ncrypto::SSLSessionPointer;
|
||||
using ncrypto::X509Pointer;
|
||||
using v8::Array;
|
||||
using v8::ArrayBuffer;
|
||||
using v8::ArrayBufferView;
|
||||
@@ -528,12 +528,6 @@ SSLCtxPointer TLSContext::Initialize(Environment* env) {
|
||||
}
|
||||
}
|
||||
|
||||
// Only load system CA certificates if no custom CAs are provided.
|
||||
// SSL_CTX_set_default_verify_paths involves filesystem I/O to read
|
||||
// the system CA bundle.
|
||||
if (options_.ca.empty()) {
|
||||
SSL_CTX_set_default_verify_paths(ctx.get());
|
||||
}
|
||||
if (options_.keylog) {
|
||||
SSL_CTX_set_keylog_callback(ctx.get(), OnKeylog);
|
||||
}
|
||||
@@ -551,30 +545,16 @@ SSLCtxPointer TLSContext::Initialize(Environment* env) {
|
||||
{
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
if (options_.ca.empty()) {
|
||||
auto store = crypto::GetOrCreateRootCertStore(env);
|
||||
X509_STORE_up_ref(store);
|
||||
SSL_CTX_set_cert_store(ctx.get(), store);
|
||||
crypto::UseDefaultRootCertStore(env, ctx.get());
|
||||
} else {
|
||||
for (const auto& ca : options_.ca) {
|
||||
uv_buf_t buf = ca;
|
||||
if (buf.len == 0) {
|
||||
auto store = crypto::GetOrCreateRootCertStore(env);
|
||||
X509_STORE_up_ref(store);
|
||||
SSL_CTX_set_cert_store(ctx.get(), store);
|
||||
crypto::UseDefaultRootCertStore(env, ctx.get());
|
||||
} else {
|
||||
BIOPointer bio = crypto::NodeBIO::NewFixed(buf.base, buf.len);
|
||||
CHECK(bio);
|
||||
X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx.get());
|
||||
while (
|
||||
auto x509 = X509Pointer(PEM_read_bio_X509_AUX(
|
||||
bio.get(), nullptr, crypto::NoPasswordCallback, nullptr))) {
|
||||
if (cert_store == crypto::GetOrCreateRootCertStore(env)) {
|
||||
cert_store = crypto::NewRootCertStore(env);
|
||||
SSL_CTX_set_cert_store(ctx.get(), cert_store);
|
||||
}
|
||||
CHECK_EQ(1, X509_STORE_add_cert(cert_store, x509.get()));
|
||||
CHECK_EQ(1, SSL_CTX_add_client_CA(ctx.get(), x509.get()));
|
||||
}
|
||||
crypto::AddCACertificates(env, ctx.get(), bio);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -643,11 +623,7 @@ SSLCtxPointer TLSContext::Initialize(Environment* env) {
|
||||
{
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
for (const auto& key : options_.keys) {
|
||||
if (key.GetKeyType() != crypto::KeyType::kKeyTypePrivate) {
|
||||
validation_error_ = "Invalid key";
|
||||
return SSLCtxPointer();
|
||||
}
|
||||
if (!SSL_CTX_use_PrivateKey(ctx.get(), key.GetAsymmetricKey().get())) {
|
||||
if (!crypto::UsePrivateKey(ctx.get(), key)) {
|
||||
validation_error_ = "Invalid key";
|
||||
return SSLCtxPointer();
|
||||
}
|
||||
@@ -659,25 +635,10 @@ SSLCtxPointer TLSContext::Initialize(Environment* env) {
|
||||
for (const auto& crl : options_.crl) {
|
||||
uv_buf_t buf = crl;
|
||||
BIOPointer bio = crypto::NodeBIO::NewFixed(buf.base, buf.len);
|
||||
DeleteFnPtr<X509_CRL, X509_CRL_free> crlptr(PEM_read_bio_X509_CRL(
|
||||
bio.get(), nullptr, crypto::NoPasswordCallback, nullptr));
|
||||
|
||||
if (!crlptr) {
|
||||
if (!crypto::AddCRL(env, ctx.get(), bio)) {
|
||||
validation_error_ = "Invalid CRL";
|
||||
return SSLCtxPointer();
|
||||
}
|
||||
|
||||
X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx.get());
|
||||
if (cert_store == crypto::GetOrCreateRootCertStore(env)) {
|
||||
cert_store = crypto::NewRootCertStore(env);
|
||||
SSL_CTX_set_cert_store(ctx.get(), cert_store);
|
||||
}
|
||||
|
||||
CHECK_EQ(1, X509_STORE_add_crl(cert_store, crlptr.get()));
|
||||
CHECK_EQ(
|
||||
1,
|
||||
X509_STORE_set_flags(
|
||||
cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Flags: --experimental-dtls --no-warnings
|
||||
|
||||
// Test that DTLS uses Node's configurable default CA set when no explicit
|
||||
// `ca` option is provided.
|
||||
|
||||
import { hasCrypto, mustCall, skip } from '../common/index.mjs';
|
||||
import * as fixtures from '../common/fixtures.mjs';
|
||||
|
||||
if (!hasCrypto) {
|
||||
skip('missing crypto');
|
||||
}
|
||||
|
||||
if (!process.features.dtls) {
|
||||
skip('DTLS is not enabled');
|
||||
}
|
||||
|
||||
const { connect, listen } = await import('node:dtls');
|
||||
const { setDefaultCACertificates } = await import('node:tls');
|
||||
|
||||
const serverCert = fixtures.readKey('agent1-cert.pem');
|
||||
const serverKey = fixtures.readKey('agent1-key.pem');
|
||||
const ca = fixtures.readKey('ca1-cert.pem');
|
||||
|
||||
setDefaultCACertificates([ca]);
|
||||
|
||||
const endpoint = listen(mustCall(), {
|
||||
// Also cover the shared certificate-chain loader adopted by DTLS.
|
||||
cert: Buffer.concat([serverCert, ca]),
|
||||
key: serverKey,
|
||||
host: '127.0.0.1',
|
||||
port: 0,
|
||||
});
|
||||
|
||||
const client = connect('127.0.0.1', endpoint.address.port);
|
||||
await client.opened;
|
||||
|
||||
await client.close();
|
||||
await endpoint.close();
|
||||
Reference in new issue
Block a user