micro509 0.1.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 (115) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +220 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.js +1 -0
  5. package/dist/internal/asn1/asn1.js +2 -0
  6. package/dist/internal/asn1/asn1.js.map +1 -0
  7. package/dist/internal/asn1/der.js +2 -0
  8. package/dist/internal/asn1/der.js.map +1 -0
  9. package/dist/internal/asn1/oids.js +2 -0
  10. package/dist/internal/asn1/oids.js.map +1 -0
  11. package/dist/internal/crypto/algorithm-names.js +2 -0
  12. package/dist/internal/crypto/algorithm-names.js.map +1 -0
  13. package/dist/internal/crypto/ecdsa.js +2 -0
  14. package/dist/internal/crypto/ecdsa.js.map +1 -0
  15. package/dist/internal/crypto/hash.js +2 -0
  16. package/dist/internal/crypto/hash.js.map +1 -0
  17. package/dist/internal/crypto/pbes2.d.ts +23 -0
  18. package/dist/internal/crypto/pbes2.js +2 -0
  19. package/dist/internal/crypto/pbes2.js.map +1 -0
  20. package/dist/internal/crypto/rsa-pss.js +2 -0
  21. package/dist/internal/crypto/rsa-pss.js.map +1 -0
  22. package/dist/internal/crypto/sig-verify.js +2 -0
  23. package/dist/internal/crypto/sig-verify.js.map +1 -0
  24. package/dist/internal/crypto/signing.d.ts +16 -0
  25. package/dist/internal/crypto/signing.js +2 -0
  26. package/dist/internal/crypto/signing.js.map +1 -0
  27. package/dist/internal/crypto/webcrypto.js +2 -0
  28. package/dist/internal/crypto/webcrypto.js.map +1 -0
  29. package/dist/internal/shared/base64.js +2 -0
  30. package/dist/internal/shared/base64.js.map +1 -0
  31. package/dist/internal/shared/dn.js +2 -0
  32. package/dist/internal/shared/dn.js.map +1 -0
  33. package/dist/internal/shared/ip.js +2 -0
  34. package/dist/internal/shared/ip.js.map +1 -0
  35. package/dist/internal/verify/name-constraints-engine.js +2 -0
  36. package/dist/internal/verify/name-constraints-engine.js.map +1 -0
  37. package/dist/internal/verify/policy-engine.js +2 -0
  38. package/dist/internal/verify/policy-engine.js.map +1 -0
  39. package/dist/internal/verify/verify-path.js +2 -0
  40. package/dist/internal/verify/verify-path.js.map +1 -0
  41. package/dist/internal/x509/extension-bits.d.ts +18 -0
  42. package/dist/internal/x509/extension-bits.js +2 -0
  43. package/dist/internal/x509/extension-bits.js.map +1 -0
  44. package/dist/internal/x509/extension-registry.js +2 -0
  45. package/dist/internal/x509/extension-registry.js.map +1 -0
  46. package/dist/internal/x509/name-fields.js +2 -0
  47. package/dist/internal/x509/name-fields.js.map +1 -0
  48. package/dist/keys/keys.d.ts +431 -0
  49. package/dist/keys/keys.js +5 -0
  50. package/dist/keys/keys.js.map +1 -0
  51. package/dist/keys.d.ts +3 -0
  52. package/dist/keys.js +1 -0
  53. package/dist/pem/pem.d.ts +56 -0
  54. package/dist/pem/pem.js +6 -0
  55. package/dist/pem/pem.js.map +1 -0
  56. package/dist/pem.d.ts +2 -0
  57. package/dist/pem.js +1 -0
  58. package/dist/pkcs/pfx.d.ts +177 -0
  59. package/dist/pkcs/pfx.js +2 -0
  60. package/dist/pkcs/pfx.js.map +1 -0
  61. package/dist/pkcs/pkcs12-mac.d.ts +41 -0
  62. package/dist/pkcs/pkcs12-mac.js +2 -0
  63. package/dist/pkcs/pkcs12-mac.js.map +1 -0
  64. package/dist/pkcs/pkcs7.d.ts +131 -0
  65. package/dist/pkcs/pkcs7.js +2 -0
  66. package/dist/pkcs/pkcs7.js.map +1 -0
  67. package/dist/pkcs.d.ts +5 -0
  68. package/dist/pkcs.js +1 -0
  69. package/dist/result/result.d.ts +68 -0
  70. package/dist/result/result.js +2 -0
  71. package/dist/result/result.js.map +1 -0
  72. package/dist/result.d.ts +2 -0
  73. package/dist/result.js +1 -0
  74. package/dist/revocation/chain.d.ts +180 -0
  75. package/dist/revocation/chain.js +2 -0
  76. package/dist/revocation/chain.js.map +1 -0
  77. package/dist/revocation/crl.d.ts +316 -0
  78. package/dist/revocation/crl.js +2 -0
  79. package/dist/revocation/crl.js.map +1 -0
  80. package/dist/revocation/ocsp.d.ts +332 -0
  81. package/dist/revocation/ocsp.js +2 -0
  82. package/dist/revocation/ocsp.js.map +1 -0
  83. package/dist/revocation/revocation.d.ts +168 -0
  84. package/dist/revocation/revocation.js +2 -0
  85. package/dist/revocation/revocation.js.map +1 -0
  86. package/dist/revocation.d.ts +5 -0
  87. package/dist/revocation.js +1 -0
  88. package/dist/verify/identity.d.ts +129 -0
  89. package/dist/verify/identity.js +2 -0
  90. package/dist/verify/identity.js.map +1 -0
  91. package/dist/verify/name-constraints.d.ts +18 -0
  92. package/dist/verify/policy.d.ts +39 -0
  93. package/dist/verify/verify.d.ts +404 -0
  94. package/dist/verify/verify.js +2 -0
  95. package/dist/verify/verify.js.map +1 -0
  96. package/dist/verify.d.ts +5 -0
  97. package/dist/verify.js +1 -0
  98. package/dist/x509/certificate.d.ts +191 -0
  99. package/dist/x509/certificate.js +2 -0
  100. package/dist/x509/certificate.js.map +1 -0
  101. package/dist/x509/csr.d.ts +55 -0
  102. package/dist/x509/csr.js +2 -0
  103. package/dist/x509/csr.js.map +1 -0
  104. package/dist/x509/extensions.d.ts +550 -0
  105. package/dist/x509/extensions.js +2 -0
  106. package/dist/x509/extensions.js.map +1 -0
  107. package/dist/x509/name.d.ts +140 -0
  108. package/dist/x509/name.js +2 -0
  109. package/dist/x509/name.js.map +1 -0
  110. package/dist/x509/parse.d.ts +377 -0
  111. package/dist/x509/parse.js +2 -0
  112. package/dist/x509/parse.js.map +1 -0
  113. package/dist/x509.d.ts +8 -0
  114. package/dist/x509.js +1 -0
  115. package/package.json +153 -0
@@ -0,0 +1,404 @@
1
+ import { ErrorResult, IndexedErrorResult, IndexedMicro509Error, Micro509Error } from "../result/result.js";
2
+ import { ParsedCertificate, ParsedCertificateSigningRequest, ParsedName } from "../x509/parse.js";
3
+ import { CrlSource } from "../revocation/crl.js";
4
+ import { CertificateSource as CertificateSource$1, RevocationPolicy } from "../revocation/chain.js";
5
+ import { DnsServiceIdentityInput, IpServiceIdentityInput, MatchServiceIdentityErrorCode, MatchServiceIdentityEvaluation, MatchServiceIdentityFailure, MatchServiceIdentityFailureDetails, MatchServiceIdentityFailureResult, MatchServiceIdentityInput, MatchServiceIdentityResult, MatchServiceIdentitySuccess, MatchableServiceIdentityInput, ServiceIdentityInput, ServiceIdentityType, SrvServiceIdentityInput, UriServiceIdentityInput, VerifyServiceIdentityInput, matchCertificateServiceIdentity, matchServiceIdentity } from "./identity.js";
6
+ import { InitialNameConstraintsInput } from "./name-constraints.js";
7
+ import { ConstrainedPolicy, PolicyValidationInput, PolicyValidationOutcome } from "./policy.js";
8
+
9
+ //#region src/verify/verify.d.ts
10
+ /** PEM string or DER bytes for a certificate. PEM may contain multiple blocks. */
11
+ type CertificateSource = string | Uint8Array;
12
+ /** PEM string or DER bytes for a certificate signing request. */
13
+ type CsrSource = string | Uint8Array;
14
+ /** High-level purpose applied during path validation to enforce leaf constraints. */
15
+ type VerifyPurpose = "serverAuth" | "clientAuth" | "ca";
16
+ /** Extended key usage purpose checked by {@linkcode checkExtendedKeyUsage}. */
17
+ type EkuCheckPurpose = "serverAuth" | "clientAuth" | "codeSigning" | "emailProtection" | "timeStamping" | "ocspSigning";
18
+ /** Result of {@linkcode checkExtendedKeyUsage}. Success carries no value; failure identifies the offending certificate. */
19
+ type EkuCheckResult = {
20
+ readonly ok: true;
21
+ readonly value: undefined;
22
+ } | IndexedErrorResult<"leaf_eku_missing" | "intermediate_eku_constraint", Record<never, never>, EkuCheckFailure>;
23
+ /** Failure from {@linkcode checkExtendedKeyUsage} with the chain index of the certificate that failed. */
24
+ interface EkuCheckFailure extends Micro509Error<"leaf_eku_missing" | "intermediate_eku_constraint"> {
25
+ /** Always `false` for failures. */
26
+ readonly ok: false;
27
+ /** Zero-based index into the chain of the certificate that lacks the required EKU. */
28
+ readonly index: number;
29
+ }
30
+ /**
31
+ * Bare trust anchor — subject identity and public key material without a
32
+ * full certificate. Used when the root CA certificate is unavailable but
33
+ * its key is known. Build from a certificate with {@linkcode trustAnchorFromCertificate}.
34
+ */
35
+ interface TrustAnchor {
36
+ /** Parsed subject distinguished name. Used for semantic issuer matching (RFC 5280 §7.1). */
37
+ readonly subject: ParsedName;
38
+ /** DER-encoded SubjectPublicKeyInfo used to verify signatures from this anchor. */
39
+ readonly subjectPublicKeyInfoDer: Uint8Array;
40
+ /** OID of the public key algorithm (e.g. `1.2.840.10045.2.1` for EC). */
41
+ readonly publicKeyAlgorithmOid: string;
42
+ /** OID of the key parameters, when algorithm-specific (e.g. named curve OID for EC). */
43
+ readonly publicKeyParametersOid?: string;
44
+ /** Hex-encoded subject key identifier for AKI matching. */
45
+ readonly subjectKeyIdentifier?: string;
46
+ }
47
+ /**
48
+ * Discriminant for every failure a verify operation can produce.
49
+ *
50
+ * - `no_trusted_root` — chain could not be anchored to any root or {@linkcode TrustAnchor}.
51
+ * - `issuer_not_found` — an intermediate's issuer was not in the candidate set.
52
+ * - `signature_invalid` — a certificate's signature failed cryptographic verification.
53
+ * - `certificate_expired` — a certificate's notBefore/notAfter window excludes the validation time.
54
+ * - `ca_required` — an issuer lacks `basicConstraints.ca = true`.
55
+ * - `key_cert_sign_required` — an issuer has keyUsage but omits `keyCertSign`.
56
+ * - `path_length_exceeded` — the number of CA certificates below an issuer exceeds its pathLength.
57
+ * - `authority_key_identifier_mismatch` — a certificate's AKI does not match the issuer's SKI.
58
+ * - `extended_key_usage_invalid` — the leaf certificate lacks the required EKU for the requested purpose.
59
+ * - `subject_alt_name_mismatch` — no SAN entry matches the requested service identity.
60
+ * - `common_name_fallback_suppressed` — CN fallback was attempted but suppressed (SAN present or disabled).
61
+ * - `self_signed_leaf_not_allowed` — the leaf is self-signed and `allowSelfSignedLeaf` was not set.
62
+ * - `unrecognized_critical_extension` — a certificate contains a critical extension the verifier cannot process.
63
+ * - `intermediate_eku_constraint` — an intermediate CA's EKU set does not include the required purpose.
64
+ * - `policy_processing_not_implemented` — policy processing encountered an unsupported construct.
65
+ * - `explicit_policy_required` — `requireExplicitPolicy` was set but no acceptable policy was found.
66
+ * - `initial_policy_set_not_satisfied` — the chain's policies do not intersect `initialPolicySet`.
67
+ * - `initial_name_constraints_not_implemented` — caller-supplied initial name constraints are unsupported.
68
+ * - `unsupported_name_constraints` — a certificate's nameConstraints use an unsupported form.
69
+ * - `name_constraints_violated` — a subject name violates a permitted/excluded subtree.
70
+ * - `unsupported_signature_algorithm_parameters` — the signature algorithm uses unrecognized parameters.
71
+ */
72
+ type VerifyErrorCode = "no_trusted_root" | "issuer_not_found" | "signature_invalid" | "certificate_expired" | "ca_required" | "key_cert_sign_required" | "path_length_exceeded" | "authority_key_identifier_mismatch" | "extended_key_usage_invalid" | "subject_alt_name_mismatch" | "common_name_fallback_suppressed" | "self_signed_leaf_not_allowed" | "unrecognized_critical_extension" | "intermediate_eku_constraint" | "policy_processing_not_implemented" | "explicit_policy_required" | "initial_policy_set_not_satisfied" | "initial_name_constraints_not_implemented" | "unsupported_name_constraints" | "name_constraints_violated" | "unsupported_signature_algorithm_parameters" | "certificate_revoked" | "revocation_indeterminate";
73
+ /** Diagnostic context attached to every {@linkcode VerifyChainFailure}. All fields are optional; presence depends on the error code. */
74
+ interface VerifyFailureDetails {
75
+ /** CN of the certificate that triggered the failure. */
76
+ readonly subjectCommonName?: string;
77
+ /** CN of the issuer of the offending certificate. */
78
+ readonly issuerCommonName?: string;
79
+ /** The value the verifier expected (e.g. a validity window bound or SKI). */
80
+ readonly expected?: string;
81
+ /** The value actually found. */
82
+ readonly actual?: string;
83
+ /** CNs of every certificate in the chain, leaf-first. Present on `no_trusted_root`. */
84
+ readonly chainCommonNames?: readonly string[];
85
+ /** SAN identifier types the leaf actually presents. Set on identity-match failures. */
86
+ readonly presentedIdentifierTypes?: readonly ("dns" | "uri" | "srv")[];
87
+ /** Why the CN-fallback path was not taken. Set on `common_name_fallback_suppressed`. */
88
+ readonly commonNameFallbackReason?: "disabled" | "suppressed_by_presented_identifier" | "common_name_missing" | "common_name_mismatch";
89
+ }
90
+ /** A chain verification failure with its error code, human message, chain index, and diagnostic details. */
91
+ interface VerifyChainFailure extends IndexedMicro509Error<VerifyErrorCode, VerifyFailureDetails> {
92
+ /** Always `false` for failures. */
93
+ readonly ok: false;
94
+ }
95
+ /** Input for {@linkcode buildCandidatePath}. */
96
+ interface BuildCandidatePathInput {
97
+ /** End-entity certificate to verify. */
98
+ readonly leaf: CertificateSource;
99
+ /** Intermediate CA certificates available for path building. Order does not matter. */
100
+ readonly intermediates?: readonly CertificateSource[];
101
+ /** Trusted root CA certificates. At least one root or trust anchor must be supplied. */
102
+ readonly roots: readonly CertificateSource[];
103
+ /** Bare trust anchors to try when no root certificate matches. */
104
+ readonly trustAnchors?: readonly TrustAnchor[];
105
+ /** Validation time. Defaults to `new Date()`. */
106
+ readonly at?: Date;
107
+ }
108
+ /** A signature-verified certification path from leaf to root, before constraint validation. */
109
+ interface CandidatePath {
110
+ /** Parsed end-entity certificate. */
111
+ readonly leaf: ParsedCertificate;
112
+ /** Full chain in leaf-to-root order (includes both leaf and root). */
113
+ readonly chain: readonly ParsedCertificate[];
114
+ /** Trusted root that terminates the path. */
115
+ readonly root: ParsedCertificate;
116
+ }
117
+ /** Result of {@linkcode buildCandidatePath}. On success, contains the {@linkcode CandidatePath}. */
118
+ type BuildCandidatePathResult = {
119
+ readonly ok: true;
120
+ readonly value: CandidatePath;
121
+ } | IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;
122
+ /** Input for {@linkcode validateCandidatePath}. */
123
+ interface ValidateCandidatePathInput extends PolicyValidationInput, InitialNameConstraintsInput {
124
+ /** Nested policy validation overrides (takes precedence over flat fields). */
125
+ readonly policy?: PolicyValidationInput;
126
+ /** Nested name constraint overrides (takes precedence over flat fields). */
127
+ readonly nameConstraints?: InitialNameConstraintsInput;
128
+ /** Pre-built certificate chain in leaf-to-root order. */
129
+ readonly chain: readonly ParsedCertificate[];
130
+ /** Validation time. Defaults to `new Date()`. */
131
+ readonly at?: Date;
132
+ /** Leaf purpose constraint to enforce. */
133
+ readonly purpose?: VerifyPurpose;
134
+ /** When `true`, allows a self-signed leaf that is also the root. Defaults to `false`. */
135
+ readonly allowSelfSignedLeaf?: boolean;
136
+ }
137
+ /** Success payload from {@linkcode validateCandidatePath}. */
138
+ interface ValidateCandidatePathSuccess {
139
+ /** Final RFC 9618-constrained policy outputs for this validated path. */
140
+ readonly policyValidation: PolicyValidationOutcome;
141
+ }
142
+ /** Result of {@linkcode validateCandidatePath}. */
143
+ type ValidateCandidatePathResult = {
144
+ readonly ok: true;
145
+ readonly value: ValidateCandidatePathSuccess; /** Shorthand duplicate of `value.policyValidation` for internal forwarding. */
146
+ readonly policyValidation: PolicyValidationOutcome;
147
+ } | IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;
148
+ /** Input for chain-level revocation checking in {@linkcode verifyCertificateChain}. */
149
+ interface ChainRevocationInput {
150
+ /** CRLs to evaluate. */
151
+ readonly crls?: readonly CrlSource[];
152
+ /** OCSP responses to evaluate (not yet implemented). */
153
+ readonly ocspResponses?: readonly (string | Uint8Array)[];
154
+ /** Extra certs for indirect CRL issuers / delegated OCSP responders. */
155
+ readonly extraCertificates?: readonly CertificateSource$1[];
156
+ /** Revocation policy. */
157
+ readonly policy?: RevocationPolicy;
158
+ }
159
+ /** Input for {@linkcode verifyCertificateChain}. Combines path-building, validation, and identity options. */
160
+ interface VerifyCertificateChainInput extends PolicyValidationInput, InitialNameConstraintsInput {
161
+ /** Nested policy validation overrides. */
162
+ readonly policy?: PolicyValidationInput;
163
+ /** Nested name constraint overrides. */
164
+ readonly nameConstraints?: InitialNameConstraintsInput;
165
+ /** End-entity certificate to verify. */
166
+ readonly leaf: CertificateSource;
167
+ /** Intermediate CA certificates available for path building. */
168
+ readonly intermediates?: readonly CertificateSource[];
169
+ /** Trusted root CA certificates. */
170
+ readonly roots: readonly CertificateSource[];
171
+ /** Bare trust anchors to try when no root certificate matches. */
172
+ readonly trustAnchors?: readonly TrustAnchor[];
173
+ /** Validation time. Defaults to `new Date()`. */
174
+ readonly at?: Date;
175
+ /** Leaf purpose constraint to enforce during validation. */
176
+ readonly purpose?: VerifyPurpose;
177
+ /** DNS/IP/URI/SRV identity to match against the leaf's SAN. */
178
+ readonly serviceIdentity?: VerifyServiceIdentityInput;
179
+ /** When `true`, allows a self-signed leaf. Defaults to `false`. */
180
+ readonly allowSelfSignedLeaf?: boolean;
181
+ /** Optional revocation checking. */
182
+ readonly revocation?: ChainRevocationInput;
183
+ }
184
+ /** Fully verified certificate chain returned on success from {@linkcode verifyCertificateChain}. */
185
+ interface VerifiedCertificateChain {
186
+ /** Parsed end-entity certificate. */
187
+ readonly leaf: ParsedCertificate;
188
+ /** Full chain in leaf-to-root order. */
189
+ readonly chain: readonly ParsedCertificate[];
190
+ /** Trusted root that terminates the path. */
191
+ readonly root: ParsedCertificate;
192
+ /** Final RFC 5280 §6 / RFC 9618 constrained policy outputs for this validated path. */
193
+ readonly policyValidation: PolicyValidationOutcome;
194
+ }
195
+ /** Result of {@linkcode verifyCertificateChain}. On success, contains the {@linkcode VerifiedCertificateChain}. */
196
+ type VerifyChainResult = {
197
+ readonly ok: true;
198
+ readonly value: VerifiedCertificateChain;
199
+ } | IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;
200
+ /** Failure from {@linkcode verifyCertificateSigningRequest}. */
201
+ interface VerifyRequestFailure extends Micro509Error<"signature_invalid" | "unsupported_signature_algorithm_parameters", VerifyFailureDetails> {
202
+ /** Always `false` for failures. */
203
+ readonly ok: false;
204
+ }
205
+ /** Result of {@linkcode verifyCertificateSigningRequest}. On success, contains the parsed CSR. */
206
+ type VerifyRequestResult = {
207
+ readonly ok: true;
208
+ readonly value: ParsedCertificateSigningRequest;
209
+ } | ErrorResult<"signature_invalid" | "unsupported_signature_algorithm_parameters", VerifyFailureDetails, VerifyRequestFailure>;
210
+ /** Input for {@linkcode validateForTlsServer}. Enforces `serverAuth` EKU and optional DNS/IP identity matching. */
211
+ interface ValidateForTlsServerInput extends BuildCandidatePathInput, PolicyValidationInput, InitialNameConstraintsInput {
212
+ /** Nested policy validation overrides. */
213
+ readonly policy?: PolicyValidationInput;
214
+ /** Nested name constraint overrides. */
215
+ readonly nameConstraints?: InitialNameConstraintsInput;
216
+ /** End-entity certificate to verify. */
217
+ readonly leaf: CertificateSource;
218
+ /** Intermediate CA certificates. */
219
+ readonly intermediates?: readonly CertificateSource[];
220
+ /** Trusted root CA certificates. */
221
+ readonly roots: readonly CertificateSource[];
222
+ /** Bare trust anchors. */
223
+ readonly trustAnchors?: readonly TrustAnchor[];
224
+ /** Validation time. Defaults to `new Date()`. */
225
+ readonly at?: Date;
226
+ /** DNS/IP identity to match against the leaf's SAN. */
227
+ readonly serviceIdentity?: VerifyServiceIdentityInput;
228
+ }
229
+ /** Input for {@linkcode validateForTlsClient}. Enforces `clientAuth` EKU. */
230
+ interface ValidateForTlsClientInput extends BuildCandidatePathInput, PolicyValidationInput, InitialNameConstraintsInput {
231
+ /** Nested policy validation overrides. */
232
+ readonly policy?: PolicyValidationInput;
233
+ /** Nested name constraint overrides. */
234
+ readonly nameConstraints?: InitialNameConstraintsInput;
235
+ }
236
+ /** Input for {@linkcode validateForCodeSigning}. Enforces `codeSigning` EKU. */
237
+ interface ValidateForCodeSigningInput extends BuildCandidatePathInput, PolicyValidationInput, InitialNameConstraintsInput {
238
+ /** Nested policy validation overrides. */
239
+ readonly policy?: PolicyValidationInput;
240
+ /** Nested name constraint overrides. */
241
+ readonly nameConstraints?: InitialNameConstraintsInput;
242
+ }
243
+ /** Input for {@linkcode validateForCa}. Enforces `basicConstraints.ca` on the leaf. */
244
+ interface ValidateForCaInput extends BuildCandidatePathInput, PolicyValidationInput, InitialNameConstraintsInput {
245
+ /** Nested policy validation overrides. */
246
+ readonly policy?: PolicyValidationInput;
247
+ /** Nested name constraint overrides. */
248
+ readonly nameConstraints?: InitialNameConstraintsInput;
249
+ }
250
+ /**
251
+ * Builds a signature-verified path from a leaf certificate to a trusted root.
252
+ *
253
+ * Parses the supplied certificates, walks the issuer chain, signature-checks
254
+ * each link, and returns the first valid path. Does not enforce time, constraints,
255
+ * or leaf purpose — call {@linkcode validateCandidatePath} or use the all-in-one
256
+ * {@linkcode verifyCertificateChain} for full validation.
257
+ *
258
+ * @example
259
+ * ```ts
260
+ * import { buildCandidatePath } from 'micro509';
261
+ *
262
+ * const result = await buildCandidatePath({
263
+ * leaf: leafPem,
264
+ * intermediates: [intermediatePem],
265
+ * roots: [rootPem],
266
+ * });
267
+ * if (result.ok) {
268
+ * console.log('path length:', result.value.chain.length);
269
+ * }
270
+ * ```
271
+ */
272
+ declare function buildCandidatePath(input: BuildCandidatePathInput): Promise<BuildCandidatePathResult>;
273
+ /**
274
+ * Validates a pre-built certificate chain for time, constraints, policy, and
275
+ * optionally leaf purpose. Wrap the result of {@linkcode buildCandidatePath}.
276
+ */
277
+ declare function validateCandidatePath(input: ValidateCandidatePathInput): Promise<ValidateCandidatePathResult>;
278
+ /**
279
+ * All-in-one certificate chain verification: builds a candidate path then
280
+ * validates time, constraints, policy, purpose, and optional service identity.
281
+ *
282
+ * Equivalent to calling {@linkcode buildCandidatePath} followed by
283
+ * {@linkcode validateCandidatePath} (plus identity matching when configured).
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * import { verifyCertificateChain } from 'micro509';
288
+ *
289
+ * const result = await verifyCertificateChain({
290
+ * leaf: serverCertPem,
291
+ * intermediates: [intermediatePem],
292
+ * roots: [rootCaPem],
293
+ * purpose: 'serverAuth',
294
+ * serviceIdentity: { type: 'dns', value: 'example.com' },
295
+ * });
296
+ * if (!result.ok) {
297
+ * console.error(result.error.code, result.error.message);
298
+ * }
299
+ * ```
300
+ */
301
+ declare function verifyCertificateChain(input: VerifyCertificateChainInput): Promise<VerifyChainResult>;
302
+ /**
303
+ * Verifies the self-signature of a PKCS#10 certificate signing request.
304
+ *
305
+ * Parses the CSR from PEM or DER, then checks that its signature is valid
306
+ * against its own embedded public key.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * import { verifyCertificateSigningRequest } from 'micro509';
311
+ *
312
+ * const result = await verifyCertificateSigningRequest(csrPem);
313
+ * if (result.ok) {
314
+ * console.log('subject:', result.value.subject.values.commonName);
315
+ * }
316
+ * ```
317
+ */
318
+ declare function verifyCertificateSigningRequest(input: CsrSource): Promise<VerifyRequestResult>;
319
+ /**
320
+ * Standalone EKU check against a verified certificate chain.
321
+ * Validates that the leaf has the requested purpose and that
322
+ * intermediate CA EKU constraints (if present) permit it.
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * import { checkExtendedKeyUsage } from 'micro509';
327
+ *
328
+ * const result = checkExtendedKeyUsage(chain, 'serverAuth');
329
+ * if (!result.ok) {
330
+ * console.error(result.error.code, result.error.message);
331
+ * }
332
+ * ```
333
+ */
334
+ declare function checkExtendedKeyUsage(chain: readonly ParsedCertificate[], purpose: EkuCheckPurpose): EkuCheckResult;
335
+ /** Extracts a {@linkcode TrustAnchor} from a parsed certificate, copying the subject, SPKI, and key identifiers. */
336
+ declare function trustAnchorFromCertificate(certificate: ParsedCertificate): TrustAnchor;
337
+ /**
338
+ * Validates a certificate chain for TLS server use:
339
+ * chain verification + `serverAuth` EKU (leaf + intermediate propagation)
340
+ * + DNS/IP identity matching.
341
+ *
342
+ * @example
343
+ * ```ts
344
+ * import { validateForTlsServer } from 'micro509';
345
+ *
346
+ * const result = await validateForTlsServer({
347
+ * leaf: serverCertPem,
348
+ * roots: [rootCaPem],
349
+ * serviceIdentity: { type: 'dns', value: 'example.com' },
350
+ * });
351
+ * if (result.ok) {
352
+ * console.log('valid for', result.value.leaf.subject.values.commonName);
353
+ * }
354
+ * ```
355
+ */
356
+ declare function validateForTlsServer(input: ValidateForTlsServerInput): Promise<VerifyChainResult>;
357
+ /**
358
+ * Validates a certificate chain for TLS client use:
359
+ * chain verification + `clientAuth` EKU (leaf + intermediate propagation).
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * import { validateForTlsClient } from 'micro509';
364
+ *
365
+ * const result = await validateForTlsClient({
366
+ * leaf: clientCertPem,
367
+ * roots: [rootCaPem],
368
+ * });
369
+ * ```
370
+ */
371
+ declare function validateForTlsClient(input: ValidateForTlsClientInput): Promise<VerifyChainResult>;
372
+ /**
373
+ * Validates a certificate chain for code signing:
374
+ * chain verification + `codeSigning` EKU (leaf + intermediate propagation).
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * import { validateForCodeSigning } from 'micro509';
379
+ *
380
+ * const result = await validateForCodeSigning({
381
+ * leaf: codeSigningCertPem,
382
+ * roots: [rootCaPem],
383
+ * });
384
+ * ```
385
+ */
386
+ declare function validateForCodeSigning(input: ValidateForCodeSigningInput): Promise<VerifyChainResult>;
387
+ /**
388
+ * Validates a certificate chain for CA use:
389
+ * chain verification + `basicConstraints.ca` check on the leaf.
390
+ *
391
+ * @example
392
+ * ```ts
393
+ * import { validateForCa } from 'micro509';
394
+ *
395
+ * const result = await validateForCa({
396
+ * leaf: intermediateCertPem,
397
+ * roots: [rootCaPem],
398
+ * });
399
+ * ```
400
+ */
401
+ declare function validateForCa(input: ValidateForCaInput): Promise<VerifyChainResult>;
402
+ //#endregion
403
+ export { BuildCandidatePathInput, BuildCandidatePathResult, CandidatePath, CertificateSource, ChainRevocationInput, type ConstrainedPolicy, CsrSource, type DnsServiceIdentityInput, EkuCheckFailure, EkuCheckPurpose, EkuCheckResult, type InitialNameConstraintsInput, type IpServiceIdentityInput, type MatchServiceIdentityErrorCode, type MatchServiceIdentityEvaluation, type MatchServiceIdentityFailure, type MatchServiceIdentityFailureDetails, type MatchServiceIdentityFailureResult, type MatchServiceIdentityInput, type MatchServiceIdentityResult, type MatchServiceIdentitySuccess, type MatchableServiceIdentityInput, type PolicyValidationInput, type PolicyValidationOutcome, type ServiceIdentityInput, type ServiceIdentityType, type SrvServiceIdentityInput, TrustAnchor, type UriServiceIdentityInput, ValidateCandidatePathInput, ValidateCandidatePathResult, ValidateCandidatePathSuccess, ValidateForCaInput, ValidateForCodeSigningInput, ValidateForTlsClientInput, ValidateForTlsServerInput, VerifiedCertificateChain, VerifyCertificateChainInput, VerifyChainFailure, VerifyChainResult, VerifyErrorCode, VerifyFailureDetails, VerifyPurpose, VerifyRequestFailure, VerifyRequestResult, type VerifyServiceIdentityInput, buildCandidatePath, checkExtendedKeyUsage, type matchCertificateServiceIdentity, type matchServiceIdentity, trustAnchorFromCertificate, validateCandidatePath, validateForCa, validateForCodeSigning, validateForTlsClient, validateForTlsServer, verifyCertificateChain, verifyCertificateSigningRequest };
404
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{OIDS as e}from"../internal/asn1/oids.js";import{parseIpAddressToBytes as t}from"../internal/shared/ip.js";import{parseCertificateDer as n,parseCertificateSigningRequestDer as r,parseCertificateSigningRequestPem as i}from"../x509/parse.js";import{verifySignedDataDetailed as a}from"../internal/crypto/sig-verify.js";import{createNameConstraintValidationState as o,evaluateNameConstraints as s}from"../internal/verify/name-constraints-engine.js";import{createPolicyValidationState as c,evaluatePolicyChain as ee}from"../internal/verify/policy-engine.js";import{buildChainInternal as l,countCaCertificatesBelowParsed as u,isSelfIssued as d,isWithinValidity as f,loadCertificates as p,loadSingleCertificate as te,verifyCertificateSignature as ne}from"../internal/verify/verify-path.js";import{errorResult as m,indexedErrorResult as h,indexedMicro509Error as g,micro509Error as _}from"../result/result.js";import{checkChainRevocation as v}from"../revocation/chain.js";import{matchServiceIdentity as y}from"./identity.js";const b=new Set([e.basicConstraints,e.keyUsage,e.extendedKeyUsage,e.subjectAltName,e.nameConstraints,e.authorityKeyIdentifier,e.subjectKeyIdentifier,e.authorityInfoAccess,e.cRLDistributionPoints,e.certificatePolicies,e.policyMappings,e.policyConstraints,e.inhibitAnyPolicy]);async function x(e){let t,n,r;try{t=te(e.leaf),n=p(e.intermediates??[]),r=p(e.roots)}catch(e){return I(`issuer_not_found`,`certificate source is malformed or leaf source does not contain exactly one certificate`,0,J({actual:e instanceof Error?e.message:`certificate source is malformed`}))}let i=e.trustAnchors??[],a=e.at??new Date,o=await l(t,n,r,i,a,{failure:I,detail:J}),s=o.chain;if(!o.foundTrustedRoot)return o.failure===void 0?o.missingIssuerAt===void 0?I(`no_trusted_root`,`no trusted root found`,void 0,J({chainCommonNames:s.map(e=>e.subject.values.commonName??`<unnamed>`)})):I(`issuer_not_found`,`issuer certificate not found`,o.missingIssuerAt,le(s,o.missingIssuerAt)):o.failure;let c=s[s.length-1];return c===void 0?I(`no_trusted_root`,`no trusted root found`):{ok:!0,value:{leaf:t,chain:s,root:c}}}async function S(e){let t=await x(e);return t.ok?t:L(t)}async function C(e){let t=e.chain,n=e.at??new Date,r=Y(e,t.length);if(!r.ok)return r;let i=t[0];if(i===void 0)return I(`issuer_not_found`,`chain is empty`,0);if(t.length===1&&d(i)&&e.allowSelfSignedLeaf!==!0)return I(`self_signed_leaf_not_allowed`,`self-signed leaf not allowed`,0,J({subjectCommonName:i.subject.values.commonName}));for(let e=0;e<t.length;e+=1){let r=t[e];if(r===void 0)return I(`issuer_not_found`,`chain element missing`,e);if(!f(r,n))return I(`certificate_expired`,`certificate not valid at requested time`,e,J({subjectCommonName:r.subject.values.commonName,expected:z(n),actual:`${z(r.notBefore)}..${z(r.notAfter)}`}));let i=F(r);if(i!==void 0)return I(`unrecognized_critical_extension`,`certificate contains unrecognized critical extension ${i}`,e,J({subjectCommonName:r.subject.values.commonName,actual:i}));if(e===t.length-1)continue;let a=t[e+1];if(a===void 0)return I(`issuer_not_found`,`issuer missing`,e);let o=await ne(r,a);if(!o.ok)return I(o.code,o.reason,e,J({subjectCommonName:r.subject.values.commonName,issuerCommonName:a.subject.values.commonName,actual:o.reason}));if(!o.valid)return I(`signature_invalid`,`certificate signature does not verify`,e,J({subjectCommonName:r.subject.values.commonName,issuerCommonName:a.subject.values.commonName}));if(a.basicConstraints?.ca!==!0)return I(`ca_required`,`issuer must be a CA certificate`,e+1,J({subjectCommonName:a.subject.values.commonName}));if(a.keyUsage!==void 0&&!a.keyUsage.flags.includes(`keyCertSign`))return I(`key_cert_sign_required`,`issuer missing keyCertSign`,e+1,J({subjectCommonName:a.subject.values.commonName}));if(r.authorityKeyIdentifier!==void 0&&a.subjectKeyIdentifier!==void 0&&r.authorityKeyIdentifier!==a.subjectKeyIdentifier)return I(`authority_key_identifier_mismatch`,`authorityKeyIdentifier does not match issuer subjectKeyIdentifier`,e,J({subjectCommonName:r.subject.values.commonName,issuerCommonName:a.subject.values.commonName,expected:a.subjectKeyIdentifier,actual:r.authorityKeyIdentifier}))}for(let e=1;e<t.length;e+=1){let n=t[e];if(n===void 0)return I(`issuer_not_found`,`chain element missing`,e);let r=u(t,e),i=n.basicConstraints?.pathLength;if(H(i)&&r>i)return I(`path_length_exceeded`,`path length constraint exceeded`,e,J({subjectCommonName:n.subject.values.commonName,expected:String(i),actual:String(r)}))}let a=ee(t,r.value.policy);if(!a.ok)return I(a.error.code,a.error.message,0,J({expected:a.error.details?.expected,actual:a.error.details?.actual}));let o=s(t,r.value.nameConstraints);return o.ok?A(i,e,a.value):o}async function w(e){let t;try{t=B(e.chain)}catch(e){return L(I(`signature_invalid`,`certificate input is malformed`,0,J({actual:e instanceof Error?e.message:`certificate input is malformed`})))}let n=await C({...e,chain:t});return n.ok?R(n.policyValidation):L(n)}async function T(e){let t=await S({leaf:e.leaf,roots:e.roots,...e.intermediates!==void 0&&{intermediates:e.intermediates},...e.trustAnchors!==void 0&&{trustAnchors:e.trustAnchors},...e.at!==void 0&&{at:e.at}});if(!t.ok)return t;let n=await w({chain:t.value.chain,...e.at!==void 0&&{at:e.at},...e.purpose!==void 0&&{purpose:e.purpose},...q(e),...e.allowSelfSignedLeaf!==void 0&&{allowSelfSignedLeaf:e.allowSelfSignedLeaf}});if(!n.ok)return n;if(e.serviceIdentity!==void 0){let n=j(t.value.leaf,e.serviceIdentity);if(!n.ok)return L(n)}if(e.revocation!==void 0){let n=await v({chain:t.value.chain,...e.revocation.crls===void 0?{}:{crls:e.revocation.crls},...e.revocation.ocspResponses===void 0?{}:{ocspResponses:e.revocation.ocspResponses},...e.revocation.extraCertificates===void 0?{}:{extraCertificates:e.revocation.extraCertificates},...e.revocation.policy===void 0?{}:{policy:e.revocation.policy},...e.at===void 0?{}:{at:e.at}});if(n.value.decision===`deny`){let e=n.value.summary.revokedCertificates[0];if(e!==void 0)return L(I(`certificate_revoked`,`certificate revoked: ${e.subject.values.commonName??`unknown`}`,void 0,J({subjectCommonName:e.subject.values.commonName})));let t=n.value.summary.indeterminateCertificates[0],r=n.value.certificates.find(e=>e.status===`indeterminate`)?.indeterminateReasons;return L(I(`revocation_indeterminate`,`revocation status indeterminate: ${t?.subject.values.commonName??`unknown`}`,void 0,J({subjectCommonName:t?.subject.values.commonName,actual:r?.join(`, `)})))}}return{ok:!0,value:{...t.value,policyValidation:n.value.policyValidation}}}async function re(e){let t;try{t=typeof e==`string`?i(e):r(new Uint8Array(e))}catch(e){return U(`signature_invalid`,`certificate request input is malformed`,J({actual:e instanceof Error?e.message:`certificate request input is malformed`}))}let n;try{n=await a(t.signatureAlgorithmOid,t.signatureAlgorithmParametersDer,t.publicKeyAlgorithmOid,t.publicKeyParametersOid,t.subjectPublicKeyInfoDer,t.signatureValue,t.certificationRequestInfoDer)}catch(e){return U(`signature_invalid`,`certificate request input is malformed`,J({subjectCommonName:t.subject.values.commonName,actual:e instanceof Error?e.message:`certificate request input is malformed`}))}return n.ok?n.valid?{ok:!0,value:t}:U(`signature_invalid`,`certificate request signature does not verify`,J({subjectCommonName:t.subject.values.commonName})):U(n.code===`verification_error`?`signature_invalid`:n.code,n.reason,J({subjectCommonName:t.subject.values.commonName,actual:n.reason}))}function E(e,t){let n;try{n=B(e)}catch{return W(`leaf_eku_missing`,`certificate input is malformed`,0)}let r=n[0];if(r===void 0)return W(`leaf_eku_missing`,`chain is empty`,0);if(r.extendedKeyUsage!==void 0&&!r.extendedKeyUsage.includes(t))return W(`leaf_eku_missing`,`leaf certificate does not include EKU ${t}`,0);for(let e=1;e<n.length;e+=1){let r=n[e];if(r!==void 0&&r.extendedKeyUsage!==void 0&&!r.extendedKeyUsage.includes(t))return W(`intermediate_eku_constraint`,`intermediate CA at index ${String(e)} constrains EKU and does not include ${t}`,e)}return{ok:!0,value:void 0}}function ie(e){let t;try{t=V(e)}catch{throw Error(`certificate input is malformed`)}return{subject:t.subject,subjectPublicKeyInfoDer:t.subjectPublicKeyInfoDer,publicKeyAlgorithmOid:t.publicKeyAlgorithmOid,...t.publicKeyParametersOid===void 0?{}:{publicKeyParametersOid:t.publicKeyParametersOid},...t.subjectKeyIdentifier===void 0?{}:{subjectKeyIdentifier:t.subjectKeyIdentifier}}}function D(e){return{leaf:e.leaf,roots:e.roots,...e.intermediates!==void 0&&{intermediates:e.intermediates},...e.trustAnchors!==void 0&&{trustAnchors:e.trustAnchors},...e.at!==void 0&&{at:e.at},...q(e)}}async function ae(e){let t=await P(e,`serverAuth`);if(!t.ok)return t;if(e.serviceIdentity!==void 0){let n=j(t.value.leaf,e.serviceIdentity);if(!n.ok)return L(n)}return t}async function oe(e){return P(e,`clientAuth`)}async function O(e){return P(e,`codeSigning`)}async function k(e){return T({...D(e),purpose:`ca`})}function A(e,t,n){let r=t.purpose;if(r!==void 0){if(r===`ca`){if(e.basicConstraints?.ca!==!0)return I(`ca_required`,`leaf is not a CA certificate`,0,J({subjectCommonName:e.subject.values.commonName}))}else if(e.extendedKeyUsage!==void 0&&!e.extendedKeyUsage.includes(r))return I(`extended_key_usage_invalid`,`leaf missing EKU ${r}`,0,J({subjectCommonName:e.subject.values.commonName,expected:r,actual:e.extendedKeyUsage.map(ue).join(`,`)}))}return{ok:!0,policyValidation:n}}function j(e,t){let n=M(t);if(!n.ok)return n;let r=y({certificate:V(e),serviceIdentity:t});if(r.ok)return{ok:!0};let i=r.error;return i.code!==`subject_alt_name_mismatch`&&i.code!==`common_name_fallback_suppressed`?I(`subject_alt_name_mismatch`,`service identity input is malformed`,0,J({expected:t.value,actual:i.code})):{ok:!1,code:i.code,message:i.message,index:0,...i.details===void 0?{}:{details:i.details}}}function M(e){if(!$(e))return I(`subject_alt_name_mismatch`,`service identity input is malformed`,0);if(e.type!==`dns`&&e.type!==`ip`)return I(`subject_alt_name_mismatch`,`service identity input is malformed`,0,J({actual:String(e.type)}));if(typeof e.value!=`string`)return I(`subject_alt_name_mismatch`,`service identity input is malformed`,0,J({actual:e.type}));if(e.type===`ip`)try{t(e.value)}catch{return I(`subject_alt_name_mismatch`,`service identity input is malformed`,0,J({expected:e.value,actual:`ip`}))}return{ok:!0}}function N(e,t){let n=E(e.value.chain,t);return n.ok?e:L(I(n.code===`leaf_eku_missing`?`extended_key_usage_invalid`:`intermediate_eku_constraint`,n.message,n.index))}async function P(e,t){let n=await T(D(e));return n.ok?N(n,t):n}function F(e){for(let t of e.extensions)if(t.critical&&!b.has(t.oid))return t.oid}function I(e,t,n,r){return{ok:!1,...g(e,t,n,r)}}function L(e){return h(e)}function R(e){return{ok:!0,value:{policyValidation:e},policyValidation:e}}function z(e){return Number.isNaN(e.getTime())?`<invalid date>`:e.toISOString()}function B(e){return e.map(V)}function V(e){return n(new Uint8Array(e.der))}function H(e){return e!==void 0&&Number.isInteger(e)&&e>=0}function U(e,t,n){return m({ok:!1,..._(e,t,n)})}function W(e,t,n){return h({ok:!1,...g(e,t,n),index:n})}function G(e){let t=X(e.initialPolicySet),n=X(e.policy?.initialPolicySet);return{...t===void 0?{}:{initialPolicySet:t},...e.requireExplicitPolicy===void 0?{}:{requireExplicitPolicy:e.requireExplicitPolicy},...e.inhibitPolicyMapping===void 0?{}:{inhibitPolicyMapping:e.inhibitPolicyMapping},...e.inhibitAnyPolicy===void 0?{}:{inhibitAnyPolicy:e.inhibitAnyPolicy},...n===void 0?{}:{initialPolicySet:n},...e.policy?.requireExplicitPolicy===void 0?{}:{requireExplicitPolicy:e.policy.requireExplicitPolicy},...e.policy?.inhibitPolicyMapping===void 0?{}:{inhibitPolicyMapping:e.policy.inhibitPolicyMapping},...e.policy?.inhibitAnyPolicy===void 0?{}:{inhibitAnyPolicy:e.policy.inhibitAnyPolicy}}}function K(e){return{...e.permittedSubtrees===void 0?{}:{permittedSubtrees:e.permittedSubtrees},...e.excludedSubtrees===void 0?{}:{excludedSubtrees:e.excludedSubtrees},...e.nameConstraints?.permittedSubtrees===void 0?{}:{permittedSubtrees:e.nameConstraints.permittedSubtrees},...e.nameConstraints?.excludedSubtrees===void 0?{}:{excludedSubtrees:e.nameConstraints.excludedSubtrees}}}function q(e){let t=G(e),n=K(e);return{...se(t)?{policy:t}:{},...ce(n)?{nameConstraints:n}:{}}}function se(e){return e.initialPolicySet!==void 0||e.requireExplicitPolicy!==void 0||e.inhibitPolicyMapping!==void 0||e.inhibitAnyPolicy!==void 0}function ce(e){return e.permittedSubtrees!==void 0||e.excludedSubtrees!==void 0}function le(e,t){let n=e[t];return J({subjectCommonName:n?.subject.values.commonName,issuerCommonName:n?.issuer.values.commonName,chainCommonNames:e.map(e=>e.subject.values.commonName??`<unnamed>`)})}function ue(e){return typeof e==`string`?e:e.value}function J(e){return{...e.subjectCommonName===void 0?{}:{subjectCommonName:e.subjectCommonName},...e.issuerCommonName===void 0?{}:{issuerCommonName:e.issuerCommonName},...e.expected===void 0?{}:{expected:e.expected},...e.actual===void 0?{}:{actual:e.actual},...e.chainCommonNames===void 0?{}:{chainCommonNames:e.chainCommonNames},...e.presentedIdentifierTypes===void 0?{}:{presentedIdentifierTypes:e.presentedIdentifierTypes},...e.commonNameFallbackReason===void 0?{}:{commonNameFallbackReason:e.commonNameFallbackReason}}}function Y(e,t){let n=c(G(e),t),r=de(K(e));return r.ok?{ok:!0,value:{policy:n,nameConstraints:o(r.value)}}:r}function X(e){return e===void 0||e===`any`||Array.isArray(e)&&e.every(e=>typeof e==`string`)?e:[]}function de(e){let t=Z(e.permittedSubtrees,`permittedSubtrees`);if(!t.ok)return t;let n=Z(e.excludedSubtrees,`excludedSubtrees`);return n.ok?{ok:!0,value:e}:n}function Z(e,t){if(e===void 0)return{ok:!0};if(!Array.isArray(e))return Q(t);for(let t of e){let e=fe(t);if(e!==void 0)return Q(e)}return{ok:!0}}function fe(e){if(!$(e))return`invalid subtree`;let t=e.base;if(!$(t)||typeof t.type!=`string`)return`invalid subtree`;switch(t.type){case`dns`:case`email`:case`uri`:return typeof t.value==`string`?void 0:t.type;case`directoryName`:return typeof t.derHex==`string`?void 0:t.type;case`ip`:return t.addressBytes instanceof Uint8Array&&t.maskBytes instanceof Uint8Array?void 0:t.type;case`otherName`:case`x400Address`:case`ediPartyName`:case`registeredID`:return t.type;default:return t.type}}function Q(e){return I(`initial_name_constraints_not_implemented`,`initial name constraints use unsupported or malformed forms`,void 0,J({actual:e}))}function $(e){return typeof e==`object`&&!!e}export{S as buildCandidatePath,E as checkExtendedKeyUsage,ie as trustAnchorFromCertificate,w as validateCandidatePath,k as validateForCa,O as validateForCodeSigning,oe as validateForTlsClient,ae as validateForTlsServer,T as verifyCertificateChain,re as verifyCertificateSigningRequest};
2
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","names":[],"sources":["../../src/verify/verify.ts"],"sourcesContent":["/**\n * Public certificate and CSR verification APIs.\n *\n * Builds and validates certificate paths per RFC 5280 §6, enforcing purpose\n * constraints, policy state, name constraints, and optional service identity\n * checks against a leaf certificate.\n *\n * Three levels of granularity:\n * - {@linkcode buildCandidatePath} — signature-verified path only\n * - {@linkcode validateCandidatePath} — time/constraint/policy validation on a pre-built path\n * - {@linkcode verifyCertificateChain} — all-in-one build + validate\n *\n * Purpose-scoped convenience wrappers: {@linkcode validateForTlsServer},\n * {@linkcode validateForTlsClient}, {@linkcode validateForCodeSigning}, {@linkcode validateForCa}.\n *\n * @module\n */\n\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport { verifySignedDataDetailed } from '#micro509/internal/crypto/sig-verify.ts';\nimport { parseIpAddressToBytes } from '#micro509/internal/shared/ip.ts';\nimport {\n\tcreateNameConstraintValidationState,\n\tevaluateNameConstraints,\n\ttype NameConstraintValidationState,\n} from '#micro509/internal/verify/name-constraints-engine.ts';\nimport {\n\tcreatePolicyValidationState,\n\tevaluatePolicyChain,\n\ttype PolicyValidationState,\n} from '#micro509/internal/verify/policy-engine.ts';\nimport {\n\tbuildChainInternal,\n\tcountCaCertificatesBelowParsed,\n\tisSelfIssued,\n\tisWithinValidity,\n\tloadCertificates,\n\tloadSingleCertificate,\n\tverifyCertificateSignature,\n} from '#micro509/internal/verify/verify-path.ts';\nimport type {\n\tErrorResult,\n\tIndexedErrorResult,\n\tIndexedMicro509Error,\n\tMicro509Error,\n} from '#micro509/result/result.ts';\nimport {\n\terrorResult,\n\tindexedErrorResult,\n\tindexedMicro509Error,\n\tmicro509Error,\n} from '#micro509/result/result.ts';\nimport type { ExtendedKeyUsage } from '#micro509/x509/extensions.ts';\nimport type {\n\tParsedCertificate,\n\tParsedCertificateSigningRequest,\n\tParsedName,\n} from '#micro509/x509/parse.ts';\nimport {\n\tparseCertificateDer,\n\tparseCertificateSigningRequestDer,\n\tparseCertificateSigningRequestPem,\n} from '#micro509/x509/parse.ts';\nimport {\n\tcheckChainRevocation,\n\ttype CertificateSource as RevocationCertificateSource,\n\ttype CrlSource,\n\ttype RevocationPolicy,\n} from '#micro509/revocation/chain.ts';\nimport type { VerifyServiceIdentityInput } from './identity.ts';\nimport { matchServiceIdentity } from './identity.ts';\nimport type { InitialNameConstraintsInput } from './name-constraints.ts';\nimport type { PolicyValidationInput, PolicyValidationOutcome } from './policy.ts';\n\nexport type * from './identity.ts';\nexport type * from './name-constraints.ts';\nexport type * from './policy.ts';\n\n// ---------------------------------------------------------------------------\n// Source types\n// ---------------------------------------------------------------------------\n\n/** PEM string or DER bytes for a certificate. PEM may contain multiple blocks. */\nexport type CertificateSource = string | Uint8Array;\n/** PEM string or DER bytes for a certificate signing request. */\nexport type CsrSource = string | Uint8Array;\n\n// ---------------------------------------------------------------------------\n// Purpose & EKU types\n// ---------------------------------------------------------------------------\n\n/** High-level purpose applied during path validation to enforce leaf constraints. */\nexport type VerifyPurpose = 'serverAuth' | 'clientAuth' | 'ca';\n\n/** Extended key usage purpose checked by {@linkcode checkExtendedKeyUsage}. */\nexport type EkuCheckPurpose =\n\t| 'serverAuth'\n\t| 'clientAuth'\n\t| 'codeSigning'\n\t| 'emailProtection'\n\t| 'timeStamping'\n\t| 'ocspSigning';\n\n/** Result of {@linkcode checkExtendedKeyUsage}. Success carries no value; failure identifies the offending certificate. */\nexport type EkuCheckResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: undefined;\n\t }\n\t| IndexedErrorResult<\n\t\t\t'leaf_eku_missing' | 'intermediate_eku_constraint',\n\t\t\tRecord<never, never>,\n\t\t\tEkuCheckFailure\n\t >;\n\n/** Failure from {@linkcode checkExtendedKeyUsage} with the chain index of the certificate that failed. */\nexport interface EkuCheckFailure\n\textends Micro509Error<'leaf_eku_missing' | 'intermediate_eku_constraint'> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n\t/** Zero-based index into the chain of the certificate that lacks the required EKU. */\n\treadonly index: number;\n}\n\n// ---------------------------------------------------------------------------\n// Trust anchor\n// ---------------------------------------------------------------------------\n\n/**\n * Bare trust anchor — subject identity and public key material without a\n * full certificate. Used when the root CA certificate is unavailable but\n * its key is known. Build from a certificate with {@linkcode trustAnchorFromCertificate}.\n */\nexport interface TrustAnchor {\n\t/** Parsed subject distinguished name. Used for semantic issuer matching (RFC 5280 §7.1). */\n\treadonly subject: ParsedName;\n\t/** DER-encoded SubjectPublicKeyInfo used to verify signatures from this anchor. */\n\treadonly subjectPublicKeyInfoDer: Uint8Array;\n\t/** OID of the public key algorithm (e.g. `1.2.840.10045.2.1` for EC). */\n\treadonly publicKeyAlgorithmOid: string;\n\t/** OID of the key parameters, when algorithm-specific (e.g. named curve OID for EC). */\n\treadonly publicKeyParametersOid?: string;\n\t/** Hex-encoded subject key identifier for AKI matching. */\n\treadonly subjectKeyIdentifier?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Error & failure types\n// ---------------------------------------------------------------------------\n\n/**\n * Discriminant for every failure a verify operation can produce.\n *\n * - `no_trusted_root` — chain could not be anchored to any root or {@linkcode TrustAnchor}.\n * - `issuer_not_found` — an intermediate's issuer was not in the candidate set.\n * - `signature_invalid` — a certificate's signature failed cryptographic verification.\n * - `certificate_expired` — a certificate's notBefore/notAfter window excludes the validation time.\n * - `ca_required` — an issuer lacks `basicConstraints.ca = true`.\n * - `key_cert_sign_required` — an issuer has keyUsage but omits `keyCertSign`.\n * - `path_length_exceeded` — the number of CA certificates below an issuer exceeds its pathLength.\n * - `authority_key_identifier_mismatch` — a certificate's AKI does not match the issuer's SKI.\n * - `extended_key_usage_invalid` — the leaf certificate lacks the required EKU for the requested purpose.\n * - `subject_alt_name_mismatch` — no SAN entry matches the requested service identity.\n * - `common_name_fallback_suppressed` — CN fallback was attempted but suppressed (SAN present or disabled).\n * - `self_signed_leaf_not_allowed` — the leaf is self-signed and `allowSelfSignedLeaf` was not set.\n * - `unrecognized_critical_extension` — a certificate contains a critical extension the verifier cannot process.\n * - `intermediate_eku_constraint` — an intermediate CA's EKU set does not include the required purpose.\n * - `policy_processing_not_implemented` — policy processing encountered an unsupported construct.\n * - `explicit_policy_required` — `requireExplicitPolicy` was set but no acceptable policy was found.\n * - `initial_policy_set_not_satisfied` — the chain's policies do not intersect `initialPolicySet`.\n * - `initial_name_constraints_not_implemented` — caller-supplied initial name constraints are unsupported.\n * - `unsupported_name_constraints` — a certificate's nameConstraints use an unsupported form.\n * - `name_constraints_violated` — a subject name violates a permitted/excluded subtree.\n * - `unsupported_signature_algorithm_parameters` — the signature algorithm uses unrecognized parameters.\n */\nexport type VerifyErrorCode =\n\t| 'no_trusted_root'\n\t| 'issuer_not_found'\n\t| 'signature_invalid'\n\t| 'certificate_expired'\n\t| 'ca_required'\n\t| 'key_cert_sign_required'\n\t| 'path_length_exceeded'\n\t| 'authority_key_identifier_mismatch'\n\t| 'extended_key_usage_invalid'\n\t| 'subject_alt_name_mismatch'\n\t| 'common_name_fallback_suppressed'\n\t| 'self_signed_leaf_not_allowed'\n\t| 'unrecognized_critical_extension'\n\t| 'intermediate_eku_constraint'\n\t| 'policy_processing_not_implemented'\n\t| 'explicit_policy_required'\n\t| 'initial_policy_set_not_satisfied'\n\t| 'initial_name_constraints_not_implemented'\n\t| 'unsupported_name_constraints'\n\t| 'name_constraints_violated'\n\t| 'unsupported_signature_algorithm_parameters'\n\t| 'certificate_revoked'\n\t| 'revocation_indeterminate';\n\n/** Diagnostic context attached to every {@linkcode VerifyChainFailure}. All fields are optional; presence depends on the error code. */\nexport interface VerifyFailureDetails {\n\t/** CN of the certificate that triggered the failure. */\n\treadonly subjectCommonName?: string;\n\t/** CN of the issuer of the offending certificate. */\n\treadonly issuerCommonName?: string;\n\t/** The value the verifier expected (e.g. a validity window bound or SKI). */\n\treadonly expected?: string;\n\t/** The value actually found. */\n\treadonly actual?: string;\n\t/** CNs of every certificate in the chain, leaf-first. Present on `no_trusted_root`. */\n\treadonly chainCommonNames?: readonly string[];\n\t/** SAN identifier types the leaf actually presents. Set on identity-match failures. */\n\treadonly presentedIdentifierTypes?: readonly ('dns' | 'uri' | 'srv')[];\n\t/** Why the CN-fallback path was not taken. Set on `common_name_fallback_suppressed`. */\n\treadonly commonNameFallbackReason?:\n\t\t| 'disabled'\n\t\t| 'suppressed_by_presented_identifier'\n\t\t| 'common_name_missing'\n\t\t| 'common_name_mismatch';\n}\n\n/** A chain verification failure with its error code, human message, chain index, and diagnostic details. */\nexport interface VerifyChainFailure\n\textends IndexedMicro509Error<VerifyErrorCode, VerifyFailureDetails> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n// ---------------------------------------------------------------------------\n// Build candidate path\n// ---------------------------------------------------------------------------\n\n/** Input for {@linkcode buildCandidatePath}. */\nexport interface BuildCandidatePathInput {\n\t/** End-entity certificate to verify. */\n\treadonly leaf: CertificateSource;\n\t/** Intermediate CA certificates available for path building. Order does not matter. */\n\treadonly intermediates?: readonly CertificateSource[];\n\t/** Trusted root CA certificates. At least one root or trust anchor must be supplied. */\n\treadonly roots: readonly CertificateSource[];\n\t/** Bare trust anchors to try when no root certificate matches. */\n\treadonly trustAnchors?: readonly TrustAnchor[];\n\t/** Validation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n}\n\n/** A signature-verified certification path from leaf to root, before constraint validation. */\nexport interface CandidatePath {\n\t/** Parsed end-entity certificate. */\n\treadonly leaf: ParsedCertificate;\n\t/** Full chain in leaf-to-root order (includes both leaf and root). */\n\treadonly chain: readonly ParsedCertificate[];\n\t/** Trusted root that terminates the path. */\n\treadonly root: ParsedCertificate;\n}\n\n/** Result of {@linkcode buildCandidatePath}. On success, contains the {@linkcode CandidatePath}. */\nexport type BuildCandidatePathResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: CandidatePath;\n\t }\n\t| IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;\n\n// ---------------------------------------------------------------------------\n// Validate candidate path\n// ---------------------------------------------------------------------------\n\n/** Input for {@linkcode validateCandidatePath}. */\nexport interface ValidateCandidatePathInput\n\textends PolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides (takes precedence over flat fields). */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides (takes precedence over flat fields). */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n\t/** Pre-built certificate chain in leaf-to-root order. */\n\treadonly chain: readonly ParsedCertificate[];\n\t/** Validation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** Leaf purpose constraint to enforce. */\n\treadonly purpose?: VerifyPurpose;\n\t/** When `true`, allows a self-signed leaf that is also the root. Defaults to `false`. */\n\treadonly allowSelfSignedLeaf?: boolean;\n}\n\n/** Success payload from {@linkcode validateCandidatePath}. */\nexport interface ValidateCandidatePathSuccess {\n\t/** Final RFC 9618-constrained policy outputs for this validated path. */\n\treadonly policyValidation: PolicyValidationOutcome;\n}\n\n/** Internal result from raw candidate-path validation before wrapping. */\ntype ValidateCandidatePathRawResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly policyValidation: PolicyValidationOutcome;\n\t }\n\t| VerifyChainFailure;\n\n/** Result of {@linkcode validateCandidatePath}. */\nexport type ValidateCandidatePathResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: ValidateCandidatePathSuccess;\n\t\t\t/** Shorthand duplicate of `value.policyValidation` for internal forwarding. */\n\t\t\treadonly policyValidation: PolicyValidationOutcome;\n\t }\n\t| IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;\n\n// ---------------------------------------------------------------------------\n// Verify chain (convenience composition)\n// ---------------------------------------------------------------------------\n\n/** Input for chain-level revocation checking in {@linkcode verifyCertificateChain}. */\nexport interface ChainRevocationInput {\n\t/** CRLs to evaluate. */\n\treadonly crls?: readonly CrlSource[];\n\t/** OCSP responses to evaluate (not yet implemented). */\n\treadonly ocspResponses?: readonly (string | Uint8Array)[];\n\t/** Extra certs for indirect CRL issuers / delegated OCSP responders. */\n\treadonly extraCertificates?: readonly RevocationCertificateSource[];\n\t/** Revocation policy. */\n\treadonly policy?: RevocationPolicy;\n}\n\n/** Input for {@linkcode verifyCertificateChain}. Combines path-building, validation, and identity options. */\nexport interface VerifyCertificateChainInput\n\textends PolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides. */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides. */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n\t/** End-entity certificate to verify. */\n\treadonly leaf: CertificateSource;\n\t/** Intermediate CA certificates available for path building. */\n\treadonly intermediates?: readonly CertificateSource[];\n\t/** Trusted root CA certificates. */\n\treadonly roots: readonly CertificateSource[];\n\t/** Bare trust anchors to try when no root certificate matches. */\n\treadonly trustAnchors?: readonly TrustAnchor[];\n\t/** Validation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** Leaf purpose constraint to enforce during validation. */\n\treadonly purpose?: VerifyPurpose;\n\t/** DNS/IP/URI/SRV identity to match against the leaf's SAN. */\n\treadonly serviceIdentity?: VerifyServiceIdentityInput;\n\t/** When `true`, allows a self-signed leaf. Defaults to `false`. */\n\treadonly allowSelfSignedLeaf?: boolean;\n\t/** Optional revocation checking. */\n\treadonly revocation?: ChainRevocationInput;\n}\n\n/** Fully verified certificate chain returned on success from {@linkcode verifyCertificateChain}. */\nexport interface VerifiedCertificateChain {\n\t/** Parsed end-entity certificate. */\n\treadonly leaf: ParsedCertificate;\n\t/** Full chain in leaf-to-root order. */\n\treadonly chain: readonly ParsedCertificate[];\n\t/** Trusted root that terminates the path. */\n\treadonly root: ParsedCertificate;\n\t/** Final RFC 5280 §6 / RFC 9618 constrained policy outputs for this validated path. */\n\treadonly policyValidation: PolicyValidationOutcome;\n}\n\n/** Result of {@linkcode verifyCertificateChain}. On success, contains the {@linkcode VerifiedCertificateChain}. */\nexport type VerifyChainResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: VerifiedCertificateChain;\n\t }\n\t| IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure>;\n\n// ---------------------------------------------------------------------------\n// CSR verification\n// ---------------------------------------------------------------------------\n\n/** Failure from {@linkcode verifyCertificateSigningRequest}. */\nexport interface VerifyRequestFailure\n\textends Micro509Error<\n\t\t'signature_invalid' | 'unsupported_signature_algorithm_parameters',\n\t\tVerifyFailureDetails\n\t> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/** Result of {@linkcode verifyCertificateSigningRequest}. On success, contains the parsed CSR. */\nexport type VerifyRequestResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: ParsedCertificateSigningRequest;\n\t }\n\t| ErrorResult<\n\t\t\t'signature_invalid' | 'unsupported_signature_algorithm_parameters',\n\t\t\tVerifyFailureDetails,\n\t\t\tVerifyRequestFailure\n\t >;\n\n// ---------------------------------------------------------------------------\n// Validation profile inputs\n// ---------------------------------------------------------------------------\n\n/** Input for {@linkcode validateForTlsServer}. Enforces `serverAuth` EKU and optional DNS/IP identity matching. */\nexport interface ValidateForTlsServerInput\n\textends BuildCandidatePathInput,\n\t\tPolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides. */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides. */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n\t/** End-entity certificate to verify. */\n\treadonly leaf: CertificateSource;\n\t/** Intermediate CA certificates. */\n\treadonly intermediates?: readonly CertificateSource[];\n\t/** Trusted root CA certificates. */\n\treadonly roots: readonly CertificateSource[];\n\t/** Bare trust anchors. */\n\treadonly trustAnchors?: readonly TrustAnchor[];\n\t/** Validation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** DNS/IP identity to match against the leaf's SAN. */\n\treadonly serviceIdentity?: VerifyServiceIdentityInput;\n}\n\n/** Input for {@linkcode validateForTlsClient}. Enforces `clientAuth` EKU. */\nexport interface ValidateForTlsClientInput\n\textends BuildCandidatePathInput,\n\t\tPolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides. */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides. */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n}\n/** Input for {@linkcode validateForCodeSigning}. Enforces `codeSigning` EKU. */\nexport interface ValidateForCodeSigningInput\n\textends BuildCandidatePathInput,\n\t\tPolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides. */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides. */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n}\n/** Input for {@linkcode validateForCa}. Enforces `basicConstraints.ca` on the leaf. */\nexport interface ValidateForCaInput\n\textends BuildCandidatePathInput,\n\t\tPolicyValidationInput,\n\t\tInitialNameConstraintsInput {\n\t/** Nested policy validation overrides. */\n\treadonly policy?: PolicyValidationInput;\n\t/** Nested name constraint overrides. */\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n}\n\n// ---------------------------------------------------------------------------\n// Internal constants\n// ---------------------------------------------------------------------------\n\n/**\n * OIDs of extensions this verifier processes during path validation.\n * Per RFC 5280 §6.1, certificates with unrecognized critical extensions\n * that are not in this set must be rejected.\n */\nconst PROCESSED_EXTENSION_OIDS: ReadonlySet<string> = new Set([\n\tOIDS.basicConstraints,\n\tOIDS.keyUsage,\n\tOIDS.extendedKeyUsage,\n\tOIDS.subjectAltName,\n\tOIDS.nameConstraints,\n\tOIDS.authorityKeyIdentifier,\n\tOIDS.subjectKeyIdentifier,\n\tOIDS.authorityInfoAccess,\n\tOIDS.cRLDistributionPoints,\n\tOIDS.certificatePolicies,\n\tOIDS.policyMappings,\n\tOIDS.policyConstraints,\n\tOIDS.inhibitAnyPolicy,\n]);\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\n/** Loose input for building a {@linkcode VerifyFailureDetails} — accepts `undefined` values that get stripped. */\ninterface VerifyFailureDetailsInput {\n\treadonly subjectCommonName?: string | undefined;\n\treadonly issuerCommonName?: string | undefined;\n\treadonly expected?: string | undefined;\n\treadonly actual?: string | undefined;\n\treadonly chainCommonNames?: readonly string[] | undefined;\n\treadonly presentedIdentifierTypes?: readonly ('dns' | 'uri' | 'srv')[] | undefined;\n\treadonly commonNameFallbackReason?:\n\t\t| 'disabled'\n\t\t| 'suppressed_by_presented_identifier'\n\t\t| 'common_name_missing'\n\t\t| 'common_name_mismatch'\n\t\t| undefined;\n}\n\n/** Mutable validation state accumulated during path walks. */\ninterface ValidationState {\n\treadonly policy: PolicyValidationState;\n\treadonly nameConstraints: NameConstraintValidationState;\n}\n\n/** Optional nested policy and name-constraint inputs extracted from public input types. */\ninterface NestedValidationInputs {\n\treadonly policy?: PolicyValidationInput;\n\treadonly nameConstraints?: InitialNameConstraintsInput;\n}\n\n/** Result of initializing validation state — may fail if constraints are unsupported. */\ntype ValidationStateResult =\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: ValidationState;\n\t }\n\t| VerifyChainFailure;\n\n/** Pass/fail result for a single validation check (carries no value on success). */\ntype ValidationCheckResult =\n\t| {\n\t\t\treadonly ok: true;\n\t }\n\t| VerifyChainFailure;\n\n// ---------------------------------------------------------------------------\n// buildCandidatePath\n// ---------------------------------------------------------------------------\n\n/**\n * Discovers and signature-verifies a candidate certification path from a\n * leaf certificate to a trusted root or trust anchor. Does NOT validate\n * time, constraints, or leaf policy — use {@linkcode validateCandidatePath}\n * for that, or {@linkcode verifyCertificateChain} for the all-in-one API.\n */\nasync function buildCandidatePathRaw(input: BuildCandidatePathInput): Promise<\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: CandidatePath;\n\t }\n\t| VerifyChainFailure\n> {\n\tlet leaf: ParsedCertificate;\n\tlet intermediates: readonly ParsedCertificate[];\n\tlet roots: readonly ParsedCertificate[];\n\ttry {\n\t\tleaf = loadSingleCertificate(input.leaf);\n\t\tintermediates = loadCertificates(input.intermediates ?? []);\n\t\troots = loadCertificates(input.roots);\n\t} catch (error) {\n\t\treturn failure(\n\t\t\t'issuer_not_found',\n\t\t\t'certificate source is malformed or leaf source does not contain exactly one certificate',\n\t\t\t0,\n\t\t\tdetail({\n\t\t\t\tactual: error instanceof Error ? error.message : 'certificate source is malformed',\n\t\t\t}),\n\t\t);\n\t}\n\tconst anchors = input.trustAnchors ?? [];\n\tconst at = input.at ?? new Date();\n\tconst buildResult = await buildChainInternal(leaf, intermediates, roots, anchors, at, {\n\t\tfailure,\n\t\tdetail,\n\t});\n\tconst chain = buildResult.chain;\n\n\tif (!buildResult.foundTrustedRoot) {\n\t\tif (buildResult.failure !== undefined) {\n\t\t\treturn buildResult.failure;\n\t\t}\n\t\tif (buildResult.missingIssuerAt !== undefined) {\n\t\t\treturn failure(\n\t\t\t\t'issuer_not_found',\n\t\t\t\t'issuer certificate not found',\n\t\t\t\tbuildResult.missingIssuerAt,\n\t\t\t\tbuildFailureDetails(chain, buildResult.missingIssuerAt),\n\t\t\t);\n\t\t}\n\t\treturn failure(\n\t\t\t'no_trusted_root',\n\t\t\t'no trusted root found',\n\t\t\tundefined,\n\t\t\tdetail({\n\t\t\t\tchainCommonNames: chain.map(\n\t\t\t\t\t(certificate) => certificate.subject.values.commonName ?? '<unnamed>',\n\t\t\t\t),\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst root = chain[chain.length - 1];\n\tif (root === undefined) {\n\t\treturn failure('no_trusted_root', 'no trusted root found');\n\t}\n\n\treturn {\n\t\tok: true,\n\t\tvalue: {\n\t\t\tleaf,\n\t\t\tchain,\n\t\t\troot,\n\t\t},\n\t};\n}\n\n/**\n * Builds a signature-verified path from a leaf certificate to a trusted root.\n *\n * Parses the supplied certificates, walks the issuer chain, signature-checks\n * each link, and returns the first valid path. Does not enforce time, constraints,\n * or leaf purpose — call {@linkcode validateCandidatePath} or use the all-in-one\n * {@linkcode verifyCertificateChain} for full validation.\n *\n * @example\n * ```ts\n * import { buildCandidatePath } from 'micro509';\n *\n * const result = await buildCandidatePath({\n * leaf: leafPem,\n * intermediates: [intermediatePem],\n * roots: [rootPem],\n * });\n * if (result.ok) {\n * console.log('path length:', result.value.chain.length);\n * }\n * ```\n */\nexport async function buildCandidatePath(\n\tinput: BuildCandidatePathInput,\n): Promise<BuildCandidatePathResult> {\n\tconst result = await buildCandidatePathRaw(input);\n\treturn result.ok ? result : verifyFailureResult(result);\n}\n\n// ---------------------------------------------------------------------------\n// validatECandidatePath\n// ---------------------------------------------------------------------------\n\n/**\n * Validates a pre-built candidate path: time window, critical extensions,\n * inter-certificate signatures, CA/keyUsage/AKI constraints, pathLength,\n * policy processing, name constraints, and leaf purpose checks.\n *\n * The chain must be in leaf-to-root order. The root (last entry) is\n * assumed trusted and not re-verified.\n */\nasync function validateCandidatePathRaw(\n\tinput: ValidateCandidatePathInput,\n): Promise<ValidateCandidatePathRawResult> {\n\tconst chain = input.chain;\n\tconst at = input.at ?? new Date();\n\tconst validationStateResult = buildValidationState(input, chain.length);\n\tif (!validationStateResult.ok) {\n\t\treturn validationStateResult;\n\t}\n\tconst leaf = chain[0];\n\n\tif (leaf === undefined) {\n\t\treturn failure('issuer_not_found', 'chain is empty', 0);\n\t}\n\n\tif (chain.length === 1 && isSelfIssued(leaf)) {\n\t\tif (input.allowSelfSignedLeaf !== true) {\n\t\t\treturn failure(\n\t\t\t\t'self_signed_leaf_not_allowed',\n\t\t\t\t'self-signed leaf not allowed',\n\t\t\t\t0,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: leaf.subject.values.commonName,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tfor (let index = 0; index < chain.length; index += 1) {\n\t\tconst current = chain[index];\n\t\tif (current === undefined) {\n\t\t\treturn failure('issuer_not_found', 'chain element missing', index);\n\t\t}\n\t\tif (!isWithinValidity(current, at)) {\n\t\t\treturn failure(\n\t\t\t\t'certificate_expired',\n\t\t\t\t'certificate not valid at requested time',\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\texpected: describeDateTime(at),\n\t\t\t\t\tactual: `${describeDateTime(current.notBefore)}..${describeDateTime(current.notAfter)}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst unprocessedCritical = findUnprocessedCriticalExtension(current);\n\t\tif (unprocessedCritical !== undefined) {\n\t\t\treturn failure(\n\t\t\t\t'unrecognized_critical_extension',\n\t\t\t\t`certificate contains unrecognized critical extension ${unprocessedCritical}`,\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\tactual: unprocessedCritical,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (index === chain.length - 1) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst issuer = chain[index + 1];\n\t\tif (issuer === undefined) {\n\t\t\treturn failure('issuer_not_found', 'issuer missing', index);\n\t\t}\n\t\tconst signatureResult = await verifyCertificateSignature(current, issuer);\n\t\tif (!signatureResult.ok) {\n\t\t\treturn failure(\n\t\t\t\tsignatureResult.code,\n\t\t\t\tsignatureResult.reason,\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t\tactual: signatureResult.reason,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (!signatureResult.valid) {\n\t\t\treturn failure(\n\t\t\t\t'signature_invalid',\n\t\t\t\t'certificate signature does not verify',\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (issuer.basicConstraints?.ca !== true) {\n\t\t\treturn failure(\n\t\t\t\t'ca_required',\n\t\t\t\t'issuer must be a CA certificate',\n\t\t\t\tindex + 1,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (issuer.keyUsage !== undefined && !issuer.keyUsage.flags.includes('keyCertSign')) {\n\t\t\treturn failure(\n\t\t\t\t'key_cert_sign_required',\n\t\t\t\t'issuer missing keyCertSign',\n\t\t\t\tindex + 1,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tcurrent.authorityKeyIdentifier !== undefined &&\n\t\t\tissuer.subjectKeyIdentifier !== undefined &&\n\t\t\tcurrent.authorityKeyIdentifier !== issuer.subjectKeyIdentifier\n\t\t) {\n\t\t\treturn failure(\n\t\t\t\t'authority_key_identifier_mismatch',\n\t\t\t\t'authorityKeyIdentifier does not match issuer subjectKeyIdentifier',\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t\texpected: issuer.subjectKeyIdentifier,\n\t\t\t\t\tactual: current.authorityKeyIdentifier,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tfor (let index = 1; index < chain.length; index += 1) {\n\t\tconst current = chain[index];\n\t\tif (current === undefined) {\n\t\t\treturn failure('issuer_not_found', 'chain element missing', index);\n\t\t}\n\t\tconst maxCaBelow = countCaCertificatesBelowParsed(chain, index);\n\t\tconst pathLength = current.basicConstraints?.pathLength;\n\t\tif (isNonNegativeInteger(pathLength) && maxCaBelow > pathLength) {\n\t\t\treturn failure(\n\t\t\t\t'path_length_exceeded',\n\t\t\t\t'path length constraint exceeded',\n\t\t\t\tindex,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\texpected: String(pathLength),\n\t\t\t\t\tactual: String(maxCaBelow),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tconst policyResult = evaluatePolicyChain(chain, validationStateResult.value.policy);\n\tif (!policyResult.ok) {\n\t\treturn failure(\n\t\t\tpolicyResult.error.code,\n\t\t\tpolicyResult.error.message,\n\t\t\t0,\n\t\t\tdetail({\n\t\t\t\texpected: policyResult.error.details?.expected,\n\t\t\t\tactual: policyResult.error.details?.actual,\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst nameConstraintResult = evaluateNameConstraints(\n\t\tchain,\n\t\tvalidationStateResult.value.nameConstraints,\n\t);\n\tif (!nameConstraintResult.ok) {\n\t\treturn nameConstraintResult;\n\t}\n\n\treturn validateLeaf(leaf, input, policyResult.value);\n}\n\n/**\n * Validates a pre-built certificate chain for time, constraints, policy, and\n * optionally leaf purpose. Wrap the result of {@linkcode buildCandidatePath}.\n */\nexport async function validateCandidatePath(\n\tinput: ValidateCandidatePathInput,\n): Promise<ValidateCandidatePathResult> {\n\tlet normalizedChain: readonly ParsedCertificate[];\n\ttry {\n\t\tnormalizedChain = normalizeValidationChain(input.chain);\n\t} catch (error) {\n\t\treturn verifyFailureResult(\n\t\t\tfailure(\n\t\t\t\t'signature_invalid',\n\t\t\t\t'certificate input is malformed',\n\t\t\t\t0,\n\t\t\t\tdetail({\n\t\t\t\t\tactual: error instanceof Error ? error.message : 'certificate input is malformed',\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t}\n\tconst result = await validateCandidatePathRaw({ ...input, chain: normalizedChain });\n\treturn result.ok\n\t\t? validateCandidatePathSuccessResult(result.policyValidation)\n\t\t: verifyFailureResult(result);\n}\n\n// ---------------------------------------------------------------------------\n// verifyCertificateChain (convenience composition)\n// ---------------------------------------------------------------------------\n\n/**\n * All-in-one certificate chain verification: builds a candidate path then\n * validates time, constraints, policy, purpose, and optional service identity.\n *\n * Equivalent to calling {@linkcode buildCandidatePath} followed by\n * {@linkcode validateCandidatePath} (plus identity matching when configured).\n *\n * @example\n * ```ts\n * import { verifyCertificateChain } from 'micro509';\n *\n * const result = await verifyCertificateChain({\n * leaf: serverCertPem,\n * intermediates: [intermediatePem],\n * roots: [rootCaPem],\n * purpose: 'serverAuth',\n * serviceIdentity: { type: 'dns', value: 'example.com' },\n * });\n * if (!result.ok) {\n * console.error(result.error.code, result.error.message);\n * }\n * ```\n */\nexport async function verifyCertificateChain(\n\tinput: VerifyCertificateChainInput,\n): Promise<VerifyChainResult> {\n\tconst buildResult = await buildCandidatePath({\n\t\tleaf: input.leaf,\n\t\troots: input.roots,\n\t\t...(input.intermediates !== undefined && {\n\t\t\tintermediates: input.intermediates,\n\t\t}),\n\t\t...(input.trustAnchors !== undefined && {\n\t\t\ttrustAnchors: input.trustAnchors,\n\t\t}),\n\t\t...(input.at !== undefined && { at: input.at }),\n\t});\n\tif (!buildResult.ok) {\n\t\treturn buildResult;\n\t}\n\n\tconst validateResult = await validateCandidatePath({\n\t\tchain: buildResult.value.chain,\n\t\t...(input.at !== undefined && { at: input.at }),\n\t\t...(input.purpose !== undefined && { purpose: input.purpose }),\n\t\t...copyValidationInputs(input),\n\t\t...(input.allowSelfSignedLeaf !== undefined && {\n\t\t\tallowSelfSignedLeaf: input.allowSelfSignedLeaf,\n\t\t}),\n\t});\n\tif (!validateResult.ok) {\n\t\treturn validateResult;\n\t}\n\tif (input.serviceIdentity !== undefined) {\n\t\tconst serviceIdentityResult = validateServiceIdentity(\n\t\t\tbuildResult.value.leaf,\n\t\t\tinput.serviceIdentity,\n\t\t);\n\t\tif (!serviceIdentityResult.ok) {\n\t\t\treturn verifyFailureResult(serviceIdentityResult);\n\t\t}\n\t}\n\n\t// Revocation checking (optional)\n\tif (input.revocation !== undefined) {\n\t\tconst revocationResult = await checkChainRevocation({\n\t\t\tchain: buildResult.value.chain,\n\t\t\t...(input.revocation.crls !== undefined ? { crls: input.revocation.crls } : {}),\n\t\t\t...(input.revocation.ocspResponses !== undefined\n\t\t\t\t? { ocspResponses: input.revocation.ocspResponses }\n\t\t\t\t: {}),\n\t\t\t...(input.revocation.extraCertificates !== undefined\n\t\t\t\t? { extraCertificates: input.revocation.extraCertificates }\n\t\t\t\t: {}),\n\t\t\t...(input.revocation.policy !== undefined ? { policy: input.revocation.policy } : {}),\n\t\t\t...(input.at !== undefined ? { at: input.at } : {}),\n\t\t});\n\n\t\tif (revocationResult.value.decision === 'deny') {\n\t\t\tconst firstRevoked = revocationResult.value.summary.revokedCertificates[0];\n\t\t\tif (firstRevoked !== undefined) {\n\t\t\t\treturn verifyFailureResult(\n\t\t\t\t\tfailure(\n\t\t\t\t\t\t'certificate_revoked',\n\t\t\t\t\t\t`certificate revoked: ${firstRevoked.subject.values.commonName ?? 'unknown'}`,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tdetail({ subjectCommonName: firstRevoked.subject.values.commonName }),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Indeterminate with hard-fail policy\n\t\t\tconst firstIndeterminate = revocationResult.value.summary.indeterminateCertificates[0];\n\t\t\tconst indeterminateReasons = revocationResult.value.certificates.find(\n\t\t\t\t(c) => c.status === 'indeterminate',\n\t\t\t)?.indeterminateReasons;\n\t\t\treturn verifyFailureResult(\n\t\t\t\tfailure(\n\t\t\t\t\t'revocation_indeterminate',\n\t\t\t\t\t`revocation status indeterminate: ${firstIndeterminate?.subject.values.commonName ?? 'unknown'}`,\n\t\t\t\t\tundefined,\n\t\t\t\t\tdetail({\n\t\t\t\t\t\tsubjectCommonName: firstIndeterminate?.subject.values.commonName,\n\t\t\t\t\t\tactual: indeterminateReasons?.join(', '),\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn {\n\t\tok: true,\n\t\tvalue: {\n\t\t\t...buildResult.value,\n\t\t\tpolicyValidation: validateResult.value.policyValidation,\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// verifyCertificateSigningRequest\n// ---------------------------------------------------------------------------\n\n/**\n * Verifies the self-signature of a PKCS#10 certificate signing request.\n *\n * Parses the CSR from PEM or DER, then checks that its signature is valid\n * against its own embedded public key.\n *\n * @example\n * ```ts\n * import { verifyCertificateSigningRequest } from 'micro509';\n *\n * const result = await verifyCertificateSigningRequest(csrPem);\n * if (result.ok) {\n * console.log('subject:', result.value.subject.values.commonName);\n * }\n * ```\n */\nexport async function verifyCertificateSigningRequest(\n\tinput: CsrSource,\n): Promise<VerifyRequestResult> {\n\tlet parsed: ParsedCertificateSigningRequest;\n\ttry {\n\t\tparsed =\n\t\t\ttypeof input === 'string'\n\t\t\t\t? parseCertificateSigningRequestPem(input)\n\t\t\t\t: parseCertificateSigningRequestDer(new Uint8Array(input));\n\t} catch (error) {\n\t\treturn verifyRequestFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'certificate request input is malformed',\n\t\t\tdetail({\n\t\t\t\tactual: error instanceof Error ? error.message : 'certificate request input is malformed',\n\t\t\t}),\n\t\t);\n\t}\n\tlet signatureResult: Awaited<ReturnType<typeof verifySignedDataDetailed>>;\n\ttry {\n\t\tsignatureResult = await verifySignedDataDetailed(\n\t\t\tparsed.signatureAlgorithmOid,\n\t\t\tparsed.signatureAlgorithmParametersDer,\n\t\t\tparsed.publicKeyAlgorithmOid,\n\t\t\tparsed.publicKeyParametersOid,\n\t\t\tparsed.subjectPublicKeyInfoDer,\n\t\t\tparsed.signatureValue,\n\t\t\tparsed.certificationRequestInfoDer,\n\t\t);\n\t} catch (error) {\n\t\treturn verifyRequestFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'certificate request input is malformed',\n\t\t\tdetail({\n\t\t\t\tsubjectCommonName: parsed.subject.values.commonName,\n\t\t\t\tactual: error instanceof Error ? error.message : 'certificate request input is malformed',\n\t\t\t}),\n\t\t);\n\t}\n\tif (!signatureResult.ok) {\n\t\tconst code =\n\t\t\tsignatureResult.code === 'verification_error' ? 'signature_invalid' : signatureResult.code;\n\t\treturn verifyRequestFailureResult(\n\t\t\tcode,\n\t\t\tsignatureResult.reason,\n\t\t\tdetail({\n\t\t\t\tsubjectCommonName: parsed.subject.values.commonName,\n\t\t\t\tactual: signatureResult.reason,\n\t\t\t}),\n\t\t);\n\t}\n\tif (!signatureResult.valid) {\n\t\treturn verifyRequestFailureResult(\n\t\t\t'signature_invalid',\n\t\t\t'certificate request signature does not verify',\n\t\t\tdetail({ subjectCommonName: parsed.subject.values.commonName }),\n\t\t);\n\t}\n\treturn { ok: true, value: parsed };\n}\n\n// ---------------------------------------------------------------------------\n// checkExtendedKeyUsage\n// ---------------------------------------------------------------------------\n\n/**\n * Standalone EKU check against a verified certificate chain.\n * Validates that the leaf has the requested purpose and that\n * intermediate CA EKU constraints (if present) permit it.\n *\n * @example\n * ```ts\n * import { checkExtendedKeyUsage } from 'micro509';\n *\n * const result = checkExtendedKeyUsage(chain, 'serverAuth');\n * if (!result.ok) {\n * console.error(result.error.code, result.error.message);\n * }\n * ```\n */\nexport function checkExtendedKeyUsage(\n\tchain: readonly ParsedCertificate[],\n\tpurpose: EkuCheckPurpose,\n): EkuCheckResult {\n\tlet normalizedChain: readonly ParsedCertificate[];\n\ttry {\n\t\tnormalizedChain = normalizeValidationChain(chain);\n\t} catch {\n\t\treturn ekuCheckFailureResult('leaf_eku_missing', 'certificate input is malformed', 0);\n\t}\n\tconst leaf = normalizedChain[0];\n\tif (leaf === undefined) {\n\t\treturn ekuCheckFailureResult('leaf_eku_missing', 'chain is empty', 0);\n\t}\n\tif (leaf.extendedKeyUsage !== undefined && !leaf.extendedKeyUsage.includes(purpose)) {\n\t\treturn ekuCheckFailureResult(\n\t\t\t'leaf_eku_missing',\n\t\t\t`leaf certificate does not include EKU ${purpose}`,\n\t\t\t0,\n\t\t);\n\t}\n\tfor (let index = 1; index < normalizedChain.length; index += 1) {\n\t\tconst intermediate = normalizedChain[index];\n\t\tif (intermediate === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\tintermediate.extendedKeyUsage !== undefined &&\n\t\t\t!intermediate.extendedKeyUsage.includes(purpose)\n\t\t) {\n\t\t\treturn ekuCheckFailureResult(\n\t\t\t\t'intermediate_eku_constraint',\n\t\t\t\t`intermediate CA at index ${String(index)} constrains EKU and does not include ${purpose}`,\n\t\t\t\tindex,\n\t\t\t);\n\t\t}\n\t}\n\treturn { ok: true, value: undefined };\n}\n\n// ---------------------------------------------------------------------------\n// trustAnchorFromCertificate\n// ---------------------------------------------------------------------------\n\n/** Extracts a {@linkcode TrustAnchor} from a parsed certificate, copying the subject, SPKI, and key identifiers. */\nexport function trustAnchorFromCertificate(certificate: ParsedCertificate): TrustAnchor {\n\tlet normalizedCertificate: ParsedCertificate;\n\ttry {\n\t\tnormalizedCertificate = reparseCertificateForTrust(certificate);\n\t} catch {\n\t\tthrow new Error('certificate input is malformed');\n\t}\n\treturn {\n\t\tsubject: normalizedCertificate.subject,\n\t\tsubjectPublicKeyInfoDer: normalizedCertificate.subjectPublicKeyInfoDer,\n\t\tpublicKeyAlgorithmOid: normalizedCertificate.publicKeyAlgorithmOid,\n\t\t...(normalizedCertificate.publicKeyParametersOid === undefined\n\t\t\t? {}\n\t\t\t: { publicKeyParametersOid: normalizedCertificate.publicKeyParametersOid }),\n\t\t...(normalizedCertificate.subjectKeyIdentifier === undefined\n\t\t\t? {}\n\t\t\t: { subjectKeyIdentifier: normalizedCertificate.subjectKeyIdentifier }),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Validation profiles\n// ---------------------------------------------------------------------------\n\n/** Extracts defined optional fields from a base input for safe forwarding. */\nfunction baseChainInput(\n\tinput: BuildCandidatePathInput &\n\t\tPolicyValidationInput &\n\t\tInitialNameConstraintsInput &\n\t\tNestedValidationInputs,\n): VerifyCertificateChainInput {\n\treturn {\n\t\tleaf: input.leaf,\n\t\troots: input.roots,\n\t\t...(input.intermediates !== undefined && {\n\t\t\tintermediates: input.intermediates,\n\t\t}),\n\t\t...(input.trustAnchors !== undefined && {\n\t\t\ttrustAnchors: input.trustAnchors,\n\t\t}),\n\t\t...(input.at !== undefined && { at: input.at }),\n\t\t...copyValidationInputs(input),\n\t};\n}\n\n/**\n * Validates a certificate chain for TLS server use:\n * chain verification + `serverAuth` EKU (leaf + intermediate propagation)\n * + DNS/IP identity matching.\n *\n * @example\n * ```ts\n * import { validateForTlsServer } from 'micro509';\n *\n * const result = await validateForTlsServer({\n * leaf: serverCertPem,\n * roots: [rootCaPem],\n * serviceIdentity: { type: 'dns', value: 'example.com' },\n * });\n * if (result.ok) {\n * console.log('valid for', result.value.leaf.subject.values.commonName);\n * }\n * ```\n */\nexport async function validateForTlsServer(\n\tinput: ValidateForTlsServerInput,\n): Promise<VerifyChainResult> {\n\tconst result = await verifyChainForExtendedKeyUsageProfile(input, 'serverAuth');\n\tif (!result.ok) {\n\t\treturn result;\n\t}\n\tif (input.serviceIdentity !== undefined) {\n\t\tconst serviceIdentityResult = validateServiceIdentity(result.value.leaf, input.serviceIdentity);\n\t\tif (!serviceIdentityResult.ok) {\n\t\t\treturn verifyFailureResult(serviceIdentityResult);\n\t\t}\n\t}\n\treturn result;\n}\n\n/**\n * Validates a certificate chain for TLS client use:\n * chain verification + `clientAuth` EKU (leaf + intermediate propagation).\n *\n * @example\n * ```ts\n * import { validateForTlsClient } from 'micro509';\n *\n * const result = await validateForTlsClient({\n * leaf: clientCertPem,\n * roots: [rootCaPem],\n * });\n * ```\n */\nexport async function validateForTlsClient(\n\tinput: ValidateForTlsClientInput,\n): Promise<VerifyChainResult> {\n\treturn verifyChainForExtendedKeyUsageProfile(input, 'clientAuth');\n}\n\n/**\n * Validates a certificate chain for code signing:\n * chain verification + `codeSigning` EKU (leaf + intermediate propagation).\n *\n * @example\n * ```ts\n * import { validateForCodeSigning } from 'micro509';\n *\n * const result = await validateForCodeSigning({\n * leaf: codeSigningCertPem,\n * roots: [rootCaPem],\n * });\n * ```\n */\nexport async function validateForCodeSigning(\n\tinput: ValidateForCodeSigningInput,\n): Promise<VerifyChainResult> {\n\treturn verifyChainForExtendedKeyUsageProfile(input, 'codeSigning');\n}\n\n/**\n * Validates a certificate chain for CA use:\n * chain verification + `basicConstraints.ca` check on the leaf.\n *\n * @example\n * ```ts\n * import { validateForCa } from 'micro509';\n *\n * const result = await validateForCa({\n * leaf: intermediateCertPem,\n * roots: [rootCaPem],\n * });\n * ```\n */\nexport async function validateForCa(input: ValidateForCaInput): Promise<VerifyChainResult> {\n\treturn verifyCertificateChain({\n\t\t...baseChainInput(input),\n\t\tpurpose: 'ca',\n\t});\n}\n\n// ---------------------------------------------------------------------------\n// Private: leaf validation\n// ---------------------------------------------------------------------------\n\n/** Enforces purpose-specific constraints on the leaf certificate (CA flag or EKU). */\nfunction validateLeaf(\n\tleaf: ParsedCertificate,\n\tinput: {\n\t\treadonly purpose?: VerifyPurpose;\n\t},\n\tpolicyValidation: PolicyValidationOutcome,\n): ValidateCandidatePathRawResult {\n\tconst purpose = input.purpose;\n\tif (purpose !== undefined) {\n\t\tif (purpose === 'ca') {\n\t\t\tif (leaf.basicConstraints?.ca !== true) {\n\t\t\t\treturn failure(\n\t\t\t\t\t'ca_required',\n\t\t\t\t\t'leaf is not a CA certificate',\n\t\t\t\t\t0,\n\t\t\t\t\tdetail({\n\t\t\t\t\t\tsubjectCommonName: leaf.subject.values.commonName,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (leaf.extendedKeyUsage !== undefined && !leaf.extendedKeyUsage.includes(purpose)) {\n\t\t\treturn failure(\n\t\t\t\t'extended_key_usage_invalid',\n\t\t\t\t`leaf missing EKU ${purpose}`,\n\t\t\t\t0,\n\t\t\t\tdetail({\n\t\t\t\t\tsubjectCommonName: leaf.subject.values.commonName,\n\t\t\t\t\texpected: purpose,\n\t\t\t\t\tactual: leaf.extendedKeyUsage.map(formatEku).join(','),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\treturn { ok: true, policyValidation };\n}\n\n/** Matches the leaf's SAN against the requested service identity. */\nfunction validateServiceIdentity(\n\tleaf: ParsedCertificate,\n\tserviceIdentity: VerifyServiceIdentityInput,\n): ValidationCheckResult {\n\tconst malformedInput = validateVerifyServiceIdentityInput(serviceIdentity);\n\tif (!malformedInput.ok) {\n\t\treturn malformedInput;\n\t}\n\tconst result = matchServiceIdentity({\n\t\tcertificate: reparseCertificateForTrust(leaf),\n\t\tserviceIdentity,\n\t});\n\tif (result.ok) {\n\t\treturn { ok: true };\n\t}\n\tconst error = result.error;\n\tif (\n\t\terror.code !== 'subject_alt_name_mismatch' &&\n\t\terror.code !== 'common_name_fallback_suppressed'\n\t) {\n\t\treturn failure(\n\t\t\t'subject_alt_name_mismatch',\n\t\t\t'service identity input is malformed',\n\t\t\t0,\n\t\t\tdetail({ expected: serviceIdentity.value, actual: error.code }),\n\t\t);\n\t}\n\treturn {\n\t\tok: false,\n\t\tcode: error.code,\n\t\tmessage: error.message,\n\t\tindex: 0,\n\t\t...(error.details === undefined ? {} : { details: error.details }),\n\t};\n}\n\nfunction validateVerifyServiceIdentityInput(\n\tserviceIdentity: VerifyServiceIdentityInput,\n): ValidationCheckResult {\n\tif (!isRecord(serviceIdentity)) {\n\t\treturn failure('subject_alt_name_mismatch', 'service identity input is malformed', 0);\n\t}\n\tif (serviceIdentity.type !== 'dns' && serviceIdentity.type !== 'ip') {\n\t\treturn failure(\n\t\t\t'subject_alt_name_mismatch',\n\t\t\t'service identity input is malformed',\n\t\t\t0,\n\t\t\tdetail({ actual: String(serviceIdentity.type) }),\n\t\t);\n\t}\n\tif (typeof serviceIdentity.value !== 'string') {\n\t\treturn failure(\n\t\t\t'subject_alt_name_mismatch',\n\t\t\t'service identity input is malformed',\n\t\t\t0,\n\t\t\tdetail({ actual: serviceIdentity.type }),\n\t\t);\n\t}\n\tif (serviceIdentity.type === 'ip') {\n\t\ttry {\n\t\t\tparseIpAddressToBytes(serviceIdentity.value);\n\t\t} catch {\n\t\t\treturn failure(\n\t\t\t\t'subject_alt_name_mismatch',\n\t\t\t\t'service identity input is malformed',\n\t\t\t\t0,\n\t\t\t\tdetail({ expected: serviceIdentity.value, actual: 'ip' }),\n\t\t\t);\n\t\t}\n\t}\n\treturn { ok: true };\n}\n\n// ---------------------------------------------------------------------------\n// Private: helpers\n// ---------------------------------------------------------------------------\n\n/** Applies an EKU check to a successfully verified chain and maps failures to verify error codes. */\nfunction applyEkuCheck(\n\tresult: {\n\t\treadonly ok: true;\n\t\treadonly value: VerifiedCertificateChain;\n\t},\n\tpurpose: EkuCheckPurpose,\n): VerifyChainResult {\n\tconst ekuCheck = checkExtendedKeyUsage(result.value.chain, purpose);\n\tif (!ekuCheck.ok) {\n\t\treturn verifyFailureResult(\n\t\t\tfailure(\n\t\t\t\tekuCheck.code === 'leaf_eku_missing'\n\t\t\t\t\t? 'extended_key_usage_invalid'\n\t\t\t\t\t: 'intermediate_eku_constraint',\n\t\t\t\tekuCheck.message,\n\t\t\t\tekuCheck.index,\n\t\t\t),\n\t\t);\n\t}\n\treturn result;\n}\n\n/** Verifies a chain then checks that all certificates permit the given EKU purpose. */\nasync function verifyChainForExtendedKeyUsageProfile(\n\tinput: BuildCandidatePathInput & PolicyValidationInput & InitialNameConstraintsInput,\n\tpurpose: EkuCheckPurpose,\n): Promise<VerifyChainResult> {\n\tconst result = await verifyCertificateChain(baseChainInput(input));\n\tif (!result.ok) {\n\t\treturn result;\n\t}\n\treturn applyEkuCheck(result, purpose);\n}\n\n/** Returns the OID of the first critical extension not in {@linkcode PROCESSED_EXTENSION_OIDS}, or `undefined`. */\nfunction findUnprocessedCriticalExtension(certificate: ParsedCertificate): string | undefined {\n\tfor (const extension of certificate.extensions) {\n\t\tif (extension.critical && !PROCESSED_EXTENSION_OIDS.has(extension.oid)) {\n\t\t\treturn extension.oid;\n\t\t}\n\t}\n\treturn undefined;\n}\n\n/** Constructs a {@linkcode VerifyChainFailure} with the given code, message, optional chain index, and details. */\nfunction failure(\n\tcode: VerifyErrorCode,\n\tmessage: string,\n\tindex?: number,\n\tdetails?: VerifyFailureDetails,\n): VerifyChainFailure {\n\treturn {\n\t\tok: false,\n\t\t...indexedMicro509Error(code, message, index, details),\n\t};\n}\n\n/** Wraps a {@linkcode VerifyChainFailure} into the standard indexed error result shape. */\nfunction verifyFailureResult(\n\terror: VerifyChainFailure,\n): IndexedErrorResult<VerifyErrorCode, VerifyFailureDetails, VerifyChainFailure> {\n\treturn indexedErrorResult(error);\n}\n\n/** Wraps a policy outcome into the validate-candidate-path success result shape. */\nfunction validateCandidatePathSuccessResult(\n\tpolicyValidation: PolicyValidationOutcome,\n): Extract<ValidateCandidatePathResult, { readonly ok: true }> {\n\treturn {\n\t\tok: true,\n\t\tvalue: { policyValidation },\n\t\tpolicyValidation,\n\t};\n}\n\n/** Describes a date in ISO format, or `'<invalid date>'` if invalid. */\nfunction describeDateTime(value: Date): string {\n\treturn Number.isNaN(value.getTime()) ? '<invalid date>' : value.toISOString();\n}\n\nfunction normalizeValidationChain(\n\tchain: readonly ParsedCertificate[],\n): readonly ParsedCertificate[] {\n\treturn chain.map(reparseCertificateForTrust);\n}\n\nfunction reparseCertificateForTrust(certificate: ParsedCertificate): ParsedCertificate {\n\treturn parseCertificateDer(new Uint8Array(certificate.der));\n}\n\n/** Returns `true` if the value is a non-negative integer (including zero). */\nfunction isNonNegativeInteger(value: number | undefined): value is number {\n\treturn value !== undefined && Number.isInteger(value) && value >= 0;\n}\n\n/** Constructs a CSR verification failure result. */\nfunction verifyRequestFailureResult(\n\tcode: VerifyRequestFailure['code'],\n\tmessage: string,\n\tdetails?: VerifyFailureDetails,\n): ErrorResult<\n\t'signature_invalid' | 'unsupported_signature_algorithm_parameters',\n\tVerifyFailureDetails,\n\tVerifyRequestFailure\n> {\n\tconst error: VerifyRequestFailure = {\n\t\tok: false,\n\t\t...micro509Error(code, message, details),\n\t};\n\treturn errorResult(error);\n}\n\n/** Constructs an EKU check failure result at the given chain index. */\nfunction ekuCheckFailureResult(\n\tcode: EkuCheckFailure['code'],\n\tmessage: string,\n\tindex: number,\n): IndexedErrorResult<\n\t'leaf_eku_missing' | 'intermediate_eku_constraint',\n\tRecord<never, never>,\n\tEkuCheckFailure\n> {\n\tconst error: EkuCheckFailure = {\n\t\tok: false,\n\t\t...indexedMicro509Error(code, message, index),\n\t\tindex,\n\t};\n\treturn indexedErrorResult(error);\n}\n\n/** Merges flat and nested policy fields, with nested taking precedence. */\nfunction resolvePolicyValidationInput(\n\tinput: NestedValidationInputs & PolicyValidationInput,\n): PolicyValidationInput {\n\tconst flatInitialPolicySet = normalizeInitialPolicySet(input.initialPolicySet);\n\tconst nestedInitialPolicySet = normalizeInitialPolicySet(input.policy?.initialPolicySet);\n\treturn {\n\t\t...(flatInitialPolicySet === undefined ? {} : { initialPolicySet: flatInitialPolicySet }),\n\t\t...(input.requireExplicitPolicy === undefined\n\t\t\t? {}\n\t\t\t: { requireExplicitPolicy: input.requireExplicitPolicy }),\n\t\t...(input.inhibitPolicyMapping === undefined\n\t\t\t? {}\n\t\t\t: { inhibitPolicyMapping: input.inhibitPolicyMapping }),\n\t\t...(input.inhibitAnyPolicy === undefined ? {} : { inhibitAnyPolicy: input.inhibitAnyPolicy }),\n\t\t...(nestedInitialPolicySet === undefined ? {} : { initialPolicySet: nestedInitialPolicySet }),\n\t\t...(input.policy?.requireExplicitPolicy === undefined\n\t\t\t? {}\n\t\t\t: { requireExplicitPolicy: input.policy.requireExplicitPolicy }),\n\t\t...(input.policy?.inhibitPolicyMapping === undefined\n\t\t\t? {}\n\t\t\t: { inhibitPolicyMapping: input.policy.inhibitPolicyMapping }),\n\t\t...(input.policy?.inhibitAnyPolicy === undefined\n\t\t\t? {}\n\t\t\t: { inhibitAnyPolicy: input.policy.inhibitAnyPolicy }),\n\t};\n}\n\n/** Merges flat and nested name-constraint fields, with nested taking precedence. */\nfunction resolveInitialNameConstraintsInput(\n\tinput: NestedValidationInputs & InitialNameConstraintsInput,\n): InitialNameConstraintsInput {\n\treturn {\n\t\t...(input.permittedSubtrees === undefined\n\t\t\t? {}\n\t\t\t: { permittedSubtrees: input.permittedSubtrees }),\n\t\t...(input.excludedSubtrees === undefined ? {} : { excludedSubtrees: input.excludedSubtrees }),\n\t\t...(input.nameConstraints?.permittedSubtrees === undefined\n\t\t\t? {}\n\t\t\t: { permittedSubtrees: input.nameConstraints.permittedSubtrees }),\n\t\t...(input.nameConstraints?.excludedSubtrees === undefined\n\t\t\t? {}\n\t\t\t: { excludedSubtrees: input.nameConstraints.excludedSubtrees }),\n\t};\n}\n\n/** Extracts the resolved policy and name-constraint inputs for forwarding. */\nfunction copyValidationInputs(\n\tinput: NestedValidationInputs & PolicyValidationInput & InitialNameConstraintsInput,\n): NestedValidationInputs {\n\tconst policy = resolvePolicyValidationInput(input);\n\tconst nameConstraints = resolveInitialNameConstraintsInput(input);\n\treturn {\n\t\t...(hasPolicyValidationInput(policy) ? { policy } : {}),\n\t\t...(hasInitialNameConstraintsInput(nameConstraints) ? { nameConstraints } : {}),\n\t};\n}\n\n/** Returns `true` if any policy validation field is defined. */\nfunction hasPolicyValidationInput(input: PolicyValidationInput): boolean {\n\treturn (\n\t\tinput.initialPolicySet !== undefined ||\n\t\tinput.requireExplicitPolicy !== undefined ||\n\t\tinput.inhibitPolicyMapping !== undefined ||\n\t\tinput.inhibitAnyPolicy !== undefined\n\t);\n}\n\n/** Returns `true` if any initial name constraint field is defined. */\nfunction hasInitialNameConstraintsInput(input: InitialNameConstraintsInput): boolean {\n\treturn input.permittedSubtrees !== undefined || input.excludedSubtrees !== undefined;\n}\n\n/** Constructs failure details with subject/issuer CNs and full chain CN list. */\nfunction buildFailureDetails(\n\tchain: readonly ParsedCertificate[],\n\tindex: number,\n): VerifyFailureDetails {\n\tconst certificate = chain[index];\n\treturn detail({\n\t\tsubjectCommonName: certificate?.subject.values.commonName,\n\t\tissuerCommonName: certificate?.issuer.values.commonName,\n\t\tchainCommonNames: chain.map((entry) => entry.subject.values.commonName ?? '<unnamed>'),\n\t});\n}\n\n/** Formats an EKU value as a human-readable string (name or raw OID). */\nfunction formatEku(value: ExtendedKeyUsage): string {\n\treturn typeof value === 'string' ? value : value.value;\n}\n\n/** Strips `undefined` values from a loose input to produce a clean {@linkcode VerifyFailureDetails}. */\nfunction detail(input: VerifyFailureDetailsInput): VerifyFailureDetails {\n\treturn {\n\t\t...(input.subjectCommonName === undefined\n\t\t\t? {}\n\t\t\t: { subjectCommonName: input.subjectCommonName }),\n\t\t...(input.issuerCommonName === undefined ? {} : { issuerCommonName: input.issuerCommonName }),\n\t\t...(input.expected === undefined ? {} : { expected: input.expected }),\n\t\t...(input.actual === undefined ? {} : { actual: input.actual }),\n\t\t...(input.chainCommonNames === undefined ? {} : { chainCommonNames: input.chainCommonNames }),\n\t\t...(input.presentedIdentifierTypes === undefined\n\t\t\t? {}\n\t\t\t: { presentedIdentifierTypes: input.presentedIdentifierTypes }),\n\t\t...(input.commonNameFallbackReason === undefined\n\t\t\t? {}\n\t\t\t: { commonNameFallbackReason: input.commonNameFallbackReason }),\n\t};\n}\n\n/** Initializes policy and name-constraint validation state for a chain walk. */\nfunction buildValidationState(\n\tinput: NestedValidationInputs & PolicyValidationInput & InitialNameConstraintsInput,\n\tchainLength: number,\n): ValidationStateResult {\n\tconst policy = createPolicyValidationState(resolvePolicyValidationInput(input), chainLength);\n\tconst initialNameConstraintsValidation = validateInitialNameConstraintsInput(\n\t\tresolveInitialNameConstraintsInput(input),\n\t);\n\tif (!initialNameConstraintsValidation.ok) {\n\t\treturn initialNameConstraintsValidation;\n\t}\n\tconst nameConstraints = createNameConstraintValidationState(\n\t\tinitialNameConstraintsValidation.value,\n\t);\n\treturn {\n\t\tok: true,\n\t\tvalue: {\n\t\t\tpolicy,\n\t\t\tnameConstraints,\n\t\t},\n\t};\n}\n\nfunction normalizeInitialPolicySet(\n\tinitialPolicySet: PolicyValidationInput['initialPolicySet'] | undefined,\n): PolicyValidationInput['initialPolicySet'] | undefined {\n\tif (initialPolicySet === undefined || initialPolicySet === 'any') {\n\t\treturn initialPolicySet;\n\t}\n\tif (!Array.isArray(initialPolicySet)) {\n\t\treturn [];\n\t}\n\treturn initialPolicySet.every((policyIdentifier) => typeof policyIdentifier === 'string')\n\t\t? initialPolicySet\n\t\t: [];\n}\n\nfunction validateInitialNameConstraintsInput(input: InitialNameConstraintsInput):\n\t| {\n\t\t\treadonly ok: true;\n\t\t\treadonly value: InitialNameConstraintsInput;\n\t }\n\t| VerifyChainFailure {\n\tconst permittedValidation = validateInitialNameConstraintSubtrees(\n\t\tinput.permittedSubtrees,\n\t\t'permittedSubtrees',\n\t);\n\tif (!permittedValidation.ok) {\n\t\treturn permittedValidation;\n\t}\n\tconst excludedValidation = validateInitialNameConstraintSubtrees(\n\t\tinput.excludedSubtrees,\n\t\t'excludedSubtrees',\n\t);\n\tif (!excludedValidation.ok) {\n\t\treturn excludedValidation;\n\t}\n\treturn { ok: true, value: input };\n}\n\nfunction validateInitialNameConstraintSubtrees(\n\tsubtrees:\n\t\t| InitialNameConstraintsInput['permittedSubtrees']\n\t\t| InitialNameConstraintsInput['excludedSubtrees'],\n\tlabel: 'permittedSubtrees' | 'excludedSubtrees',\n): { readonly ok: true } | VerifyChainFailure {\n\tif (subtrees === undefined) {\n\t\treturn { ok: true };\n\t}\n\tif (!Array.isArray(subtrees)) {\n\t\treturn invalidInitialNameConstraintsFailure(label);\n\t}\n\tfor (const subtree of subtrees) {\n\t\tconst invalidForm = describeInvalidInitialNameConstraintForm(subtree);\n\t\tif (invalidForm !== undefined) {\n\t\t\treturn invalidInitialNameConstraintsFailure(invalidForm);\n\t\t}\n\t}\n\treturn { ok: true };\n}\n\nfunction describeInvalidInitialNameConstraintForm(subtree: unknown): string | undefined {\n\tif (!isRecord(subtree)) {\n\t\treturn 'invalid subtree';\n\t}\n\tconst base = subtree.base;\n\tif (!isRecord(base) || typeof base.type !== 'string') {\n\t\treturn 'invalid subtree';\n\t}\n\tswitch (base.type) {\n\t\tcase 'dns':\n\t\tcase 'email':\n\t\tcase 'uri':\n\t\t\treturn typeof base.value === 'string' ? undefined : base.type;\n\t\tcase 'directoryName':\n\t\t\treturn typeof base.derHex === 'string' ? undefined : base.type;\n\t\tcase 'ip':\n\t\t\treturn base.addressBytes instanceof Uint8Array && base.maskBytes instanceof Uint8Array\n\t\t\t\t? undefined\n\t\t\t\t: base.type;\n\t\tcase 'otherName':\n\t\tcase 'x400Address':\n\t\tcase 'ediPartyName':\n\t\tcase 'registeredID':\n\t\t\treturn base.type;\n\t\tdefault:\n\t\t\treturn base.type;\n\t}\n}\n\nfunction invalidInitialNameConstraintsFailure(actual: string): VerifyChainFailure {\n\treturn failure(\n\t\t'initial_name_constraints_not_implemented',\n\t\t'initial name constraints use unsupported or malformed forms',\n\t\tundefined,\n\t\tdetail({ actual }),\n\t);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null;\n}\n"],"mappings":"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"}