diff --git a/README.adoc b/README.adoc index 8b13789..907286d 100644 --- a/README.adoc +++ b/README.adoc @@ -1 +1,217 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2024 Hyperpolymath += Explicit Trust Plane +:author: Hyperpolymath +:email: hyperpolymath@proton.me +:revnumber: 1.0.0 +:revdate: 2024-12-28 +:toc: left +:toclevels: 3 +:icons: font +:source-highlighter: rouge +image:https://img.shields.io/badge/license-AGPL--3.0--or--later-blue[License] +image:https://img.shields.io/badge/status-active-green[Status] +image:https://img.shields.io/badge/DNSSEC-required-red[DNSSEC] + +== Overview + +*Explicit Trust Plane* is a framework for DNS-published cryptographic identity, treating DNS as a decentralized public key infrastructure (PKI) rather than merely a naming system. + +[source] +---- +┌─────────────────────────────────────────────────────────────────┐ +│ EXPLICIT TRUST PLANE │ +│ │ +│ Your cryptographic identity, published via DNS │ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ X.509 │ │ OpenPGP │ │ X25519 │ │ DANE │ │ +│ │ Ed448 │ │ Ed25519 │ │ KEX │ │ TLSA │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ +│ │ │ │ │ │ +│ └─────────────┴──────┬──────┴─────────────┘ │ +│ │ │ +│ ┌──────▼──────┐ │ +│ │ DNS │ │ +│ │ + DNSSEC │ │ +│ └─────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +---- + +== Features + +* *Modern Cryptography* - Ed448, Ed25519, X25519 (no legacy RSA required) +* *Algorithm-Agile* - Ready for post-quantum migration +* *Self-Sovereign Identity* - No centralized key servers +* *Reproducible* - Scripted key generation and DNS export +* *Explicit Role Separation* - Signing vs key exchange vs identity + +== Quick Start + +[source,bash] +---- +# Clone the repository +git clone https://github.com/hyperpolymath/explicit-trust-plane.git +cd explicit-trust-plane + +# Generate all cryptographic materials for your domain +./scripts/generate-ca.sh yourdomain.com +./scripts/generate-cert.sh yourdomain.com +./scripts/generate-kex.sh yourdomain.com +./scripts/generate-pgp.sh "Your Name" "you@yourdomain.com" + +# Export DNS records +./scripts/export-dns.sh yourdomain.com + +# View the generated zone file +cat dns/records/yourdomain.com.zone +---- + +== Project Structure + +[source] +---- +explicit-trust-plane/ +├── ca/ # Certificate Authority materials +│ ├── root/ # Ed448 Root CA (KEEP OFFLINE!) +│ │ ├── ca-ed448.key # Private key (HSM recommended) +│ │ ├── ca-ed448.crt # Root certificate +│ │ └── ca-ed448.crt.b64 # Base64 for DNS +│ └── intermediate/ # Ed448 Intermediate CA +│ ├── intermediate-ed448.key +│ ├── intermediate-ed448.crt +│ └── chain.crt # Full certificate chain +├── certs/ # End-entity certificates +│ ├── *.key # Ed25519 private keys +│ ├── *.crt # Certificates +│ └── *.crt.b64 # Base64 for DNS CERT records +├── pgp/ # OpenPGP keys +│ ├── *.asc # ASCII armored public keys +│ ├── *.pgp # Binary public keys +│ └── *.pgp.b64 # Base64 for DNS CERT records +├── kex/ # Key exchange materials +│ ├── *.x25519.key # X25519 private keys +│ └── *.x25519.pub.b64 # Base64 for IPSECKEY records +├── dns/ # DNS zone files +│ └── records/ # Generated zone includes +├── scripts/ # Automation scripts +│ ├── generate-ca.sh # Create CA hierarchy +│ ├── generate-cert.sh # Create server certificates +│ ├── generate-pgp.sh # Create OpenPGP keys +│ ├── generate-kex.sh # Create X25519 keys +│ ├── export-dns.sh # Export all as DNS records +│ └── rotate-keys.sh # Key rotation with backup +└── docs/ # Documentation + ├── DESIGN.adoc # Architecture & rationale + └── DEPLOYMENT.adoc # End-to-end deployment guide +---- + +== Algorithm Selection + +[cols="1,1,2,2"] +|=== +| Algorithm | Type | Use Case | DNS Record Type + +| Ed448 +| Signature +| Long-term CA certificates +| CERT (PKIX) + +| Ed25519 +| Signature +| Server certs, PGP signing +| CERT (PKIX/PGP) + +| X25519 +| Key Exchange +| TLS 1.3, VPN bootstrap +| IPSECKEY + +| SHA-256 +| Hash +| TLSA fingerprints +| TLSA +|=== + +IMPORTANT: These are *different cryptographic objects*, not one key encoded multiple ways. + +== DNS Record Types + +=== CERT Records (RFC 4398) + +[source,dns] +---- +; X.509 Certificate +_cert.example.com. IN CERT PKIX 0 0 + +; OpenPGP Key +_pgp.example.com. IN CERT PGP 0 0 +---- + +=== IPSECKEY Records (RFC 4025) + +[source,dns] +---- +_ipsec.example.com. IN IPSECKEY 10 0 2 . +---- + +=== TLSA Records (RFC 6698 - DANE) + +[source,dns] +---- +_443._tcp.example.com. IN TLSA 3 1 1 +---- + +== Security Requirements + +[CAUTION] +==== +*DNSSEC is mandatory.* Without DNSSEC, DNS-published keys can be spoofed via cache poisoning attacks. +==== + +* *No MD5/SHA1* - SHA-256 minimum for all operations +* *HTTPS only* - No HTTP URLs in any configuration +* *HSM for CA keys* - Root CA private key must be offline +* *Key rotation* - Automated rotation scripts provided + +== Minimum Viable Set + +For a single domain, you need: + +1. *1× Ed448 Root CA* - Offline, 10-year validity +2. *1× Ed25519 Server Cert* - For TLS authentication +3. *1× X25519 Key* - For TLS 1.3 key exchange +4. *1× OpenPGP Key* - For human identity + +== Documentation + +* link:docs/DESIGN.adoc[Design Document] - Full architecture and rationale +* link:docs/DEPLOYMENT.adoc[Deployment Guide] - End-to-end deployment walkthrough + +== Prerequisites + +* OpenSSL 3.0+ (Ed448/Ed25519 support) +* GnuPG 2.2+ (modern ECC support) +* DNSSEC-enabled DNS zone + +Check your versions: +[source,bash] +---- +openssl version # OpenSSL 3.0.0 or later +gpg --version # gnupg 2.2.0 or later +---- + +== License + +SPDX-License-Identifier: AGPL-3.0-or-later + +This project is licensed under the GNU Affero General Public License v3.0 or later. + +== Contributing + +See link:CONTRIBUTING.md[CONTRIBUTING.md] for guidelines. + +== Author + +Hyperpolymath diff --git a/ca/intermediate/.gitkeep b/ca/intermediate/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ca/root/.gitkeep b/ca/root/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/certs/.gitkeep b/certs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dns/records/.gitkeep b/dns/records/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dns/zone.template b/dns/zone.template new file mode 100644 index 0000000..afc527e --- /dev/null +++ b/dns/zone.template @@ -0,0 +1,181 @@ +; SPDX-License-Identifier: AGPL-3.0-or-later +; SPDX-FileCopyrightText: 2024 Hyperpolymath +; +; Explicit Trust Plane - DNS Zone Template +; +; INSTRUCTIONS: +; 1. Replace with your actual domain +; 2. Generate cryptographic materials using scripts/ +; 3. Run scripts/export-dns.sh to generate actual records +; 4. Copy or include the generated records in your zone +; +; IMPORTANT: Enable DNSSEC before deploying these records! + +$ORIGIN . +$TTL 3600 + +; ============================================================================= +; STANDARD DNS RECORDS (for reference) +; ============================================================================= + +; SOA and NS records - customize for your setup +; @ IN SOA ns1.. hostmaster.. ( +; 2024122801 ; serial (YYYYMMDDNN) +; 3600 ; refresh (1 hour) +; 1800 ; retry (30 min) +; 604800 ; expire (1 week) +; 300 ; minimum TTL (5 min) +; ) +; @ IN NS ns1.. +; @ IN NS ns2.. + +; ============================================================================= +; X.509 CERTIFICATES (CERT PKIX - RFC 4398) +; ============================================================================= +; +; Type: PKIX (1) = X.509 certificate in DER format, Base64 encoded +; Key Tag: 0 (unused) +; Algorithm: 0 (determined by certificate content) + +; Root CA Certificate (Ed448) +; Usage: Trust anchor, published for transparency +_ca._cert IN CERT PKIX 0 0 ( + ; === INSERT BASE64-ENCODED ROOT CA CERTIFICATE (DER) === + ; Generate with: openssl x509 -in ca-ed448.crt -outform DER | base64 -w0 + PLACEHOLDER_ROOT_CA_CERTIFICATE +) + +; Intermediate CA Certificate (Ed448) +; Usage: Chain validation +_intermediate._cert IN CERT PKIX 0 0 ( + ; === INSERT BASE64-ENCODED INTERMEDIATE CA CERTIFICATE (DER) === + PLACEHOLDER_INTERMEDIATE_CA_CERTIFICATE +) + +; Server Certificate (Ed25519) +; Usage: TLS authentication +_server._cert IN CERT PKIX 0 0 ( + ; === INSERT BASE64-ENCODED SERVER CERTIFICATE (DER) === + PLACEHOLDER_SERVER_CERTIFICATE +) + +; ============================================================================= +; OPENPGP KEYS (CERT PGP - RFC 4398) +; ============================================================================= +; +; Type: PGP (3) = OpenPGP public key packet +; Key Tag: 0 (unused) +; Algorithm: 0 (determined by key content) + +; Primary identity key +_pgp IN CERT PGP 0 0 ( + ; === INSERT BASE64-ENCODED PGP PUBLIC KEY === + ; Generate with: gpg --export user@domain | base64 -w0 + PLACEHOLDER_PGP_PUBLIC_KEY +) + +; Per-user pattern (optional) +; user._pgpkey IN CERT PGP 0 0 ( ... ) + +; ============================================================================= +; KEY EXCHANGE (IPSECKEY - RFC 4025) +; ============================================================================= +; +; Format: precedence gateway-type algorithm gateway public-key +; +; Precedence: 10 (priority, lower = higher) +; Gateway Type: 0 = no gateway +; Algorithm: 2 = DSA (placeholder; actual algorithm is X25519) +; Gateway: . (null) +; Public Key: Base64-encoded raw 32-byte X25519 public key + +; X25519 for TLS 1.3 / VPN key agreement +_ipsec IN IPSECKEY 10 0 2 . ( + ; === INSERT BASE64-ENCODED X25519 PUBLIC KEY (32 bytes) === + ; Generate with: openssl pkey -in x25519.key -pubout -outform DER | tail -c32 | base64 + PLACEHOLDER_X25519_PUBLIC_KEY +) + +; ============================================================================= +; DANE/TLSA (RFC 6698) +; ============================================================================= +; +; Format: usage selector matching-type certificate-data +; +; Usage: 3 = DANE-EE (end entity, no CA validation) +; Selector: 1 = Subject Public Key Info (SPKI) +; Matching Type: 1 = SHA-256 hash +; +; Naming: _port._proto.hostname + +; HTTPS (port 443) +_443._tcp IN TLSA 3 1 1 ( + ; === INSERT SHA-256 HASH OF CERTIFICATE SPKI === + ; Generate with: + ; openssl x509 -in server.crt -noout -pubkey | \ + ; openssl pkey -pubin -outform DER | sha256sum | cut -d' ' -f1 + PLACEHOLDER_TLSA_HASH +) + +; SMTP (port 25) - for mail servers +; _25._tcp.mail IN TLSA 3 1 1 ( HASH ) + +; SMTPS (port 465) +; _465._tcp.mail IN TLSA 3 1 1 ( HASH ) + +; IMAPS (port 993) +; _993._tcp.mail IN TLSA 3 1 1 ( HASH ) + +; ============================================================================= +; CERTIFICATE AUTHORITY AUTHORIZATION (CAA - RFC 8659) +; ============================================================================= +; +; Restricts which CAs can issue certificates for this domain + +; Allow Let's Encrypt only +@ IN CAA 0 issue "letsencrypt.org" + +; Disallow wildcard certificates from any CA +@ IN CAA 0 issuewild ";" + +; Report violations +@ IN CAA 0 iodef "mailto:security@" + +; ============================================================================= +; MTA-STS / SMTP SECURITY (RFC 8461) +; ============================================================================= + +; MTA-STS policy location +_mta-sts IN TXT "v=STSv1; id=20241228" + +; SMTP TLS reporting +_smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@" + +; ============================================================================= +; DKIM (RFC 6376) +; ============================================================================= +; +; DKIM with Ed25519 (RFC 8463) + +; selector._domainkey IN TXT "v=DKIM1; k=ed25519; p=BASE64_PUBLIC_KEY" + +; ============================================================================= +; DMARC (RFC 7489) +; ============================================================================= + +_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@" + +; ============================================================================= +; DNSSEC NOTES +; ============================================================================= +; +; DNSSEC records (DNSKEY, DS, RRSIG, NSEC/NSEC3) are managed by your DNS +; provider or signing infrastructure. They are not included in this template. +; +; Recommended algorithms: +; - Algorithm 15: Ed25519 (preferred) +; - Algorithm 13: ECDSA P-256 (fallback) +; +; DO NOT use: +; - Algorithm 5: RSA/SHA-1 (deprecated) +; - Algorithm 7: RSA/SHA-1 NSEC3 (deprecated) diff --git a/docs/DEPLOYMENT.adoc b/docs/DEPLOYMENT.adoc new file mode 100644 index 0000000..3d2a25f --- /dev/null +++ b/docs/DEPLOYMENT.adoc @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2024 Hyperpolymath += Explicit Trust Plane: End-to-End Deployment Guide +:author: Hyperpolymath +:email: hyperpolymath@proton.me +:revnumber: 1.0.0 +:revdate: 2024-12-28 +:toc: left +:toclevels: 4 +:sectnums: +:icons: font +:source-highlighter: rouge +:experimental: + +== Introduction + +This guide walks you through deploying the Explicit Trust Plane from scratch—from key generation to DNS publication to TLS configuration and client verification. + +=== Prerequisites + +* A registered domain with DNS hosting that supports: +** CERT records +** IPSECKEY records +** TLSA records +** DNSSEC signing +* OpenSSL 3.0+ installed +* GnuPG 2.2+ installed +* A server for TLS deployment + +=== Time Estimate + +| Phase | Duration | +|-------|----------| +| Key Generation | 5-10 minutes | +| DNS Configuration | 15-30 minutes | +| TLS Server Setup | 15-30 minutes | +| Verification | 10-15 minutes | +| *Total* | *45-85 minutes* | + +== Phase 1: Key Generation + +=== 1.1 Clone the Repository + +[source,bash] +---- +git clone https://github.com/hyperpolymath/explicit-trust-plane.git +cd explicit-trust-plane +---- + +=== 1.2 Generate Certificate Authority + +[CAUTION] +==== +The Root CA private key must be kept offline after generation. Consider: + +* Using an air-gapped machine +* Storing on an encrypted USB drive +* Using a Hardware Security Module (HSM) +==== + +[source,bash] +---- +# Replace with your actual domain +export DOMAIN="example.com" + +# Generate Root CA (10 years) and Intermediate CA (5 years) +./scripts/generate-ca.sh "${DOMAIN}" +---- + +Expected output: +[source] +---- +=== Explicit Trust Plane - CA Generation === +Domain: example.com +Root validity: 3650 days +Intermediate validity: 1825 days + +[1/4] Generating Ed448 Root CA private key... +[2/4] Generating Root CA certificate... +[3/4] Generating Ed448 Intermediate CA private key... +[4/4] Generating Intermediate CA certificate... + +=== CA Generation Complete === + +Root CA: + Private key: ca/root/ca-ed448.key (KEEP OFFLINE!) + Certificate: ca/root/ca-ed448.crt + DNS (Base64): ca/root/ca-ed448.crt.b64 + +Intermediate CA: + Private key: ca/intermediate/intermediate-ed448.key + Certificate: ca/intermediate/intermediate-ed448.crt + Chain: ca/intermediate/chain.crt + DNS (Base64): ca/intermediate/intermediate-ed448.crt.b64 + +Root CA fingerprint (SHA256): +SHA256 Fingerprint=AB:CD:12:34:... + +SECURITY REMINDER: + - Move ca-ed448.key to offline/HSM storage immediately + - Never store root CA key on networked systems +---- + +=== 1.3 Generate Server Certificate + +[source,bash] +---- +# Generate Ed25519 server certificate (1 year validity) +./scripts/generate-cert.sh "${DOMAIN}" 365 +---- + +This creates: +* `certs/example.com.key` - Private key (Ed25519) +* `certs/example.com.crt` - Certificate +* `certs/example.com.fullchain.crt` - Full chain for web servers +* `certs/example.com.crt.b64` - Base64 for DNS CERT record + +=== 1.4 Generate X25519 Key Exchange + +[source,bash] +---- +./scripts/generate-kex.sh "${DOMAIN}" +---- + +This creates: +* `kex/example.com.x25519.key` - Private key +* `kex/example.com.x25519.pub.b64` - Base64 public key for IPSECKEY + +=== 1.5 Generate OpenPGP Key + +[source,bash] +---- +./scripts/generate-pgp.sh "Your Name" "admin@${DOMAIN}" +---- + +This creates: +* `pgp/admin_at_example_com.asc` - ASCII armored public key +* `pgp/admin_at_example_com.pgp.b64` - Base64 for DNS CERT record + +=== 1.6 Export DNS Records + +[source,bash] +---- +./scripts/export-dns.sh "${DOMAIN}" +---- + +This generates a complete zone file at: +`dns/records/example.com.zone` + +== Phase 2: DNS Configuration + +=== 2.1 Enable DNSSEC + +[WARNING] +==== +DNSSEC must be enabled *before* publishing cryptographic records. Without DNSSEC, attackers can spoof your keys via DNS cache poisoning. +==== + +The DNSSEC setup process varies by provider: + +==== Cloudflare + +1. Go to DNS → Settings → DNSSEC +2. Click "Enable DNSSEC" +3. Add the DS record to your registrar + +==== AWS Route 53 + +[source,bash] +---- +# Create KSK +aws route53 create-key-signing-key \ + --hosted-zone-id Z123456789 \ + --name example-com-ksk \ + --key-management-service-arn arn:aws:kms:... + +# Enable DNSSEC +aws route53 enable-hosted-zone-dnssec \ + --hosted-zone-id Z123456789 +---- + +==== Self-Hosted (BIND) + +[source,bash] +---- +# Generate DNSSEC keys +dnssec-keygen -a ED25519 -f KSK example.com +dnssec-keygen -a ED25519 example.com + +# Sign the zone +dnssec-signzone -S -o example.com db.example.com +---- + +=== 2.2 Add CERT Records + +Open `dns/records/example.com.zone` and add the records to your DNS provider. + +==== Using dig to verify format + +[source,bash] +---- +# Extract the CERT record content +cat dns/records/example.com.zone | grep -A5 "_server._cert" +---- + +==== Cloudflare (API) + +[source,bash] +---- +ZONE_ID="your-zone-id" +API_TOKEN="your-api-token" +CERT_DATA=$(cat certs/example.com.crt.b64) + +curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \ + -H "Authorization: Bearer ${API_TOKEN}" \ + -H "Content-Type: application/json" \ + --data '{ + "type": "CERT", + "name": "_server._cert", + "data": { + "type": 1, + "key_tag": 0, + "algorithm": 0, + "certificate": "'"${CERT_DATA}"'" + }, + "ttl": 3600 + }' +---- + +==== BIND Zone File + +Add to your zone file: +[source,dns] +---- +$INCLUDE /etc/bind/zones/example.com.trust-plane.zone +---- + +=== 2.3 Add IPSECKEY Record + +[source,bash] +---- +KEX_DATA=$(cat kex/example.com.x25519.pub.b64) + +# For BIND +echo "_ipsec IN IPSECKEY 10 0 2 . ${KEX_DATA}" +---- + +=== 2.4 Add TLSA Record + +The export script generates TLSA records automatically: + +[source,dns] +---- +_443._tcp IN TLSA 3 1 1 abcd1234... ; SHA256 of SPKI +---- + +=== 2.5 Add CAA Records + +Restrict certificate issuance: +[source,dns] +---- +@ IN CAA 0 issue "letsencrypt.org" +@ IN CAA 0 issuewild ";" +@ IN CAA 0 iodef "mailto:security@example.com" +---- + +=== 2.6 Verify DNS Propagation + +Wait for DNS propagation (typically 5-60 minutes), then verify: + +[source,bash] +---- +# Check CERT record +dig +short CERT _server._cert.example.com + +# Check IPSECKEY record +dig +short IPSECKEY _ipsec.example.com + +# Check TLSA record +dig +short TLSA _443._tcp.example.com + +# Verify DNSSEC +dig +dnssec +short example.com +---- + +== Phase 3: TLS Server Configuration + +=== 3.1 Nginx Configuration + +[source,nginx] +---- +# /etc/nginx/sites-available/example.com + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name example.com; + + # Ed25519 Certificate Chain + ssl_certificate /path/to/explicit-trust-plane/certs/example.com.fullchain.crt; + ssl_certificate_key /path/to/explicit-trust-plane/certs/example.com.key; + + # Modern TLS configuration + ssl_protocols TLSv1.3; + ssl_prefer_server_ciphers off; + + # HSTS + add_header Strict-Transport-Security "max-age=63072000" always; + + # ... rest of configuration +} +---- + +[NOTE] +==== +Nginx requires OpenSSL 1.1.1+ for Ed25519 certificate support. +Check with: `nginx -V 2>&1 | grep -o 'OpenSSL [0-9.]*'` +==== + +=== 3.2 Caddy Configuration + +[source,caddyfile] +---- +# /etc/caddy/Caddyfile + +example.com { + tls /path/to/certs/example.com.fullchain.crt /path/to/certs/example.com.key + + # ... rest of configuration +} +---- + +=== 3.3 Apache Configuration + +[source,apache] +---- +# /etc/apache2/sites-available/example.com.conf + + + ServerName example.com + + SSLEngine on + SSLCertificateFile /path/to/certs/example.com.crt + SSLCertificateKeyFile /path/to/certs/example.com.key + SSLCertificateChainFile /path/to/ca/intermediate/chain.crt + + # Modern TLS + SSLProtocol -all +TLSv1.3 + + # ... rest of configuration + +---- + +=== 3.4 Test TLS Configuration + +[source,bash] +---- +# Test connection +openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ + openssl x509 -text -noout | head -20 + +# Verify certificate chain +openssl s_client -connect example.com:443 -servername example.com -showcerts < /dev/null 2>/dev/null + +# Check certificate algorithm +openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ + openssl x509 -noout -text | grep "Public Key Algorithm" +---- + +== Phase 4: Client Verification + +=== 4.1 Verify DNS-Published Certificate + +[source,bash] +---- +# Fetch certificate from DNS +CERT_B64=$(dig +short CERT _server._cert.example.com | awk '{print $4}') + +# Decode and display +echo "${CERT_B64}" | base64 -d | openssl x509 -inform DER -text -noout + +# Compare with TLS certificate +TLS_CERT=$(openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ + openssl x509 -outform DER | base64 -w0) + +if [ "${CERT_B64}" = "${TLS_CERT}" ]; then + echo "DNS certificate matches TLS certificate" +else + echo "WARNING: Certificates do not match!" +fi +---- + +=== 4.2 Verify DANE/TLSA + +[source,bash] +---- +# Get TLSA record +TLSA_HASH=$(dig +short TLSA _443._tcp.example.com | awk '{print $4}') + +# Calculate hash from live certificate +LIVE_HASH=$(openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ + openssl x509 -pubkey -noout | \ + openssl pkey -pubin -outform DER | \ + sha256sum | cut -d' ' -f1) + +if [ "${TLSA_HASH}" = "${LIVE_HASH}" ]; then + echo "TLSA validation passed" +else + echo "WARNING: TLSA hash mismatch!" +fi +---- + +=== 4.3 Verify OpenPGP Key + +[source,bash] +---- +# Fetch PGP key from DNS +PGP_B64=$(dig +short CERT _pgp.example.com | awk '{print $4}') + +# Import to GPG +echo "${PGP_B64}" | base64 -d | gpg --import + +# Verify key +gpg --list-keys admin@example.com +---- + +=== 4.4 Automated Verification Script + +Create `scripts/verify-deployment.sh`: + +[source,bash] +---- +#!/usr/bin/env bash +# Verify Explicit Trust Plane deployment + +set -euo pipefail + +DOMAIN="${1:-example.com}" +ERRORS=0 + +echo "=== Verifying Explicit Trust Plane for ${DOMAIN} ===" +echo "" + +# Check DNSSEC +echo -n "[DNSSEC] " +if dig +dnssec +short "${DOMAIN}" | grep -q "RRSIG"; then + echo "PASS - DNSSEC enabled" +else + echo "FAIL - DNSSEC not detected" + ((ERRORS++)) +fi + +# Check CERT record +echo -n "[CERT] " +if dig +short CERT "_server._cert.${DOMAIN}" | grep -q "PKIX"; then + echo "PASS - CERT record found" +else + echo "FAIL - CERT record not found" + ((ERRORS++)) +fi + +# Check IPSECKEY record +echo -n "[IPSEC] " +if dig +short IPSECKEY "_ipsec.${DOMAIN}" | grep -q "10"; then + echo "PASS - IPSECKEY record found" +else + echo "WARN - IPSECKEY record not found (optional)" +fi + +# Check TLSA record +echo -n "[TLSA] " +if dig +short TLSA "_443._tcp.${DOMAIN}" | grep -q "3 1 1"; then + echo "PASS - TLSA record found" +else + echo "WARN - TLSA record not found" +fi + +# Check TLS connection +echo -n "[TLS] " +if openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" < /dev/null 2>/dev/null | grep -q "Verify return code: 0"; then + echo "PASS - TLS connection verified" +else + echo "WARN - TLS verification issue (may be expected with self-signed CA)" +fi + +echo "" +if [ "${ERRORS}" -eq 0 ]; then + echo "=== All critical checks passed ===" +else + echo "=== ${ERRORS} critical check(s) failed ===" + exit 1 +fi +---- + +== Phase 5: Maintenance + +=== 5.1 Certificate Rotation + +Run the rotation script before certificates expire: + +[source,bash] +---- +# Rotate server certificate +./scripts/rotate-keys.sh example.com cert + +# Update DNS records +./scripts/export-dns.sh example.com + +# Deploy new certificate to server +# (copy to server and reload nginx/caddy/apache) + +# Update TLSA record in DNS +---- + +=== 5.2 Monitoring + +Set up alerts for: + +* Certificate expiration (30 days warning) +* DNSSEC signature expiration +* TLSA record mismatches + +Example cron job for monitoring: + +[source,bash] +---- +# /etc/cron.daily/check-certs +#!/bin/bash +DOMAIN="example.com" +DAYS=30 + +# Check certificate expiration +openssl s_client -connect "${DOMAIN}:443" -servername "${DOMAIN}" < /dev/null 2>/dev/null | \ + openssl x509 -checkend $((DAYS * 86400)) || \ + echo "Certificate expires within ${DAYS} days" | mail -s "Cert Alert: ${DOMAIN}" admin@${DOMAIN} +---- + +=== 5.3 Backup Strategy + +[source,bash] +---- +# Backup all keys (encrypted) +tar -czf - ca/ certs/ pgp/ kex/ | \ + gpg --symmetric --cipher-algo AES256 > "trust-plane-backup-$(date +%Y%m%d).tar.gz.gpg" + +# Store backup securely: +# - Encrypted cloud storage +# - Offline media (USB, tape) +# - Multiple geographic locations +---- + +== Troubleshooting + +=== CERT Record Not Resolving + +1. Verify record syntax: `dig +trace CERT _server._cert.example.com` +2. Check if DNS provider supports CERT records +3. Ensure DNSSEC is properly configured + +=== TLS Handshake Failures + +1. Verify OpenSSL/Nginx supports Ed25519: `openssl version` +2. Check certificate chain completeness +3. Verify key and certificate match: `openssl x509 -noout -modulus -in cert.crt` + +=== DANE Validation Failures + +1. Ensure TLSA record matches current certificate +2. Check DNSSEC chain is intact +3. Verify selector (1 = SPKI) and matching type (1 = SHA256) + +=== PGP Key Import Failures + +1. Verify key format: `echo "${B64}" | base64 -d | gpg --list-packets` +2. Check key hasn't expired +3. Ensure key is complete (not truncated by DNS) + +== Quick Reference Commands + +[source,bash] +---- +# Generate all materials +./scripts/generate-ca.sh example.com +./scripts/generate-cert.sh example.com +./scripts/generate-kex.sh example.com +./scripts/generate-pgp.sh "Name" "email@example.com" +./scripts/export-dns.sh example.com + +# Verify DNS records +dig +short CERT _server._cert.example.com +dig +short IPSECKEY _ipsec.example.com +dig +short TLSA _443._tcp.example.com +dig +dnssec +short example.com + +# Verify TLS +openssl s_client -connect example.com:443 + +# Rotate keys +./scripts/rotate-keys.sh example.com cert +./scripts/export-dns.sh example.com +---- + +== Appendix: DNS Provider Support Matrix + +[cols="1,1,1,1,1,1"] +|=== +| Provider | CERT | IPSECKEY | TLSA | DNSSEC | Notes + +| Cloudflare +| Yes +| Yes +| Yes +| Yes +| Full support via API + +| AWS Route 53 +| Yes +| Yes +| Yes +| Yes +| KMS integration available + +| Google Cloud DNS +| Yes +| Yes +| Yes +| Yes +| Full support + +| DigitalOcean +| Limited +| No +| Limited +| No +| Consider alternative + +| Namecheap +| No +| No +| No +| No +| Use external DNS + +| GoDaddy +| No +| No +| No +| Limited +| Not recommended +|=== + +== Next Steps + +After completing this deployment: + +1. *Document your setup* - Record all generated fingerprints +2. *Set up monitoring* - Automated expiration alerts +3. *Plan key rotation* - Calendar reminders for certificate renewal +4. *Security audit* - Review the deployment with your security team +5. *Publish documentation* - Let users know how to verify your identity diff --git a/docs/DESIGN.adoc b/docs/DESIGN.adoc new file mode 100644 index 0000000..665692c --- /dev/null +++ b/docs/DESIGN.adoc @@ -0,0 +1,702 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2024 Hyperpolymath += Explicit Trust Plane: DNS-Published Cryptographic Identity System +:author: Hyperpolymath +:email: hyperpolymath@proton.me +:revnumber: 1.0.0 +:revdate: 2024-12-28 +:toc: left +:toclevels: 4 +:sectnums: +:icons: font +:source-highlighter: rouge +:experimental: + +== Executive Summary + +The *Explicit Trust Plane* is an architecture for publishing cryptographic identity materials via DNS, treating DNS as a decentralized public key infrastructure (PKI) rather than merely a naming system. + +This design enables: + +* Self-sovereign cryptographic identity +* No dependence on centralized key servers +* Algorithm-agile infrastructure ready for post-RSA migration +* Explicit separation of cryptographic roles (signing vs key exchange) +* Reproducible key generation and publication workflows + +== Design Principles + +=== Separation of Cryptographic Roles + +[cols="1,2,2"] +|=== +| Role | Purpose | Why Separate + +| *Digital Signatures* +| Authentication, integrity, non-repudiation +| Signing keys need long-term stability + +| *Key Exchange* +| Establishing shared secrets for encryption +| Key agreement requires ephemeral properties + +| *Human Identity* +| Email, web-of-trust, decentralized identity +| Different trust model than TLS +|=== + +IMPORTANT: These are *different cryptographic objects*, not one certificate "reused three ways." + +=== Algorithm Selection Rationale + +[cols="1,1,2,2"] +|=== +| Algorithm | Type | Use Case | Rationale + +| Ed448 +| Signature +| Long-term X.509 certificates +| 224-bit security level, post-quantum hedge + +| Ed25519 +| Signature +| Fast signing, PGP keys +| Widely supported, fast, 128-bit security + +| X25519 +| Key Exchange +| TLS 1.3, VPNs, ephemeral sessions +| Mandatory in modern TLS, distinct from Ed25519 + +| SHA-256+ +| Hash +| All cryptographic operations +| MD5/SHA1 prohibited per security policy +|=== + +=== Why Not RSA? + +RSA remains supported for legacy compatibility but is *not recommended* for new deployments: + +* Key sizes growing unsustainably (4096+ bits) +* Slower than elliptic curve alternatives +* Larger certificate and key sizes +* No forward secrecy without additional DHE + +== Architecture Overview + +[source] +---- +┌─────────────────────────────────────────────────────────────────┐ +│ EXPLICIT TRUST PLANE │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Ed448 │ │ Ed25519 │ │ X25519 │ │ +│ │ X.509 │ │ X.509 │ │ IPSECKEY │ │ +│ │ │ │ + PGP │ │ │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ DNS LAYER │ │ +│ │ ┌────────┐ ┌────────┐ ┌───────────┐ ┌───────────┐ │ │ +│ │ │ CERT │ │ CERT │ │ IPSECKEY │ │ TLSA │ │ │ +│ │ │ (X509) │ │ (PGP) │ │ │ │ (DANE) │ │ │ +│ │ └────────┘ └────────┘ └───────────┘ └───────────┘ │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ DNSSEC │ │ +│ │ (Mandatory for Production) │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +---- + +== Cryptographic Materials + +=== Certificate Hierarchy + +==== Root CA (Offline) + +* *Algorithm:* Ed448 +* *Validity:* 10 years +* *Storage:* Air-gapped, hardware security module (HSM) preferred +* *Purpose:* Sign intermediate certificates only + +==== Intermediate CA (Online) + +* *Algorithm:* Ed448 +* *Validity:* 2-5 years +* *Storage:* HSM or encrypted disk with restricted access +* *Purpose:* Sign end-entity certificates + +==== End-Entity Certificates + +[cols="1,1,1,2"] +|=== +| Certificate | Algorithm | Validity | Purpose + +| TLS Server +| Ed448 or Ed25519 +| 90 days - 1 year +| HTTPS authentication + +| Code Signing +| Ed448 +| 1-2 years +| Software authenticity + +| Email (S/MIME) +| Ed25519 +| 1 year +| Email encryption/signing + +| Client Auth +| Ed25519 +| 90 days +| Mutual TLS +|=== + +=== OpenPGP Keys + +[cols="1,1,2"] +|=== +| Key Type | Algorithm | Purpose + +| Primary +| Ed25519 +| Identity binding, certification + +| Signing Subkey +| Ed25519 +| Day-to-day signatures + +| Encryption Subkey +| cv25519 +| Email/file encryption +|=== + +=== Key Exchange Materials + +* *Algorithm:* X25519 +* *Purpose:* TLS 1.3 key agreement, VPN establishment +* *Published via:* IPSECKEY DNS record + +== DNS Record Types + +=== CERT Records (RFC 4398) + +[source,dns] +---- +; X.509 Certificate +_cert.example.com. IN CERT PKIX 0 0 + +; OpenPGP Key +_pgp.example.com. IN CERT PGP 0 0 +---- + +.CERT Record Format +[cols="1,3"] +|=== +| Field | Description + +| `PKIX` (1) +| X.509 certificate in DER format + +| `PGP` (3) +| OpenPGP public key packet + +| Key Tag +| 0 (unused for our purposes) + +| Algorithm +| 0 (algorithm encoded in certificate) +|=== + +=== IPSECKEY Records (RFC 4025) + +[source,dns] +---- +; X25519 Key Exchange Key +_ipsec.example.com. IN IPSECKEY 10 0 2 . +---- + +.IPSECKEY Record Format +[cols="1,3"] +|=== +| Field | Description + +| Precedence +| Priority (10 = typical) + +| Gateway Type +| 0 = no gateway + +| Algorithm +| 2 = DSA (placeholder, actual key is X25519) + +| Gateway +| `.` (no gateway) + +| Public Key +| Base64-encoded raw public key +|=== + +=== TLSA Records (RFC 6698 - DANE) + +[source,dns] +---- +; DANE TLS Certificate Association +_443._tcp.example.com. IN TLSA 3 1 1 +---- + +.TLSA Parameters +[cols="1,1,3"] +|=== +| Usage | Value | Meaning + +| 3 +| DANE-EE +| End entity certificate pinning + +| Selector +| 1 +| Subject Public Key Info (SPKI) + +| Matching Type +| 1 +| SHA-256 hash +|=== + +== Key Generation Procedures + +=== Prerequisites + +* OpenSSL 3.0+ (Ed448/Ed25519 support) +* GnuPG 2.2+ (modern ECC support) +* DNSSEC-enabled zone + +=== Ed448 Root CA + +[source,bash] +---- +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# Generate Ed448 Root CA + +set -euo pipefail + +DOMAIN="${1:-example.com}" +VALIDITY_DAYS="${2:-3650}" # 10 years + +# Generate private key +openssl genpkey -algorithm ED448 -out "ca-ed448.key" + +# Generate self-signed root certificate +openssl req -new -x509 \ + -key "ca-ed448.key" \ + -out "ca-ed448.crt" \ + -days "${VALIDITY_DAYS}" \ + -subj "/CN=${DOMAIN} Root CA/O=${DOMAIN}/C=US" \ + -addext "basicConstraints=critical,CA:TRUE" \ + -addext "keyUsage=critical,keyCertSign,cRLSign" \ + -addext "subjectKeyIdentifier=hash" + +# Verify +openssl x509 -in "ca-ed448.crt" -text -noout | head -20 + +echo "Generated: ca-ed448.key, ca-ed448.crt" +---- + +=== Ed25519 Server Certificate + +[source,bash] +---- +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# Generate Ed25519 Server Certificate + +set -euo pipefail + +DOMAIN="${1:-example.com}" + +# Generate private key +openssl genpkey -algorithm ED25519 -out "server-ed25519.key" + +# Generate CSR +openssl req -new \ + -key "server-ed25519.key" \ + -out "server-ed25519.csr" \ + -subj "/CN=${DOMAIN}/O=${DOMAIN}" + +# Self-sign for testing (in production, sign with CA) +openssl x509 -req \ + -in "server-ed25519.csr" \ + -signkey "server-ed25519.key" \ + -out "server-ed25519.crt" \ + -days 365 \ + -extfile <(printf "subjectAltName=DNS:%s,DNS:*.%s" "${DOMAIN}" "${DOMAIN}") + +echo "Generated: server-ed25519.key, server-ed25519.csr, server-ed25519.crt" +---- + +=== X25519 Key Exchange + +[source,bash] +---- +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# Generate X25519 Key Exchange Key + +set -euo pipefail + +# Generate private key +openssl genpkey -algorithm X25519 -out "x25519.key" + +# Extract public key (raw, for IPSECKEY) +openssl pkey -in "x25519.key" -pubout -outform DER | \ + tail -c 32 | base64 > "x25519.pub.b64" + +echo "Generated: x25519.key" +echo "Public key (Base64 for IPSECKEY):" +cat "x25519.pub.b64" +---- + +=== OpenPGP Key + +[source,bash] +---- +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# Generate modern OpenPGP key + +set -euo pipefail + +NAME="${1:-Example User}" +EMAIL="${2:-user@example.com}" + +# Generate key with Ed25519 primary + CV25519 encryption subkey +gpg --batch --generate-key < "${EMAIL}.pgp.b64" + +echo "Generated PGP key for ${EMAIL}" +echo "DNS record data in: ${EMAIL}.pgp.b64" +---- + +== DNS Zone Template + +[source,dns] +---- +; SPDX-License-Identifier: AGPL-3.0-or-later +; Explicit Trust Plane DNS Zone Template +; Replace and Base64 values with actual data + +$ORIGIN . +$TTL 3600 + +; ============================================================================= +; X.509 Certificates (CERT PKIX) +; ============================================================================= + +; Ed448 Root CA +_ca._cert IN CERT PKIX 0 0 ( + +) + +; Ed25519 Server Certificate +_server._cert IN CERT PKIX 0 0 ( + +) + +; ============================================================================= +; OpenPGP Keys (CERT PGP) +; ============================================================================= + +; Primary identity key +_pgp IN CERT PGP 0 0 ( + +) + +; Per-user keys (optional pattern) +user._pgpkey IN CERT PGP 0 0 ( + +) + +; ============================================================================= +; Key Exchange (IPSECKEY) +; ============================================================================= + +; X25519 for VPN/TLS key agreement +_ipsec IN IPSECKEY 10 0 2 . ( + +) + +; ============================================================================= +; DANE/TLSA +; ============================================================================= + +; HTTPS on port 443 +_443._tcp IN TLSA 3 1 1 ( + +) + +; SMTP on port 25 (MTA-STS) +_25._tcp.mail IN TLSA 3 1 1 ( + +) + +; ============================================================================= +; CAA (Certificate Authority Authorization) +; ============================================================================= + +@ IN CAA 0 issue "letsencrypt.org" +@ IN CAA 0 issuewild ";" +@ IN CAA 0 iodef "mailto:security@" +---- + +== Deployment Architecture + +=== Single-Repository Model (Recommended for Small Deployments) + +[source] +---- +explicit-trust-plane/ +├── ca/ +│ ├── root/ +│ │ ├── ca-ed448.key # OFFLINE - HSM +│ │ └── ca-ed448.crt +│ └── intermediate/ +│ ├── intermediate-ed448.key +│ └── intermediate-ed448.crt +├── certs/ +│ ├── server-ed25519.key +│ ├── server-ed25519.crt +│ └── server-ed25519.crt.der # For DNS CERT +├── pgp/ +│ ├── primary.pgp # ASCII armored +│ └── primary.pgp.b64 # For DNS CERT +├── kex/ +│ ├── x25519.key +│ └── x25519.pub.b64 # For IPSECKEY +├── dns/ +│ ├── zone.template +│ └── records/ +│ ├── cert.zone +│ ├── tlsa.zone +│ └── ipseckey.zone +├── scripts/ +│ ├── generate-ca.sh +│ ├── generate-cert.sh +│ ├── generate-pgp.sh +│ ├── generate-kex.sh +│ ├── export-dns.sh +│ └── rotate-keys.sh +└── docs/ + ├── DESIGN.adoc # This document + ├── DEPLOYMENT.adoc # Deployment guide + └── ROTATION.adoc # Key rotation procedures +---- + +=== Multi-Repository Model (Recommended for Organizations) + +|=== +| Repository | Contents | Access + +| `trust-plane-ca` +| Root and intermediate CA materials +| Highly restricted + +| `trust-plane-certs` +| End-entity certificates +| Operations team + +| `trust-plane-pgp` +| OpenPGP keyrings +| Identity administrators + +| `trust-plane-dns` +| DNS zone files and automation +| DNS operators +|=== + +== Security Considerations + +=== DNSSEC Requirement + +CAUTION: Without DNSSEC, DNS-published keys can be spoofed via cache poisoning. + +All DNS zones publishing cryptographic material *must* be DNSSEC-signed. + +=== Key Storage + +[cols="1,1,2"] +|=== +| Material | Storage | Notes + +| Root CA private key +| Air-gapped HSM +| Never on networked systems + +| Intermediate CA key +| HSM or encrypted disk +| Limited operator access + +| Server private keys +| Encrypted at rest +| Auto-rotation recommended + +| PGP primary key +| Offline backup + smartcard +| Subkeys for daily use + +| X25519 private key +| Encrypted, ephemeral preferred +| Generate fresh for each session +|=== + +=== Rotation Schedule + +[cols="1,1,2"] +|=== +| Material | Rotation Interval | Trigger Events + +| Root CA +| 10 years +| Compromise only + +| Intermediate CA +| 2-5 years +| Annual review + +| Server certificates +| 90 days - 1 year +| Let's Encrypt cadence + +| PGP subkeys +| 1-2 years +| Proactive rotation + +| X25519 keys +| Session-based +| Each connection +|=== + +== Validation and Testing + +=== Verify CERT Records + +[source,bash] +---- +# Query CERT record +dig +short CERT _cert.example.com + +# Decode and verify certificate +dig +short CERT _cert.example.com | base64 -d | openssl x509 -inform DER -text -noout +---- + +=== Verify TLSA Records + +[source,bash] +---- +# Query TLSA +dig +short TLSA _443._tcp.example.com + +# Verify with openssl +openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \ + openssl x509 -pubkey -noout | \ + openssl pkey -pubin -outform DER | \ + sha256sum +---- + +=== Verify IPSECKEY Records + +[source,bash] +---- +# Query IPSECKEY +dig +short IPSECKEY _ipsec.example.com +---- + +== Future Considerations + +=== Post-Quantum Readiness + +The current design uses Ed448 for long-term certificates as a hedge against quantum computers. When NIST post-quantum standards mature: + +* CRYSTALS-Dilithium for signatures +* CRYSTALS-Kyber for key exchange +* Hybrid schemes during transition + +=== DMARC/DKIM Integration + +Email authentication via DKIM can publish keys using: + +* `selector._domainkey.example.com TXT "v=DKIM1; k=ed25519; p=..."` + +This integrates naturally with the Explicit Trust Plane model. + +== References + +* RFC 4398 - Storing Certificates in the DNS +* RFC 4025 - A Method for Storing IPsec Keying Material in DNS +* RFC 6698 - DNS-Based Authentication of Named Entities (DANE) +* RFC 8461 - SMTP MTA Strict Transport Security (MTA-STS) +* RFC 8032 - Edwards-Curve Digital Signature Algorithm (EdDSA) +* RFC 7748 - Elliptic Curves for Security (X25519, X448) + +== Appendix A: Quick Reference Card + +[source] +---- +╔════════════════════════════════════════════════════════════════════╗ +║ EXPLICIT TRUST PLANE - QUICK REFERENCE ║ +╠════════════════════════════════════════════════════════════════════╣ +║ ║ +║ PURPOSE ALGORITHM DNS RECORD TYPE ║ +║ ───────────────────────────────────────────────────────────────── ║ +║ Long-term signing Ed448 CERT PKIX (X.509) ║ +║ Fast signing Ed25519 CERT PKIX/PGP ║ +║ Key exchange X25519 IPSECKEY ║ +║ TLS pinning - TLSA ║ +║ Human identity Ed25519+cv25519 CERT PGP ║ +║ ║ +║ MINIMUM VIABLE SET: ║ +║ • 1× Ed448 Root CA (offline) ║ +║ • 1× Ed25519 Server Cert (TLS) ║ +║ • 1× X25519 Key Exchange (TLS 1.3) ║ +║ • 1× OpenPGP Ed25519 (identity) ║ +║ ║ +║ SECURITY REQUIREMENTS: ║ +║ ✓ DNSSEC mandatory ║ +║ ✓ No MD5/SHA1 ║ +║ ✓ HTTPS only ║ +║ ✓ HSM for CA keys ║ +║ ║ +╚════════════════════════════════════════════════════════════════════╝ +---- + +== Appendix B: Glossary + +CA:: Certificate Authority +DANE:: DNS-Based Authentication of Named Entities +DNSSEC:: DNS Security Extensions +HSM:: Hardware Security Module +IPSECKEY:: IPsec Key DNS record type +PKIX:: Public Key Infrastructure (X.509) +SPKI:: Subject Public Key Info +TLSA:: TLS Authentication DNS record type diff --git a/justfile b/justfile index 0e12d43..2fb9261 100644 --- a/justfile +++ b/justfile @@ -1,21 +1,17 @@ -# RSR-template-repo - RSR Standard Justfile Template +# Explicit Trust Plane - DNS-Published Cryptographic Identity # https://just.systems/man/en/ # -# This is the CANONICAL template for all RSR projects. -# Copy this file to new projects and customize the {{PLACEHOLDER}} values. -# # Run `just` to see all available recipes -# Run `just cookbook` to generate docs/just-cookbook.adoc -# Run `just combinations` to see matrix recipe options +# Run `just generate example.com` to generate all crypto materials set shell := ["bash", "-uc"] set dotenv-load := true set positional-arguments := true -# Project metadata - CUSTOMIZE THESE -project := "RSR-template-repo" -version := "0.1.0" -tier := "infrastructure" # 1 | 2 | infrastructure +# Project metadata +project := "explicit-trust-plane" +version := "1.0.0" +tier := "infrastructure" # ═══════════════════════════════════════════════════════════════════════════════ # DEFAULT & HELP @@ -50,31 +46,51 @@ info: # BUILD & COMPILE # ═══════════════════════════════════════════════════════════════════════════════ -# Build the project (debug mode) -build *args: - @echo "Building {{project}}..." - # TODO: Add build command for your language - # Rust: cargo build {{args}} - # ReScript: npm run build - # Elixir: mix compile - -# Build in release mode with optimizations -build-release *args: - @echo "Building {{project}} (release)..." - # TODO: Add release build command - # Rust: cargo build --release {{args}} - -# Build and watch for changes -build-watch: - @echo "Watching for changes..." - # TODO: Add watch command - # Rust: cargo watch -x build - # ReScript: npm run watch - -# Clean build artifacts [reversible: rebuild with `just build`] +# Generate all cryptographic materials for a domain +generate domain: + @echo "Generating all crypto materials for {{domain}}..." + ./scripts/generate-ca.sh "{{domain}}" + ./scripts/generate-cert.sh "{{domain}}" + ./scripts/generate-kex.sh "{{domain}}" + ./scripts/export-dns.sh "{{domain}}" + @echo "" + @echo "Done! See dns/records/{{domain}}.zone for DNS records" + +# Generate CA only +generate-ca domain: + ./scripts/generate-ca.sh "{{domain}}" + +# Generate server certificate only +generate-cert domain: + ./scripts/generate-cert.sh "{{domain}}" + +# Generate key exchange key only +generate-kex domain: + ./scripts/generate-kex.sh "{{domain}}" + +# Generate OpenPGP key +generate-pgp name email: + ./scripts/generate-pgp.sh "{{name}}" "{{email}}" + +# Export DNS records +export-dns domain: + ./scripts/export-dns.sh "{{domain}}" + +# Rotate keys with backup +rotate domain keytype="all": + ./scripts/rotate-keys.sh "{{domain}}" "{{keytype}}" + +# Clean generated materials [destructive!] clean: - @echo "Cleaning..." - rm -rf target _build dist lib node_modules + @echo "Cleaning generated materials..." + rm -rf ca/root/*.key ca/root/*.crt ca/root/*.der ca/root/*.b64 ca/root/*.srl + rm -rf ca/intermediate/*.key ca/intermediate/*.crt ca/intermediate/*.csr ca/intermediate/*.der ca/intermediate/*.b64 ca/intermediate/*.srl + rm -rf certs/*.key certs/*.crt certs/*.csr certs/*.der certs/*.b64 + rm -rf pgp/*.asc pgp/*.pgp pgp/*.b64 + rm -rf kex/*.key kex/*.pub kex/*.raw kex/*.b64 + rm -rf dns/records/*.zone + rm -rf backup/ + @echo "Cleaned. .gitkeep files preserved." # Deep clean including caches [reversible: rebuild] clean-all: clean diff --git a/kex/.gitkeep b/kex/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pgp/.gitkeep b/pgp/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/export-dns.sh b/scripts/export-dns.sh new file mode 100755 index 0000000..f1d94ea --- /dev/null +++ b/scripts/export-dns.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# export-dns.sh - Export all cryptographic materials as DNS zone records +# +# Usage: ./export-dns.sh + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly DNS_DIR="${PROJECT_ROOT}/dns" +readonly RECORDS_DIR="${DNS_DIR}/records" + +DOMAIN="${1:-example.com}" +TIMESTAMP=$(date -Iseconds) + +echo "=== Explicit Trust Plane - DNS Export ===" +echo "Domain: ${DOMAIN}" +echo "Timestamp: ${TIMESTAMP}" +echo "" + +mkdir -p "${RECORDS_DIR}" + +# Sanitize domain +SAFE_DOMAIN="${DOMAIN//\*/_wildcard_}" + +# --- Header --- +cat > "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" <> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; X.509 Certificates (CERT PKIX)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + +# Root CA +if [[ -f "${PROJECT_ROOT}/ca/root/ca-ed448.crt.b64" ]]; then + echo "; Root CA Certificate (Ed448)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "_ca._cert IN CERT PKIX 0 0 (" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + fold -w 64 < "${PROJECT_ROOT}/ca/root/ca-ed448.crt.b64" | sed 's/^/ /' >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo ")" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +fi + +# Intermediate CA +if [[ -f "${PROJECT_ROOT}/ca/intermediate/intermediate-ed448.crt.b64" ]]; then + echo "; Intermediate CA Certificate (Ed448)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "_intermediate._cert IN CERT PKIX 0 0 (" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + fold -w 64 < "${PROJECT_ROOT}/ca/intermediate/intermediate-ed448.crt.b64" | sed 's/^/ /' >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo ")" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +fi + +# Server certificate +if [[ -f "${PROJECT_ROOT}/certs/${SAFE_DOMAIN}.crt.b64" ]]; then + echo "; Server Certificate (Ed25519)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "_server._cert IN CERT PKIX 0 0 (" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + fold -w 64 < "${PROJECT_ROOT}/certs/${SAFE_DOMAIN}.crt.b64" | sed 's/^/ /' >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo ")" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +fi + +# --- CERT Records (PGP) --- +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; OpenPGP Keys (CERT PGP)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + +for pgp_file in "${PROJECT_ROOT}/pgp/"*.pgp.b64; do + if [[ -f "${pgp_file}" ]]; then + filename=$(basename "${pgp_file}" .pgp.b64) + echo "; PGP Key: ${filename}" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "_pgp IN CERT PGP 0 0 (" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + fold -w 64 < "${pgp_file}" | sed 's/^/ /' >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo ")" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + fi +done + +# --- IPSECKEY Records --- +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; Key Exchange (IPSECKEY)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + +if [[ -f "${PROJECT_ROOT}/kex/${SAFE_DOMAIN}.x25519.pub.b64" ]]; then + echo "; X25519 Key Exchange" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + PUBKEY=$(cat "${PROJECT_ROOT}/kex/${SAFE_DOMAIN}.x25519.pub.b64") + echo "_ipsec IN IPSECKEY 10 0 2 . ${PUBKEY}" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +fi + +# --- TLSA Records --- +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; DANE/TLSA Records" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + +if [[ -f "${PROJECT_ROOT}/certs/${SAFE_DOMAIN}.crt" ]]; then + TLSA_HASH=$(openssl x509 -in "${PROJECT_ROOT}/certs/${SAFE_DOMAIN}.crt" -noout -pubkey 2>/dev/null | openssl pkey -pubin -outform DER 2>/dev/null | sha256sum | cut -d' ' -f1) + echo "; DANE-EE TLSA for HTTPS (port 443)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "_443._tcp IN TLSA 3 1 1 ${TLSA_HASH}" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +fi + +# --- CAA Records --- +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; Certificate Authority Authorization (CAA)" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "; ==============================================================================" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "@ IN CAA 0 issue \"letsencrypt.org\"" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "@ IN CAA 0 issuewild \";\"" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "@ IN CAA 0 iodef \"mailto:security@${DOMAIN}\"" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" >> "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" + +echo "=== DNS Export Complete ===" +echo "" +echo "Zone file: ${RECORDS_DIR}/${SAFE_DOMAIN}.zone" +echo "" +echo "Record types included:" +grep -c "IN CERT" "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" 2>/dev/null | xargs -I{} echo " CERT: {} records" +grep -c "IN IPSECKEY" "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" 2>/dev/null | xargs -I{} echo " IPSECKEY: {} records" +grep -c "IN TLSA" "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" 2>/dev/null | xargs -I{} echo " TLSA: {} records" +grep -c "IN CAA" "${RECORDS_DIR}/${SAFE_DOMAIN}.zone" 2>/dev/null | xargs -I{} echo " CAA: {} records" +echo "" +echo "IMPORTANT: Enable DNSSEC before deploying these records!" diff --git a/scripts/generate-ca.sh b/scripts/generate-ca.sh new file mode 100755 index 0000000..26a702b --- /dev/null +++ b/scripts/generate-ca.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# generate-ca.sh - Generate Ed448 Root and Intermediate Certificate Authorities +# +# Usage: ./generate-ca.sh [root-validity-days] [intermediate-validity-days] + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly CA_DIR="${PROJECT_ROOT}/ca" + +DOMAIN="${1:-example.com}" +ROOT_VALIDITY="${2:-3650}" # 10 years +INTER_VALIDITY="${3:-1825}" # 5 years + +echo "=== Explicit Trust Plane - CA Generation ===" +echo "Domain: ${DOMAIN}" +echo "Root validity: ${ROOT_VALIDITY} days" +echo "Intermediate validity: ${INTER_VALIDITY} days" +echo "" + +# --- Root CA --- +echo "[1/4] Generating Ed448 Root CA private key..." +mkdir -p "${CA_DIR}/root" +openssl genpkey -algorithm ED448 -out "${CA_DIR}/root/ca-ed448.key" +chmod 600 "${CA_DIR}/root/ca-ed448.key" + +echo "[2/4] Generating Root CA certificate..." +openssl req -new -x509 \ + -key "${CA_DIR}/root/ca-ed448.key" \ + -out "${CA_DIR}/root/ca-ed448.crt" \ + -days "${ROOT_VALIDITY}" \ + -subj "/CN=${DOMAIN} Root CA/O=${DOMAIN}/C=US" \ + -addext "basicConstraints=critical,CA:TRUE,pathlen:1" \ + -addext "keyUsage=critical,keyCertSign,cRLSign" \ + -addext "subjectKeyIdentifier=hash" + +# --- Intermediate CA --- +echo "[3/4] Generating Ed448 Intermediate CA private key..." +mkdir -p "${CA_DIR}/intermediate" +openssl genpkey -algorithm ED448 -out "${CA_DIR}/intermediate/intermediate-ed448.key" +chmod 600 "${CA_DIR}/intermediate/intermediate-ed448.key" + +echo "[4/4] Generating Intermediate CA certificate..." +# Create CSR for intermediate +openssl req -new \ + -key "${CA_DIR}/intermediate/intermediate-ed448.key" \ + -out "${CA_DIR}/intermediate/intermediate-ed448.csr" \ + -subj "/CN=${DOMAIN} Intermediate CA/O=${DOMAIN}/C=US" + +# Sign intermediate with root +openssl x509 -req \ + -in "${CA_DIR}/intermediate/intermediate-ed448.csr" \ + -CA "${CA_DIR}/root/ca-ed448.crt" \ + -CAkey "${CA_DIR}/root/ca-ed448.key" \ + -CAcreateserial \ + -out "${CA_DIR}/intermediate/intermediate-ed448.crt" \ + -days "${INTER_VALIDITY}" \ + -extfile <(printf "basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid:always") + +# Create certificate chain +cat "${CA_DIR}/intermediate/intermediate-ed448.crt" "${CA_DIR}/root/ca-ed448.crt" > "${CA_DIR}/intermediate/chain.crt" + +# Export DER for DNS CERT records +openssl x509 -in "${CA_DIR}/root/ca-ed448.crt" -outform DER -out "${CA_DIR}/root/ca-ed448.crt.der" +openssl x509 -in "${CA_DIR}/intermediate/intermediate-ed448.crt" -outform DER -out "${CA_DIR}/intermediate/intermediate-ed448.crt.der" + +# Create Base64 for DNS +base64 -w0 < "${CA_DIR}/root/ca-ed448.crt.der" > "${CA_DIR}/root/ca-ed448.crt.b64" +base64 -w0 < "${CA_DIR}/intermediate/intermediate-ed448.crt.der" > "${CA_DIR}/intermediate/intermediate-ed448.crt.b64" + +echo "" +echo "=== CA Generation Complete ===" +echo "" +echo "Root CA:" +echo " Private key: ${CA_DIR}/root/ca-ed448.key (KEEP OFFLINE!)" +echo " Certificate: ${CA_DIR}/root/ca-ed448.crt" +echo " DNS (Base64): ${CA_DIR}/root/ca-ed448.crt.b64" +echo "" +echo "Intermediate CA:" +echo " Private key: ${CA_DIR}/intermediate/intermediate-ed448.key" +echo " Certificate: ${CA_DIR}/intermediate/intermediate-ed448.crt" +echo " Chain: ${CA_DIR}/intermediate/chain.crt" +echo " DNS (Base64): ${CA_DIR}/intermediate/intermediate-ed448.crt.b64" +echo "" +echo "Root CA fingerprint (SHA256):" +openssl x509 -in "${CA_DIR}/root/ca-ed448.crt" -noout -fingerprint -sha256 +echo "" + +echo "SECURITY REMINDER:" +echo " - Move ca-ed448.key to offline/HSM storage immediately" +echo " - Never store root CA key on networked systems" diff --git a/scripts/generate-cert.sh b/scripts/generate-cert.sh new file mode 100755 index 0000000..636723c --- /dev/null +++ b/scripts/generate-cert.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# generate-cert.sh - Generate Ed25519 Server Certificate +# +# Usage: ./generate-cert.sh [validity-days] [--self-signed] + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly CERTS_DIR="${PROJECT_ROOT}/certs" +readonly CA_DIR="${PROJECT_ROOT}/ca" + +DOMAIN="${1:-example.com}" +VALIDITY="${2:-365}" +SELF_SIGNED="${3:-}" + +echo "=== Explicit Trust Plane - Server Certificate Generation ===" +echo "Domain: ${DOMAIN}" +echo "Validity: ${VALIDITY} days" +echo "" + +mkdir -p "${CERTS_DIR}" + +# Sanitize domain for filename +SAFE_DOMAIN="${DOMAIN//\*/_wildcard_}" + +echo "[1/3] Generating Ed25519 private key..." +openssl genpkey -algorithm ED25519 -out "${CERTS_DIR}/${SAFE_DOMAIN}.key" +chmod 600 "${CERTS_DIR}/${SAFE_DOMAIN}.key" + +echo "[2/3] Generating Certificate Signing Request..." +openssl req -new \ + -key "${CERTS_DIR}/${SAFE_DOMAIN}.key" \ + -out "${CERTS_DIR}/${SAFE_DOMAIN}.csr" \ + -subj "/CN=${DOMAIN}/O=${DOMAIN}" + +echo "[3/3] Signing certificate..." +if [[ "${SELF_SIGNED}" == "--self-signed" ]] || [[ ! -f "${CA_DIR}/intermediate/intermediate-ed448.crt" ]]; then + echo " (Self-signing - no CA available or --self-signed specified)" + openssl x509 -req \ + -in "${CERTS_DIR}/${SAFE_DOMAIN}.csr" \ + -signkey "${CERTS_DIR}/${SAFE_DOMAIN}.key" \ + -out "${CERTS_DIR}/${SAFE_DOMAIN}.crt" \ + -days "${VALIDITY}" \ + -extfile <(printf "subjectAltName=DNS:%s,DNS:*.%s\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=serverAuth,clientAuth" "${DOMAIN}" "${DOMAIN}") +else + echo " (Signing with Intermediate CA)" + openssl x509 -req \ + -in "${CERTS_DIR}/${SAFE_DOMAIN}.csr" \ + -CA "${CA_DIR}/intermediate/intermediate-ed448.crt" \ + -CAkey "${CA_DIR}/intermediate/intermediate-ed448.key" \ + -CAcreateserial \ + -out "${CERTS_DIR}/${SAFE_DOMAIN}.crt" \ + -days "${VALIDITY}" \ + -extfile <(printf "subjectAltName=DNS:%s,DNS:*.%s\nkeyUsage=critical,digitalSignature\nextendedKeyUsage=serverAuth,clientAuth\nauthorityKeyIdentifier=keyid:always" "${DOMAIN}" "${DOMAIN}") + + # Create full chain + cat "${CERTS_DIR}/${SAFE_DOMAIN}.crt" "${CA_DIR}/intermediate/chain.crt" > "${CERTS_DIR}/${SAFE_DOMAIN}.fullchain.crt" +fi + +# Export DER for DNS CERT records +openssl x509 -in "${CERTS_DIR}/${SAFE_DOMAIN}.crt" -outform DER -out "${CERTS_DIR}/${SAFE_DOMAIN}.crt.der" +base64 -w0 < "${CERTS_DIR}/${SAFE_DOMAIN}.crt.der" > "${CERTS_DIR}/${SAFE_DOMAIN}.crt.b64" + +# Generate TLSA record data +echo "" +echo "=== Certificate Generation Complete ===" +echo "" +echo "Files generated:" +echo " Private key: ${CERTS_DIR}/${SAFE_DOMAIN}.key" +echo " Certificate: ${CERTS_DIR}/${SAFE_DOMAIN}.crt" +echo " CSR: ${CERTS_DIR}/${SAFE_DOMAIN}.csr" +echo " DER: ${CERTS_DIR}/${SAFE_DOMAIN}.crt.der" +echo " DNS (Base64): ${CERTS_DIR}/${SAFE_DOMAIN}.crt.b64" + +if [[ -f "${CERTS_DIR}/${SAFE_DOMAIN}.fullchain.crt" ]]; then + echo " Full chain: ${CERTS_DIR}/${SAFE_DOMAIN}.fullchain.crt" +fi + +echo "" +echo "Certificate details:" +openssl x509 -in "${CERTS_DIR}/${SAFE_DOMAIN}.crt" -noout -subject -issuer -dates + +echo "" +echo "TLSA Record (3 1 1 - DANE-EE, SPKI, SHA-256):" +echo "_443._tcp.${DOMAIN}. IN TLSA 3 1 1 $(openssl x509 -in "${CERTS_DIR}/${SAFE_DOMAIN}.crt" -noout -pubkey | openssl pkey -pubin -outform DER | sha256sum | cut -d' ' -f1)" + +echo "" +echo "CERT Record (PKIX):" +echo "_cert.${DOMAIN}. IN CERT PKIX 0 0 $(cat "${CERTS_DIR}/${SAFE_DOMAIN}.crt.b64")" diff --git a/scripts/generate-kex.sh b/scripts/generate-kex.sh new file mode 100755 index 0000000..7d47343 --- /dev/null +++ b/scripts/generate-kex.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# generate-kex.sh - Generate X25519 Key Exchange Key +# +# Usage: ./generate-kex.sh + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly KEX_DIR="${PROJECT_ROOT}/kex" + +DOMAIN="${1:-example.com}" + +echo "=== Explicit Trust Plane - X25519 Key Exchange Generation ===" +echo "Domain: ${DOMAIN}" +echo "" + +mkdir -p "${KEX_DIR}" + +# Sanitize domain for filename +SAFE_DOMAIN="${DOMAIN//\*/_wildcard_}" + +echo "[1/3] Generating X25519 private key..." +openssl genpkey -algorithm X25519 -out "${KEX_DIR}/${SAFE_DOMAIN}.x25519.key" +chmod 600 "${KEX_DIR}/${SAFE_DOMAIN}.x25519.key" + +echo "[2/3] Extracting public key..." +openssl pkey -in "${KEX_DIR}/${SAFE_DOMAIN}.x25519.key" -pubout -out "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub" + +# Extract raw 32-byte public key for IPSECKEY record +# X25519 public key in DER format has a 12-byte header, so we take the last 32 bytes +openssl pkey -in "${KEX_DIR}/${SAFE_DOMAIN}.x25519.key" -pubout -outform DER | tail -c 32 > "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.raw" + +echo "[3/3] Preparing DNS record data..." +base64 -w0 < "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.raw" > "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.b64" + +echo "" +echo "=== Key Exchange Generation Complete ===" +echo "" +echo "Files generated:" +echo " Private key: ${KEX_DIR}/${SAFE_DOMAIN}.x25519.key" +echo " Public key: ${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub" +echo " Raw public key: ${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.raw" +echo " DNS (Base64): ${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.b64" + +echo "" +echo "Public key (Base64, 32 bytes):" +cat "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.b64" +echo "" + +echo "" +echo "Public key (Hex):" +xxd -p < "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.raw" | tr -d '\n' +echo "" + +echo "" +echo "=== DNS Record ===" +echo "" +echo "IPSECKEY Record:" +echo "_ipsec.${DOMAIN}. IN IPSECKEY 10 0 2 . $(cat "${KEX_DIR}/${SAFE_DOMAIN}.x25519.pub.b64")" +echo "" +echo "Note: Algorithm '2' is a placeholder. X25519 is identified by the key format." +echo "" +echo "SECURITY NOTE:" +echo " X25519 keys for key exchange should ideally be ephemeral." +echo " This static key is suitable for:" +echo " - IPsec VPN discovery" +echo " - Initial key agreement bootstrap" +echo " - Out-of-band key verification" +echo " For TLS 1.3, ephemeral X25519 keys are generated per-session." diff --git a/scripts/generate-pgp.sh b/scripts/generate-pgp.sh new file mode 100755 index 0000000..175e004 --- /dev/null +++ b/scripts/generate-pgp.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# generate-pgp.sh - Generate Modern OpenPGP Key (Ed25519 + CV25519) +# +# Usage: ./generate-pgp.sh "Real Name" "email@example.com" [expiry] + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly PGP_DIR="${PROJECT_ROOT}/pgp" + +NAME="${1:-Example User}" +EMAIL="${2:-user@example.com}" +EXPIRY="${3:-2y}" + +echo "=== Explicit Trust Plane - OpenPGP Key Generation ===" +echo "Name: ${NAME}" +echo "Email: ${EMAIL}" +echo "Expiry: ${EXPIRY}" +echo "" + +mkdir -p "${PGP_DIR}" + +# Sanitize email for filename +SAFE_EMAIL="${EMAIL//@/_at_}" +SAFE_EMAIL="${SAFE_EMAIL//./_}" + +# Check if key already exists +if gpg --list-keys "${EMAIL}" &>/dev/null; then + echo "WARNING: Key for ${EMAIL} already exists!" + echo "Delete it first with: gpg --delete-secret-and-public-key ${EMAIL}" + exit 1 +fi + +echo "[1/4] Generating Ed25519 primary key with CV25519 encryption subkey..." + +# Generate key batch +gpg --batch --generate-key < "${PGP_DIR}/${SAFE_EMAIL}.asc" +gpg --export "${EMAIL}" > "${PGP_DIR}/${SAFE_EMAIL}.pgp" + +echo "[4/4] Preparing DNS record data..." +base64 -w0 < "${PGP_DIR}/${SAFE_EMAIL}.pgp" > "${PGP_DIR}/${SAFE_EMAIL}.pgp.b64" + +# Generate WKD hash +LOCAL_PART="${EMAIL%%@*}" +WKD_HASH=$(printf '%s' "${LOCAL_PART}" | sha1sum | cut -c1-40 | xxd -r -p | base32 | tr 'A-Z' 'a-z' | tr -d '=') + +echo "" +echo "=== OpenPGP Key Generation Complete ===" +echo "" +echo "Key fingerprint:" +gpg --fingerprint "${EMAIL}" + +echo "" +echo "Files generated:" +echo " ASCII armor: ${PGP_DIR}/${SAFE_EMAIL}.asc" +echo " Binary: ${PGP_DIR}/${SAFE_EMAIL}.pgp" +echo " DNS (Base64): ${PGP_DIR}/${SAFE_EMAIL}.pgp.b64" + +echo "" +echo "Key structure:" +gpg --list-keys --with-subkey-fingerprints "${EMAIL}" + +echo "" +echo "=== DNS Records ===" +echo "" +echo "CERT Record (PGP):" +echo "_pgp.${EMAIL#*@}. IN CERT PGP 0 0 $(cat "${PGP_DIR}/${SAFE_EMAIL}.pgp.b64")" + +echo "" +echo "Alternative: OPENPGPKEY Record (RFC 7929):" +DOMAIN_PART="${EMAIL#*@}" +echo "${WKD_HASH}._openpgpkey.${DOMAIN_PART}. IN OPENPGPKEY $(cat "${PGP_DIR}/${SAFE_EMAIL}.pgp.b64")" + +echo "" +echo "WKD Path (Web Key Directory):" +echo "https://${DOMAIN_PART}/.well-known/openpgpkey/hu/${WKD_HASH}" + +echo "" +echo "SECURITY REMINDER:" +echo " - Back up your private key securely" +echo " - Consider using a hardware token (YubiKey, etc.)" +echo " - The primary key should be kept offline; use subkeys for daily operations" diff --git a/scripts/rotate-keys.sh b/scripts/rotate-keys.sh new file mode 100755 index 0000000..f26f7cb --- /dev/null +++ b/scripts/rotate-keys.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: AGPL-3.0-or-later +# SPDX-FileCopyrightText: 2024 Hyperpolymath +# +# rotate-keys.sh - Automated key rotation with backup +# +# Usage: ./rotate-keys.sh +# key-type: cert | kex | all + +set -euo pipefail + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" +readonly BACKUP_DIR="${PROJECT_ROOT}/backup" + +DOMAIN="${1:-example.com}" +KEY_TYPE="${2:-all}" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) + +echo "=== Explicit Trust Plane - Key Rotation ===" +echo "Domain: ${DOMAIN}" +echo "Key type: ${KEY_TYPE}" +echo "Timestamp: ${TIMESTAMP}" +echo "" + +# Sanitize domain +SAFE_DOMAIN="${DOMAIN//\*/_wildcard_}" + +# Create backup directory +mkdir -p "${BACKUP_DIR}/${TIMESTAMP}" + +backup_and_rotate_cert() { + echo "[CERT] Rotating server certificate..." + + if [[ -f "${PROJECT_ROOT}/certs/${SAFE_DOMAIN}.key" ]]; then + echo " Backing up existing certificate..." + cp -r "${PROJECT_ROOT}/certs" "${BACKUP_DIR}/${TIMESTAMP}/certs" + fi + + echo " Generating new certificate..." + "${SCRIPT_DIR}/generate-cert.sh" "${DOMAIN}" + + echo " [CERT] Rotation complete" +} + +backup_and_rotate_kex() { + echo "[KEX] Rotating X25519 key exchange key..." + + if [[ -f "${PROJECT_ROOT}/kex/${SAFE_DOMAIN}.x25519.key" ]]; then + echo " Backing up existing key..." + cp -r "${PROJECT_ROOT}/kex" "${BACKUP_DIR}/${TIMESTAMP}/kex" + fi + + echo " Generating new key..." + "${SCRIPT_DIR}/generate-kex.sh" "${DOMAIN}" + + echo " [KEX] Rotation complete" +} + +case "${KEY_TYPE}" in + cert) + backup_and_rotate_cert + ;; + kex) + backup_and_rotate_kex + ;; + all) + backup_and_rotate_cert + echo "" + backup_and_rotate_kex + ;; + *) + echo "ERROR: Unknown key type '${KEY_TYPE}'" + echo "Usage: $0 [cert|kex|all]" + exit 1 + ;; +esac + +echo "" +echo "=== Key Rotation Complete ===" +echo "" +echo "Backup location: ${BACKUP_DIR}/${TIMESTAMP}/" +echo "" +echo "NEXT STEPS:" +echo " 1. Run: ./export-dns.sh ${DOMAIN}" +echo " 2. Update DNS records with new values" +echo " 3. Deploy new certificates to servers" +echo " 4. Verify with: dig CERT _cert.${DOMAIN}" +echo " 5. Test TLS: openssl s_client -connect ${DOMAIN}:443" +echo "" +echo "SECURITY REMINDER:" +echo " - Old keys in backup should be securely deleted after verification" +echo " - Ensure new DNS records propagate before switching servers"