Feature OverviewEN
varwof Feature Overview
Project: pki — All-in-One PKI Infrastructure in Go 1.26 (single binary replacing OpenSSL wrappers + Python services)
Database: SQLite (modernc.org/sqlite, pure Go without CGO) — recommended; PostgreSQL and MySQL/MariaDB available via Dialect dialect but community-maintained (not CI-tested for new features)
Code Size: ~8,300 lines (50+ .go source files, excluding tests and tools)
1. Architecture Overview
┌──────────────────────────────────────────────────────────────┐
│ CLI (24 subcommands) │
│ serve│issue│renew│batch│revoke│crl│sign│export│import│ │
│ init-ca│ca-list│ca-info│ct-submit│key│db│user│token│audit│ │
│ ra│recover│version│init-config│completion│pades │
└──────┬───────────────────────────────────────────────────────┘
│
├── internal/config Config loading/merging/searching
├── internal/ca CA creation, certificate issuance, CRL, revocation, RA approval, key escrow
├── internal/db SQLite ORM (v1-v7 migrations)
├── internal/serve HTTP server + Web UI + JSON API
├── internal/ocsp OCSP responder (RFC 6960)
├── internal/tsa Timestamp server (RFC 3161)
├── internal/pades PAdES PDF signing
├── internal/pkcs7 PKCS#7/CMS SignedData (including CAdES-T with real TSA)
├── internal/signer Detached/embedded file signing + verification
├── internal/pkcs12 PFX export (pure Go)
├── internal/acme ACME v2 (RFC 8555)
├── internal/scep SCEP (RFC 8894)
├── internal/notify Webhook notifications
├── internal/rbac RBAC + JWT authentication
├── internal/serve/ratelimit Token bucket rate limiting
├── internal/ocsp/cache LRU response cache
├── internal/ca/ldap LDAP/AD integration
└── internal/signer/pbes2 Private key encryption (PBKDF2 + AES-256-CBC)
│
┌──────▼──────┐
│ pki-k8s-issuer/ │ cert-manager external issuer (separate repo, k8s.io/client-go)
│ main.go │ watches CertificateRequest CR → POST /api/v1/k8s/sign → patch status
│ Dockerfile │
│ k8s/rbac.* │
└─────────────┘
▼
/var/lib/pki/pki.db (SQLite)
2. CLI Subcommands
2.1 varwof serve — Start Unified PKI Service
Provides TSA, OCSP, Web UI, REST API, ACME, and static file distribution in a single process.
| Flag | Description |
|---|---|
--config |
Configuration file path |
--reload |
Enable config hot-reload (10s polling) |
--install |
(Windows) Install as a system service |
--uninstall |
(Windows) Uninstall system service |
Port Architecture:
:4430(HTTP) — Public certificate distribution, health checks, limited API (no RBAC):4433(HTTPS) — Full functionality: TSA / OCSP / API / Web UI / ACME / SCEP (requirestls_addr,tls_cert,tls_key)
Middleware Layer (HTTPS):
- RBAC role authorization (Bearer/Basic)
- Token bucket rate limiting (
rate_limit.enabled) - Access log (accessLog)
Signal Handling:
- SIGINT/SIGTERM — Graceful shutdown
- SIGHUP — Hot-reload config (atomic.Pointer safe swap)
--reload— Auto-pollcfgFilemtime, callreloadConfigNow()to rebuild handler/CRL loop
2.2 varwof issue — Issue Certificate
Issues a certificate from CSR or auto-generated key pair, automatically stored in the database.
| Flag | Default | Description |
|---|---|---|
--csr |
"" |
CSR PEM file (if provided, skip key generation) |
--cn |
"" |
Common Name |
--san |
"" |
Comma-separated SANs (supports DNS:/IP:/URI:/email:) |
--profile |
config default | Certificate template (technical + management m-* profiles) |
--as |
"" |
Issue as management role (auto-sets OU+profile; values: admin/operator/revoker/auditor/readonly/console/auto-renew/reporter) |
--key-type |
config default | Key algorithm |
--ca |
config default | Issuing CA |
--validity |
365 | Validity period in days |
--out / --out-dir / --out-name / --out-key |
— | Output paths |
--encrypt |
false | Output PBKDF2+AES-256-CBC encrypted private key |
SAN Example: --san "DNS:example.com,DNS:www.example.com,IP:1.2.3.4"
Private Key Encryption: When --encrypt is set, reads config pbes2_passphrase, PBKDF2 (SHA-256, 100k iterations) derives key, AES-256-CBC encrypts PKCS#8 DER, outputs PEM with DEK-Info header.
Key Strength Enforcement (NIST SP 800-57): Before issuance, the requesting public key strength is validated; weak keys are rejected:
- RSA < 2048 bits rejected
- EC curves restricted to NIST P-256 / P-384 / P-521; legacy curves (e.g. P-224) rejected
- Ed25519 always accepted
- Applies to all issuance paths: CLI
issue/batch, CSR signing, API, AIC, sub-CA key import (parsePrivateKey/ParsePrivateKey/DecryptKeyPKCS8)
2.3 varwof batch — Batch Issuance
Batch issue certificates from a CSV file, automatically written to {cn}.pem / {cn}.key.
| Flag | Description |
|---|---|
--csv |
CSV file path (required) |
--ca |
Issuing CA |
--profile |
Certificate template |
--out-dir |
Output directory |
CSV Format:
cn,san
server1,server1.example.com
server2,"DNS:server2.example.com,IP:10.0.0.2"
2.4 varwof renew — Certificate Renewal
Automatically detects original certificate profile, SANs, and key type for renewal.
| Flag | Description |
|---|---|
--serial |
Original certificate serial number |
--ca |
CA of the original certificate |
--validity |
New validity period in days (default same as original) |
2.5 varwof sign — File Signing (PKCS#7 / CAdES-T)
Signs a file to produce a detached signature (.p7s) or embedded signature. Supports --verify and CAdES-T (real TSA timestamp).
| Flag | Description |
|---|---|
--verify |
Verification mode (default: signing mode) |
--embed |
Embed signature at end of file |
--cades |
Add CAdES-T signature timestamp unsigned attribute (requires TSA signer cert/key) |
--sig |
Specify signature file path for verification |
--cert / --key / --chain |
Manually specify signing certificate |
--ca |
Use CA config to auto-load signing certificate |
CAdES-T: With --cades, reads configured TSA signing certificate, computes SHA256 hash of CMS SignedData's signatureValue, builds RFC 3161 TimeStampReq, calls in-process tsa.SignRequest to sign, embeds unsigned attribute id-aa-signatureTimeStampToken (1.2.840.113549.1.9.16.2.14). Automatically skipped when no TSA is configured (outputs DER NULL placeholder).
Embedded Signature Format:
[original content]PKISIG\x00[8 hex char length][PKCS#7 DER]
Verification Support: ECDSA / RSA PKCS#1v1.5 / Ed25519 three signature algorithms, optional root certificate chain verification.
2.6 varwof pades sign — PDF Signing (PAdES-B)
Signs a PDF file to produce an output PDF with PAdES-B signature.
| Flag | Description |
|---|---|
<file.pdf> |
Input PDF path (required argument) |
--out |
Output PDF path (default: <file>-signed.pdf) |
--ca |
Use CA config to auto-load signing certificate |
--cert / --key / --cn |
Manually specify signing certificate, private key, Common Name |
--profile |
Signing certificate profile (must support digitalSignature) |
--config |
Configuration file path |
Implementation: Appends signature field via incremental update, two-step approach: reserve 16KB hex placeholder → compute ByteRange → build CMS detached signature (/SubFilter /adbe.pkcs7.detached) → replace placeholder. No third-party PDF library dependency.
2.7 varwof revoke — Revoke Certificate
| Flag | Description |
|---|---|
--serial |
Hex serial number |
--cert |
Certificate file (auto-extract serial number) |
--reason |
Revocation reason (unspecified / keyCompromise / caCompromise / ...) |
--ca |
CA name |
2.8 varwof crl — Generate CRL
| Flag | Description |
|---|---|
--out |
Output DER path (default: {output_dir}/{ca}.crl) |
--ca |
CA name |
2.9 varwof import — Import from OpenSSL
Compatible with OpenSSL's index.txt format, batch import existing certificates into database.
| Flag | Description |
|---|---|
--index |
index.txt path (default: index.txt) |
--cert-dir |
Certificate PEM directory |
--ca |
Assign CA name |
--ca-cert |
CA certificate (automatically registered in ca_meta) |
2.10 varwof export — PFX/PKCS#12 Export
Implemented in pure Go (software.sslmate.com/src/go-pkcs12), using Modern encoding (AES-256-CBC + SHA-256).
| Flag | Description |
|---|---|
--cert |
Certificate PEM (required) |
--key |
Private key PEM (required) |
--chain |
Chain certificate PEM |
--out |
Output path (required) |
--password |
PFX password (empty password supported) |
--pfx |
Must be set to true |
2.11 varwof init-ca — Initialize CA
Creates a root CA or sub CA, stores in database, outputs PEM files.
| Flag | Default | Description |
|---|---|---|
--name |
— | CA name (required) |
--profile |
root-ca |
root-ca or sub-ca |
--parent |
"" |
Parent CA name |
--key-type |
config default | Key algorithm |
--validity |
3650 (10 years) | Validity period in days |
--out-cert / --out-key |
— | Output PEM paths |
--permitted-dns |
"" |
(Sub CA) Permitted DNS suffixes |
--excluded-dns |
"" |
(Sub CA) Excluded DNS suffixes |
--no-store-key |
false | Do not store private key after issuance (offline root CA) |
2.12 varwof ca-list / varwof ca-info — CA Query
List all CAs or view single CA details (including certificate statistics distribution).
ca-info output fields: Name, Subject, Issuer, Serial, Algorithm, Validity, Fingerprint, Is CA, Max Path, Certificate statistics (total/revoked/expired/expiring ≤30d)
2.13 varwof ct-submit — CT Log Submission
Submits a certificate to a Certificate Transparency log server and obtains an SCT.
| Flag | Description |
|---|---|
--log-url |
CT log server URL |
--cert |
Certificate PEM file |
--chain |
Chain certificate PEM file |
Automatic submission after issuance: configure ct.enabled=true + ct.logs list, auto-calls ctSubmitLogs during issuance.
2.14 varwof key — Private Key Encryption/Decryption
| Subcommand | Description |
|---|---|
varwof key encrypt --in <key.pem> --out <enc-key.pem> |
Encrypt private key |
varwof key decrypt --in <enc-key.pem> --out <key.pem> |
Decrypt private key |
Encryption format: PBKDF2 (SHA-256, 100k iterations, 16B random salt) → AES-256-CBC (random 16B IV) encrypts PKCS#8 DER.
2.15 varwof recover — Key Recovery
Decrypts previously escrowed encrypted private key using admin private key.
| Flag | Description |
|---|---|
--serial |
Certificate serial number |
--ca |
CA name |
--admin-key |
Admin private key PEM path |
2.16 varwof user — User Management (RBAC)
| Subcommand | Description |
|---|---|
varwof user add --username U --role R [--password P] |
Create user |
varwof user list |
List all users |
varwof user update --username U [--role R] [--password P] |
Update user |
varwof user delete --username U |
Delete user |
varwof user bind-operator-cert --username U --cert cert.pem |
Bind an operator certificate (proxies the account's CA scope) |
varwof user unbind-operator-cert --username U |
Unbind the operator certificate |
Roles: admin / operator / revoker / auditor / readonly / console / auto-renew / reporter
Operator-cert proxy: bind a password-login user to a scope-limited
m-*management certificate; the user's effective CA scope then comes from that certificate (cryptographic binding). Binding validates fail-closed; expired/revoked/foreign certificates are rejected immediately.
2.17 varwof token — API Token Management
| Subcommand | Description |
|---|---|
varwof token create --username U |
Create JWT API token |
varwof token list |
List all active tokens |
varwof token revoke --token T |
Revoke token |
Tokens are used for Bearer or Basic authentication in the HTTP API.
2.18 varwof audit — Audit Log
| Subcommand | Description |
|---|---|
varwof audit list |
List audit logs |
varwof audit verify |
Verify Merkle hash chain integrity |
Integrity algorithm: SHA256(prev_hash + "|" + timestamp + "|" + username + "|" + action + "|" + detail)
2.19 varwof ra — RA Approval Workflow
| Subcommand | Description |
|---|---|
varwof ra submit --csr F --cn N [--san ...] [--approvals N] |
Submit approval request |
varwof ra list [--status pending/approved/rejected/issued] |
Request list |
varwof ra approve --id N [--comment "..."] |
Approve (auto-issue when threshold reached) |
varwof ra reject --id N [--reason "..."] |
Reject |
varwof ra show --id N |
Request details |
M/N multi-level approval: after required_approvals people approve, automatically calls ca.Sign to issue certificate.
2.20 varwof db backup — Online Database Backup
varwof db backup --out /backup/pki-2024-01-01.db
Uses SQLite VACUUM INTO to create a transactionally consistent snapshot without service interruption.
2.21 varwof version / varwof init-config / varwof completion
varwof version # Version + build info
varwof init-config # Generate annotated default config file
varwof completion bash # Generate bash completion script
2.21 varwof deploy — Deployment Config Generator
| Flag | Description |
|---|---|
--target |
Deployment target: nginx, apache, or k8s-secret |
--cert |
Certificate PEM file path |
--key |
Private key PEM file path |
--chain |
CA chain PEM file path (optional) |
--out |
Output file path (default: stdout) |
--secret-name |
Kubernetes Secret name (k8s-secret target) |
--namespace |
Kubernetes namespace (k8s-secret, default: "default") |
Examples:
varwof deploy --target nginx --cert server.pem --key server.key
varwof deploy --target k8s-secret --cert server.pem --key server.key \
--secret-name myapp-tls --namespace production --out secret.yaml
2.22 varwof report — Compliance Report Generation
Generate audit-ready compliance report PDFs for SOC 2, PCI DSS, NIST SP 800-53, and ISO 27001 standards.
| Flag | Description |
|---|---|
--template |
Report template: soc2, pci, nist, iso (default: soc2) |
--out |
Output PDF path (default: compliance-<template>-<date>.pdf) |
--ca |
Filter by CA name (optional) |
Examples:
varwof report --template soc2 --out soc2-report.pdf
varwof report --template pci
varwof report --template nist --ca "Root CA"
The report includes:
- Scope — PKI infrastructure overview
- CA Hierarchy — Root vs. subordinate CA counts
- Certificate Inventory — Valid/revoked/expired counts
- Expiry Analysis — Certificates expiring in 30/90 days
- Control Mapping — Standard-specific controls with PASS/FAIL status
- Conclusion — Overall compliance summary
2.23 varwof benchmark — Cryptographic Performance Benchmark
Measure hash and signature algorithm throughput on the current hardware for capacity planning and algorithm selection.
| Flag | Default | Description |
|---|---|---|
--algo |
All | Comma-separated algorithm filter (sha256,sha384,sha512,rsa-2048,rsa-4096,ecdsa-p256,ecdsa-p384,ed25519) |
--size |
0 (all sizes) | Data block size in bytes; 0 runs 1KB / 2KB / 4KB / 8KB / 12KB / 16KB / 20KB / 32KB / 64KB (certificate-sized data) |
--duration |
2s | Duration per round |
--concurrency |
1 | Number of parallel goroutines (multi-core throughput) |
--json |
false | Output JSON format |
Examples:
varwof benchmark # All algorithms, 2s/round
varwof benchmark --algo ed25519,ecdsa-p256 # Ed25519 + ECDSA P-256 only
varwof benchmark --algo sha256 --size 1024 # SHA-256 only, 1KB blocks
varwof benchmark --concurrency 4 # 4-core parallel test
varwof benchmark --duration 5s --json # 5s/round, JSON output
Output format (table):
Algorithm Operation Size Ops/s Latency Throughput
───────── ───────── ──── ───── ─────── ──────────
SHA256 hash 1KB 937.2K 1.0μs 915 MB/s
ED25519 sign 1KB 30.7K 32.0μs —
Supported algorithms:
- Hash: SHA-256, SHA-384, SHA-512 (pure Go, no CGO)
- Sign: RSA-2048, RSA-4096, ECDSA P-256, ECDSA P-384, Ed25519
- Sign measurement includes key generation + sign + verify full pipeline
3. HTTP API Endpoints
3.1 JSON REST API
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/cas |
List all CAs |
| GET | /api/v1/ca/{name} |
Single CA details |
| GET | /api/v1/certs?ca=X&status=V/R&cn=Y |
Query certificates |
| GET | /api/v1/cert/{caName}/{serial} |
Single certificate |
| GET | /api/v1/crl/{caName} |
CRL download (DER) |
| GET | /api/v1/healthz |
Health check |
3.2 TSA Endpoint
| Method | Path | Content-Type | Description |
|---|---|---|---|
| POST | /tsa |
application/timestamp-query |
RFC 3161 timestamp |
| POST | /timestamp |
application/timestamp-query |
Alias |
3.3 OCSP Endpoint
| Method | Path | Content-Type | Description |
|---|---|---|---|
| POST | /ocsp |
application/ocsp-request |
OCSP request |
| GET | /ocsp |
?query=<base64> |
GET method OCSP |
3.4 ACME Endpoint (v2)
| Method | Path | Description |
|---|---|---|
| GET | /acme |
ACME directory |
| POST | /acme/new-nonce |
Get nonce |
| POST | /acme/new-account |
Register account |
| POST | /acme/new-order |
Create order |
| POST | /acme/challenge/{id} |
HTTP-01 challenge |
| GET | .well-known/acme-challenge/{token} |
HTTP-01 validation |
| POST | /acme/cert/{order-id} |
Download certificate |
3.5 SCEP Endpoint
| Method | Path | Description |
|---|---|---|
| GET | /scep?operation=GetCACert |
Get CA certificate |
| GET | /scep?operation=GetNextCACert |
Get next CA certificate (CA rollover) |
| POST | /scep?operation=PKCSReq |
Certificate request |
3.6 Public Port (HTTP Only)
| Path | Description |
|---|---|
/healthz, /readyz |
Health checks |
/pki/* |
Static file distribution |
4. Core Packages
4.1 internal/ca — CA Operations
| Function/File | Description |
|---|---|
CreateCA(cfg) |
Create root CA or sub CA, auto-generate key, store in database |
Sign(cfg) |
Issue certificate using CA, 20B random serial number, up to 10 retries for collision avoidance; supports IssuerAltName/SubjectInfoAccess/CertificatePolicies extensions |
GenerateKey(keyType) |
5 key types (ecdsa-p256/p384, rsa-2048/4096, ed25519, sm2(需 -tags gmsm)) |
GenerateCRL(cfg) |
Build DER CRL from database (including InvalidityDate per-entry extension) |
Revoke(db, caName, serial, reason) |
Revoke certificate |
LoadSigner(certPath, keyPath) |
Load PEM certificate + key |
escrow.go |
Key escrow: AES-256-GCM + RSA-OAEP hybrid encryption |
ra.go |
RA approval: submit/approve/reject/list + signFn callback decoupling |
CertToPEM(der) / KeyToPEM(key) |
DER/PKCS8 → PEM |
4.2 internal/db — SQLite Database Layer
Table: ca_meta
| Column | Description |
|---|---|
name |
Primary key, CA identifier |
cert_der |
DER-encoded CA certificate |
subject / not_before / not_after |
Certificate metadata |
key_algorithm / fingerprint |
Algorithm/fingerprint |
Table: certificates
| Column | Description |
|---|---|
serial_number + ca_name |
Composite primary key |
status |
V=Valid, R=Revoked, E=Expired |
subject / common_name / cert_der |
Subject and certificate |
not_before / not_after / revoked_at |
Timestamps |
fingerprint / revoke_reason / invalidity_date |
Fingerprint/reason/invalidity date |
Table: users (v2) | Table: api_tokens (v3) | Table: audit_log (v4+v7 hash chain) | Table: ra_requests / ra_approvals (v6)
Auto Migration: v1-v9, executed automatically at startup, tracked via user_version.
4.3 internal/pkcs7 — PKCS#7/CMS SignedData
| Function | Description |
|---|---|
BuildSignedData(eContentType, eContent, cert, signer, chain) |
Build signed CMS |
BuildSignedDataWithDigest(..., hash, signatureValue) |
Explicitly specify hash algorithm + detached signature |
SignatureValue(eContentType, eContent, cert, signer, hash) |
Build and return CMS signatureValue DER (computes signatureValue without building complete CMS) |
Supported Signature OIDs:
- ECDSA:
sha256WithECDSA/sha384WithECDSA/sha512WithECDSA - RSA:
sha256WithRSAEncryption/sha384WithRSAEncryption/sha512WithRSAEncryption - Ed25519:
id-EdDSA25519
Hash Auto-Selection:
| Key Type | Hash |
|---|---|
| ECDSA P-256 / RSA 2048 | SHA-256 |
| ECDSA P-384 / RSA 4096+ | SHA-384 |
| ECDSA P-521 | SHA-512 |
| Ed25519 | No pre-hash |
Signed Attributes: content-type OID, messageDigest, signingCertificate (RFC 2634 ESS)
4.4 internal/signer — File Signing
| Function | Description |
|---|---|
SignDetached(filePath, cfg) |
Create <file>.p7s detached signature |
SignEmbedded(filePath, cfg) |
Embed signature at end of file |
SignWithCades(filePath, cfg) |
Add CAdES-T timestamp (real TSA signature or placeholder) |
VerifyDetached(filePath, sigPath, rootCAs) |
Verify detached signature |
VerifyEmbedded(filePath, rootCAs) |
Verify embedded signature |
4.5 internal/pades — PAdES PDF Signing
| Function | Description |
|---|---|
SignPDF(inputPath, outputPath, cfg) |
Append incremental signature field to PDF file, PAdES-B format (/SubFilter /adbe.pkcs7.detached) |
buildByteRange(inputPath) |
Compute PDF ByteRange (file size + placeholder offset) |
buildSignatureDictionary(start, length, contents) |
Build PDF signature object dictionary |
4.6 internal/tsa — RFC 3161 Timestamp
| Function | Description |
|---|---|
ParseTimeStampReq(der) |
ASN.1 parse TimeStampReq |
BuildTimeStampReq(hash, nonce, certReq) |
Build RFC 3161 TimeStampReq DER |
BuildTSTInfo(req, serial) |
Build TSTInfo (configurable accuracy/ordering/policy) |
SignRequest(reqDER, cfg) |
Full flow: parse → TSTInfo → PKCS#7 signing |
4.7 internal/ocsp — OCSP Responder
| Function | Description |
|---|---|
NewHandler(cfg) |
Create OCSP HTTP handler |
(*Handler) ServeHTTP(w, r) |
Supports POST (DER) and GET (base64) |
Status Results: Good / Revoked (with timestamp + reason) / Unknown
4.8 internal/pkcs12 — PFX Export
Uses pure Go PKCS#12 library (Modern encoding: AES-256-CBC + SHA-256), supports empty passwords and password protection.
4.9 internal/acme — ACME v2 (RFC 8555)
| Feature | Description |
|---|---|
| Directory | /acme returns ACME directory |
| Account | new-account registration (JWS with JWK or KID) |
| Order | new-order creation, SAN list validation |
| Challenge | HTTP-01 / DNS-01 validation |
| Authorization | "any challenge valid" per RFC 8555 §7.1.5 |
| Issuance | Full E2E flow → certificate via ca.Sign (tested with lego) |
| Retry-After | Challenge returns Retry-After: 5, authz polls with exponential backoff |
| SQLite WAL mode | _pragma=journal_mode(WAL)&_pragma=busy_timeout(5000) prevents lock contention |
4.10 internal/scep — SCEP (RFC 8894)
| Operation | Description |
|---|---|
| GetCACert | Returns CA certificate wrapped in degenerate PKCS#7 |
| GetNextCACert | Returns next CA certificate (GET/POST), currently same as GetCACert |
| PKCSReq | Parse PKCS#7 wrapped CSR → call ca.Sign to issue → return CertRep |
4.11 internal/notify — Webhook Notifications
| Feature | Description |
|---|---|
| Event Push | POST JSON of issue/revoke/certificate expiry events to configured URL |
| Scheduled Scan | 24h timer scans expired CAs and certificates and pushes notifications |
| Configuration | webhook.url + webhook.events list |
4.12 internal/rbac — RBAC + JWT Authentication
| Feature | Description |
|---|---|
| Users | Local SQLite storage, bcrypt password hashing |
| Roles | admin / operator / revoker / auditor / readonly / console / auto-renew / reporter |
| JWT | golang.org/x/crypto Ed25519 signing, RBAC middleware validation |
| Auth | Bearer Token / Basic Auth both supported |
4.13 internal/serve/ratelimit — Token Bucket Rate Limiting
| Feature | Description |
|---|---|
| Algorithm | golang.org/x/time/rate per-IP token bucket |
| Configuration | rate_limit.enabled / rate (rps) / burst |
| Response | HTTP 429 Too Many Requests when exceeded |
| Cleanup | Background goroutine cleans expired IP records every minute |
4.14 internal/ocsp/cache — OCSP LRU Cache
| Feature | Description |
|---|---|
| Structure | Thread-safe LRU map + TTL expiry |
| Key | SHA256(OCSP request DER) |
| Configuration | ocsp.cache_size / ocsp.cache_ttl |
| Strategy | Fetch from cache before lookup, store in cache after signing |
4.15 internal/ca/ldap — LDAP/AD Integration
| Feature | Description |
|---|---|
| Connection | NewLDAPConn(cfg) dial + bind |
| Query | LookupLDAP(conn, cfg, username) search BaseDN |
| Mapping | map_* config items auto-map to pkix.Name (CN/O/OU/L/ST/C/email) |
| Verification | CheckLDAPGroupMembership(entry, groupDN) memberOf check |
| Integration | issue.go auto-uses LDAP to populate Subject during issuance |
4.16 pki-k8s-issuer — cert-manager External Issuer
| Feature | Description |
|---|---|
| Architecture | Separate binary using k8s.io/client-go dynamic informer |
| Protocol | Watches certificaterequests.cert-manager.io/v1 CR, posts CSR to POST /api/v1/k8s/sign, patches status with certificate |
| Server | internal/serve/api_k8s.go — parses PCA/PEM CSR, calls ca.Sign() |
| Authentication | PKI API token via PKI_TOKEN env or --pki-token flag |
| RBAC | ClusterRole: certificaterequests get/list/watch/patch + certificaterequests/status patch |
| ClusterIssuer | Declarative kind: ClusterIssuer as cert-manager API gateway |
| Deployment | pki-k8s-issuer/k8s/deployment.yaml — single-replica Deployment in cert-manager namespace |
5. Certificate Templates (Profiles)
Technical Templates
| Template | KeyUsage | ExtKeyUsage | Special Extensions |
|---|---|---|---|
root-ca |
certSign, crlSign | — | CA:true, pathLen:1 |
sub-ca |
certSign, crlSign | — | CA:true, pathLen:0, CRL DP, Name Constraints (DNS/Email/URI/IP) |
tls-server |
digitalSignature, keyEncipherment | serverAuth, clientAuth | CRL DP, AIA (OCSP+caIssuers) |
tls-client |
digitalSignature | clientAuth | CRL DP, AIA (OCSP+caIssuers) |
ocsp-signer |
digitalSignature | OCSPSigning | CRL DP, AIA (OCSP+caIssuers) |
timestamp |
digitalSignature | — | CRL DP, AIA (OCSP+caIssuers), EKU timeStamping critical via ExtraExtensions |
codesigning |
digitalSignature | CodeSigning | CRL DP, AIA (OCSP+caIssuers) |
email |
digitalSignature, keyEncipherment | EmailProtection | CRL DP, AIA (OCSP+caIssuers) |
document |
digitalSignature, contentCommitment | — | CRL DP, AIA (OCSP+caIssuers) |
agent-proxy |
digitalSignature | clientAuth | CRL DP, AIA, validity ≤ 1h, AIC extension, requires at least one OU |
identity-user |
digitalSignature, keyEncipherment | emailProtection, clientAuth | CRL DP, AIA — person base identity certificate issued from an identity source (Phase 2); CN/OU/email auto-filled from bridge-ldap/bridge-oauth, optional PA extension |
All EE profiles include BasicConstraints CA:FALSE.
All EE profiles support optional extensions: IssuerAltName (2.5.29.18), SubjectInfoAccess (1.3.6.1.5.5.7.1.11), CertificatePolicies (2.5.29.32), configured via defaults.issuer_alt_names/subject_info_access/policy_oids.
Management Certificate Templates (m-*)
Built-in PKI management role presets that auto-set OU=<role> + ClientAuth EKU + DigitalSignature KU. Use the --as shortcut — no need to manually pass subject.
| Template | OU | Role | Recommended Use |
|---|---|---|---|
m-admin |
admin | admin | Super admin mTLS cert |
m-operator |
operator | operator | Operations mTLS cert |
m-revoker |
revoker | revoker | Revocation-only mTLS cert |
m-auditor |
auditor | auditor | Audit mTLS cert |
m-readonly |
readonly | readonly | Monitoring/viewer mTLS cert |
m-console |
console | console | Web Console backend service cert |
m-auto-renew |
auto-renew | auto-renew | Automated renewal bot mTLS cert |
m-reporter |
reporter | reporter | Report generation mTLS cert |
m-subadmin |
sub-admin | — | Sub-CA admin (CA=true, CertSign, --scope writes OID extension) |
Example:
varwof issue --ca "Issuing CA" --as admin --cn "Alice Admin" --out alice.pem
varwof issue --ca "Issuing CA" --as auto-renew --cn "k8s-renewer" --out renew-bot.pem
varwof issue --ca "Issuing CA" --profile m-subadmin --scope "Agent CA" --cn "Agent CA Admin" --out agent-admin.pem
6. Key Type Support Matrix
| Operation | ecdsa-p256 | ecdsa-p384 | rsa-2048 | rsa-4096 | ed25519 |
|---|---|---|---|---|---|
| Key Generation | ✓ | ✓ | ✓ | ✓ | ✓ |
| Certificate Issuance | ✓ | ✓ | ✓ | ✓ | ✓ |
| PKCS#7 Signing | ✓ | ✓ | ✓ | ✓ | ✓ |
| PKCS#7 Verification | ✓ | ✓ | ✓ | ✓ | ✓ |
| OCSP Signing | ✓ | ✓ | ✓ | ✓ | ✓ |
| TSA Signing | ✓ | ✓ | ✓ | ✓ | ✓ |
| PFX Export | ✓ | ✓ | ✓ | ✓ | ✓ |
| Hash | SHA-256 | SHA-384 | SHA-256/384 | SHA-384 | No pre-hash |
7. Configuration Guide
7.1 Configuration Search Order
./pki.json(current directory)~/.config/pki/pki.json/etc/varwof/core/pki.json(Linux) or%PROGRAMDATA%\varwof\core\pki.json(Windows)
Can be overridden with --config <path>.
7.2 Complete Configuration Structure
{
"db": "/var/lib/pki/pki.db",
"cas": {
"root": { "cert": "...", "key": "..." },
"issuing": { "cert": "...", "key": "...", "chain": "..." },
"tsa": { "cert": "...", "key": "..." },
"codesign":{ "cert": "...", "key": "..." }
},
"tsa": {
"signer_cert": "...",
"signer_key": "...",
"chain": "...",
"tsa_policy": "2.16.840.1.113733.1.9.2",
"ordering": false,
"accuracy_seconds": 1,
"accuracy_millis": 0,
"accuracy_micros": 0
},
"ocsp": {
"signer_cert": "...",
"signer_key": "..."
},
"serve": {
"addr": ":4430",
"tls_addr": ":4433",
"tls_cert": "...",
"tls_key": "..."
},
"defaults": {
"ca": "issuing",
"profile": "tls-server",
"key_type": "ecdsa-p256",
"hash": "sha256",
"ocsp_url": "http://pki.example.com/ocsp",
"issuer_url": "http://pki.example.com/ca.pem",
"issuer_alt_names": [],
"subject_info_access": [],
"policy_oids": []
},
"crl": {
"validity_days": 30,
"output_dir": "/etc/varwof/core/crls",
"crl_base_url": "http://pki.example.com/api/v1/crl",
"auto_renew": true
},
"webhook": {
"url": "https://hooks.example.com/pki",
"events": ["issue", "revoke", "expiry"]
},
"ct": {
"enabled": true,
"logs": [{"url": "https://ct.example.com/2025", "key": "base64key..."}]
},
"rbac": {
"enabled": true,
"jwt_secret": "CHANGE_ME"
},
"ra": {
"required_approvals": 2,
"default_ca": "issuing",
"default_profile": "tls-server"
},
"pbes2_passphrase": "CHANGE_ME",
"key_escrow": {
"admin_public_key": "/etc/varwof/core/escrow/admin.pub.pem"
}
}
7.3 Merge Rules
DefaultConfig() → SearchConfigPath() → CLI --config → subcommand --config, deep-merged each time with MergeConfig(base, override), non-empty fields override.
8. Cross-Platform Support
Windows
- Service management:
varwof serve --install/--uninstall serve_windows.gousesgolang.org/x/sys/windows/svc- Service name:
pki, auto-start, uses%PROGRAMDATA%paths
Unix
serve_unix.gousessignal.Notifyto listen for SIGINT/SIGTERM/SIGHUPatomic.Pointersafe swap for config/DB/TSA/OCSP handler
9. DB Migration History
| Version | Additions |
|---|---|
| v1 | Initial schema: ca_meta, certificates |
| v2 | users table + serial_counter |
| v3 | api_tokens table |
| v4 | audit_log table |
| v5 | Added escrow_data column to certificates |
| v6 | ra_requests, ra_approvals tables |
| v7 | Added entry_hash, prev_hash columns to audit_log |
| v9 | Added invalidity_date column to certificates (RFC 5280 InvalidityDate CRL extension) |
10. E2E Validation Status
| Validation Item | Method | Status |
|---|---|---|
| init-ca root | openssl verify |
✓ |
| init-ca sub-ca | openssl verify -CAfile root.pem sub.pem |
✓ |
| TSA reply | openssl ts -reply / -verify |
✓ |
| OCSP good | openssl ocsp -issuer ... -cert ... |
✓ |
| OCSP revoked | Query status after revocation | ✓ |
| CRL | HTTP API returns valid DER | ✓ |
| Issue + chain | openssl verify -CAfile ... -untrusted ... |
✓ |
| CodeSign PKCS#7 | Go VerifyDetached / VerifyEmbedded | ✓ |
| CodeSign openssl | openssl cms -verify |
✓ |
| CAdES-T (real TSA) | CMS with id-aa-signatureTimeStampToken unsigned attribute |
✓ |
| PAdES-B PDF signing | Adobe Reader / Go verify PDF signature field | ✓ |
| PFX export | pkcs12.DecodeChain pure Go |
✓ |
| SCEP | Go test (GetCACert + GetNextCACert + PKCSReq) | ✓ |
| RBAC | Bearer/Basic auth + role authorization | ✓ |
| LDAP integration | Auto-populate Subject during issuance | ✓ |
| Rate limiting | 429 Too Many Requests | ✓ |
| OCSP cache | Cache hit/expiry | ✓ |
| RA approval | Submit → M/N approval → auto-issue | ✓ |
| Audit integrity | varwof audit verify full chain validation |
✓ |
| Private key encryption | varwof key encrypt/decrypt round-trip |
✓ |
| DB backup | VACUUM INTO consistent snapshot | ✓ |
| Config hot-reload | varwof serve --reload mtime detection |
✓ |
| Windows cross-compile | GOOS=windows build |
✓ |
| RFC 5280 serial 20B | openssl x509 -serial length 40 hex chars |
✓ |
| AIA caIssuers | openssl x509 -text -certopt ext check AIA |
✓ |
| Name Constraints all forms | openssl x509 -text DNS/Email/URI/IP |
✓ |
| CRL InvalidityDate | openssl crl -text per-entry extension |
✓ |
| IssuerAltName | openssl x509 -text Issuer Alt Name |
✓ |
| SubjectInfoAccess | openssl x509 -text Subject Info Access |
✓ |
| CertificatePolicies | openssl x509 -text Policies |
✓ |
11. Test Coverage (~550+ test cases, 35 test files, 72.6% coverage)
| Package | Tests | Coverage Content |
|---|---|---|
| root CLI | 16 | sign/export/init-ca/revoke/issue/crl + error paths |
internal/ca |
16 | Create root/sub CA, issuance, CRL, revocation, 5 key types |
internal/db |
15 | cert CRUD, ca_meta CRUD |
internal/serve |
16 | Route dispatch, JSON API, MIME dispatch, WebUI |
internal/pkcs7 |
14 | BuildSignedData, WithChain, CAdES-T, various OIDs |
internal/signer |
10 | sign/verify detached/embedded/chain/tamper |
internal/tsa |
8 | Parse, TSTInfo, Policy QIs |
internal/ocsp |
4 | Cache, Good, Unknown, BadRequest |
internal/pkcs12 |
5 | Basic/password/chain |
internal/config |
6 | Default config, loading, merging |
internal/scep |
3 | GetCACert, GetNextCACert, PKCSReq |
internal/ca (ldap) |
1 | nil cfg safe path |
internal/pades |
4 | BuildByteRange, BuildSignatureDictionary, SignPDF (including error paths) |
All pass go vet ./... and go test -count=1 ./...
16. Internationalization (i18n)
The system supports English and Chinese, negotiated via the HTTP Accept-Language header.
Language detection priority:
- Config file
localefield (e.g."locale": "zh") - HTTP
Accept-Languageheader - Default
en
Coverage:
| Area | Languages | Notes |
|---|---|---|
| CLI output | EN/ZH | Error messages, prompts |
| Web UI | EN/ZH | Login, navigation, dashboard, issue form, admin panel |
| API errors | EN | Currently English only |
Translation files: internal/i18n/locales/{en,zh}.json, JSON key-value format.