skip to content
QUANTUM NEXUM

← spork

Configuration

Spork uses TOML for configuration. The spork.toml file controls CA behavior, certificate profiles, and operational settings.

File search order

Spork searches for configuration in this order:

  1. --config command-line argument
  2. ./spork.toml in current directory
  3. $CA_DIR/spork.toml in CA directory
  4. ~/.config/spork/spork.toml user config

Basic configuration

# spork.toml

[ca]
# CA directory (overridden by --ca flag)
path = "./pki/issuing"

# Default signature algorithm
algorithm = "ecdsa-p384"  # see Algorithm selection below

# Key encryption
key_encryption = "aes-256-gcm"
require_passphrase = true

[database]
# Storage backend: sqlite (default) or postgresql (planned)
type = "sqlite"
path = "spork.db"  # relative to CA directory

# PostgreSQL (planned — not yet available)
# type = "postgresql"
# url = "postgres://user:pass@localhost/spork"

[logging]
level = "info"   # trace, debug, info, warn, error
format = "json"  # json, text
file = "spork.log"

Algorithm selection

Algorithm string Description
ecdsa-p384 ECDSA P-384 (192-bit classical security; no quantum resistance)
rsa-2048 RSA 2048-bit (compatibility; not recommended for new PKI)
rsa-3072 RSA 3072-bit
rsa-4096 RSA 4096-bit
mldsa44 ML-DSA-44 (FIPS 204 specification-conformant — NIST category 2, post-quantum)
mldsa65 ML-DSA-65 (FIPS 204 specification-conformant — NIST category 3, post-quantum)
mldsa87 ML-DSA-87 (FIPS 204 specification-conformant — NIST category 5, post-quantum)

Composite signatures (a classical and a PQ algorithm paired in one certificate) are not supported. The format is specified in draft-ietf-lamps-pq-composite-sigs, which has cleared IETF review and is awaiting RFC publication; Spork implements none of it, so there is no composite algorithm string to configure. Use a single algorithm per CA, and run parallel classical and PQ hierarchies if you need both.

Certificate profiles

Profiles define templates for certificate issuance. Each profile specifies key usage, extended key usage, and validity constraints. The profile name is passed to spork issue --profile <name>.

# TLS server certificate profile
[profiles.tls-server]
key_usage = ["digitalSignature"]
extended_key_usage = ["serverAuth"]
validity_days = 365

# Require SAN; CN alone is not sufficient
require_san = true
allowed_san_types = ["dns", "ip"]

[profiles.tls-server.subject]
required = ["CN"]
allowed = ["O", "OU", "L", "ST", "C"]
forbidden = ["emailAddress"]

# TLS client certificate profile
[profiles.tls-client]
key_usage = ["digitalSignature"]
extended_key_usage = ["clientAuth"]
validity_days = 365
require_san = false
allowed_san_types = ["email", "uri"]

[profiles.tls-client.subject]
required = ["CN"]
allowed = ["O", "OU", "emailAddress"]

# Code signing certificate profile
[profiles.code-sign]
key_usage = ["digitalSignature"]
extended_key_usage = ["codeSigning"]
validity_days = 365
require_san = false

[profiles.code-sign.subject]
required = ["CN", "O"]
allowed = ["OU", "L", "ST", "C"]

Validity periods

[validity]
root_ca_years = 20
policy_ca_years = 10
issuing_ca_years = 7
end_entity_days = 365

# Maximum end-entity validity enforced by this CA
max_end_entity_days = 365

# CRL update schedule
crl_validity_days = 7
crl_overlap_days = 1  # generate new CRL before current one expires

Spork is intended for private CAs. Public-web Baseline Requirements (CA/Browser Forum ballot SC-081v3) cap TLS end-entity validity at 200 days as of March 2026; private CAs may choose longer periods appropriate to their policy. Set max_end_entity_days to whatever your policy requires.

Extension templates

Extensions configured here are embedded in every certificate issued by the CA. Replace placeholder URLs with your own infrastructure endpoints.

[extensions]

# Authority Information Access
[extensions.aia]
ocsp = "http://ocsp.example.com/"
ca_issuers = "http://aia.example.com/issuing-ca.crt"

# CRL Distribution Points
[extensions.cdp]
uris = [
  "http://crl.example.com/issuing-ca.crl",
  "ldap://ldap.example.com/cn=Issuing%20CA,ou=PKI,o=Example,c=US"
]

# Certificate Policies
[extensions.policies]
oids = ["2.23.140.1.2.2"]   # Organization Validated (example)
cps_uri = "http://www.example.com/pki/cps"

# Name Constraints (for CA certificates)
[extensions.name_constraints]
permitted_dns = [".example.com", ".example.org"]
excluded_dns = [".forbidden.example.com"]
permitted_email = ["@example.com"]

Full example

Complete spork.toml for a private issuing CA:

[ca]
path = "/opt/pki/issuing"
algorithm = "mldsa65"
key_encryption = "aes-256-gcm"
require_passphrase = true

[database]
type = "sqlite"
path = "spork.db"

[logging]
level = "info"
format = "json"
file = "/var/log/spork/issuing.log"

[validity]
end_entity_days = 365
max_end_entity_days = 365
crl_validity_days = 7

[extensions.aia]
ocsp = "http://ocsp.example.com/"
ca_issuers = "http://aia.example.com/issuing-ca.crt"

[extensions.cdp]
uris = ["http://crl.example.com/issuing-ca.crl"]

[profiles.tls-server]
key_usage = ["digitalSignature"]
extended_key_usage = ["serverAuth"]
validity_days = 365
require_san = true
allowed_san_types = ["dns", "ip"]

[profiles.tls-server.subject]
required = ["CN"]
allowed = ["O", "OU", "L", "ST", "C"]