Skip to content

Commit f35fe3c

Browse files
committed
crypto: added support for reading system store crtificates in windows
1 parent 50a4131 commit f35fe3c

File tree

1 file changed

+90
-5
lines changed

1 file changed

+90
-5
lines changed

src/crypto/crypto_context.cc

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
#include <openssl/engine.h>
1919
#endif // !OPENSSL_NO_ENGINE
2020

21+
#ifdef _WIN32
22+
#include <Windows.h>
23+
#include <wincrypt.h>
24+
25+
#include "base64-inl.h"
26+
#endif
27+
2128
namespace node {
2229

2330
using v8::Array;
@@ -190,17 +197,84 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
190197

191198
} // namespace
192199

200+
void ReadSystemStoreCertificates(
201+
std::vector<std::string>* system_root_certificates) {
202+
const HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT");
203+
CHECK_NE(hStore, NULL);
204+
205+
auto cleanup = OnScopeLeave(
206+
[hStore]() { CHECK_EQ(CertCloseStore(hStore, 0), TRUE); });
207+
208+
PCCERT_CONTEXT pCtx = nullptr;
209+
210+
while ((pCtx = CertEnumCertificatesInStore(hStore, pCtx)) != nullptr) {
211+
const DWORD cbSize = CertGetNameStringW(pCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE,
212+
0, nullptr, nullptr, 0);
213+
214+
CHECK_GT(cbSize, 0);
215+
216+
std::vector<wchar_t> pszName(cbSize);
217+
218+
CHECK_GT(CertGetNameStringW(pCtx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr,
219+
pszName.data(), cbSize),
220+
0);
221+
222+
const char* certificate_src_ptr =
223+
reinterpret_cast<const char*>(pCtx->pbCertEncoded);
224+
const size_t slen = pCtx->cbCertEncoded;
225+
const size_t dlen = base64_encoded_size(slen);
226+
227+
char* certificate_dst_ptr = UncheckedMalloc(dlen);
228+
229+
CHECK_NOT_NULL(certificate_dst_ptr);
230+
231+
auto cleanup = OnScopeLeave(
232+
[certificate_dst_ptr]() { free(certificate_dst_ptr); });
233+
234+
const size_t written = base64_encode(certificate_src_ptr, slen,
235+
certificate_dst_ptr, dlen);
236+
CHECK_EQ(written, dlen);
237+
238+
std::string base64_string_output(certificate_dst_ptr, dlen);
239+
240+
constexpr size_t distance = 72;
241+
size_t pos = distance;
242+
243+
while (pos < base64_string_output.size()) {
244+
base64_string_output.insert(pos, "\n");
245+
pos += distance + 1;
246+
}
247+
248+
base64_string_output = "-----BEGIN CERTIFICATE-----\n" +
249+
base64_string_output +
250+
"\n-----END CERTIFICATE-----";
251+
252+
system_root_certificates->emplace_back(std::move(base64_string_output));
253+
}
254+
}
255+
193256
X509_STORE* NewRootCertStore() {
194257
static std::vector<X509*> root_certs_vector;
195258
static Mutex root_certs_vector_mutex;
196259
Mutex::ScopedLock lock(root_certs_vector_mutex);
197260

198261
if (root_certs_vector.empty() &&
199262
per_process::cli_options->ssl_openssl_cert_store == false) {
263+
264+
std::vector<std::string> combined_root_certs;
265+
200266
for (size_t i = 0; i < arraysize(root_certs); i++) {
267+
combined_root_certs.emplace_back(root_certs[i]);
268+
}
269+
270+
#ifdef _WIN32
271+
ReadSystemStoreCertificates(&combined_root_certs);
272+
#endif
273+
274+
for (size_t i = 0; i < combined_root_certs.size(); i++) {
201275
X509* x509 =
202-
PEM_read_bio_X509(NodeBIO::NewFixed(root_certs[i],
203-
strlen(root_certs[i])).get(),
276+
PEM_read_bio_X509(NodeBIO::NewFixed(combined_root_certs[i].c_str(),
277+
combined_root_certs[i].length()).get(),
204278
nullptr, // no re-use of X509 structure
205279
NoPasswordCallback,
206280
nullptr); // no callback data
@@ -234,19 +308,30 @@ X509_STORE* NewRootCertStore() {
234308

235309
void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
236310
Environment* env = Environment::GetCurrent(args);
237-
Local<Value> result[arraysize(root_certs)];
311+
312+
std::vector<std::string> combined_root_certs;
238313

239314
for (size_t i = 0; i < arraysize(root_certs); i++) {
315+
combined_root_certs.emplace_back(root_certs[i]);
316+
}
317+
318+
#ifdef _WIN32
319+
ReadSystemStoreCertificates(&combined_root_certs);
320+
#endif
321+
322+
std::vector<Local<Value>> result(combined_root_certs.size());
323+
324+
for (size_t i = 0; i < combined_root_certs.size(); i++) {
240325
if (!String::NewFromOneByte(
241326
env->isolate(),
242-
reinterpret_cast<const uint8_t*>(root_certs[i]))
327+
reinterpret_cast<const uint8_t*>(combined_root_certs[i].c_str()))
243328
.ToLocal(&result[i])) {
244329
return;
245330
}
246331
}
247332

248333
args.GetReturnValue().Set(
249-
Array::New(env->isolate(), result, arraysize(root_certs)));
334+
Array::New(env->isolate(), result.data(), combined_root_certs.size()));
250335
}
251336

252337
bool SecureContext::HasInstance(Environment* env, const Local<Value>& value) {

0 commit comments

Comments
 (0)