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":"extensions.js","names":["_exhaustive"],"sources":["../../src/x509/extensions.ts"],"sourcesContent":["/**\n * Typed certificate and CSR extension model plus ASN.1 encoder helpers.\n *\n * Defines input types for every supported X.509v3 extension (RFC 5280) and\n * the DER encoders consumed by certificate and CSR builder flows.\n *\n * @module\n */\n\nimport { hexToBytes } from '#micro509/internal/asn1/asn1.ts';\nimport {\n\tbool,\n\tconcatBytes,\n\tDEFAULT_MAX_DER_DEPTH,\n\texplicitContext,\n\tia5String,\n\timplicitConstructedContext,\n\timplicitPrimitiveContext,\n\tintegerFromNumber,\n\tobjectIdentifier,\n\toctetString,\n\treadElement,\n\treadRootElement,\n\treadSequenceChildren,\n\tsequence,\n\ttlv,\n\tutf8String,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport { sha1 } from '#micro509/internal/crypto/hash.ts';\nimport { parseIpAddressToBytes } from '#micro509/internal/shared/ip.ts';\nimport {\n\tencodeDistributionPointReasonFlagsContent,\n\tencodeKeyUsageExtension,\n} from '#micro509/internal/x509/extension-bits.ts';\nimport type {\n\tExtensionDefinition,\n\tExtensionRegistryContext,\n} from '#micro509/internal/x509/extension-registry.ts';\nimport {\n\tAUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION,\n\tAUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n\tBASIC_CONSTRAINTS_EXTENSION_DEFINITION,\n\tCERTIFICATE_POLICIES_EXTENSION_DEFINITION,\n\tCRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION,\n\tEXTENDED_KEY_USAGE_EXTENSION_DEFINITION,\n\tgetExtensionDefinition,\n\tINHIBIT_ANY_POLICY_EXTENSION_DEFINITION,\n\tKEY_USAGE_EXTENSION_DEFINITION,\n\tNAME_CONSTRAINTS_EXTENSION_DEFINITION,\n\tPOLICY_CONSTRAINTS_EXTENSION_DEFINITION,\n\tPOLICY_MAPPINGS_EXTENSION_DEFINITION,\n\tSUBJECT_ALT_NAME_EXTENSION_DEFINITION,\n\tSUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n} from '#micro509/internal/x509/extension-registry.ts';\nimport type { RelativeDistinguishedNameInput } from './name.ts';\nimport { encodeRelativeDistinguishedName } from './name.ts';\n\nexport type { NameAttribute, NameFieldKey, RelativeDistinguishedNameInput } from './name.ts';\n\n/**\n * RFC 5280 §4.2.1.3 Key Usage bit flag.\n *\n * Each value corresponds to one bit in the KeyUsage BIT STRING.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 RFC 5280 §4.2.1.3}\n */\nexport type KeyUsage =\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\n/**\n * RFC 5280 §4.2.1.6 Subject Alternative Name / GeneralName.\n *\n * Discriminated union keyed on `type`.\n *\n * The `'unknown'` variant preserves unrecognized {@linkcode GeneralName} tags for round-trip fidelity.\n */\nexport type SubjectAltName =\n\t| {\n\t\t\t/** DNS hostname (dNSName [2]). */\n\t\t\treadonly type: 'dns';\n\t\t\t/** Fully-qualified domain name, e.g. `\"example.com\"`. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** IP address (iPAddress [7]). */\n\t\t\treadonly type: 'ip';\n\t\t\t/** Dotted-decimal IPv4 or colon-hex IPv6 string. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** Email address (rfc822Name [1]). */\n\t\t\treadonly type: 'email';\n\t\t\t/** RFC 822 mailbox, e.g. `\"admin@example.com\"`. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** URI (uniformResourceIdentifier [6]). */\n\t\t\treadonly type: 'uri';\n\t\t\t/** Absolute URI string. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** SRV-ID otherName (id-on-dnsSRV). */\n\t\t\treadonly type: 'srv';\n\t\t\t/** SRV service name, e.g. `\"_imaps.example.com\"`. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** X.500 directory name (directoryName [4]). */\n\t\t\treadonly type: 'directoryName';\n\t\t\t/** Hex-encoded DER of the Name SEQUENCE. */\n\t\t\treadonly derHex: string;\n\t }\n\t| {\n\t\t\t/** Unrecognized {@linkcode GeneralName} tag, preserved as raw bytes. */\n\t\t\treadonly type: 'unknown';\n\t\t\t/** ASN.1 context tag number. */\n\t\t\treadonly tag: number;\n\t\t\t/** Raw content bytes of the element. */\n\t\t\treadonly value: Uint8Array;\n\t };\n\n/** Alias for {@linkcode SubjectAltName} — used where RFC 5280 says \"GeneralName\". */\nexport type GeneralName = SubjectAltName;\n\n/**\n * Revocation reason flags for CRL Distribution Points and Issuing Distribution Points\n * (RFC 5280 §4.2.1.13, §5.2.5).\n */\nexport type DistributionPointReason =\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\n/**\n * Name component of a CRL Distribution Point (RFC 5280 §4.2.1.13).\n *\n * Supply exactly one of `fullName` or `relativeName`.\n */\nexport interface DistributionPointName {\n\t/** Absolute {@linkcode GeneralName}(s) identifying the distribution point (usually a URI). */\n\treadonly fullName?: readonly GeneralName[];\n\t/** Name relative to the issuer's DN; mutually exclusive with `fullName`. */\n\treadonly relativeName?: RelativeDistinguishedNameInput;\n}\n\n/**\n * Input for a single CRL Distribution Point (RFC 5280 §4.2.1.13).\n *\n * At least one of `distributionPoint` or `crlIssuer` must be provided.\n * The union enforces this constraint at the type level.\n */\nexport type DistributionPoint =\n\t| {\n\t\t\t/** Where to fetch the CRL (fullName or relativeName). */\n\t\t\treadonly distributionPoint: DistributionPointName;\n\t\t\t/** Revocation reason subset. Absent means all reasons. */\n\t\t\treadonly reasons?: readonly DistributionPointReason[];\n\t\t\t/** Entity that signed the CRL, when different from the cert issuer. */\n\t\t\treadonly crlIssuer?: readonly GeneralName[];\n\t }\n\t| {\n\t\t\t/** Where to fetch the CRL. Optional when `crlIssuer` is present. */\n\t\t\treadonly distributionPoint?: DistributionPointName;\n\t\t\t/** Revocation reason subset. Absent means all reasons. */\n\t\t\treadonly reasons?: readonly DistributionPointReason[];\n\t\t\t/** Entity that signed the CRL. Required when `distributionPoint` is absent. */\n\t\t\treadonly crlIssuer: readonly GeneralName[];\n\t };\n\n/** Base shape for Issuing Distribution Point (RFC 5280 §5.2.5) — no scope restriction. */\nexport interface IssuingDistributionPointBase {\n\t/** Where to fetch this CRL. */\n\treadonly distributionPoint?: DistributionPointName;\n\t/** Limits the CRL to these revocation reasons. Absent means all reasons. */\n\treadonly onlySomeReasons?: readonly DistributionPointReason[];\n\t/** When true, the CRL may contain entries from other CAs. Default false. */\n\treadonly indirectCrl?: boolean;\n\t/** Must be absent or false in this variant (no user-cert-only restriction). */\n\treadonly onlyContainsUserCerts?: false;\n\t/** Must be absent or false in this variant (no CA-cert-only restriction). */\n\treadonly onlyContainsCACerts?: false;\n\t/** When true, the CRL only covers attribute certificates. Default false. */\n\treadonly onlyContainsAttributeCerts?: boolean;\n}\n\n/** IDP scoped to end-entity (user) certificates only. Mutually exclusive with CA / attribute scopes. */\nexport interface IssuingDistributionPointForUserCerts\n\textends Omit<IssuingDistributionPointBase, 'onlyContainsUserCerts'> {\n\t/** This variant only covers end-entity certificates. */\n\treadonly onlyContainsUserCerts: true;\n\t/** Must be absent or false when the CRL is not CA-only. */\n\treadonly onlyContainsCACerts?: false;\n\t/** Must be absent or false when the CRL is not attribute-cert-only. */\n\treadonly onlyContainsAttributeCerts?: false;\n}\n\n/** IDP scoped to CA certificates only. Mutually exclusive with user / attribute scopes. */\nexport interface IssuingDistributionPointForCaCerts\n\textends Omit<IssuingDistributionPointBase, 'onlyContainsCACerts'> {\n\t/** Must be absent or false when the CRL is not user-cert-only. */\n\treadonly onlyContainsUserCerts?: false;\n\t/** This variant only covers CA certificates. */\n\treadonly onlyContainsCACerts: true;\n\t/** Must be absent or false when the CRL is not attribute-cert-only. */\n\treadonly onlyContainsAttributeCerts?: false;\n}\n\n/** IDP scoped to attribute certificates only. Mutually exclusive with user / CA scopes. */\nexport interface IssuingDistributionPointForAttributeCerts\n\textends Omit<IssuingDistributionPointBase, 'onlyContainsAttributeCerts'> {\n\t/** Must be absent or false when the CRL is not user-cert-only. */\n\treadonly onlyContainsUserCerts?: false;\n\t/** Must be absent or false when the CRL is not CA-only. */\n\treadonly onlyContainsCACerts?: false;\n\t/** This variant only covers attribute certificates. */\n\treadonly onlyContainsAttributeCerts: true;\n}\n\n/**\n * Input for the Issuing Distribution Point CRL extension (RFC 5280 §5.2.5).\n *\n * The union enforces that at most one of the `onlyContains*` flags is true.\n */\nexport type IssuingDistributionPoint =\n\t| IssuingDistributionPointBase\n\t| IssuingDistributionPointForUserCerts\n\t| IssuingDistributionPointForCaCerts\n\t| IssuingDistributionPointForAttributeCerts;\n\n/**\n * RFC 5280 §4.2.1.9 Basic Constraints.\n *\n * A certificate with `ca: true` may issue other certificates; `pathLength`\n * limits how many additional CAs may appear below it in the chain.\n */\nexport interface BasicConstraints {\n\t/** Whether this certificate belongs to a CA. End-entity certs set this to `false`. */\n\treadonly ca: boolean;\n\t/** Maximum number of intermediate CA certificates allowed below this CA. Only valid when `ca` is `true`. */\n\treadonly pathLength?: number;\n}\n\n/** A single certificate policy: an OID plus optional qualifiers. */\nexport interface PolicyInformation {\n\t/** Dotted-decimal OID of the policy (e.g. `\"2.23.140.1.2.1\"` for DV). */\n\treadonly policyIdentifier: string;\n\t/** Optional CPS URIs or user notices attached to this policy. */\n\treadonly policyQualifiers?: readonly PolicyQualifierInfo[];\n}\n\n/** RFC 5280 §4.2.1.4 — array of policy OIDs with optional qualifiers. */\nexport type CertificatePolicies = readonly {\n\t/** Dotted-decimal OID of the policy (e.g. `\"2.23.140.1.2.1\"` for DV). */\n\treadonly policyIdentifier: string;\n\t/** Optional CPS URIs or user notices attached to this policy. */\n\treadonly policyQualifiers?: readonly (\n\t\t| {\n\t\t\t\treadonly type: 'cps';\n\t\t\t\treadonly uri: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'userNotice';\n\t\t\t\treadonly noticeRef?: {\n\t\t\t\t\treadonly organization: string;\n\t\t\t\t\treadonly noticeNumbers: readonly number[];\n\t\t\t\t};\n\t\t\t\treadonly explicitText?: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'oid';\n\t\t\t\treadonly oid: string;\n\t\t\t\treadonly qualifierDer: Uint8Array;\n\t\t }\n\t)[];\n}[];\n\n/** CPS (Certification Practice Statement) URI policy qualifier. */\nexport interface CpsPolicyQualifierInfo {\n\t/** Discriminant for the `'cps'` qualifier variant. */\n\treadonly type: 'cps';\n\t/** URL of the Certification Practice Statement document. */\n\treadonly uri: string;\n}\n\n/** Reference to a numbered notice within an organization's practice statement. */\nexport interface PolicyNoticeReference {\n\t/** Organization name that published the notice. */\n\treadonly organization: string;\n\t/** One-based notice numbers within that organization's documentation. */\n\treadonly noticeNumbers: readonly number[];\n}\n\n/** UserNotice policy qualifier — human-readable notice text and/or a notice reference. */\nexport interface UserNoticePolicyQualifierInfo {\n\t/** Discriminant for the `'userNotice'` qualifier variant. */\n\treadonly type: 'userNotice';\n\t/** Pointer to a numbered notice in an organization's practice statement. */\n\treadonly noticeRef?: PolicyNoticeReference;\n\t/** Free-form text to display to relying parties. */\n\treadonly explicitText?: string;\n}\n\n/** Opaque policy qualifier identified by a custom OID, carried as raw DER. */\nexport interface CustomPolicyQualifierInfo {\n\t/** Discriminant for the custom-OID qualifier variant. */\n\treadonly type: 'oid';\n\t/** Dotted-decimal OID of the qualifier. */\n\treadonly oid: string;\n\t/** DER-encoded qualifier payload. */\n\treadonly qualifierDer: Uint8Array;\n}\n\n/** Discriminated union of all supported policy qualifier types. */\nexport type PolicyQualifierInfo =\n\t| CpsPolicyQualifierInfo\n\t| UserNoticePolicyQualifierInfo\n\t| CustomPolicyQualifierInfo;\n\n/** Maps a policy OID in the issuer's domain to an equivalent OID in the subject's domain. */\nexport interface PolicyMapping {\n\t/** Policy OID as defined by the issuing CA. Must not be anyPolicy. */\n\treadonly issuerDomainPolicy: string;\n\t/** Equivalent policy OID in the subject CA's domain. Must not be anyPolicy. */\n\treadonly subjectDomainPolicy: string;\n}\n\n/** RFC 5280 §4.2.1.5 — array of issuer-to-subject policy OID pairs. */\nexport type PolicyMappings = readonly {\n\t/** Policy OID as defined by the issuing CA. Must not be anyPolicy. */\n\treadonly issuerDomainPolicy: string;\n\t/** Equivalent policy OID in the subject CA's domain. Must not be anyPolicy. */\n\treadonly subjectDomainPolicy: string;\n}[];\n\n/**\n * RFC 5280 §4.2.1.11 Policy Constraints.\n *\n * At least one field must be present. Values are certificate-count\n * thresholds measured from the current certificate toward the end entity.\n */\nexport interface PolicyConstraints {\n\t/** After this many certificates, an acceptable policy must be in the path. */\n\treadonly requireExplicitPolicy?: number;\n\t/** After this many certificates, policy mapping is no longer allowed. */\n\treadonly inhibitPolicyMapping?: number;\n}\n\n/**\n * RFC 5280 §4.2.1.14 Inhibit anyPolicy.\n *\n * After `skipCerts` additional certificates in the path, the special\n * anyPolicy OID is no longer considered a match.\n */\nexport interface InhibitAnyPolicy {\n\t/** Number of additional certificates before anyPolicy stops being valid. */\n\treadonly skipCerts: number;\n}\n\n/**\n * Input for `createCertificate`, `createSelfSignedCertificate`,\n * and `createCertificateSigningRequest`.\n *\n * Every field is optional. Omitted extensions are not encoded. Built-in\n * extensions (SKI, AKI, basicConstraints defaults) are handled automatically\n * by the builder.\n */\nexport interface CertificateExtensionsInput {\n\t/** Subject Alternative Names (dns, ip, email, uri, srv, directoryName). */\n\treadonly subjectAltNames?: readonly SubjectAltName[];\n\t/** Key Usage flags (digitalSignature, keyCertSign, etc.). */\n\treadonly keyUsage?: readonly KeyUsage[];\n\t/** Basic Constraints (CA flag + optional pathLength). Defaults to `{ ca: false }` for certs. */\n\treadonly basicConstraints?: BasicConstraints;\n\t/** Extended Key Usage purposes (serverAuth, clientAuth, etc.). */\n\treadonly extendedKeyUsage?: readonly ExtendedKeyUsage[];\n\t/** Name Constraints — permitted and/or excluded subtrees. */\n\treadonly nameConstraints?: NameConstraints;\n\t/** Certificate Policies with optional qualifiers. */\n\treadonly certificatePolicies?: CertificatePolicies;\n\t/** Policy Mappings between issuer and subject policy domains. */\n\treadonly policyMappings?: PolicyMappings;\n\t/** Policy Constraints (requireExplicitPolicy / inhibitPolicyMapping thresholds). */\n\treadonly policyConstraints?: PolicyConstraints;\n\t/** Inhibit anyPolicy skip-certs threshold. */\n\treadonly inhibitAnyPolicy?: InhibitAnyPolicy;\n\t/** Authority Information Access — OCSP responder and CA issuer URIs. */\n\treadonly authorityInfoAccess?: readonly AuthorityInformationAccess[];\n\t/** CRL Distribution Points — where to check revocation status. */\n\treadonly crlDistributionPoints?: readonly DistributionPoint[];\n\t/** Arbitrary extensions not covered by the built-in fields. */\n\treadonly customExtensions?: readonly CustomExtension[];\n}\n\n/** An extension not covered by the typed fields in {@linkcode CertificateExtensionsInput}. */\nexport interface CustomExtension {\n\t/** Dotted-decimal OID of the extension. */\n\treadonly oid: string;\n\t/** Pre-encoded DER content for the extnValue OCTET STRING. */\n\treadonly value: Uint8Array;\n\t/** Whether the extension is critical. Default `false`. */\n\treadonly critical?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Name constraints (RFC 5280 §4.2.1.10)\n// ---------------------------------------------------------------------------\n\n/**\n * A name form used as a constraint base in namEConstraints.\n * Distinct from {@linkcode SubjectAltName} because IP constraints carry\n * address + mask bytes (8 for IPv4, 32 for IPv6) rather than bare addresses.\n */\nexport type NameConstraintForm =\n\t| {\n\t\t\t/** DNS domain constraint (dNSName [2]). */\n\t\t\treadonly type: 'dns';\n\t\t\t/** Domain suffix, e.g. `\".example.com\"` or `\"example.com\"`. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** Email constraint (rfc822Name [1]). */\n\t\t\treadonly type: 'email';\n\t\t\t/** Email domain or full address pattern. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** URI constraint (uniformResourceIdentifier [6]). */\n\t\t\treadonly type: 'uri';\n\t\t\t/** Host or domain component of a URI. */\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\t/** IP range constraint (iPAddress [7]). */\n\t\t\treadonly type: 'ip';\n\t\t\t/** Network address bytes (4 for IPv4, 16 for IPv6). */\n\t\t\treadonly addressBytes: Uint8Array;\n\t\t\t/** Subnet mask bytes (same length as addressBytes). */\n\t\t\treadonly maskBytes: Uint8Array;\n\t }\n\t| {\n\t\t\t/** Directory name constraint (directoryName [4]). */\n\t\t\treadonly type: 'directoryName';\n\t\t\t/** Hex-encoded DER of the Name SEQUENCE. */\n\t\t\treadonly derHex: string;\n\t };\n\n/**\n * Name constraint forms parsed from DER but not supported for encoding or\n * validation. Preserved for diagnostic round-tripping.\n */\nexport type UnsupportedNameConstraintForm =\n\t| {\n\t\t\t/** otherName [0] — raw bytes. */\n\t\t\treadonly type: 'otherName';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\t/** x400Address [3] — raw bytes. */\n\t\t\treadonly type: 'x400Address';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\t/** ediPartyName [5] — raw bytes. */\n\t\t\treadonly type: 'ediPartyName';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\t/** registeredID [8] — decoded OID string. */\n\t\t\treadonly type: 'registeredID';\n\t\t\treadonly value: string;\n\t };\n\n/** Union of supported and unsupported name constraint forms as produced by parsing. */\nexport type ParsedNameConstraintForm =\n\t| {\n\t\t\treadonly type: 'dns';\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\treadonly type: 'email';\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\treadonly type: 'uri';\n\t\t\treadonly value: string;\n\t }\n\t| {\n\t\t\treadonly type: 'ip';\n\t\t\treadonly addressBytes: Uint8Array;\n\t\t\treadonly maskBytes: Uint8Array;\n\t }\n\t| {\n\t\t\treadonly type: 'directoryName';\n\t\t\treadonly derHex: string;\n\t }\n\t| {\n\t\t\treadonly type: 'otherName';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\treadonly type: 'x400Address';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\treadonly type: 'ediPartyName';\n\t\t\treadonly value: Uint8Array;\n\t }\n\t| {\n\t\t\treadonly type: 'registeredID';\n\t\t\treadonly value: string;\n\t };\n\n/** A single subtree entry in a Name Constraints permitted/excluded list. */\nexport interface GeneralSubtree<\n\tTForm extends ParsedNameConstraintForm =\n\t\t| {\n\t\t\t\treadonly type: 'dns';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'email';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'uri';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'ip';\n\t\t\t\treadonly addressBytes: Uint8Array;\n\t\t\t\treadonly maskBytes: Uint8Array;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'directoryName';\n\t\t\t\treadonly derHex: string;\n\t\t },\n> {\n\t/** The name form that defines this constraint boundary. */\n\treadonly base: TForm;\n}\n\n/**\n * RFC 5280 §4.2.1.10 Name Constraints.\n *\n * A CA certificate may restrict the namespace of all subject names in\n * subsequent certificates in the path.\n */\nexport interface NameConstraints<\n\tTForm extends ParsedNameConstraintForm =\n\t\t| {\n\t\t\t\treadonly type: 'dns';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'email';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'uri';\n\t\t\t\treadonly value: string;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'ip';\n\t\t\t\treadonly addressBytes: Uint8Array;\n\t\t\t\treadonly maskBytes: Uint8Array;\n\t\t }\n\t\t| {\n\t\t\t\treadonly type: 'directoryName';\n\t\t\t\treadonly derHex: string;\n\t\t },\n> {\n\t/** Names that MUST fall within these subtrees to be valid. */\n\treadonly permittedSubtrees?: readonly GeneralSubtree<TForm>[];\n\t/** Names that MUST NOT fall within these subtrees. Takes precedence over permitted. */\n\treadonly excludedSubtrees?: readonly GeneralSubtree<TForm>[];\n}\n\n/** Well-known AIA access methods: OCSP responder or CA issuer certificate. */\nexport type KnownAuthorityInfoAccessMethod = 'ocsp' | 'caIssuers';\n\n/** AIA access method identified by a custom OID not in the well-known set. */\nexport interface CustomAuthorityInfoAccessMethod {\n\t/** Discriminant for the custom-OID access method variant. */\n\treadonly type: 'oid';\n\t/** Dotted-decimal OID of the access method. */\n\treadonly value: string;\n}\n\n/** AIA access method — either a well-known string or a custom OID. */\nexport type AuthorityInfoAccessMethod =\n\t| KnownAuthorityInfoAccessMethod\n\t| CustomAuthorityInfoAccessMethod;\n\n/** A single entry in the Authority Information Access extension (RFC 5280 §4.2.2.1). */\nexport interface AuthorityInformationAccess {\n\t/** Access method (`'ocsp'`, `'caIssuers'`, or custom OID). */\n\treadonly method:\n\t\t| 'ocsp'\n\t\t| 'caIssuers'\n\t\t| {\n\t\t\t\treadonly type: 'oid';\n\t\t\t\treadonly value: string;\n\t\t };\n\t/** URI where the resource can be fetched. */\n\treadonly uri: string;\n}\n\n/** Well-known Extended Key Usage purpose strings (RFC 5280 §4.2.1.12). */\nexport type KnownExtendedKeyUsage =\n\t| 'serverAuth'\n\t| 'clientAuth'\n\t| 'codeSigning'\n\t| 'emailProtection'\n\t| 'timeStamping'\n\t| 'ocspSigning';\n\n/** Extended Key Usage purpose identified by a custom OID. */\nexport interface CustomExtendedKeyUsage {\n\t/** Discriminant for the custom-OID EKU variant. */\n\treadonly type: 'oid';\n\t/** Dotted-decimal OID of the usage purpose. */\n\treadonly value: string;\n}\n\n/** Extended Key Usage — either a well-known purpose string or a custom OID. */\nexport type ExtendedKeyUsage =\n\t| 'serverAuth'\n\t| 'clientAuth'\n\t| 'codeSigning'\n\t| 'emailProtection'\n\t| 'timeStamping'\n\t| 'ocspSigning'\n\t| {\n\t\t\treadonly type: 'oid';\n\t\t\treadonly value: string;\n\t };\n\n/** Map from well-known EKU names to their dotted-decimal OIDs. */\nconst EXTENDED_KEY_USAGE_OIDS: Record<KnownExtendedKeyUsage, string> = {\n\tserverAuth: OIDS.serverAuth,\n\tclientAuth: OIDS.clientAuth,\n\tcodeSigning: OIDS.codeSigning,\n\temailProtection: OIDS.emailProtection,\n\ttimeStamping: OIDS.timeStamping,\n\tocspSigning: OIDS.ocspSigning,\n};\n\n/** Map from well-known AIA method names to their dotted-decimal OIDs. */\nconst AUTHORITY_INFO_ACCESS_METHOD_OIDS: Record<KnownAuthorityInfoAccessMethod, string> = {\n\tocsp: OIDS.ocspAccessMethod,\n\tcaIssuers: OIDS.caIssuersAccessMethod,\n};\n\n/**\n * Build the v3 extensions block for a certificate.\n *\n * Automatically adds SKI, AKI (when issuer key is available), and\n * basicConstraints (defaults to `{ ca: false }`). Additional extensions\n * come from the caller's {@linkcode CertificateExtensionsInput}.\n *\n * @param subjectPublicKeyInfo DER-encoded SPKI of the subject.\n * @param issuerPublicKeyInfo DER-encoded SPKI of the issuer, or `undefined` for self-signed.\n * @param input Optional extension configuration.\n * @param subjectIsEmpty Whether the certificate subject DN is empty. When `true`, the\n * subjectAltName extension is marked critical per RFC 5280 §4.2.1.6.\n * @returns Array of DER-encoded Extension SEQUENCEs.\n */\nexport function buildCertificateExtensions(\n\tsubjectPublicKeyInfo: Uint8Array,\n\tissuerPublicKeyInfo: Uint8Array | undefined,\n\tinput: CertificateExtensionsInput | undefined,\n\tsubjectIsEmpty = false,\n): Uint8Array[] {\n\tconst extensions: Uint8Array[] = [];\n\tconst seen = new Set<string>();\n\tconst basicConstraints = input?.basicConstraints ?? { ca: false };\n\tpushKnownExtension(extensions, seen, BASIC_CONSTRAINTS_EXTENSION_DEFINITION, basicConstraints);\n\tpushKnownExtension(\n\t\textensions,\n\t\tseen,\n\t\tSUBJECT_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n\t\tbuildSubjectKeyIdentifier(subjectPublicKeyInfo),\n\t);\n\tif (issuerPublicKeyInfo !== undefined) {\n\t\tpushKnownExtension(\n\t\t\textensions,\n\t\t\tseen,\n\t\t\tAUTHORITY_KEY_IDENTIFIER_EXTENSION_DEFINITION,\n\t\t\tbuildSubjectKeyIdentifier(issuerPublicKeyInfo),\n\t\t);\n\t}\n\tappendConfiguredExtensions(extensions, seen, input, 'certificate', {\n\t\tincludeBasicConstraints: false,\n\t\tsubjectIsEmpty,\n\t});\n\treturn extensions;\n}\n\n/**\n * Build the extensions for a CSR's extensionRequest attribute.\n *\n * Unlike {@linkcode buildCertificateExtensions}, SKI/AKI are not auto-generated.\n *\n * @param input Optional extension configuration.\n * @returns Array of DER-encoded Extension SEQUENCEs.\n */\nexport function buildRequestedExtensions(\n\tinput: CertificateExtensionsInput | undefined,\n): Uint8Array[] {\n\tconst extensions: Uint8Array[] = [];\n\tconst seen = new Set<string>();\n\tappendConfiguredExtensions(extensions, seen, input, 'csr', { includeBasicConstraints: true });\n\treturn extensions;\n}\n\n/** Encode and push each configured extension from the input, enforcing no duplicates. */\nfunction appendConfiguredExtensions(\n\tencoded: Uint8Array[],\n\tseen: Set<string>,\n\tinput: CertificateExtensionsInput | undefined,\n\tcontext: ExtensionRegistryContext,\n\toptions: {\n\t\treadonly includeBasicConstraints: boolean;\n\t\t/** When true, SAN is marked critical per RFC 5280 §4.2.1.6. */\n\t\treadonly subjectIsEmpty?: boolean;\n\t},\n): void {\n\tif (input === undefined) {\n\t\treturn;\n\t}\n\tif (options.includeBasicConstraints && input.basicConstraints !== undefined) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tBASIC_CONSTRAINTS_EXTENSION_DEFINITION,\n\t\t\tinput.basicConstraints,\n\t\t);\n\t}\n\tif (input.keyUsage !== undefined && input.keyUsage.length > 0) {\n\t\tpushKnownExtension(encoded, seen, KEY_USAGE_EXTENSION_DEFINITION, input.keyUsage);\n\t}\n\tif (input.subjectAltNames !== undefined && input.subjectAltNames.length > 0) {\n\t\t// RFC 5280 §4.2.1.6: SAN MUST be critical when subject DN is empty.\n\t\tconst sanCritical = options.subjectIsEmpty === true ? true : undefined;\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tSUBJECT_ALT_NAME_EXTENSION_DEFINITION,\n\t\t\tinput.subjectAltNames,\n\t\t\tsanCritical,\n\t\t);\n\t}\n\tif (input.extendedKeyUsage !== undefined && input.extendedKeyUsage.length > 0) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tEXTENDED_KEY_USAGE_EXTENSION_DEFINITION,\n\t\t\tinput.extendedKeyUsage,\n\t\t);\n\t}\n\tif (input.nameConstraints !== undefined) {\n\t\tpushKnownExtension(encoded, seen, NAME_CONSTRAINTS_EXTENSION_DEFINITION, input.nameConstraints);\n\t}\n\tif (input.certificatePolicies !== undefined && input.certificatePolicies.length > 0) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tCERTIFICATE_POLICIES_EXTENSION_DEFINITION,\n\t\t\tinput.certificatePolicies,\n\t\t);\n\t}\n\tif (input.policyMappings !== undefined && input.policyMappings.length > 0) {\n\t\tpushKnownExtension(encoded, seen, POLICY_MAPPINGS_EXTENSION_DEFINITION, input.policyMappings);\n\t}\n\tif (input.policyConstraints !== undefined) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tPOLICY_CONSTRAINTS_EXTENSION_DEFINITION,\n\t\t\tinput.policyConstraints,\n\t\t);\n\t}\n\tif (input.inhibitAnyPolicy !== undefined) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tINHIBIT_ANY_POLICY_EXTENSION_DEFINITION,\n\t\t\tinput.inhibitAnyPolicy,\n\t\t);\n\t}\n\tif (input.authorityInfoAccess !== undefined && input.authorityInfoAccess.length > 0) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tAUTHORITY_INFO_ACCESS_EXTENSION_DEFINITION,\n\t\t\tinput.authorityInfoAccess,\n\t\t);\n\t}\n\tif (input.crlDistributionPoints !== undefined && input.crlDistributionPoints.length > 0) {\n\t\tpushKnownExtension(\n\t\t\tencoded,\n\t\t\tseen,\n\t\t\tCRL_DISTRIBUTION_POINTS_EXTENSION_DEFINITION,\n\t\t\tinput.crlDistributionPoints,\n\t\t);\n\t}\n\tif (input.customExtensions !== undefined) {\n\t\tfor (const extension of input.customExtensions) {\n\t\t\tconst knownDefinition = getExtensionDefinition(extension.oid);\n\t\t\tif (knownDefinition !== undefined && !knownDefinition.contexts.includes(context)) {\n\t\t\t\tthrow new Error(`Extension ${extension.oid} is not supported in ${context} context`);\n\t\t\t}\n\t\t\tpushExtension(\n\t\t\t\tencoded,\n\t\t\t\tseen,\n\t\t\t\textension.oid,\n\t\t\t\tnew Uint8Array(extension.value),\n\t\t\t\textension.critical ?? false,\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Encode a known extension via its registry definition and push it. */\nfunction pushKnownExtension<TParsed, TInput>(\n\tencoded: Uint8Array[],\n\tseen: Set<string>,\n\tdefinition: ExtensionDefinition<TParsed, TInput>,\n\tvalue: TInput,\n\tcritical = definition.defaultCritical,\n): void {\n\tpushExtension(encoded, seen, definition.oid, definition.encode(value), critical);\n}\n\n/**\n * Encode a single X.509 Extension SEQUENCE (OID + optional critical BOOLEAN + OCTET STRING).\n *\n * @param oid Dotted-decimal extension OID.\n * @param extnValue DER-encoded extension payload.\n * @param critical Whether to mark the extension as critical. Default `false`.\n */\nexport function encodeExtension(oid: string, extnValue: Uint8Array, critical = false): Uint8Array {\n\tconst fields = [objectIdentifier(oid)];\n\tif (critical) {\n\t\tfields.push(bool(true));\n\t}\n\tfields.push(octetString(extnValue));\n\treturn sequence(fields);\n}\n\n/**\n * DER-encode a {@linkcode BasicConstraints} value.\n *\n * @param input CA flag and optional pathLength.\n * @returns DER SEQUENCE suitable for wrapping in an Extension OCTET STRING.\n */\nexport function encodeBasicConstraints(input: BasicConstraints): Uint8Array {\n\tconst fields: Uint8Array[] = [];\n\tif (input.ca) {\n\t\tfields.push(bool(true));\n\t}\n\tif (input.pathLength !== undefined) {\n\t\tif (!input.ca) {\n\t\t\tthrow new Error('pathLength requires ca=true');\n\t\t}\n\t\tfields.push(integerFromNumber(input.pathLength));\n\t}\n\treturn sequence(fields);\n}\n\n/**\n * DER-encode a Key Usage BIT STRING from an array of {@linkcode KeyUsage} flags.\n *\n * @param usages Flags to set in the bit string.\n */\nexport function encodeKeyUsage(usages: readonly KeyUsage[]): Uint8Array {\n\treturn encodeKeyUsageExtension(usages);\n}\n\n/**\n * DER-encode a single {@linkcode SubjectAltName} GeneralName element.\n *\n * @param value The SAN entry to encode.\n */\nexport function encodeSubjectAltName(value: SubjectAltName): Uint8Array {\n\tswitch (value.type) {\n\t\tcase 'dns':\n\t\t\treturn implicitPrimitiveContext(2, new TextEncoder().encode(value.value));\n\t\tcase 'email':\n\t\t\treturn implicitPrimitiveContext(1, new TextEncoder().encode(value.value));\n\t\tcase 'uri':\n\t\t\treturn implicitPrimitiveContext(6, new TextEncoder().encode(value.value));\n\t\tcase 'srv':\n\t\t\treturn implicitConstructedContext(\n\t\t\t\t0,\n\t\t\t\tsequence([objectIdentifier(OIDS.idOnDnsSrv), explicitContext(0, ia5String(value.value))]),\n\t\t\t);\n\t\tcase 'ip':\n\t\t\treturn implicitPrimitiveContext(7, encodeIpAddress(value.value));\n\t\tcase 'directoryName':\n\t\t\treturn implicitConstructedContext(4, extractDirectoryNameContent(value.derHex));\n\t\tcase 'unknown':\n\t\t\treturn tlv(value.tag, value.value);\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = value;\n\t\t\tthrow new Error(`Unhandled SubjectAltName type: ${String(_exhaustive)}`);\n\t\t}\n\t}\n}\n\n/**\n * DER-encode an Extended Key Usage SEQUENCE OF OIDs.\n *\n * @param usages EKU purposes to encode.\n */\nexport function encodeExtendedKeyUsage(usages: readonly ExtendedKeyUsage[]): Uint8Array {\n\treturn sequence(usages.map((usage) => objectIdentifier(getExtendedKeyUsageOid(usage))));\n}\n\n/**\n * DER-encode an Authority Information Access SEQUENCE.\n *\n * @param entries AIA entries (OCSP, caIssuers, or custom) to encode.\n */\nexport function encodeAuthorityInfoAccess(\n\tentries: readonly AuthorityInformationAccess[],\n): Uint8Array {\n\treturn sequence(\n\t\tentries.map((entry) =>\n\t\t\tsequence([\n\t\t\t\tobjectIdentifier(getAuthorityInfoAccessMethodOid(entry.method)),\n\t\t\t\timplicitPrimitiveContext(6, new TextEncoder().encode(entry.uri)),\n\t\t\t]),\n\t\t),\n\t);\n}\n\n/**\n * DER-encode a CRL Distribution Points SEQUENCE.\n *\n * @param points Distribution points to encode.\n */\nexport function encodeCrlDistributionPoints(points: readonly DistributionPoint[]): Uint8Array {\n\treturn sequence(points.map((point) => sequence(encodeDistributionPoint(point))));\n}\n\n/**\n * DER-encode a Name Constraints extension value.\n *\n * @param constraints Permitted and/or excluded subtrees.\n */\nexport function encodeNameConstraints(constraints: NameConstraints): Uint8Array {\n\tconst parts: Uint8Array[] = [];\n\tif (constraints.permittedSubtrees !== undefined && constraints.permittedSubtrees.length > 0) {\n\t\tparts.push(\n\t\t\timplicitConstructedContext(\n\t\t\t\t0,\n\t\t\t\tconcatBytes(constraints.permittedSubtrees.map(encodeGeneralSubtree)),\n\t\t\t),\n\t\t);\n\t}\n\tif (constraints.excludedSubtrees !== undefined && constraints.excludedSubtrees.length > 0) {\n\t\tparts.push(\n\t\t\timplicitConstructedContext(\n\t\t\t\t1,\n\t\t\t\tconcatBytes(constraints.excludedSubtrees.map(encodeGeneralSubtree)),\n\t\t\t),\n\t\t);\n\t}\n\treturn sequence(parts);\n}\n\n/**\n * DER-encode a Certificate Policies extension value.\n *\n * @param policies Non-empty array of policy information entries.\n */\nexport function encodeCertificatePolicies(policies: CertificatePolicies): Uint8Array {\n\tif (policies.length === 0) {\n\t\tthrow new Error('certificatePolicies must not be empty');\n\t}\n\treturn sequence(policies.map(encodePolicyInformation));\n}\n\n/**\n * DER-encode a Policy Mappings extension value.\n *\n * @param mappings Non-empty array of issuer-to-subject policy pairs. Neither OID may be anyPolicy.\n */\nexport function encodePolicyMappings(mappings: PolicyMappings): Uint8Array {\n\tif (mappings.length === 0) {\n\t\tthrow new Error('policyMappings must not be empty');\n\t}\n\treturn sequence(\n\t\tmappings.map((mapping) => {\n\t\t\tvalidatePolicyOid(mapping.issuerDomainPolicy);\n\t\t\tvalidatePolicyOid(mapping.subjectDomainPolicy);\n\t\t\tif (\n\t\t\t\tmapping.issuerDomainPolicy === OIDS.anyPolicy ||\n\t\t\t\tmapping.subjectDomainPolicy === OIDS.anyPolicy\n\t\t\t) {\n\t\t\t\tthrow new Error('policyMappings must not use anyPolicy');\n\t\t\t}\n\t\t\treturn sequence([\n\t\t\t\tobjectIdentifier(mapping.issuerDomainPolicy),\n\t\t\t\tobjectIdentifier(mapping.subjectDomainPolicy),\n\t\t\t]);\n\t\t}),\n\t);\n}\n\n/**\n * DER-encode a Policy Constraints extension value.\n *\n * @param constraints At least one of `requireExplicitPolicy` or `inhibitPolicyMapping` must be set.\n */\nexport function encodePolicyConstraints(constraints: PolicyConstraints): Uint8Array {\n\tconst fields: Uint8Array[] = [];\n\tif (constraints.requireExplicitPolicy !== undefined) {\n\t\tfields.push(\n\t\t\timplicitPrimitiveContext(0, encodeIntegerContent(constraints.requireExplicitPolicy)),\n\t\t);\n\t}\n\tif (constraints.inhibitPolicyMapping !== undefined) {\n\t\tfields.push(\n\t\t\timplicitPrimitiveContext(1, encodeIntegerContent(constraints.inhibitPolicyMapping)),\n\t\t);\n\t}\n\tif (fields.length === 0) {\n\t\tthrow new Error('policyConstraints must set requireExplicitPolicy or inhibitPolicyMapping');\n\t}\n\treturn sequence(fields);\n}\n\n/**\n * DER-encode an Inhibit anyPolicy extension value (single INTEGER).\n *\n * @param input The skipCerts threshold.\n */\nexport function encodeInhibitAnyPolicy(input: InhibitAnyPolicy): Uint8Array {\n\treturn integerFromNumber(input.skipCerts);\n}\n\n/** DER-encode a single PolicyInformation SEQUENCE. */\nfunction encodePolicyInformation(policy: PolicyInformation): Uint8Array {\n\tvalidatePolicyOid(policy.policyIdentifier);\n\tconst fields = [objectIdentifier(policy.policyIdentifier)];\n\tif (policy.policyQualifiers !== undefined && policy.policyQualifiers.length > 0) {\n\t\tfields.push(sequence(policy.policyQualifiers.map(encodePolicyQualifierInfo)));\n\t}\n\treturn sequence(fields);\n}\n\n/** DER-encode a single PolicyQualifierInfo SEQUENCE. */\nfunction encodePolicyQualifierInfo(qualifier: PolicyQualifierInfo): Uint8Array {\n\tswitch (qualifier.type) {\n\t\tcase 'cps':\n\t\t\treturn sequence([objectIdentifier(OIDS.cpsPolicyQualifier), ia5String(qualifier.uri)]);\n\t\tcase 'userNotice':\n\t\t\treturn sequence([\n\t\t\t\tobjectIdentifier(OIDS.userNoticePolicyQualifier),\n\t\t\t\tencodeUserNoticePolicyQualifierInfo(qualifier),\n\t\t\t]);\n\t\tcase 'oid':\n\t\t\tvalidateOid(qualifier.oid);\n\t\t\treturn sequence([objectIdentifier(qualifier.oid), new Uint8Array(qualifier.qualifierDer)]);\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = qualifier;\n\t\t\tthrow new Error(`Unhandled PolicyQualifierInfo type: ${String(_exhaustive)}`);\n\t\t}\n\t}\n}\n\n/** DER-encode a UserNotice qualifier SEQUENCE. */\nfunction encodeUserNoticePolicyQualifierInfo(qualifier: UserNoticePolicyQualifierInfo): Uint8Array {\n\tconst fields: Uint8Array[] = [];\n\tif (qualifier.noticeRef !== undefined) {\n\t\tfields.push(encodePolicyNoticeReference(qualifier.noticeRef));\n\t}\n\tif (qualifier.explicitText !== undefined) {\n\t\tfields.push(utf8String(qualifier.explicitText));\n\t}\n\treturn sequence(fields);\n}\n\n/** DER-encode a NoticeReference SEQUENCE. */\nfunction encodePolicyNoticeReference(reference: PolicyNoticeReference): Uint8Array {\n\treturn sequence([\n\t\tutf8String(reference.organization),\n\t\tsequence(reference.noticeNumbers.map((noticeNumber) => integerFromNumber(noticeNumber))),\n\t]);\n}\n\n/** Encode an INTEGER and return only the content bytes (no TLV wrapper). */\nfunction encodeIntegerContent(value: number): Uint8Array {\n\treturn readElement(integerFromNumber(value)).value;\n}\n\n/** DER-encode a GeneralSubtree SEQUENCE (base name only; min/max omitted per RFC 5280). */\nfunction encodeGeneralSubtree(subtree: GeneralSubtree): Uint8Array {\n\treturn sequence([encodeNameConstraintForm(subtree.base)]);\n}\n\n/** DER-encode the fields of a single DistributionPoint. */\nfunction encodeDistributionPoint(point: DistributionPoint): Uint8Array[] {\n\tif (point.crlIssuer !== undefined && point.crlIssuer.length === 0) {\n\t\tthrow new Error('DistributionPoint crlIssuer must not be empty');\n\t}\n\tif (point.distributionPoint === undefined && point.crlIssuer === undefined) {\n\t\tthrow new Error('DistributionPoint must contain distributionPoint or crlIssuer');\n\t}\n\tconst fields: Uint8Array[] = [];\n\tif (point.distributionPoint !== undefined) {\n\t\tfields.push(\n\t\t\timplicitConstructedContext(0, encodeDistributionPointName(point.distributionPoint)),\n\t\t);\n\t}\n\tif (point.reasons !== undefined && point.reasons.length > 0) {\n\t\tfields.push(\n\t\t\timplicitPrimitiveContext(1, encodeDistributionPointReasonFlagsContent(point.reasons)),\n\t\t);\n\t}\n\tif (point.crlIssuer !== undefined && point.crlIssuer.length > 0) {\n\t\tfields.push(\n\t\t\timplicitConstructedContext(2, concatBytes(point.crlIssuer.map(encodeSubjectAltName))),\n\t\t);\n\t}\n\treturn fields;\n}\n\n/** DER-encode a DistributionPointName (fullName or relativeName). */\nfunction encodeDistributionPointName(name: DistributionPointName): Uint8Array {\n\tif (name.fullName !== undefined && name.relativeName !== undefined) {\n\t\tthrow new Error('DistributionPointName cannot contain both fullName and relativeName');\n\t}\n\tif (name.fullName !== undefined) {\n\t\tif (name.fullName.length === 0) {\n\t\t\tthrow new Error('DistributionPointName fullName must not be empty');\n\t\t}\n\t\treturn implicitConstructedContext(0, concatBytes(name.fullName.map(encodeSubjectAltName)));\n\t}\n\tif (name.relativeName !== undefined) {\n\t\tconst relativeName = encodeRelativeDistinguishedName(name.relativeName);\n\t\tconst relativeNameElement = readElement(relativeName);\n\t\treturn implicitConstructedContext(\n\t\t\t1,\n\t\t\trelativeName.slice(relativeNameElement.start, relativeNameElement.end),\n\t\t);\n\t}\n\tthrow new Error('DistributionPointName must contain fullName or relativeName');\n}\n\n/** DER-encode a NameConstraintForm as an implicit-tagged {@linkcode GeneralName}. */\nfunction encodeNameConstraintForm(form: NameConstraintForm): Uint8Array {\n\tswitch (form.type) {\n\t\tcase 'dns':\n\t\t\treturn implicitPrimitiveContext(2, new TextEncoder().encode(form.value));\n\t\tcase 'email':\n\t\t\treturn implicitPrimitiveContext(1, new TextEncoder().encode(form.value));\n\t\tcase 'uri':\n\t\t\treturn implicitPrimitiveContext(6, new TextEncoder().encode(form.value));\n\t\tcase 'ip':\n\t\t\treturn implicitPrimitiveContext(7, concatBytes([form.addressBytes, form.maskBytes]));\n\t\tcase 'directoryName':\n\t\t\treturn implicitConstructedContext(4, extractDirectoryNameContent(form.derHex));\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = form;\n\t\t\tthrow new Error(`Unhandled NameConstraintForm type: ${String(_exhaustive)}`);\n\t\t}\n\t}\n}\n\n/** Extract the content bytes from a hex-encoded DER SEQUENCE (strips the outer TLV). */\nfunction extractDirectoryNameContent(derHex: string): Uint8Array {\n\tconst element = readRootElement(hexToBytes(derHex), { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\tif (element.tag !== 0x30) {\n\t\tthrow new Error('directoryName derHex must encode a DER SEQUENCE');\n\t}\n\treturn new Uint8Array(element.value);\n}\n\n/**\n * Resolve an {@linkcode ExtendedKeyUsage} to its dotted-decimal OID.\n *\n * @param usage Well-known string or custom OID object.\n */\nexport function getExtendedKeyUsageOid(usage: ExtendedKeyUsage): string {\n\tif (typeof usage === 'string') {\n\t\treturn EXTENDED_KEY_USAGE_OIDS[usage];\n\t}\n\tvalidateOid(usage.value);\n\treturn usage.value;\n}\n\n/**\n * Map a dotted-decimal OID to an {@linkcode ExtendedKeyUsage} value.\n *\n * Returns a well-known string for recognized OIDs, or `{ type: 'oid', value }` otherwise.\n */\nexport function parseExtendedKeyUsageOid(oid: string): ExtendedKeyUsage {\n\tswitch (oid) {\n\t\tcase OIDS.serverAuth:\n\t\t\treturn 'serverAuth';\n\t\tcase OIDS.clientAuth:\n\t\t\treturn 'clientAuth';\n\t\tcase OIDS.codeSigning:\n\t\t\treturn 'codeSigning';\n\t\tcase OIDS.emailProtection:\n\t\t\treturn 'emailProtection';\n\t\tcase OIDS.timeStamping:\n\t\t\treturn 'timeStamping';\n\t\tcase OIDS.ocspSigning:\n\t\t\treturn 'ocspSigning';\n\t}\n\treturn { type: 'oid', value: oid };\n}\n\n/**\n * Resolve an {@linkcode AuthorityInfoAccessMethod} to its dotted-decimal OID.\n *\n * @param method Well-known string or custom OID object.\n */\nexport function getAuthorityInfoAccessMethodOid(method: AuthorityInfoAccessMethod): string {\n\tif (typeof method === 'string') {\n\t\treturn AUTHORITY_INFO_ACCESS_METHOD_OIDS[method];\n\t}\n\tvalidateOid(method.value);\n\treturn method.value;\n}\n\n/**\n * Map a dotted-decimal OID to an {@linkcode AuthorityInfoAccessMethod} value.\n *\n * Returns `'ocsp'` or `'caIssuers'` for recognized OIDs, or `{ type: 'oid', value }` otherwise.\n */\nexport function parseAuthorityInfoAccessMethodOid(oid: string): AuthorityInfoAccessMethod {\n\tswitch (oid) {\n\t\tcase OIDS.ocspAccessMethod:\n\t\t\treturn 'ocsp';\n\t\tcase OIDS.caIssuersAccessMethod:\n\t\t\treturn 'caIssuers';\n\t}\n\treturn { type: 'oid', value: oid };\n}\n\n/** Parse a dotted-decimal/colon-hex IP string to raw address bytes. */\nfunction encodeIpAddress(input: string): Uint8Array {\n\treturn parseIpAddressToBytes(input);\n}\n\n/** @internal Compute the SKI as SHA-1 of the subjectPublicKey BIT STRING content. */\nexport function buildSubjectKeyIdentifier(subjectPublicKeyInfo: Uint8Array): Uint8Array {\n\tconst topLevel = readSequenceChildren(subjectPublicKeyInfo);\n\tconst subjectPublicKey = topLevel[1];\n\tif (subjectPublicKey === undefined || subjectPublicKey.tag !== 0x03) {\n\t\tthrow new Error('SPKI missing subject public key bit string');\n\t}\n\tconst publicKeyBytes = subjectPublicKey.value.slice(1);\n\treturn sha1(publicKeyBytes);\n}\n\n/** Throw if the string is not a valid dotted-decimal OID. */\nfunction validateOid(oid: string): void {\n\tif (!/^\\d+(?:\\.\\d+)+$/.test(oid)) {\n\t\tthrow new Error(`Invalid OID: ${oid}`);\n\t}\n}\n\n/** Validate that a policy OID is syntactically valid. */\nfunction validatePolicyOid(oid: string): void {\n\tvalidateOid(oid);\n}\n\n/** Encode and push an extension, rejecting duplicate OIDs. */\nfunction pushExtension(\n\tencoded: Uint8Array[],\n\tseen: Set<string>,\n\toid: string,\n\tvalue: Uint8Array,\n\tcritical = false,\n): void {\n\tvalidateOid(oid);\n\tif (seen.has(oid)) {\n\t\tthrow new Error(`Duplicate extension OID: ${oid}`);\n\t}\n\tseen.add(oid);\n\tencoded.push(encodeExtension(oid, value, critical));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
//#region src/x509/name.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Union of recognized X.501 attribute type shorthand names.
|
|
4
|
+
*
|
|
5
|
+
* Each key maps to an OID + ASN.1 string encoding in `NAME_FIELD_DEFINITIONS`.
|
|
6
|
+
*/
|
|
7
|
+
type NameFieldKey = "commonName" | "surname" | "serialNumber" | "country" | "locality" | "state" | "street" | "organization" | "organizationalUnit" | "title" | "givenName" | "emailAddress";
|
|
8
|
+
/**
|
|
9
|
+
* Convenience object form of an X.501 distinguished name.
|
|
10
|
+
*
|
|
11
|
+
* Populated fields are emitted in the order defined by
|
|
12
|
+
* `NAME_OBJECT_ORDER`.\
|
|
13
|
+
* Each populated field becomes its own single-attribute RDN.
|
|
14
|
+
*
|
|
15
|
+
* For caller-controlled ordering, pass a {@linkcode NameAttribute} array to {@linkcode encodeName}.\
|
|
16
|
+
* For multi-valued RDNs, use {@linkcode encodeRelativeDistinguishedName}.
|
|
17
|
+
*/
|
|
18
|
+
interface NameObject {
|
|
19
|
+
/** Subject or issuer common name (CN). */
|
|
20
|
+
readonly commonName?: string;
|
|
21
|
+
/** Subject surname (SN). */
|
|
22
|
+
readonly surname?: string;
|
|
23
|
+
/** Device or entity serial number — not the certificate serial. */
|
|
24
|
+
readonly serialNumber?: string;
|
|
25
|
+
/** ISO 3166 two-letter country code (C). Must be exactly 2 characters. */
|
|
26
|
+
readonly country?: string;
|
|
27
|
+
/** City or locality (L). */
|
|
28
|
+
readonly locality?: string;
|
|
29
|
+
/** State or province (ST). */
|
|
30
|
+
readonly state?: string;
|
|
31
|
+
/** Street address. */
|
|
32
|
+
readonly street?: string;
|
|
33
|
+
/** Organization name (O). */
|
|
34
|
+
readonly organization?: string;
|
|
35
|
+
/** Organizational unit (OU). Deprecated in modern CA practice. */
|
|
36
|
+
readonly organizationalUnit?: string;
|
|
37
|
+
/** Job title or functional designation. */
|
|
38
|
+
readonly title?: string;
|
|
39
|
+
/** First / given name (GN). */
|
|
40
|
+
readonly givenName?: string;
|
|
41
|
+
/** RFC 822 email address. Encoded as IA5String, not UTF-8. */
|
|
42
|
+
readonly emailAddress?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Single name attribute within a distinguished name.
|
|
46
|
+
*
|
|
47
|
+
* RFC 5280 / X.501 call this structure an `AttributeTypeAndValue`.
|
|
48
|
+
*
|
|
49
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}
|
|
50
|
+
* {@linkcode encodeName} places each attribute in its own single-attribute RDN.\
|
|
51
|
+
* {@linkcode encodeRelativeDistinguishedName} packs several attributes into one RDN.
|
|
52
|
+
*/
|
|
53
|
+
interface NameAttribute {
|
|
54
|
+
/** Which attribute type this pair represents. */
|
|
55
|
+
readonly type: NameFieldKey;
|
|
56
|
+
/** The string value for this attribute (encoding chosen per field definition). */
|
|
57
|
+
readonly value: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Input for {@linkcode encodeName}.
|
|
61
|
+
*
|
|
62
|
+
* Accepts either a {@linkcode NameObject} convenience shape or an ordered array of {@linkcode NameAttribute} pairs.\
|
|
63
|
+
* Both forms encode one attribute per RDN.
|
|
64
|
+
*/
|
|
65
|
+
type NameInput = NameObject | readonly NameAttribute[];
|
|
66
|
+
/**
|
|
67
|
+
* Input for {@linkcode encodeRelativeDistinguishedName}.
|
|
68
|
+
*
|
|
69
|
+
* Each entry becomes one name attribute inside the RDN's `SET OF`.\
|
|
70
|
+
* Use this shape for multi-valued RDNs.
|
|
71
|
+
*
|
|
72
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}
|
|
73
|
+
*/
|
|
74
|
+
type RelativeDistinguishedNameInput = readonly NameAttribute[];
|
|
75
|
+
/**
|
|
76
|
+
* DER-encodes an X.509 `Name`.
|
|
77
|
+
*
|
|
78
|
+
* Returns a DER `SEQUENCE` of RelativeDistinguishedNames (RDNs).\
|
|
79
|
+
* Each RDN emitted by this helper contains exactly one name attribute.
|
|
80
|
+
*
|
|
81
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}
|
|
82
|
+
*
|
|
83
|
+
* {@linkcode NameObject} input emits populated fields in the canonical order from `NAME_OBJECT_ORDER`.\
|
|
84
|
+
* {@linkcode NameAttribute} array input preserves caller-supplied ordering,
|
|
85
|
+
* but each entry still becomes its own single-attribute RDN.
|
|
86
|
+
*
|
|
87
|
+
* Attribute OIDs and ASN.1 string encodings come from `NAME_FIELD_DEFINITIONS`.\
|
|
88
|
+
* Empty strings and `undefined` fields are ignored when the input is a {@linkcode NameObject}.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* const der = encodeName({ country: 'US', commonName: 'example.com' });
|
|
93
|
+
*
|
|
94
|
+
* // emits two single-attribute RDNs: C=US, then CN=example.com
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const der = encodeName([
|
|
100
|
+
* { type: 'country', value: 'US' },
|
|
101
|
+
* { type: 'commonName', value: 'example.com' },
|
|
102
|
+
* ]);
|
|
103
|
+
*
|
|
104
|
+
* // preserves caller order: C first, then CN
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* @param input Name fields in convenience-object form or caller-ordered attribute form.
|
|
108
|
+
* @returns DER-encoded X.509 `Name` bytes.
|
|
109
|
+
* @throws {Error} If the input produces no attributes, contains an unsupported field key, or uses an invalid country code.
|
|
110
|
+
*/
|
|
111
|
+
declare function encodeName(input: NameInput): Uint8Array;
|
|
112
|
+
/**
|
|
113
|
+
* DER-encodes a single RelativeDistinguishedName (RDN).
|
|
114
|
+
*
|
|
115
|
+
* Returns a DER `SET OF` name attributes for one X.509 name segment.\
|
|
116
|
+
* Use this when you need a multi-valued RDN.
|
|
117
|
+
*
|
|
118
|
+
* @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}
|
|
119
|
+
*
|
|
120
|
+
* Attribute OIDs and ASN.1 string encodings come from
|
|
121
|
+
* `NAME_FIELD_DEFINITIONS`.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* const rdn = encodeRelativeDistinguishedName([
|
|
126
|
+
* { type: 'commonName', value: 'example.com' },
|
|
127
|
+
* { type: 'serialNumber', value: 'device-7' },
|
|
128
|
+
* ]);
|
|
129
|
+
*
|
|
130
|
+
* // emits one RDN with both attributes in the same SET
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @param attributes Attribute list to encode inside one RDN.
|
|
134
|
+
* @returns DER-encoded RelativeDistinguishedName bytes.
|
|
135
|
+
* @throws {Error} If the attribute list is empty, contains an unsupported field key, or uses an invalid country code.
|
|
136
|
+
*/
|
|
137
|
+
declare function encodeRelativeDistinguishedName(attributes: RelativeDistinguishedNameInput): Uint8Array;
|
|
138
|
+
//#endregion
|
|
139
|
+
export { NameAttribute, NameFieldKey, NameInput, NameObject, RelativeDistinguishedNameInput, encodeName, encodeRelativeDistinguishedName };
|
|
140
|
+
//# sourceMappingURL=name.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{objectIdentifier as e,sequence as t,setOf as n}from"../internal/asn1/der.js";import{NAME_FIELD_DEFINITIONS as r,NAME_OBJECT_ORDER as i,nameFieldKeyFromOid as a}from"../internal/x509/name-fields.js";function o(e){let n=l(e)?e:f(e);return n.length===0?t([]):t(n.map(u))}function s(e){return(l(e)?e:f(e)).length===0}function c(e){if(e.length===0)throw Error(`Relative distinguished name must contain at least one attribute`);return n(e.map(d))}function l(e){return Array.isArray(e)}function u(e){return n([d(e)])}function d(n){let i=r[n.type];if(i===void 0)throw Error(`Unsupported name field: ${n.type}`);if(n.type===`country`&&n.value.length!==2)throw Error(`Country must be a 2-character code`);return t([e(i.oid),i.encode(n.value)])}function f(e){let t=[];for(let n of i){let r=e[n];typeof r==`string`&&r.length>0&&t.push({type:n,value:r})}return t}export{o as encodeName,c as encodeRelativeDistinguishedName,s as isNameInputEmpty,a as nameFieldKeyFromOid};
|
|
2
|
+
//# sourceMappingURL=name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.js","names":[],"sources":["../../src/x509/name.ts"],"sourcesContent":["/**\n * Distinguished-name input and DER encoding helpers.\n *\n * Encodes X.509 `Name` values used for certificate subjects, issuers,\n * and CSR subjects.\\\n * A `Name` is a DER `SEQUENCE` of RelativeDistinguishedNames (RDNs), and each\n * RDN is a `SET OF` one or more name attributes.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}\n *\n * Use {@linkcode encodeName} for the common case where each attribute occupies\n * its own RDN.\\\n * Use {@linkcode encodeRelativeDistinguishedName} when you need one\n * multi-valued RDN.\n *\n * `NameObject` favors convenience: populated fields are emitted in the\n * canonical order from `NAME_OBJECT_ORDER`.\\\n * `NameAttribute` arrays favor control: caller order is preserved, but each\n * entry still becomes its own single-attribute RDN.\n *\n * Attribute OIDs and ASN.1 string encodings come from\n * `NAME_FIELD_DEFINITIONS`.\n *\n * @example\n * ```ts\n * import { encodeName } from 'micro509/x509';\n *\n * const subjectDer = encodeName({\n * \tcountry: 'US',\n * \torganization: 'ACME Inc',\n * \tcommonName: 'example.com',\n * });\n *\n * // DER for: C=US, O=ACME Inc, CN=example.com\n * ```\n *\n * @example\n * ```ts\n * import { encodeName } from 'micro509/x509';\n *\n * const subjectDer = encodeName([\n * \t{ type: 'commonName', value: 'example.com' },\n * \t{ type: 'organization', value: 'ACME Inc' },\n * \t{ type: 'country', value: 'US' },\n * ]);\n *\n * // preserves caller-supplied attribute order\n * ```\n *\n * @example\n * ```ts\n * import { encodeRelativeDistinguishedName } from 'micro509/x509';\n *\n * const rdnDer = encodeRelativeDistinguishedName([\n * \t{ type: 'commonName', value: 'example.com' },\n * \t{ type: 'serialNumber', value: 'device-7' },\n * ]);\n *\n * // one multi-valued RDN containing CN + serialNumber\n * ```\n *\n * @module\n */\n\nimport { objectIdentifier, sequence, setOf } from '#micro509/internal/asn1/der.ts';\nimport { NAME_FIELD_DEFINITIONS, NAME_OBJECT_ORDER } from '#micro509/internal/x509/name-fields.ts';\n\n/**\n * Union of recognized X.501 attribute type shorthand names.\n *\n * Each key maps to an OID + ASN.1 string encoding in `NAME_FIELD_DEFINITIONS`.\n */\nexport type NameFieldKey =\n\t| 'commonName'\n\t| 'surname'\n\t| 'serialNumber'\n\t| 'country'\n\t| 'locality'\n\t| 'state'\n\t| 'street'\n\t| 'organization'\n\t| 'organizationalUnit'\n\t| 'title'\n\t| 'givenName'\n\t| 'emailAddress';\n\n/**\n * Convenience object form of an X.501 distinguished name.\n *\n * Populated fields are emitted in the order defined by\n * `NAME_OBJECT_ORDER`.\\\n * Each populated field becomes its own single-attribute RDN.\n *\n * For caller-controlled ordering, pass a {@linkcode NameAttribute} array to {@linkcode encodeName}.\\\n * For multi-valued RDNs, use {@linkcode encodeRelativeDistinguishedName}.\n */\nexport interface NameObject {\n\t/** Subject or issuer common name (CN). */\n\treadonly commonName?: string;\n\t/** Subject surname (SN). */\n\treadonly surname?: string;\n\t/** Device or entity serial number — not the certificate serial. */\n\treadonly serialNumber?: string;\n\t/** ISO 3166 two-letter country code (C). Must be exactly 2 characters. */\n\treadonly country?: string;\n\t/** City or locality (L). */\n\treadonly locality?: string;\n\t/** State or province (ST). */\n\treadonly state?: string;\n\t/** Street address. */\n\treadonly street?: string;\n\t/** Organization name (O). */\n\treadonly organization?: string;\n\t/** Organizational unit (OU). Deprecated in modern CA practice. */\n\treadonly organizationalUnit?: string;\n\t/** Job title or functional designation. */\n\treadonly title?: string;\n\t/** First / given name (GN). */\n\treadonly givenName?: string;\n\t/** RFC 822 email address. Encoded as IA5String, not UTF-8. */\n\treadonly emailAddress?: string;\n}\n\n/**\n * Single name attribute within a distinguished name.\n *\n * RFC 5280 / X.501 call this structure an `AttributeTypeAndValue`.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}\n * {@linkcode encodeName} places each attribute in its own single-attribute RDN.\\\n * {@linkcode encodeRelativeDistinguishedName} packs several attributes into one RDN.\n */\nexport interface NameAttribute {\n\t/** Which attribute type this pair represents. */\n\treadonly type: NameFieldKey;\n\t/** The string value for this attribute (encoding chosen per field definition). */\n\treadonly value: string;\n}\n\n/**\n * Input for {@linkcode encodeName}.\n *\n * Accepts either a {@linkcode NameObject} convenience shape or an ordered array of {@linkcode NameAttribute} pairs.\\\n * Both forms encode one attribute per RDN.\n */\nexport type NameInput = NameObject | readonly NameAttribute[];\n\n/**\n * Input for {@linkcode encodeRelativeDistinguishedName}.\n *\n * Each entry becomes one name attribute inside the RDN's `SET OF`.\\\n * Use this shape for multi-valued RDNs.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}\n */\nexport type RelativeDistinguishedNameInput = readonly NameAttribute[];\n\nexport { nameFieldKeyFromOid } from '#micro509/internal/x509/name-fields.ts';\n\n/**\n * DER-encodes an X.509 `Name`.\n *\n * Returns a DER `SEQUENCE` of RelativeDistinguishedNames (RDNs).\\\n * Each RDN emitted by this helper contains exactly one name attribute.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}\n *\n * {@linkcode NameObject} input emits populated fields in the canonical order from `NAME_OBJECT_ORDER`.\\\n * {@linkcode NameAttribute} array input preserves caller-supplied ordering,\n * but each entry still becomes its own single-attribute RDN.\n *\n * Attribute OIDs and ASN.1 string encodings come from `NAME_FIELD_DEFINITIONS`.\\\n * Empty strings and `undefined` fields are ignored when the input is a {@linkcode NameObject}.\n *\n * @example\n * ```ts\n * const der = encodeName({ country: 'US', commonName: 'example.com' });\n *\n * // emits two single-attribute RDNs: C=US, then CN=example.com\n * ```\n *\n * @example\n * ```ts\n * const der = encodeName([\n * \t{ type: 'country', value: 'US' },\n * \t{ type: 'commonName', value: 'example.com' },\n * ]);\n *\n * // preserves caller order: C first, then CN\n * ```\n *\n * @param input Name fields in convenience-object form or caller-ordered attribute form.\n * @returns DER-encoded X.509 `Name` bytes.\n * @throws {Error} If the input produces no attributes, contains an unsupported field key, or uses an invalid country code.\n */\nexport function encodeName(input: NameInput): Uint8Array {\n\tconst attributes = isNameAttributes(input) ? input : nameObjectToAttributes(input);\n\tif (attributes.length === 0) {\n\t\treturn sequence([]);\n\t}\n\n\treturn sequence(attributes.map(encodeNameAttributeAsSet));\n}\n\n/** True when a {@linkcode NameInput} resolves to zero attributes (empty DN). */\nexport function isNameInputEmpty(input: NameInput): boolean {\n\tconst attributes = isNameAttributes(input) ? input : nameObjectToAttributes(input);\n\treturn attributes.length === 0;\n}\n\n/**\n * DER-encodes a single RelativeDistinguishedName (RDN).\n *\n * Returns a DER `SET OF` name attributes for one X.509 name segment.\\\n * Use this when you need a multi-valued RDN.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1 RFC 5280 Appendix A.1}\n *\n * Attribute OIDs and ASN.1 string encodings come from\n * `NAME_FIELD_DEFINITIONS`.\n *\n * @example\n * ```ts\n * const rdn = encodeRelativeDistinguishedName([\n * \t{ type: 'commonName', value: 'example.com' },\n * \t{ type: 'serialNumber', value: 'device-7' },\n * ]);\n *\n * // emits one RDN with both attributes in the same SET\n * ```\n *\n * @param attributes Attribute list to encode inside one RDN.\n * @returns DER-encoded RelativeDistinguishedName bytes.\n * @throws {Error} If the attribute list is empty, contains an unsupported field key, or uses an invalid country code.\n */\nexport function encodeRelativeDistinguishedName(\n\tattributes: RelativeDistinguishedNameInput,\n): Uint8Array {\n\tif (attributes.length === 0) {\n\t\tthrow new Error('Relative distinguished name must contain at least one attribute');\n\t}\n\treturn setOf(attributes.map(encodeNameAttribute));\n}\n\n/** Narrows a {@linkcode NameInput} to the ordered-attribute-array form. */\nfunction isNameAttributes(input: NameInput): input is readonly NameAttribute[] {\n\treturn Array.isArray(input);\n}\n\n/** Wraps a single attribute in a SET OF for the Name SEQUENCE. */\nfunction encodeNameAttributeAsSet(attribute: NameAttribute): Uint8Array {\n\treturn setOf([encodeNameAttribute(attribute)]);\n}\n\n/**\n * DER-encodes one name attribute SEQUENCE.\n *\n * Throws for unsupported field keys and invalid country codes.\n */\nfunction encodeNameAttribute(attribute: NameAttribute): Uint8Array {\n\tconst definition = NAME_FIELD_DEFINITIONS[attribute.type];\n\tif (definition === undefined) {\n\t\tthrow new Error(`Unsupported name field: ${attribute.type}`);\n\t}\n\tif (attribute.type === 'country' && attribute.value.length !== 2) {\n\t\tthrow new Error('Country must be a 2-character code');\n\t}\n\treturn sequence([objectIdentifier(definition.oid), definition.encode(attribute.value)]);\n}\n\n/** Converts a {@linkcode NameObject} to ordered attributes per `NAME_OBJECT_ORDER`. */\nfunction nameObjectToAttributes(input: NameObject): readonly NameAttribute[] {\n\tconst attributes: NameAttribute[] = [];\n\tfor (const key of NAME_OBJECT_ORDER) {\n\t\tconst value = input[key];\n\t\tif (typeof value === 'string' && value.length > 0) {\n\t\t\tattributes.push({ type: key, value });\n\t\t}\n\t}\n\treturn attributes;\n}\n"],"mappings":"6MAmMA,SAAgB,EAAW,EAA8B,CACxD,IAAM,EAAa,EAAiB,CAAK,EAAI,EAAQ,EAAuB,CAAK,EAKjF,OAJI,EAAW,SAAW,EAClB,EAAS,CAAC,CAAC,EAGZ,EAAS,EAAW,IAAI,CAAwB,CAAC,CACzD,CAGA,SAAgB,EAAiB,EAA2B,CAE3D,OADmB,EAAiB,CAAK,EAAI,EAAQ,EAAuB,CAAK,EAAA,CAC/D,SAAW,CAC9B,CA2BA,SAAgB,EACf,EACa,CACb,GAAI,EAAW,SAAW,EACzB,MAAU,MAAM,iEAAiE,EAElF,OAAO,EAAM,EAAW,IAAI,CAAmB,CAAC,CACjD,CAGA,SAAS,EAAiB,EAAqD,CAC9E,OAAO,MAAM,QAAQ,CAAK,CAC3B,CAGA,SAAS,EAAyB,EAAsC,CACvE,OAAO,EAAM,CAAC,EAAoB,CAAS,CAAC,CAAC,CAC9C,CAOA,SAAS,EAAoB,EAAsC,CAClE,IAAM,EAAa,EAAuB,EAAU,MACpD,GAAI,IAAe,IAAA,GAClB,MAAU,MAAM,2BAA2B,EAAU,MAAM,EAE5D,GAAI,EAAU,OAAS,WAAa,EAAU,MAAM,SAAW,EAC9D,MAAU,MAAM,oCAAoC,EAErD,OAAO,EAAS,CAAC,EAAiB,EAAW,GAAG,EAAG,EAAW,OAAO,EAAU,KAAK,CAAC,CAAC,CACvF,CAGA,SAAS,EAAuB,EAA6C,CAC5E,IAAM,EAA8B,CAAC,EACrC,IAAK,IAAM,KAAO,EAAmB,CACpC,IAAM,EAAQ,EAAM,GAChB,OAAO,GAAU,UAAY,EAAM,OAAS,GAC/C,EAAW,KAAK,CAAE,KAAM,EAAK,OAAM,CAAC,CAEtC,CACA,OAAO,CACR"}
|