Skip to content
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

Allow Node to use certificates from the macOS Keychain when making HTTPS requests #39657

Closed
chriskilding opened this issue Aug 4, 2021 · 19 comments
Labels
feature request Issues that request new features to be added to Node.js. macos Issues and PRs related to the macOS platform / OSX. tls Issues and PRs related to the tls subsystem.

Comments

@chriskilding
Copy link

chriskilding commented Aug 4, 2021

On macOS and iOS platforms, Node should integrate with the Keychain to source its certificates for TLS requests.

Is your feature request related to a problem? Please describe.

At work our IT department is setting up TLS traffic inspection using custom certificates. These certificates are preinstalled in the keychains of our corporate Macs.

Mac apps and some CLI programs - like the system curl - are built against the Apple Secure Transport or Network frameworks. These allow them to use certificates from the keychain when making TLS requests. As a result the custom certificates work without issue in these programs.

Meanwhile, other programs that don't use the Apple frameworks basically all break, unless application-specific workarounds are used. The most high-profile failure we see in Node apps is NPM failing to fetch dependencies because of certificate errors.

At the moment the workaround for Node is to export the root cert to the filesystem, and set the NODE_EXTRA_CA_CERTS variable. This is doable but it's annoying, and results in duplicates of the certificate that must be maintained going forward. It would be far easier if Node used one of the aforementioned Apple frameworks, so that it can use certificates from the keychain transparently.

Describe the solution you'd like

Following the example of Curl (https://github.com/curl/curl/blob/master/docs/INSTALL.md#apple-platforms-macos-ios-tvos-watchos-and-their-simulator-counterparts), Node for macOS should use either the Secure Transport or Network framework to make TLS requests.

Describe alternatives you've considered

As far as I know the only way to integrate with the Keychain for TLS requests is to use the Apple frameworks.

@chriskilding
Copy link
Author

Would be good to get some pointers on where to start building this, for anyone who is interested in doing so.

Am I right that the place to start would be the https or tls modules within Node core?

@aduh95 aduh95 added feature request Issues that request new features to be added to Node.js. tls Issues and PRs related to the tls subsystem. macos Issues and PRs related to the macOS platform / OSX. labels Aug 5, 2021
@targos
Copy link
Member

targos commented Aug 5, 2021

Am I right that the place to start would be the https or tls modules within Node core?

Not sure, but I think it would probably have to be written in C++ somewhere in src/crypto

@chriskilding
Copy link
Author

I'm wondering if using the Network framework for HTTPS requests might tangentially be helpful for Electron apps, and other Mac apps that use Node...

If you submit an app to the App Store that is deemed to use cryptography, you normally have to do some extra export compliance paperwork. However there are exemptions if you're just using encryption that's built into the OS.

Apple's docs (https://developer.apple.com/documentation/security/complying_with_encryption_export_regulations) say:

Typically, the use of encryption that’s built into the operating system—for example, when your app makes HTTPS connections using URLSession—is exempt from export documentation upload requirements, whereas the use of proprietary encryption is not. To determine whether your use of encryption is considered exempt, see Determine your export compliance requirements.

So perhaps if the Node https API was backed by URLSession (one of the main Network classes), we could benefit from the exemption.

@z3n-badam
Copy link

Having done the US Dept Commerce export restrictions dance in a previous life working for a company that published our own build of Linux, I can confirm that leveraging the OS is a much easier route to go down.

Functionally, this enhancement is pretty important for organizations that are using technologies such as Cisco Umbrella - it spoofs DNS and is essentially a "corporate security approved man-in-the-middle", generating its own SSL certs on the fly. Right now, node apps running behind such a regime cannot connect successfully to any site that Umbrella is intercepting because the SSL certs that Umbrella generates have their own root cert installed in the Apple System keychain. (Note: not in the System Roots keychain). Node would need to look in both keychains to be successful in such an environment - easiest way to do this is via the OS framework.

@samskiter
Copy link

Working around this is a pain for anyone with a corporate machine/proxy - node should ideally respect the CAs installed on macos

@bnoordhuis
Copy link
Member

This feature request comes up every 1.5 years or so. It's never been implemented and the chances of it happening this time are... let's say, no better than before.

The reason node works the way it does is consistency. Node version x.y.z works exactly the same on every platform. Important for apps and libraries.

Previous discussions also ran aground on questions like "what if there is more than one trust store?" (Case in point: my Linux box has two. Which one is leading?)

@samskiter
Copy link

samskiter commented Jun 1, 2022 via email

@samskiter
Copy link

samskiter commented Jun 1, 2022 via email

@bnoordhuis
Copy link
Member

I put together a package that lets you use the system's trust store: https://github.com/bnoordhuis/node-native-certs

Uses the same library that Deno uses. Not yet published because I need to wrangle GitHub Actions into publishing the build artifacts somehow (it's a native library.)

If an Actions guru wants to chip in, that'd be very welcome.

@chriskilding
Copy link
Author

@bnoordhuis thanks for your contribution, and good to know it's the same as Deno under the covers. I'll see if I can rustle up a GitHub Action for you

@carl-3
Copy link

carl-3 commented Oct 11, 2022

I put together a package that lets you use the system's trust store: https://github.com/bnoordhuis/node-native-certs

Uses the same library that Deno uses. Not yet published because I need to wrangle GitHub Actions into publishing the build artifacts somehow (it's a native library.)

If an Actions guru wants to chip in, that'd be very welcome.

As a noob, could you please explain how to go about using this package to allow node to access my keychain?

@chriskilding
Copy link
Author

This package is something that will be evolved in several iterations to integrate it closer with Node.

In the first version, you'd install the package in a project which needs to use TLS root certs from the Keychain.
You'd then need to add a bit of glue code to your app to attach the retrieved certificate bundle to your HTTPS library.

You can either put that glue code in application startup (which will attach the bundle to all future requests), or you can attach the bundle to an individual request.

For example, if you use the built-in https module you could do:

const https = require("https")
const nativeCerts = require("native-certs")
const ca = nativeCerts()

// Note that this call is async so you also need a callback handler
https.get({ca, host: "example.com", path: "/"})

Or at startup it might look like:

const https = require("https")
const nativeCerts = require("native-certs")
const ca = nativeCerts()

https.globalAgent.options.ca = ca

// later on...

https.get({host: "example.com", path: "/"})

After that, all your app's HTTPS requests will use the root certs obtained from:

  • The Keychain (on macOS)
  • The Windows Certificate Store (on Windows)
  • The standard certificate lookup locations like /etc/ssl (on Linux)

If you want to use the certs on a different type of TLS connection (e.g. a database), you'd need to look up the respective networking library's way of specifying alternative certs.

@bnoordhuis
Copy link
Member

#44532 attempted to add Windows keychain support but seems to have stalled. The fact it's Windows-only makes it less likely to get merged so maybe someone wants to adopt it and add macOS support?

Expectation management: I can't guarantee it's going to get merged but multi-platform support would definitely help strengthen its case.

@diogoperes
Copy link

diogoperes commented Mar 6, 2023

@chriskilding since the native-certs is not yet on npm how could we use the library? I've tried to download the project and run the build command with cargo, but I'm not sure what I should do with the files on the target folder. Can I get some help with this please? A lib like that would be helpful for what I'm trying to achieve

@chriskilding
Copy link
Author

Hi @diogoperes, if you want to do this on your laptop this would be called a local module install. This uses the npm link command.

More here: https://docs.npmjs.com/cli/v9/commands/npm-link

@github-actions
Copy link
Contributor

github-actions bot commented Sep 3, 2023

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.

@github-actions github-actions bot added the stale label Sep 3, 2023
@samskiter
Copy link

I think this should be kept open - it looks like there has been some progress toward something that may work...

As mentioned, use expectation would be that node works like curl - if you can curl the file you should be able to use npm to install it...

@bnoordhuis
Copy link
Member

No one stepped up to do the leg work and "be like curl" is too generic to be actionable. It doesn't seem like this feature request is going anywhere and it's best to let it die off in that case.

@bnoordhuis
Copy link
Member

bnoordhuis commented Sep 27, 2023

Since there's been no follow-up and no new pull requests (edit: as far as I can see), I'll take the liberty of closing this.

@bnoordhuis bnoordhuis closed this as not planned Won't fix, can't repro, duplicate, stale Sep 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. macos Issues and PRs related to the macOS platform / OSX. tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

No branches or pull requests

8 participants