certauth/SKILL.md

7.1 KiB

CertAuth Key Vault - API & Web UI Guide

Overview

CertAuth is a self-contained Certificate Authority running on 192.168.8.248 (accessible as certauth.ms on the local network). It uses two YubiKey 5 Nano devices as hardware security modules — one for the Root CA and one for the Intermediate CA — requiring physical touch + PIN to sign certificates.

Authentication

Two auth methods are supported:

JWT Token (API)

# Login
curl -X POST https://certauth.ms/api/token \
  -H "Content-Type: application/json" \
  -d '{"username":"certauth","password":"CHANGE_ME_ADMIN_PASS"}'

# Response: {"access_token": "eyJ...", "token_type": "bearer"}

# Use token in subsequent requests
curl -H "Authorization: Bearer $TOKEN" https://certauth.ms/api/domains
# Login via web endpoint (sets cookie)
curl -c cookies.txt -L https://certauth.ms/login \
  -d "username=certauth&password=CHANGE_ME_ADMIN_PASS"

# Use cookie in subsequent requests
curl -b cookies.txt https://certauth.ms/api/domains/web

Or use -b "token=$TOKEN" with the token value for cookie-auth endpoints.

Admin Credentials

  • Username: certauth
  • Password: CHANGE_ME_ADMIN_PASS
  • PFX download password: certauth

API Endpoints

All endpoints require authentication. The server is at https://certauth.ms.

Health Check

curl -k https://certauth.ms/api/health
# → {"status":"ok"}

CA Chain Download

curl -k https://certauth.ms/api/ca-chain -o ca-chain.crt

Returns the Intermediate + Root CA chain in PEM format.


Domains

List domains:

curl -H "Authorization: Bearer $TOKEN" https://certauth.ms/api/domains

Register domain (API):

curl -X POST https://certauth.ms/api/domains \
  -H "Authorization: Bearer $TOKEN" \
  -d "name=example.com&description=My+website"

Register domain (web/cookie auth):

curl -b cookies.txt -X POST https://certauth.ms/api/domains/web \
  -d "name=example.com&description=My+website"

Certificates

List certificates:

curl -H "Authorization: Bearer $TOKEN" https://certauth.ms/api/certs

Request certificate (API):

curl -X POST https://certauth.ms/api/certs/request \
  -H "Authorization: Bearer $TOKEN" \
  -d "cn=example.com&sans=example.com%2Cwww.example.com&days=365&domain_id=1"

Request certificate (web/cookie auth):

curl -b cookies.txt -X POST https://certauth.ms/api/certs/web/request \
  -d "cn=example.com&sans=example.com%2Cwww.example.com&days=365&domain_id=0"

Parameters:

  • cn — Common Name (required)
  • sans — Comma-separated Subject Alternative Names (URL-encoded)
  • days — Validity in days (default: 365)
  • domain_id — Domain ID to link to (0 = auto-match by CN)

Sign/Issue certificate:

curl -X POST https://certauth.ms/api/certs/{cert_id}/sign \
  -H "Authorization: Bearer $TOKEN"

Sign/Issue certificate (web/cookie auth):

curl -b cookies.txt -X POST https://certauth.ms/api/certs/{cert_id}/sign/web

⚠️ Signing requires physical YubiKey touch + PIN — this will block until the operator touches YubiKey 2 and enters the PIN.

Download PEM (cert + chain):

curl -b cookies.txt https://certauth.ms/api/certs/{cert_id}/pem -o cert.pem

Download PFX (cert + key + chain, password: certauth):

curl -b cookies.txt https://certauth.ms/api/certs/{cert_id}/pfx -o cert.pfx

History

View certificate history:

curl -b cookies.txt https://certauth.ms/history

Setup Scripts

Bash installer (Linux/macOS):

curl -sL https://certauth.ms/setup.sh | sudo bash -s 192.168.8.248

PowerShell installer (Windows):

iwr https://certauth.ms/setup.ps1 -UseBasicParsing | iex

Complete Workflow Example

Here's a full end-to-end example to register a domain, request a cert, issue it, and download:

# 1. Login and get token
TOKEN=$(curl -s -X POST https://certauth.ms/api/token \
  -H "Content-Type: application/json" \
  -d '{"username":"certauth","password":"CHANGE_ME_ADMIN_PASS"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# 2. Register domain
curl -s -X POST https://certauth.ms/api/domains \
  -H "Authorization: Bearer $TOKEN" \
  -d "name=myapp.local&description=Internal+app"

# 3. Request certificate
CERT_ID=$(curl -s -X POST https://certauth.ms/api/certs/request \
  -H "Authorization: Bearer $TOKEN" \
  -d "cn=myapp.local&sans=myapp.local%2Cwww.myapp.local&days=365&domain_id=0" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")

echo "Certificate ID: $CERT_ID"

# 4. Issue certificate (requires YubiKey touch!)
curl -s -X POST https://certauth.ms/api/certs/$CERT_ID/sign \
  -H "Authorization: Bearer $TOKEN"

# 5. Download PEM (cert + intermediate + root)
curl -s -H "Authorization: Bearer $TOKEN" \
  https://certauth.ms/api/certs/$CERT_ID/pem -o myapp.pem

# 6. Download PFX (cert + key + chain, password: certauth)
curl -s -H "Authorization: Bearer $TOKEN" \
  https://certauth.ms/api/certs/$CERT_ID/pfx -o myapp.pfx

# 7. Verify
openssl verify -CAfile ca-chain.crt myapp.pem

Certificate Details

  • Key type: EC P-384 (SECP384R1)
  • Signature algorithm: ECDSA-SHA384
  • CA chain: Intermediate CA (YubiKey 2) → Root CA (YubiKey 1)
  • Extensions: Server Auth + Client Auth EKU, proper AKI/SKI
  • Validity: 365 days per leaf cert (configurable)
  • PFX password: certauth

Installing CA Chain on Clients

The setup.sh endpoint serves a self-installing bash script that:

  1. Auto-detects the server IP (or prompts)
  2. Downloads the CA chain
  3. Installs it to the OS trust store
  4. Supports: Debian/Ubuntu, RHEL/CentOS/Fedora, Arch, Alpine, macOS

For macOS specifically, the CA is installed to the System Keychain with security add-trusted-cert.

For LibreWolf (which disables enterprise roots by default):

  • Set security.enterprise_roots.enabled = true in about:config
  • OR import the root CA via certutil into LibreWolf's NSS database

Key Files on Server

Path Description
/etc/ssl/ca/root/root-ca.crt Root CA certificate
/etc/ssl/ca/intermediate/intermediate-ca.crt Intermediate CA certificate
/etc/ssl/ca/ca-chain.crt Full chain (intermediate + root)
/etc/ssl/ca/issued/ Issued leaf certificates and keys
/etc/ssl/certauth/tls.pem Server cert + chain (for Caddy)
/etc/ssl/certauth/tls.key Server private key
/opt/certauth/api/ API application files
/var/lib/certauth/certauth.db SQLite database

DNS

  • certauth.ms192.168.8.248 (served by dnsmasq on the server)
  • Also added to router DNS for network-wide resolution

Troubleshooting

  • SSL_ERROR_BAD_CERT_DOMAIN: Make sure you're using https://certauth.ms not the IP. Firefox/NSS has quirks with IP Address SANs.
  • SEC_ERROR_UNKNOWN_ISSUER: The CA chain isn't trusted. Install via setup.sh or import manually.
  • Signing fails: YubiKey 2 must be touched and PIN entered when signing.
  • DNS not resolving: Check that certauth.ms is in your router's DNS or AdGuard Home config.