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 — NIST category 2, post-quantum)
mldsa65 ML-DSA-65 (FIPS 204 — NIST category 3, post-quantum)
mldsa87 ML-DSA-87 (FIPS 204 — NIST category 5, post-quantum)
ecdsa-p384+mldsa65 Hybrid: ECDSA P-384 with ML-DSA-65 composite

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 = 15
issuing_ca_years = 10
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"]