--- ./src/node_crypto.cc.orig6 Tue Oct 3 05:12:28 2017 +++ ./src/node_crypto.cc Fri Oct 20 17:54:23 2017 @@ -27,6 +27,7 @@ #include #include #include +#include #define THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(val, prefix) \ do { \ @@ -711,6 +712,52 @@ static X509_STORE* NewRootCertStore() { static std::vector root_certs_vector; if (root_certs_vector.empty()) { + // prefer CA cert files from env var SSL_CERT_DIR if set and exists, + // otherwise from the OS default dir (usually /etc/openssl/certs/) if it + // exists, otherwise fallback to the hardcoded certs. + const char *dir = getenv(X509_get_default_cert_file_env()); + DIR *certs_dir = opendir(dir != NULL ? dir : ""); + if (certs_dir == NULL) { + dir = X509_get_default_cert_dir(); + certs_dir = opendir(dir != NULL ? dir : ""); + } + if (certs_dir != NULL) { + // read the certs from the openssl lib's default cert dir + struct dirent *de; + char path[PATH_MAX]; + char rpath[PATH_MAX+1]; + size_t len; + struct stat st; + FILE *fp; + X509 *cert; + while ((de = readdir(certs_dir)) != NULL) { + strlcpy(path, dir, sizeof(path)); + strlcat(path, "/", sizeof(path)); + if (strlcat(path, de->d_name, sizeof(path)) >= sizeof(path)) + continue; // pathname too long/truncated - ignore + if (realpath(path, rpath) == NULL) + continue; + rpath[PATH_MAX]='\0'; + len = strlen(rpath); + if (strcmp(".pem", rpath + len - 4) != 0) + continue; // *.pem files only + if (lstat(rpath, &st) != 0) + continue; // rpath sz was not sufficient in realpath(), etc. + if ((st.st_mode & S_IFREG) != S_IFREG) + continue; // regular files, only + if ((fp = fopen(rpath, "r")) == NULL) + continue; // not readable + if ((cert = PEM_read_X509(fp, NULL, NULL, NULL)) != NULL) { + if (X509_check_ca(cert)) + root_certs_vector.push_back(cert); + // X509_STORE_add_cert(root_cert_store, cert); + else + X509_free(cert); + } + fclose(fp); + } + (void) closedir(certs_dir); + } else { for (size_t i = 0; i < arraysize(root_certs); i++) { BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); X509 *x509 = PEM_read_bio_X509(bp, nullptr, NoPasswordCallback, nullptr); @@ -721,6 +768,7 @@ root_certs_vector.push_back(x509); } + } } X509_STORE* store = X509_STORE_new(); --- ./doc/api/tls.md.orig6 Tue Oct 3 05:12:28 2017 +++ ./doc/api/tls.md Fri Oct 20 17:54:23 2017 @@ -971,9 +971,11 @@ A key is *required* for ciphers that make use of certificates. Either `key` or `pfx` can be used to provide it. -If the 'ca' option is not given, then Node.js will use the default -publicly trusted list of CAs as given in -. +If no 'ca' details are given, then Node.js will use all CA \*.pem files in the +directory given by the environment variable `SSL_CERT_DIR`, if it is unset +the CA \*.pem files in the default cert directory of the OS (usually +'/etc/openssl/certs/') and if this directory does not exist Node.js finally +falls back to an internal, hardcoded, [publicly trusted list of CAs]. ## tls.createServer([options][, secureConnectionListener]) @@ -1222,6 +1224,7 @@ [RFC 4492]: https://www.rfc-editor.org/rfc/rfc4492.txt [SSL_CTX_set_timeout]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_timeout.html [SSL_METHODS]: https://www.openssl.org/docs/man1.0.2/ssl/ssl.html#DEALING-WITH-PROTOCOL-METHODS +[publicly trusted list of CAs]: https://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt [Stream]: stream.html#stream_stream [TLS Session Tickets]: https://www.ietf.org/rfc/rfc5077.txt [TLS recommendations]: https://wiki.mozilla.org/Security/Server_Side_TLS