kryptos/x509/certificate

X.509 Certificate generation and parsing.

This module provides a builder for creating X.509 certificates. Certificates can be self-signed. CA-signing is not currently supported.

Example

import gleam/option.{None}
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: 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.

Parameters

  • cert: A parsed certificate

Returns

  • Ok(AuthorityKeyIdentifier) if extension is present
  • Error(Nil) if extension is not present
pub fn basic_constraints(
  cert: Certificate(Parsed),
) -> Result(x509.BasicConstraints, Nil)

Returns the Basic Constraints extension from a parsed certificate.

Parameters

  • cert: A parsed certificate

Returns

  • Ok(BasicConstraints) if the extension is present
  • Error(Nil) if the extension is not present
pub fn extended_key_usage(
  cert: Certificate(Parsed),
) -> List(x509.ExtendedKeyUsage)

Returns the Extended Key Usage purposes from a parsed certificate.

Parameters

  • cert: A parsed certificate

Returns

List of extended key usage purposes, or empty list if extension not present.

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

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

This returns every extension present in the certificate, including those that kryptos also parses into typed representations (Basic Constraints, Key Usage, Extended Key Usage, Subject Alt Names, etc).

This is useful for inspecting extension criticality or accessing the raw DER-encoded value of any extension.

The Bool indicates whether the extension was marked as critical per RFC 5280.

Parameters

  • cert: A parsed certificate

Returns

List of all extension tuples #(Oid, Bool, BitArray).

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().

Parameters

  • der: Raw DER-encoded certificate bytes

Returns

  • Ok(Certificate(Parsed)) if parsing succeeds
  • Error(ParseError) if the ASN.1 structure is malformed
  • Error(UnsupportedAlgorithm(oid)) if the signature algorithm or key type is not supported
  • Error(UnrecognizedCriticalExtension(oid)) if an unknown extension is marked critical (per RFC 5280)
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().

Parameters

  • pem: A string containing one or more PEM-encoded certificates

Returns

  • Ok(List(Certificate(Parsed))) with parsed certificates (empty list if no certificates found)
  • Error(ParseError) if base64 decoding fails or certificate structure is invalid
  • Error(UnsupportedAlgorithm(oid)) if any certificate uses an unsupported algorithm
  • Error(UnrecognizedCriticalExtension(oid)) if any certificate has unknown critical extensions
pub fn issuer(cert: Certificate(Parsed)) -> x509.Name

Returns the issuer distinguished name.

The issuer identifies the CA that signed this certificate. For self-signed certificates, issuer equals subject.

Parameters

  • cert: A parsed certificate

Returns

The issuer as a distinguished name.

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

Returns the Key Usage flags from a parsed certificate.

Parameters

  • cert: A parsed certificate

Returns

List of key usage flags, or empty list if extension not present.

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.

Returns

A new Builder ready for configuration.

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

Returns the public key embedded in the certificate.

Parameters

  • cert: A parsed certificate

Returns

The subject’s public key (RSA, EC, Ed, or XDH).

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.

Parameters

  • builder: The configured certificate builder
  • key: An EC private key from ec.generate_key_pair
  • hash: The hash algorithm for signing.

Returns

  • Ok(Certificate(Built)) containing the signed certificate
  • Error(Nil) if the hash algorithm is not supported, validity is missing, or the public key cannot be encoded
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.

Parameters

  • builder: The configured certificate builder
  • key: An EdDSA private key from eddsa.generate_key_pair

Returns

  • Ok(Certificate(Built)) containing the signed certificate
  • Error(Nil) if validity is missing or the public key cannot be encoded
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.

Parameters

  • builder: The configured certificate builder
  • key: An RSA private key from rsa.generate_key_pair
  • hash: The hash algorithm for signing.

Returns

  • Ok(Certificate(Built)) containing the signed certificate
  • Error(Nil) if the hash algorithm is not supported, validity is missing, or the public key cannot be encoded
pub fn serial_number(cert: Certificate(Parsed)) -> BitArray

Returns the serial number of a parsed certificate.

Serial numbers are unique within a CA and encoded as unsigned integers.

Parameters

  • cert: A parsed certificate

Returns

The serial number as raw bytes.

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

Returns the signature algorithm used to sign the certificate.

Parameters

  • cert: A parsed certificate

Returns

The signature algorithm identifier.

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

Returns the subject distinguished name.

The subject identifies the entity the certificate was issued to.

Parameters

  • cert: A parsed certificate

Returns

The subject as a distinguished name.

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

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

Parameters

  • cert: A parsed certificate

Returns

List of SANs (DNS names, emails, IPs), or empty list if extension not present.

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

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

Parameters

  • cert: A parsed certificate

Returns

  • Ok(BitArray) with the SKI bytes if extension is present
  • Error(Nil) if extension is not present
pub fn to_der(cert: Certificate(a)) -> BitArray

Exports the certificate as DER-encoded bytes.

DER (Distinguished Encoding Rules) is a binary format commonly used for programmatic certificate handling.

Parameters

  • cert: The signed certificate

Returns

The raw DER-encoded certificate bytes.

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

Exports the certificate as a PEM-encoded string.

PEM (Privacy-Enhanced Mail) is a Base64-encoded format with header and footer lines.

Parameters

  • cert: The signed certificate

Returns

A PEM-encoded string with -----BEGIN CERTIFICATE----- headers.

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

Returns the validity period of the certificate.

Parameters

  • cert: A parsed certificate

Returns

The validity period with not_before and not_after timestamps.

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.

This verifies that the certificate was signed by the private key corresponding to the provided public key.

Parameters

  • cert: The parsed certificate to verify
  • issuer_public_key: The public key to verify against (must be RSA, ECDSA, or EdDSA)

Returns

  • Ok(Nil) if the signature is valid
  • Error(SignatureVerificationFailed) if the signature is invalid
  • Error(UnsupportedAlgorithm) if the key cannot be used for verification
pub fn verify_self_signed(
  cert: Certificate(Parsed),
) -> Result(Nil, CertificateError)

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

This is a convenience function that extracts the public key from the certificate and verifies the signature against it.

Parameters

  • cert: The parsed self-signed certificate to verify

Returns

  • Ok(Nil) if the signature is valid
  • Error(SignatureVerificationFailed) if the signature is invalid
  • Error(UnsupportedAlgorithm) if the certificate contains a key that cannot sign (e.g., XDH)
pub fn version(cert: Certificate(Parsed)) -> Int

Returns the version of a parsed certificate.

X.509 certificates use:

  • Version 1 = value 0
  • Version 2 = value 1
  • Version 3 = value 2 (most common, supports extensions)

Parameters

  • cert: A parsed certificate

Returns

The version number (0, 1, or 2).

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.

Parameters

  • builder: The certificate builder
  • aki: The AKI configuration:
    • AkiAuto - compute from the public key (default)
    • AkiExplicit(bytes) - use provided keyIdentifier bytes
    • AkiExclude - omit the AKI extension

Returns

The updated builder.

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.

Parameters

  • builder: The certificate builder
  • ca: True if this is a CA certificate
  • path_len_constraint: Maximum path length (only valid for CA certs)

Returns

The updated builder.

Notes

Per RFC 5280, path_len_constraint is only meaningful when ca is True. If ca is False and path_len_constraint is present, the constraint is ignored.

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

Adds a DNS name to the Subject Alternative Names extension.

SANs allow a certificate to be valid for multiple hostnames.

Parameters

  • builder: The certificate builder
  • name: A DNS hostname (e.g., “example.com” or “*.example.com”)

Returns

  • Ok(Builder) with the updated builder
  • Error(Nil) if the DNS name contains non-ASCII characters
pub fn with_email(
  builder: Builder,
  email: String,
) -> Result(Builder, Nil)

Adds an email address to the Subject Alternative Names extension.

Parameters

  • builder: The certificate builder
  • email: An email address (e.g., “user@example.com”)

Returns

  • Ok(Builder) with the updated builder
  • Error(Nil) if the email contains non-ASCII characters
pub fn with_extended_key_usage(
  builder: Builder,
  usage: x509.ExtendedKeyUsage,
) -> Builder

Adds an Extended Key Usage purpose to the certificate.

Extended Key Usage provides more specific purposes than Key Usage, such as server authentication or code signing.

Parameters

  • builder: The certificate builder
  • usage: The extended key usage purpose to add

Returns

The updated builder.

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

Adds an IP address to the Subject Alternative Names extension.

Parameters

  • builder: The certificate builder
  • ip: An IPv4 address (e.g., “192.168.1.1”) or IPv6 address (e.g., “2001:db8::1”, “::1”)

Returns

  • Ok(Builder) with the updated builder
  • Error(Nil) if the IP address cannot be parsed
pub fn with_key_usage(
  builder: Builder,
  usage: x509.KeyUsage,
) -> Builder

Adds a Key Usage flag to the certificate.

Key Usage defines the cryptographic operations the key may be used for. Multiple usages can be added by chaining calls.

Parameters

  • builder: The certificate builder
  • usage: The key usage flag to add

Returns

The updated builder.

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.

Parameters

  • builder: The certificate builder
  • serial: The serial number as raw bytes

Returns

The updated builder.

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

Sets the distinguished name subject for the certificate.

The subject identifies who the certificate is issued to.

Parameters

  • builder: The certificate builder
  • subject: A distinguished name created with x509.name

Returns

The updated builder.

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 in the certificate.

Parameters

  • builder: The certificate builder
  • ski: The SKI configuration - use SkiAuto to compute from the public key (SHA-1 hash per RFC 5280 method 1) or SkiExplicit(bytes) for a custom value

Returns

The updated builder.

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

Sets the validity period for the certificate.

Parameters

  • builder: The certificate builder
  • validity: The validity period with not_before and not_after timestamps

Returns

The updated builder.

Search Document