Since we have learned the basics of post-quantum secure VPN tunnels, let’s configure a site-to-site VPN between a Palo Alto Networks firewall and a FortiGate with PQC ciphers to verify vendor interoperability. Spoiler: it works like a charm. ;)
Palo Alto Networks supports PQC ciphers since PAN-OS 11.2, while 12.1 finally brought the ML-KEM algorithm. FortiGates support PQC ciphers since FortiOS 7.6. My lab consists of a PA-440 with PAN-OS 12.1.6 and a FG-70F with FortiOS 7.6.7.
Setup
(Note that I’m not showing a complete site-to-site VPN tutorial, but focusing on the PQC part.)
I’m using the hybrid approach. PQC ciphers are used *additionally* to the classical ECDH key agreement. That is: group21 + mlkem.
Palo Alto Networks NGFW
On the Palo side, you need to configure the IKE/IPsec Crypto, the IKE Gateway and the IPsec tunnel in the following way:
Fortinet FortiGate
On the Forti, it’s these steps that are done completely in the VPN Tunnels pane:
On the CLI, it’s this (excluding the tunnel interface and the static route). Note the set addke1 ml-kem-1024 lines.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
config vpn ipsec phase1-interface edit "pa-lab" set interface "wan1" set ip-version 6 set ike-version 2 set peertype any set net-device disable set proposal aes256gcm-prfsha512 set dhgrp 21 set addke1 ml-kem-1024 set nattraversal disable set transport udp set remote-gw6 2a00:6020:ad0b:8303::2 set psksecret ENC Hr6QZodcvtxFwPEt4i1acXEZJIwGCboi1zx4+tA1CAB0zZR9jnIQMcYYpc375bFqulodhZmcN3IIA1JVaDTgK5y3gIG5VuCpkXwsaLQH8Tf4jRJEMTQYg2bBD/QpU8HGJgdEwyBvoRs880zTPoGr6fVsSLgy7smftEQi1NGzMW1M6S7QoEDyjopO6nKKQB0I/+4k6VlmMjY3dkVA next end config vpn ipsec phase2-interface edit "all-ipv6" set phase1name "pa-lab" set proposal aes256gcm set dhgrp 21 set addke1 ml-kem-1024 set src-addr-type subnet6 set dst-addr-type subnet6 set keylifeseconds 3600 next end |
Verify
Both firewalls deliver only basic “it’s working” green icons in the GUI:
If you want to verify whether or not post-quantum ciphers are used, the CLI is a must. Note the ML-KEM keywords:
Palo:
show vpn ike-sa detail gateway <name> and
show vpn ipsec-sa tunnel <name>:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
weberjoh@pa-lab> show vpn ike-sa detail gateway fg-lab IKE Gateway fg-lab, ID 2 2a00:6020:ad0b:8303::2 => 2a00:6020:ad0b:8303::9 Current time: Jun.18 09:28:56 IKE SA: SPI: 9835E5BCE743D9A4:8153CAA28008FAA6 Init State: Established SN: 11 Authentication: PSK, peer PSK Proposal: AES256-GCM16/COMBINED/DH21/ML-KEM-1024/NONE/NONE/NONE/NONE/NONE/NONE ID local: ipaddr:2a00:6020:ad0b:8303::2 remote: ipaddr:2a00:6020:ad0b:8303::9 ID_i: IPv6_address:2a00:6020:ad0b:8303::9 ID_r: IPv6_address:2a00:6020:ad0b:8303::2 NAT: Not detected Message ID: rx 6, tx 1914 Liveness check: sending informational packet after idle 5 seconds Created: Jun.18 06:49:24, 2 hours 39 minutes 33 seconds ago Expires: Jun.18 14:49:24, rekey in 4 hours 8 minutes 2 seconds (24455 sec) Child SA 29914: Tunnel 2 fg-lab Type: ESP Resp State: Mature Message ID: 00000004 Parent SN: 11 SPI: A50203B8 : BEA130B7 <= ESP: BEA130B6 Algorithm: AES256-GCM16/COMBINED/DH21/ML-KEM-1024 TS local: Proto:any, ::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, Ports:any TS remote: Proto:any, ::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff, Ports:any Created: Jun.18 09:08:36, 20 minutes 21 seconds ago Expires: Jun.18 10:08:36, rekey in 33 minutes 2 seconds (3203 sec) weberjoh@pa-lab> weberjoh@pa-lab> weberjoh@pa-lab> show vpn ipsec-sa tunnel fg-lab GwID/client IP TnID Peer-Address Tunnel(Gateway) Algorithm SPI(in) SPI(out) life(Sec/KB) remain-time(Sec) -------------- ---- ------------ --------------- --------- ------- -------- ------------ ---------------- 2 2 2a00:6020:ad0b:8303::9 fg-lab(fg-lab) ESP/G256/ /DH21/ML-KEM-1024 A50203B8 BEA130B7 3600/Unlimited 2357 Show IPSec SA: Total 1 tunnels found. 1 ipsec sa found. |
Forti:
Please note that neither of the following two commands show the key agreement protocol, hence are not usable here: get vpn ike gateway <name>, get vpn ipsec tunnel name <name>.
–> This is the one: diagnose vpn ike gateway list name <name>:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
fg-lab # diagnose vpn ike gateway list name pa-lab vd: root/0 name: pa-lab version: 2 interface: wan1 5 addr: 2a00:6020:ad0b:8303::9:500 -> 2a00:6020:ad0b:8303::2:500 tun_id: 10.0.0.1/::10.0.0.1 remote_location: 0.0.0.0 network-id: 0 transport: UDP created: 78734s ago peer-id: 2a00:6020:ad0b:8303::2 peer-id-auth: no pending-queue: 0 PPK: no IKE SA: created 2/5 established 2/5 time 20/4238/21070 ms IPsec SA: created 1/25 established 1/25 time 0/866/21070 ms id/spi: 320 15b515dc59e0a898/cb080b494e28fca3 direction: responder status: established 3212-3212s ago = 20ms proposal: aes256gcm child: yes SK_ei: cfbac895857d9ed8-7954388f85030dc3-f2b0e7bb050f2143-45c69edfa3d5377d-b954a6bc SK_er: d062865f3b430a50-795d4be04b81d0a7-5d8cea7d6665c54c-f761ddc81470c232-e64fd33e SK_ai: SK_ar: message-id sent/recv: 2/642 QKD: no PQC-KEM (IKE): yes PQC-KEM (all IPsec): yes lifetime/rekey: 86400/82917 DPD sent/recv: 00000000/00000000 peer-id: 2a00:6020:ad0b:8303::2 |
That’s it. Happy networking. :)
Soli Deo Gloria!
Photo by Hugues de BUYER-MIMEURE on Unsplash.














