Skip to content

Commit

Permalink
Trust CA root certificates on Windows and NODE_EXTRA_CA_CERTS (#587)
Browse files Browse the repository at this point in the history
* Use Node's root certificates on Windows

`workerd`'s `trustBrowserCas` uses `SSL_CTX_set_default_verify_paths()`
to enable the system trust store. Unfortunately, this doesn't work on
Windows, meaning any HTTPS `fetch()` would fail, with an
`unable to get local issuer certificate` error.

This change passes the root certificates from Node's bundled CA store
to `workerd` as `trustedCertificates` on Windows.

Closes #3264

* Read extra trusted certificates from `NODE_EXTRA_CA_CERTS`

Wrangler passes the Cloudflare root certificate using the
`NODE_EXTRA_CA_CERTS` environment variable. This change loads CA
certs from this variable, fixing HTTPS `fetch()`s with WARP enabled.
This can also be used for trusting self-signed certificates.

Closes #3218
  • Loading branch information
mrbbot committed Nov 1, 2023
1 parent 2a5fa19 commit 74c8b85
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
29 changes: 26 additions & 3 deletions packages/miniflare/src/plugins/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import assert from "assert";
import { readFileSync } from "fs";
import fs from "fs/promises";
import tls from "tls";
import { TextEncoder } from "util";
import { bold } from "kleur/colors";
import SCRIPT_ENTRY from "worker:core/entry";
Expand Down Expand Up @@ -44,6 +45,25 @@ import {
} from "./modules";
import { ServiceDesignatorSchema } from "./services";

// `workerd`'s `trustBrowserCas` should probably be named `trustSystemCas`.
// Rather than using a bundled CA store like Node, it uses
// `SSL_CTX_set_default_verify_paths()` to use the system CA store:
// https://github.com/capnproto/capnproto/blob/6e26d260d1d91e0465ca12bbb5230a1dfa28f00d/c%2B%2B/src/kj/compat/tls.c%2B%2B#L745
// Unfortunately, this doesn't work on Windows. Luckily, Node exposes its own
// bundled CA store's certificates, so we just use those.
const trustedCertificates =
process.platform === "win32" ? Array.from(tls.rootCertificates) : [];
if (process.env.NODE_EXTRA_CA_CERTS !== undefined) {
// Try load extra CA certs if defined, ignoring errors. Node will log a
// warning if it fails to load this anyway. Note, this we only load this once
// at process startup to match Node's behaviour:
// https://nodejs.org/api/cli.html#node_extra_ca_certsfile
try {
const extra = readFileSync(process.env.NODE_EXTRA_CA_CERTS, "utf8");
trustedCertificates.push(extra);
} catch {}
}

const encoder = new TextEncoder();
const numericCompare = new Intl.Collator(undefined, { numeric: true }).compare;

Expand Down Expand Up @@ -360,14 +380,17 @@ export function getGlobalServices({
bindings: serviceEntryBindings,
},
},
// Allow access to private/public addresses:
// https://github.com/cloudflare/miniflare/issues/412
{
name: "internet",
network: {
// Allow access to private/public addresses:
// https://github.com/cloudflare/miniflare/issues/412
allow: ["public", "private"],
deny: [],
tlsOptions: { trustBrowserCas: true },
tlsOptions: {
trustBrowserCas: true,
trustedCertificates,
},
},
},
];
Expand Down
13 changes: 13 additions & 0 deletions packages/miniflare/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,16 @@ test("Miniflare: modules in sub-directories", async (t) => {
const res = await mf.dispatchFetch("http://localhost");
t.is(await res.text(), "123");
});

test("Miniflare: HTTPS fetches using browser CA certificates", async (t) => {
const mf = new Miniflare({
modules: true,
script: `export default {
fetch() {
return fetch("https://workers.cloudflare.com/cf.json");
}
}`,
});
const res = await mf.dispatchFetch("http://localhost");
t.true(res.ok);
});

0 comments on commit 74c8b85

Please sign in to comment.