Over the first 8 parts of this series we built quantum-safe VPN tunnels on your laptop, using containers. That’s how you learn protocols: in a clean environment where everything is under your control.
But running a VPN in a container is not the usual setup in production. At some point the question changes from “does the protocol work?” to “does the platform work?”. This is where we go find out.
The hardware
The platform I’ve used for this exercise is part of the Cisco 8000 Series Secure Router, specifically the C8235-G2. Three of them, wired back to back, running IOS XE 26.2 with the “advantage” license (which unlocks all crypto features).
Why 26.2? Because 26.1 gave you post-quantum key exchange (ML-KEM) and left authentication classical. 26.2 adds ML-DSA signatures for IKEv2, so a site-to-site tunnel can now be quantum-safe end to end. Both pillars in one box.
The lab
3 routers, 2 VLANs, 1 hub-and-spoke topology that stays the same for everything that follows:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ R1 │ │ R2 │ │ R3 │
│ (Spoke-1) │ │ (Hub/Transit)│ │ (Spoke-2) │
│ │ │ │ │ │
│ Vlan12 │ │ Vlan12 │ │ │
│ 10.0.12.1 │ │ 10.0.12.2 │ │ │
│ │ VLAN 12 │ │ │ │
│ Tw0/0/0 ├──────────┤ Tw0/0/0 │ │ │
│ │ 2.5 Gb │ │ │ │
│ │ │ Vlan23 │ │ Vlan23 │
│ │ │ 10.0.23.1 │ │ 10.0.23.2 │
│ │ │ │ VLAN 23 │ │
│ │ │ Tw0/0/1 ├──────────┤ Tw0/0/0 │
│ │ │ │ 2.5 Gb │ │
└──────────────┘ └──────────────┘ └──────────────┘
R2 sits in the middle as a Layer 3 transit router. The IPsec tunnel runs end to end between R1 and R3, traversing R2 as an intermediate hop to emulate a real WAN where crypto endpoints are not directly connected.
Later, when we test phased migration, R2 becomes a VPN hub terminating tunnels to both spokes. Same 3 boxes, different role for the one in the middle.
IOS XE 26.2 support
Here’s the honest status, verified on hardware:
| Feature | Status on 26.2 |
|---|---|
| ML-KEM-768 hybrid key exchange | Working |
| RFC 8784 PPK | Working |
| ML-DSA-44 / 65 / 87 signatures | Working |
| IKEv2 fragmentation for PQC payloads | Working |
| ML-DSA certificates via external CA + PKCS#12 import | Working |
The container labs were clean: you installed a package, wrote a config, and things worked. On IOS XE the concepts are identical (same RFCs, same algorithms, same threat model)
The format for this post, and the next two, is different from the container posts. You won’t be typing along (unless you have some 8000 Secure Routers lying around), but you’ll see every command and every piece of show output exactly as it came off the router. The goal isn’t to hand you a recipe; it’s to show you what post-quantum IPsec looks like in production, so you know exactly what to expect when your own migration starts.
Start classical
First, the tunnel between R1 and R3. R2 just forwards packets between them (Layer 3 transit), emulating a real WAN where the crypto endpoints aren’t directly connected.
Here’s the IKEv2 config on R1:
crypto ikev2 proposal CLASSICAL-PROPOSAL
encryption aes-cbc-256
integrity sha512
group 20
crypto ikev2 policy CLASSICAL-POLICY
proposal CLASSICAL-PROPOSAL
crypto ikev2 keyring CLASSICAL-KEYRING
peer R3
address 10.0.23.2
pre-shared-key C1sco12345psk
crypto ikev2 profile CLASSICAL-PROFILE
match identity remote address 10.0.23.2 255.255.255.255
authentication remote pre-share
authentication local pre-share
keyring local CLASSICAL-KEYRING
crypto ipsec transform-set CLASSICAL-TS esp-gcm 256
mode tunnel
crypto ipsec profile CLASSICAL-IPSEC
set transform-set CLASSICAL-TS
set ikev2-profile CLASSICAL-PROFILE
interface Tunnel0
ip address 192.168.100.1 255.255.255.0
tunnel source Vlan12
tunnel destination 10.0.23.2
tunnel mode ipsec ipv4
tunnel protection ipsec profile CLASSICAL-IPSEC
R3 mirrors it (peer address 10.0.12.1, tunnel IP 192.168.100.2).
A quick note on group 20. That’s ECDH-384, the NIST P-384 curve. In the container labs, strongSwan used X25519 (Curve25519). Both are elliptic-curve Diffie-Hellman doing the same job: two peers agree on a shared secret without sending it over the wire. From a PQC perspective they’re equally “classical” and equally vulnerable to Shor’s algorithm. IOS XE uses group 20 because it’s natively supported and gives a higher security margin. The PQC story doesn’t change.
Verify the tunnel is up:
R1# show crypto ikev2 sa
Tunnel-id Local Remote fvrf/ivrf Status
1 10.0.12.1/500 10.0.23.2/500 none/none READY
Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:20, Auth sign: PSK, Auth verify: PSK
Life/Active Time: 86400/8 sec
R1# ping 192.168.100.2
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms
DH Grp:20, Auth sign: PSK, Auth verify: PSK. Classical key exchange, classical authentication. This is the baseline.
One thing worth making explicit: the pre-shared-key in the keyring is for authentication only. It proves R1 is really talking to R3, not an attacker. The actual tunnel encryption key comes from the DH exchange (group 20). Swap PSK for certificates and the tunnel encryption doesn’t change at all. Part 10 does exactly that swap.
Add a PPK
Same approach as Part 5, just with Cisco CLI. A Postquantum Preshared Key (PPK) gets mixed into the IKE key derivation. The PPK never travels on the wire, so even if a future quantum computer breaks the DH exchange from a recording, it still can’t derive the session keys without the secret it never saw.
The config goes inside the existing keyring on both R1 and R3:
crypto ikev2 keyring CLASSICAL-KEYRING
peer R3
ppk manual id PPK-R1R3 key hex 48656C6C6F506F737451756172746E756D required
crypto ikev2 profile CLASSICAL-PROFILE
keyring ppk CLASSICAL-KEYRING
required means the tunnel won’t come up without PPK. Both sides need the same ID and key.
Clear the SA and let it renegotiate:
R1# clear crypto ikev2 sa
R1# ping 192.168.100.2
!!!!!
Check the result:
R1# show crypto ikev2 sa detailed | include Quantum
Quantum-safe Encryption using Manual PPK
R1# show crypto ikev2 stats | include Quantum
Sessions with Quantum Resistance: 1 Manual: 1 Dynamic: 0
That’s it. Same classical DH exchange underneath, but the derived keys now also depend on a secret that was never transmitted.
The operational catch is the same too: every peer pair needs the same secret provisioned and rotated out of band. That’s the classic key-distribution headache that public-key crypto was invented to avoid, which is exactly why PPK is a transitional step.
Remove the PPK
PPK proved the concept: you can protect the key derivation against quantum attacks without changing the underlying DH exchange. But once the platform supports ML-KEM natively, you don’t need the out-of-band key anymore. Let’s remove PPK before moving on.
On both R1 and R3:
crypto ikev2 profile CLASSICAL-PROFILE
no keyring ppk CLASSICAL-KEYRING
crypto ikev2 keyring CLASSICAL-KEYRING
peer R3
no ppk manual id PPK-R1R3
Clear the SA:
R1# clear crypto ikev2 sa
R1# ping 192.168.100.2
!!!!!
Back to the baseline: classical DH, classical PSK, no quantum protection. Now we add the real thing.
Native ML-KEM hybrid
Starting with 26.1, IOS XE natively supports ML-KEM for IPsec tunnels. Two lines on both R1 and R3:
crypto ikev2 fragmentation mtu 1400
crypto ikev2 proposal CLASSICAL-PROPOSAL
pqc mlkem768 optional
That’s it. pqc mlkem768 optional adds ML-KEM to the proposal (optional means: use it if the peer supports it, fall back to classical if it doesn’t). The fragmentation command is needed because ML-KEM adds about 1.5 KB to the IKE exchange, same problem we measured in Part 3, same solution: IKEv2 fragmentation splits the oversized messages into pieces that fit in a single UDP datagram.
Clear the SA:
R1# clear crypto ikev2 sa
R1# ping 192.168.100.2
....!
First few pings may time out while the larger handshake completes.
Now look at the tunnel:
R1# show crypto ikev2 sa detailed
Tunnel-id Local Remote fvrf/ivrf Status
1 10.0.12.1/500 10.0.23.2/500 none/none READY
Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:20, Auth sign: PSK, Auth verify: PSK
PQC Key Exchange: ML-KEM-768
Life/Active Time: 86400/9 sec
...
IETF Std Fragmentation enabled.
Quantum-safe Encryption using PQC: ML-KEM-768
IETF Std Fragmentation MTU in use: 1372 bytes.
There it is: PQC Key Exchange: ML-KEM-768 right there in the show output. The key exchange is quantum-safe, and the tunnel negotiated it without any pre-shared secrets or out-of-band key distribution.
Phased migration
This is the real-world scenario. You have a Cisco network with multiple sites. You can’t upgrade everything at once. So you start with the hub, then upgrade spokes one by one.
The topology changes here. In the exercises above, the tunnel ran R1-to-R3 directly (R2 just forwarded). Now R2 becomes a VPN hub: it terminates two separate tunnels, one to each spoke. New keyrings, new profiles on all three routers.
The key difference is in the proposals. The hub (R2) and the already-upgraded spoke (R1) include pqc mlkem768 optional. The legacy spoke (R3) does not.
R2 (hub) proposal:
crypto ikev2 proposal HUB-PROPOSAL
pqc mlkem768 optional
encryption aes-cbc-256
integrity sha512
group 20
R1 (upgraded spoke):
crypto ikev2 proposal PQC-PROPOSAL
pqc mlkem768 optional
encryption aes-cbc-256
integrity sha512
group 20
R3 (legacy spoke), no PQC yet:
crypto ikev2 proposal SPOKE-PROPOSAL
encryption aes-cbc-256
integrity sha512
group 20
Now check the hub’s two tunnels:
R2# show crypto ikev2 sa
Tunnel-id Local Remote fvrf/ivrf Status
1 10.0.12.2/500 10.0.12.1/500 none/none READY
Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:20, Auth sign: PSK, Auth verify: PSK
PQC Key Exchange: ML-KEM-768
Life/Active Time: 86400/19 sec
Tunnel-id Local Remote fvrf/ivrf Status
2 10.0.23.1/500 10.0.23.2/500 none/none READY
Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:20, Auth sign: PSK, Auth verify: PSK
Life/Active Time: 86400/18 sec
One hub, two tunnels. The R2-R1 tunnel shows ML-KEM-768 (both support it). The R2-R3 tunnel stays classical (R3 doesn’t have pqc in its proposal, so it falls back to plain DH group 20). That’s optional doing its job: no breakage, graceful fallback.
Now upgrade R3:
R3(config)# crypto ikev2 proposal SPOKE-PROPOSAL
R3(config-ikev2-proposal)# pqc mlkem768 optional
R2# clear crypto ikev2 sa
After renegotiation:
R2# show crypto ikev2 sa
Tunnel-id Local Remote fvrf/ivrf Status
1 10.0.12.2/500 10.0.12.1/500 none/none READY
...
PQC Key Exchange: ML-KEM-768
Tunnel-id Local Remote fvrf/ivrf Status
2 10.0.23.1/500 10.0.23.2/500 none/none READY
...
PQC Key Exchange: ML-KEM-768
Both tunnels quantum-safe. Cool!
That’s the migration strategy: upgrade the hub first with optional, then roll out to spokes at your own pace. Once everything is upgraded, change optional to required to enforce PQC everywhere and reject classical-only peers.
Where we stand
Key exchange is done. The two approaches we covered (PPK and ML-KEM) are alternatives, not layers you stack. PPK is an option when the platform doesn’t support ML-KEM yet; once it does, ML-KEM is the cleaner path because it doesn’t require distributing secrets out of band.
But authentication is still a pre-shared key. At scale, managing per-tunnel PSKs doesn’t work, and an RSA or ECDSA certificate is forgeable by a future quantum computer. The missing half of the picture is ML-DSA certificates, and that’s where IOS XE gets really interesting. Part 10 walks through the PKI story: how we build the CA externally, import the certificates, and what ML-DSA costs on the wire.
See you there!
