{"slug": "the-great-certificate-size-explosion-ipsec-series-part-7", "title": "The Great Certificate Size Explosion – IPsec Series, Part 7", "summary": "OpenSSL 3.5+ now natively supports all three NIST post-quantum algorithms (ML-KEM, ML-DSA, SLH-DSA), and a hands-on test shows that post-quantum certificates are dramatically larger than classical ones: a self-signed ML-DSA-44 certificate is 3,987 bytes versus 326 bytes for Ed25519 and 1,043 bytes for RSA-3072, with SLH-DSA-SHA2-128f reaching 17,371 bytes. The size explosion is the key challenge for post-quantum authentication in IPsec, as larger certificates increase bandwidth and latency on the wire.", "body_md": "In Part 6 we met the post-quantum signatures and learned *why* authentication has a sneakier quantum deadline than key exchange. Now let’s get tactile. We’re going to generate real post-quantum keys and certificates with our own hands, line them up next to the classics, and **weigh them**. The size story is the single most important thing to internalise about post-quantum authentication, and the best part is you measure it yourself with nothing fancier than `ls`\n\n. Everything runs in a throwaway `alpine`\n\ncontainer with OpenSSL, so all you need is Docker.\n\n## Tooling\n\n** OpenSSL 3.5+** is the first mainstream OpenSSL with\n\n**native** support for all three NIST PQC algorithms (ML-KEM, ML-DSA, and SLH-DSA) built right in. No external plugins, no patches, no extra add-ons to install. If you’ve got 3.5 or newer, you generate post-quantum keys and certificates with plain, ordinary OpenSSL commands, the same kind you’d use for any classical key (check your version with\n\n`openssl version`\n\n).**Wait, if OpenSSL does ML-KEM, why did we use strongSwan for the key exchange?** Fair question. OpenSSL is a crypto *library*, not a VPN; its PQC support is wired into **TLS and certificates**, not IKEv2. So OpenSSL is perfect for *making and inspecting* the keys and certificates here, but it can’t run an IKEv2 handshake. That’s why anything happening on the actual VPN wire (the key exchange in Parts 4–5, and the authentication coming up in Part 8) is strongSwan’s job. Two tools, two jobs.\n\nA tiny throwaway container gives us a clean 3.5+ environment in seconds:\n\n```\ndocker run --rm -it alpine:3.22 sh\n```\n\nThen inside you install openssl:\n\n```\napk add --no-cache openssl\nopenssl version          # expect OpenSSL 3.5.x or newer\nmkdir -p /pqauth && cd /pqauth\n```\n\nAll commands below run in that same shell.\n\n## Step 1: Confirm the PQC algorithms are there\n\n```\nopenssl list -signature-algorithms | grep -iE \"ml-dsa|slh-dsa|ed25519\"\n```\n\nYou’ll see the ML-DSA and SLH-DSA families listed, for example:\n\n```\n{ 1.3.101.112, ED25519 } @ default\n{ 2.16.840.1.101.3.4.3.18, id-ml-dsa-65, ML-DSA-65, MLDSA65 } @ default\n{ 2.16.840.1.101.3.4.3.20, id-slh-dsa-sha2-128s, SLH-DSA-SHA2-128s } @ default\n...\n```\n\nThere they are: straight from OpenSSL’s default provider, no plugins required.\n\n## Step 2: Mint a self-signed cert\n\nWe’ll generate a key *and* a self-signed certificate for eight algorithms in one loop. Quick note on the yardstick: a **self-signed certificate** (subject = issuer, signed with its own key) is the cleanest possible comparison: it bundles exactly one public key and one signature with no external CA, so the size reflects *only* the algorithm’s footprint. We also output **DER** (the compact binary encoding that actually travels on the wire), not the base64 PEM text you usually see.\n\n```\nalgs=\"ED25519:ed25519 EC:ecp256 RSA:rsa3072 ML-DSA-44:mldsa44 ML-DSA-65:mldsa65 ML-DSA-87:mldsa87 SLH-DSA-SHA2-128s:slh128s SLH-DSA-SHA2-128f:slh128f\"\n\nfor entry in $algs; do\n    alg=${entry%%:*}; name=${entry##*:}\n    case \"$alg\" in\n        RSA) openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out \"$name.key\" ;;\n        EC)  openssl genpkey -algorithm EC  -pkeyopt ec_paramgen_curve:P-256 -out \"$name.key\" ;;\n        *)   openssl genpkey -algorithm \"$alg\" -out \"$name.key\" ;;\n    esac\n    openssl req -x509 -new -key \"$name.key\" -out \"$name.crt\" -days 365 -subj \"/CN=$name-peer\" -outform DER\ndone\n```\n\nNotice that for the post-quantum algorithms, generating a key uses the *exact same one-liner* as a classical one; only the algorithm name changes. That’s the beauty of OpenSSL 3.5: post-quantum isn’t a separate, special workflow, it’s just another algorithm you pass to the same command.\n\n## Step 3: Weigh them\n\n```\nls -la *.crt | awk '{print $5\"  \"$9}' | sort -n\n```\n\nBrace yourself:\n\n```\n326    ed25519.crt\n389    ecp256.crt\n1043   rsa3072.crt\n3987   mldsa44.crt\n5516   mldsa65.crt\n7474   mldsa87.crt\n8139   slh128s.crt\n17371  slh128f.crt\n```\n\nLook at that jump! Let’s put it in plain terms with the underlying numbers:\n\n| Algorithm | Security | Public key | Signature | Cert (DER) |\n|---|---|---|---|---|\n| Ed25519 | ~128-bit | 32 B | 64 B | 326 B |\n| ECDSA P-256 | ~128-bit | 65 B | ~70 B | 389 B |\n| RSA-3072 | ~128-bit | 384 B | 384 B | 1043 B |\nML-DSA-44 |\nNIST L2 | 1312 B | 2420 B | 3987 B |\nML-DSA-65 |\nNIST L3 | 1952 B | 3309 B | 5516 B |\nML-DSA-87 |\nNIST L5 | 2592 B | 4627 B | 7474 B |\n| SLH-DSA-128s | NIST L1 | 32 B | 7856 B | 8139 B |\n| SLH-DSA-128f | NIST L1 | 32 B | 17088 B | 17371 B |\n\nAn Ed25519 certificate is just **326 bytes**. The equivalent ML-DSA-65 cert is **5516 bytes**, roughly **17× larger**. And SLH-DSA-128f? Its signature *alone* is **17088 bytes**, bigger than many entire web pages. Notice SLH-DSA’s quirk too: a tiny 32-byte public key, but a gigantic signature. *Whoa.*\n\n**Wait, why isn’t the cert just key + signature?** Good catch. For ML-DSA-65, key (1952 B) + signature (3309 B) = 5261 B, yet the cert is 5516 B, about 255 B more. A certificate isn’t a simple concatenation; it’s a structured X.509 document embedding the key and signature alongside metadata (version, serial, validity dates, issuer/subject names, algorithm OIDs, a few extensions, plus ASN.1/DER framing on every field). That overhead is roughly *fixed* (~230–260 B) regardless of algorithm, which is why it dominates a tiny Ed25519 cert but barely registers on a chunky ML-DSA one.\n\n## Why this size story matters\n\nHandshakes don’t carry one cert; they carry **certificate chains plus a handshake signature**. Swap a 3-cert ECDSA chain (~1.2 KB total) for an ML-DSA-65 chain and you’re suddenly shipping\n\n**15–20 KB** in the handshake. In IKEv2 that means the\n\n`IKE_AUTH`\n\nexchange balloons and leans hard on **fragmentation**: the same pressure ML-KEM put on\n\n`IKE_INTERMEDIATE`\n\nback in the key-exchange pillar, but now on the authentication leg.And “leaning hard on fragmentation” isn’t just a minor detail. Fragmentation was designed as an occasional fallback for the rare oversized message; post-quantum flips that so *almost every* handshake is large and fragmented. That brings real costs:\n\n**Packet loss hurts more.** An N-fragment message reassembles only if*all N*arrive; lose one and the whole thing retransmits. On lossy links, big PQC handshakes retransmit more and latency spikes.**Middleboxes are hostile to fragments.** Firewalls, NATs, and load balancers routinely drop or mishandle fragmented UDP, producing handshakes that fail in really hard-to-debug ways.**Bigger pre-auth attack surface.** These bytes fly*before*the peer has proven who it is, so a responder must buffer and reassemble fragments from a not-yet-authenticated initiator: extra state an attacker can try to overload.\n\nNone of this *breaks* PQC auth (strongSwan handles it), but it’s why “the certs got bigger” turns into round trips, retransmits, and middlebox trouble at scale. We’ll watch exactly this happen on the wire in Part 8.\n\n## Step 4: Are they slow?\n\nA common worry, so before we sign anything ourselves (we’ll do that in Step 5), here’s what to expect per signature:\n\n| Algorithm | Signing | Notes |\n|---|---|---|\n| Ed25519 / ECDSA | ~instant | so fast the timing is dominated by just launching the command |\n| ML-DSA-44/65/87 | ~instant | sits right alongside the classics |\n| SLH-DSA-128f | a few ms | noticeably heavier |\n| SLH-DSA-128s | ~100+ ms | dramatically slower to sign |\n\nThe takeaway: **ML-DSA signs and verifies right alongside Ed25519 and ECDSA**, while **SLH-DSA’s s (“small”) variants are hugely slower.** That slowness is\n\n*exactly*why SLH-DSA is reserved for things you sign rarely (a root CA signs a handful of certs a year, so who cares if each takes 100 ms?) rather than a busy TLS terminator doing thousands of handshakes a second. You’ll feel that difference for yourself with the\n\n`time`\n\ncommand in Step 5.## Step 5: Sign, verify, tamper\n\nCertificates are about *trust*, and trust comes from signatures that can’t be forged. Let’s prove it.\n\n```\necho \"transfer 1000 to tom\" > msg.txt\nopenssl pkeyutl -sign -inkey mldsa65.key -rawin -in msg.txt -out msg.sig\nwc -c < msg.sig          # ~3309 bytes\n\n# Pull out the public half and verify with it\nopenssl pkey -in mldsa65.key -pubout -out mldsa65.pub\nopenssl pkeyutl -verify -pubin -inkey mldsa65.pub -rawin -in msg.txt -sigfile msg.sig\n```\n\nYou should see `Signature Verified Successfully`\n\n. Note the clean split: signing used the **private** key, verifying used *only* the **public** key. That’s the whole point of public-key signatures: signing is private, verifying is public.\n\nNow tamper with the message and watch it fail:\n\n```\necho \"transfer 1000 to mallory\" > msg.txt\nopenssl pkeyutl -verify -pubin -inkey mldsa65.pub -rawin -in msg.txt -sigfile msg.sig\n```\n\n`Signature Verification Failure`\n\n. Change a single byte and the post-quantum signature rejects it: exactly the unforgeable integrity guarantee we depend on, now resting on lattice math instead of elliptic curves.\n\nWant to *feel* the SLH-DSA difference? Time it:\n\n```\ntime openssl pkeyutl -sign -inkey slh128s.key -rawin -in msg.txt -out slh.sig\nwc -c < slh.sig          # ~7856 bytes\n```\n\nNoticeably slower, and the signature more than twice the ML-DSA size. That’s the hash-based trade-off in action: ultra-cautious security, but you’d never want it on a high-volume handshake.\n\n## What we just did\n\nYou generated post-quantum certificates, measured the size hit with your own hands, watched ML-DSA and SLH-DSA sign and verify (and reject a forgery), and felt the SLH-DSA speed penalty. The “certs get bigger” story is no longer something you read; it’s something you weighed.\n\nBut certificates sitting in a folder are only half the fun. In **Part 8** we hand these certs to strongSwan and use them to mutually authenticate a *real* IKEv2 VPN tunnel: classical ECDSA first, then bleeding-edge post-quantum ML-DSA. We’ll watch the handshake balloon and fragment exactly as predicted, and stand right at the bleeding edge where this stuff is still being built. See you there!", "url": "https://wpnews.pro/news/the-great-certificate-size-explosion-ipsec-series-part-7", "canonical_source": "https://blogs.cisco.com/developer/the-great-certificate-size-explosion-ipsec-series-part-7", "published_at": "2026-08-17 14:00:19+00:00", "updated_at": "2026-08-17 14:11:59.705886+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "large-language-models", "robotics", "autonomous-vehicles"], "entities": ["OpenSSL", "NIST", "ML-KEM", "ML-DSA", "SLH-DSA", "strongSwan", "Alpine Linux", "Docker"], "alternates": {"html": "https://wpnews.pro/news/the-great-certificate-size-explosion-ipsec-series-part-7", "markdown": "https://wpnews.pro/news/the-great-certificate-size-explosion-ipsec-series-part-7.md", "text": "https://wpnews.pro/news/the-great-certificate-size-explosion-ipsec-series-part-7.txt", "jsonld": "https://wpnews.pro/news/the-great-certificate-size-explosion-ipsec-series-part-7.jsonld"}}