{"slug": "ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10", "title": "ML-DSA Certificates on Cisco Routers – IPsec Series, Part 10", "summary": "Cisco's IOS XE routers now support ML-DSA certificates (FIPS 204) for IPsec authentication, replacing pre-shared keys, as detailed in a technical blog post. The post shows that ML-DSA-65 public keys are 1,974 bytes versus 294 for RSA-2048 and 91 for ECDSA P-256, with certificates at 5,647 bytes versus 920, requiring IKEv2 to handle larger payloads. The configuration involves importing PKCS#12 bundles generated with OpenSSL 3.5+ and setting 'revocation-check none' to avoid CRL stalls.", "body_md": "Part 9 made the key exchange quantum-safe. ML-KEM-768 is running on all three routers, fragmentation is handling the bigger messages, and the phased rollout lets you migrate at your own pace. But authentication is still a pre-shared key, and at scale that doesn’t work.\n\nThis post closes the gap. We swap PSK for **ML-DSA certificates** (FIPS 204), the same signature scheme from Parts 6-8 in the container labs. The difference: on IOS XE, the path from “I have a key” to “I have a certificate” requires some work. And once the tunnel is up, we measure exactly what ML-DSA costs on the wire.\n\n## The PKI lives on your workstation\n\nThe entire ML-DSA identity for each router is built on your workstation with OpenSSL 3.5+ and imported as a PKCS#12 bundle (a single password-encrypted file carrying the private key, its certificate, and the issuing CA chain together).\n\nThis is the verified path for getting ML-DSA identities onto the routers. We generate a root CA per parameter set, an identity certificate for R1, R2, and R3, and a PKCS#12 bundle for each.\n\n```\n=== Artifact sizes in bytes (R1 identity, DER-encoded cert)\nALGORITHM          PUBKEY      PRIVKEY         CERT          P12\nrsa-2048              294         1218          920         3698\necdsa-p256             91          138          528         1827\nmldsa44              1334         2626         4118        11504\nmldsa65              1974         4098         5647        16032\nmldsa87              2614         4962         7605        20816\n```\n\nLook at that table: a ML-DSA-65 public key is **1,974 bytes against 294** for RSA-2048 and **against 91** for ECDSA P-256. The certificate carrying it is **5,647 bytes against 920**. That’s not a small change, it’s an order of magnitude, and IKEv2 has to carry it.\n\n## Import the bundle\n\nCopy the PKCS#12 file to the router and import:\n\n``` python\nR1(config)# crypto pki import TP-MLDSA65 pkcs12 bootflash:/mldsa65-r1.p12 password cisco123\n% Importing pkcs12...\nSource filename [mldsa65-r1.p12]?\nReading file from bootflash:/mldsa65-r1.p12\nCRYPTO_PKI: Imported PKCS12 file successfully.\n```\n\nThat `password cisco123` protects the bundle for the few seconds it sits on `bootflash:` and nothing else. The bundle gets deleted right after import. Don’t reuse this pattern for a bundle that lives anywhere longer than one import. Delete it immediately:\n\n```\nR1# delete /force bootflash:/mldsa65-r1.p12\n```\n\nOne more thing: the default `revocation-check crl` on the trustpoint means the router tries to download a CRL (Cert Revocation List) before trusting a peer’s certificate. Lab certificates have no CRL distribution point, so the handshake stalls. Fix it:\n\n```\nR1(config)# crypto pki trustpoint TP-MLDSA65\nR1(ca-trustpoint)# revocation-check none\n```\n\nConfirm the router parsed an ML-DSA certificate:\n\n```\nR1# show crypto pki certificates verbose TP-MLDSA65\nCertificate\n  Status: Available\n  Version: 3\n  Certificate Usage: Signature\n  Issuer:\n    cn=PQC-LAB-ROOT-mldsa65\n  Subject:\n    Name: R1-mldsa65\n    IP Address: 10.0.12.1\n    cn=R1-mldsa65\n  Subject Key Info:\n    Public Key Algorithm: ML-DSA\n    Public Key Size: (1974 bytes)\n  Signature Algorithm: ML-DSA-65\n  X509v3 extensions:\n    X509v3 Subject Alternative Name:\n            IP Address : 10.0.12.1\n    Extended Key Usage:\n        Server Auth\n        Client Auth\n```\n\n`Public Key Algorithm: ML-DSA`, 1,974 bytes, matching the container lab OpenSSL output exactly.\n\nBoth `Server Auth` and `Client Auth` EKUs are needed. An IKEv2 peer is initiator on one negotiation and responder on the next, so a client-only certificate fails half the time.\n\n## Swap PSK for ML-DSA\n\nDo this on **both R1 and R3**. The key exchange config doesn’t change at all: `pqc mlkem768 optional` from Part 9 stays exactly as it is. Only the authentication method changes.\n\n```\ncrypto ikev2 profile MLDSA-PROFILE\n match identity remote address 10.0.23.2 255.255.255.255\n identity local address 10.0.12.1\n authentication local mldsa-sig\n authentication remote mldsa-sig\n pki trustpoint TP-MLDSA65\n dpd 30 5 periodic\n\ncrypto ipsec profile MLDSA-IPSEC\n set transform-set CLASSICAL-TS\n set ikev2-profile MLDSA-PROFILE\n\ninterface Tunnel0\n tunnel protection ipsec profile MLDSA-IPSEC\n```\n\nThe router warns you:\n\n```\n Warning: MLDSA Auth packets are extremely large. Please enable IKEv2 Fragmentation.\n```\n\nFragmentation was already enabled in Part 9, so we’re covered. Changing tunnel protection shuts the interface, so bring it back:\n\n```\nR1(config)# interface Tunnel0\nR1(config-if)# no shutdown\n```\n\n## The payoff\n\n```\nR1# ping 192.168.100.2\n!!!!!\nSuccess rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms\n\nR1# show crypto ikev2 sa detailed\nTunnel-id Local                 Remote                fvrf/ivrf            Status\n2         10.0.12.1/500         10.0.23.2/500         none/none            READY\n      Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:20, Auth sign: MLDSA, Auth verify: MLDSA\n      PQC Key Exchange: ML-KEM-768\n      ...\n      IETF Std Fragmentation  enabled.\n      Quantum-safe Encryption using PQC: ML-KEM-768\n      IETF Std Fragmentation MTU in use: 1372 bytes.\n```\n\nThere it is, on one line: **`Auth sign: MLDSA, Auth verify: MLDSA`** next to **` PQC Key Exchange: ML-KEM-768`**. Both halves of the tunnel are quantum-safe. Key exchange resists harvest-now-decrypt-later. Authentication resists a future forged identity.\n\n## What ML-DSA actually costs on the wire\n\nThe warning said the auth packets are “exetremely large”, but **how** large? We set up a packet capture on R2 (the transit hop that sees every IKE packet without being a crypto endpoint) and measured one complete handshake for each signature algorithm.\n\n| Authentication | IKE_AUTH frames | IKE_AUTH bytes | Whole handshake | vs RSA-2048 | \n|---|---|---|---|---|\n| RSA-2048 | 3 | 3,462 | 7 frames / 7,111 B | 1.0x | \n| ML-DSA-44 | 12 | 15,384 | 16 frames / 19,033 B | 4.4x | \n| ML-DSA-65 | 16 | 20,752 | 20 frames / 24,401 B | 6.0x | \n| ML-DSA-87 | 20 | 27,848 | 24 frames / 31,497 B | 8.0x | \n\n`IKE_SA_INIT` is 2 frames and about 1.1 KB in every case: it only carries the classical ECDH exchange (group 20), whose public value is 512 bytes. The ML-KEM `IKE_INTERMEDIATE` exchange is also constant at 2 frames and 2,548 bytes (the ML-KEM-768 encapsulation key alone is 1,184 bytes). Neither changes with the signature algorithm. All the *variable* growth is in `IKE_AUTH`, which is where the certificate and the signature travel.\n\nThe largest ML-DSA frame is 1,422 bytes in every run. That’s the fragmentation MTU doing its job: instead of one enormous datagram you get a dozen or more well-behaved ones. Exactly why the router nags you about fragmentation.\n\n**Choosing a parameter set.** ML-DSA-65 costs 35% more IKE_AUTH bytes than ML-DSA-44 and buys you NIST security category 3 instead of 2. ML-DSA-87 costs another 34% on top for category 5. Unless you have a specific mandate, **65 is the sensible default**.\n\n**Is 20 KB a problem?** For a site-to-site tunnel that negotiates once and rekeys every 24 hours, no. For a hub terminating thousands of DMVPN spokes that all reconnect after a power event, definitely something to factor into capacity planning. The cost is per-negotiation, not per-packet: once the SA is up, ESP data plane traffic is unchanged.\n\n## Where we stand now\n\nThe tunnel is fully quantum-safe. But we just proved it on a single pair of routers. How do you migrate authentication across a whole network? That’s a different problem from key exchange, and the answer is less comfortable. Key exchange negotiates with `optional`; authentication has no fallback keyword. Part 11 walks through the migration playbook, the experiments that show where it breaks, and the operational gotchas that only show up on real hardware.\n\nSee you there. Bring your planning hat.", "url": "https://wpnews.pro/news/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10", "canonical_source": "https://blogs.cisco.com/developer/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10", "published_at": "2026-09-08 17:48:10+00:00", "updated_at": "2026-09-08 18:20:39.260903+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "large-language-models", "robotics", "autonomous-vehicles"], "entities": ["Cisco", "IOS XE", "ML-DSA", "FIPS 204", "OpenSSL 3.5", "PKCS#12", "R1", "R3"], "alternates": {"html": "https://wpnews.pro/news/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10", "markdown": "https://wpnews.pro/news/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10.md", "text": "https://wpnews.pro/news/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10.txt", "jsonld": "https://wpnews.pro/news/ml-dsa-certificates-on-cisco-routers-ipsec-series-part-10.jsonld"}}