-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
fix(tls): Optionally support loading native certs #11491
fix(tls): Optionally support loading native certs #11491
Conversation
Outstanding Issues
|
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.
There is now a lot of duplicated logic. I would suggest the following:
On ProgramState
creation, create a single rustls::RootCertStore
should be created containing certificates based on the user requested CA stores, and the certificate provided by --cert
. This rustls::RootCertStore
should then be injected into create_http_client
(and deno_fetch
), and all other places where we use TLS (deno_net
etc).
This would also allow you to remove all the places we inject ca_data
, because that would already be part of the rustls::RootCertStore
.
7d0744a
to
a60f607
Compare
a60f607
to
567eae6
Compare
Ok this was refactored and updated to:
|
567eae6
to
9ef120c
Compare
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.
Drive-by review.
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.
@justinmchase nice work! I pointed out some nitpicks and how to solve problem with adding multiple TLS related crates to deno_core
crate.
Ok thanks @bartlomieju I know how to proceed. |
Ok merged with The new tests call These tests positively test that the mozilla certs connect to deno.land and positively test that not loading any ca certs (an empty root_cert_store) fails to connect to deno.land. The only other test vector that isn't covered by existing tests would be to then put the right cert into the system keystore and test loading that... I don't know how to do that consistently across systems without some really complicated automation and frankly... it feels a bit tautological to test as that entire functionality exists in a different dependency we are adding which has its own testing. I've been testing manually and can confirm that adding the new flag allows me to connect to my internal company sites successfully. I'll leave it up to the maintainers to decide which tests are needed. |
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.
Left some comments but your PR mostly looks (very!) good.
Node supports all these use-cases via esoteric OpenSSL env vars. We can centralize and clean this up.
We'll be doing even better. Node can only use the system's openssl certificate bundle, whereas we will be able to use the native macos and windows stores.
It's an often-requested feature that never happened because openssl can't do it. Take nodejs/node#39657 - a feature request from < 24 hours ago.
let root_cert_store = state | ||
.borrow() | ||
.borrow::<DefaultTlsOptions>() | ||
.root_cert_store | ||
.clone(); |
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.
Cloning the store every time is somewhat inefficient. On my system it copies ~200 kB of data.
It's not really a regression though because we currently copy webpki_roots::TLS_SERVER_ROOTS
and that's about the same size.
Ideally, we create and cache the Arc<rustls::ClientConfig>
so it can be reused instead of created anew for every connection...
...but that's something that can wait for a follow-up PR, it doesn't have to block this one.
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.
That is why I did that, the roots were cloned before and this ended up following that pattern for better or worse.
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.
Given how this already feels to be max size for this PR I'm happy to leave this for a future refactor.
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.
That's fine, but please add a TODO here so we don't forget about it :)
If Ben and Luca are ok with this, then I have no objections. We just need to make sure this is properly documented after this patch lands. |
ddb5082
to
e7dcd32
Compare
e7dcd32
to
19653bf
Compare
Just to be clear by "this" I assume you mean keeping the functionality as it is in this pr right now? To have the If so then this PR is ready I believe. I linted, formatted and squashed the changes in the branch as well as manually tested one more time. |
For posterity: I don't have opinions on how this feature should be activated. Bartek or Luca are more qualified to make that call. |
That's right, I'll give this PR another review tonight. Could you please open a PR in https://github.com/denoland/manual that describes this functionality? Turning Luca's comment into some kind of doc would be awesome. |
Fix typo Co-authored-by: Ben Noordhuis <[email protected]>
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.
@justinmchase this PR is really well implemented, very nice work! I have only a couple minor nitpicks left and we're good to merge.
[[package]] | ||
name = "openssl-probe" | ||
version = "0.1.4" | ||
source = "registry+https://github.com/rust-lang/crates.io-index" | ||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" | ||
|
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.
Yikes 😬 it comes from rustls-native-certs
and it doesn't seem it could be in any way skipped (no feature flags in that crate). I looked up that crate's code and it doesn't do any interaction with OpenSSL so I guess we can live with that.
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.
Interesting, I think it does say something about it in the docs now that you mention it:
On Linux and other UNIX-like operating systems, the openssl-probe crate is used to discover the filename of the system CA bundle.
let root_cert_store = state | ||
.borrow() | ||
.borrow::<DefaultTlsOptions>() | ||
.root_cert_store | ||
.clone(); |
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.
That's fine, but please add a TODO here so we don't forget about it :)
@justinmchase it looks like this error was returned when pulling code for |
Succeeded this time, I didn't change anything. Weird. 🤷 All comments have been addressed I believe. Thanks all. |
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.
LGTM, thank you @justinmchase!
`fetch()` and client-side websocket used to support HTTP/2, but this regressed in denoland#11491. This patch reenables it by explicitly adding `h2` and `http/1.1` to the list of ALPN protocols on the HTTP and websocket clients. Fixes denoland#12517.
`fetch()` and client-side websocket used to support HTTP/2, but this regressed in #11491. This patch reenables it by explicitly adding `h2` and `http/1.1` to the list of ALPN protocols on the HTTP and websocket clients.
Overview
This changes Deno to support optionally loading certificates from the users local certificate store. This will allow them to successfully connect via tls with corporate and self signed certs provided they have them installed in their keystore. It also allows them to deal with revoked certs by simply updating their keystore without having to upgrade Deno.
Potentially in the future Deno could consider modifying its default behavior to load from the certificate store but for now it is only optionally enabled by specifying it in the new flag described below.
This change also adds a new flag
DENO_TLS_CA_STORE
which can have the valuessystem,mozilla
and will load them in the order they are specified and defaults tomozilla
.system
controls loading certs from the users certificate store andmozilla
controls loading the bundled mozilla certs.Issues
Fixes #11482
Related To #10312
Testing
I have access through VPN to an internal website which is using a certificate issued by my companies internal CA. With latest Deno I am unable to access that site because the only certificate I have is installed in my system keychain by my IT department.
The app code:
To see this error I am able to run:
Now with these changes I've run
Using the flag to remove the certificate store, results in the error again (as expected)