mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 17:51:29 +00:00
72cda5877a
CLI syntax corrected across 5 files (concepts, demo-guide, demo-advanced, architecture, features): list-certs→certs list, get-cert→certs get, etc. Removed non-existent health/metrics commands, replaced with status. Subcommand count 10→12 everywhere. architecture.md: Go 1.22→1.25, endpoint count 91→93, ER diagram expanded from 15 to 21 tables (added renewal_policies, certificate_revocations, discovered_certificates, discovery_scans, network_scan_targets). connectors.md: added GenerateCRL and SignOCSPResponse to issuer interface, added Email and Webhook rows to notifier config table. compliance docs: fixed keygen warning messages to match actual log output, CERTCTL_STEPCA_PROVISIONER_KEY→CERTCTL_STEPCA_KEY_PATH, openssl genrsa→ crypto/ecdsa.GenerateKey, CERTCTL_SERVER_ADDR→CERTCTL_SERVER_HOST+PORT. README.md: v2.0.0 version bump, solo developer mention, feature list, table of contents, documentation table moved to top, 7 fact-check fixes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
318 lines
17 KiB
Markdown
318 lines
17 KiB
Markdown
# NIST SP 800-57 Key Management Alignment
|
||
|
||
NIST SP 800-57 Part 1 Rev 5 (May 2020) is the authoritative US government guidance on cryptographic key management. This document maps certctl's implementation to its recommendations. certctl follows NIST guidance where applicable; this guide documents the alignment and identifies gaps for future roadmap planning.
|
||
|
||
## Key Generation (Section 6.1)
|
||
|
||
certctl generates certificate keys on agent infrastructure using Go's `crypto/rand` for entropy, backed by `/dev/urandom` on Linux and `CryptGenRandom` on Windows. Key generation happens as follows:
|
||
|
||
**Agent-Side Key Generation (Production Default)**
|
||
- Agents generate ECDSA P-256 key pairs per certificate using `crypto/ecdsa` + `crypto/elliptic` (Go stdlib)
|
||
- Key generation triggered by `AwaitingCSR` job state in renewal/issuance workflows
|
||
- Agent creates Certificate Signing Request (CSR) with `x509.CreateCertificateRequest`, signed with the agent's private key
|
||
- Only the CSR crosses the network to the control plane; private key material never leaves the agent
|
||
- Configuration: `CERTCTL_KEYGEN_MODE=agent` (default, production)
|
||
|
||
**Server-Side Key Generation (Demo Only)**
|
||
- Available for development and testing via `CERTCTL_KEYGEN_MODE=server`
|
||
- Explicitly logged as a warning at startup: "server-side key generation enabled (CERTCTL_KEYGEN_MODE=server) — private keys touch control plane, demo only"
|
||
- Docker Compose demo uses server mode for backward compatibility
|
||
- Not recommended for production; agent mode is the secure default
|
||
|
||
**Entropy Source**
|
||
- `crypto/rand` provides cryptographically secure random bytes
|
||
- On Linux: backed by `/dev/urandom` via `getrandom()` syscall
|
||
- On Windows: backed by `CryptGenRandom()` (now `BCryptGenRandom()`)
|
||
- Meets NIST SP 800-90B requirements for entropy generation
|
||
|
||
## Key Storage and Protection (Sections 6.3, 6.4)
|
||
|
||
certctl implements tiered key storage with different protection profiles based on key purpose.
|
||
|
||
**Agent Private Keys**
|
||
- Stored on agent filesystem at `CERTCTL_KEY_DIR` (default: `/var/lib/certctl/keys`)
|
||
- File permissions: 0600 (read/write by agent process only, no world/group access)
|
||
- One PEM file per certificate, organized by certificate ID
|
||
- Accessible only to the agent process; isolated from other processes
|
||
- For container deployments: use Docker volumes with restricted permissions (`-v /var/lib/certctl/keys:0600`)
|
||
|
||
**Issuing CA Keys (Local CA Connector)**
|
||
- Loaded from disk at server startup via `CERTCTL_CA_CERT_PATH` and `CERTCTL_CA_KEY_PATH` env vars
|
||
- Supports RSA (PKCS#1, PKCS#8) and ECDSA (SEC1, PKCS#8) key formats
|
||
- Validates certificate constraints before use:
|
||
- `IsCA=true` flag present
|
||
- `KeyUsageCertSign` extension set
|
||
- Valid certificate chain (for sub-CA mode)
|
||
- Keys held in memory during server runtime (no on-disk caching after load)
|
||
- Cleared from memory only on server shutdown
|
||
|
||
**Sub-CA Mode (Enterprise Integration)**
|
||
- CA certificate and key signed by upstream enterprise root (e.g., Active Directory Certificate Services)
|
||
- Certctl acts as subordinate CA, inheriting issuer DN from upstream CA
|
||
- All issued certificates chain to enterprise trust anchor
|
||
- CA key protection inherits upstream root's key management practices
|
||
- Configured via: `CERTCTL_CA_CERT_PATH=/path/to/ca.crt` and `CERTCTL_CA_KEY_PATH=/path/to/ca.key`
|
||
|
||
**NIST Gap: HSM Storage**
|
||
NIST SP 800-57 Part 1 recommends Hardware Security Module (HSM) storage for high-value keys (CA signing keys). certctl V2 uses filesystem storage on the server. HSM support is planned for V5 roadmap, enabling integration with:
|
||
- AWS CloudHSM
|
||
- Azure Dedicated HSM
|
||
- Thales Luna, Gemalto SafeNet, YubiHSM (on-premises)
|
||
- PKCS#11-compatible devices
|
||
|
||
## Cryptoperiods (Section 5.3, Table 1)
|
||
|
||
NIST recommends cryptoperiods (key validity durations) based on key type and security requirements. certctl enforces cryptoperiods through certificate profiles and renewal policies.
|
||
|
||
**Certificate Profile Enforcement**
|
||
- Certificate profiles (M11a) define `max_ttl` constraint per enrollment profile
|
||
- All certificates issued through a profile cannot exceed the profile's max_ttl
|
||
- Profile configuration example:
|
||
```json
|
||
{
|
||
"id": "prof-web-prod",
|
||
"name": "Production Web Certs",
|
||
"max_ttl_seconds": 31536000, // 1 year max
|
||
"allowed_key_algorithms": ["ECDSA_P256"],
|
||
"required_sans": ["example.com"]
|
||
}
|
||
```
|
||
|
||
**Renewal Thresholds**
|
||
- Renewal policies with configurable `alert_thresholds_days`: `[30, 14, 7, 0]` (days before expiry)
|
||
- Background scheduler checks renewal eligibility every 1 hour
|
||
- Certificates transitioned to `Expiring` status at 30 days, `Expired` at 0 days
|
||
- Renewal workflow can be triggered manually or automatically
|
||
|
||
**NIST Cryptoperiod Recommendations vs certctl Implementation**
|
||
|
||
| Key Type | NIST Recommendation | certctl Implementation |
|
||
|----------|---------------------|------------------------|
|
||
| CA signing key | 3–10 years | Configured via CA certificate not-after date; inheritable from upstream CA in sub-CA mode |
|
||
| End-entity web server cert | 1–3 years (trending shorter) | Profile `max_ttl` configurable; ACME issuer typically 90 days; SC-081v3 mandating 47 days by 2029 |
|
||
| Code signing cert | 2–8 years | Profile enforcement via `max_ttl`; not primary certctl use case |
|
||
| Short-lived credentials | < 1 hour recommended | Profile TTL < 1 hour; exempt from CRL/OCSP (expiry is sufficient revocation); auto-expiry on scheduler tick |
|
||
| OCSP signing key | 1–2 years | Embedded OCSP responder uses issuing CA key (same period as issuer) or delegated signing cert |
|
||
| TLS/SSL interoperability cert | 1–2 years | Trending 1 year or less; certctl's ACME/sub-CA/step-ca issuers all support short periods |
|
||
|
||
## Key States and Transitions (Section 5.2)
|
||
|
||
NIST defines lifecycle states for keys: pre-activation, active, suspended, deactivated, compromised, and destroyed. certctl maps these to certificate and job states:
|
||
|
||
| NIST Key State | certctl Equivalent | Implementation |
|
||
|---|---|---|
|
||
| **Pre-activation** | `Pending` job state / `AwaitingCSR` | Job created but key not yet generated; awaiting agent CSR submission (agent-mode) or server keygen (demo mode) |
|
||
| **Active** | Certificate status `Active` | Cert deployed to targets and in use; within validity period (not before < now < not after) |
|
||
| **Suspended** | Job state `AwaitingApproval` | Interactive approval holds deployment job pending human review; resumes on approval or cancels on rejection |
|
||
| **Deactivated** | Certificate status `Expired` | Past not-after date; auto-transitioned by scheduler every 2 minutes; renewal eligible |
|
||
| **Compromised** | Certificate status `Revoked` | Issued via `POST /api/v1/certificates/{id}/revoke` with RFC 5280 revocation reason |
|
||
| **Destroyed** | Archived (implementation detail) | Operator responsibility; certctl retains all certs in audit trail for compliance; no destructive deletion API |
|
||
|
||
**State Transition Audit Trail**
|
||
All transitions logged to immutable `audit_events` table with:
|
||
- Event type (e.g., `certificate_revoked`, `renewal_job_completed`)
|
||
- Actor (authenticated user or agent ID)
|
||
- Timestamp (RFC3339)
|
||
- Resource (certificate ID)
|
||
- Reason (revocation reason code, approval reason, etc.)
|
||
- HTTP method, path, status (for API calls)
|
||
|
||
Example audit entry for revocation:
|
||
```json
|
||
{
|
||
"id": "ae-2024-0615",
|
||
"event_type": "certificate_revoked",
|
||
"actor": "ops-alice@example.com",
|
||
"timestamp": "2024-06-15T14:23:00Z",
|
||
"resource_id": "cert-web-prod-2024",
|
||
"resource_type": "certificate",
|
||
"description": "Revoked: reason=keyCompromise",
|
||
"body_hash": "sha256:a1b2c3d..."
|
||
}
|
||
```
|
||
|
||
## Algorithm Recommendations (Section 5.1, SP 800-131A)
|
||
|
||
NIST SP 800-131A Rev 2 (January 2024) categorizes cryptographic algorithms as Approved, Conditionally Approved, or Disallowed. certctl implements only NIST-approved algorithms:
|
||
|
||
| Algorithm | NIST Status | certctl Support | Notes |
|
||
|-----------|-------------|-----------------|-------|
|
||
| **ECDSA P-256** | Approved (128-bit security strength) | Default for agent-side keygen | Meets NIST curve requirements (FIPS 186-4) |
|
||
| **ECDSA P-384** | Approved (192-bit security strength) | Supported via profile configuration | Higher security margin; slower than P-256 |
|
||
| **ECDSA P-521** | Approved (256-bit security strength) | Supported via profile configuration | Rarely needed; overkill for TLS |
|
||
| **RSA 2048** | Approved minimum (112-bit security, transitioning) | Supported via all issuers | Deprecated path; migrate to 3072+ by 2030 per NIST |
|
||
| **RSA 3072** | Approved (128-bit security) | Supported via all issuers | Recommended minimum for long-term security |
|
||
| **RSA 4096** | Approved (192-bit security) | Supported via all issuers | Supported but slower; overkill for most TLS |
|
||
| **SHA-256** | Approved | Used throughout | CSR signing, certificate fingerprints, audit body hashing, CRL/OCSP signing |
|
||
| **SHA-384** | Approved (192-bit) | Supported where algorithm selection available | Used in some CA signing scenarios |
|
||
| **SHA-512** | Approved (256-bit) | Supported where algorithm selection available | Rarely needed; SHA-256 suffices for most use cases |
|
||
| **SHA-1** | Deprecated | Not used in certctl | Browsers reject SHA-1 certs; certctl never generates them |
|
||
|
||
**Algorithm Enforcement via Profiles**
|
||
Certificate profiles enforce allowed key algorithms:
|
||
```json
|
||
{
|
||
"id": "prof-web-prod",
|
||
"allowed_key_algorithms": ["ECDSA_P256", "ECDSA_P384", "RSA3072"]
|
||
}
|
||
```
|
||
|
||
**Post-Quantum Cryptography (Tracking)**
|
||
NIST has finalized PQC standards (FIPS 204, FIPS 205) in August 2024:
|
||
- **ML-KEM** (Kyber): Approved key encapsulation mechanism
|
||
- **ML-DSA** (Dilithium): Approved digital signature algorithm
|
||
- **SLH-DSA** (SPHINCS+): Approved stateless hash-based signature scheme
|
||
|
||
certctl will track NIST's PQC roadmap and plan integration when hybrid PQC+classical certificate formats reach browser/infrastructure support. Currently, pure PQC certificates are not widely interoperable.
|
||
|
||
## Key Distribution and Transport (Section 6.2)
|
||
|
||
NIST SP 800-57 Part 1 Section 6.2 addresses secure key distribution to minimize exposure during transit. certctl implements a zero-transmission-of-private-keys model:
|
||
|
||
**Private Key Distribution**
|
||
- Agent-side keygen model: Private keys never leave agent infrastructure
|
||
- CSR transmitted over HTTPS (TLS 1.2+) with mutual TLS optional
|
||
- API key authentication via `Authorization: Bearer <api-key>` header
|
||
- All API calls logged to immutable audit trail
|
||
|
||
**Signed Certificate Distribution**
|
||
- Certificates (public component) distributed via `GET /agents/{id}/work` over HTTPS
|
||
- Work endpoint enriches deployment jobs with certificate PEM and metadata
|
||
- Certificate PEM is idempotent (same cert always returns same bytes)
|
||
|
||
**Target Deployment**
|
||
- Deployment to targets via local filesystem write (NGINX, Apache, HAProxy)
|
||
- No network transmission of private keys to targets
|
||
- Agents read local private key from `CERTCTL_KEY_DIR` on deployment
|
||
- For appliances without agents (F5 BIG-IP, IIS), proxy agent pattern:
|
||
- Proxy agent runs in same trust zone as appliance
|
||
- Proxy agent holds target API credentials (iControl, WinRM)
|
||
- Control plane never communicates with appliance directly
|
||
- Deployment request includes certificate and proxy agent ID
|
||
- Proxy agent executes deployment via appliance API
|
||
|
||
**Revocation Distribution**
|
||
- Certificate Revocation List (CRL) via `GET /api/v1/crl/{issuer_id}`
|
||
- Returns DER-encoded X.509 CRL signed by issuing CA
|
||
- 24-hour validity period
|
||
- Includes all revoked serials, reasons, and revocation timestamps
|
||
- Subject to URL caching; OCSP preferred for real-time revocation
|
||
- OCSP via `GET /api/v1/ocsp/{issuer_id}/{serial}`
|
||
- Returns DER-encoded OCSP response (OCSPResponse ASN.1 structure)
|
||
- Signed by issuing CA (or delegated OCSP signing cert)
|
||
- Responds with good/revoked/unknown status
|
||
- Real-time, more bandwidth-efficient than CRL polling
|
||
|
||
## Revocation and Compromise (NIST SP 800-57 Part 3)
|
||
|
||
NIST SP 800-57 Part 3 covers revocation (Section 2.5) when keys are suspected compromised or no longer needed. certctl implements comprehensive revocation infrastructure:
|
||
|
||
**Revocation API**
|
||
- Endpoint: `POST /api/v1/certificates/{id}/revoke`
|
||
- Request body:
|
||
```json
|
||
{
|
||
"reason": "keyCompromise",
|
||
"reason_text": "Private key exposed in log file"
|
||
}
|
||
```
|
||
- Supports all 8 RFC 5280 revocation reason codes:
|
||
- `unspecified` — no specific reason provided
|
||
- `keyCompromise` — private key suspected compromised
|
||
- `caCompromise` — issuing CA key compromised
|
||
- `affiliationChanged` — subject org/affiliation changed
|
||
- `superseded` — cert superseded by newer cert
|
||
- `cessationOfOperation` — key no longer in use
|
||
- `certificateHold` — temporary hold (rarely used)
|
||
- `privilegeWithdrawn` — subject authorization withdrawn
|
||
|
||
**Revocation Recording**
|
||
- Certificate status updated to `Revoked`
|
||
- Entry recorded in `certificate_revocations` table with:
|
||
- Certificate serial number
|
||
- Revocation timestamp
|
||
- Revocation reason code
|
||
- Issuer ID
|
||
- Idempotent (revoking an already-revoked cert is safe; returns 200 OK)
|
||
|
||
**Issuer Notification (Best-Effort)**
|
||
- Control plane calls `issuer.RevokeCertificate(ctx, serial, reason)` on issuing connector
|
||
- Failure does not block the revocation (async, logged, retried)
|
||
- Supported issuers:
|
||
- Local CA: generates new CRL immediately
|
||
- ACME: submits revocation to ACME server (RFC 8555 Section 7.6)
|
||
- step-ca: calls `/revoke` API
|
||
- OpenSSL: executes user-provided revocation script
|
||
|
||
**Revocation Notifications**
|
||
- Notifiers triggered after revocation recorded: Slack, Teams, PagerDuty, OpsGenie, email, webhook
|
||
- Message includes certificate common name, issuer, reason, actor, timestamp
|
||
- Delivery is asynchronous and retried on failure
|
||
|
||
**CRL and OCSP Distribution**
|
||
- CRL updated on every revocation (or scheduled refresh for non-issued revocations)
|
||
- OCSP responder queries revocation table in real-time
|
||
- Short-lived certificate exemption: certs with TTL < 1 hour skip CRL/OCSP (expiry is sufficient revocation)
|
||
|
||
**Revocation Audit Trail**
|
||
All revocation events logged:
|
||
- Event type: `certificate_revoked`
|
||
- Actor: authenticated user or service
|
||
- Reason code: RFC 5280 enum
|
||
- Timestamp: RFC3339
|
||
- Issuer notification status: success or error reason
|
||
|
||
## Alignment Summary Table
|
||
|
||
| NIST SP 800-57 Area | Status | Coverage | Notes |
|
||
|---|---|---|---|
|
||
| **Key Generation** | ✅ Aligned | 100% | Agent-side ECDSA P-256 using crypto/rand; server mode flagged as demo-only |
|
||
| **Key Storage** | ⚠️ Partially Aligned | 80% | Filesystem with 0600 perms; HSM support planned V5 |
|
||
| **Cryptoperiods** | ✅ Aligned | 100% | Profile-enforced max_ttl; threshold-based renewal alerting |
|
||
| **Key States** | ✅ Aligned | 100% | Full lifecycle tracking with immutable audit trail |
|
||
| **Algorithms** | ✅ Aligned | 100% | NIST-approved algorithms only; post-quantum tracking in progress |
|
||
| **Key Distribution** | ✅ Aligned | 100% | Private keys never transmitted; CSR/cert over TLS; agent-local deployment |
|
||
| **Revocation** | ✅ Aligned | 100% | CRL, OCSP, all RFC 5280 reason codes; real-time updates |
|
||
|
||
## Gaps and Remediation Roadmap
|
||
|
||
### V2 (Current)
|
||
- [x] Agent-side key generation
|
||
- [x] Profile-enforced cryptoperiods
|
||
- [x] CRL and OCSP distribution
|
||
- [x] RFC 5280 revocation support
|
||
- [x] Immutable audit trail
|
||
|
||
### V3 (Planned: 2026)
|
||
- Role-based access control (limit revocation/approval to authorized operators)
|
||
- Bulk revocation by profile/owner/agent (fleet-level revocation policy)
|
||
|
||
### V5 (Planned: 2027+)
|
||
- HSM support for CA key storage
|
||
- PKCS#11 integration for hardware tokens
|
||
- FIPS 140-2/3 validated crypto module (BoringCrypto build or external FIPS library)
|
||
- Key destruction API (explicit secure erasure of agent keys)
|
||
- Key escrow / recovery mechanism (backup encrypted private keys for disaster recovery)
|
||
|
||
### Post-Quantum (2027+)
|
||
- ML-KEM and ML-DSA support when browser/TLS ecosystem supports hybrid certificates
|
||
- Migration path documentation (how to transition existing RSA certs to PQC)
|
||
|
||
## References
|
||
|
||
- NIST SP 800-57 Part 1 Rev 5 (May 2020): https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf
|
||
- NIST SP 800-131A Rev 2 (January 2024): https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf
|
||
- FIPS 186-4 (Digital Signature Standard): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
|
||
- RFC 5280 (X.509 PKI Certificate and CRL Profile): https://tools.ietf.org/html/rfc5280
|
||
- RFC 8555 (Automatic Certificate Management Environment): https://tools.ietf.org/html/rfc8555
|
||
- NIST FIPS 204 (ML-DSA): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf
|
||
- NIST FIPS 205 (ML-KEM): https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.205.pdf
|
||
|
||
## Questions or Corrections?
|
||
|
||
This document reflects certctl's implementation as of March 2026. For the latest code, refer to:
|
||
- Key generation: `cmd/agent/main.go` (agent keygen) and `internal/service/renewal.go` (server keygen)
|
||
- Key storage: `internal/config/config.go` (CERTCTL_KEY_DIR, CERTCTL_CA_CERT_PATH)
|
||
- Revocation: `internal/service/revocation.go` and `internal/api/handler/certificates.go`
|
||
- Audit trail: `internal/api/middleware/audit.go`
|