-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
Documented way to add certificates to existing SecureContext #27079
Comments
I’m not sure it’s safe to consider @nodejs/crypto may have more insight (and more helpful opinions). |
I'm not sure a wrapper is the right solution. That feels like the start of extra functions to maintain. Besides appending to or enumerating the current list, removing is equally useful (as opposed to revoking). I wonder if adding more documentation would enable a home rolled |
If this is your use case, I believe it is met by #26415 Adding direct access to SecureContext.context is a no-go, we're more likely to deprecate that and then make it inaccessible from user space, re-exporting well defined functions. This allows us to do less error checking in C++, among other things, and just assert on C++ API misuse. |
Not sure if that is feasible, only the |
This would solve my use case with documented API, albeit a little more cumbersome than my current approach.
Just to confirm, should we expect the
Yeah, that is what my mind wandered to. Figured it was something like that. |
Let me be abolutely clear: Because node.js attempts not to break user's code, even code that depends on undocumented implementation details or internal properties, we are unlikely to make breaking changes to SecureContext outside a semver-major, but you use it at your own risk. |
The ability to add additional certificate authorities at runtime is an important need for the company I work for. The short version is that the lack of support for Windows' built-in certificate store results in many developers slamming NODE_TLS_REJECT_UNAUTHORIZED=0 into their code as a quick workaround so they can debug and test locally. @sam-github any thought on what a well designed Node.js API for adding additional CAs would look like? The most obvious idea would be to let Alternately, what do you think about |
@ebickle Your devs have demonstrated that they are comfortable setting an env variable, so why not set NODE_EXTRA_CA_CERTS instead of NODE_TLS_REJECT_UNAUTHORIZED?
That said, I personally don't have any problem with a mutable |
The crux of it is that NODE_EXTRA_CA_CERTS cannot be set at runtime, unfortunately. The longer answer is is that developers run into the TLS verification failure and they're in the mental mode of "get the project working" not "configure my development workstation". They Google around for documentation, give NODE_EXTRA_CA_CERTS a try at runtime and fail, then give up and toss NODE_TLS_REJECT_UNAUTHORIZED into the codebase regardless of how much security training we toss at them. They can't find the solution (at a project-level) within a reasonable amount of time and then move on to get their work done. In an enterprise-scenario with a very large number of nonhomogeneous developer workstations around the world, getting NODE_EXTRA_CA_CERTS on the dev machines consistently is also an operational challenge. Appreciate the advice on using
Bigger change, but gets directly to the use case of wanting to add private enterprise CAs to Node.js without affecting anything else. By adding it to createSecureContext, the functionality would be consistent across all of Node.js instead of just being patched in here or there. An alternate solution would be to have an |
But you asked for a js API to add a cert... which means that a cert (probably in PEM) has to exist on the machine (probably checked into the code base) to be passed to that js API.... I'm not seeing how modifying a project's package.json to do In a sufficiently enterprise env, I'd expect the start script to be baked into the base Dockerfile.
Please describe why not. It seems completely equivalent to your proposals, but much simpler and consistent with how tls is configured now. Your initial suggestion was:
Assuming that your suggestion supported your use-case (which I did assume!), your example API is identical in behaviour to my suggestion:
This "override" API proposal doesn't add anything that doesn't exist already, as far as I can see:
It just allows writing:
instead of what is possible right now:
|
The How would you see |
Yes, that's what I'd expect. |
I've been doing some initial work on this over the past few weeks. After digging through the code, I'd recommend against a What about adding a setter to After validating the input and ensuring the certs can be read as valid X509 objects they can be placed in the The frozen nature of the Separately, while doing a code review of |
The performance issues are a good point. What about cacheing? If the textual value of DEFAULT_CA is the same as that used for the default X509_STORE, use the default store? It seems like a general fix to the
PR fixes for them, or open an issue to ask if they are a problem, or ask in the slack/irc if you'd like a quick conversation. If you think they are security problems, report on hacker one (see our security page). |
Modifies the tls.rootCertificates property so that it is settable. PEM-formatted certificates set to the property are loaded into a new Node.js root certificate store that is used for all subsequent TLS requests and peer certificate validation. Allows full programmatic control of a Node.js process' root certificate store. Fixes: nodejs#20432 Refs: nodejs#27079
Modifies the tls.rootCertificates property so that it is settable. PEM-formatted certificates set to the property are loaded into a new Node.js root certificate store that is used for all subsequent TLS requests and peer certificate validation. Allows full programmatic control of a Node.js process' root certificate store. Fixes: nodejs#20432 Refs: nodejs#27079 Changed root_cert_store to a smart pointer Added support for empty root certificates Added comment
I just want to add a use case here that's not addressed by the ability to modify global TLS defaults or other approaches discussed above: trusting an extra CA, in addition to both the built-in root CAs and NODE_EXTRA_CA_CERTS CAs etc, for just a single connection. I'm writing this within a JS library, not the end application, so I do not control Node's configuration, and I need to add an extra CA for a connection in a way that works regardless of options & global state. In this case:
The 3rd point was noted and fixed in the past (see #32074) but the fix caused issues with This use case could be supported by one of either:
|
@pimterry I have added a monkey-patch to the standard library |
@pimterry Glad to see someone else digging into this area again! I've been wanting to write a proper fix for Node in this area, particularly after my failed attempt with #32074 Ultimately I realized that most of Node.js' "additional certificate handling" is a bit of a bolted on hack (for better or worse). It works, but it doesn't provide a solid foundation for additional enhancements. What I was hoping to do was provide a class/type that provides an abstraction for a certificate store. The "certificate store object" could then be used to add additional certificates ( It would be an efficient solution that covers most uses cases and provides a solid foundation for future improvements. I didn't want to propose a change that significant on my own, but if a few others are interested I'm happy to collaborate on a fork to see if a solid proposal comes together. |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
I would still find a solution to this useful, and I'd like to fix it. Would a PR potentially be accepted to:
(Happy to bikeshed the name if this is workable - I haven't tested this yet, but from a skim everything suggests that should work fine. As far as I'm aware, by doing this as part of normal context setup the performance impact here would be effectively zero (a single I think this would immediately fix this issue for the individual context case, which was the original motivating problem for @cinderblock at the start of this issue, and would solve my own use case above too. This doesn't fix the more general "globally trust an extra CA, defined at runtime" issue that @ebickle is facing, but it does at least provide an API to awkwardly work around that by adding additional CAs to every context individually. Should I put together a PR? |
@pimterry I was going to suggest the exact same thing. I don't feel strongly about the naming, but as an alternative a boolean could be used to avoid exclusive It's been awhile since I've looked at code, but we should make sure the new option can flow through from HTTPS agent options as well ( I'm not in a position to know if they'll accept a PR, but this is a strong use case and simple enough code that they likely will. A PR makes sense to me! If you get busy, let me know and I'll code up the PR. Happy to help review too. |
Ok thanks @ebickle. No response from the core team yet, but I'll put together a PR later this week and hopefully that'll spark some progress. |
Just to update here: I had a first pass at this, but sadly it turns out it's not quite as quick & easy as I'd hoped. You absolutely can call That means the proposed small change would indeed work and allow you to use I'll keep digging, I think there's a path through here by changing |
@pimterry The behavior of I'm experimenting with solving both issues in one go - I've My initial POC works right now, including |
Oh great work! Glad to see somebody investigating this already. I wasn't sure if that was a bug or intentional due to some problematic implications of changing this, but I'd be very happy to see it fixed 👍 |
@pimterry I still need to write some unit tests and do a thorough review, but if you want to experiment take a look at https://github.com/ebickle/node/tree/fix/tls-missing-extra-certificates I also haven't settled on what naming / design pattern I like best yet, but you can test it out by modifying
Then compile (using my fork/branch as the base) and add |
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment. For more information on how the project manages feature requests, please consult the feature request management document. |
There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment. For more information on how the project manages feature requests, please consult the feature request management document. |
This is not the right thing to do. Can we get a |
:( |
Good nudge @cinderblock! Since all that ancient discussion above, I've now joined the Node core team, so I can now help a bit more with actually making this happen 😄. I agree this would be extremely useful for some use cases, so I've reopened this & added never-stale. I think:
I think if we can get that PR merged (fixing #32010), then this approach should work with very simple changes (AFAICT) and then this issue would be sorted. I don't have a lot of time to dig into this in depth, but I'm happy to help shepherd from Node maintainer side. Is that all correct? If so, step 1 is fixing the conflicts in #44529 and then finishing up that PR. @ebickle I know this has been a bit of a saga, but any chance you're interested in working on that to wrap this up once & for all? |
@pimterry I'm happy to dust off my PR and resolve the conflicts or otherwise get it back up and ready. I left off with some exploration of other open source tools to see how they integrated OpenSSL directly with the Windows certificate store with the hope that we could do something similar in Node - e.g. using an OS's built in certificates helps resolve the need for adding certificates manually at runtime. I got about halfway done before I realized node.js doesn't have much platform-specific logic outside of libuv, and libuv doesn't have TLS as a feature. I had wanted to think of a good solution for that and then got busy. I'd also played with some ideas for fancier higher level constructs like a "CertificateStore" object in Node.js that could be used at the global/environment level or as a parameter for a TLS agent. I got that about 70% done before I figured I was over-engineering... but if any of that sounds interesting, let me know! In any event, the plan outlined above sounds good and gets the job done in the shorter/medium term! |
This all sounds very cool! Definitely interesting to explore, but yes that's much more complicated & it'd definitely require some wider debate since it's quite a major change. Let's start with solving the practical problem and see where we can go from there. If you can ping me on that PR once the conflicts are resolved and you think it's ready, I'll review and help move it forwards 👍 |
In some cases, I've found that I've wanted to add a single CA to the list of trusted CAs that Node.js uses by default. There seems to be no documented way to do this. As it stands, officially, if you want to use non standard CAs, you can, but must also specify all CAs that might have otherwise been loaded automatically.
From the
createSecureContext
documentation:In trying to accomplish this, I've come across a seemingly stable but undocumented API #20432 (comment)
It looks to be a real API for a number of reasons:
_
)Would it make sense to document this feature?
Alternatives
If the default list of CAs were accessible in node, we could do this ourselves without adding extra APIs. I have not actually looked at if this is possible or unintentionally exposed by the SecureContext API.
Related Issues
#4464
#20432
#26908 (comment)
The text was updated successfully, but these errors were encountered: