-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: added support for reading certificates from macOS system store #56599
base: main
Are you sure you want to change the base?
Conversation
Review requested:
|
8fd32ce
to
f3c212c
Compare
Would it be possible for someone to re-open the feature request please? #39657. It was closed due to being stale / no progress on it. |
Co-authored-by: Joyee Cheung <[email protected]>
key: fixtures.readKey('agent1-key.pem'), | ||
cert: fixtures.readKey('agent1-cert.pem') | ||
}, handleRequest); | ||
httpsServer.listen(0, common.mustCall(async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing an async function to httpsServer.listen(...)
is unexpected here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it a problem? It seems to work fine, I tried a few other approaches including using the node test framework but I struggled to get the test to wait for the https server to be listening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've found an example pattern that should work: https://github.com/nodejs/node/blob/c3a7b29e56a5ada6327ebb622ba746d022685742/test/parallel/test-tls-client-allow-partial-trust-chain.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjusted, let me know if any issues with the new one
src/crypto/crypto_context.cc
Outdated
// where the trustSettings parameter returns NULL. | ||
// No trust-settings array means | ||
// “this certificate must be verifiable using a known trusted certificate”. | ||
if (trustSettings == nullptr && !trustEvaluated) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this going against what the docs says? The certificate is only to be trusted as root certificate if trustSettings is not null but points to an empty array? i.e. this should already be covered in IsTrustSettingsTrustedForPolicy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No is trust settings won’t find it as there’s no trust settings. The validate is implementing the part of the statement must be validated by another certificate. This is for intermediate certificates that are not sent by the web server but are present in the OS keychain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case shouldn't this be removed from the global root certificate array? And verified using SecPolicyCreateSSL
instead on a per-connection basis? IIUC this is taking all the intermediate certificates, doing a basic check with SecPolicyCreateBasicX509
, and if it looks X509 compliant, add it to the global root certificate array, which seems unsafe..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SecTrustEvaluateWithError is validating that this is a trusted certificate.
Potentially, I suspect that’s what Chromium is doing although I didn’t find the code, intermediate certificates do work there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I can tell chromium stores intermediates here:
https://github.com/chromium/chromium/blob/main/net/cert/internal/trust_store_mac.cc#L823
The code is quite hard to follow.
When evaluating client certificates they do use SecTrustEvaluateWithError
in order to get the full chain:
https://github.com/chromium/chromium/blob/98f89988c9774d0e138a0724aa64c46187203a77/net/ssl/client_cert_store_mac.cc#L83-L84
but I can't see the same for regular certificate validation.
I think this is compliant but let me know if you think there's a better way of doing it
Thanks for the reviews all I'll continue actioning tomorrow. |
Fixes #39657
Builds on #44532 but for macOS
TODO:
Make it work, it works 🥳Review that all CF resources are being appropriately released, I think its right nowReview whether and where tests are appropriate- Added although disabled by defaultI can take a look at the Windows one after, resolving the conflicts and addressing the review comments as well.
Happy to refactor heavily, I haven't used c++ before and I wrote it initially in objective c and ported it across.
This is heavily based upon chromium and some of OpenJDK along with a PR I have open with OpenJDK
Testing
I'm using https://github.com/timja/openjdk-intermediate-ca-reproducer as a reproducer:
Install the certificates, either by adding to keychain manually (see README) or using
/usr/bin/security
(see what the test is doing in this PR.main.js
/Users/$USER/projects/node/out/Release/node --use-system-ca main.js
I've also tested this through a ZScaler MiTM setup.