Files
scriptc/tests/fixtures/server/cases/https-ca-default/main.ts
Chris Tate 27e7537cec Crypto introspection, the TLS CA store, and the http2/rejection tail
- The crypto introspection statics (getFips and the cipher/hash/curve name lists) bake at the call site, and the crypto constant table joins http2's under a generalized per-module baked-constants lowering.
- The CA-store introspection surface lands in its own unit (scr_tls_ca.c) behind its own link gate, so a getCACertificates-only binary never pulls mbedTLS: getCACertificates, rootCertificates, setDefaultCACertificates.
- http2.createSecureServer grows the eager request handler and the runtime options record, riding the same server-options walk as tls.createServer; string-typed 'data' listeners decode.
- process once/off for 'unhandledRejection' plus the sibling 'rejectionHandled' registry, removal by closure identity per the warning-registry stance.
- Merge resolution unions this lane with main's fs ladders, createRequire erasure, and dyn secure-context work; the runtime's retired "DOM" nickname is spelled "dyn" throughout.
2026-07-24 19:49:54 -05:00

90 lines
2.9 KiB
TypeScript

/* setDefaultCACertificates is LIVE trust: the client never passes a `ca`
* option — the DEFAULT anchors decide. With the local CA installed via
* setDefaultCACertificates the request verifies; with the empty set it
* fails exactly like the leaf-only no-ca shape ("unable to verify the
* first certificate"); getCACertificates('default') reflects each state.
* The https-client-basic pattern: this program is only a client, the
* driver is a real node:https server with the fixture leaf. */
import { readFileSync } from "node:fs";
import { createServer } from "node:net";
import { request } from "node:https";
import { getCACertificates, setDefaultCACertificates } from "node:tls";
import type { IncomingMessage } from "node:http";
const ca = readFileSync("tests/fixtures/server/certs/ca.pem", "utf8");
let port = 0;
let attempts = 0;
function fetchPath(path: string, insecure: boolean, next: () => void): void {
const req = insecure
? request({ hostname: "localhost", port, path, method: "GET", agent: false, rejectUnauthorized: false }, (res) => onRes(res, path, next))
: request({ hostname: "localhost", port, path, method: "GET", agent: false }, (res) => onRes(res, path, next));
req.on("error", (err) => {
console.log(`${path} error ${err.message}`);
next();
});
req.end();
}
function onRes(res: IncomingMessage, path: string, next: () => void): void {
console.log(`${path} status=${res.statusCode !== undefined ? res.statusCode : -1}`);
let body = "";
res.on("data", (chunk: Buffer) => {
body += chunk.toString("utf8");
});
res.on("end", () => {
console.log(`${path} body=${body}`);
next();
});
}
function run(): void {
// The local CA becomes the WHOLE default store: the leaf verifies.
setDefaultCACertificates([ca]);
console.log("default-size", getCACertificates("default").length);
fetchPath("/text", false, () => {
// Trust nothing: the same request now fails verification.
setDefaultCACertificates([]);
console.log("default-size", getCACertificates("default").length);
fetchPath("/text", false, () => {
// Restore the local CA — trust is per-dial, not per-process-start.
setDefaultCACertificates([ca]);
fetchPath("/text", false, () => {
fetchPath("/quit", true, () => console.log("done"));
});
});
});
}
function start(): void {
attempts++;
const req = request(
{ hostname: "localhost", port, path: "/ready", method: "GET", rejectUnauthorized: false },
(res) => {
res.on("end", () => {
console.log("driver up");
run();
});
res.on("data", () => {});
},
);
req.on("error", () => {
if (attempts < 400) {
setTimeout(start, 25);
} else {
console.log("driver never came up");
}
});
req.end();
}
const probe = createServer();
probe.listen(0, () => {
port = probe.address().port;
probe.close(() => {
process.stderr.write(`PORT ${port}\n`);
start();
});
});