kryptos/x509/certificate

X.509 Certificate generation and parsing.

Builder for creating self-signed X.509 certificates. CA-signing is not currently supported.

Example

import gleam/option
import gleam/time/duration
import gleam/time/timestamp
import kryptos/ec
import kryptos/hash
import kryptos/x509
import kryptos/x509/certificate

let #(private_key, _) = ec.generate_key_pair(ec.P256)

let subject =
  x509.name([
    x509.cn("example.com"),
    x509.organization("Acme Inc"),
  ])

let now = timestamp.system_time()
// 86,400 seconds per day per CA/Browser Forum definition
let one_year_later = timestamp.add(now, duration.seconds(86_400 * 365))
let validity = x509.Validity(not_before: now, not_after: one_year_later)

let assert Ok(builder) =
  certificate.new()
  |> certificate.with_subject(subject)
  |> certificate.with_validity(validity)
  |> certificate.with_basic_constraints(ca: False, path_len_constraint: option.None)
  |> certificate.with_key_usage(x509.DigitalSignature)
  |> certificate.with_extended_key_usage(x509.ServerAuth)
  |> certificate.with_dns_name("example.com")

let assert Ok(cert) =
  certificate.self_signed_with_ecdsa(builder, private_key, hash.Sha256)

Parsing Certificates

import kryptos/x509/certificate

let pem = "-----BEGIN CERTIFICATE-----
MIIBkTCB+wIJAK...
-----END CERTIFICATE-----"

let assert Ok([cert]) = certificate.from_pem(pem)

// Access certificate fields
let subject = certificate.subject(cert)
let validity = certificate.validity(cert)
let public_key = certificate.public_key(cert)

// Verify a self-signed certificate
let assert Ok(Nil) = certificate.verify_self_signed(cert)

Types

Configuration for the Authority Key Identifier extension.

pub type AuthorityKeyIdentifierConfig {
  AkiAuto
  AkiExplicit(BitArray)
  AkiExclude
}

Constructors

  • AkiAuto

    Automatically compute AKI as SHA-1 hash of the signing key (default).

  • AkiExplicit(BitArray)

    Use a custom AKI keyIdentifier value.

  • AkiExclude

    Exclude the AKI extension entirely.

A builder for constructing X.509 certificates.

Create a builder with new(), configure it with with_* functions, then sign with one of the signing functions:

  • self_signed_with_ecdsa() for ECDSA keys
  • self_signed_with_rsa() for RSA keys
  • self_signed_with_eddsa() for Ed25519/Ed448 keys
pub opaque type Builder

Phantom type marker for certificates created via the builder.

pub type Built

An X.509 Certificate.

The phantom type parameter tracks how the certificate was created:

  • Certificate(Built) - created via self_signed_with_ecdsa etc.
  • Certificate(Parsed) - created via from_pem or from_der

Export functions (to_pem, to_der) work on any Certificate(a). Accessor functions (version, subject, etc.) require Certificate(Parsed).

pub opaque type Certificate(status)

Error type for certificate parsing failures.

pub type CertificateError {
  ParseError
  UnsupportedAlgorithm(x509.Oid)
  SignatureVerificationFailed
  UnrecognizedCriticalExtension(x509.Oid)
}

Constructors

  • ParseError

    Failed to parse the certificate data.

  • UnsupportedAlgorithm(x509.Oid)

    The certificate uses an algorithm or key type that is not supported.

  • SignatureVerificationFailed

    Cryptographic signature verification failed.

  • UnrecognizedCriticalExtension(x509.Oid)

    The certificate contains an unrecognized extension marked as critical.

    Per RFC 5280 §4.2, certificates with unknown critical extensions must be rejected. Non-critical unknown extensions are allowed.

Phantom type marker for certificates parsed from PEM/DER.

pub type Parsed

Configuration for the Subject Key Identifier extension.

pub type SubjectKeyIdentifierConfig {
  SkiAuto
  SkiExplicit(BitArray)
}

Constructors

  • SkiAuto

    Automatically compute SKI as SHA-1 hash of the public key (RFC 5280 method 1).

  • SkiExplicit(BitArray)

    Use a custom SKI value.

Values

pub fn authority_key_identifier(
  cert: Certificate(Parsed),
) -> Result(x509.AuthorityKeyIdentifier, Nil)

Returns the Authority Key Identifier (AKI) from a parsed certificate.

pub fn basic_constraints(
  cert: Certificate(Parsed),
) -> Result(x509.BasicConstraints, Nil)

Returns the Basic Constraints extension from a parsed certificate.

pub fn extended_key_usage(
  cert: Certificate(Parsed),
) -> List(x509.ExtendedKeyUsage)

Returns the Extended Key Usage purposes from a parsed certificate.

pub fn extensions(
  cert: Certificate(Parsed),
) -> List(#(x509.Oid, Bool, BitArray))

Returns all extensions as raw (OID, critical, value) tuples.

Includes all extensions, even those with typed representations. The Bool indicates whether the extension was marked as critical per RFC 5280.

pub fn from_der(
  der: BitArray,
) -> Result(Certificate(Parsed), CertificateError)

Parse a DER-encoded X.509 certificate.

Validates the ASN.1 structure and extracts all standard fields and extensions. Unknown non-critical extensions are preserved but not parsed.

Note: This function does NOT verify the certificate’s cryptographic signature. To verify a certificate was signed by an issuer, use verify(). For self-signed certificates, use verify_self_signed().

pub fn from_pem(
  pem: String,
) -> Result(List(Certificate(Parsed)), CertificateError)

Parse all PEM-encoded certificates from a string.

Extracts and parses all -----BEGIN CERTIFICATE----- blocks from the input. Certificates are returned in the order they appear.

Note: This function does NOT verify the certificates’ cryptographic signatures. To verify a certificate was signed by an issuer, use verify(). For self-signed certificates, use verify_self_signed().

pub fn generate_serial_number() -> BitArray

Generates a random 20-byte serial number with the high bit cleared per RFC 5280.

pub fn issuer(cert: Certificate(Parsed)) -> x509.Name

Returns the issuer distinguished name.

For self-signed certificates, issuer equals subject.

pub fn key_usage(
  cert: Certificate(Parsed),
) -> List(x509.KeyUsage)

Returns the Key Usage flags from a parsed certificate.

pub fn new() -> Builder

Creates a new certificate builder with default values.

Use the with_* functions to configure the builder, then call a signing function to generate the certificate.

pub fn public_key(cert: Certificate(Parsed)) -> x509.PublicKey

Returns the public key embedded in the certificate.

pub fn self_signed_with_ecdsa(
  builder: Builder,
  key: ec.PrivateKey,
  hash: hash.HashAlgorithm,
) -> Result(Certificate(Built), Nil)

Signs a self-signed certificate with an ECDSA private key.

The public key is derived from the private key and used as both the issuer and subject public key.

pub fn self_signed_with_eddsa(
  builder: Builder,
  key: eddsa.PrivateKey,
) -> Result(Certificate(Built), Nil)

Signs a self-signed certificate with an EdDSA private key.

The public key is derived from the private key and used as both the issuer and subject public key. EdDSA has built-in hashing, so no hash algorithm parameter is needed.

pub fn self_signed_with_rsa(
  builder: Builder,
  key: rsa.PrivateKey,
  hash: hash.HashAlgorithm,
) -> Result(Certificate(Built), Nil)

Signs a self-signed certificate with an RSA private key using PKCS#1 v1.5 padding.

The public key is derived from the private key and used as both the issuer and subject public key.

pub fn serial_number(cert: Certificate(Parsed)) -> BitArray

Returns the serial number of a parsed certificate.

pub fn signature_algorithm(
  cert: Certificate(Parsed),
) -> x509.SignatureAlgorithm

Returns the signature algorithm used to sign the certificate.

pub fn subject(cert: Certificate(Parsed)) -> x509.Name

Returns the subject distinguished name.

pub fn subject_alt_names(
  cert: Certificate(Parsed),
) -> List(x509.SubjectAltName)

Returns the Subject Alternative Names (SANs) from a parsed certificate.

pub fn subject_key_identifier(
  cert: Certificate(Parsed),
) -> Result(BitArray, Nil)

Returns the Subject Key Identifier (SKI) from a parsed certificate.

pub fn to_der(cert: Certificate(a)) -> BitArray

Exports the certificate as DER-encoded bytes.

pub fn to_pem(cert: Certificate(a)) -> String

Exports the certificate as a PEM-encoded string.

pub fn validity(cert: Certificate(Parsed)) -> x509.Validity

Returns the validity period of the certificate.

pub fn verify(
  cert: Certificate(Parsed),
  issuer_public_key: x509.PublicKey,
) -> Result(Nil, CertificateError)

Verify a certificate’s signature against an issuer’s public key.

The public key must be RSA, ECDSA, or EdDSA (XDH keys cannot sign).

pub fn verify_self_signed(
  cert: Certificate(Parsed),
) -> Result(Nil, CertificateError)

Verify a self-signed certificate against its own public key.

pub fn version(cert: Certificate(Parsed)) -> Int

Returns the version of a parsed certificate (0 = v1, 1 = v2, 2 = v3).

pub fn with_authority_key_identifier(
  builder: Builder,
  aki: AuthorityKeyIdentifierConfig,
) -> Builder

Configures the Authority Key Identifier extension for the certificate.

By default, self-signed certificates include an AKI with keyIdentifier computed as the SHA-1 hash of the signing public key. Use AkiExplicit for a custom value or AkiExclude to omit the extension.

pub fn with_basic_constraints(
  builder: Builder,
  ca ca: Bool,
  path_len_constraint path_len_constraint: option.Option(Int),
) -> Builder

Sets the Basic Constraints extension.

This extension indicates whether the certificate is a CA certificate and optionally limits the path length of the certification chain. Per RFC 5280, path_len_constraint is only meaningful when ca is True.

pub fn with_dns_name(
  builder: Builder,
  name: String,
) -> Result(Builder, Nil)

Adds a DNS name to the Subject Alternative Names extension.

The name must contain only ASCII characters.

pub fn with_email(
  builder: Builder,
  email: String,
) -> Result(Builder, Nil)

Adds an email address to the Subject Alternative Names extension.

The email must contain only ASCII characters.

pub fn with_extended_key_usage(
  builder: Builder,
  usage: x509.ExtendedKeyUsage,
) -> Builder

Adds an Extended Key Usage purpose to the certificate.

EKU narrows allowed purposes beyond Key Usage (e.g., ServerAuth, CodeSigning). Multiple usages can be added by chaining calls.

pub fn with_ip(
  builder: Builder,
  ip: String,
) -> Result(Builder, Nil)

Adds an IP address to the Subject Alternative Names extension.

Accepts IPv4 (e.g., “192.168.1.1”) or IPv6 (e.g., “2001:db8::1”) addresses.

pub fn with_key_usage(
  builder: Builder,
  usage: x509.KeyUsage,
) -> Builder

Adds a Key Usage flag to the certificate.

Multiple usages can be added by chaining calls.

pub fn with_serial_number(
  builder: Builder,
  serial: BitArray,
) -> Builder

Sets the serial number for the certificate.

If not set, a random serial number will be generated during signing.

pub fn with_subject(
  builder: Builder,
  subject: x509.Name,
) -> Builder

Sets the distinguished name subject for the certificate.

pub fn with_subject_key_identifier(
  builder: Builder,
  ski: SubjectKeyIdentifierConfig,
) -> Builder

Enables the Subject Key Identifier extension in the certificate.

If not called, the SKI extension will not be included. Use SkiAuto to compute from the public key (SHA-1 hash per RFC 5280 method 1) or SkiExplicit(bytes) for a custom value.

pub fn with_validity(
  builder: Builder,
  validity: x509.Validity,
) -> Builder

Sets the validity period for the certificate.

Search Document