0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ubuntu 25.10 + strongSwan 6.0.3 で IPsec VPN の PQ/T Hybrid KEX を実機確認する

Posted at

この記事は「PQC Advent Calendar 2025」の 24 日目です。
※この記事はAIによって生成されたコンテンツを含みます。スクリーンショット、コマンド出力、ログ、トレースなどには含みません。


本記事では、Ubuntu 25.10(questing)上でビルドした strongSwan 6.0.3 を用いて、RFC9272 および RFC9370 に準拠した PQC IPsec が動作することを確認します。
また、Wireshark による IKE_INTERMEDIATE のパケットについても確認します。

背景

PQC 時代の IPsec については、こちらの記事でご確認ください。
PQC 時代の IPsec を比較する : RFC8784 / RFC9242 + RFC9370

検証環境

pqcipsec.drawio.png

OS / strongSwan

  • OS:Ubuntu 25.10
    • UTM 4.7.4
    • M1 MacBook Pro (14inch, 2021)
  • strongSwan:6.0.3(ビルド)

strongSwan 6.0.3 のインストール・ビルド

strongSwan 6.0.0 以降をインストールするために、ソースからビルドします。

git clone https://github.com/strongswan/strongswan.git
cd strongswan/
./autogen.sh
./configure   --prefix=/usr   --sysconfdir=/etc   --enable-swanctl   --enable-openssl   --enable-kem   --enable-mlkem   --enable-systemd   --disable-stroke   --enable-pki   --enable-pem   --enable-random   --enable-constraints   --enable-xauth-generic
make -j$(nproc)
sudo make install
sudo systemctl daemon-reload
sudo systemctl restart strongswan

トップに戻る

対応アルゴリズム確認

swanctl --list-algs の鍵交換アルゴリズムの項目で ML_KEM がサポートされていることを確認します。

(snip)

ke:
  MODP_3072[openssl]
  MODP_4096[openssl]
  MODP_6144[openssl]
  MODP_8192[openssl]
  MODP_2048[openssl]
  MODP_2048_224[openssl]
  MODP_2048_256[openssl]
  MODP_1536[openssl]
  MODP_1024[openssl]
  MODP_1024_160[openssl]
  MODP_768[openssl]
  MODP_CUSTOM[openssl]
  ML_KEM_512[openssl]
  ML_KEM_768[openssl]
  ML_KEM_1024[openssl]
  ECP_256[openssl]
  ECP_384[openssl]
  ECP_521[openssl]
  ECP_224[openssl]
  ECP_192[openssl]
  ECP_256_BP[openssl]
  ECP_384_BP[openssl]
  ECP_512_BP[openssl]
  ECP_224_BP[openssl]
  CURVE_25519[openssl]
  CURVE_448[openssl]

トップに戻る

設定

ネットワーク名前空間の設定

複数ノードを用意できないため、Ubuntu 上で Linux Network Namespace (ns) を利用して、IPsec 接続を試行します。
また、仕様上、複数 ns で同一 charon を共有することを前提とします。
なお、各インターフェースの MTU を 9000 byte まで拡張していますが、フラグメントを回避するため(後述)です。

sudo ip netns add ipsec1
sudo ip netns add router
sudo ip netns add ipsec2
sudo ip link add ipsec1-veth0 type veth peer name gw-veth0
sudo ip link add ipsec2-veth0 type veth peer name gw-veth1
sudo ip link set ipsec1-veth0 netns ipsec1
sudo ip link set gw-veth0 netns router
sudo ip link set gw-veth1 netns router
sudo ip link set ipsec2-veth0 netns ipsec2
sudo ip netns exec ipsec1 ip address add 192.0.2.1/24 dev ipsec1-veth0
sudo ip netns exec ipsec1 ip addr add 203.0.113.1/32 dev lo
sudo ip netns exec ipsec2 ip address add 198.51.100.1/24 dev ipsec2-veth0
sudo ip netns exec ipsec2 ip addr add 203.0.113.2/32 dev lo
sudo ip netns exec router ip address add 192.0.2.254/24 dev gw-veth0
sudo ip netns exec router ip address add 198.51.100.254/24 dev gw-veth1
sudo ip netns exec ipsec1 ip link set dev ipsec1-veth0 address 00:00:5E:00:53:11
sudo ip netns exec ipsec2 ip link set dev ipsec2-veth0 address 00:00:5E:00:53:22
sudo ip netns exec router ip link set dev gw-veth0 address 00:00:5E:00:53:12
sudo ip netns exec router ip link set dev gw-veth1 address 00:00:5E:00:53:21
sudo ip netns exec ipsec1 ip link set dev ipsec1-veth0 mtu 9000
sudo ip netns exec router ip link set dev gw-veth0 mtu 9000
sudo ip netns exec router ip link set dev gw-veth1 mtu 9000
sudo ip netns exec ipsec2 ip link set dev ipsec2-veth0 mtu 9000
sudo ip netns exec ipsec1 ip link set ipsec1-veth0 up
sudo ip netns exec ipsec1 ip link set lo up
sudo ip netns exec router ip link set gw-veth0 up
sudo ip netns exec router ip link set gw-veth1 up
sudo ip netns exec ipsec2 ip link set ipsec2-veth0 up
sudo ip netns exec ipsec2 ip link set lo up
sudo ip netns exec ipsec1 ip route add default via 192.0.2.254
sudo ip netns exec ipsec2 ip route add default via 198.51.100.254
sudo ip netns exec router sysctl net.ipv4.ip_forward=1

トップに戻る

strongSwan 設定ディレクトリ

ns 毎異なる設定を読み込むため、それぞれのディレクトリを作成、バインドマウントします。

sudo mkdir -p /etc/ipsec.d/run
sudo mkdir -p /etc/netns/ipsec1/ipsec.d/run
sudo mkdir -p /etc/netns/ipsec2/ipsec.d/run
sudo mkdir -p /etc/netns/ipsec1/swanctl
sudo mkdir -p /etc/netns/ipsec2/swanctl
sudo mkdir -p /etc/swanctl/ipsec1/conf.d
sudo mkdir -p /etc/swanctl/ipsec2/conf.d
sudo mount --bind /etc/ipsec.d/run /etc/netns/ipsec1/ipsec.d/run
sudo mount --bind /etc/ipsec.d/run /etc/netns/ipsec2/ipsec.d/run
sudo mount --bind /etc/swanctl/ipsec1 /etc/netns/ipsec1/swanctl
sudo mount --bind /etc/swanctl/ipsec2 /etc/netns/ipsec2/swanctl

トップに戻る

strongSwan 設定

/etc/swanctl/ipsec1/conf.d/ipsec1.conf:
connections {
  ipsec1-ipsec2 {
    version = 2
    fragmentation = no

    local_addrs  = 192.0.2.1
    remote_addrs = 198.51.100.1

    # IKEv2 proposal:
    #  - AES-256-GCM
    #  - PRF SHA-384
    #  - 1st KE: ecp384 (ECDH)
    #  - 2nd KE: mlkem1024 (ML-KEM, RFC9370+9242 で IKE_INTERMEDIATE を使う)
    proposals = aes256gcm16-prfsha384-x25519-ke1_mlkem1024

    rekey_time  = 1h
    dpd_delay   = 30s
    dpd_timeout = 120s

    local {
      auth = psk
      id   = ipsec1
    }

    remote {
      auth = psk
      id   = ipsec2
    }

    children {
      net {
        mode = tunnel

        local_ts  = 203.0.113.1/32
        remote_ts = 203.0.113.2/32

        # ESP 側も PFS + hybrid KE
        esp_proposals = aes256gcm16-x25519-ke1_mlkem1024

        start_action = start
        dpd_action   = restart
      }
    }
  }
}

secrets {
  ike-psk {
    id-0   = ipsec1
    id-1   = ipsec2
    secret = "foo-bar-hoge-fuga"
  }
}
/etc/swanctl/ipsec2/conf.d/ipsec2.conf:
connections {
  ipsec2-ipsec1 {
    version = 2
    fragmentation = no

    local_addrs  = 198.51.100.1
    remote_addrs = 192.0.2.1

    proposals = aes256gcm16-prfsha384-x25519-ke1_mlkem1024

    rekey_time  = 1h
    dpd_delay   = 30s
    dpd_timeout = 120s

    local {
      auth = psk
      id   = ipsec2
    }

    remote {
      auth = psk
      id   = ipsec1
    }

    children {
      net {
        mode = tunnel

        local_ts  = 203.0.113.2/32
        remote_ts = 203.0.113.1/32

        esp_proposals = aes256gcm16-x25519-ke1_mlkem1024

        start_action = trap
        dpd_action   = restart
      }
    }
  }
}

secrets {
  ike-psk {
    id-0   = ipsec1
    id-1   = ipsec2
    secret = "foo-bar-hoge-fuga"
  }
}

トップに戻る

strongSwan デーモン起動 & 設定ロード

systemd 経由で起動すると netns の設定がロードできないため事前に停止してから各 ns で charon-systemd を起動します。

sudo systemctl stop strongswan
sudo systemctl disable strongswan
sudo ip netns exec ipsec2 charon-systemd &
sleep 1
sudo ip netns exec ipsec2 swanctl --load-all
sudo ip netns exec ipsec1 charon-systemd &
sleep 1
sudo ip netns exec ipsec1 swanctl --load-all

トップに戻る

接続施行

パケットキャプチャ & テストトラフィック発生

IPsec 関連のパケットに限定して、パケットキャプチャを実施し、テストトラフィックとして ICMP パケットを発生させます。

sudo ip netns exec ipsec1 tcpdump -i ipsec1-veth0 -nn -vv -w ipsec1.pcap '(udp port 500 or udp port 4500 or esp)' &
sudo ip netns exec ipsec1 ping -c 3 203.0.113.2 -I 203.0.113.1

トップに戻る

接続確認

IKE SA で PQ/T Hybrid KEX CURVE_25519/KE1_ML_KEM_1024 が使われていることを確認できます。

sudo ip netns exec ipsec1 swanctl --list-sas
ipsec1-ipsec2: #1, ESTABLISHED, IKEv2, d3aaa4ac1e7dc15b_i* 1d16d7f3431e6e1d_r
  local  'ipsec1' @ 192.0.2.1[4500]
  remote 'ipsec2' @ 198.51.100.1[4500]
  AES_GCM_16-256/PRF_HMAC_SHA2_384/CURVE_25519/KE1_ML_KEM_1024
  established 17s ago, rekeying in 3335s
  net: #1, reqid 1, INSTALLED, TUNNEL, ESP:AES_GCM_16-256
    installed 17s ago, rekeying in 3314s, expires in 3943s
    in  cd809f41,    252 bytes,     3 packets,     7s ago
    out ccac11d7,    252 bytes,     3 packets,     7s ago
    local  203.0.113.1/32
    remote 203.0.113.2/32

iniciator spi: d3aaa4ac1e7dc15b responder spi: 1d16d7f3431e6e1d であり、上記の結果と一致することが確認できます。
IKE_INTERMEDIATE で 1679 byte のパケットを送信していることを確認できます。
PQC KEM のためサイズが大きく、MTU を増やしていない場合、フラグメントが発生してしまいます。
 2025-12-24 at 21.02.23.png

なお、MTU を増やしていない場合は、IKE_INTERMEDIATE がフラグメントしていることが確認できます。
 2025-12-24 at 21.07.42.png

トップに戻る

まとめ

本記事では、StrongSwan 6.0.3 を用いて IKE_INTERMEDIATE で PQ/T Hybrid KEX CURVE_25519/KE1_ML_KEM_1024 が利用できることを確認しました。
また、PQC KEX のサイズが大きいことも併せて確認できました。

PQC への移行は今後ますます重要となりますので、ぜひご自身の環境でも検証してみてください。

トップに戻る

参考文献

Network Namespaceとvethでルーターのあるネットワークを作ってみる - Qiita
strongSwan - strongSwan 6.0.0 Released
strongSwan in Linux Network Namespaces :: strongSwan Documentation

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?