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.
- package/LICENSE +22 -0
- package/README.md +220 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1 -0
- package/dist/internal/asn1/asn1.js +2 -0
- package/dist/internal/asn1/asn1.js.map +1 -0
- package/dist/internal/asn1/der.js +2 -0
- package/dist/internal/asn1/der.js.map +1 -0
- package/dist/internal/asn1/oids.js +2 -0
- package/dist/internal/asn1/oids.js.map +1 -0
- package/dist/internal/crypto/algorithm-names.js +2 -0
- package/dist/internal/crypto/algorithm-names.js.map +1 -0
- package/dist/internal/crypto/ecdsa.js +2 -0
- package/dist/internal/crypto/ecdsa.js.map +1 -0
- package/dist/internal/crypto/hash.js +2 -0
- package/dist/internal/crypto/hash.js.map +1 -0
- package/dist/internal/crypto/pbes2.d.ts +23 -0
- package/dist/internal/crypto/pbes2.js +2 -0
- package/dist/internal/crypto/pbes2.js.map +1 -0
- package/dist/internal/crypto/rsa-pss.js +2 -0
- package/dist/internal/crypto/rsa-pss.js.map +1 -0
- package/dist/internal/crypto/sig-verify.js +2 -0
- package/dist/internal/crypto/sig-verify.js.map +1 -0
- package/dist/internal/crypto/signing.d.ts +16 -0
- package/dist/internal/crypto/signing.js +2 -0
- package/dist/internal/crypto/signing.js.map +1 -0
- package/dist/internal/crypto/webcrypto.js +2 -0
- package/dist/internal/crypto/webcrypto.js.map +1 -0
- package/dist/internal/shared/base64.js +2 -0
- package/dist/internal/shared/base64.js.map +1 -0
- package/dist/internal/shared/dn.js +2 -0
- package/dist/internal/shared/dn.js.map +1 -0
- package/dist/internal/shared/ip.js +2 -0
- package/dist/internal/shared/ip.js.map +1 -0
- package/dist/internal/verify/name-constraints-engine.js +2 -0
- package/dist/internal/verify/name-constraints-engine.js.map +1 -0
- package/dist/internal/verify/policy-engine.js +2 -0
- package/dist/internal/verify/policy-engine.js.map +1 -0
- package/dist/internal/verify/verify-path.js +2 -0
- package/dist/internal/verify/verify-path.js.map +1 -0
- package/dist/internal/x509/extension-bits.d.ts +18 -0
- package/dist/internal/x509/extension-bits.js +2 -0
- package/dist/internal/x509/extension-bits.js.map +1 -0
- package/dist/internal/x509/extension-registry.js +2 -0
- package/dist/internal/x509/extension-registry.js.map +1 -0
- package/dist/internal/x509/name-fields.js +2 -0
- package/dist/internal/x509/name-fields.js.map +1 -0
- package/dist/keys/keys.d.ts +431 -0
- package/dist/keys/keys.js +5 -0
- package/dist/keys/keys.js.map +1 -0
- package/dist/keys.d.ts +3 -0
- package/dist/keys.js +1 -0
- package/dist/pem/pem.d.ts +56 -0
- package/dist/pem/pem.js +6 -0
- package/dist/pem/pem.js.map +1 -0
- package/dist/pem.d.ts +2 -0
- package/dist/pem.js +1 -0
- package/dist/pkcs/pfx.d.ts +177 -0
- package/dist/pkcs/pfx.js +2 -0
- package/dist/pkcs/pfx.js.map +1 -0
- package/dist/pkcs/pkcs12-mac.d.ts +41 -0
- package/dist/pkcs/pkcs12-mac.js +2 -0
- package/dist/pkcs/pkcs12-mac.js.map +1 -0
- package/dist/pkcs/pkcs7.d.ts +131 -0
- package/dist/pkcs/pkcs7.js +2 -0
- package/dist/pkcs/pkcs7.js.map +1 -0
- package/dist/pkcs.d.ts +5 -0
- package/dist/pkcs.js +1 -0
- package/dist/result/result.d.ts +68 -0
- package/dist/result/result.js +2 -0
- package/dist/result/result.js.map +1 -0
- package/dist/result.d.ts +2 -0
- package/dist/result.js +1 -0
- package/dist/revocation/chain.d.ts +180 -0
- package/dist/revocation/chain.js +2 -0
- package/dist/revocation/chain.js.map +1 -0
- package/dist/revocation/crl.d.ts +316 -0
- package/dist/revocation/crl.js +2 -0
- package/dist/revocation/crl.js.map +1 -0
- package/dist/revocation/ocsp.d.ts +332 -0
- package/dist/revocation/ocsp.js +2 -0
- package/dist/revocation/ocsp.js.map +1 -0
- package/dist/revocation/revocation.d.ts +168 -0
- package/dist/revocation/revocation.js +2 -0
- package/dist/revocation/revocation.js.map +1 -0
- package/dist/revocation.d.ts +5 -0
- package/dist/revocation.js +1 -0
- package/dist/verify/identity.d.ts +129 -0
- package/dist/verify/identity.js +2 -0
- package/dist/verify/identity.js.map +1 -0
- package/dist/verify/name-constraints.d.ts +18 -0
- package/dist/verify/policy.d.ts +39 -0
- package/dist/verify/verify.d.ts +404 -0
- package/dist/verify/verify.js +2 -0
- package/dist/verify/verify.js.map +1 -0
- package/dist/verify.d.ts +5 -0
- package/dist/verify.js +1 -0
- package/dist/x509/certificate.d.ts +191 -0
- package/dist/x509/certificate.js +2 -0
- package/dist/x509/certificate.js.map +1 -0
- package/dist/x509/csr.d.ts +55 -0
- package/dist/x509/csr.js +2 -0
- package/dist/x509/csr.js.map +1 -0
- package/dist/x509/extensions.d.ts +550 -0
- package/dist/x509/extensions.js +2 -0
- package/dist/x509/extensions.js.map +1 -0
- package/dist/x509/name.d.ts +140 -0
- package/dist/x509/name.js +2 -0
- package/dist/x509/name.js.map +1 -0
- package/dist/x509/parse.d.ts +377 -0
- package/dist/x509/parse.js +2 -0
- package/dist/x509/parse.js.map +1 -0
- package/dist/x509.d.ts +8 -0
- package/dist/x509.js +1 -0
- package/package.json +153 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-path.js","names":[],"sources":["../../../src/internal/verify/verify-path.ts"],"sourcesContent":["/**\n * Internal certificate path-building and signature-check helpers.\n *\n * Loads and parses candidate certificates, ranks issuer candidates by AKI/root\n * affinity, matches against bare {@linkcode TrustAnchor}s, and performs the\n * depth-first chain search used by the public verify APIs in `verify.ts`.\n *\n * @module\n */\n\nimport { toHex } from '#micro509/internal/asn1/asn1.ts';\nimport { verifySignedDataDetailed } from '#micro509/internal/crypto/sig-verify.ts';\nimport { canonicalDnKey, compareDistinguishedNames } from '#micro509/internal/shared/dn.ts';\nimport type {\n\tCertificateSource,\n\tTrustAnchor,\n\tVerifyChainFailure,\n\tVerifyErrorCode,\n\tVerifyFailureDetails,\n} from '#micro509/verify/verify.ts';\nimport type { ParsedCertificate } from '#micro509/x509/parse.ts';\nimport { parseCertificatesFromSource } from '#micro509/x509/parse.ts';\n\ntype VerifyCertificateSignatureResult =\n\t| { readonly ok: true; readonly valid: boolean }\n\t| {\n\t\t\treadonly ok: false;\n\t\t\treadonly code: 'signature_invalid' | 'unsupported_signature_algorithm_parameters';\n\t\t\treadonly reason: string;\n\t };\n\n/** Result of the internal chain-building search. */\nexport interface InternalBuildResult {\n\t/** Deepest chain found (leaf-to-root order), may be partial if no root was reached. */\n\treadonly chain: readonly ParsedCertificate[];\n\t/** `true` when the chain terminates at a trusted root or anchor. */\n\treadonly foundTrustedRoot: boolean;\n\t/** Chain index where no issuer candidate existed, when the search dead-ended. */\n\treadonly missingIssuerAt?: number;\n\t/** Best failure encountered during the search, for diagnostic reporting. */\n\treadonly failure?: VerifyChainFailure;\n}\n\n/** Result of attempting to match a certificate against bare trust anchors. */\ninterface TrustAnchorMatchResult {\n\t/** `true` if a trust anchor verified the certificate's signature. */\n\treadonly matched: boolean;\n\t/** Failure to report when matching was attempted but signature verification failed. */\n\treadonly failure?: VerifyChainFailure;\n}\n\n/** Loose input for constructing failure detail objects during path building. */\ninterface VerifyPathFailureDetailsInput {\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}\n\n/** Callbacks injected by the caller to construct failure objects during path building. */\nexport interface VerifyPathCallbacks {\n\t/** Constructs a {@linkcode VerifyChainFailure} from a code, message, chain index, and details. */\n\treadonly failure: (\n\t\tcode: VerifyErrorCode,\n\t\tmessage: string,\n\t\tindex?: number,\n\t\tdetails?: VerifyFailureDetails,\n\t) => VerifyChainFailure;\n\t/** Constructs a {@linkcode VerifyFailureDetails} from loose inputs. */\n\treadonly detail: (input: VerifyPathFailureDetailsInput) => VerifyFailureDetails;\n}\n\n/** Returns `true` if `at` falls within the certificate's notBefore/notAfter window (inclusive). */\nexport function isWithinValidity(certificate: ParsedCertificate, at: Date): boolean {\n\treturn (\n\t\tcertificate.notBefore.getTime() <= at.getTime() &&\n\t\tat.getTime() <= certificate.notAfter.getTime()\n\t);\n}\n\n/** Returns `true` if the certificate's subject and issuer DNs are semantically equal (RFC 5280 §7.1). */\nexport function isSelfIssued(certificate: ParsedCertificate): boolean {\n\treturn compareDistinguishedNames(certificate.subject, certificate.issuer);\n}\n\n/** Counts non-self-issued CA certificates in positions 0..(index-1) for pathLength checking. */\nexport function countCaCertificatesBelowParsed(\n\tchain: readonly ParsedCertificate[],\n\tindex: number,\n): number {\n\tlet total = 0;\n\tfor (let cursor = 1; cursor < index; cursor += 1) {\n\t\tconst certificate = chain[cursor];\n\t\tif (certificate?.basicConstraints?.ca === true && !isSelfIssued(certificate)) {\n\t\t\ttotal += 1;\n\t\t}\n\t}\n\treturn total;\n}\n\n/** Parses an array of PEM/DER sources into parsed certificates, expanding multi-block PEM. */\nexport function loadCertificates(\n\tsources: readonly CertificateSource[],\n): readonly ParsedCertificate[] {\n\tconst loaded: ParsedCertificate[] = [];\n\tfor (const source of sources) {\n\t\tloaded.push(...expandSource(source));\n\t}\n\treturn loaded;\n}\n\n/** Parses exactly one certificate from a PEM/DER source. Throws if the source contains zero or multiple certificates. */\nexport function loadSingleCertificate(source: CertificateSource): ParsedCertificate {\n\tconst loaded = expandSource(source);\n\tconst first = loaded[0];\n\tif (first === undefined) {\n\t\tthrow new Error('No certificate found');\n\t}\n\tif (loaded.length !== 1) {\n\t\tthrow new Error('Expected a single certificate source');\n\t}\n\treturn first;\n}\n\n/** Verifies that `certificate` was signed by `issuer`'s public key. */\nexport async function verifyCertificateSignature(\n\tcertificate: ParsedCertificate,\n\tissuer: ParsedCertificate,\n): Promise<VerifyCertificateSignatureResult> {\n\tconst result = await verifySignedDataDetailed(\n\t\tcertificate.signatureAlgorithmOid,\n\t\tcertificate.signatureAlgorithmParametersDer,\n\t\tissuer.publicKeyAlgorithmOid,\n\t\tissuer.publicKeyParametersOid,\n\t\tissuer.subjectPublicKeyInfoDer,\n\t\tcertificate.signatureValue,\n\t\tcertificate.tbsCertificateDer,\n\t);\n\tif (!result.ok && result.code === 'verification_error') {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tcode: 'signature_invalid',\n\t\t\treason: result.reason,\n\t\t};\n\t}\n\treturn result;\n}\n\n/**\n * Depth-first chain search from leaf to root. Tries all issuer candidates,\n * checking validity, CA constraints, AKI, pathLength, and signatures at each\n * step. Returns the first fully anchored path or the deepest partial path\n * with the best failure encountered.\n */\nexport async function buildChainInternal(\n\tleaf: ParsedCertificate,\n\tintermediates: readonly ParsedCertificate[],\n\troots: readonly ParsedCertificate[],\n\ttrustAnchors: readonly TrustAnchor[],\n\tat: Date,\n\tcallbacks: VerifyPathCallbacks,\n): Promise<InternalBuildResult> {\n\tconst candidates = [...intermediates, ...roots];\n\tconst subjectIndex = new Map<string, ParsedCertificate[]>();\n\tconst order = new Map<string, number>();\n\tconst rootFingerprints = new Set(roots.map((candidate) => fingerprint(candidate)));\n\tconst anchorIndex = new Map<string, TrustAnchor[]>();\n\tfor (const anchor of trustAnchors) {\n\t\tconst key = canonicalDnKey(anchor.subject);\n\t\tconst existing = anchorIndex.get(key);\n\t\tif (existing === undefined) {\n\t\t\tanchorIndex.set(key, [anchor]);\n\t\t} else {\n\t\t\texisting.push(anchor);\n\t\t}\n\t}\n\tlet sawUntrustedAnchor = false;\n\tlet deepestPath: readonly ParsedCertificate[] = [leaf];\n\tlet deepestMissingIssuerAt: number | undefined;\n\tlet preferredFailure: VerifyChainFailure | undefined;\n\tconst deadEnds = new Set<string>();\n\n\tcandidates.forEach((candidate, index) => {\n\t\tconst key = canonicalDnKey(candidate.subject);\n\t\tconst existing = subjectIndex.get(key);\n\t\tif (existing === undefined) {\n\t\t\tsubjectIndex.set(key, [candidate]);\n\t\t} else {\n\t\t\texisting.push(candidate);\n\t\t}\n\t\torder.set(fingerprint(candidate), index);\n\t});\n\n\tconst maxDepth = candidates.length + 1;\n\tconst startFingerprint = fingerprint(leaf);\n\tconst success = await search(leaf, [leaf], new Set([startFingerprint]), 0);\n\tif (success !== undefined) {\n\t\treturn { chain: success, foundTrustedRoot: true };\n\t}\n\tif (preferredFailure !== undefined) {\n\t\treturn {\n\t\t\tchain: deepestPath,\n\t\t\tfoundTrustedRoot: false,\n\t\t\tfailure: preferredFailure,\n\t\t};\n\t}\n\tif (sawUntrustedAnchor) {\n\t\treturn { chain: deepestPath, foundTrustedRoot: false };\n\t}\n\treturn deepestMissingIssuerAt === undefined\n\t\t? { chain: deepestPath, foundTrustedRoot: false }\n\t\t: {\n\t\t\t\tchain: deepestPath,\n\t\t\t\tfoundTrustedRoot: false,\n\t\t\t\tmissingIssuerAt: deepestMissingIssuerAt,\n\t\t\t};\n\n\tasync function search(\n\t\tcurrent: ParsedCertificate,\n\t\tpath: readonly ParsedCertificate[],\n\t\tvisited: ReadonlySet<string>,\n\t\tcaBelowCount: number,\n\t): Promise<readonly ParsedCertificate[] | undefined> {\n\t\tif (rootFingerprints.has(fingerprint(current))) {\n\t\t\treturn path;\n\t\t}\n\t\tconst matchedAnchor = await matchTrustAnchor(current, anchorIndex, callbacks, path.length - 1);\n\t\tif (matchedAnchor.failure !== undefined) {\n\t\t\trecordFailure(matchedAnchor.failure, path);\n\t\t}\n\t\tif (matchedAnchor.matched) {\n\t\t\treturn path;\n\t\t}\n\t\tif (path.length > maxDepth) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst visitedKey = [...visited].sort().join(',');\n\t\tconst memoKey = `${fingerprint(current)}:${caBelowCount}:${visitedKey}`;\n\t\tif (deadEnds.has(memoKey)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst issuers = rankIssuerCandidates(\n\t\t\tcurrent,\n\t\t\tsubjectIndex.get(canonicalDnKey(current.issuer)) ?? [],\n\t\t\torder,\n\t\t\trootFingerprints,\n\t\t);\n\t\tif (issuers.length === 0) {\n\t\t\tconst wasDeepest = path.length > deepestPath.length;\n\t\t\tupdateDeepest(path);\n\t\t\tif (isSelfIssued(current)) {\n\t\t\t\tsawUntrustedAnchor = true;\n\t\t\t} else if (wasDeepest) {\n\t\t\t\tdeepestMissingIssuerAt = path.length - 1;\n\t\t\t}\n\t\t\tdeadEnds.add(memoKey);\n\t\t\treturn undefined;\n\t\t}\n\n\t\tfor (const issuer of issuers) {\n\t\t\tconst issuerFingerprint = fingerprint(issuer);\n\t\t\tif (visited.has(issuerFingerprint)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isWithinValidity(issuer, at)) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'certificate_expired',\n\t\t\t\t\t\t'certificate not valid at requested time',\n\t\t\t\t\t\tpath.length,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t\texpected: describeDateTime(at),\n\t\t\t\t\t\t\tactual: `${describeDateTime(issuer.notBefore)}..${describeDateTime(issuer.notAfter)}`,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (issuer.basicConstraints?.ca !== true) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'ca_required',\n\t\t\t\t\t\t'issuer must be a CA certificate',\n\t\t\t\t\t\tpath.length,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (issuer.keyUsage !== undefined && !issuer.keyUsage.flags.includes('keyCertSign')) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'key_cert_sign_required',\n\t\t\t\t\t\t'issuer missing keyCertSign',\n\t\t\t\t\t\tpath.length,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tcurrent.authorityKeyIdentifier !== undefined &&\n\t\t\t\tissuer.subjectKeyIdentifier !== undefined &&\n\t\t\t\tcurrent.authorityKeyIdentifier !== issuer.subjectKeyIdentifier\n\t\t\t) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'authority_key_identifier_mismatch',\n\t\t\t\t\t\t'authorityKeyIdentifier does not match issuer subjectKeyIdentifier',\n\t\t\t\t\t\tpath.length - 1,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t\texpected: issuer.subjectKeyIdentifier,\n\t\t\t\t\t\t\tactual: current.authorityKeyIdentifier,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst nextCaBelowCount =\n\t\t\t\tcaBelowCount +\n\t\t\t\t(current.basicConstraints?.ca === true && !isSelfIssued(current) && path.length > 1\n\t\t\t\t\t? 1\n\t\t\t\t\t: 0);\n\t\t\tconst pathLength = issuer.basicConstraints?.pathLength;\n\t\t\tif (isNonNegativeInteger(pathLength) && nextCaBelowCount > pathLength) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'path_length_exceeded',\n\t\t\t\t\t\t'path length constraint exceeded',\n\t\t\t\t\t\tpath.length,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t\texpected: String(pathLength),\n\t\t\t\t\t\t\tactual: String(nextCaBelowCount),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst signatureResult = await verifyCertificateSignature(current, issuer);\n\t\t\tif (!signatureResult.ok) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\tsignatureResult.code,\n\t\t\t\t\t\tsignatureResult.reason,\n\t\t\t\t\t\tpath.length - 1,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t\tactual: signatureResult.reason,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!signatureResult.valid) {\n\t\t\t\trecordFailure(\n\t\t\t\t\tcallbacks.failure(\n\t\t\t\t\t\t'signature_invalid',\n\t\t\t\t\t\t'certificate signature does not verify',\n\t\t\t\t\t\tpath.length - 1,\n\t\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\t\tsubjectCommonName: current.subject.values.commonName,\n\t\t\t\t\t\t\tissuerCommonName: issuer.subject.values.commonName,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tpath,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst nextVisited = new Set(visited);\n\t\t\tnextVisited.add(issuerFingerprint);\n\t\t\tconst nextPath = [...path, issuer];\n\t\t\tconst result = await search(issuer, nextPath, nextVisited, nextCaBelowCount);\n\t\t\tif (result !== undefined) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\tdeadEnds.add(memoKey);\n\t\tupdateDeepest(path);\n\t\treturn undefined;\n\t}\n\n\tfunction updateDeepest(path: readonly ParsedCertificate[]): boolean {\n\t\tif (path.length > deepestPath.length) {\n\t\t\tdeepestPath = path;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction recordFailure(\n\t\tcandidateFailure: VerifyChainFailure,\n\t\tpath: readonly ParsedCertificate[],\n\t): void {\n\t\tif (preferredFailure === undefined || path.length > deepestPath.length) {\n\t\t\tpreferredFailure = candidateFailure;\n\t\t\tdeepestPath = path;\n\t\t}\n\t}\n}\n\n/** Expands a PEM (possibly multi-block) or DER source into parsed certificates. */\nfunction expandSource(source: CertificateSource): readonly ParsedCertificate[] {\n\treturn parseCertificatesFromSource(source);\n}\n\n/** Filters and sorts issuer candidates: AKI match first, then roots, then input order. */\nfunction rankIssuerCandidates(\n\tcurrent: ParsedCertificate,\n\tcandidates: readonly ParsedCertificate[],\n\torder: ReadonlyMap<string, number>,\n\trootFingerprints: ReadonlySet<string>,\n): readonly ParsedCertificate[] {\n\tconst aki = current.authorityKeyIdentifier;\n\tconst filtered = [...candidates].filter((candidate) => isIssuerOf(candidate, current));\n\tconst fps = new Map<ParsedCertificate, string>();\n\tfor (const candidate of filtered) {\n\t\tfps.set(candidate, fingerprint(candidate));\n\t}\n\treturn filtered.sort((left, right) => {\n\t\tconst akiScore = compareBooleans(matchesAki(left, aki), matchesAki(right, aki));\n\t\tif (akiScore !== 0) {\n\t\t\treturn akiScore;\n\t\t}\n\t\tconst leftFp = fps.get(left) ?? '';\n\t\tconst rightFp = fps.get(right) ?? '';\n\t\tconst rootScore = compareBooleans(rootFingerprints.has(leftFp), rootFingerprints.has(rightFp));\n\t\tif (rootScore !== 0) {\n\t\t\treturn rootScore;\n\t\t}\n\t\treturn (\n\t\t\t(order.get(leftFp) ?? Number.MAX_SAFE_INTEGER) -\n\t\t\t(order.get(rightFp) ?? Number.MAX_SAFE_INTEGER)\n\t\t);\n\t});\n}\n\n/** Returns `true` if the candidate's SKI matches the given authority key identifier. */\nfunction matchesAki(candidate: ParsedCertificate, aki: string | undefined): boolean {\n\treturn (\n\t\taki !== undefined &&\n\t\tcandidate.subjectKeyIdentifier !== undefined &&\n\t\tcandidate.subjectKeyIdentifier === aki\n\t);\n}\n\n/** Sort comparator: `true` sorts before `false`. Returns -1, 0, or 1. */\nfunction compareBooleans(left: boolean, right: boolean): number {\n\tif (left === right) {\n\t\treturn 0;\n\t}\n\treturn left ? -1 : 1;\n}\n\n/** Returns `true` if `issuer`'s subject DN semantically matches `child`'s issuer DN (RFC 5280 §7.1). */\nfunction isIssuerOf(issuer: ParsedCertificate, child: ParsedCertificate): boolean {\n\treturn compareDistinguishedNames(child.issuer, issuer.subject);\n}\n\n/** Attempts to verify `certificate` against each bare trust anchor whose subject DN matches. */\nasync function matchTrustAnchor(\n\tcertificate: ParsedCertificate,\n\tanchorIndex: ReadonlyMap<string, readonly TrustAnchor[]>,\n\tcallbacks: VerifyPathCallbacks,\n\tindex: number,\n): Promise<TrustAnchorMatchResult> {\n\tconst anchors = anchorIndex.get(canonicalDnKey(certificate.issuer));\n\tif (anchors === undefined) {\n\t\treturn { matched: false };\n\t}\n\tlet firstFailure: VerifyChainFailure | undefined;\n\tfor (const anchor of anchors) {\n\t\tif (\n\t\t\tanchor.subjectKeyIdentifier !== undefined &&\n\t\t\tcertificate.authorityKeyIdentifier !== undefined &&\n\t\t\tanchor.subjectKeyIdentifier !== certificate.authorityKeyIdentifier\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\t\tlet verified: VerifyCertificateSignatureResult;\n\t\ttry {\n\t\t\tconst verificationResult = await verifySignedDataDetailed(\n\t\t\t\tcertificate.signatureAlgorithmOid,\n\t\t\t\tcertificate.signatureAlgorithmParametersDer,\n\t\t\t\tanchor.publicKeyAlgorithmOid,\n\t\t\t\tanchor.publicKeyParametersOid,\n\t\t\t\tanchor.subjectPublicKeyInfoDer,\n\t\t\t\tcertificate.signatureValue,\n\t\t\t\tcertificate.tbsCertificateDer,\n\t\t\t);\n\t\t\tverified =\n\t\t\t\t!verificationResult.ok && verificationResult.code === 'verification_error'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tok: false,\n\t\t\t\t\t\t\tcode: 'signature_invalid',\n\t\t\t\t\t\t\treason: verificationResult.reason,\n\t\t\t\t\t\t}\n\t\t\t\t\t: verificationResult;\n\t\t} catch (error) {\n\t\t\tif (firstFailure === undefined) {\n\t\t\t\tfirstFailure = callbacks.failure(\n\t\t\t\t\t'signature_invalid',\n\t\t\t\t\t'certificate signature does not verify',\n\t\t\t\t\tindex,\n\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\tsubjectCommonName: certificate.subject.values.commonName,\n\t\t\t\t\t\tactual: error instanceof Error ? error.message : 'trust anchor key is malformed',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (!verified.ok) {\n\t\t\t// Capture the first failure but continue trying other anchors\n\t\t\tif (firstFailure === undefined) {\n\t\t\t\tfirstFailure = callbacks.failure(\n\t\t\t\t\tverified.code,\n\t\t\t\t\tverified.reason,\n\t\t\t\t\tindex,\n\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\tsubjectCommonName: certificate.subject.values.commonName,\n\t\t\t\t\t\tactual: verified.reason,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (!verified.valid) {\n\t\t\tif (firstFailure === undefined) {\n\t\t\t\tfirstFailure = callbacks.failure(\n\t\t\t\t\t'signature_invalid',\n\t\t\t\t\t'certificate signature does not verify',\n\t\t\t\t\tindex,\n\t\t\t\t\tcallbacks.detail({\n\t\t\t\t\t\tsubjectCommonName: certificate.subject.values.commonName,\n\t\t\t\t\t\tactual: 'certificate signature does not verify',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\treturn { matched: true };\n\t}\n\treturn firstFailure !== undefined\n\t\t? { matched: false, failure: firstFailure }\n\t\t: { matched: false };\n}\n\nfunction describeDateTime(value: Date): string {\n\treturn Number.isNaN(value.getTime()) ? '<invalid date>' : value.toISOString();\n}\n\nfunction isNonNegativeInteger(value: number | undefined): value is number {\n\treturn value !== undefined && Number.isInteger(value) && value >= 0;\n}\n\n/** Cache for computed fingerprints to avoid repeated toHex() calls. */\nconst fingerprintCache = new WeakMap<ParsedCertificate, string>();\n\n/** Returns a hex fingerprint of the certificate's raw DER, used for cycle detection and dedup. */\nfunction fingerprint(certificate: ParsedCertificate): string {\n\tlet cached = fingerprintCache.get(certificate);\n\tif (cached === undefined) {\n\t\tcached = toHex(certificate.der);\n\t\tfingerprintCache.set(certificate, cached);\n\t}\n\treturn cached;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/internal/x509/extension-bits.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Decoded BIT STRING flags with DER conformance metadata.
|
|
4
|
+
*
|
|
5
|
+
* `flags` contains the recognized flag values with any non-zero padding bits
|
|
6
|
+
* masked out. `nonZeroPadding` is `true` when the original BIT STRING encoding
|
|
7
|
+
* had non-zero bits in positions that DER (X.690 §11.2.2) requires to be zero.
|
|
8
|
+
* Verification layers can use this signal to reject non-conformant encodings.
|
|
9
|
+
*/
|
|
10
|
+
interface ParsedBitFlags<T extends string> {
|
|
11
|
+
/** Decoded flag values, padding bits masked. */
|
|
12
|
+
readonly flags: readonly T[];
|
|
13
|
+
/** `true` when the original encoding had non-zero padding bits (DER violation). */
|
|
14
|
+
readonly nonZeroPadding: boolean;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { ParsedBitFlags };
|
|
18
|
+
//# sourceMappingURL=extension-bits.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{bitString as e,readRootElement as t}from"../asn1/der.js";const n=[`digitalSignature`,`nonRepudiation`,`keyEncipherment`,`dataEncipherment`,`keyAgreement`,`keyCertSign`,`cRLSign`,`encipherOnly`,`decipherOnly`],r=[`keyCompromise`,`cACompromise`,`affiliationChanged`,`superseded`,`cessationOfOperation`,`certificateHold`,`privilegeWithdrawn`,`aACompromise`];function i(t){let r=c(t,e=>d(n,e,`key usage`));return e(r.bytes,r.unusedBits)}function a(e){let r=t(e,{maxDepth:64});if(r.tag!==3)throw Error(`keyUsage must be a BIT STRING`);return u(l(r.value,n,0),`keyUsage`)}function o(e){let t=c(e,e=>d(r,e,`distribution point reason`)+1);return Uint8Array.of(t.unusedBits,...t.bytes)}function s(e){return u(l(e,r,1),`DistributionPoint reasons`)}function c(e,t){if(e.length===0)return{bytes:new Uint8Array,unusedBits:0};let n=-1,r=[];for(let i of e){let e=t(i);r.push(e),e>n&&(n=e)}let i=Math.floor(n/8)+1,a=new Uint8Array(i);for(let e of r){let t=Math.floor(e/8),n=e%8;a[t]=(a[t]??0)|1<<7-n}return{bytes:a,unusedBits:(8-(n+1)%8)%8}}function l(e,t,n){if(e.length===0)throw Error(`Empty BIT STRING`);let r=e[0]??0;if(r>7)throw Error(`Invalid BIT STRING`);let i=e.slice(1);if(i.length===0&&r!==0)throw Error(`Invalid BIT STRING`);let a=!1;r>0&&i.length>0&&(a=((i[i.length-1]??0)&(1<<r)-1)!=0);let o=[];for(let e=0;e<t.length;e+=1){let r=e+n,a=Math.floor(r/8);if(a>=i.length)break;if((i[a]??0)&1<<7-r%8){let n=t[e];n!==void 0&&o.push(n)}}return{flags:o,nonZeroPadding:a}}function u(e,t){if(e.nonZeroPadding)throw Error(`${t} BIT STRING must not set padding bits`);return e}function d(e,t,n){let r=e.indexOf(t);if(r<0)throw Error(`Unsupported ${n}: ${t}`);return r}export{o as encodeDistributionPointReasonFlagsContent,i as encodeKeyUsageExtension,s as parseDistributionPointReasonFlagsContent,a as parseKeyUsageExtension};
|
|
2
|
+
//# sourceMappingURL=extension-bits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-bits.js","names":[],"sources":["../../../src/internal/x509/extension-bits.ts"],"sourcesContent":["/**\n * BIT STRING helpers for {@linkcode KeyUsage} and {@linkcode DistributionPointReason} flags.\n *\n * Centralizes the bit-position ordering so certificate builders and parsers\n * produce identical wire encodings.\n *\n * @module\n */\n\nimport { bitString, DEFAULT_MAX_DER_DEPTH, readRootElement } from '#micro509/internal/asn1/der.ts';\nimport type { DistributionPointReason, KeyUsage } from '#micro509/x509/extensions.ts';\n\n/**\n * Decoded BIT STRING flags with DER conformance metadata.\n *\n * `flags` contains the recognized flag values with any non-zero padding bits\n * masked out. `nonZeroPadding` is `true` when the original BIT STRING encoding\n * had non-zero bits in positions that DER (X.690 §11.2.2) requires to be zero.\n * Verification layers can use this signal to reject non-conformant encodings.\n */\nexport interface ParsedBitFlags<T extends string> {\n\t/** Decoded flag values, padding bits masked. */\n\treadonly flags: readonly T[];\n\t/** `true` when the original encoding had non-zero padding bits (DER violation). */\n\treadonly nonZeroPadding: boolean;\n}\n\n/** Canonical bit-position order for Key Usage flags (RFC 5280 §4.2.1.3). */\nconst KEY_USAGE_ORDER = [\n\t'digitalSignature',\n\t'nonRepudiation',\n\t'keyEncipherment',\n\t'dataEncipherment',\n\t'keyAgreement',\n\t'keyCertSign',\n\t'cRLSign',\n\t'encipherOnly',\n\t'decipherOnly',\n] as const satisfies readonly KeyUsage[];\n\n/** Canonical bit-position order for DistributionPoint reason flags (RFC 5280 §4.2.1.13). */\nconst DISTRIBUTION_POINT_REASON_ORDER = [\n\t'keyCompromise',\n\t'cACompromise',\n\t'affiliationChanged',\n\t'superseded',\n\t'cessationOfOperation',\n\t'certificateHold',\n\t'privilegeWithdrawn',\n\t'aACompromise',\n] as const satisfies readonly DistributionPointReason[];\n\n/**\n * Encode an array of {@linkcode KeyUsage} flags into a DER BIT STRING.\n *\n * @param usages Flags to set. Bit positions follow RFC 5280 §4.2.1.3 order.\n */\nexport function encodeKeyUsageExtension(usages: readonly KeyUsage[]): Uint8Array {\n\tconst encoded = encodeBitFlags(usages, (usage) =>\n\t\tindexInOrder(KEY_USAGE_ORDER, usage, 'key usage'),\n\t);\n\treturn bitString(encoded.bytes, encoded.unusedBits);\n}\n\n/**\n * Decode a DER-encoded Key Usage BIT STRING into an array of {@linkcode KeyUsage} flags.\n *\n * @param bytes DER of the keyUsage extension value (BIT STRING).\n */\nexport function parseKeyUsageExtension(bytes: Uint8Array): ParsedBitFlags<KeyUsage> {\n\tconst bitStringElement = readRootElement(bytes, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (bitStringElement.tag !== 0x03) {\n\t\tthrow new Error('keyUsage must be a BIT STRING');\n\t}\n\treturn requireCanonicalBitFlags(\n\t\tdecodeBitFlags(bitStringElement.value, KEY_USAGE_ORDER, 0),\n\t\t'keyUsage',\n\t);\n}\n\n/**\n * Encode {@linkcode DistributionPointReason} flags as BIT STRING content bytes\n * (unusedBits prefix + flag bytes), suitable for wrapping in an implicit context tag.\n *\n * @param reasons Reason flags to encode.\n */\nexport function encodeDistributionPointReasonFlagsContent(\n\treasons: readonly DistributionPointReason[],\n): Uint8Array {\n\tconst encoded = encodeBitFlags(\n\t\treasons,\n\t\t(reason) =>\n\t\t\tindexInOrder(DISTRIBUTION_POINT_REASON_ORDER, reason, 'distribution point reason') + 1,\n\t);\n\treturn Uint8Array.of(encoded.unusedBits, ...encoded.bytes);\n}\n\n/**\n * Decode BIT STRING content bytes into {@linkcode DistributionPointReason} flags.\n *\n * @param value Raw content bytes (unusedBits prefix + flag bytes).\n * @returns Decoded reason flags, preserving empty-but-present values and padding metadata.\n */\nexport function parseDistributionPointReasonFlagsContent(\n\tvalue: Uint8Array,\n): ParsedBitFlags<DistributionPointReason> {\n\treturn requireCanonicalBitFlags(\n\t\tdecodeBitFlags(value, DISTRIBUTION_POINT_REASON_ORDER, 1),\n\t\t'DistributionPoint reasons',\n\t);\n}\n\n/** Pack named flags into a minimal byte array with DER BIT STRING unused-bits count. */\nfunction encodeBitFlags<T extends string>(\n\tvalues: readonly T[],\n\tbitForValue: (value: T) => number,\n): {\n\treadonly bytes: Uint8Array;\n\treadonly unusedBits: number;\n} {\n\tif (values.length === 0) {\n\t\treturn { bytes: new Uint8Array(0), unusedBits: 0 };\n\t}\n\tlet highestBit = -1;\n\tconst bits: number[] = [];\n\tfor (const value of values) {\n\t\tconst bit = bitForValue(value);\n\t\tbits.push(bit);\n\t\tif (bit > highestBit) {\n\t\t\thighestBit = bit;\n\t\t}\n\t}\n\tconst byteLength = Math.floor(highestBit / 8) + 1;\n\tconst bytes = new Uint8Array(byteLength);\n\tfor (const bit of bits) {\n\t\tconst byteIndex = Math.floor(bit / 8);\n\t\tconst bitIndex = bit % 8;\n\t\tconst current = bytes[byteIndex] ?? 0;\n\t\tbytes[byteIndex] = current | (1 << (7 - bitIndex));\n\t}\n\tconst totalBits = highestBit + 1;\n\tconst unusedBits = (8 - (totalBits % 8)) % 8;\n\treturn {\n\t\tbytes,\n\t\tunusedBits,\n\t};\n}\n\n/** Unpack set bits from a BIT STRING content into named flags from a candidate list. */\nfunction decodeBitFlags<T extends string>(\n\tvalue: Uint8Array,\n\tcandidates: readonly T[],\n\tbitOffset: number,\n): ParsedBitFlags<T> {\n\tif (value.length === 0) {\n\t\tthrow new Error('Empty BIT STRING');\n\t}\n\tconst unusedBits = value[0] ?? 0;\n\tif (unusedBits > 7) {\n\t\tthrow new Error('Invalid BIT STRING');\n\t}\n\tconst bytes = value.slice(1);\n\tif (bytes.length === 0 && unusedBits !== 0) {\n\t\tthrow new Error('Invalid BIT STRING');\n\t}\n\t// Detect non-zero padding bits in the unused positions of the last byte.\n\t// DER X.690 §11.2.2 requires these to be zero. Rather than rejecting here\n\t// (which would break interop with real-world non-conformant certificates),\n\t// we record the violation so verification layers can decide.\n\tlet nonZeroPadding = false;\n\tif (unusedBits > 0 && bytes.length > 0) {\n\t\tconst lastByte = bytes[bytes.length - 1] ?? 0;\n\t\tconst paddingMask = (1 << unusedBits) - 1;\n\t\tnonZeroPadding = (lastByte & paddingMask) !== 0;\n\t}\n\tconst flags: T[] = [];\n\tfor (let index = 0; index < candidates.length; index += 1) {\n\t\tconst bit = index + bitOffset;\n\t\tconst byteIndex = Math.floor(bit / 8);\n\t\tif (byteIndex >= bytes.length) {\n\t\t\tbreak;\n\t\t}\n\t\tconst byte = bytes[byteIndex] ?? 0;\n\t\tconst bitIndex = bit % 8;\n\t\tif ((byte & (1 << (7 - bitIndex))) !== 0) {\n\t\t\tconst candidate = candidates[index];\n\t\t\tif (candidate !== undefined) {\n\t\t\t\tflags.push(candidate);\n\t\t\t}\n\t\t}\n\t}\n\treturn { flags, nonZeroPadding };\n}\n\nfunction requireCanonicalBitFlags<T extends string>(\n\tparsed: ParsedBitFlags<T>,\n\tlabel: string,\n): ParsedBitFlags<T> {\n\tif (parsed.nonZeroPadding) {\n\t\tthrow new Error(`${label} BIT STRING must not set padding bits`);\n\t}\n\treturn parsed;\n}\n\n/** Look up the bit position of a flag in its canonical order array. Throws on unknown flags. */\nfunction indexInOrder<T extends string>(order: readonly T[], value: T, label: string): number {\n\tconst index = order.indexOf(value);\n\tif (index < 0) {\n\t\tthrow new Error(`Unsupported ${label}: ${value}`);\n\t}\n\treturn index;\n}\n"],"mappings":"gEA4BA,MAAM,EAAkB,CACvB,mBACA,iBACA,kBACA,mBACA,eACA,cACA,UACA,eACA,cACD,EAGM,EAAkC,CACvC,gBACA,eACA,qBACA,aACA,uBACA,kBACA,qBACA,cACD,EAOA,SAAgB,EAAwB,EAAyC,CAChF,IAAM,EAAU,EAAe,EAAS,GACvC,EAAa,EAAiB,EAAO,WAAW,CACjD,EACA,OAAO,EAAU,EAAQ,MAAO,EAAQ,UAAU,CACnD,CAOA,SAAgB,EAAuB,EAA6C,CACnF,IAAM,EAAmB,EAAgB,EAAO,CAAE,SAAA,EAAgC,CAAC,EACnF,GAAI,EAAiB,MAAQ,EAC5B,MAAU,MAAM,+BAA+B,EAEhD,OAAO,EACN,EAAe,EAAiB,MAAO,EAAiB,CAAC,EACzD,UACD,CACD,CAQA,SAAgB,EACf,EACa,CACb,IAAM,EAAU,EACf,EACC,GACA,EAAa,EAAiC,EAAQ,2BAA2B,EAAI,CACvF,EACA,OAAO,WAAW,GAAG,EAAQ,WAAY,GAAG,EAAQ,KAAK,CAC1D,CAQA,SAAgB,EACf,EAC0C,CAC1C,OAAO,EACN,EAAe,EAAO,EAAiC,CAAC,EACxD,2BACD,CACD,CAGA,SAAS,EACR,EACA,EAIC,CACD,GAAI,EAAO,SAAW,EACrB,MAAO,CAAE,MAAO,IAAI,WAAe,WAAY,CAAE,EAElD,IAAI,EAAa,GACX,EAAiB,CAAC,EACxB,IAAK,IAAM,KAAS,EAAQ,CAC3B,IAAM,EAAM,EAAY,CAAK,EAC7B,EAAK,KAAK,CAAG,EACT,EAAM,IACT,EAAa,EAEf,CACA,IAAM,EAAa,KAAK,MAAM,EAAa,CAAC,EAAI,EAC1C,EAAQ,IAAI,WAAW,CAAU,EACvC,IAAK,IAAM,KAAO,EAAM,CACvB,IAAM,EAAY,KAAK,MAAM,EAAM,CAAC,EAC9B,EAAW,EAAM,EAEvB,EAAM,IADU,EAAM,IAAc,GACN,GAAM,EAAI,CACzC,CAGA,MAAO,CACN,QACA,YAHmB,GADF,EAAa,GACM,GAAM,CAI3C,CACD,CAGA,SAAS,EACR,EACA,EACA,EACoB,CACpB,GAAI,EAAM,SAAW,EACpB,MAAU,MAAM,kBAAkB,EAEnC,IAAM,EAAa,EAAM,IAAM,EAC/B,GAAI,EAAa,EAChB,MAAU,MAAM,oBAAoB,EAErC,IAAM,EAAQ,EAAM,MAAM,CAAC,EAC3B,GAAI,EAAM,SAAW,GAAK,IAAe,EACxC,MAAU,MAAM,oBAAoB,EAMrC,IAAI,EAAiB,GACjB,EAAa,GAAK,EAAM,OAAS,IAGpC,IAFiB,EAAM,EAAM,OAAS,IAAM,IACvB,GAAK,GAAc,IACM,GAE/C,IAAM,EAAa,CAAC,EACpB,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAW,OAAQ,GAAS,EAAG,CAC1D,IAAM,EAAM,EAAQ,EACd,EAAY,KAAK,MAAM,EAAM,CAAC,EACpC,GAAI,GAAa,EAAM,OACtB,MAID,IAFa,EAAM,IAAc,GAEpB,GAAM,EADF,EAAM,EACmB,CACzC,IAAM,EAAY,EAAW,GACzB,IAAc,IAAA,IACjB,EAAM,KAAK,CAAS,CAEtB,CACD,CACA,MAAO,CAAE,QAAO,gBAAe,CAChC,CAEA,SAAS,EACR,EACA,EACoB,CACpB,GAAI,EAAO,eACV,MAAU,MAAM,GAAG,EAAM,sCAAsC,EAEhE,OAAO,CACR,CAGA,SAAS,EAA+B,EAAqB,EAAU,EAAuB,CAC7F,IAAM,EAAQ,EAAM,QAAQ,CAAK,EACjC,GAAI,EAAQ,EACX,MAAU,MAAM,eAAe,EAAM,IAAI,GAAO,EAEjD,OAAO,CACR"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{implicitPrimitiveContext as e,octetString as t,readRootElement as n,sequence as r}from"../asn1/der.js";import{hexToBytes as i,toHex as a}from"../asn1/asn1.js";import{OIDS as o}from"../asn1/oids.js";import{encodeAuthorityInfoAccess as s,encodeBasicConstraints as c,encodeCertificatePolicies as l,encodeCrlDistributionPoints as u,encodeExtendedKeyUsage as d,encodeInhibitAnyPolicy as f,encodeKeyUsage as p,encodeNameConstraints as m,encodePolicyConstraints as h,encodePolicyMappings as g,encodeSubjectAltName as _}from"../../x509/extensions.js";import{parseAuthorityInfoAccess as v,parseAuthorityKeyIdentifier as y,parseBasicConstraints as b,parseCertificatePolicies as x,parseCrlDistributionPoints as S,parseExtendedKeyUsage as C,parseInhibitAnyPolicy as w,parseKeyUsage as T,parseNameConstraints as E,parsePolicyConstraints as D,parsePolicyMappings as O,parseSubjectAltNames as k}from"../../x509/parse.js";const A=new Map,j=J({oid:o.basicConstraints,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>b(e),encode:e=>c(e),applyParsed:(e,t)=>{e.basicConstraints=t}}),M=J({oid:o.keyUsage,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>T(e),encode:e=>p(e),applyParsed:(e,t)=>{e.keyUsage=t}}),N=J({oid:o.extendedKeyUsage,contexts:[`certificate`,`csr`],defaultCritical:!1,decode:e=>C(e),encode:e=>d(e),applyParsed:(e,t)=>{e.extendedKeyUsage=t}}),P=J({oid:o.subjectAltName,contexts:[`certificate`,`csr`],defaultCritical:!1,decode:e=>k(e),encode:e=>r(e.map(_)),applyParsed:(e,t)=>{e.subjectAltNames=t}}),F=J({oid:o.nameConstraints,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>E(e),encode:e=>m(e),applyParsed:(e,t)=>{e.nameConstraints=t}}),I=J({oid:o.certificatePolicies,contexts:[`certificate`,`csr`],defaultCritical:!1,decode:e=>x(e),encode:e=>l(e),applyParsed:(e,t)=>{e.certificatePolicies=t}}),L=J({oid:o.policyMappings,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>O(e),encode:e=>g(e),applyParsed:(e,t)=>{e.policyMappings=t}}),R=J({oid:o.policyConstraints,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>D(e),encode:e=>h(e),applyParsed:(e,t)=>{e.policyConstraints=t}}),z=J({oid:o.inhibitAnyPolicy,contexts:[`certificate`,`csr`],defaultCritical:!0,decode:e=>w(e),encode:e=>f(e),applyParsed:(e,t)=>{e.inhibitAnyPolicy=t}}),B=J({oid:o.authorityInfoAccess,contexts:[`certificate`,`csr`],defaultCritical:!1,decode:e=>v(e),encode:e=>s(e),applyParsed:(e,t)=>{e.authorityInfoAccess=t}}),V=J({oid:o.cRLDistributionPoints,contexts:[`certificate`,`csr`],defaultCritical:!1,decode:e=>S(e),encode:e=>u(e),applyParsed:(e,t)=>{e.crlDistributionPoints=t}}),H=J({oid:o.subjectKeyIdentifier,contexts:[`certificate`],defaultCritical:!1,autoGenerated:!0,decode:e=>X(e),encode:e=>t(Y(e)),applyParsed:(e,t)=>{e.subjectKeyIdentifier=t}}),U=J({oid:o.authorityKeyIdentifier,contexts:[`certificate`],defaultCritical:!1,autoGenerated:!0,decode:e=>y(e),encode:t=>r([e(0,Y(t))]),applyParsed:(e,t)=>{t!==void 0&&(e.authorityKeyIdentifier=t)}}),W=[j,M,N,P,F,I,L,R,z,B,V,H,U],G=new Map(W.map(e=>[e.oid,e]));function K(e){return G.get(e)}function q(e,t,n,r){let i=K(t);if(i===void 0||!i.contexts.includes(e))return!1;let a=A.get(t);return a===void 0?!1:(a(n,r),!0)}function J(e){return A.set(e.oid,(t,n)=>{e.applyParsed(t,e.decode(n))}),e}function Y(e){return typeof e==`string`?i(e):e}function X(e){let t=n(e,{maxDepth:64});if(t.tag!==4)throw Error(`SubjectKeyIdentifier must be an OCTET STRING`);return a(t.value)}export{B as AUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION,U as AUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION,j as BASIC_CONSTRAINTS_EXTENSION_DEFINITION,I as CERTIFICATE_POLICIES_EXTENSION_DEFINITION,W as CERT_CSR_EXTENSION_DEFINITIONS,V as CRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION,N as EXTENDED_KEY_USAGE_EXTENSION_DEFINITION,z as INHIBIT_ANY_POLICY_EXTENSION_DEFINITION,M as KEY_USAGE_EXTENSION_DEFINITION,F as NAME_CONSTRAINTS_EXTENSION_DEFINITION,R as POLICY_CONSTRAINTS_EXTENSION_DEFINITION,L as POLICY_MAPPINGS_EXTENSION_DEFINITION,P as SUBJECT_ALT_NAME_EXTENSION_DEFINITION,H as SUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION,q as decodeAndApplyKnownExtension,K as getExtensionDefinition};
|
|
2
|
+
//# sourceMappingURL=extension-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-registry.js","names":[],"sources":["../../../src/internal/x509/extension-registry.ts"],"sourcesContent":["/**\n * Internal extension registry for certificate and CSR parsing.\n *\n * Maps each supported extension OID to a definition that can decode DER,\n * encode input, and apply parsed values to the accumulator used during\n * certificate/CSR parsing.\n *\n * @module\n */\n\nimport { hexToBytes, toHex } from '#micro509/internal/asn1/asn1.ts';\nimport {\n\tDEFAULT_MAX_DER_DEPTH,\n\timplicitPrimitiveContext,\n\toctetString,\n\treadRootElement,\n\tsequence,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport type { ParsedBitFlags } from '#micro509/internal/x509/extension-bits.ts';\nimport type {\n\tAuthorityInformationAccess,\n\tBasicConstraints,\n\tCertificatePolicies,\n\tDistributionPoint,\n\tExtendedKeyUsage,\n\tInhibitAnyPolicy,\n\tKeyUsage,\n\tNameConstraints,\n\tParsedNameConstraintForm,\n\tPolicyConstraints,\n\tPolicyMappings,\n\tSubjectAltName,\n} from '#micro509/x509/extensions.ts';\nimport {\n\tbuildSubjectKeyIdentifier,\n\tencodeAuthorityInfoAccess,\n\tencodeBasicConstraints,\n\tencodeCertificatePolicies,\n\tencodeCrlDistributionPoints,\n\tencodeExtendedKeyUsage,\n\tencodeInhibitAnyPolicy,\n\tencodeKeyUsage,\n\tencodeNameConstraints,\n\tencodePolicyConstraints,\n\tencodePolicyMappings,\n\tencodeSubjectAltName,\n} from '#micro509/x509/extensions.ts';\nimport type { ParsedDistributionPoint } from '#micro509/x509/parse.ts';\nimport {\n\tparseAuthorityInfoAccess,\n\tparseAuthorityKeyIdentifier,\n\tparseBasicConstraints,\n\tparseCertificatePolicies,\n\tparseCrlDistributionPoints,\n\tparseExtendedKeyUsage,\n\tparseInhibitAnyPolicy,\n\tparseKeyUsage,\n\tparseNameConstraints,\n\tparsePolicyConstraints,\n\tparsePolicyMappings,\n\tparseSubjectAltNames,\n} from '#micro509/x509/parse.ts';\n\n/** Whether an extension applies to certificate parsing, CSR parsing, or both. */\nexport type ExtensionRegistryContext = 'certificate' | 'csr';\n\n/**\n * Readonly snapshot of decoded known extensions collected during parsing.\n *\n * Fields mirror the extension slots on {@linkcode ParsedCertificate}.\n */\nexport interface KnownParsedExtensionAccumulator {\n\t/** Basic Constraints (CA flag + optional pathLength). */\n\treadonly basicConstraints?: BasicConstraints;\n\t/** Key Usage flags (digitalSignature, keyCertSign, etc.). */\n\treadonly keyUsage?: ParsedBitFlags<KeyUsage>;\n\t/** Extended Key Usage purposes (serverAuth, clientAuth, etc.). */\n\treadonly extendedKeyUsage?: readonly ExtendedKeyUsage[];\n\t/** Subject Alternative Names (dns, ip, email, uri, srv, directoryName). */\n\treadonly subjectAltNames?: readonly SubjectAltName[];\n\t/** Name Constraints (permitted/excluded subtrees). */\n\treadonly nameConstraints?: NameConstraints<ParsedNameConstraintForm>;\n\t/** Certificate Policies extension values. */\n\treadonly certificatePolicies?: CertificatePolicies;\n\t/** Policy Mappings from issuer to subject policy domains. */\n\treadonly policyMappings?: PolicyMappings;\n\t/** Policy Constraints (requireExplicitPolicy / inhibitPolicyMapping). */\n\treadonly policyConstraints?: PolicyConstraints;\n\t/** Inhibit Any-Policy skip-certs value. */\n\treadonly inhibitAnyPolicy?: InhibitAnyPolicy;\n\t/** Authority Information Access (OCSP, CA issuers). */\n\treadonly authorityInfoAccess?: readonly AuthorityInformationAccess[];\n\t/** CRL Distribution Points. */\n\treadonly crlDistributionPoints?: readonly ParsedDistributionPoint[];\n\t/** Hex-encoded Subject Key Identifier. */\n\treadonly subjectKeyIdentifier?: string;\n\t/** Hex-encoded Authority Key Identifier. */\n\treadonly authorityKeyIdentifier?: string;\n}\n\n/**\n * Mutable version of {@linkcode KnownParsedExtensionAccumulator} used during\n * extension parsing to progressively fill in decoded values.\n */\nexport interface MutableKnownParsedExtensionAccumulator extends KnownParsedExtensionAccumulator {\n\tbasicConstraints?: BasicConstraints;\n\tkeyUsage?: ParsedBitFlags<KeyUsage>;\n\textendedKeyUsage?: readonly ExtendedKeyUsage[];\n\tsubjectAltNames?: readonly SubjectAltName[];\n\tnameConstraints?: NameConstraints<ParsedNameConstraintForm>;\n\tcertificatePolicies?: CertificatePolicies;\n\tpolicyMappings?: PolicyMappings;\n\tpolicyConstraints?: PolicyConstraints;\n\tinhibitAnyPolicy?: InhibitAnyPolicy;\n\tauthorityInfoAccess?: readonly AuthorityInformationAccess[];\n\tcrlDistributionPoints?: readonly ParsedDistributionPoint[];\n\tsubjectKeyIdentifier?: string;\n\tauthorityKeyIdentifier?: string;\n}\n\n/**\n * Full lifecycle definition for a known X.509 extension: decode, encode,\n * and apply-to-accumulator during parsing.\n *\n * `TParsed` is the type produced when decoding DER; `TInput` is the type\n * accepted when encoding (they may differ, e.g. for NameConstraints).\n */\nexport interface ExtensionDefinition<TParsed, TInput = TParsed> {\n\t/** Dotted-decimal OID of the extension. */\n\treadonly oid: string;\n\t/** Contexts where this extension is valid (`'certificate'`, `'csr'`, or both). */\n\treadonly contexts: readonly ExtensionRegistryContext[];\n\t/** Whether the extension is marked critical by default when encoding. */\n\treadonly defaultCritical: boolean;\n\t/** When true, the extension is computed by the builder (e.g. SKI, AKI) rather than user-supplied. */\n\treadonly autoGenerated?: boolean;\n\t/** Decode the extension's DER extnValue into a typed value. */\n\tdecode(valueDer: Uint8Array): TParsed;\n\t/** Encode a typed input into the extension's DER extnValue. */\n\tencode(value: TInput): Uint8Array;\n\t/** Store a decoded value into the parse-time accumulator. */\n\tapplyParsed(accumulator: MutableKnownParsedExtensionAccumulator, value: TParsed): void;\n}\n\n/**\n * Module-internal decode-and-apply closures, captured at definition time.\n *\n * Each entry is keyed by OID and populated by {@linkcode defineExtensionDefinition}\n * when the concrete generic type is known, avoiding the correlated-union problem\n * that would arise from calling `decode` and `applyParsed` through a union type.\n */\nconst extensionAppliers = new Map<\n\tstring,\n\t(accumulator: MutableKnownParsedExtensionAccumulator, valueDer: Uint8Array) => void\n>();\n\n/** Registry entry for Basic Constraints (OID 2.5.29.19). Critical by default. */\nexport const BASIC_CONSTRAINTS_EXTENSION_DEFINITION: ExtensionDefinition<BasicConstraints> =\n\tdefineExtensionDefinition<BasicConstraints>({\n\t\toid: OIDS.basicConstraints,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: true,\n\t\tdecode: (valueDer) => parseBasicConstraints(valueDer),\n\t\tencode: (value) => encodeBasicConstraints(value),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.basicConstraints = value;\n\t\t},\n\t});\n\n/** Registry entry for Key Usage (OID 2.5.29.15). Critical by default. */\nexport const KEY_USAGE_EXTENSION_DEFINITION: ExtensionDefinition<\n\tParsedBitFlags<KeyUsage>,\n\treadonly KeyUsage[]\n> = defineExtensionDefinition<ParsedBitFlags<KeyUsage>, readonly KeyUsage[]>({\n\toid: OIDS.keyUsage,\n\tcontexts: ['certificate', 'csr'],\n\tdefaultCritical: true,\n\tdecode: (valueDer) => parseKeyUsage(valueDer),\n\tencode: (value) => encodeKeyUsage(value),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.keyUsage = value;\n\t},\n});\n\n/** Registry entry for Extended Key Usage (OID 2.5.29.37). Non-critical by default. */\nexport const EXTENDED_KEY_USAGE_EXTENSION_DEFINITION: ExtensionDefinition<\n\treadonly ExtendedKeyUsage[]\n> = defineExtensionDefinition<readonly ExtendedKeyUsage[]>({\n\toid: OIDS.extendedKeyUsage,\n\tcontexts: ['certificate', 'csr'],\n\tdefaultCritical: false,\n\tdecode: (valueDer) => parseExtendedKeyUsage(valueDer),\n\tencode: (value) => encodeExtendedKeyUsage(value),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.extendedKeyUsage = value;\n\t},\n});\n\n/** Registry entry for Subject Alternative Name (OID 2.5.29.17). Non-critical by default. */\nexport const SUBJECT_ALT_NAME_EXTENSION_DEFINITION: ExtensionDefinition<readonly SubjectAltName[]> =\n\tdefineExtensionDefinition<readonly SubjectAltName[]>({\n\t\toid: OIDS.subjectAltName,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: false,\n\t\tdecode: (valueDer) => parseSubjectAltNames(valueDer),\n\t\tencode: (value) => sequence(value.map(encodeSubjectAltName)),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.subjectAltNames = value;\n\t\t},\n\t});\n\n/** Registry entry for Name Constraints (OID 2.5.29.30). Critical by default. */\nexport const NAME_CONSTRAINTS_EXTENSION_DEFINITION: ExtensionDefinition<\n\tNameConstraints<ParsedNameConstraintForm>,\n\tNameConstraints\n> = defineExtensionDefinition<NameConstraints<ParsedNameConstraintForm>, NameConstraints>({\n\toid: OIDS.nameConstraints,\n\tcontexts: ['certificate', 'csr'],\n\tdefaultCritical: true,\n\tdecode: (valueDer) => parseNameConstraints(valueDer),\n\tencode: (value) => encodeNameConstraints(value),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.nameConstraints = value;\n\t},\n});\n\n/** Registry entry for Certificate Policies (OID 2.5.29.32). Non-critical by default. */\nexport const CERTIFICATE_POLICIES_EXTENSION_DEFINITION: ExtensionDefinition<CertificatePolicies> =\n\tdefineExtensionDefinition<CertificatePolicies>({\n\t\toid: OIDS.certificatePolicies,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: false,\n\t\tdecode: (valueDer) => parseCertificatePolicies(valueDer),\n\t\tencode: (value) => encodeCertificatePolicies(value),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.certificatePolicies = value;\n\t\t},\n\t});\n\n/** Registry entry for Policy Mappings (OID 2.5.29.33). Critical by default. */\nexport const POLICY_MAPPINGS_EXTENSION_DEFINITION: ExtensionDefinition<PolicyMappings> =\n\tdefineExtensionDefinition<PolicyMappings>({\n\t\toid: OIDS.policyMappings,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: true,\n\t\tdecode: (valueDer) => parsePolicyMappings(valueDer),\n\t\tencode: (value) => encodePolicyMappings(value),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.policyMappings = value;\n\t\t},\n\t});\n\n/** Registry entry for Policy Constraints (OID 2.5.29.36). Critical by default. */\nexport const POLICY_CONSTRAINTS_EXTENSION_DEFINITION: ExtensionDefinition<PolicyConstraints> =\n\tdefineExtensionDefinition<PolicyConstraints>({\n\t\toid: OIDS.policyConstraints,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: true,\n\t\tdecode: (valueDer) => parsePolicyConstraints(valueDer),\n\t\tencode: (value) => encodePolicyConstraints(value),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.policyConstraints = value;\n\t\t},\n\t});\n\n/** Registry entry for Inhibit anyPolicy (OID 2.5.29.54). Critical by default. */\nexport const INHIBIT_ANY_POLICY_EXTENSION_DEFINITION: ExtensionDefinition<InhibitAnyPolicy> =\n\tdefineExtensionDefinition<InhibitAnyPolicy>({\n\t\toid: OIDS.inhibitAnyPolicy,\n\t\tcontexts: ['certificate', 'csr'],\n\t\tdefaultCritical: true,\n\t\tdecode: (valueDer) => parseInhibitAnyPolicy(valueDer),\n\t\tencode: (value) => encodeInhibitAnyPolicy(value),\n\t\tapplyParsed: (accumulator, value) => {\n\t\t\taccumulator.inhibitAnyPolicy = value;\n\t\t},\n\t});\n\n/** Registry entry for Authority Information Access (OID 1.3.6.1.5.5.7.1.1). Non-critical. */\nexport const AUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION: ExtensionDefinition<\n\treadonly AuthorityInformationAccess[]\n> = defineExtensionDefinition<readonly AuthorityInformationAccess[]>({\n\toid: OIDS.authorityInfoAccess,\n\tcontexts: ['certificate', 'csr'],\n\tdefaultCritical: false,\n\tdecode: (valueDer) => parseAuthorityInfoAccess(valueDer),\n\tencode: (value) => encodeAuthorityInfoAccess(value),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.authorityInfoAccess = value;\n\t},\n});\n\n/** Registry entry for CRL Distribution Points (OID 2.5.29.31). Non-critical by default. */\nexport const CRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION: ExtensionDefinition<\n\treadonly ParsedDistributionPoint[],\n\treadonly DistributionPoint[]\n> = defineExtensionDefinition<readonly ParsedDistributionPoint[], readonly DistributionPoint[]>({\n\toid: OIDS.cRLDistributionPoints,\n\tcontexts: ['certificate', 'csr'],\n\tdefaultCritical: false,\n\tdecode: (valueDer) => parseCrlDistributionPoints(valueDer),\n\tencode: (value) => encodeCrlDistributionPoints(value),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.crlDistributionPoints = value;\n\t},\n});\n\n/** Registry entry for Subject Key Identifier (OID 2.5.29.14). Auto-generated; non-critical. */\nexport const SUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION: ExtensionDefinition<\n\tstring,\n\tstring | Uint8Array\n> = defineExtensionDefinition<string, string | Uint8Array>({\n\toid: OIDS.subjectKeyIdentifier,\n\tcontexts: ['certificate'],\n\tdefaultCritical: false,\n\tautoGenerated: true,\n\tdecode: (valueDer) => decodeSubjectKeyIdentifier(valueDer),\n\tencode: (value) => octetString(normalizeKeyIdentifier(value)),\n\tapplyParsed: (accumulator, value) => {\n\t\taccumulator.subjectKeyIdentifier = value;\n\t},\n});\n\n/** Registry entry for Authority Key Identifier (OID 2.5.29.35). Auto-generated; non-critical. */\nexport const AUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION: ExtensionDefinition<\n\tstring | undefined,\n\tstring | Uint8Array\n> = defineExtensionDefinition<string | undefined, string | Uint8Array>({\n\toid: OIDS.authorityKeyIdentifier,\n\tcontexts: ['certificate'],\n\tdefaultCritical: false,\n\tautoGenerated: true,\n\tdecode: (valueDer) => parseAuthorityKeyIdentifier(valueDer),\n\tencode: (value) => sequence([implicitPrimitiveContext(0, normalizeKeyIdentifier(value))]),\n\tapplyParsed: (accumulator, value) => {\n\t\tif (value !== undefined) {\n\t\t\taccumulator.authorityKeyIdentifier = value;\n\t\t}\n\t},\n});\n\n/** Union of all built-in extension definition constants. */\nexport type KnownExtensionDefinition =\n\t| typeof BASIC_CONSTRAINTS_EXTENSION_DEFINITION\n\t| typeof KEY_USAGE_EXTENSION_DEFINITION\n\t| typeof EXTENDED_KEY_USAGE_EXTENSION_DEFINITION\n\t| typeof SUBJECT_ALT_NAME_EXTENSION_DEFINITION\n\t| typeof NAME_CONSTRAINTS_EXTENSION_DEFINITION\n\t| typeof CERTIFICATE_POLICIES_EXTENSION_DEFINITION\n\t| typeof POLICY_MAPPINGS_EXTENSION_DEFINITION\n\t| typeof POLICY_CONSTRAINTS_EXTENSION_DEFINITION\n\t| typeof INHIBIT_ANY_POLICY_EXTENSION_DEFINITION\n\t| typeof AUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION\n\t| typeof CRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION\n\t| typeof SUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION\n\t| typeof AUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION;\n\n/** All built-in extension definitions, in registration order. */\nexport const CERT_CSR_EXTENSION_DEFINITIONS: readonly KnownExtensionDefinition[] = [\n\tBASIC_CONSTRAINTS_EXTENSION_DEFINITION,\n\tKEY_USAGE_EXTENSION_DEFINITION,\n\tEXTENDED_KEY_USAGE_EXTENSION_DEFINITION,\n\tSUBJECT_ALT_NAME_EXTENSION_DEFINITION,\n\tNAME_CONSTRAINTS_EXTENSION_DEFINITION,\n\tCERTIFICATE_POLICIES_EXTENSION_DEFINITION,\n\tPOLICY_MAPPINGS_EXTENSION_DEFINITION,\n\tPOLICY_CONSTRAINTS_EXTENSION_DEFINITION,\n\tINHIBIT_ANY_POLICY_EXTENSION_DEFINITION,\n\tAUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION,\n\tCRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION,\n\tSUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n\tAUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n];\n\n/** OID-keyed lookup for known extension definitions. */\nconst EXTENSION_DEFINITION_MAP = new Map<string, KnownExtensionDefinition>(\n\tCERT_CSR_EXTENSION_DEFINITIONS.map((definition) => [definition.oid, definition]),\n);\n\n/**\n * Return all known extension definitions, optionally filtered by context.\n *\n * @param context If provided, only definitions valid in that context are returned.\n */\nexport function listExtensionDefinitions(\n\tcontext?: ExtensionRegistryContext,\n): readonly KnownExtensionDefinition[] {\n\tif (context === undefined) {\n\t\treturn CERT_CSR_EXTENSION_DEFINITIONS;\n\t}\n\treturn CERT_CSR_EXTENSION_DEFINITIONS.filter((definition) =>\n\t\tdefinition.contexts.includes(context),\n\t);\n}\n\n/**\n * Look up a known extension definition by OID.\n *\n * Overloaded for each built-in OID constant to return the exact definition type.\n *\n * @param oid Dotted-decimal extension OID.\n * @returns The matching definition, or `undefined` for unrecognized OIDs.\n */\nexport function getExtensionDefinition(\n\toid: typeof OIDS.basicConstraints,\n): typeof BASIC_CONSTRAINTS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.keyUsage,\n): typeof KEY_USAGE_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.extendedKeyUsage,\n): typeof EXTENDED_KEY_USAGE_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.subjectAltName,\n): typeof SUBJECT_ALT_NAME_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.nameConstraints,\n): typeof NAME_CONSTRAINTS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.certificatePolicies,\n): typeof CERTIFICATE_POLICIES_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.policyMappings,\n): typeof POLICY_MAPPINGS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.policyConstraints,\n): typeof POLICY_CONSTRAINTS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.inhibitAnyPolicy,\n): typeof INHIBIT_ANY_POLICY_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.authorityInfoAccess,\n): typeof AUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.cRLDistributionPoints,\n): typeof CRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.subjectKeyIdentifier,\n): typeof SUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(\n\toid: typeof OIDS.authorityKeyIdentifier,\n): typeof AUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION;\nexport function getExtensionDefinition(oid: string): KnownExtensionDefinition | undefined;\nexport function getExtensionDefinition(oid: string): KnownExtensionDefinition | undefined {\n\treturn EXTENSION_DEFINITION_MAP.get(oid);\n}\n\n/**\n * If `oid` matches a known extension valid in `context`, decode its DER\n * value and store the result in the accumulator.\n *\n * @returns `true` if the extension was recognized and applied.\n */\nexport function decodeAndApplyKnownExtension(\n\tcontext: ExtensionRegistryContext,\n\toid: string,\n\taccumulator: MutableKnownParsedExtensionAccumulator,\n\tvalueDer: Uint8Array,\n): boolean {\n\tconst definition = getExtensionDefinition(oid);\n\tif (definition === undefined || !definition.contexts.includes(context)) {\n\t\treturn false;\n\t}\n\tconst applier = extensionAppliers.get(oid);\n\tif (applier === undefined) {\n\t\treturn false;\n\t}\n\tapplier(accumulator, valueDer);\n\treturn true;\n}\n\n/**\n * Compute a Subject Key Identifier (SHA-1 of the public key bits) from\n * a DER-encoded SubjectPublicKeyInfo.\n */\nexport function buildSubjectKeyIdentifierFromSubjectPublicKeyInfo(\n\tsubjectPublicKeyInfo: Uint8Array,\n): Uint8Array {\n\treturn buildSubjectKeyIdentifier(subjectPublicKeyInfo);\n}\n\n/**\n * Identity helper that narrows the type of an {@linkcode ExtensionDefinition} literal\n * and captures a decode-and-apply closure in {@linkcode extensionAppliers}.\n *\n * The closure is built here — where `TParsed` is concrete — so that\n * `decodeAndApplyKnownExtension` can call it through the union-typed\n * `KnownExtensionDefinition` without hitting TypeScript's correlated-union limitation.\n */\nfunction defineExtensionDefinition<TParsed, TInput = TParsed>(\n\tdefinition: ExtensionDefinition<TParsed, TInput>,\n): ExtensionDefinition<TParsed, TInput> {\n\textensionAppliers.set(definition.oid, (accumulator, valueDer) => {\n\t\tdefinition.applyParsed(accumulator, definition.decode(valueDer));\n\t});\n\treturn definition;\n}\n\n/** Accept hex string or Uint8Array and return raw bytes. */\nfunction normalizeKeyIdentifier(value: string | Uint8Array): Uint8Array {\n\treturn typeof value === 'string' ? hexToBytes(value) : value;\n}\n\n/** Decode an SKI extension value DER to a hex string. */\nfunction decodeSubjectKeyIdentifier(valueDer: Uint8Array): string {\n\tconst element = readRootElement(valueDer, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (element.tag !== 0x04) {\n\t\tthrow new Error('SubjectKeyIdentifier must be an OCTET STRING');\n\t}\n\treturn toHex(element.value);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{ia5String as e,printableString as t,utf8String as n}from"../asn1/der.js";import{OIDS as r}from"../asn1/oids.js";const i={commonName:{oid:r.commonName,encode:n},surname:{oid:r.surname,encode:n},serialNumber:{oid:r.serialNumber,encode:t},country:{oid:r.countryName,encode:t},locality:{oid:r.localityName,encode:n},state:{oid:r.stateOrProvinceName,encode:n},street:{oid:r.streetAddress,encode:n},organization:{oid:r.organizationName,encode:n},organizationalUnit:{oid:r.organizationalUnitName,encode:n},title:{oid:r.title,encode:n},givenName:{oid:r.givenName,encode:n},emailAddress:{oid:r.emailAddress,encode:e}},a=[`country`,`state`,`locality`,`street`,`organization`,`organizationalUnit`,`commonName`,`givenName`,`surname`,`title`,`serialNumber`,`emailAddress`],o=new Map;for(let e of a)o.set(i[e].oid,e);function s(e){return o.get(e)}export{i as NAME_FIELD_DEFINITIONS,a as NAME_OBJECT_ORDER,s as nameFieldKeyFromOid};
|
|
2
|
+
//# sourceMappingURL=name-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-fields.js","names":[],"sources":["../../../src/internal/x509/name-fields.ts"],"sourcesContent":["/**\n * Distinguished-name field metadata.\n *\n * Maps friendly {@linkcode NameFieldKey} names to their ASN.1 OIDs and string-encoding functions.\n * @module\n */\n\nimport { ia5String, printableString, utf8String } from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport type { NameFieldKey } from '#micro509/x509/name.ts';\n\n/**\n * OID and ASN.1 string encoder for one distinguished-name attribute type.\n */\nexport interface NameFieldDefinition {\n\t/** Dotted-decimal OID (e.g. `\"2.5.4.3\"` for commonName). */\n\treadonly oid: string;\n\t/** Encodes the attribute value to the correct ASN.1 string type (UTF8, PrintableString, IA5). */\n\treadonly encode: (value: string) => Uint8Array;\n}\n\n/**\n * Registry mapping every {@linkcode NameFieldKey} to its OID and ASN.1 encoder.\n *\n * Country and serialNumber use PrintableString; emailAddress uses IA5String;\n * all others use UTF8String.\n */\nexport const NAME_FIELD_DEFINITIONS: Record<NameFieldKey, NameFieldDefinition> = {\n\tcommonName: { oid: OIDS.commonName, encode: utf8String },\n\tsurname: { oid: OIDS.surname, encode: utf8String },\n\tserialNumber: { oid: OIDS.serialNumber, encode: printableString },\n\tcountry: { oid: OIDS.countryName, encode: printableString },\n\tlocality: { oid: OIDS.localityName, encode: utf8String },\n\tstate: { oid: OIDS.stateOrProvinceName, encode: utf8String },\n\tstreet: { oid: OIDS.streetAddress, encode: utf8String },\n\torganization: { oid: OIDS.organizationName, encode: utf8String },\n\torganizationalUnit: { oid: OIDS.organizationalUnitName, encode: utf8String },\n\ttitle: { oid: OIDS.title, encode: utf8String },\n\tgivenName: { oid: OIDS.givenName, encode: utf8String },\n\temailAddress: { oid: OIDS.emailAddress, encode: ia5String },\n};\n\n/**\n * Canonical emission order when converting a {@linkcode NameObject} to RDN attributes.\n *\n * Follows the conventional `C/ST/L/STREET/O/OU/CN/…` ordering.\n */\nexport const NAME_OBJECT_ORDER: readonly NameFieldKey[] = [\n\t'country',\n\t'state',\n\t'locality',\n\t'street',\n\t'organization',\n\t'organizationalUnit',\n\t'commonName',\n\t'givenName',\n\t'surname',\n\t'title',\n\t'serialNumber',\n\t'emailAddress',\n];\n\n/** Reverse lookup table: OID string → friendly {@linkcode NameFieldKey}. */\nconst NAME_FIELD_KEYS_BY_OID = new Map<string, NameFieldKey>();\nfor (const key of NAME_OBJECT_ORDER) {\n\tNAME_FIELD_KEYS_BY_OID.set(NAME_FIELD_DEFINITIONS[key].oid, key);\n}\n\n/** Resolves a dotted-decimal OID to its {@linkcode NameFieldKey}, or `undefined` if unknown. */\nexport function nameFieldKeyFromOid(oid: string): NameFieldKey | undefined {\n\treturn NAME_FIELD_KEYS_BY_OID.get(oid);\n}\n"],"mappings":"uHA2BA,MAAa,EAAoE,CAChF,WAAY,CAAE,IAAK,EAAK,WAAY,OAAQ,CAAW,EACvD,QAAS,CAAE,IAAK,EAAK,QAAS,OAAQ,CAAW,EACjD,aAAc,CAAE,IAAK,EAAK,aAAc,OAAQ,CAAgB,EAChE,QAAS,CAAE,IAAK,EAAK,YAAa,OAAQ,CAAgB,EAC1D,SAAU,CAAE,IAAK,EAAK,aAAc,OAAQ,CAAW,EACvD,MAAO,CAAE,IAAK,EAAK,oBAAqB,OAAQ,CAAW,EAC3D,OAAQ,CAAE,IAAK,EAAK,cAAe,OAAQ,CAAW,EACtD,aAAc,CAAE,IAAK,EAAK,iBAAkB,OAAQ,CAAW,EAC/D,mBAAoB,CAAE,IAAK,EAAK,uBAAwB,OAAQ,CAAW,EAC3E,MAAO,CAAE,IAAK,EAAK,MAAO,OAAQ,CAAW,EAC7C,UAAW,CAAE,IAAK,EAAK,UAAW,OAAQ,CAAW,EACrD,aAAc,CAAE,IAAK,EAAK,aAAc,OAAQ,CAAU,CAC3D,EAOa,EAA6C,CACzD,UACA,QACA,WACA,SACA,eACA,qBACA,aACA,YACA,UACA,QACA,eACA,cACD,EAGM,EAAyB,IAAI,IACnC,IAAK,IAAM,KAAO,EACjB,EAAuB,IAAI,EAAuB,EAAI,CAAC,IAAK,CAAG,EAIhE,SAAgB,EAAoB,EAAuC,CAC1E,OAAO,EAAuB,IAAI,CAAG,CACtC"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { Pbes2EncryptionOptions, Pbes2EncryptionScheme, Pbes2Prf } from "../internal/crypto/pbes2.js";
|
|
2
|
+
|
|
3
|
+
//#region src/keys/keys.d.ts
|
|
4
|
+
/** Hash algorithm paired with an RSA key. */
|
|
5
|
+
type RsaHash = "SHA-256" | "SHA-384" | "SHA-512";
|
|
6
|
+
/** RSA signature padding scheme. */
|
|
7
|
+
type RsaScheme = "pkcs1-v1_5" | "pss";
|
|
8
|
+
/** NIST elliptic curve for ECDSA keys. */
|
|
9
|
+
type EcNamedCurve = "P-256" | "P-384" | "P-521";
|
|
10
|
+
/** RSA variant of {@linkcode KeyAlgorithmInput}. */
|
|
11
|
+
interface RsaKeyAlgorithmInput {
|
|
12
|
+
/** Discriminant selecting RSA key generation. */
|
|
13
|
+
readonly kind: "rsa";
|
|
14
|
+
/** RSA modulus size in bits. Defaults to `2048`. */
|
|
15
|
+
readonly modulusLength?: 2048 | 3072 | 4096;
|
|
16
|
+
/** Hash algorithm for the key. Defaults to `'SHA-256'`. */
|
|
17
|
+
readonly hash?: RsaHash;
|
|
18
|
+
/** Signature padding scheme. Defaults to `'pkcs1-v1_5'`. */
|
|
19
|
+
readonly scheme?: RsaScheme;
|
|
20
|
+
}
|
|
21
|
+
/** ECDSA variant of {@linkcode KeyAlgorithmInput}. */
|
|
22
|
+
interface EcKeyAlgorithmInput {
|
|
23
|
+
/** Discriminant selecting ECDSA key generation. */
|
|
24
|
+
readonly kind: "ecdsa";
|
|
25
|
+
/** NIST curve. Defaults to `'P-256'`. */
|
|
26
|
+
readonly curve?: EcNamedCurve;
|
|
27
|
+
}
|
|
28
|
+
/** Ed25519 variant of {@linkcode KeyAlgorithmInput}. */
|
|
29
|
+
interface Ed25519KeyAlgorithmInput {
|
|
30
|
+
/** Discriminant selecting Ed25519 key generation. */
|
|
31
|
+
readonly kind: "ed25519";
|
|
32
|
+
}
|
|
33
|
+
/** Input for {@linkcode generateKeyPair}. Selects algorithm family and parameters. */
|
|
34
|
+
type KeyAlgorithmInput = RsaKeyAlgorithmInput | EcKeyAlgorithmInput | Ed25519KeyAlgorithmInput;
|
|
35
|
+
/** Key pair with convenience export helpers. Returned by {@linkcode generateKeyPair}. */
|
|
36
|
+
interface KeyPairMaterial {
|
|
37
|
+
/** The WebCrypto public key (extractable, `verify` usage). */
|
|
38
|
+
readonly publicKey: CryptoKey;
|
|
39
|
+
/** The WebCrypto private key (extractable, `sign` usage). */
|
|
40
|
+
readonly privateKey: CryptoKey;
|
|
41
|
+
/** Export the public key as DER-encoded SubjectPublicKeyInfo. */
|
|
42
|
+
exportSpkiDer(): Promise<Uint8Array>;
|
|
43
|
+
/** Export the public key as PEM-encoded SubjectPublicKeyInfo. */
|
|
44
|
+
exportSpkiPem(): Promise<string>;
|
|
45
|
+
/** Export the private key as DER-encoded PKCS#8 PrivateKeyInfo. */
|
|
46
|
+
exportPkcs8Der(): Promise<Uint8Array>;
|
|
47
|
+
/** Export the private key as PEM-encoded PKCS#8 PrivateKeyInfo. */
|
|
48
|
+
exportPkcs8Pem(): Promise<string>;
|
|
49
|
+
/** Export the public key as a JSON Web Key. */
|
|
50
|
+
exportPublicJwk(): Promise<JsonWebKey>;
|
|
51
|
+
/** Export the private key as a JSON Web Key. */
|
|
52
|
+
exportPrivateJwk(): Promise<JsonWebKey>;
|
|
53
|
+
}
|
|
54
|
+
/** RSA variant of {@linkcode PublicKeyImportInput}. */
|
|
55
|
+
interface ImportRsaPublicKeyInput {
|
|
56
|
+
/** Discriminant selecting RSA import. */
|
|
57
|
+
readonly kind: "rsa";
|
|
58
|
+
/** Hash algorithm. Defaults to `'SHA-256'`. */
|
|
59
|
+
readonly hash?: RsaHash;
|
|
60
|
+
/** Signature padding scheme. Defaults to `'pkcs1-v1_5'`. */
|
|
61
|
+
readonly scheme?: RsaScheme;
|
|
62
|
+
}
|
|
63
|
+
/** ECDSA variant of {@linkcode PublicKeyImportInput}. */
|
|
64
|
+
interface ImportEcPublicKeyInput {
|
|
65
|
+
/** Discriminant selecting ECDSA import. */
|
|
66
|
+
readonly kind: "ecdsa";
|
|
67
|
+
/** NIST curve the key belongs to. Required for EC import. */
|
|
68
|
+
readonly curve: EcNamedCurve;
|
|
69
|
+
}
|
|
70
|
+
/** Ed25519 variant of {@linkcode PublicKeyImportInput}. */
|
|
71
|
+
interface ImportEd25519PublicKeyInput {
|
|
72
|
+
/** Discriminant selecting Ed25519 import. */
|
|
73
|
+
readonly kind: "ed25519";
|
|
74
|
+
}
|
|
75
|
+
/** Algorithm descriptor for public key import functions. */
|
|
76
|
+
type PublicKeyImportInput = ImportRsaPublicKeyInput | ImportEcPublicKeyInput | ImportEd25519PublicKeyInput;
|
|
77
|
+
/** Algorithm descriptor for private key import functions. Same shape as {@linkcode PublicKeyImportInput}. */
|
|
78
|
+
type PrivateKeyImportInput = PublicKeyImportInput;
|
|
79
|
+
/** PBES2 encryption options for {@linkcode exportEncryptedPkcs8Der} and {@linkcode exportEncryptedPkcs8Pem}. */
|
|
80
|
+
type EncryptedPkcs8Options = Pbes2EncryptionOptions;
|
|
81
|
+
/** Options for OpenSSL-style `Proc-Type: 4,ENCRYPTED` PEM encryption (PKCS#1/SEC1). */
|
|
82
|
+
interface LegacyPemEncryptionOptions {
|
|
83
|
+
/** Passphrase used to derive the encryption key. */
|
|
84
|
+
readonly password: string;
|
|
85
|
+
/** 16-byte initialization vector. Random when omitted. */
|
|
86
|
+
readonly iv?: Uint8Array;
|
|
87
|
+
/** AES-CBC cipher. Defaults to `'AES-256-CBC'`. */
|
|
88
|
+
readonly cipher?: "AES-128-CBC" | "AES-192-CBC" | "AES-256-CBC";
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Generate an asymmetric key pair for signing and verification.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const ecKeys = await generateKeyPair({ kind: 'ecdsa', curve: 'P-384' });
|
|
96
|
+
* const rsaKeys = await generateKeyPair({ kind: 'rsa', modulusLength: 4096 });
|
|
97
|
+
* const edKeys = await generateKeyPair({ kind: 'ed25519' });
|
|
98
|
+
*
|
|
99
|
+
* // Default: ECDSA P-256
|
|
100
|
+
* const keys = await generateKeyPair();
|
|
101
|
+
* const pem = await keys.exportPkcs8Pem();
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare function generateKeyPair(algorithm?: KeyAlgorithmInput): Promise<KeyPairMaterial>;
|
|
105
|
+
/**
|
|
106
|
+
* Export a public key as DER-encoded SubjectPublicKeyInfo.
|
|
107
|
+
*
|
|
108
|
+
* @see {@linkcode importSpkiDer} for the inverse operation
|
|
109
|
+
* @see {@linkcode exportSpkiPem} for PEM output
|
|
110
|
+
*/
|
|
111
|
+
declare function exportSpkiDer(publicKey: CryptoKey): Promise<Uint8Array>;
|
|
112
|
+
/**
|
|
113
|
+
* Export a private key as DER-encoded PKCS#8 PrivateKeyInfo.
|
|
114
|
+
*
|
|
115
|
+
* @see {@linkcode importPkcs8Der} for the inverse operation
|
|
116
|
+
* @see {@linkcode exportPkcs8Pem} for PEM output
|
|
117
|
+
* @see {@linkcode exportEncryptedPkcs8Der} for password-protected export
|
|
118
|
+
*/
|
|
119
|
+
declare function exportPkcs8Der(privateKey: CryptoKey): Promise<Uint8Array>;
|
|
120
|
+
/**
|
|
121
|
+
* Export a public key as a JSON Web Key.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const keys = await generateKeyPair({ kind: 'ecdsa', curve: 'P-256' });
|
|
126
|
+
* const jwk = await exportPublicJwk(keys.publicKey);
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
declare function exportPublicJwk(publicKey: CryptoKey): Promise<JsonWebKey>;
|
|
130
|
+
/**
|
|
131
|
+
* Export a private key as a JSON Web Key.
|
|
132
|
+
*
|
|
133
|
+
* @see {@linkcode importPrivateJwk} for the inverse operation
|
|
134
|
+
* @see {@linkcode exportPublicJwk} for public key export
|
|
135
|
+
*/
|
|
136
|
+
declare function exportPrivateJwk(privateKey: CryptoKey): Promise<JsonWebKey>;
|
|
137
|
+
/**
|
|
138
|
+
* Export a private key as PEM-encoded PKCS#8 PrivateKeyInfo.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* const keys = await generateKeyPair();
|
|
143
|
+
* const pem = await exportPkcs8Pem(keys.privateKey);
|
|
144
|
+
* // -----BEGIN PRIVATE KEY-----
|
|
145
|
+
* // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEH...
|
|
146
|
+
* // -----END PRIVATE KEY-----
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @see {@linkcode importPkcs8Pem} for the inverse operation
|
|
150
|
+
* @see {@linkcode exportEncryptedPkcs8Pem} for password-protected export
|
|
151
|
+
*/
|
|
152
|
+
declare function exportPkcs8Pem(privateKey: CryptoKey): Promise<string>;
|
|
153
|
+
/**
|
|
154
|
+
* Export a private key as DER-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.
|
|
155
|
+
*
|
|
156
|
+
* Uses PBES2 (PKCS#5 v2.1) with AES-CBC and PBKDF2. Compatible with OpenSSL.
|
|
157
|
+
*
|
|
158
|
+
* @param privateKey - The private key to export
|
|
159
|
+
* @param options - Encryption options including password and optional algorithm settings
|
|
160
|
+
*
|
|
161
|
+
* @see {@linkcode importEncryptedPkcs8Der} for the inverse operation
|
|
162
|
+
* @see {@linkcode exportEncryptedPkcs8Pem} for PEM output
|
|
163
|
+
*/
|
|
164
|
+
declare function exportEncryptedPkcs8Der(privateKey: CryptoKey, options: EncryptedPkcs8Options): Promise<Uint8Array>;
|
|
165
|
+
/**
|
|
166
|
+
* Export a private key as PEM-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* const keys = await generateKeyPair();
|
|
171
|
+
* const pem = await exportEncryptedPkcs8Pem(keys.privateKey, { password: 'secret' });
|
|
172
|
+
* // -----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
173
|
+
* // MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAc...
|
|
174
|
+
* // -----END ENCRYPTED PRIVATE KEY-----
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @see {@linkcode importEncryptedPkcs8Pem} for the inverse operation
|
|
178
|
+
*/
|
|
179
|
+
declare function exportEncryptedPkcs8Pem(privateKey: CryptoKey, options: EncryptedPkcs8Options): Promise<string>;
|
|
180
|
+
/**
|
|
181
|
+
* Export an RSA private key as DER-encoded PKCS#1 RSAPrivateKey.
|
|
182
|
+
*
|
|
183
|
+
* PKCS#1 is the legacy RSA-only format. For algorithm-agnostic export, use
|
|
184
|
+
* {@linkcode exportPkcs8Der}.
|
|
185
|
+
*
|
|
186
|
+
* @throws {Error} If the key is not an RSA key
|
|
187
|
+
*
|
|
188
|
+
* @see {@linkcode importPkcs1Der} for the inverse operation
|
|
189
|
+
* @see {@linkcode exportPkcs1Pem} for PEM output
|
|
190
|
+
*/
|
|
191
|
+
declare function exportPkcs1Der(privateKey: CryptoKey): Promise<Uint8Array>;
|
|
192
|
+
/**
|
|
193
|
+
* Export an RSA private key as PEM-encoded PKCS#1 RSAPrivateKey.
|
|
194
|
+
*
|
|
195
|
+
* @throws {Error} If the key is not an RSA key
|
|
196
|
+
*
|
|
197
|
+
* @see {@linkcode importPkcs1Pem} for the inverse operation
|
|
198
|
+
* @see {@linkcode exportEncryptedPkcs1Pem} for password-protected export
|
|
199
|
+
*/
|
|
200
|
+
declare function exportPkcs1Pem(privateKey: CryptoKey): Promise<string>;
|
|
201
|
+
/**
|
|
202
|
+
* Export an RSA private key as legacy `Proc-Type: 4,ENCRYPTED` PEM (PKCS#1).
|
|
203
|
+
*
|
|
204
|
+
* Uses OpenSSL's traditional PEM encryption with MD5-based key derivation.
|
|
205
|
+
* For modern encryption, prefer {@linkcode exportEncryptedPkcs8Pem}.
|
|
206
|
+
*
|
|
207
|
+
* @throws {Error} If the key is not an RSA key
|
|
208
|
+
*
|
|
209
|
+
* @see {@linkcode importEncryptedPkcs1Pem} for the inverse operation
|
|
210
|
+
*/
|
|
211
|
+
declare function exportEncryptedPkcs1Pem(privateKey: CryptoKey, options: LegacyPemEncryptionOptions): Promise<string>;
|
|
212
|
+
/**
|
|
213
|
+
* Export an EC private key as DER-encoded SEC 1 ECPrivateKey.
|
|
214
|
+
*
|
|
215
|
+
* SEC 1 is the legacy EC-only format. For algorithm-agnostic export, use
|
|
216
|
+
* {@linkcode exportPkcs8Der}.
|
|
217
|
+
*
|
|
218
|
+
* @throws {Error} If the key is not an EC key
|
|
219
|
+
*
|
|
220
|
+
* @see {@linkcode importSec1Der} for the inverse operation
|
|
221
|
+
* @see {@linkcode exportSec1Pem} for PEM output
|
|
222
|
+
*/
|
|
223
|
+
declare function exportSec1Der(privateKey: CryptoKey): Promise<Uint8Array>;
|
|
224
|
+
/**
|
|
225
|
+
* Export an EC private key as PEM-encoded SEC 1 ECPrivateKey.
|
|
226
|
+
*
|
|
227
|
+
* @throws {Error} If the key is not an EC key
|
|
228
|
+
*
|
|
229
|
+
* @see {@linkcode importSec1Pem} for the inverse operation
|
|
230
|
+
* @see {@linkcode exportEncryptedSec1Pem} for password-protected export
|
|
231
|
+
*/
|
|
232
|
+
declare function exportSec1Pem(privateKey: CryptoKey): Promise<string>;
|
|
233
|
+
/**
|
|
234
|
+
* Export an EC private key as legacy `Proc-Type: 4,ENCRYPTED` PEM (SEC 1).
|
|
235
|
+
*
|
|
236
|
+
* Uses OpenSSL's traditional PEM encryption with MD5-based key derivation.
|
|
237
|
+
* For modern encryption, prefer {@linkcode exportEncryptedPkcs8Pem}.
|
|
238
|
+
*
|
|
239
|
+
* @throws {Error} If the key is not an EC key
|
|
240
|
+
*
|
|
241
|
+
* @see {@linkcode importEncryptedSec1Pem} for the inverse operation
|
|
242
|
+
*/
|
|
243
|
+
declare function exportEncryptedSec1Pem(privateKey: CryptoKey, options: LegacyPemEncryptionOptions): Promise<string>;
|
|
244
|
+
/**
|
|
245
|
+
* Export a public key as PEM-encoded SubjectPublicKeyInfo.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```ts
|
|
249
|
+
* const keys = await generateKeyPair();
|
|
250
|
+
* const pem = await exportSpkiPem(keys.publicKey);
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
declare function exportSpkiPem(publicKey: CryptoKey): Promise<string>;
|
|
254
|
+
/**
|
|
255
|
+
* Export a key as raw base64 (no PEM headers).
|
|
256
|
+
*
|
|
257
|
+
* Returns SPKI-encoded base64 for public keys, PKCS#8-encoded base64 for private keys.
|
|
258
|
+
* Useful for compact storage or transmission where PEM overhead is undesirable.
|
|
259
|
+
*
|
|
260
|
+
* @throws {Error} If the key is a symmetric/secret key
|
|
261
|
+
*
|
|
262
|
+
* @see {@linkcode importSpkiBase64} for public key import
|
|
263
|
+
* @see {@linkcode importPkcs8Base64} for private key import
|
|
264
|
+
*/
|
|
265
|
+
declare function exportBinaryBase64(key: CryptoKey): Promise<string>;
|
|
266
|
+
/**
|
|
267
|
+
* Import a public key from DER-encoded SubjectPublicKeyInfo.
|
|
268
|
+
*
|
|
269
|
+
* @param der - DER-encoded SubjectPublicKeyInfo bytes
|
|
270
|
+
* @param algorithm - Expected algorithm (must match key contents)
|
|
271
|
+
* @returns Extractable CryptoKey with `verify` usage
|
|
272
|
+
*
|
|
273
|
+
* @throws {Error} If DER is malformed or algorithm doesn't match key
|
|
274
|
+
*
|
|
275
|
+
* @see {@linkcode exportSpkiDer} for the inverse operation
|
|
276
|
+
* @see {@linkcode importSpkiPem} for PEM input
|
|
277
|
+
*/
|
|
278
|
+
declare function importSpkiDer(der: Uint8Array, algorithm: PublicKeyImportInput): Promise<CryptoKey>;
|
|
279
|
+
/**
|
|
280
|
+
* Import a public key from PEM-encoded SubjectPublicKeyInfo.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* const pem = `-----BEGIN PUBLIC KEY-----
|
|
285
|
+
* MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
|
|
286
|
+
* -----END PUBLIC KEY-----`;
|
|
287
|
+
* const key = await importSpkiPem(pem, { kind: 'ecdsa', curve: 'P-256' });
|
|
288
|
+
* ```
|
|
289
|
+
*
|
|
290
|
+
* @see {@linkcode exportSpkiPem} for the inverse operation
|
|
291
|
+
*/
|
|
292
|
+
declare function importSpkiPem(pem: string, algorithm: PublicKeyImportInput): Promise<CryptoKey>;
|
|
293
|
+
/**
|
|
294
|
+
* Import a public key from base64-encoded SubjectPublicKeyInfo (no PEM headers).
|
|
295
|
+
*
|
|
296
|
+
* @see {@linkcode exportBinaryBase64} for the inverse operation
|
|
297
|
+
* @see {@linkcode importSpkiPem} for PEM input with headers
|
|
298
|
+
*/
|
|
299
|
+
declare function importSpkiBase64(base64: string, algorithm: PublicKeyImportInput): Promise<CryptoKey>;
|
|
300
|
+
/**
|
|
301
|
+
* Import a private key from DER-encoded PKCS#8 PrivateKeyInfo.
|
|
302
|
+
*
|
|
303
|
+
* @param der - DER-encoded PKCS#8 PrivateKeyInfo bytes
|
|
304
|
+
* @param algorithm - Expected algorithm (must match key contents)
|
|
305
|
+
* @returns Extractable CryptoKey with `sign` usage
|
|
306
|
+
*
|
|
307
|
+
* @throws {Error} If DER is malformed or algorithm doesn't match key
|
|
308
|
+
*
|
|
309
|
+
* @see {@linkcode exportPkcs8Der} for the inverse operation
|
|
310
|
+
* @see {@linkcode importPkcs8Pem} for PEM input
|
|
311
|
+
* @see {@linkcode importEncryptedPkcs8Der} for encrypted PKCS#8
|
|
312
|
+
*/
|
|
313
|
+
declare function importPkcs8Der(der: Uint8Array, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
314
|
+
/**
|
|
315
|
+
* Import a private key from PEM-encoded PKCS#8 PrivateKeyInfo.
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```ts
|
|
319
|
+
* const key = await importPkcs8Pem(pemString, { kind: 'ecdsa', curve: 'P-256' });
|
|
320
|
+
* ```
|
|
321
|
+
*/
|
|
322
|
+
declare function importPkcs8Pem(pem: string, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
323
|
+
/**
|
|
324
|
+
* Import a private key from DER-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.
|
|
325
|
+
*
|
|
326
|
+
* Decrypts the PBES2 envelope using the provided password, then imports the key.
|
|
327
|
+
*
|
|
328
|
+
* @param der - DER-encoded EncryptedPrivateKeyInfo bytes
|
|
329
|
+
* @param password - Decryption password
|
|
330
|
+
* @param algorithm - Expected algorithm (must match decrypted key)
|
|
331
|
+
*
|
|
332
|
+
* @throws {Error} If DER is malformed, password is wrong, or algorithm doesn't match
|
|
333
|
+
*
|
|
334
|
+
* @see {@linkcode exportEncryptedPkcs8Der} for the inverse operation
|
|
335
|
+
*/
|
|
336
|
+
declare function importEncryptedPkcs8Der(der: Uint8Array, password: string, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
337
|
+
/**
|
|
338
|
+
* Import a private key from PEM-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* const key = await importEncryptedPkcs8Pem(pem, 'secret', { kind: 'rsa' });
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
declare function importEncryptedPkcs8Pem(pem: string, password: string, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
346
|
+
/**
|
|
347
|
+
* Import an RSA private key from DER-encoded PKCS#1 RSAPrivateKey.
|
|
348
|
+
*
|
|
349
|
+
* PKCS#1 is the legacy RSA-only format. Internally converts to PKCS#8 for import.
|
|
350
|
+
*
|
|
351
|
+
* @see {@linkcode exportPkcs1Der} for the inverse operation
|
|
352
|
+
* @see {@linkcode importPkcs1Pem} for PEM input
|
|
353
|
+
*/
|
|
354
|
+
declare function importPkcs1Der(der: Uint8Array, algorithm?: ImportRsaPublicKeyInput): Promise<CryptoKey>;
|
|
355
|
+
/**
|
|
356
|
+
* Import an RSA private key from PEM-encoded PKCS#1 RSAPrivateKey.
|
|
357
|
+
*
|
|
358
|
+
* Expects the `-----BEGIN RSA PRIVATE KEY-----` PEM label.
|
|
359
|
+
*
|
|
360
|
+
* @see {@linkcode exportPkcs1Pem} for the inverse operation
|
|
361
|
+
* @see {@linkcode importEncryptedPkcs1Pem} for encrypted PEM
|
|
362
|
+
*/
|
|
363
|
+
declare function importPkcs1Pem(pem: string, algorithm?: ImportRsaPublicKeyInput): Promise<CryptoKey>;
|
|
364
|
+
/**
|
|
365
|
+
* Import an RSA private key from legacy `Proc-Type: 4,ENCRYPTED` PEM (PKCS#1).
|
|
366
|
+
*
|
|
367
|
+
* Decrypts OpenSSL's traditional PEM encryption format.
|
|
368
|
+
*
|
|
369
|
+
* @see {@linkcode exportEncryptedPkcs1Pem} for the inverse operation
|
|
370
|
+
* @see {@linkcode importEncryptedPkcs8Pem} for modern PBES2 encryption
|
|
371
|
+
*/
|
|
372
|
+
declare function importEncryptedPkcs1Pem(pem: string, password: string, algorithm?: ImportRsaPublicKeyInput): Promise<CryptoKey>;
|
|
373
|
+
/**
|
|
374
|
+
* Import a private key from base64-encoded PKCS#8 PrivateKeyInfo (no PEM headers).
|
|
375
|
+
*
|
|
376
|
+
* @see {@linkcode exportBinaryBase64} for the inverse operation
|
|
377
|
+
* @see {@linkcode importPkcs8Pem} for PEM input with headers
|
|
378
|
+
*/
|
|
379
|
+
declare function importPkcs8Base64(base64: string, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
380
|
+
/**
|
|
381
|
+
* Import an EC private key from DER-encoded SEC 1 ECPrivateKey.
|
|
382
|
+
*
|
|
383
|
+
* SEC 1 is the legacy EC-only format. Internally converts to PKCS#8 for import.
|
|
384
|
+
*
|
|
385
|
+
* @see {@linkcode exportSec1Der} for the inverse operation
|
|
386
|
+
* @see {@linkcode importSec1Pem} for PEM input
|
|
387
|
+
*/
|
|
388
|
+
declare function importSec1Der(der: Uint8Array, algorithm: ImportEcPublicKeyInput): Promise<CryptoKey>;
|
|
389
|
+
/**
|
|
390
|
+
* Import an EC private key from PEM-encoded SEC 1 ECPrivateKey.
|
|
391
|
+
*
|
|
392
|
+
* Expects the `-----BEGIN EC PRIVATE KEY-----` PEM label.
|
|
393
|
+
*
|
|
394
|
+
* @see {@linkcode exportSec1Pem} for the inverse operation
|
|
395
|
+
* @see {@linkcode importEncryptedSec1Pem} for encrypted PEM
|
|
396
|
+
*/
|
|
397
|
+
declare function importSec1Pem(pem: string, algorithm: ImportEcPublicKeyInput): Promise<CryptoKey>;
|
|
398
|
+
/**
|
|
399
|
+
* Import an EC private key from legacy `Proc-Type: 4,ENCRYPTED` PEM (SEC 1).
|
|
400
|
+
*
|
|
401
|
+
* Decrypts OpenSSL's traditional PEM encryption format.
|
|
402
|
+
*
|
|
403
|
+
* @see {@linkcode exportEncryptedSec1Pem} for the inverse operation
|
|
404
|
+
* @see {@linkcode importEncryptedPkcs8Pem} for modern PBES2 encryption
|
|
405
|
+
*/
|
|
406
|
+
declare function importEncryptedSec1Pem(pem: string, password: string, algorithm: ImportEcPublicKeyInput): Promise<CryptoKey>;
|
|
407
|
+
/**
|
|
408
|
+
* Import a public verification key from a JSON Web Key.
|
|
409
|
+
*
|
|
410
|
+
* @param jwk - JSON Web Key object with public key components
|
|
411
|
+
* @param algorithm - Expected algorithm (must match JWK's `kty` and `crv`)
|
|
412
|
+
* @returns Extractable CryptoKey with `verify` usage
|
|
413
|
+
*
|
|
414
|
+
* @throws {Error} If JWK is malformed or algorithm doesn't match
|
|
415
|
+
*
|
|
416
|
+
* @see {@linkcode exportPublicJwk} for the inverse operation
|
|
417
|
+
*/
|
|
418
|
+
declare function importPublicJwk(jwk: JsonWebKey, algorithm: PublicKeyImportInput): Promise<CryptoKey>;
|
|
419
|
+
/**
|
|
420
|
+
* Import a private signing key from a JSON Web Key.
|
|
421
|
+
*
|
|
422
|
+
* @example
|
|
423
|
+
* ```ts
|
|
424
|
+
* const jwk = { kty: 'EC', crv: 'P-256', x: '...', y: '...', d: '...' };
|
|
425
|
+
* const key = await importPrivateJwk(jwk, { kind: 'ecdsa', curve: 'P-256' });
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
declare function importPrivateJwk(jwk: JsonWebKey, algorithm: PrivateKeyImportInput): Promise<CryptoKey>;
|
|
429
|
+
//#endregion
|
|
430
|
+
export { EcKeyAlgorithmInput, EcNamedCurve, Ed25519KeyAlgorithmInput, EncryptedPkcs8Options, ImportEcPublicKeyInput, ImportEd25519PublicKeyInput, ImportRsaPublicKeyInput, KeyAlgorithmInput, KeyPairMaterial, LegacyPemEncryptionOptions, type Pbes2EncryptionOptions, type Pbes2EncryptionScheme, type Pbes2Prf, PrivateKeyImportInput, PublicKeyImportInput, RsaHash, RsaKeyAlgorithmInput, RsaScheme, exportBinaryBase64, exportEncryptedPkcs1Pem, exportEncryptedPkcs8Der, exportEncryptedPkcs8Pem, exportEncryptedSec1Pem, exportPkcs1Der, exportPkcs1Pem, exportPkcs8Der, exportPkcs8Pem, exportPrivateJwk, exportPublicJwk, exportSec1Der, exportSec1Pem, exportSpkiDer, exportSpkiPem, generateKeyPair, importEncryptedPkcs1Pem, importEncryptedPkcs8Der, importEncryptedPkcs8Pem, importEncryptedSec1Pem, importPkcs1Der, importPkcs1Pem, importPkcs8Base64, importPkcs8Der, importPkcs8Pem, importPrivateJwk, importPublicJwk, importSec1Der, importSec1Pem, importSpkiBase64, importSpkiDer, importSpkiPem };
|
|
431
|
+
//# sourceMappingURL=keys.d.ts.map
|