tls: load NODE_EXTRA_CA_CERTS at startup#23354
Conversation
sam-github
left a comment
There was a problem hiding this comment.
This makes the env var behave as intended and described. One suggested change.
There was a problem hiding this comment.
I find the text confusing here, I'm not sure what is meant by "setting paths". Rather than rewriting though, I suggest removing the entire doc change, both sentences. Its unnecessary, env variables are intended to be set outside node, not by node to configure itself at runtime.
There was a problem hiding this comment.
Right. My explanation here makes the doc even confusing.
|
@sam-github @bnoordhuis PTAL |
There was a problem hiding this comment.
One suggestion: I think this can be called unconditionally. certLoadExtraRootCertsFile is a null op if extra_root_certs_file hasn't been set, and it is only set if this env var is present, so this is a non-obvious optimization. I think its a bit fragile, if a CLI flag was introduced to set the extra_root_certs_file, for example, then this code would not execute, and the bug you are fixing would resurface for that use case.
There was a problem hiding this comment.
Another potential footgun: the C++ code does suid root checks (calls SafeGetenv("NODE_EXTRA_CA_CERTS")); process.env does not.
There was a problem hiding this comment.
I have removed the conditional statement as @sam-github suggested. After the removing, we don't use process.env.NODE_EXTRA_CA_CERTS in js land which avoids the potential footgun @bnoordhuis described.
There was a problem hiding this comment.
This breaks ./configure --without-ssl builds. Not the require statement itself but the internalBinding('crypto') statement in the included file, it'll throw an exception.
There was a problem hiding this comment.
Would making this conditional on Boolean(process.versions.openssl) as test/common/util.js does for hasCrypto be OK, or is there a better way?
There was a problem hiding this comment.
I have placed this line in if (process.versions.openssl) {.
... or is there a better way?
I think it's ok as lib/internal/util also uses process.versions.openssl to assert crypto:
Line 18 in 972d0be
There was a problem hiding this comment.
And a new test has been added to ensure that it won't throw without ssl.
There was a problem hiding this comment.
Another potential footgun: the C++ code does suid root checks (calls SafeGetenv("NODE_EXTRA_CA_CERTS")); process.env does not.
addaleax
left a comment
There was a problem hiding this comment.
Is this a semver-major change? It seems like it could be?
There was a problem hiding this comment.
You could just access the binding directly here if you like
There was a problem hiding this comment.
I assumed there are codes other than just calling functions from binding before.
Accessing the binding directly is better as it could indicate why if (process.versions.openssl) is necessary to other contributors.
There was a problem hiding this comment.
Ditto about accessing the binding directly (again, only if you like)
|
@addaleax Yes. This might break something. |
There was a problem hiding this comment.
Why the comma is introduced?
There was a problem hiding this comment.
It's unintentionally introduced(my personal code style :-)). I'm going to restore this line.
There was a problem hiding this comment.
Shouldn't this condition be split into two, like in the current code? If root_cert_store is already created and extra_root_certs_file is not empty, we should still add them, right?
There was a problem hiding this comment.
If root_cert_store is already created and extra_root_certs_file is not empty, we should still add them, right?
No, it seems the original codes won't set root_cert_store again if it's available. Please remind me if I mistake something.
There was a problem hiding this comment.
You are correct. I misread the code. But I still have one question. As per old code if the root_cert_store is not there yet, a new instance of NewRootCertStore is created and assigned to it. Shouldn't the new code also do the same?
There was a problem hiding this comment.
As per old code if the root_cert_store is not there yet, a new instance of NewRootCertStore is created and assigned to it.
Yes. One of the reasons is that I use root_cert_store to indicate whether the certs have been loaded in the flowing test.
But I think you are right. I'm going to modify the code and make the new code do the same.
|
@thefourtheye PTAL |
thefourtheye
left a comment
There was a problem hiding this comment.
Nit: The newly exposed functions' names sound a little wordy.
There was a problem hiding this comment.
Nit: Maybe we can just run this test only when crypto is not there, just to emphasize?
There was a problem hiding this comment.
It seems that we don't run tests with --without-ssl build. I would like and change the comment a bit and keep the test.
17923f2 to
924e117
Compare
bnoordhuis
left a comment
There was a problem hiding this comment.
Left some comments but mostly LGTM.
There was a problem hiding this comment.
Style nit: 4 space indent (line continuation.)
There was a problem hiding this comment.
Style: root_cert_store == nullptr
(I know older code says !root_cert_store but new code shouldn't.)
There was a problem hiding this comment.
Style: can you line up the arguments?
There was a problem hiding this comment.
The certIsExtra... name is kind of misleading; the other cert... methods are for SPKAC.
There was a problem hiding this comment.
--expose-internals isn't necessary, is it?
There was a problem hiding this comment.
Maybe clarify that this test is written for ./configure --without-ssl builds. (That's right, isn't it?
4a8bfbe to
bcef787
Compare
|
@bnoordhuis Thanks for your comments. PTAL. |
There was a problem hiding this comment.
Could this possibly be injected via bootstrapper.cc instead? Especially since it's only used here.
There was a problem hiding this comment.
Now, it's removed to UseExtraCaCerts.
refack
left a comment
There was a problem hiding this comment.
Left some questions, and requests.
There was a problem hiding this comment.
Avoid globals. If this is per environment, it should be a member property of node::Environment. If it's actually a per-process global, IMHO it should be grouped into a struct with root_cert_store and extra_root_certs_file
There was a problem hiding this comment.
Grouping root_cert_store will make the code a bit messy. And as the extra_root_certs_file has been removed, I guess it's okay now.
There was a problem hiding this comment.
Since there is no test IMHO the description should be:
... won't throw even when there is no... Hence we don't test `common.hasCrypto`
^^^^
There was a problem hiding this comment.
Thanks. I guess I made this test too confusing.
There was a problem hiding this comment.
IMHO this will be more readable is it was:
if {
} else if {
} else if {
} else {
assert.fail("Bad child process invocation")
}Having a if (process.argv[2] !== 'child') guard remove the need to do return in each clause
There was a problem hiding this comment.
This should be outside of the scope that start in L9
There was a problem hiding this comment.
What is the difference between this and the one before?
IF they can be merged, please do, else please add a comment.
There was a problem hiding this comment.
Is there a requirement to call this from JS? If not this should be called during Environment::Start, or even in
Lines 2972 to 2975 in cf3f8dd
https://github.com/nodejs/node/blob/bcef787dce0a380e3ce66936e72c49176de67838/src/node_crypto.cc#L835-L837
There was a problem hiding this comment.
Loading extra ca certs will emit a warning when the certs files are not valid:
Line 881 in 05394d2
And as the
Environment and the js runtime(this name maybe not correct) is not setup yet while calling UseExtraCaCerts, we can't move the calling here.
I would like to move LoadExtraRootCertsFile() to bootstrapper.cc as @jasnell suggested, how do you think about it?
There was a problem hiding this comment.
Since IIUC this is sort of a command line error, we do have precident of printing the error directly:
Lines 2434 to 2444 in cf3f8dd
Lines 354 to 359 in cf3f8dd
Lines 382 to 415 in cf3f8dd
Alternatively if you add this to Environment::Start, you could use this to setup the warning:
for example after:
Line 278 in cf3f8dd
There was a problem hiding this comment.
we do have precident of printing the error directly
Then I think moving the calling into the function body of UseExtraCaCerts is better. Let me take a try on my mac(as I remember there is a test to check the warning message.).
|
Hello @oyyd, thank you for this fix. |
|
Hi @refack, feel free to leave more comments :-). I'm going to check them later. |
There was a problem hiding this comment.
Can we replace this new global boolean with following logic:
if (!extra_root_certs_file.empty()) {
...
if (err) {
...
extra_root_certs_file = nullptr;
}
}
...
static void IsExtraRootCertsFileLoaded(const FunctionCallbackInfo<Value>& args) {
return args.GetReturnValue().Set(extra_root_certs_file != nullptr);
}There was a problem hiding this comment.
The compiler complained about the extra_root_certs_file != nullptr. (Otherwise, I think it should be a better choice.)
|
@refack Thanks. Please take another look. |
|
The new test needs to extend |
Ohh, that's a common pitfall. |
There was a problem hiding this comment.
| { env: { NODE_EXTRA_CA_CERTS } }, | |
| {env: Object.assign({}, process.env, { NODE_EXTRA_CA_CERTS })}, |
|
The failed travis ci test is unrelated. Now it's ready. |
This commit makes node load extra certificates at startup instead of first use. PR-URL: nodejs#23354 Fixes: nodejs#20434 Refs: nodejs#20432 Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
NODE_EXTRA_CA_CERTSis not intended to be used to set the paths of extra certificates and this approach to setting is not reliable. This commit makes node load extra certificates at startup rather than on first use.Fixes: #20434
Refs: #20432
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes