| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Review requested:
|
Sorry, something went wrong.
|
Related: #39657 (comment) Having such functionality in node isn't completely out of the question but the default behavior should be consistent across platforms, meaning it should almost certainly be opt-in. |
Sorry, something went wrong.
|
@bnoordhuis Thanks for taking a look at the draft PR. I've taken a quick look at the thread mentioned in your comment. It seems like for windows we can go ahead with the current approach of reading system store and implement the solution behind an opt-in flag. I believe it will be a build-time flag. |
Sorry, something went wrong.
Why not a regular cli option? |
Sorry, something went wrong.
|
@RaisinTen I choose a build time flag rather than a regular cli option more from my understanding so far. I see a similar use case with node which reads the default OpenSSL cert store for certificates when built with openssl-use-def-ca-store. |
Sorry, something went wrong.
|
@twitharshil that one is actually a runtime flag accompanied by a build time flag. --use-bundled-ca and --use-openssl-ca are the runtime flags. --openssl-use-def-ca-store is the build time flag that is used to select which one of those 2 runtime flags would be enabled by default. |
Sorry, something went wrong.
|
Hey @bnoordhuis @RaisinTen |
Sorry, something went wrong.
There was a problem hiding this comment.
Left some comments. I've commented on some of the technical aspects but I'm still on the fence as to whether it's a desirable feature.
Speaking for myself, the fact that so far it's Windows-only counts against it.
Sorry, something went wrong.
There was a problem hiding this comment.
This manual formatting of a certificate is kind of questionable. If you have the certificate in DER format, you can pass it to openssl directly:
X509Pointer cert(d2i_X509(nullptr, buf, len));
if (cert) {
// ...
}openssl has utility functions like X509_print_ex() for formatting it as PEM, which I guess you're doing so they show up in tls.rootCertificates?
Sorry, something went wrong.
@bnoordhuis I think this feature has been one of the most demanding features for quite some time now. In recent times I worked closely to support these MITM-based proxies environment only for the windows platform so I thought of upstreaming this feature to node. Over the years no one picked up this work, so I believe supporting the windows platform at least is better than nothing? We can iteratively get this done for other platforms as well in separate PRs. I am open if someone else wants to pick this work for macOS & Linux otherwise I will pick it up once I find more time. |
Sorry, something went wrong.
|
Hey, @bnoordhuis @jasnell I've addressed the PR comments, can I get another round of review on my PR? |
Sorry, something went wrong.
There was a problem hiding this comment.
Generally LGTM but this should probably be reviewed by someone more familiar with the Windows crypto API than I am.
Sorry, something went wrong.
| void ReadSystemStoreCertificates( | ||
| std::vector<std::string>* system_root_certificates) { | ||
| #ifdef _WIN32 | ||
| const HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT"); |
There was a problem hiding this comment.
| const HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT"); | |
| const HCERTSTORE hStore = CertOpenSystemStoreW(nullptr, L"ROOT"); |
Because the first arg is a pointer, right? How likely is it for this method to fail?
Sorry, something went wrong.
| while ((certificate_context_ptr = CertEnumCertificatesInStore( | ||
| hStore, certificate_context_ptr)) != nullptr) { |
There was a problem hiding this comment.
Prefer something like this for readability reasons:
| while ((certificate_context_ptr = CertEnumCertificatesInStore( | |
| hStore, certificate_context_ptr)) != nullptr) { | |
| for (;;) { | |
| certificate_context_ptr = | |
| CertEnumCertificatesInStore(hStore, certificate_context_ptr); | |
| if (certificate_context_ptr == nullptr) break; |
Sorry, something went wrong.
|
|
||
| bio.reset(); |
There was a problem hiding this comment.
| bio.reset(); |
Not necessary to reset manually, the destructor does that automatically when it goes out of scope.
Sorry, something went wrong.
| PEM_read_bio_X509(NodeBIO::NewFixed(root_certs[i], | ||
| strlen(root_certs[i])).get(), | ||
| nullptr, // no re-use of X509 structure | ||
| PEM_read_bio_X509(NodeBIO::NewFixed(combined_root_certs[i].c_str(), |
There was a problem hiding this comment.
| PEM_read_bio_X509(NodeBIO::NewFixed(combined_root_certs[i].c_str(), | |
| PEM_read_bio_X509(NodeBIO::NewFixed(combined_root_certs[i].data(), |
Sorry, something went wrong.
| reinterpret_cast<const uint8_t*>(root_certs[i])) | ||
| .ToLocal(&result[i])) { | ||
| env->isolate(), | ||
| reinterpret_cast<const uint8_t*>(combined_root_certs[i].c_str())) |
There was a problem hiding this comment.
Minor optimization:
| reinterpret_cast<const uint8_t*>(combined_root_certs[i].c_str())) | |
| reinterpret_cast<const uint8_t*>(combined_root_certs[i].data()), | |
| v8::NewStringType::kNormal, | |
| combined_root_certs[i].size()) |
Sorry, something went wrong.
|
It seems this PR has stalled. @twitharshil Do you plan to finish it? |
Sorry, something went wrong.
I'll take it over. |
Sorry, something went wrong.
@joyeecheung in case you want to pick this up I've pushed a branch here with conflicts resolved: let me know either way |
Sorry, something went wrong.
| void ReadSystemStoreCertificates( | ||
| std::vector<std::string>* system_root_certificates) { | ||
| #ifdef _WIN32 | ||
| const HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT"); |
There was a problem hiding this comment.
Worth taking a look at this change to openjdk and thinking about is the system store enough:
openjdk/jdk@5e5500c
https://bugs.openjdk.org/browse/JDK-6782021
There's also the Jetbrains implementation that accesses a number of stores and aggregates them:
https://github.com/JetBrains/jvm-native-trusted-roots/blob/trunk/src/main/java/org/jetbrains/nativecerts/win32/Crypt32ExtUtil.java#L30-L36
I've had confirmation that the jetbrains one doesn't work with intermediate certificates, awaiting confirmation with the OpenJDK one.
Sorry, something went wrong.
There was a problem hiding this comment.
To make matters a bit more complex - Windows has this feature of revoking certificates through the "disallowed" store, that Chromium implements, for example https://github.com/chromium/chromium/blob/a5cf86ae718b86764946713e7abae12f1fa42d08/net/cert/internal/trust_store_win.cc#L334
Though I feel that for an initial implementation, not supporting that is fine because apparently many runtimes do not support it either (also we do not respect that when using the bundled certificates, anyway)
Sorry, something went wrong.
|
@timja I opened #56833 which rewrites the code a bit to make it easier to add more certificates other than the root CA of the current user (what this PR allows). There is a pretty extensive list of stores that Chromium considers that is documented here https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/faq.md#does-the-chrome-certificate-verifier-consider-local-trust-decisions - maybe it's not necessary to implement them all in the first iteration, but it would be nice to follow them all eventually. And to match what Chromium does we should also check that the certificates are configured for TLS use, which I left a TODO there as well, will look into that tomorrow before I open the PR for review. |
Sorry, something went wrong.
|
@joyeecheung / someone mind closing this? It was resolved as part of #56833 |
Sorry, something went wrong.
|
#56833 has already landed and released, so I'll close this. Thanks for initiating the work Harshil! :) |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Description of Change
MITM-based proxy environments like ZScaler intercepts the requests sent to a certain endpoint from the user machine and serve a redirect to their own servers ( for eg: https://gateway.zscloud.net/ ) before finally redirecting back to the original endpoint. We have observed root certificates of these proxy vendors present on the user system store. These certificates are needed for the request's SSL certificate verification.
Chrome reads certificates from the system store hence the certificate verification step passes when a request is sent out of the user machine through chrome as a client.
Node uses a statically compiled, hardcoded list of certificate authorities, rather than relying on the system's trust store, hence request going out from node as a client fails at the SSL verification step behind such environments.
This PR targets to read the certificates from the user system store and embed them with the existing list of root certificates with the node.
Note:
These changes will make a huge impact on the applications that use open source projects like electron which uses node in their networking layers.
In my current implementation, I've added logic to read the certificates from the system store and embed it with the existing list together in a single file. I am open to suggestions if we want the certificate read logic to be written somewhere else.
This PR only targets the windows platform for now. All the users from which we collected feedback were windows users only. Changes made in the PR are feature flagged behind a runtime CLI option named --node-use-system-ca