Skip to content

Quick Start

Post-Quantum X.509 PKI in Go

CI codecov Go Report Card Go Reference Release Dependabot License

QPKI is a quantum-safe PKI toolkit to help organizations prepare for post-quantum cryptography (PQC) with interoperable, standards-compliant certificates.

For education and prototyping — Learn PKI concepts, experiment with PQC migration, and test crypto-agility. See Qlab for step-by-step tutorials.

  • State-of-the-art X.509 certificates (RFC 5280 compliant)
  • Post-Quantum Cryptography (PQC) support via ML-DSA, SLH-DSA and ML-KEM
  • CSR generation for all algorithms including RFC 9883 ML-KEM attestation
  • Catalyst certificates (ITU-T X.509 Section 9.8) - dual keys via extensions
  • Composite certificates (IETF draft-13, DRAFT) - dual keys bound together
  • Hybrid certificates (classical + PQC via combined or separate modes)
  • SSH Certificates (OpenSSH format) - user and host certificate issuance (classical algorithms)
  • CMS Signatures & Encryption (RFC 5652) - sign and encrypt with PQC
  • Crypto-agility - seamless migration between algorithms (ECDSA → ML-DSA)
  • Profiles (certificate templates) - define certificate policies in YAML
  • Credentials - group certificates with coupled lifecycle
  • HSM support via PKCS#11
  • Cross-validated with external implementations (OpenSSL, BouncyCastle)
  • CLI-first - simple, scriptable, no database required
  • PQC via Cloudflare CIRCL — FIPS 203/204/205 implementations, NIST ACVP test vectors validated
  • Pure Go by default - CGO optional (only for HSM/PKCS#11)
AlgorithmSecurityNotes
ECDSA (P-256, P-384, P-521)~128/192/256-bitNIST curves, P-384 recommended
EdDSA (Ed25519, Ed448)~128/224-bitFast, constant-time
RSA (2048, 4096)~112/140-bitLegacy compatibility

EC keys support both ECDSA (signature) and ECDH (key agreement) depending on certificate keyUsage.

AlgorithmSecurityNotes
ML-DSA-44/65/87NIST Level 1/3/5FIPS 204, lattice-based
SLH-DSA-128/192/256NIST Level 1/3/5FIPS 205, hash-based
ML-KEM-512/768/1024NIST Level 1/3/5FIPS 203, key encapsulation

Classical security levels reflect resistance to classical attacks only. Post-quantum algorithms are designed to remain secure against quantum adversaries.

  • Go 1.25 or later (only for building from source)
  • No CGO required for standard usage
  • CGO required only for HSM/PKCS#11 support (optional)
  • No external dependencies (OpenSSL not required)

Download the latest release for your platform from GitHub Releases.

Linux / macOS:

Terminal window
# Download (replace VERSION, OS, and ARCH as needed)
curl -LO https://github.com/remiblancher/qpki/releases/latest/download/qpki_VERSION_OS_ARCH.tar.gz
# Extract
tar -xzf qpki_*.tar.gz
# Install
sudo mv qpki /usr/local/bin/
# Verify
qpki --version

Available platforms:

OSArchitectureFile
Linuxamd64qpki_VERSION_linux_amd64.tar.gz
Linuxarm64qpki_VERSION_linux_arm64.tar.gz
macOSIntelqpki_VERSION_darwin_amd64.tar.gz
macOSApple Siliconqpki_VERSION_darwin_arm64.tar.gz
macOSUniversalqpki_VERSION_darwin_all.tar.gz
Windowsamd64qpki_VERSION_windows_amd64.zip

Linux packages:

Terminal window
# Debian/Ubuntu
sudo dpkg -i qpki_VERSION_linux_amd64.deb
# RHEL/Fedora
sudo rpm -i qpki_VERSION_linux_amd64.rpm
Terminal window
brew tap remiblancher/qpki
brew install qpki

All releases are signed with GPG. To verify:

Terminal window
# Import public key
gpg --keyserver keyserver.ubuntu.com --recv-keys 39CD0BF9647E3F56
# Download checksums and signature
curl -LO https://github.com/remiblancher/qpki/releases/download/vX.Y.Z/checksums.txt
curl -LO https://github.com/remiblancher/qpki/releases/download/vX.Y.Z/checksums.txt.sig
# Verify signature
gpg --verify checksums.txt.sig checksums.txt

Requires Go 1.25 or later.

Terminal window
# Clone and build
git clone https://github.com/remiblancher/qpki.git
cd qpki
go build -o qpki ./cmd/qpki
# Or install directly to GOPATH/bin
go install github.com/remiblancher/qpki/cmd/qpki@latest
Terminal window
qpki version
qpki --help
Terminal window
# Create a CA with ECDSA P-384 (recommended)
qpki ca init --profile ec/root-ca --ca-dir ./root-ca --var cn="My Root CA"
# → root-ca/{ca.crt, private/ca.key, certs/, crl/, index.txt, serial}
# Create a hybrid CA (ECDSA + ML-DSA, ITU-T X.509 Section 9.8)
qpki ca init --profile hybrid/catalyst/root-ca --ca-dir ./hybrid-ca --var cn="Hybrid Root CA"
# Create a pure PQC CA (ML-DSA-87)
qpki ca init --profile ml/root-ca --ca-dir ./pqc-ca --var cn="PQC Root CA"
Terminal window
# Create a subordinate/issuing CA signed by the root
qpki ca init --profile ec/issuing-ca --ca-dir ./issuing-ca \
--parent ./root-ca --var cn="Issuing CA"

This creates a complete CA structure with:

  • ca.crt - Subordinate CA certificate
  • chain.crt - Full certificate chain (sub CA + root)
  • private/ca.key - Subordinate CA private key

Generate private key files. The public key is mathematically derived from the private key and can be extracted using qpki key pub.

Terminal window
# Generate an ECDSA key
qpki key generate --algorithm ecdsa-p256 --out key.pem
# Generate an ML-DSA-65 (PQC lattice-based) key
qpki key generate --algorithm ml-dsa-65 --out ml-dsa-key.pem
# Generate an SLH-DSA-128f (PQC hash-based) key
qpki key generate --algorithm slh-dsa-128f --out slh-dsa-key.pem
# Generate with passphrase protection
qpki key generate --algorithm ecdsa-p384 --out key.pem --passphrase mysecret
# Extract public key from private key
qpki key pub --key key.pem --out key.pub

When using --keyout, the private key is generated alongside the CSR. Use --key to create a CSR from an existing key.

Terminal window
# Generate NEW key pair + CSR
qpki csr gen --algorithm ecdsa-p256 --keyout server.key --cn server.example.com --out server.csr
# CSR from EXISTING key (no key generation)
qpki csr gen --key existing.key --cn server.example.com --out server.csr
# PQC CSR (ML-DSA)
qpki csr gen --algorithm ml-dsa-65 --keyout mldsa.key --cn alice@example.com --out mldsa.csr
# ML-KEM CSR with RFC 9883 attestation
qpki csr gen --algorithm ml-kem-768 --keyout kem.key --cn alice@example.com \
--attest-cert sign.crt --attest-key sign.key --out kem.csr
# Hybrid CSR (ECDSA + ML-DSA dual signatures)
qpki csr gen --algorithm ecdsa-p256 --keyout classical.key \
--hybrid ml-dsa-65 --hybrid-keyout pqc.key --cn example.com --out hybrid.csr

Certificates are always issued from a CSR (Certificate Signing Request). For direct issuance with key generation, use qpki credential enroll instead.

Terminal window
# From classical CSR with variables
qpki cert issue --ca-dir ./myca --profile ec/tls-server \
--csr server.csr --out server.crt \
--var cn=api.example.com \
--var dns_names=api.example.com,api-v2.example.com
# Using a variables file
qpki cert issue --ca-dir ./myca --profile ec/tls-server \
--csr server.csr --var-file vars.yaml
# From PQC signature CSR (ML-DSA, SLH-DSA)
qpki cert issue --ca-dir ./myca --profile ml/tls-server-sign \
--csr mldsa.csr --out server.crt \
--var cn=pqc.example.com
# From ML-KEM CSR (requires RFC 9883 attestation for verification)
qpki cert issue --ca-dir ./myca --profile ml-kem/client \
--csr kem.csr --out kem.crt \
--attest-cert sign.crt --var cn=client@example.com
# From Hybrid CSR (classical + PQC dual signatures)
qpki cert issue --ca-dir ./myca --profile hybrid/catalyst/tls-server \
--csr hybrid.csr --out server.crt \
--var cn=hybrid.example.com
Terminal window
# Show certificate details
qpki inspect certificate.crt
# Show key information
qpki inspect private-key.pem
# Verify certificate chain
qpki cert verify server.crt --ca ./myca/ca.crt
# Verify with CRL revocation check
qpki cert verify server.crt --ca ./myca/ca.crt --crl ./myca/crl/ca.crl
# List all issued certificates
qpki cert list --ca-dir ./myca
# List only valid certificates
qpki cert list --ca-dir ./myca --status valid
Terminal window
# Sign a document (detached signature)
qpki cms sign --data doc.pdf --cert signer.crt --key signer.key --out doc.p7s
# Verify signature
qpki cms verify doc.p7s --data doc.pdf --ca ca.crt
# Encrypt for recipient (supports ECDH, RSA, ML-KEM)
qpki cms encrypt --recipient bob.crt --in secret.txt --out secret.p7m
# Decrypt
qpki cms decrypt --key bob.key --in secret.p7m --out secret.txt
Terminal window
# Revoke a certificate by serial number
qpki cert revoke 02 --ca-dir ./myca --reason superseded
# Revoke and generate new CRL
qpki cert revoke 02 --ca-dir ./myca --gen-crl
# Generate/update CRL
qpki crl gen --ca-dir ./myca --days 30

Profiles are YAML files that define how certificates are issued. 1 profile = 1 certificate type.

QPKI includes 50+ built-in profiles covering common use cases. All examples in this README use these built-in profiles for simplicity.

Terminal window
# List all built-in profiles
qpki profile list
# View profile details
qpki profile info hybrid/catalyst/tls-server
# Export a profile to customize it
qpki profile export ec/tls-server ./my-tls-server.yaml
# Export all profiles for reference
qpki profile export --all ./templates/

You can also create custom profiles from scratch. See Profiles for the full YAML specification.

Profile Categories:

CategoryDescription
ec/*ECDSA profiles (modern classical)
rsa/*RSA profiles (legacy compatibility)
ml/*ML-DSA and ML-KEM (post-quantum)
slh/*SLH-DSA (hash-based post-quantum)
hybrid/catalyst/*Catalyst dual-key (ITU-T X.509 9.8)
hybrid/composite/*IETF composite signatures

Example Profile (catalyst mode):

name: hybrid/catalyst/tls-server
mode: catalyst
algorithms:
- ecdsa-p256
- ml-dsa-65
validity: 365d
extensions:
keyUsage:
values: [digitalSignature]
extKeyUsage:
values: [serverAuth]

See Profiles for details.

A credential is a managed bundle of private key(s) + certificate(s) with coupled lifecycle management (enrollment, renewal, revocation).

credential enroll generates everything in one command:

Terminal window
qpki credential enroll --ca-dir ./myca --profile ec/tls-client --var cn=Alice
# → credentials/<id>/{credential.meta.json, certificates.pem, private-keys.pem}

Why use credentials?

  • Coupled lifecycle: Renew or revoke all certificates at once
  • Multi-certificate: Use multiple --profile flags for crypto-agility (classical + PQC)
Terminal window
# Create credential with multiple profiles (crypto-agility)
qpki credential enroll --ca-dir ./myca --profile ec/client --profile ml/client --var cn=Alice
# Create credential with custom ID
qpki credential enroll --ca-dir ./myca --profile hybrid/catalyst/tls-client --var cn=Alice --id alice-prod

Manage credential lifecycle:

Terminal window
# List credentials
qpki credential list
# Show credential details
qpki credential info alice-20250115-abc123
# Renew all certificates in a credential
qpki credential rotate alice-20250115-abc123
# Renew with crypto migration (add/change profiles)
qpki credential rotate alice-20250115-abc123 --profile ec/client --profile ml/client
# Revoke all certificates in a credential
qpki credential revoke alice-20250115-abc123 --reason keyCompromise

See Credentials for details.

This project focuses on real-world Post-Quantum PKI interoperability. All artifacts are designed to be compatible with standard PKI tooling and are cross-tested with external implementations.

StandardDescriptionStatus
RFC 5280X.509 Certificates and CRL🟢
RFC 2986PKCS#10 CSR🟢
RFC 9883ML-KEM CSR Attestation🟢
RFC 6960OCSP🟢
RFC 3161TSA Timestamping🟢
RFC 5652CMS Signed Data🟢
RFC 8419EdDSA in CMS🟢
RFC 9814SLH-DSA in CMS🟢
RFC 9882ML-DSA in CMS🟢
FIPS 203ML-KEM🟢
FIPS 204ML-DSA🟢
FIPS 205SLH-DSA🟢
ITU-T X.509 9.8Catalyst (dual-key extensions)🟢
IETF draft-13Composite Signatures🟢

Artifacts are validated using OpenSSL 3.6+ and BouncyCastle 1.83+.

TypeQPKIOpenSSLBouncyCastle
Classical (ECDSA/RSA)🟢🟢 verify🟢 verify
PQC (ML-DSA, SLH-DSA)🟢🟢 verify🟢 verify
Catalyst Hybrid🟢 both sigs🟢 ECDSA only🟢 both sigs
Composite (IETF)🟢 both sigs🔴🟡 parse only*
TypeQPKIOpenSSLBouncyCastle
Classical🟢🟢 verify🟢 verify
PQC (ML-DSA)🟢🟢 verify🟢 verify
ML-KEM (RFC 9883)🟢🟢 parse🟢 verify
Hybrid🟢🟢 primary🟢 both sigs
TypeQPKIOpenSSLBouncyCastle
Classical🟢🟢 verify🟢 verify
PQC (ML-DSA, SLH-DSA)🟢🟢 verify🟢 verify
Catalyst Hybrid🟢 both sigs🟢 ECDSA only🟢 both sigs
Composite (IETF)🟢 both sigs🔴🟡 parse only*
ArtifactQPKIOpenSSLBouncyCastle
OCSP Response🟢🟢 verify🟢 verify
TSA Timestamp🟢🟢 verify🟢 verify
CMS Signed Data🟢🟢 verify🟢 verify
CMS Enveloped (ML-KEM)🟢🟢 decrypt🟢 decrypt
FeatureStatusNotes
Composite signatures🟡 PartialBC 1.83 uses draft-07 OIDs, we use IETF draft-13
OpenSSL Catalyst🟡 PartialOnly ECDSA signature verified, PQC ignored
HSM support (PKCS#11)🟢Tested with SoftHSM; hardware HSM not yet validated

*Composite: BC 1.83 implements draft-07 (Entrust OIDs 2.16.840.1.114027.80.8.1.x), our implementation uses draft-13 (IETF standard OIDs 1.3.6.1.5.5.7.6.x). Certificates parse correctly but signature verification requires OID migration in BC.

Terminal window
make crosstest # All (OpenSSL + BouncyCastle)
make crosstest-openssl # OpenSSL only
make crosstest-bc # BouncyCastle only (requires Java 17+)

OpenSSL and BouncyCastle are used for interoperability validation only. This project does not embed nor depend on these libraries.

See docs/dev/TESTING.md for details on the testing strategy.

DocumentDescription
InstallationDownload binaries, Homebrew, or build from source
Quick StartCreate your first CA and certificate in 5 minutes
Post-QuantumPQC algorithms and hybrid certificates
DocumentDescription
CACA initialization and management
ProfilesCertificate profile templates
Keys & CSRKey generation and CSR operations
CertificatesCertificate issuance
CRLRevocation lists
DocumentDescription
CredentialsBundled key + certificate lifecycle
DocumentDescription
OCSPReal-time certificate status (RFC 6960)
TSATimestamping service (RFC 3161)
CMSCMS signatures and encryption (RFC 5652)
COSECBOR Object Signing (IoT, attestation)
SSHSSH certificate issuance (OpenSSH format)
DocumentDescription
HSMHardware Security Module integration (PKCS#11)
AuditAudit logging and SIEM integration
DocumentDescription
Crypto-AgilityAlgorithm migration guide
HybridHybrid certificates
DocumentDescription
CLIComplete command reference
TroubleshootingCommon errors and solutions
StandardsOIDs and formats
PKI BasicsCertificates, keys, CAs, trust chains
GlossaryPKI and PQC terminology
DocumentDescription
ArchitectureSystem architecture overview
ContributingContribution guide
TestingTesting guide
InteroperabilityInterop testing

Developed and maintained by Remi Blancher, cryptography and PKI specialist with 20+ years of experience in cryptographic infrastructures and post-quantum migration.

For questions, feedback, or professional inquiries:

Apache License 2.0 - See LICENSE for details.