Skip to content

serpent213/reactor-ca

Repository files navigation

asciicast

Go CI Coverage License: BSD-2-Clause Go Reference

ReactorCA

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.

Table of Contents

Features

  • 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.

Screenshots

host list screenshot

host info ambassador-zyx-alpha screenshot

↑ TOC

Motivation and Design Targets

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

↑ TOC

Cryptographic Implementation

ReactorCA is built on proven cryptographic foundations:

Core Libraries

  • Go Standard Crypto: Uses crypto/x509 for certificate operations, crypto/rsa and crypto/ecdsa for key generation, and crypto/rand for secure randomness
  • age Encryption: Modern file encryption using Filippo Valsorda's age library for private key protection

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:

↑ TOC

Installation

Pre-built Binaries

Download the latest release for your platform from the releases page.

Build from Source

git clone https://github.com/serpent213/reactor-ca.git
cd reactor-ca
go build -o ca ./cmd/ca

↑ TOC

Quick Start

1. Initialize Configuration

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.

2. Create CA Certificate

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.

3. Issue Host Certificate

To issue a certificate for a host defined in your hosts.yaml:

ca host issue web-server-example

4. List Certificates

To list all certificates with their expiration dates:

ca host list

5. Export and Deploy Certificates

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.

↑ TOC

CLI Reference

Global Flags

  • --root <path> - Root directory for config and store (env: REACTOR_CA_ROOT)

CA Management

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

Host Certificate Management

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

Configuration Management

Command Description
ca config validate Validate configuration files

↑ TOC

Common Workflows

New CA Workflow

# 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

Import Existing CA

# 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

Certificate Renewal

# 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

Key Rotation

# 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.

↑ TOC

Emergency Access

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.

↑ TOC

Configuration

CA Configuration (config/ca.yaml)

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

Hosts Configuration (config/hosts.yaml)

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.

↑ TOC

X.509 Certificate Extensions

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.

Certificate Defaults

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)
  • 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

When you specify extensions, ReactorCA applies defaults first, then merges your configuration at the field level.

Extension Examples by Use Case

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

Available Extensions

See RFC 5280 for details.

Basic Constraints

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)

Key Usage

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

Extended Key Usage

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

Subject Key Identifier

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"

Authority Key Identifier

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)

Name Constraints

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

CRL Distribution Points

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 revocation
  • key_compromise - Private key compromised
  • ca_compromise - CA key compromised
  • affiliation_changed - Subject's affiliation changed
  • superseded - Certificate replaced
  • cessation_of_operation - Entity ceased operation
  • certificate_hold - Temporary revocation
  • privilege_withdrawn - Privileges revoked
  • aa_compromise - Attribute authority compromised

Custom Extensions (Unknown OIDs)

Define custom extensions using Object Identifiers (OIDs) with flexible encoding options. Start the extension name with custom_.

Value Encoding Notation

ReactorCA supports multiple encoding formats for custom extension values:

Simple Encodings:

  • base64: "data" - Base64-encoded binary data
  • hex: "data" - Hexadecimal-encoded binary data

ASN.1 Types:

  • asn1: {string: "text"} - UTF-8 string
  • asn1: {int: 123} - Integer value
  • asn1: {bool: true} - Boolean value
  • asn1: {oid: "1.2.3.4"} - Object identifier
  • asn1: {sequence: [{string: "foo"}, {int: 64}]} - SEQUENCE of values
  • asn1: {octetstring: {string: "wrapped data"}} - OCTET STRING wrapper
  • asn1: {bitstring: "10110000"} - BIT STRING from binary string
  • asn1: {bitstring: [0, 2, 3]} - BIT STRING from bit positions
Examples
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

↑ TOC

Store Structure

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

↑ TOC

Cryptographic Options

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.

Supported Key Algorithms

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

Supported Hash Algorithms

  • SHA256: Good default, excellent compatibility
  • SHA384: Stronger, recommended for ECP384 and higher
  • SHA512: Strongest, for high-security environments

Subject Alternative Name Types

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.

↑ TOC

Key Protection and Authentication

ReactorCA supports multiple encryption providers for private key protection:

Password-based Encryption (default)

Password sources are checked in order:

  1. Password File: Specified in ca.yaml under password.file
  2. Environment Variable: Set via REACTOR_CA_PASSWORD (or custom env var)
  3. Interactive Prompt: Secure terminal input (fallback)

SSH Key-based Encryption (age-ssh)

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

Hardware Token Encryption (age plugins)

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

↑ TOC

Intermediate CAs

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.

↑ TOC

agenix integration

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.

↑ TOC

Development

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!

↑ TOC

Browser Compatibility Matrix

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

↑ TOC

Limitations

  • No intermediate CA support
  • No certificate revocation (CRL/OCSP) support
  • No PKCS#12 bundle creation
  • No automated renewal daemon (use cron/systemd timers)

↑ TOC

Alternative Solutions

  • 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

↑ TOC

Further Reading: Introduction to PKI and X.509

↑ TOC

About

Homelab/SOHO Certificate Authority with age encryption and deployment

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Sponsor this project

 

Languages