From d0492998297515620b241bc42d6dbfc8990f5db2 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Thu, 9 Mar 2017 13:33:51 -0500 Subject: [PATCH] CRYPTO: Add configure option to use system CA certificates This patch allows distribution packagers to pass a `--system-ca-certificates` argument to `./configure` in order to specify a CA certificate bundle file on the system on which Node will be installed. If this argument is passed, Node will *only* use the system CA certificates and not its internal built-in ones, though they can still be extended through the use of the NODE_EXTRA_CA_CERTS environment variable. Signed-off-by: Stephen Gallagher --- configure | 6 ++++++ node.gyp | 6 +++++- src/node_crypto.cc | 32 ++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 31d682575e7a0d..ef20045cbd6bf5 100755 --- a/configure +++ b/configure @@ -269,6 +269,10 @@ parser.add_option('--systemtap-includes', action='store', dest='systemtap_includes', help='directory containing systemtap header files') +parser.add_option('--system-ca-certificates', + action='store', + dest='system_ca_certs', + help='Location of the system-provided certificate bundle') parser.add_option('--tag', action='store', @@ -914,6 +918,8 @@ def configure_node(o): else: o['variables']['coverage'] = 'false' + o['variables']['system_ca_certs'] = options.system_ca_certs or '' + def configure_library(lib, output): shared_lib = 'shared_' + lib output['variables']['node_' + shared_lib] = b(getattr(options, shared_lib)) diff --git a/node.gyp b/node.gyp index 637a1934287841..f1a7ab81bf937a 100644 --- a/node.gyp +++ b/node.gyp @@ -408,7 +408,11 @@ ], }], ], - }]] + }], + [ 'system_ca_certs!=""', { + 'defines': [ 'SYSTEM_CA_CERTS="<(system_ca_certs)"' ], + }] + ] }, { 'defines': [ 'HAVE_OPENSSL=0' ] }], diff --git a/src/node_crypto.cc b/src/node_crypto.cc index f4b0506a15e4d1..77b77d97a2ac13 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -696,7 +696,26 @@ static int X509_up_ref(X509* cert) { #endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL -static X509_STORE* NewRootCertStore() { +static X509_STORE* NewRootCertStore(SecureContext* sc) { + X509_STORE* store; + +#if defined(SYSTEM_CA_CERTS) + + // Use the system CA certificates bundle provided at configure time instead + // of the built-in ones. + if (SSL_CTX_load_verify_locations(sc->ctx_, SYSTEM_CA_CERTS, NULL) == 1) { + store = SSL_CTX_get_cert_store(sc->ctx_); + } else { // Empty store + // If we can't read the SYSTEM_CERTS location, then the only safe action + // is to add no certificates at all. This might be supplemented later by + // the environment variable NODE_EXTRA_CA_CERTS + store = X509_STORE_new(); + } + + return store; + +#else // use built-in CA certificates + if (root_certs_vector.empty()) { for (size_t i = 0; i < arraysize(root_certs); i++) { BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); @@ -710,7 +729,7 @@ static X509_STORE* NewRootCertStore() { } } - X509_STORE* store = X509_STORE_new(); + store = X509_STORE_new(); if (ssl_openssl_cert_store) { X509_STORE_set_default_paths(store); } else { @@ -721,6 +740,7 @@ static X509_STORE* NewRootCertStore() { } return store; +#endif // SYSTEM_CERTS } @@ -745,7 +765,7 @@ void SecureContext::AddCACert(const FunctionCallbackInfo& args) { while (X509* x509 = PEM_read_bio_X509(bio, nullptr, CryptoPemCallback, nullptr)) { if (cert_store == root_cert_store) { - cert_store = NewRootCertStore(); + cert_store = NewRootCertStore(sc); SSL_CTX_set_cert_store(sc->ctx_, cert_store); } X509_STORE_add_cert(cert_store, x509); @@ -784,7 +804,7 @@ void SecureContext::AddCRL(const FunctionCallbackInfo& args) { X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); if (cert_store == root_cert_store) { - cert_store = NewRootCertStore(); + cert_store = NewRootCertStore(sc); SSL_CTX_set_cert_store(sc->ctx_, cert_store); } @@ -837,7 +857,7 @@ void SecureContext::AddRootCerts(const FunctionCallbackInfo& args) { (void) &clear_error_on_return; // Silence compiler warning. if (!root_cert_store) { - root_cert_store = NewRootCertStore(); + root_cert_store = NewRootCertStore(sc); if (!extra_root_certs_file.empty()) { unsigned long err = AddCertsFromFile( // NOLINT(runtime/int) @@ -1079,7 +1099,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo& args) { X509* ca = sk_X509_value(extra_certs, i); if (cert_store == root_cert_store) { - cert_store = NewRootCertStore(); + cert_store = NewRootCertStore(sc); SSL_CTX_set_cert_store(sc->ctx_, cert_store); } X509_STORE_add_cert(cert_store, ca);