|
18 | 18 | #include <openssl/engine.h>
|
19 | 19 | #endif // !OPENSSL_NO_ENGINE
|
20 | 20 |
|
| 21 | +#ifdef _WIN32 |
| 22 | +#include <Windows.h> |
| 23 | +#include <wincrypt.h> |
| 24 | + |
| 25 | +#include "base64-inl.h" |
| 26 | +#endif |
| 27 | + |
21 | 28 | namespace node {
|
22 | 29 |
|
23 | 30 | using v8::Array;
|
@@ -190,17 +197,84 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
|
190 | 197 |
|
191 | 198 | } // namespace
|
192 | 199 |
|
| 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 | + |
193 | 256 | X509_STORE* NewRootCertStore() {
|
194 | 257 | static std::vector<X509*> root_certs_vector;
|
195 | 258 | static Mutex root_certs_vector_mutex;
|
196 | 259 | Mutex::ScopedLock lock(root_certs_vector_mutex);
|
197 | 260 |
|
198 | 261 | if (root_certs_vector.empty() &&
|
199 | 262 | per_process::cli_options->ssl_openssl_cert_store == false) {
|
| 263 | + |
| 264 | + std::vector<std::string> combined_root_certs; |
| 265 | + |
200 | 266 | 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++) { |
201 | 275 | 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(), |
204 | 278 | nullptr, // no re-use of X509 structure
|
205 | 279 | NoPasswordCallback,
|
206 | 280 | nullptr); // no callback data
|
@@ -234,19 +308,30 @@ X509_STORE* NewRootCertStore() {
|
234 | 308 |
|
235 | 309 | void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
|
236 | 310 | Environment* env = Environment::GetCurrent(args);
|
237 |
| - Local<Value> result[arraysize(root_certs)]; |
| 311 | + |
| 312 | + std::vector<std::string> combined_root_certs; |
238 | 313 |
|
239 | 314 | 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++) { |
240 | 325 | if (!String::NewFromOneByte(
|
241 | 326 | env->isolate(),
|
242 |
| - reinterpret_cast<const uint8_t*>(root_certs[i])) |
| 327 | + reinterpret_cast<const uint8_t*>(combined_root_certs[i].c_str())) |
243 | 328 | .ToLocal(&result[i])) {
|
244 | 329 | return;
|
245 | 330 | }
|
246 | 331 | }
|
247 | 332 |
|
248 | 333 | args.GetReturnValue().Set(
|
249 |
| - Array::New(env->isolate(), result, arraysize(root_certs))); |
| 334 | + Array::New(env->isolate(), result.data(), combined_root_certs.size())); |
250 | 335 | }
|
251 | 336 |
|
252 | 337 | bool SecureContext::HasInstance(Environment* env, const Local<Value>& value) {
|
|
0 commit comments