tunnelfetch 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +617 -0
  3. package/README.zh-CN.md +470 -0
  4. package/package.json +74 -0
  5. package/src/client/cookies.js +429 -0
  6. package/src/client/decode.js +346 -0
  7. package/src/client/redirect.js +249 -0
  8. package/src/client.js +704 -0
  9. package/src/errors.js +181 -0
  10. package/src/http1/chunked.js +289 -0
  11. package/src/http1/index.js +10 -0
  12. package/src/http1/request.js +143 -0
  13. package/src/http1/response.js +493 -0
  14. package/src/http2/connection.js +1170 -0
  15. package/src/http2/constants.js +129 -0
  16. package/src/http2/frames.js +291 -0
  17. package/src/http2/hpack.js +420 -0
  18. package/src/http2/huffman.js +203 -0
  19. package/src/http2/index.js +21 -0
  20. package/src/index.js +46 -0
  21. package/src/pool.js +256 -0
  22. package/src/proxy/direct.js +62 -0
  23. package/src/proxy/http-connect.js +206 -0
  24. package/src/proxy/index.js +197 -0
  25. package/src/proxy/socks5.js +344 -0
  26. package/src/tls/aead.js +263 -0
  27. package/src/tls/connect.js +407 -0
  28. package/src/tls/constants.js +334 -0
  29. package/src/tls/extensions.js +376 -0
  30. package/src/tls/handshake-messages.js +901 -0
  31. package/src/tls/handshake.js +568 -0
  32. package/src/tls/handshake12.js +507 -0
  33. package/src/tls/index.js +44 -0
  34. package/src/tls/keyschedule.js +473 -0
  35. package/src/tls/record.js +872 -0
  36. package/src/tls/tickets.js +145 -0
  37. package/src/tls/transcript.js +101 -0
  38. package/src/tls/wire.js +224 -0
  39. package/src/transport.js +296 -0
  40. package/src/trust/der.js +551 -0
  41. package/src/trust/index.js +375 -0
  42. package/src/trust/name.js +235 -0
  43. package/src/trust/ocsp.js +759 -0
  44. package/src/trust/path.js +595 -0
  45. package/src/trust/roots.js +454 -0
  46. package/src/trust/x509.js +902 -0
  47. package/src/util/bytes.js +470 -0
  48. package/src/util/deadline.js +266 -0
  49. package/src/warmup-fixture.js +85 -0
  50. package/src/warmup.js +243 -0
  51. package/types/client/cookies.d.ts +159 -0
  52. package/types/client/decode.d.ts +54 -0
  53. package/types/client/redirect.d.ts +96 -0
  54. package/types/client.d.ts +323 -0
  55. package/types/errors.d.ts +141 -0
  56. package/types/http1/chunked.d.ts +48 -0
  57. package/types/http1/index.d.ts +3 -0
  58. package/types/http1/request.d.ts +44 -0
  59. package/types/http1/response.d.ts +183 -0
  60. package/types/http2/connection.d.ts +282 -0
  61. package/types/http2/constants.d.ts +95 -0
  62. package/types/http2/frames.d.ts +116 -0
  63. package/types/http2/hpack.d.ts +99 -0
  64. package/types/http2/huffman.d.ts +21 -0
  65. package/types/http2/index.d.ts +5 -0
  66. package/types/index.d.ts +17 -0
  67. package/types/pool.d.ts +135 -0
  68. package/types/proxy/direct.d.ts +26 -0
  69. package/types/proxy/http-connect.d.ts +37 -0
  70. package/types/proxy/index.d.ts +62 -0
  71. package/types/proxy/socks5.d.ts +47 -0
  72. package/types/tls/aead.d.ts +67 -0
  73. package/types/tls/connect.d.ts +280 -0
  74. package/types/tls/constants.d.ts +275 -0
  75. package/types/tls/extensions.d.ts +195 -0
  76. package/types/tls/handshake-messages.d.ts +430 -0
  77. package/types/tls/handshake.d.ts +90 -0
  78. package/types/tls/handshake12.d.ts +35 -0
  79. package/types/tls/index.d.ts +9 -0
  80. package/types/tls/keyschedule.d.ts +272 -0
  81. package/types/tls/record.d.ts +361 -0
  82. package/types/tls/tickets.d.ts +66 -0
  83. package/types/tls/transcript.d.ts +52 -0
  84. package/types/tls/wire.d.ts +106 -0
  85. package/types/transport.d.ts +222 -0
  86. package/types/trust/der.d.ts +239 -0
  87. package/types/trust/index.d.ts +194 -0
  88. package/types/trust/name.d.ts +33 -0
  89. package/types/trust/ocsp.d.ts +138 -0
  90. package/types/trust/path.d.ts +139 -0
  91. package/types/trust/roots.d.ts +36 -0
  92. package/types/trust/x509.d.ts +401 -0
  93. package/types/util/bytes.d.ts +183 -0
  94. package/types/util/deadline.d.ts +133 -0
  95. package/types/warmup-fixture.d.ts +11 -0
  96. package/types/warmup.d.ts +45 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * A trust anchor as supplied by a caller: PEM text or raw DER.
3
+ * @typedef {string | Uint8Array} AnchorInput
4
+ */
5
+ /**
6
+ * Revocation policy, for the modes that validate chains. Checking is via stapled OCSP only, so
7
+ * the knob decides what a MISSING staple means: `'staple'` (the default) tolerates absence but
8
+ * fully verifies any staple that is present; `'require-staple'` makes absence OCSP_REQUIRED.
9
+ * A verified `revoked` or `unknown` verdict is fatal under both — no value ignores it.
10
+ * @typedef {'staple' | 'require-staple'} RevocationPolicy
11
+ */
12
+ /**
13
+ * Verify against the bundled CCADB root store. The default.
14
+ * @typedef {{ mode?: 'system', revocation?: RevocationPolicy }} SystemTrust
15
+ */
16
+ /**
17
+ * Verify against exactly these anchors and nothing else. The bundled store is not consulted.
18
+ * @typedef {{ mode: 'anchors', anchors: AnchorInput[],
19
+ * revocation?: RevocationPolicy }} AnchorsTrust
20
+ */
21
+ /**
22
+ * Full path validation, plus a requirement that some certificate in the accepted path (or its
23
+ * anchor) match one of `pins`. Pins are `sha256/` followed by the base64 SHA-256 of a
24
+ * SubjectPublicKeyInfo, the same spelling HPKP used.
25
+ * @typedef {{ mode: 'pinned', pins: string[], anchors?: AnchorInput[],
26
+ * revocation?: RevocationPolicy }} PinnedTrust
27
+ */
28
+ /**
29
+ * No path validation at all. `insecureAcceptAnyCertificate` is mandatory and must be `true`, so
30
+ * that this mode can never be reached by a typo in `mode`. Supplying `pins` turns it into
31
+ * pin-only trust: no chain is built, but a pin must still match. `revocation` is refused here:
32
+ * without a validated issuer there is no trusted key to verify a staple against, so the check
33
+ * cannot be performed honestly and pretending otherwise would be worse.
34
+ * @typedef {{ mode: 'none', insecureAcceptAnyCertificate: true, pins?: string[] }} NoTrust
35
+ */
36
+ /**
37
+ * Caller-supplied policy. Returning normally accepts the chain; throwing rejects it. The third
38
+ * argument carries the peer's stapled OCSP response (DER, or null) so a custom policy can judge
39
+ * revocation itself — `verifyOcspStaple` is exported for exactly that.
40
+ * @typedef {{ mode: 'custom',
41
+ * verify: (chain: ParsedCertificate[], hostname: string,
42
+ * details?: { ocspResponse: Uint8Array | null })
43
+ * => void | Promise<void> }} CustomTrust
44
+ */
45
+ /**
46
+ * The `verify=` knob, in httpx's spirit. Written as a discriminated union so that a TypeScript
47
+ * caller cannot ask for pinning without pins, or reach `mode: 'none'` without spelling out the
48
+ * flag that says they meant it — both of which are otherwise runtime errors discovered in
49
+ * production rather than compile errors discovered while typing.
50
+ * @typedef {SystemTrust | AnchorsTrust | PinnedTrust | NoTrust | CustomTrust} TrustConfig
51
+ */
52
+ /**
53
+ * A parsed certificate, as returned by `parseCertificate`. Only the members other layers rely on
54
+ * are named here; the object carries the full parse.
55
+ * @typedef {object} ParsedCertificate
56
+ * @property {Uint8Array} der the original bytes, never re-encoded
57
+ * @property {Uint8Array} tbsBytes exact TBSCertificate slice the signature covers
58
+ * @property {{ spkiDer: Uint8Array, algorithmOid: string, keyBytes: Uint8Array }} spki
59
+ * @property {{ text: string }} subject
60
+ * @property {{ text: string }} issuer
61
+ * @property {number} notBefore epoch ms
62
+ * @property {number} notAfter epoch ms
63
+ * @property {{ dns: string[], ip: Uint8Array[], uri: string[], email: string[] }} subjectAltNames
64
+ */
65
+ /**
66
+ * Verify a TLS-delivered certificate chain for `hostname`.
67
+ *
68
+ * @param {object} opts
69
+ * @param {Uint8Array[]} opts.chain DER certificates, leaf first, as the peer sent them
70
+ * @param {string} opts.hostname identity from the request URL (DNS name or IP literal)
71
+ * @param {TrustConfig} [opts.trust] the verification policy; defaults to the bundled roots
72
+ * @param {number} [opts.now] epoch ms, for tests and for callers with a better clock
73
+ * @param {Uint8Array | null} [opts.ocspResponse] the peer's stapled DER OCSPResponse, when the
74
+ * handshake carried one; judged under `trust.revocation` (see the policy comment above)
75
+ * @returns {Promise<ParsedCertificate>} the parsed leaf. Every other outcome throws.
76
+ */
77
+ export function verifyChain({ chain, hostname, trust, now, ocspResponse, }: {
78
+ chain: Uint8Array[];
79
+ hostname: string;
80
+ trust?: TrustConfig | undefined;
81
+ now?: number | undefined;
82
+ ocspResponse?: Uint8Array<ArrayBufferLike> | null | undefined;
83
+ }): Promise<ParsedCertificate>;
84
+ export { matchesIdentity } from "./name.js";
85
+ /**
86
+ * A trust anchor as supplied by a caller: PEM text or raw DER.
87
+ */
88
+ export type AnchorInput = string | Uint8Array;
89
+ /**
90
+ * Revocation policy, for the modes that validate chains. Checking is via stapled OCSP only, so
91
+ * the knob decides what a MISSING staple means: `'staple'` (the default) tolerates absence but
92
+ * fully verifies any staple that is present; `'require-staple'` makes absence OCSP_REQUIRED.
93
+ * A verified `revoked` or `unknown` verdict is fatal under both — no value ignores it.
94
+ */
95
+ export type RevocationPolicy = "staple" | "require-staple";
96
+ /**
97
+ * Verify against the bundled CCADB root store. The default.
98
+ */
99
+ export type SystemTrust = {
100
+ mode?: "system";
101
+ revocation?: RevocationPolicy;
102
+ };
103
+ /**
104
+ * Verify against exactly these anchors and nothing else. The bundled store is not consulted.
105
+ */
106
+ export type AnchorsTrust = {
107
+ mode: "anchors";
108
+ anchors: AnchorInput[];
109
+ revocation?: RevocationPolicy;
110
+ };
111
+ /**
112
+ * Full path validation, plus a requirement that some certificate in the accepted path (or its
113
+ * anchor) match one of `pins`. Pins are `sha256/` followed by the base64 SHA-256 of a
114
+ * SubjectPublicKeyInfo, the same spelling HPKP used.
115
+ */
116
+ export type PinnedTrust = {
117
+ mode: "pinned";
118
+ pins: string[];
119
+ anchors?: AnchorInput[];
120
+ revocation?: RevocationPolicy;
121
+ };
122
+ /**
123
+ * No path validation at all. `insecureAcceptAnyCertificate` is mandatory and must be `true`, so
124
+ * that this mode can never be reached by a typo in `mode`. Supplying `pins` turns it into
125
+ * pin-only trust: no chain is built, but a pin must still match. `revocation` is refused here:
126
+ * without a validated issuer there is no trusted key to verify a staple against, so the check
127
+ * cannot be performed honestly and pretending otherwise would be worse.
128
+ */
129
+ export type NoTrust = {
130
+ mode: "none";
131
+ insecureAcceptAnyCertificate: true;
132
+ pins?: string[];
133
+ };
134
+ /**
135
+ * Caller-supplied policy. Returning normally accepts the chain; throwing rejects it. The third
136
+ * argument carries the peer's stapled OCSP response (DER, or null) so a custom policy can judge
137
+ * revocation itself — `verifyOcspStaple` is exported for exactly that.
138
+ */
139
+ export type CustomTrust = {
140
+ mode: "custom";
141
+ verify: (chain: ParsedCertificate[], hostname: string, details?: {
142
+ ocspResponse: Uint8Array | null;
143
+ }) => void | Promise<void>;
144
+ };
145
+ /**
146
+ * The `verify=` knob, in httpx's spirit. Written as a discriminated union so that a TypeScript
147
+ * caller cannot ask for pinning without pins, or reach `mode: 'none'` without spelling out the
148
+ * flag that says they meant it — both of which are otherwise runtime errors discovered in
149
+ * production rather than compile errors discovered while typing.
150
+ */
151
+ export type TrustConfig = SystemTrust | AnchorsTrust | PinnedTrust | NoTrust | CustomTrust;
152
+ /**
153
+ * A parsed certificate, as returned by `parseCertificate`. Only the members other layers rely on
154
+ * are named here; the object carries the full parse.
155
+ */
156
+ export type ParsedCertificate = {
157
+ /**
158
+ * the original bytes, never re-encoded
159
+ */
160
+ der: Uint8Array;
161
+ /**
162
+ * exact TBSCertificate slice the signature covers
163
+ */
164
+ tbsBytes: Uint8Array;
165
+ spki: {
166
+ spkiDer: Uint8Array;
167
+ algorithmOid: string;
168
+ keyBytes: Uint8Array;
169
+ };
170
+ subject: {
171
+ text: string;
172
+ };
173
+ issuer: {
174
+ text: string;
175
+ };
176
+ /**
177
+ * epoch ms
178
+ */
179
+ notBefore: number;
180
+ /**
181
+ * epoch ms
182
+ */
183
+ notAfter: number;
184
+ subjectAltNames: {
185
+ dns: string[];
186
+ ip: Uint8Array[];
187
+ uri: string[];
188
+ email: string[];
189
+ };
190
+ };
191
+ export { parseCertificate, decodePem } from "./x509.js";
192
+ export { validatePath, anchorFromCertificate } from "./path.js";
193
+ export { verifyOcspStaple, parseOcspResponse } from "./ocsp.js";
194
+ export { systemAnchors, provenance as rootStoreProvenance } from "./roots.js";
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Parse an IP literal (v4 dotted-quad or v6, optionally [bracketed]) to raw bytes, else null.
3
+ * @param {string} text
4
+ * @returns {Uint8Array | null}
5
+ */
6
+ export function parseIp(text: string): Uint8Array | null;
7
+ /**
8
+ * Verify that `cert` is a certificate for `hostname`. Returns nothing; every non-match throws
9
+ * CERT_NAME_MISMATCH with the entries that were considered, so one log line shows exactly how
10
+ * close the certificate was.
11
+ *
12
+ * @param {import('./x509.js').Certificate} cert
13
+ * @param {string} hostname DNS name (A-label form) or IP literal, per the request URL
14
+ * @returns {void}
15
+ */
16
+ export function matchesIdentity(cert: import("./x509.js").Certificate, hostname: string): void;
17
+ /**
18
+ * RFC 5280 s4.2.1.10 dNSName subtree: a constraint "example.com" covers the host itself and any
19
+ * subdomain, at a label boundary. The seen-in-the-wild ".example.com" form covers subdomains
20
+ * only. An empty constraint covers every DNS name (used by permittedSubtrees to say "any DNS").
21
+ * @param {string} name
22
+ * @param {string} base
23
+ * @returns {boolean}
24
+ */
25
+ export function dnsWithinSubtree(name: string, base: string): boolean;
26
+ /**
27
+ * iPAddress subtree: same family, and (address & mask) equal on every byte.
28
+ * @param {Uint8Array} ip
29
+ * @param {Uint8Array} addr
30
+ * @param {Uint8Array} mask
31
+ * @returns {boolean}
32
+ */
33
+ export function ipWithinSubtree(ip: Uint8Array, addr: Uint8Array, mask: Uint8Array): boolean;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Parse a DER OCSPResponse (RFC 6960 s4.2.1) into a fully-walked structure.
3
+ *
4
+ * A parser, not a judge, exactly like parseCertificate: it throws OCSP_PARSE on malformed or
5
+ * self-contradictory bytes and on constructs this package refuses to interpret (unknown
6
+ * responseType, unrecognized critical extensions); whether the parsed response is TRUE is
7
+ * verifyOcspStaple's problem.
8
+ *
9
+ * @param {Uint8Array} der
10
+ * @returns {OcspResponse}
11
+ */
12
+ export function parseOcspResponse(der: Uint8Array): OcspResponse;
13
+ /**
14
+ * Verify a stapled OCSP response against the certificate it must vouch for.
15
+ *
16
+ * Every check the module comment promises happens here, in this order: parse, match the CertID
17
+ * to `leaf`/`issuer`, establish the signer (the CA itself or an RFC 6960 s4.2.2.2 delegated
18
+ * responder), verify the signature over the original tbsResponseData bytes, and only then read
19
+ * the verdict and its freshness window. `revoked` and `unknown` always throw; `good` throws
20
+ * unless the window covers `now`.
21
+ *
22
+ * @param {object} args
23
+ * @param {Uint8Array} args.staple DER OCSPResponse, exactly as the peer stapled it
24
+ * @param {import('./x509.js').Certificate} args.leaf the validated leaf the staple must cover
25
+ * @param {OcspIssuer} args.issuer the leaf's issuer, from the validated path
26
+ * @param {number} args.now epoch ms, injected — never a wall clock read here
27
+ * @returns {Promise<OcspVerdict>} every failure throws a typed CertificateError (OCSP_* codes)
28
+ */
29
+ export function verifyOcspStaple({ staple, leaf, issuer, now }: {
30
+ staple: Uint8Array;
31
+ leaf: import("./x509.js").Certificate;
32
+ issuer: OcspIssuer;
33
+ now: number;
34
+ }): Promise<OcspVerdict>;
35
+ /**
36
+ * CertID (RFC 6960 s4.1.1): which certificate a SingleResponse is talking about.
37
+ */
38
+ export type OcspCertId = {
39
+ hashOid: string;
40
+ issuerNameHash: Uint8Array;
41
+ issuerKeyHash: Uint8Array;
42
+ /**
43
+ * INTEGER content bytes, minimal DER
44
+ */
45
+ serialBytes: Uint8Array;
46
+ };
47
+ /**
48
+ * One SingleResponse, parsed. Times are epoch ms.
49
+ */
50
+ export type OcspSingleResponse = {
51
+ certId: OcspCertId;
52
+ status: {
53
+ kind: "good";
54
+ } | {
55
+ kind: "unknown";
56
+ } | {
57
+ kind: "revoked";
58
+ revocationTime: number;
59
+ reason: number | null;
60
+ };
61
+ thisUpdate: number;
62
+ nextUpdate: number | null;
63
+ };
64
+ /**
65
+ * A parsed BasicOCSPResponse. `tbsBytes` is the exact original ResponseData element — the bytes
66
+ * the signature covers, never re-encoded.
67
+ */
68
+ export type OcspBasicResponse = {
69
+ tbsBytes: Uint8Array;
70
+ signatureAlgorithm: import("./x509.js").AlgorithmId;
71
+ signature: Uint8Array;
72
+ responderId: {
73
+ kind: "name";
74
+ nameBytes: Uint8Array;
75
+ } | {
76
+ kind: "key";
77
+ keyHash: Uint8Array;
78
+ };
79
+ /**
80
+ * epoch ms
81
+ */
82
+ producedAt: number;
83
+ singles: OcspSingleResponse[];
84
+ /**
85
+ * attached responder certificates, parsed
86
+ */
87
+ certs: import("./x509.js").Certificate[];
88
+ };
89
+ export type OcspResponse = {
90
+ responseStatus: number;
91
+ responseStatusName: string;
92
+ /**
93
+ * null exactly when responseStatus != successful
94
+ */
95
+ basic: OcspBasicResponse | null;
96
+ };
97
+ /**
98
+ * The issuer of the certificate under check, reduced to what OCSP verification needs. Built by
99
+ * the caller from the VALIDATED path — the certificate that actually signed the leaf, or the
100
+ * trust anchor when the leaf sits directly under one — never from the unverified wire chain.
101
+ */
102
+ export type OcspIssuer = {
103
+ /**
104
+ * exact subject Name DER
105
+ */
106
+ subjectBytes: Uint8Array;
107
+ /**
108
+ * SubjectPublicKeyInfo DER
109
+ */
110
+ spkiDer: Uint8Array;
111
+ /**
112
+ * for error messages
113
+ */
114
+ subjectText: string;
115
+ };
116
+ /**
117
+ * What a verified `good` staple reports. Every other outcome throws; there is no boolean.
118
+ */
119
+ export type OcspVerdict = {
120
+ status: "good";
121
+ /**
122
+ * epoch ms
123
+ */
124
+ producedAt: number;
125
+ /**
126
+ * epoch ms
127
+ */
128
+ thisUpdate: number;
129
+ /**
130
+ * epoch ms
131
+ */
132
+ nextUpdate: number | null;
133
+ /**
134
+ * whether a delegated responder certificate signed, rather than
135
+ * the CA key itself
136
+ */
137
+ delegated: boolean;
138
+ };
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The RFC 5280 s6.1.1 trust-anchor triple, normalised. Validity bounds are recorded but never
3
+ * enforced — see the module comment for why expiring a root is store policy, not path policy.
4
+ * @typedef {object} TrustAnchor
5
+ * @property {Uint8Array} subjectBytes exact subject DN DER
6
+ * @property {string} subjectText
7
+ * @property {Uint8Array} spkiDer
8
+ * @property {Uint8Array | null} subjectKeyIdentifier
9
+ * @property {import('./x509.js').NameConstraints | null} nameConstraints
10
+ * @property {number | null} notBefore
11
+ * @property {number | null} notAfter
12
+ */
13
+ /**
14
+ * Anything normalizeAnchor accepts: DER, a parsed certificate, or an anchor-shaped record.
15
+ * The record form also admits `nameConstraintsBytes` (raw extnValue), which is how the bundled
16
+ * store defers parsing to the one anchor a handshake actually lands on.
17
+ * @typedef {object} AnchorRecord
18
+ * @property {Uint8Array} subjectBytes
19
+ * @property {Uint8Array} spkiDer
20
+ * @property {string} [subjectText]
21
+ * @property {Uint8Array | null} [subjectKeyIdentifier]
22
+ * @property {import('./x509.js').NameConstraints | null} [nameConstraints]
23
+ * @property {Uint8Array | null} [nameConstraintsBytes]
24
+ * @property {number | null} [notBefore]
25
+ * @property {number | null} [notAfter]
26
+ */
27
+ /** @typedef {Uint8Array | import('./x509.js').Certificate | AnchorRecord} AnchorLike */
28
+ /**
29
+ * An indexed anchor lookup: everything path building needs from a root store. The bundled
30
+ * store implements it with a subject-hash index so a handshake touches one anchor, not all.
31
+ * @typedef {{ forIssuer: (subjectDn: Uint8Array) => AnchorLike[] | Promise<AnchorLike[]> }}
32
+ * AnchorSource
33
+ */
34
+ /**
35
+ * Strip a parsed certificate down to the RFC 5280 s6.1.1 trust-anchor triple. Used for the
36
+ * `mode:'anchors'` knob and by the root-store generator, so both feed path validation through
37
+ * the identical shape.
38
+ * @param {import('./x509.js').Certificate} cert
39
+ * @returns {TrustAnchor}
40
+ */
41
+ export function anchorFromCertificate(cert: import("./x509.js").Certificate): TrustAnchor;
42
+ /**
43
+ * Verify `cert`'s signature over its original to-be-signed bytes with the signer's public key.
44
+ *
45
+ * The scheme comes from resolveSignatureScheme (which is where MD5/SHA-1 die, before any
46
+ * cryptography runs). For ECDSA the curve belongs to the issuer's key, not the OID, so the
47
+ * WebCrypto import parameters are chosen from the issuer's SPKI and only the hash from the OID —
48
+ * both looked up in SIG_SCHEME_PARAMS rather than re-declared here.
49
+ *
50
+ * Exported (as verifySignedObject) for the OCSP checker: a BasicOCSPResponse is signed exactly
51
+ * like a certificate — an AlgorithmIdentifier, a BIT STRING over the original DER of a TBS
52
+ * element — and two implementations of "check an X.509-style signature" is two chances for one
53
+ * of them to be subtly the weaker. `cert` is therefore the structural subset both callers can
54
+ * supply: `{ tbsBytes, signature, signatureAlgorithm, subject: { text } }`, which a parsed
55
+ * Certificate satisfies as-is and the OCSP checker fakes up from response fields.
56
+ *
57
+ * @param {{ tbsBytes: Uint8Array, signature: Uint8Array,
58
+ * signatureAlgorithm: import('./x509.js').AlgorithmId,
59
+ * subject: { text: string } }} cert what was signed, certificate-shaped
60
+ * @param {Uint8Array} issuerSpkiDer the signer's SubjectPublicKeyInfo, DER
61
+ * @param {string} issuerText the signer's name, for error messages
62
+ * @returns {Promise<void>} every failure throws a typed CertificateError
63
+ */
64
+ export function verifySignedObject(cert: {
65
+ tbsBytes: Uint8Array;
66
+ signature: Uint8Array;
67
+ signatureAlgorithm: import("./x509.js").AlgorithmId;
68
+ subject: {
69
+ text: string;
70
+ };
71
+ }, issuerSpkiDer: Uint8Array, issuerText: string): Promise<void>;
72
+ /**
73
+ * Build and validate a certification path. Every failure throws a typed CertificateError;
74
+ * there is no boolean to forget to check.
75
+ *
76
+ * @param {object} opts
77
+ * @param {Array<Uint8Array | import('./x509.js').Certificate>} opts.chain DER (or
78
+ * already-parsed) certificates, leaf first, in whatever order and with whatever extras the
79
+ * server chose to send
80
+ * @param {AnchorLike[] | AnchorSource} opts.anchors trust anchors, or an indexed anchor source
81
+ * @param {string | null} [opts.hostname] identity to require of the leaf; omit to skip
82
+ * (index.js never omits)
83
+ * @param {number} [opts.now] epoch ms
84
+ * @param {number} [opts.maxPathLength] hard cap on path certificates — this runs on a metered
85
+ * runtime and a pathological chain must cost O(cap), not O(chain²)
86
+ * @returns {Promise<{ leaf: import('./x509.js').Certificate,
87
+ * path: import('./x509.js').Certificate[], anchor: TrustAnchor }>} parsed leaf, the
88
+ * validated path (leaf first), and the anchor that terminated it
89
+ */
90
+ export function validatePath({ chain, anchors, hostname, now, maxPathLength }: {
91
+ chain: Array<Uint8Array | import("./x509.js").Certificate>;
92
+ anchors: AnchorLike[] | AnchorSource;
93
+ hostname?: string | null | undefined;
94
+ now?: number | undefined;
95
+ maxPathLength?: number | undefined;
96
+ }): Promise<{
97
+ leaf: import("./x509.js").Certificate;
98
+ path: import("./x509.js").Certificate[];
99
+ anchor: TrustAnchor;
100
+ }>;
101
+ /**
102
+ * The RFC 5280 s6.1.1 trust-anchor triple, normalised. Validity bounds are recorded but never
103
+ * enforced — see the module comment for why expiring a root is store policy, not path policy.
104
+ */
105
+ export type TrustAnchor = {
106
+ /**
107
+ * exact subject DN DER
108
+ */
109
+ subjectBytes: Uint8Array;
110
+ subjectText: string;
111
+ spkiDer: Uint8Array;
112
+ subjectKeyIdentifier: Uint8Array | null;
113
+ nameConstraints: import("./x509.js").NameConstraints | null;
114
+ notBefore: number | null;
115
+ notAfter: number | null;
116
+ };
117
+ /**
118
+ * Anything normalizeAnchor accepts: DER, a parsed certificate, or an anchor-shaped record.
119
+ * The record form also admits `nameConstraintsBytes` (raw extnValue), which is how the bundled
120
+ * store defers parsing to the one anchor a handshake actually lands on.
121
+ */
122
+ export type AnchorRecord = {
123
+ subjectBytes: Uint8Array;
124
+ spkiDer: Uint8Array;
125
+ subjectText?: string | undefined;
126
+ subjectKeyIdentifier?: Uint8Array<ArrayBufferLike> | null | undefined;
127
+ nameConstraints?: import("./x509.js").NameConstraints | null | undefined;
128
+ nameConstraintsBytes?: Uint8Array<ArrayBufferLike> | null | undefined;
129
+ notBefore?: number | null | undefined;
130
+ notAfter?: number | null | undefined;
131
+ };
132
+ export type AnchorLike = Uint8Array | import("./x509.js").Certificate | AnchorRecord;
133
+ /**
134
+ * An indexed anchor lookup: everything path building needs from a root store. The bundled
135
+ * store implements it with a subject-hash index so a handshake touches one anchor, not all.
136
+ */
137
+ export type AnchorSource = {
138
+ forIssuer: (subjectDn: Uint8Array) => AnchorLike[] | Promise<AnchorLike[]>;
139
+ };
@@ -0,0 +1,36 @@
1
+ /** Where these anchors came from. */
2
+ export const provenance: Readonly<{
3
+ source: "ccadb:IncludedRootsPEMTxt?TrustBitsInclude=Websites";
4
+ retrievedAt: "2026-07-30";
5
+ upstreamSha256: "1813222850e0d3efb875b2978e61acbcb5fcdce93d5c4358443050e9659394bd";
6
+ anchorCount: 121;
7
+ }>;
8
+ export namespace systemAnchors {
9
+ /**
10
+ * @param {Uint8Array} dnBytes exact subject DN DER of the issuer being resolved
11
+ * @returns {Promise<StoredAnchor[]>}
12
+ */
13
+ function forIssuer(dnBytes: Uint8Array): Promise<StoredAnchor[]>;
14
+ }
15
+ export type PackedAnchor = {
16
+ name: string;
17
+ s: string;
18
+ spki: string;
19
+ ski: string | null;
20
+ nc: string | null;
21
+ nb: number;
22
+ na: number;
23
+ };
24
+ /**
25
+ * An unpacked anchor record, shaped for path validation's normalizeAnchor: name constraints
26
+ * stay raw (`nameConstraintsBytes`) so only the anchor a handshake lands on pays for parsing.
27
+ */
28
+ export type StoredAnchor = {
29
+ subjectText: string;
30
+ subjectBytes: Uint8Array;
31
+ spkiDer: Uint8Array;
32
+ subjectKeyIdentifier: Uint8Array | null;
33
+ nameConstraintsBytes: Uint8Array | null;
34
+ notBefore: number;
35
+ notAfter: number;
36
+ };