package core:crypto/x509
Overview
X.509 v3 certificate parsing, signature verification, and chain (path) validation.
The parser is built on the strict DER reader in core:encoding/asn1 and
is zero-copy where possible: the returned Certificate's byte-slice
fields are views into the input DER, which must outlive it. The few
allocated fields (the extension/SAN tables) are released with
destroy.
Input is DER. To parse a PEM certificate, decode it first with core:encoding/pem (label "CERTIFICATE") and pass the resulting bytes.
A successful parse means the bytes were well-formed, NOT that the
certificate is valid or trusted. The Certificate carries everything
the verifier needs: raw_tbs (the exact byte range a signature covers),
raw_spki (the range hashed for tls-server-end-point channel binding,
RFC 5929, and SPKI pinning), and raw_issuer/raw_subject (for the RFC
5280 binary-comparison rule).
Hostname verification (verify_hostname) implements the RFC 6125
subset modern clients use: subject alternative names only (no
CommonName fallback), with at most one wildcard as the entire
left-most label.
Trust is established by verify_chain, which builds a path from a leaf
to a supplied trust anchor through supplied intermediates and checks,
for each certificate, validity, signature, name chaining, and the CA /
keyCertSign / pathLenConstraint rules; verify_signature exposes the
single-edge signature check on its own.
LIMITATIONS:
- Signature verification covers RSA PKCS#1 v1.5 and RSA-PSS (SHA-256/384/512), ECDSA P-256/P-384, and Ed25519. These paths return .Unsupported_Algorithm: SHA-1 (deprecated and rejected, RFC 9155), ECDSA P-521 (effectively dead in web PKI), and RSA-PSS naming a digest or MGF this package does not recognize. - Name constraints (RFC 5280 4.2.1.10) are enforced for the dNSName and iPAddress forms: a CA's permitted/excluded subtrees are checked against every subordinate certificate's SANs, regardless of the extension's criticality. A NameConstraints that uses any other base form (directoryName, rfc822Name, URI, otherName), a minimum/maximum, or that is malformed cannot be fully evaluated, so the whole chain is rejected (fail closed) rather than accepted unchecked. NOT enforced: the RFC 5280 rule that the extension be critical, and dNSName syntax validation (a leading-period constraint is accepted, as OpenSSL does). - REVOCATION IS NOT CHECKED. verify_chain performs NO CRL or OCSP revocation checking. Callers that need revocation (e.g. TLS clients) MUST supply it separately (OCSP stapling, CRLite, …). - Certificate policies / policy constraints are not evaluated, and there is no Public Suffix List: a (CABF-forbidden) wildcard such as "*.com" would match "host.com". As a backstop, verify_chain still fails closed on any uninterpreted CRITICAL extension (.Unhandled_Critical_Extension). - EKU is checked only when opts.required_eku is set, and then by RFC 5280 semantics: a certificate with no EKU extension is unrestricted (it is not required to assert the purpose); a certificate that DOES assert EKU must include the purpose, enforced across the leaf and every intermediate (EKU nesting). Leaf KeyUsage is not checked against the intended protocol use.
Parsing is deliberately lenient wherever strictness is a validation concern rather than a structural one. Exception: Parser rejects duplicate extension OIDs (Duplicate_Extension, RFC 5280 section 4.2).
- Only dNSName and iPAddress subject alternative names are decoded
(into dns_names / ip_addresses). Other GeneralName forms (URI,
rfc822Name, directoryName, otherName) are skipped; the raw SAN
extension is still available via extensions.
- Only the extensions path validation needs are decoded
(BasicConstraints, KeyUsage, ExtKeyUsage, SubjectAltName,
Subject/Authority Key Identifier; NameConstraints is decoded at
verification time). All others (AIA, CRL distribution points,
certificate policies, …) are left raw in extensions.
- Subject and issuer are kept as raw DER (raw_subject / raw_issuer),
which is what name chaining compares (the RFC 5280 binary rule). The
attributes (CN, O, …) are decoded on demand by parse_dn, not at parse
time; dn_get / dn_string read them out and serial_string formats
the serial.
- Unsupported public-key curves yield Public_Key_Algorithm.Unknown.
- Non-conformant-but-extractable values are preserved: negative or
over-long serials, and validity dates far in the future. Validity
is stored as core:time.Time, which tops out near year 2262; dates
beyond that (the RFC 5280 "99991231235959Z" no-expiration sentinel)
saturate to that bound at parse time rather than failing, so they
read as "effectively never expires".
- Per-extension criticality rules (e.g. that subjectKeyIdentifier be
non-critical) are left to the caller via Extension.critical, and
a critical extension this package does not understand sets
unhandled_critical rather than failing the parse.
See: https://www.rfc-editor.org/rfc/rfc5280 https://www.rfc-editor.org/rfc/rfc6125 https://www.rfc-editor.org/rfc/rfc5929
Index
Constants (0)
This section is empty.
Variables (0)
This section is empty.
Procedures (22)
Procedure Groups (0)
This section is empty.
Types
Certificate ¶
Certificate :: struct { // Raw views into the input DER. raw: []u8, // the whole Certificate element raw_tbs: []u8, // TBSCertificate, header included, the signed bytes raw_issuer: []u8, // issuer Name element (RFC 5280 binary comparison) raw_subject: []u8, // subject Name element raw_spki: []u8, // SubjectPublicKeyInfo element; hash for tls-server-end-point / SPKI pinning version: int, // Certificate serial number as the raw DER INTEGER content (minimal two's-complement). // It is an opaque identifier, compare and display by these bytes. A positive serial whose top // bit is set carries a leading 0x00 sign octet; a serial of 0 is the single octet {0x00}. RFC 5280 requires // serials to be positive and <= 20 octets, but non-conformant (negative, zero, or over-long) serials are preserved serial: []u8, signature_algorithm: Signature_Algorithm, signature_oid: []u8, // OID content octets signature: []u8, // Validity bounds. time.Time is i64 nanoseconds and tops out near year 2262; X.509 dates beyond that (notably the RFC 5280 // "99991231235959Z" no-expiration sentinel) saturate to that bound at parse time, so they compare as "effectively never expires" // rather than overflowing. See asn1's _time_from_unix. not_before: time.Time, not_after: time.Time, public_key_algorithm: Public_Key_Algorithm, // RSA: modulus and exponent magnitudes. rsa_n: []u8, rsa_e: []u8, // ECDSA: the uncompressed point (0x04 || X || Y); Ed25519: the 32-byte key. ec_point: []u8, // RSASSA-PSS parameters, decoded from the signatureAlgorithm's // RSASSA-PSS-params (meaningful only when signature_algorithm == // .RSA_PSS; RFC 4055 defaults applied for omitted fields). pss_hash and // pss_mgf_hash are hash.Algorithm.Invalid when the certificate names a // digest this package cannot verify, which verify_signature reports as // .Unsupported_Algorithm rather than a failure. pss_hash: crypto_hash.Algorithm, pss_mgf_hash: crypto_hash.Algorithm, pss_salt_len: int, // BasicConstraints (basic_constraints_valid reports presence). basic_constraints_valid: bool, is_ca: bool, max_path_len: int, // -1 when absent has_key_usage: bool, key_usage: bit_set[Key_Usage_Bit; u16], has_ext_key_usage: bool, ext_key_usage: bit_set[EKU_Bit; u8], eku_has_unknown: bool, subject_key_id: []u8, authority_key_id: []u8, dns_names: []string, // ALLOCATED ip_addresses: [][]u8, // Every extension, in order, including ones this package does not interpret. extensions: []Extension, // True if a critical extension other than the ones interpreted // here was present. RFC 5280 requires a relying party to reject // such a certificate at validation time; parsing still succeeds so // the caller can inspect. // // The specific unhandled OIDs are recoverable by walking `extensions` // for entries with `critical = true` whose OID is none of the handled // ones (_OID_EXT_*). unhandled_critical: bool, }
Certificate is a parsed X.509 v3 certificate. Byte-slice fields are views into the input DER (which must outlive the Certificate) The dns_names / ip_addresses / extensions slices are allocated (their elements still view the DER) and released by destroy.
Related Procedures With Parameters
Related Procedures With Returns
DN_Attribute ¶
DN_Attribute :: struct { type: DN_Attribute_Type, value: string, oid: []u8, }
DN_Attribute is one relative distinguished name: a type and its value. When
type is Other, oid holds the raw attribute-type OID content octets.
Values are emitted as UTF8String, except Country and Serial_Number which
are PrintableString (X.520), the policy RFC 5280 section 4.1.2.4 advises.
DN_Attribute_Type ¶
DN_Attribute_Type :: enum int { Common_Name, // CN, 2.5.4.3 Country, // C, 2.5.4.6 Locality, // L, 2.5.4.7 State_Or_Province, // ST, 2.5.4.8 Organization, // O, 2.5.4.10 Organizational_Unit, // OU, 2.5.4.11 Serial_Number, // 2.5.4.5 Other, // any other attribute; its type OID is in `oid` }
Distinguished-name attribute types the DN builder knows by name. Other
carries any attribute outside this set via DN_Attribute.oid (used by
parse_dn for attributes it does not recognize by name).
Related Procedures With Parameters
EKU_Bit ¶
EKU_Bit :: enum u8 { Server_Auth, Client_Auth, Code_Signing, Email_Protection, Time_Stamping, OCSP_Signing, Any, }
Extended key usage purposes (RFC 5280 section 4.2.1.12) recognized by name;
unrecognized purposes set eku_has_unknown.
Error ¶
Error :: enum int { None, Malformed, // DER-level violation, structural mismatch, or trailing garbage. Unsupported_Version, // Certificate version beyond v3. Invalid_Validity, // notBefore/notAfter missing or unparseable. Invalid_Extension, // A recognized extension's content didn't match its schema. Duplicate_Extension, // The same extension OID appeared more than once (RFC 5280 section 4.2 forbids this). Hostname_Mismatch, // Hostname verification: no SAN matched. No_SAN, // Hostname verification: the certificate has no usable SANs of the queried kind. Allocation_Failed, // Allocating the extension/SAN tables failed. // --- verification (verify_signature / verify_chain) --- Signature_Invalid, // A signature did not verify against the issuer's public key. Unsupported_Algorithm, // The signature or public-key algorithm is recognized but not implemented here. Not_Yet_Valid, // A certificate's notBefore is in the future relative to the supplied time. Expired, // A certificate's notAfter is in the past relative to the supplied time. Unknown_Authority, // (no issuer found, failed name chaining, validity, CA constraints, or signature verification). Unhandled_Critical_Extension, // Failed to handle a critical extension, automatic rejection Incompatible_Usage, // Lacks EKU, or EKU not authorized }
Ext_Key_Usage ¶
Ext_Key_Usage is the decoded set of recognized ExtKeyUsage purposes; unrecognized purposes set Certificate.eku_has_unknown.
Related Procedures With Parameters
Extension ¶
Extension is one raw entry from the TBS extensions list. oid is
the OID content octets; value the extnValue OCTET STRING content.
Key_Usage ¶
Key_Usage :: bit_set[Key_Usage_Bit; u16]
Key_Usage is the decoded KeyUsage extension bit set.
Related Procedures With Parameters
Key_Usage_Bit ¶
Key_Usage_Bit :: enum u16 { Digital_Signature = 0, Content_Commitment = 1, Key_Encipherment = 2, Data_Encipherment = 3, Key_Agreement = 4, Key_Cert_Sign = 5, CRL_Sign = 6, Encipher_Only = 7, Decipher_Only = 8, }
Key_Usage bits per RFC 5280 section 4.2.1.3
Private_Key ¶
Private_Key :: struct { algorithm: Public_Key_Algorithm, private: []u8, public: []u8, // RSA CRT components (big-endian magnitudes), used when algorithm == RSA. rsa_n: []u8, // modulus rsa_e: []u8, // public exponent rsa_d: []u8, // private exponent rsa_p: []u8, // prime1 rsa_q: []u8, // prime2 rsa_dp: []u8, // d mod (p-1) rsa_dq: []u8, // d mod (q-1) rsa_iq: []u8, }
Private_Key holds the RAW key material to serialize as a PKCS#8
PrivateKeyInfo (RFC 5208 / 5958). It is the bytes the crypto packages expose,
which marshal_pkcs8 only assembles into DER:
- ECDSA: private is the secret scalar (ecdsa.private_key_bytes), public
(optional) the uncompressed point (ecdsa.public_key_bytes).
- Ed25519: private is the 32-byte seed (ed25519.private_key_bytes).
- RSA: the rsa_* CRT components, as big-endian magnitudes, from the
rsa.private_key_{n,e,d,p,q,dp,dq,iq} accessors.
Related Procedures With Parameters
Public_Key ¶
Public_Key :: struct { algorithm: Public_Key_Algorithm, rsa_n: []u8, rsa_e: []u8, ec_point: []u8, }
Public_Key holds the subject public-key material to encode into a SubjectPublicKeyInfo, mirroring the fields parse() extracts onto a Certificate: rsa_n/rsa_e (unsigned magnitudes) for RSA; ec_point for ECDSA (the uncompressed point 0x04||X||Y) and Ed25519 (the 32-byte key).
Related Procedures With Parameters
Public_Key_Algorithm ¶
Public_Key_Algorithm :: enum int { Unknown, RSA, ECDSA_P256, ECDSA_P384, ECDSA_P521, Ed25519, }
Public_Key_Algorithm identifies the certificate's subject public key type. Unknown covers key algorithms (or EC curves) this package does not decode; the SubjectPublicKeyInfo bytes remain available in raw_spki.
Signature_Algorithm ¶
Signature_Algorithm :: enum int { Unknown, RSA_SHA1, // obsolete; parsed for identification only RSA_SHA256, RSA_SHA384, RSA_SHA512, RSA_PSS, ECDSA_SHA256, ECDSA_SHA384, ECDSA_SHA512, Ed25519, }
Signature_Algorithm covers the PKIX signature algorithms a client encounters in practice. RSASSA-PSS parameters are decoded into the Certificate's pss_* fields.
Related Procedures With Parameters
TBS_Certificate ¶
TBS_Certificate :: struct { serial: []u8, signature_algorithm: Signature_Algorithm, issuer: []DN_Attribute, not_before: time.Time, not_after: time.Time, subject: []DN_Attribute, public_key: Public_Key, extensions: [][]u8, }
TBS_Certificate gathers the fields of a TBSCertificate to encode. issuer
and subject are RDNSequences; serial is the serialNumber's unsigned
magnitude; extensions is a list of pre-encoded Extension DER (from the
marshal_ext_* helpers), embedded in order.
Related Procedures With Parameters
Verify_Options ¶
Verify_Options :: struct { // Trust anchors. A chain is accepted iff it terminates at one of // these (matched by name + signature, as ordinary issuers). Usually // self-signed roots, but any certificate trusted a priori works. roots: []^Certificate, // Untrusted intermediates available to bridge the leaf to a root. // Order does not matter; verify_chain searches them. intermediates: []^Certificate, // Reference time for every certificate's validity window. current_time: time.Time, // If non-empty, the leaf must pass verify_hostname for this name. dns_name: string, // If set, the leaf's ExtKeyUsage must permit this purpose (a leaf // with no EKU extension is unrestricted and always passes). TLS // clients pass .Server_Auth. required_eku: runtime.Maybe($T=EKU_Bit), }
Verify_Options parameterizes verify_chain.
Related Procedures With Parameters
Constants
This section is empty.
Variables
This section is empty.
Procedures
destroy ¶
destroy :: proc(cert: ^Certificate, allocator := context.allocator) {…}
dn_get ¶
dn_get :: proc(attrs: []DN_Attribute, type: DN_Attribute_Type) -> (value: string, ok: bool) {…}
dn_get returns the value of the first attribute of type (e.g. .Common_Name),
and whether one was present.
dn_string ¶
@(require_results) dn_string :: proc(attrs: []DN_Attribute, allocator := context.allocator) -> string {…}
dn_string renders attrs as an RFC 4514 string ("CN=leaf,O=Acme,C=US"):
RDNs in reverse order, short names for the recognized attributes and the
dotted OID for Other, with RFC 4514 section 2.4 special characters escaped.
The returned string is the caller's to free.
marshal_certificate ¶
@(require_results) marshal_certificate :: proc(tbs_der: []u8, signature_algorithm: Signature_Algorithm, signature: []u8, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_certificate wraps a (separately signed) TBSCertificate into a
complete X.509 Certificate. signature_algorithm must match the one inside
the TBS (RFC 5280 section 4.1.1.2). The slice is the caller's to free.
marshal_csr ¶
@(require_results) marshal_csr :: proc(cri_der: []u8, signature_algorithm: Signature_Algorithm, signature: []u8, allocator := context.allocator) -> (csr_der: []u8, err: Error) {…}
marshal_csr wraps a (separately signed) CertificationRequestInfo into a
complete PKCS#10 CertificationRequest. signature is the raw signature
value over cri_der, a DER ECDSA-Sig-Value for ECDSA, the 64-byte value
for Ed25519, and signature_algorithm selects the matching
AlgorithmIdentifier. The slice is the caller's to free.
marshal_csr_info ¶
@(require_results) marshal_csr_info :: proc(subject: []DN_Attribute, key: Public_Key, extensions: [][]u8 = nil, allocator := context.allocator) -> (cri_der: []u8, err: Error) {…}
marshal_csr_info encodes the CertificationRequestInfo, the to-be-signed
portion of a PKCS#10 CSR (RFC 2986): version v1, the subject DN, the subject
public key, and the attributes set. Sign the returned bytes and pass them
with the signature to marshal_csr. The slice is the caller's to free;
subject, key, and extensions need not outlive the call.
extensions is a list of pre-encoded Extension DER (from the marshal_ext_*
helpers); when non-empty it is requested via a single PKCS#9
extensionRequest attribute (the standard way a CSR asks the CA to place
extensions, SANs, key usage in the issued certificate). Pass nil for the
empty attributes set.
marshal_dn ¶
@(require_results) marshal_dn :: proc(attrs: []DN_Attribute, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_dn encodes attrs as a DER Name (RDNSequence): one single-valued
RelativeDistinguishedName per attribute, in the given order. The returned
slice is the caller's to free; the attribute value bytes are copied into
it, so attrs need not outlive the call.
marshal_ext_basic_constraints ¶
@(require_results) marshal_ext_basic_constraints :: proc(is_ca: bool, max_path_len: int, critical: bool, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_ext_basic_constraints encodes id-ce-basicConstraints:
BasicConstraints ::= SEQUENCE { cA BOOLEAN DEFAULT FALSE, pathLenConstraint INTEGER OPTIONAL }
cA is emitted only when is_ca; pathLenConstraint only when is_ca and
max_path_len >= 0 (a negative value means "absent").
marshal_ext_ext_key_usage ¶
@(require_results) marshal_ext_ext_key_usage :: proc(eku: bit_set[EKU_Bit; u8], critical: bool, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_ext_ext_key_usage encodes id-ce-extKeyUsage: ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId in EKU_Bit order.
marshal_ext_key_usage ¶
@(require_results) marshal_ext_key_usage :: proc(usage: bit_set[Key_Usage_Bit; u16], critical: bool, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_ext_key_usage encodes id-ce-keyUsage as a KeyUsage BIT STRING, minimally (trailing zero bits dropped, per DER named bit strings).
marshal_ext_san ¶
@(require_results) marshal_ext_san :: proc(dns_names: []string, ip_addresses: [][]u8, critical: bool, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_ext_san encodes id-ce-subjectAltName: GeneralNames ::= SEQUENCE OF GeneralName emitting dNSName [2] IA5String entries (in order) followed by iPAddress [7] OCTET STRING entries. IP values are the raw 4- or 16-octet address.
marshal_pkcs8 ¶
@(require_results) marshal_pkcs8 :: proc(key: Private_Key, allocator := context.allocator) -> (der: []u8, err: Error) {…}
Serializes key as a DER PKCS#8 PrivateKeyInfo. The crypto has already
happened; this only nests the raw bytes. An unknown algorithm yields
.Unsupported_Algorithm. The returned slice is the caller's to free.
marshal_spki ¶
@(require_results) marshal_spki :: proc(key: Public_Key, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_spki encodes key as a DER SubjectPublicKeyInfo, the inverse of
the SPKI decoding in parse(); the returned slice is the caller's to free.
Unknown / unsupported key algorithms yield .Unsupported_Algorithm.
marshal_tbs_certificate ¶
@(require_results) marshal_tbs_certificate :: proc(tbs: TBS_Certificate, allocator := context.allocator) -> (der: []u8, err: Error) {…}
marshal_tbs_certificate encodes a v3 TBSCertificate (RFC 5280 section 4.1), the to-be-signed portion of a certificate. Sign the returned bytes and pass them with the signature to marshal_certificate. The slice is the caller's to free; the inputs need not outlive the call.
parse ¶
@(require_results) parse :: proc(der: []u8, allocator := context.allocator) -> (cert: Certificate, err: Error) {…}
parse decodes one DER certificate. The returned Certificate holds views into der, which must outlive it;
the allocated tables are released with destroy(). Trailing bytes after the certificate are an error.
parse_dn ¶
@(require_results) parse_dn :: proc(der: []u8, allocator := context.allocator) -> (attrs: []DN_Attribute, err: Error) {…}
parse_dn decodes a DER Name (an RDNSequence, e.g. cert.raw_subject or
cert.raw_issuer) into its attributes, the inverse of marshal_dn. Attributes
outside the recognized set (see DN_Attribute_Type) come back as Other with
their type OID in oid. The returned slice is the caller's to free; every
value (and oid) is a VIEW into der, which must outlive the result.
Values are taken as the raw content octets of the attribute value: correct for the UTF8String / PrintableString / IA5String forms certificates use in practice, but Teletex/BMP/Universal strings are NOT transcoded (returned as their raw bytes).
private_key_clear ¶
private_key_clear :: proc "contextless" (key: ^Private_Key) {…}
private_key_clear securely wipes the secret material key references.
The byte buffers are the caller's: this clears their secret contents
in place (the public modulus / exponent / point are left untouched; only the
slice headers are dropped). The DER that marshal_pkcs8 returns also holds the
key, so wipe and free it separately.
serial_string ¶
@(require_results) serial_string :: proc(cert: ^Certificate, allocator := context.allocator) -> string {…}
serial_string formats the certificate serial as upper-case colon-separated hex ("07:44:76:…"). The serial is an opaque identifier (up to 20 octets) Allocated String
valid_at ¶
@(require_results) valid_at :: proc "contextless" (cert: ^Certificate, now: time.Time) -> bool {…}
valid_at returns true iff now falls within the
certificate's validity window (inclusive on both ends, per RFC 5280
section 4.1.2.5). Obtain now from e.g. time.now().
verify_chain ¶
@(require_results) verify_chain :: proc(leaf: ^Certificate, opts: Verify_Options, allocator := context.allocator) -> (chain: []^Certificate, err: Error) {…}
A certificate carrying a critical extension this package does not interpret fails the path closed (see .Unhandled_Critical_Extension). When opts.dns_name is set the leaf must pass verify_hostname; when opts.required_eku is set the leaf AND every intermediate must permit that purpose (e.g. an email-only sub-CA cannot issue a TLS server leaf).
The trust anchor is treated as trusted input: it must be valid at opts.current_time and is name-chained + signature-checked as the issuer below it, but its CA authorization (basicConstraints / keyCertSign / pathLenConstraint) and its own self-signature are NOT re-checked. An expired anchor is still rejected; resilience to that comes from the search trying every other available anchor and intermediate.
verify_hostname ¶
@(require_results) verify_hostname :: proc(cert: ^Certificate, host: string) -> Error {…}
verify_hostname checks host against the certificate's subject
alternative names per RFC 6125:
- IP-literal hosts match iPAddress SANs by byte equality only. - DNS hosts match dNSName SANs case-insensitively; one wildcard is permitted as the ENTIRE left-most label of the SAN ("*.example.com" matches "a.example.com" but never "a.b.example.com", "example.com", or partial labels like "f*.example.com"). - The legacy CommonName fallback is not implemented (deprecated since RFC 6125).
Returns .None on match, .Hostname_Mismatch when SANs of the right kind exist but none match, and .No_SAN when the certificate carries no SAN of the queried kind.
verify_signature ¶
@(require_results) verify_signature :: proc(cert: ^Certificate, issuer: ^Certificate) -> Error {…}
============================================================ Signature verification and chain (path) validation.
verify_signature checks that cert's signature was produced by the
private key matching issuer's public key, over cert.raw_tbs (the
signed TBSCertificate). It checks ONLY the cryptographic signature,
not validity periods, names, basic constraints, or that issuer is
actually authorized to issue cert; verify_chain does all of that.
Returns .None on a good signature, .Signature_Invalid on a bad one, and .Unsupported_Algorithm when the signature algorithm (SHA-1, which is rejected per RFC 9155; ECDSA P-521; or RSA-PSS with an unrecognized digest) or the issuer key type is not implemented here.
Procedure Groups
This section is empty.
Source Files
- doc.odin
- ext.odin
- marshal.odin
- name.odin
- name_constraints.odin
- parse.odin
- pkcs8.odin
- verify.odin
- x509.odin
Generation Information
Generated with odin version dev-2026-09 (vendor "odin") Windows_amd64 @ 2026-10-01 00:18:38.976892800 +0000 UTC