245 lines
7.1 KiB
Markdown
245 lines
7.1 KiB
Markdown
# 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)
|
|
|
|
```bash
|
|
# 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
|
|
```
|
|
|
|
### Cookie Auth (Web UI / curl)
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
curl -k https://certauth.ms/api/health
|
|
# → {"status":"ok"}
|
|
```
|
|
|
|
### CA Chain Download
|
|
|
|
```bash
|
|
curl -k https://certauth.ms/api/ca-chain -o ca-chain.crt
|
|
```
|
|
|
|
Returns the Intermediate + Root CA chain in PEM format.
|
|
|
|
---
|
|
|
|
### Domains
|
|
|
|
**List domains:**
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" https://certauth.ms/api/domains
|
|
```
|
|
|
|
**Register domain (API):**
|
|
```bash
|
|
curl -X POST https://certauth.ms/api/domains \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-d "name=example.com&description=My+website"
|
|
```
|
|
|
|
**Register domain (web/cookie auth):**
|
|
```bash
|
|
curl -b cookies.txt -X POST https://certauth.ms/api/domains/web \
|
|
-d "name=example.com&description=My+website"
|
|
```
|
|
|
|
---
|
|
|
|
### Certificates
|
|
|
|
**List certificates:**
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" https://certauth.ms/api/certs
|
|
```
|
|
|
|
**Request certificate (API):**
|
|
```bash
|
|
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):**
|
|
```bash
|
|
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:**
|
|
```bash
|
|
curl -X POST https://certauth.ms/api/certs/{cert_id}/sign \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
**Sign/Issue certificate (web/cookie auth):**
|
|
```bash
|
|
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):**
|
|
```bash
|
|
curl -b cookies.txt https://certauth.ms/api/certs/{cert_id}/pem -o cert.pem
|
|
```
|
|
|
|
**Download PFX (cert + key + chain, password: `certauth`):**
|
|
```bash
|
|
curl -b cookies.txt https://certauth.ms/api/certs/{cert_id}/pfx -o cert.pfx
|
|
```
|
|
|
|
---
|
|
|
|
### History
|
|
|
|
**View certificate history:**
|
|
```bash
|
|
curl -b cookies.txt https://certauth.ms/history
|
|
```
|
|
|
|
---
|
|
|
|
### Setup Scripts
|
|
|
|
**Bash installer (Linux/macOS):**
|
|
```bash
|
|
curl -sL https://certauth.ms/setup.sh | sudo bash -s 192.168.8.248
|
|
```
|
|
|
|
**PowerShell installer (Windows):**
|
|
```powershell
|
|
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:
|
|
|
|
```bash
|
|
# 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.ms` → `192.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. |