Skip to content

LastVet Hybrid Post-Quantum TLS Posture

Status: Implemented (August 2026)
Related: POSTURE.md, ../architecture/COX_STATIC_IP_INGRESS.md

Introduction

This document describes LastVet's hybrid post-quantum (PQ) Transport Layer Security configuration at the public API edge. It is written for security engineers and compliance auditors evaluating how LastVet protects veteran and provider traffic against long-horizon adversaries.

Public HTTPS for api.last.vet and api-staging.last.vet terminates on Caddy 2.11 on lastvet-edge (192.168.1.89). Cloudflare provides authoritative DNS only (grey-cloud, not proxied). No third-party CDN terminates TLS on API hostnames.

Threat model addressed

Harvest now, decrypt later

State-level and well-resourced adversaries can passively record encrypted TLS traffic today and attempt decryption when cryptographically relevant quantum computers exist. Classical ECDH key exchange (e.g., X25519 alone) provides no protection against this future threat: recorded handshake material could be broken retroactively.

Hybrid key exchange mitigates this by combining a classical Diffie-Hellman group with a post-quantum KEM so that breaking the session key requires defeating both primitives.

What this change does not address

Gap Notes
TLS certificate signatures Let's Encrypt certificates remain ECDSA P-256. PQ signature migration (ML-DSA) awaits ACME ecosystem maturity
Application-layer auth JWT validation, consent checks, and RLS are unchanged
East-west TLS Postgres and MinIO TLS posture are separate documents
Compromised endpoint Host or process compromise bypasses transport encryption

What was implemented

Item Detail
Hybrid key exchange X25519 + ML-KEM-768 (X25519MLKEM768 in Go TLS / IETF hybrid construction)
Hostnames api.last.vet (production), api-staging.last.vet (staging)
TLS version TLS 1.3
Fallback Clients without PQ support negotiate classical X25519
Edge software Caddy v2.11.4 (Go 1.26.3) on lastvet-edge
Explicit curve list x25519mlkem768 x25519 secp256r1 secp384r1 in each site tls block

Canonical config: ../infra/lastvet-edge/Caddyfile (live copy at /etc/caddy/Caddyfile on lastvet-edge).

Architecture

Client (Chrome/Safari/iOS/curl)
    │  TLS 1.3 handshake
    │  Preferred: X25519MLKEM768 (hybrid)
    │  Fallback:  X25519 (classical)
Caddy on lastvet-edge :443
    │  Let's Encrypt cert (ECDSA P-256)
    │  Reverse proxy (plaintext HTTP to origin)
lastvet-api :3001 (prod) / :3000 (staging)

Cryptographic choices

Hybrid design rationale

Hybrid TLS combines:

  1. X25519 — mature classical elliptic-curve Diffie-Hellman (128-bit classical security).
  2. ML-KEM-768 — NIST-standardized post-quantum KEM (FIPS 203, August 2024).

If either primitive is broken independently, the other still contributes key material to the TLS 1.3 key schedule. This follows the hybrid design principles in IETF draft-ietf-tls-hybrid-design.

Go's crypto/tls implements the X25519MLKEM768 group as a single negotiated curve identifier combining both mechanisms.

Why not PQ-only?

PQ-only key exchange would break compatibility with clients that do not yet advertise ML-KEM groups. Hybrid preserves classical security for legacy clients while upgrading capable clients immediately.

Client compatibility

Client PQ hybrid support Behavior
Chrome 124+ (April 2024) Yes Prefers X25519MLKEM768 when server offers it
Safari 17.4+ / iOS 17.4+ (March 2024) Yes Same
Older browsers / tools No Fall back to X25519 (classically secure, not PQ-safe)
OpenSSL 3.0.x No PQ group in -groups Cannot test PQ via s_client; use Go 1.23+ or OpenSSL 3.5+
OpenSSL 3.5+ Yes openssl s_client -groups X25519MLKEM768

LastVet iOS ships to US App Store territories on iOS versions that support hybrid PQ when linked against current Apple TLS stacks.

Operational notes

Operation Command / practice
Validate config sudo caddy validate --config /etc/caddy/Caddyfile
Apply changes sudo systemctl reload caddy (preserves in-flight connections)
Do not use systemctl restart caddy unless recovery requires it
Cert storage /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/

PQ curve configuration does not alter ACME issuance or renewal. Certificates remain Let's Encrypt domain-validated ECDSA P-256.

Testing methodology

Verified August 2026 after explicit curve list deployment:

Hybrid PQ negotiation (Go 1.26 TLS client)

host=api-staging.last.vet test=pq negotiated=X25519MLKEM768 cipher=TLS_AES_128_GCM_SHA256
host=api.last.vet       test=pq negotiated=X25519MLKEM768 cipher=TLS_AES_128_GCM_SHA256

Classical fallback

host=api-staging.last.vet test=classical negotiated=X25519 cipher=TLS_AES_128_GCM_SHA256

Service health after reload

  • https://api-staging.last.vet/health → HTTP 200
  • https://api.last.vet/health → HTTP 200

Certificate validity (unchanged by PQ config)

Hostname Issuer Valid
api-staging.last.vet Let's Encrypt (YE1) Aug 12 – Nov 10, 2026
api.last.vet Let's Encrypt (YE2) Aug 12 – Nov 10, 2026

OpenSSL 3.0.13 on ops hosts cannot request PQ groups natively. Use Go 1.23+, OpenSSL 3.5+, or SSL Labs for external verification.

Compliance and references

Reference Relevance
NIST FIPS 203 ML-KEM standard
NIST IR 8105 PQ migration guidance
IETF draft-ietf-tls-hybrid-design Hybrid TLS rationale
HIPAA §164.312(e)(1) Transmission security (complements application-layer controls)

Version history

Version Date Notes
v1 August 2026 Explicit x25519mlkem768 curve preference on Caddy 2.11.4 / Go 1.26.3

Future work

Item Status
PQ certificate signatures (ML-DSA / Dilithium) via Let's Encrypt Planned when ACME support matures
SSL Labs / external monitor cadence Recommended quarterly check