A Go CLI tool to manage a homelab/small-office Certificate Authority with centrally managed, age encrypted private keys.
Typical usage scenario: Run it on your desktop once a year or once a month to issue and deploy TLS certificates for your LAN/VPN devices, enabling them to provide HTTPS access without warnings. For easy management, you can keep your (encrypted) CA store and configuration within a Git repository.
- Features
- Motivation and Design Targets
- Cryptographic Implementation
- Installation
- Quick Start
- CLI Reference
- Common Workflows
- Emergency Access
- Configuration
- X.509 Certificate Extensions
- Store Structure
- Cryptographic Options
- Key Protection and Authentication
- Intermediate CAs
- agenix integration
- Development
- Browser Compatibility Matrix
- Limitations
- Alternative Solutions
- Further Reading: Introduction to PKI and X.509
- Create and manage a self-signed Certificate Authority
- Generate and renew certificates for hosts/services and other entities
- Strong key encryption with multiple providers:
- Password-based encryption using age with scrypt key derivation
- SSH key-based encryption using existing SSH identities (age-ssh)
- Hardware token encryption using age plugins (Secure Enclave, YubiKey, etc.)
- Certificate inventory and expiration tracking
- Simple deployment to target locations via shell scripts, for example directly to your FritzBox, Proxmox PVE instance or NixOS configuration
- Single statically-linked binary with no runtime dependencies
For a quick overview, maybe you want to have a look at the example configs.
Running your own CA works well to provide X.509 certificates to internal hosts and services, for them to offer TLS encryption. But certificate lifetimes are nowadays, 2025, limited to one year (by Apple at least), and the Industry [is] to Shift to 47-Day SSL/TLS Certificate Validity by 2029.
The certificate lifespan reductions will be implemented in phases:
- ~6 months (starting March 2026),
- ~3 months (starting March 2027), and
- 1.5 months (starting March 2029)
Therefore a one-button reissue & deploy solution is required, easily manageable as part of an infrastructure Git repo.
- “Inversion of control” of traditional CA flow: CSRs are rare, all keys are managed centrally
- Easily rekey, reissue and deploy to many hosts with a single command, so certificates can be kept fresh with minimal infrastructure and configuration
- Encryption of private keys, so config and store can be shared via Git
- Modern CLI
- Sane and secure defaults
- Easy to deploy and package
- Proper documentation including basic X.509/CA knowledge
ReactorCA is built on proven cryptographic foundations:
- Go Standard Crypto: Uses
crypto/x509
for certificate operations,crypto/rsa
andcrypto/ecdsa
for key generation, andcrypto/rand
for secure randomness - age Encryption: Modern file encryption using Filippo Valsorda's age library for private key protection
Private keys are stored as .key.age
files, protected by the age encryption format. All methods use ChaCha20-Poly1305 for the actual encryption, with different approaches for securing the file key:
Password protection:
- scrypt derives a key from your password
- This key encrypts the file key in the age header
- Password strength directly impacts security
SSH key protection:
- Your SSH private key decrypts the file key
- Optional additional password protection
- Works with Ed25519, RSA, and ECDSA keys
Hardware security:
- Hardware device required to decrypt the file key
- YubiKey PIV slots via
age-plugin-yubikey
- Apple Secure Enclave (Touch ID) via
age-plugin-se
- TPM support via
age-plugin-tpm
- Etc.
Download the latest release for your platform from the releases page.
git clone https://github.com/serpent213/reactor-ca.git
cd reactor-ca
go build -o ca ./cmd/ca
First, create the default config files:
ca init
ReactorCA automatically detects your SSH keys and configures encryption accordingly:
- SSH keys found: Uses SSH-based encryption (prefers Ed25519 over RSA)
- No SSH keys: Falls back to password-based encryption
This creates configuration files in the config/
directory. Edit them according to your needs.
After editing the configuration, create the CA:
ca ca create
This creates a self-signed CA certificate and private key (encrypted with the password you provide).
That root CA certificate needs to be installed on all client devices to be able to verify the host certificate to be created in the next step. See INSTALL_CA for details.
To issue a certificate for a host defined in your hosts.yaml:
ca host issue web-server-example
To list all certificates with their expiration dates:
ca host list
ReactorCA supports flexible certificate export and deployment:
Export only (automatic during certificate issuance):
ca host issue web-server-example # Exports to configured paths automatically
Deploy only (run deployment commands independently):
ca host deploy web-server-example # Runs deployment without re-issuing
Issue, export and deploy together:
ca host issue web-server-example --deploy # Issue certificate then deploy
Deploy will create temp files if the required files are not exported, so export
and deploy
options can be used independently from each other.
Deploy scripts run in Bash, except for Windows where they run in PowerShell.
--root <path>
- Root directory for config and store (env:REACTOR_CA_ROOT
)
Command | Description |
---|---|
ca ca create |
Create a new CA key and self-signed certificate |
ca ca renew |
Renew the CA certificate using the existing key |
ca ca rekey |
Create a new key and certificate, replacing the old ones |
ca ca info |
Display detailed information about the CA certificate |
ca ca info --openssl |
Invoke openssl to display full text dump |
ca ca import --cert <path> --key <path> |
Import an existing CA certificate and private key |
ca ca export-key |
Export unencrypted CA private key to stdout |
ca ca export-key -o file.key |
Export CA private key to file |
ca ca reencrypt |
Change the master password/update recipients for all encrypted keys |
Command | Description |
---|---|
ca host issue <host-id> |
Issue/renew a certificate for a host |
ca host issue --all |
Issue/renew certificates for all hosts |
ca host issue <host-id> --rekey |
Force generation of a new private key |
ca host issue <host-id> --deploy |
Issue and deploy certificate in one step |
ca host list |
List all host certificates with their status |
ca host list --expired |
Show only expired certificates |
ca host list --expiring-in 30 |
Show certificates expiring in next 30 days |
ca host list --json |
Output in JSON format |
ca host info <host-id> |
Display detailed certificate information |
ca host info <host-id> --openssl |
Invoke openssl to display full text dump |
ca host deploy <host-id> |
Run deployment command for a host |
ca host deploy --all |
Deploy all host certificates |
ca host export-key <host-id> |
Export unencrypted private key to stdout |
ca host export-key <host-id> -o file.key |
Export private key to file |
ca host import-key <host-id> --key <path> |
Import existing private key |
ca host sign-csr --csr <path> --out <path> |
Sign external CSR |
ca host clean |
Remove certificates for hosts no longer in config |
Command | Description |
---|---|
ca config validate |
Validate configuration files |
# Initialize configuration
ca init
# Edit configuration
vim config/ca.yaml
# Create the CA
ca ca create
# Edit host configuration
vim config/hosts.yaml
# Issue certificates
ca host issue web-server-example
# Initialize configuration (optional)
ca init
# Import existing CA
ca ca import --cert path/to/ca.crt --key path/to/ca.key
# Edit host configuration
vim config/hosts.yaml
# Issue certificates
ca host issue web-server-example
# Renew a specific certificate
ca host issue web-server-example
# Renew all certificates
ca host issue --all
# Renew and deploy
ca host issue web-server-example --deploy
# Rotate the CA key and certificate
ca ca rekey
# Rotate a specific host key and certificate
ca host issue web-server-example --rekey
# Rotate all host keys and certificates, run all deploy scripts
ca host issue --all --rekey --deploy
All modifications to the store are recorded in store/ca.log
.
If ReactorCA cannot be run, you can manually decrypt private keys using the age
command:
# Decrypt CA private key (SSH-based encryption)
age -d -i ~/.ssh/id_ed25519 store/ca/ca.key.age > ca.key
# Decrypt host private key
age -d -i ~/.ssh/id_ed25519 store/hosts/web-server/cert.key.age > host.key
The store structure is simple: certificates are in PEM format (.crt
files) and private keys are age-encrypted (.key.age
files). Your encryption method determines which identity file to use with age -d -i
.
ca:
# Subject details for the CA certificate
subject:
common_name: Reactor Homelab CA
organization: Reactor Industries
organizational_unit: IT Department
country: DE
state: Berlin
locality: Berlin
email: "[email protected]"
# Certificate validity
validity:
years: 10
# Cryptographic settings
key_algorithm: ECP384 # RSA2048, RSA3072, RSA4096, ECP256, ECP384, ECP521, ED25519
hash_algorithm: SHA384 # SHA256, SHA384, SHA512
# X.509 certificate extensions (optional) - see X.509 Certificate Extensions section for details
extensions:
basic_constraints:
path_length: 0 # There can be only one CA!
name_constraints: # Good idea to tighten security
critical: true
permitted_dns_domains: [".homelab.local", ".internal"]
permitted_ip_ranges: ["192.168.0.0/16", "10.0.0.0/8"]
# Encryption configuration
encryption:
provider: password # password | ssh | plugin
password:
min_length: 12
env_var: REACTOR_CA_PASSWORD
ssh:
identity_file: "~/.ssh/id_ed25519" # SSH private key for decryption
recipients: # SSH public keys for encryption
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@host"
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgExample user@host"
plugin:
identity_file: "~/.age/plugin-identity.txt" # age plugin identity
recipients: # age plugin recipients
- "age1se1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwgjgtev8" # Secure Enclave
- "age1yubikey1qgg72x2qfk9wg3wh0qg9u0v7l5dkq4jx69fv80p6wdus3ftg6flwgjgtev8" # YubiKey
Host certificates inherit CA subject fields (organization, country, etc.) when not specified, except common_name
which must be explicitly set for each host, if desired.
In that case, common_name
must also be listed in alternative_names.dns
. RFC 2818 (2000) deprecates the use of Common Name for host identities.
hosts:
web-server-example:
# Subject Alternative Names
alternative_names:
dns:
- web.reactor.local
- grafana.reactor.local
ip:
- 192.168.1.100
- 10.10.0.1
# Certificate validity
validity:
years: 1
# Cryptographic settings (optional, defaults to CA settings)
key_algorithm: RSA2048
hash_algorithm: SHA256
# X.509 certificate extensions (optional) - see X.509 Certificate Extensions section for all options
# extensions:
# custom_homelab_tag: # Custom extension for environment identification
# critical: false
# oid: "1.3.6.1.4.1.99999.1"
# asn1:
# string: "homelab-production"
# Export paths (optional) - files written during 'host issue'
export:
cert: "/etc/ssl/certs/web-server.pem" # Certificate in PEM format
chain: "/etc/ssl/certs/web-server-chain.pem" # Certificate + CA chain
key_encrypted: "/etc/ssl/private/web-server.key.age" # Encrypted private key (age format)
# Deployment commands (optional) - executed during 'host deploy'
# Deploy can run independently or together with issue (--deploy flag)
# Variables available:
# - ${cert}: Certificate file (from export.cert or temporary file)
# - ${chain}: Certificate chain (from export.chain or temporary file)
# - ${key_encrypted}: Encrypted private key (from export.key_encrypted or temporary file)
# - ${private_key}: Temporary unencrypted private key (secure, auto-cleanup)
deploy:
command: |
echo 'Deploying certificates...'
scp ${cert} ${chain} server:/etc/ssl/
ssh server systemctl reload nginx
For detailed information about certificate extensions (Key Usage, Extended Key Usage, Name Constraints, custom OIDs, etc.), see the X.509 Certificate Extensions section.
ReactorCA supports fine-grained configuration of X.509 certificate extensions for both CA and host certificates. Extensions provide additional constraints, identifiers, and capabilities beyond the basic certificate fields.
ReactorCA provides sensible defaults for basic TLS use cases:
-
CA certificates (
ca ca create
,ca ca renew
,ca ca rekey
):- Basic Constraints (critical,
CA=true
) - Key Usage (critical,
cert_sign
+crl_sign
)
- Basic Constraints (critical,
-
Host certificates (
ca host issue
):- Key Usage (
digital_signature
+key_encipherment
) - Extended Key Usage (
server_auth
+client_auth
) - Subject Alternative Names are populated from
alternative_names
configuration
- Key Usage (
When you specify extensions, ReactorCA applies defaults first, then merges your configuration at the field level.
Homelab CA with Name Constraints (recommended for security):
ca:
extensions:
basic_constraints:
critical: true
ca: true
path_length: 0 # No intermediate CAs allowed
name_constraints:
critical: true
permitted_dns_domains: [".homelab.local", ".internal"]
permitted_ip_ranges: ["192.168.0.0/16", "10.0.0.0/8"]
Web Server Certificate:
hosts:
web-server:
extensions:
key_usage:
critical: false
digital_signature: true
key_encipherment: true
extended_key_usage:
critical: false
server_auth: true
client_auth: true # For mutual TLS
Code Signing Certificate (disable TLS capabilities):
hosts:
code-signer:
extensions:
key_usage:
critical: true
digital_signature: true
content_commitment: true # Non-repudiation for code signing
extended_key_usage:
critical: true
server_auth: false # Disable TLS server auth
client_auth: false # Disable TLS client auth
code_signing: true # Enable code signing only
Email Certificate (S/MIME only, no TLS):
hosts:
email-cert:
extensions:
key_usage:
critical: false
digital_signature: true
content_commitment: true # Non-repudiation for email
key_encipherment: true # For encrypted email
extended_key_usage:
critical: false
server_auth: false # Disable TLS server auth
client_auth: false # Disable TLS client auth
email_protection: true # Enable S/MIME email protection
See RFC 5280 for details.
Controls whether a certificate can act as a CA and limits certification path length.
extensions:
basic_constraints:
critical: true # Must be critical for CA certificates
ca: true # Whether this certificate can sign other certificates
path_length: 2 # Maximum intermediate CAs in the chain (optional, default unset)
Specifies the cryptographic operations for which the public key may be used.
extensions:
key_usage:
critical: true # Recommended for CAs
digital_signature: true # Digital signatures (excluding certificates and CRLs)
content_commitment: true # Non-repudiation (formerly called non_repudiation)
key_encipherment: true # Key transport (RSA encryption)
data_encipherment: true # Data encryption (rarely used)
key_agreement: true # Key agreement (ECDH, DH)
key_cert_sign: true # Certificate signing (required for CAs)
crl_sign: true # CRL signing (recommended for CAs)
encipher_only: true # Restrict key agreement to encryption only
decipher_only: true # Restrict key agreement to decryption only
Defines specific purposes for which the public key may be used, beyond basic cryptographic operations.
extensions:
extended_key_usage:
critical: false # Usually not critical for compatibility
server_auth: true # TLS server authentication (1.3.6.1.5.5.7.3.1)
client_auth: true # TLS client authentication (1.3.6.1.5.5.7.3.2)
code_signing: true # Code signing (1.3.6.1.5.5.7.3.3)
email_protection: true # S/MIME email protection (1.3.6.1.5.5.7.3.4)
time_stamping: true # Time stamping (1.3.6.1.5.5.7.3.8)
ocsp_signing: true # OCSP response signing (1.3.6.1.5.5.7.3.9)
unknown_ext_key_usage: # Custom EKU OIDs
- "1.3.6.1.4.1.311.10.3.4" # Microsoft EFS
- "1.3.6.1.5.5.7.3.21" # SSH client authentication
Provides a means of identifying certificates that contain a particular public key.
extensions:
subject_key_identifier:
critical: false # Never critical per RFC 5280
method: "hash" # "hash" (SHA-1 of public key) or "manual"
manual_value: "hex:01234567..." # Required when method is "manual"
Identifies the public key corresponding to the private key used to sign a certificate.
extensions:
authority_key_identifier:
critical: false # Never critical per RFC 5280
key_id: "hex:FEDCBA98..." # Key identifier (usually matches issuer's SKI)
Powerful security feature: Restricts the namespace within which all subject names in subsequent certificates must be located. Ideal for homelab CAs to prevent certificate misuse.
extensions:
name_constraints:
critical: true # Should be critical for security
permitted_dns_domains:
- ".homelab.local" # Permits subdomains of homelab.local
- ".internal" # Permits *.internal domains
excluded_dns_domains:
- ".example.com" # Explicitly excludes example.com
permitted_ip_ranges:
- "192.168.0.0/16" # Private network ranges
- "10.0.0.0/8"
- "172.16.0.0/12"
excluded_ip_ranges:
- "169.254.0.0/16" # Link-local addresses
permitted_email_addresses:
- "homelab.local" # Domain constraint for email
- "[email protected]" # Specific email address
excluded_email_addresses:
- "[email protected]"
permitted_uri_domains:
- "homelab.local" # Permits URIs with homelab.local domain
excluded_uri_domains:
- "public.example.com" # Excludes URIs with public.example.com domain
Specifies where Certificate Revocation Lists (CRLs) can be retrieved for checking certificate revocation status. Supports multiple distribution points with optional reason codes.
extensions:
crl_distribution_points:
critical: false # Usually not critical for compatibility
distribution_points:
- urls:
- "http://crl.example.com/ca.crl" # HTTP CRL endpoint
- "ldap://ldap.example.com/cn=CA,dc=example,dc=com" # LDAP CRL endpoint
reasons: [key_compromise, ca_compromise] # Optional: specific revocation reasons
- urls:
- "http://backup-crl.example.com/ca.crl" # Backup CRL endpoint
# No reasons specified = all revocation reasons
Supported CRL Reasons:
unspecified
- General revocationkey_compromise
- Private key compromisedca_compromise
- CA key compromisedaffiliation_changed
- Subject's affiliation changedsuperseded
- Certificate replacedcessation_of_operation
- Entity ceased operationcertificate_hold
- Temporary revocationprivilege_withdrawn
- Privileges revokedaa_compromise
- Attribute authority compromised
Define custom extensions using Object Identifiers (OIDs) with flexible encoding options. Start the extension name with custom_
.
ReactorCA supports multiple encoding formats for custom extension values:
Simple Encodings:
base64: "data"
- Base64-encoded binary datahex: "data"
- Hexadecimal-encoded binary data
ASN.1 Types:
asn1: {string: "text"}
- UTF-8 stringasn1: {int: 123}
- Integer valueasn1: {bool: true}
- Boolean valueasn1: {oid: "1.2.3.4"}
- Object identifierasn1: {sequence: [{string: "foo"}, {int: 64}]}
- SEQUENCE of valuesasn1: {octetstring: {string: "wrapped data"}}
- OCTET STRING wrapperasn1: {bitstring: "10110000"}
- BIT STRING from binary stringasn1: {bitstring: [0, 2, 3]}
- BIT STRING from bit positions
extensions:
custom_policy_extension:
oid: "1.3.6.1.4.1.12345.1.2.3" # Your organization's OID space
base64: "SGVsbG8gV29ybGQ=" # Base64-encoded data
custom_device_metadata:
oid: "1.3.6.1.4.1.12345.100"
# Structured device information using SEQUENCE
asn1:
sequence:
- string: "raspberry-pi"
- string: "homelab"
- int: 2024
custom_permissions:
oid: "1.3.6.1.4.1.12345.200"
# Permission flags using BIT STRING (read=bit0, write=bit1, admin=bit3)
asn1:
bitstring: [0, 1, 3]
custom_wrapped_data:
oid: "1.3.6.1.4.1.12345.300"
# OCTET STRING containing UTF8 string
asn1:
octetstring:
string: "Environment=Production"
custom_simple_tag:
oid: "1.3.6.1.4.1.12345.3"
asn1:
string: "homelab-production" # ASN.1 UTF8String
custom_build_number:
oid: "1.3.6.1.4.1.12345.4"
asn1:
int: 42 # ASN.1 INTEGER
custom_enabled_flag:
critical: true
oid: "1.3.6.1.4.1.12345.5"
asn1:
bool: true # ASN.1 BOOLEAN
store/
├── ca/
│ ├── ca.crt # CA certificate (PEM format)
│ └── ca.key.age # age-encrypted CA private key
├── hosts/
│ └── <host-id>/
│ ├── cert.crt # Host certificate (PEM format)
│ └── cert.key.age # age-encrypted host private key
└── ca.log # Operation log
See browser support matrix for real-life test results.
Rule of thumb: use ECP; for cheap Chinese plastic appliances it might be necessary to fall back to RSA2048-SHA256.
Algorithm | Key Size | Performance | Security | Compatibility |
---|---|---|---|---|
RSA2048 | 2048-bit | Medium | Good | Excellent |
RSA3072 | 3072-bit | Slow | Strong | Excellent |
RSA4096 | 4096-bit | Slow | Very Strong | Excellent |
ECP256 | P-256 | Fast | Strong | Good |
ECP384 | P-384 | Medium | Very Strong | Good |
ECP521 | P-521 | Medium | Very Strong | Good |
ED25519 | 256-bit | Very Fast | Strong | Limited |
- SHA256: Good default, excellent compatibility
- SHA384: Stronger, recommended for ECP384 and higher
- SHA512: Strongest, for high-security environments
ReactorCA supports multiple SAN types:
alternative_names:
dns:
- example.com
- "*.example.com"
ip:
- 192.168.1.100
- "2001:db8::1"
email:
- "[email protected]"
uri:
- "https://example.com"
Note that alternative_name
is special, for convenience it is an entity-level parameter for an extension, which usually live under extensions
.
ReactorCA supports multiple encryption providers for private key protection:
Password sources are checked in order:
- Password File: Specified in
ca.yaml
underpassword.file
- Environment Variable: Set via
REACTOR_CA_PASSWORD
(or custom env var) - Interactive Prompt: Secure terminal input (fallback)
Uses existing SSH infrastructure for key protection:
- Identity File: Your SSH private key (e.g.,
~/.ssh/id_ed25519
) - Recipients: SSH public keys that can decrypt the private keys
- Supports: Ed25519, RSA, and ECDSA SSH keys
- No passwords required: Leverages SSH agent or unlocked SSH keys
Uses age plugins for hardware-backed key protection:
- Identity File: Plugin identity file (e.g.,
~/.age/plugin-identity.txt
) - Recipients: Hardware token public keys (e.g., Secure Enclave, YubiKey)
- Supports: Any age-plugin-* binary (secure-enclave, yubikey, tpm, etc.)
- Hardware security: Private keys never leave the secure hardware
Currently, ReactorCA is primarily designed for a very basic setup: A single root CA directly signs all certificates without intermediaries. But you should be fine creating an intermediate CA manually and importing it into ReactorCA, then using it for your everyday operation.
If you are using agenix (or a similar system) for secret distribution, you can share secrets between ReactorCA and agenix, usually by employing the additional_recipients
option. Note that password encryption does NOT mix with age-ssh or plugin modes for security reasons.
This project uses devenv.nix
for reproducible development and Just as build helper:
# Enter development shell
devenv shell
# List commands
just
# Most important
just build && ./ca --version
just docs
just lint
just test
just check
PRs to the develop
branch welcome!
Key/Signature | Firefox 141.0-macOS |
Firefox 140.0-CI |
Chromium 139.0-CI |
Webkit 26.0-CI |
Curl 8.5-CI |
---|---|---|---|---|---|
RSA2048-SHA256 | 🟢 PASS | 🟢 PASS | 🟢 PASS | 🟢 PASS | 🟢 PASS |
RSA2048-SHA512 | 🟢 PASS | 🔴 FAIL | 🟢 PASS | 🔴 FAIL | 🟢 PASS |
RSA3072-SHA256 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
RSA3072-SHA512 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
RSA4096-SHA256 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
RSA4096-SHA512 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP256-SHA256 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP256-SHA512 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP384-SHA256 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP384-SHA512 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP521-SHA256 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ECP521-SHA512 | 🟢 PASS | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ED25519-SHA256 | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
ED25519-SHA512 | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🔴 FAIL | 🟢 PASS |
-
ED25519 not recommended for general public in 2025.
-
Apparently, the browsers used by Microsoft's Playwright container in the Github Action have very limited crypto support.
-
Local tests won't run with Chrome, so far, and won't succeed with Safari on my machine. To run:
just test browser just update-browser-matrix
- No intermediate CA support
- No certificate revocation (CRL/OCSP) support
- No PKCS#12 bundle creation
- No automated renewal daemon (use cron/systemd timers)
- XCA: great, simple GUI-based CA
- certstrap: didn't know about it before starting ;)
- EasyRSA: a classic
- CFSSL: powerful client-server solution (there'a also a wrapper)
- step-ca: fully fledged server with ACME support
- Zytrax Survival Guide: comprehensive guide and explanation
- Tutorial by Jamie Nguyen: demonstrates how to act as your own certificate authority (CA) using the OpenSSL command-line tools