Dissecting IPsec with strongSwan on Debian

Translations

Overview

In this article, I will dissect the concept of Virtual Private Network (VPN) using the Internet Protocol security (IPsec) protocol. The goal is to help you better understand the various steps involved in setting up an IPsec tunnel, which relies on different protocols, and then to show you a concrete step-by-step example on the Debian GNU/Linux operating system using the strongSwan solution.

Introduction

In the context of networking, tunnels allow communication using a network over another one by applying data encapsulation, much like when driving inside a tunnel to cross mountains that are complex to cross without a tunnel in order to connect two valleys. Generally, this allows communication between two private networks (let’s say our valleys), which are not natively routed over the Internet, using a public network like the Internet (our mountains) as the underlying transport. In this case, it is called a VPN. There are other benefits to setting up tunnels and different types of network protocols that enable their creation. Here, we will focus on IPsec, a suite of protocols that allows the establishment of client-to-site VPN (a host to a remote network, for example remote employees connecting to their company network) or site-to-site VPN (a network to another remote network, for example a branch office site network connecting to the main site network).
From my experience, I have encountered IPsec in many implementations, and it is sometimes poorly understood in its setup and how it works. Beyond merely making it “work”, it is crucial to understand the various mechanisms involved to make the right configuration choices but also to facilitate maintenance and troubleshooting.

IPsec: Theory

IPsec is actually a suite of protocols that enables secure data transfer and negotiates the necessary security parameters. IPsec also offers different modes of operation that define how data is routed.

AH and ESP

Two protocols operating on top of the Internet Protocol (IP) provide different functionalities for transferring data as part of the framework of IPsec:

  • Authentication Header (AH) offers data integrity (preventing the data from being altered) and data authentication (ensuring that the data comes from the source IP address of the packet) for the entire IP packet.
  • Encapsulating Security Payload (ESP) offers data integrity, data confidentiality (preventing the data from being disclosed), and data authentication for the payload of the IP packet.

Note that both protocols have an anti-replay mechanism to prevent replay or malicious injection of packets using sequence numbers. Also, AH and ESP can potentially be combined.

Transport Mode and Tunnel Mode

IPsec can operate either in transport mode or in tunnel mode depending on the requirements.

  • In tunnel mode, the original IP packet (IP header and payload) is encapsulated in a new IP packet with an ESP and/or AH header. This mode is used to establish VPNs.
  • In transport mode, the original payload is kept within the original IP packet to which an ESP and/or AH header is added. There is no encapsulation and this mode is used to secure data transfer without establishing a VPN.

AH and ESP Headers in Transport Mode
AH and ESP Headers in Tunnel Mode

ISAKMP and IKE

Another protocol is used to establish the tunnel in a secure fashion: the Internet Security Association and Key Management Protocol (ISAKMP), which enables the exchange of encryption keys and authentication of the tunnel endpoints. ISAKMP is essentially a framework that can be implemented using various protocols: Internet Key Exchange (IKE), Kerberized Internet Negotiation of Keys (KINK)… The goal of these protocols is to build Security Associations (SA), which are sets of attributes (encryption algorithm, encryption keys, hash function, pseudo-random function, identifiers, etc.) making secure communication possible via AH or ESP.

IKE is widely used and relies on the User Datagram Protocol (UDP) on port 500. It allows various operations:

  • Authentication based on digital certificates or pre-shared key (PSK).
  • Encryption key exchange using the Diffie-Hellman (DH) key exchange method. This enables the establishment of a shared secret by sending information in clear text over an unsecured network. It relies on the mathematical principle that this exchanged information is extremely hard to reuse for an attacker as exponentiation is extremely difficult to reverse via discrete logarithm. The arithmetic modulus value used is specified via numbered groups (the larger the group number, the larger the modulus size which strengthens the key exchange). I encourage you to read this page for more details.

IKE exists in two versions: IKEv1 and IKEv2. The latter is more efficient and secure than its predecessor, so I will focus only on IKEv2 here. The IKEv2 protocol is a series of structured request and response exchanges aimed at defining SAs first to encrypt the IKE exchange, then to encrypt data exchange via ESP and/or AH:

  • IKE_SA_INIT: messages to negotiate security parameters (encryption algorithm for confidentiality, hashing function for integrity, pseudo-random function for deriving encryption keys from the initial negotiation, DH group and value for the initial key exchange, nonce to prevent replay of calculated cryptographic values).
  • IKE_AUTH: messages to transmit identities and create the first ESP and/or AH SA.
  • INFORMATIONAL: messages to verify the continuity of an SA, delete SAs, report errors, etc.
  • CREATE_CHILD_SA: messages to create additional ESP and/or AH SAs.

    IKEv2 Exchanges

IPsec allows Forward Secrecy (FS) or Perfect Forward Secrecy (PFS) by negotiating different encryption keys via a new DH exchange for each new SA with IKE. Thus, if the secrets used for key generation were compromised by an attacker, past communications are not compromised.

NAT-T

When using IPsec, several problems can arise due to potential use of Network Address Translation (NAT). If a source address translation in the IP header is performed along the path between the two IPsec gateways trying to negotiate tunnel establishment, the address of one gateway is modified, and its authenticity cannot be verified by its peer, preventing tunnel setup with IKE. Additionally, with the ESP protocol, there is no TCP or UDP header providing checksums and port numbers used for packet multiplexing via Port Address Translation (PAT).

To resolve these issues, IKE can detect the presence of NAT applied between the two gateways and trigger the encapsulation of IKE and then ESP packets in a UDP segment with (source and destination) port 4500. This is called NAT-Traversal (NAT-T). It allows the negotiation of the tunnel to complete and enables PAT if needed, thanks to the new UDP header bringing port numbers.
Note that AH is not supported by NAT-T because AH authentication relies on not modifying the IP header (unlike ESP). NAT-T usage is widespread due to the extensive use of NAT on the Internet. As a result, AH usage is restricted.

ESP Header in Tunnel Mode with NAT-T

In the next part of this article, we will see a concrete example of setting up an IPsec VPN and delve deeper into certain technical aspects.

IPsec: Practical Implementation with strongSwan on Debian

When setting up a VPN tunnel, several key elements must be chosen during its design:

  • The protocol: AH or ESP, depending on the desired security properties and the presence of NAT.
  • The use of NAT-T or not.
  • The mode: transport or tunnel.
  • The various encryption algorithms, hash functions, pseudo-random functions, and the DH group.
  • The method used for authentication: digital certificates or PSK.

To go further, I propose an example of implementation of IPsec ESP with IKEv2 using PSK authentication in tunnel mode on the Debian platform using the strongSwan solution. This open-source solution supports numerous protocols and modes for creating IPsec VPNs.
The diagram below illustrates the setup I used, consisting of 2 gateways (Gateway 1 and Gateway 2) establishing an IPsec VPN to interconnect a client and a remote server.

IPsec Lab Topology

Installation of strongSwan

On each gateway, install the strongSwan package:

$ sudo -- sh -c 'apt-get update && apt-get install -y strongswan'

On each gateway, verify that the strongswan service is active:

$ systemctl status strongswan-starter.service ; systemctl is-enabled strongswan-starter.service
● strongswan-starter.service - strongSwan IPsec IKEv1/IKEv2 daemon using ipsec.conf
Loaded: loaded (/lib/systemd/system/strongswan-starter.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2022-07-16 09:04:05 UTC; 20min ago
Main PID: 3207 (starter)
Tasks: 18 (limit: 529)
Memory: 2.1M
CPU: 13ms
CGroup: /system.slice/strongswan-starter.service
├─3207 /usr/lib/ipsec/starter --daemon charon --nofork
└─3211 /usr/lib/ipsec/charon
enabled

The gateways must be able to perform packet routing, so enable packet routing (or IP Forwarding) on each gateway:

$ sudo sysctl -w net.ipv4.ip_forward=1

Configuration of IPsec

On each gateway, save the default IPsec configuration file:

$ sudo mv /etc/ipsec.conf /etc/ipsec.conf.bkp

On each gateway, create a new IPsec configuration file:

$ sudo vim /etc/ipsec.conf

On the Gateway 1 gateway, insert the following configuration:

config setup
        charondebug="all"
        uniqueids=yes
conn ipsec-example
        type=tunnel
        auto=start
        keyexchange=ikev2
        authby=psk
        left=193.167.10.14
        leftsubnet=10.10.1.0/24
        right=193.167.10.13
        rightsubnet=10.10.2.0/24
        ike=aes256gcm16-sha256-modp1024!
        esp=aes256gcm16-sha256-modp1024!
        keyingtries=%forever
        ikelifetime=60s
        lifetime=30s
        dpddelay=10s
        dpdaction=restart

On the Gateway 2 gateway, insert the following configuration:

config setup
        charondebug="all"
        uniqueids=yes
conn ipsec-example
        type=tunnel
        auto=start
        keyexchange=ikev2
        authby=psk
        left=193.167.10.13
        leftsubnet=10.10.2.0/24
        right=193.167.10.14
        rightsubnet=10.10.1.0/24
        ike=aes256gcm16-sha256-modp1024!
        esp=aes256gcm16-sha256-modp1024!
        keyingtries=%forever
        ikelifetime=60s
        lifetime=30s
        dpddelay=10s
        dpdaction=restart

Let’s detail each of these parameters (I also invite you to read the official documentation):

  • config setup: section defining general settings
    • charondebug="all": sets the logging verbosity level (usually with the /var/log/syslog file) for the charon daemon responsible for implementing IKEv2 for strongSwan. Here, we choose to log all messages.
    • uniqueids=yes: specifies if a unique identifier should be used for each SA. Here, we choose yes.
  • conn ipsec-example: section defining IPsec connection parameters. Here, we name the section ipsec-example.
    • type=tunnel: defines the IPsec mode. Here, we choose tunnel mode.
    • auto=start: defines the action to take when the daemon starts. Here, we choose to load the parameters and start the IPsec connection.
    • keyexchange=ikev2: specifies the protocol for establishing the secure tunnel. Here, we choose IKEv2.
    • authby=psk: specifies the authentication method. Here, we choose PSK.
    • left=193.167.10.13: defines the external IP address (used to establish the tunnel) of the first gateway. Here, it’s the address of the eth2 interface of either Gateway 1 or Gateway 2 (switch the value depending on whether the configuration is for Gateway 1 or Gateway 2).
    • leftsubnet=10.10.2.0/24: defines the address of the internal network associated with the first gateway. Here, it’s the network associated with Gateway 1 or Gateway 2 (switch the value depending on whether the configuration is for Gateway 1 or Gateway 2).
    • right=193.167.10.14: defines the external IP address (used to establish the tunnel) of the second gateway. Here, it’s the address of the eth2 interface of Gateway 2 or Gateway 1 (switch the value depending on whether the configuration is for Gateway 2 or Gateway 1).
    • rightsubnet=10.10.1.0/24: defines the address of the internal network associated with the second gateway. Here, it’s the network associated with Gateway 2 or Gateway 1 (switch the value depending on whether the configuration is for Gateway 2 or Gateway 1).
    • ike=aes256gcm16-sha256-modp1024!: defines the cryptographic cipher suite (encryption algorithm, hash function, and DH group, which here includes the length of the arithmetic module) for IKE SAs. Here, we choose the Advanced Encryption Standard (AES) algorithm with a 256-bit encryption key length and Galois/Counter Mode (GCM) operation mode, which adds an additional authentication function; the SHA-256 hash function generates a 256-bit digest for data integrity checking and as a pseudo-random function; DH group 2 using a 1024-bit arithmetic module. You can refer here for all possible values.
    • esp=aes256gcm16-sha256-modp1024!!: defines the cryptographic suite or cipher suite (encryption algorithm, hash function, and DH group, which here includes the length of the arithmetic module) for ESP SAs. Here, we choose the AES algorithm with a 256-bit encryption key length and GCM operation mode, which adds an additional authentication function; the SHA-256 hash function generates a 256-bit digest for data integrity checking and as a pseudo-random function; DH group 2 using a 1024-bit arithmetic module, allowing for a new DH exchange during SA renegotiation. You can refer here for all possible values.
    • keyingtries=%forever: defines the number of attempts to negotiate a connection. Here, we choose to attempt indefinitely.
    • ikelifetime=60s: defines the validity period of an IKE negotiation channel (and thus an IKE SA) before renegotiation. Here, we intentionally choose a very low value, namely 60 seconds.
    • lifetime=30s: defines the validity period of an SA for sending data packets. Here, we intentionally choose a very low value, namely 30 seconds.
    • dpddelay=10s: defines the interval between two IKE INFORMATIONAL packets if no traffic is received. Here, we intentionally choose a low value, namely 10 seconds.
    • dpdaction=restart: defines the action to take in case of a timeout after sending IKE INFORMATIONAL messages. Here, we choose to restart the IKE negotiation.

Next, generate a PSK on one of the gateways (here we choose a randomly generated value encoded in Base64 with 32 bytes, providing sufficiently high entropy):

$ openssl rand -base64 32
pH56SwETVACv0FaMjPv28fH3Jkq6PVqeeRCvlTZtKCk=

On Gateway 1, add the PSK to the IPsec configuration:

$ "193.167.10.14 192.167.10.13 : PSK \"pH56SwETVACv0FaMjPv28fH3Jkq6PVqeeRCvlTZtKCk=\"" | sudo tee -a /etc/ipsec.secrets

On Gateway 2, add the PSK to the IPsec configuration:

$ "193.167.10.13 192.167.10.14 : PSK \"pH56SwETVACv0FaMjPv28fH3Jkq6PVqeeRCvlTZtKCk=\"" | sudo tee -a /etc/ipsec.secrets

Tunnel Establishment

Initiate the tunnel establishment by starting the IKE daemon charon with the IPsec configuration on each gateway:

$ sudo ipsec start

Verify the successful establishment of the tunnel with the following command on each gateway:

$ sudo ipsec status
Security Associations (1 up, 0 connecting):
ipsec-example[1]: ESTABLISHED 53 seconds ago, 193.167.10.14[193.167.10.14]...193.167.10.13[193.167.10.13]
ipsec-example{2}:  INSTALLED, TUNNEL, reqid 1, ESP SPIs: ceea3102_i c6ea8633_o
ipsec-example{2}:   10.10.1.0/24 === 10.10.2.0/24
Here, we can see that the tunnel has successfully established between the two gateways, and the values of the Security Parameter Index (SPI) used are displayed. These are 32-bit identifiers inserted into the ESP header, associating packets with SAs.

On the StrongSwan gateways, automatically insert static routes in order to route internal network traffic into the tunnel using routing table 220. You can view these routes once the daemon is launched:

$ sudo ip route list table 220
10.10.2.0/24 via 193.167.10.13 dev eth2 proto static src 10.10.1.254
In our case, here on Gateway 1, a route has been inserted to reach the internal network associated with Gateway 2 via Gateway 2 (this traffic will be encapsulated with ESP, as we will confirm shortly). If the traffic is emitted by Gateway 1 itself, it will arrive with the source IP address being the IP address of the interface of the internal network associated with Gateway 1.

StrongSwan uses the xfrm framework to encapsulate packets into the IPsec tunnel. We can visualize the configuration in place with xfrm on the gateways:

$ sudo ip xfrm policy
src 10.10.1.0/24 dst 10.10.2.0/24 
	dir out priority 375423 ptype main 
	tmpl src 193.167.10.14 dst 193.167.10.13
		proto esp spi 0xc6ea8633 reqid 1 mode tunnel
src 10.10.2.0/24 dst 10.10.1.0/24 
	dir fwd priority 375423 ptype main 
	tmpl src 193.167.10.13 dst 193.167.10.14
		proto esp reqid 1 mode tunnel
src 10.10.2.0/24 dst 10.10.1.0/24 
	dir in priority 375423 ptype main 
	tmpl src 193.167.10.13 dst 193.167.10.14
		proto esp reqid 1 mode tunnel

Another command allows us to visualize the SA states actually in place:

$ sudo ip xfrm state
src 193.167.10.14 dst 193.167.10.13
	proto esp spi 0xc6ea8633 reqid 1 mode tunnel
	replay-window 0 flag af-unspec
	aead rfc4106(gcm(aes)) 0xc6c5007ab2941ec02d4b5069ef311439aa71c7c4788b87347a0b6deb40ab46e4836a3f9d 128
	anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000
src 193.167.10.13 dst 193.167.10.14
	proto esp spi 0xceea3102 reqid 1 mode tunnel
	replay-window 32 flag af-unspec
	aead rfc4106(gcm(aes)) 0x6c9dfc3a57558810a3e3fcab5946a89df77f68d05acca022e0530efbfb9d23e12c1f475e 128
	anti-replay context: seq 0x0, oseq 0x0, bitmap 0x00000000

By looking at the StrongSwan logs, we can track the successful establishment of the tunnel:

$ sudo tail -fn 0 /var/log/syslog | grep charon
Jul 16 14:27:54 debian11 charon: 00[DMN] Starting IKE charon daemon (strongSwan 5.9.1, Linux 5.10.0-12-amd64, x86_64)
Jul 16 14:27:54 debian11 charon: 00[CFG] loading ca certificates from '/etc/ipsec.d/cacerts'
Jul 16 14:27:54 debian11 charon: 00[CFG] loading aa certificates from '/etc/ipsec.d/aacerts'
Jul 16 14:27:54 debian11 charon: 00[CFG] loading ocsp signer certificates from '/etc/ipsec.d/ocspcerts'
Jul 16 14:27:54 debian11 charon: 00[CFG] loading attribute certificates from '/etc/ipsec.d/acerts'
Jul 16 14:27:54 debian11 charon: 00[CFG] loading crls from '/etc/ipsec.d/crls'
Jul 16 14:27:54 debian11 charon: 00[CFG] loading secrets from '/etc/ipsec.secrets'
Jul 16 14:27:54 debian11 charon: 00[CFG]   loaded IKE secret for 193.167.10.14 192.167.10.13
Jul 16 14:27:54 debian11 charon: 00[LIB] loaded plugins: charon aesni aes rc2 sha2 sha1 md5 mgf1 random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pkcs8 pkcs12 pgp dnskey sshkey pem openssl fips-prf gmp agent xcbc hmac gcm drbg attr kernel-netlink resolve socket-default connmark stroke updown eap-mschapv2 xauth-generic counters
Jul 16 14:27:54 debian11 charon: 00[LIB] dropped capabilities, running as uid 0, gid 0
Jul 16 14:27:54 debian11 charon: 00[JOB] spawning 16 worker threads
Jul 16 14:27:54 debian11 charon: 05[CFG] received stroke: add connection 'ipsec-example'
Jul 16 14:27:54 debian11 charon: 05[CFG] added configuration 'ipsec-example'
Jul 16 14:27:54 debian11 charon: 06[CFG] received stroke: initiate 'ipsec-example'
Jul 16 14:27:54 debian11 charon: 06[IKE] initiating IKE_SA ipsec-example[1] to 193.167.10.13
Jul 16 14:27:54 debian11 charon: 06[ENC] generating IKE_SA_INIT request 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(FRAG_SUP) N(HASH_ALG) N(REDIR_SUP) ]
Jul 16 14:27:54 debian11 charon: 06[NET] sending packet: from 193.167.10.14[500] to 193.167.10.13[500] (328 bytes)
Jul 16 14:27:54 debian11 charon: 09[NET] received packet: from 193.167.10.13[500] to 193.167.10.14[500] (336 bytes)
Jul 16 14:27:54 debian11 charon: 09[ENC] parsed IKE_SA_INIT response 0 [ SA KE No N(NATD_S_IP) N(NATD_D_IP) N(FRAG_SUP) N(HASH_ALG) N(CHDLESS_SUP) N(MULT_AUTH) ]
Jul 16 14:27:54 debian11 charon: 09[CFG] selected proposal: IKE:AES_GCM_16_256/PRF_HMAC_SHA2_256/MODP_1024
Jul 16 14:27:54 debian11 charon: 09[IKE] authentication of '193.167.10.14' (myself) with pre-shared key
Jul 16 14:27:54 debian11 charon: 09[IKE] establishing CHILD_SA ipsec-example{1}
Jul 16 14:27:54 debian11 charon: 09[ENC] generating IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH SA TSi TSr N(MOBIKE_SUP) N(ADD_4_ADDR) N(ADD_4_ADDR) N(MULT_AUTH) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
Jul 16 14:27:54 debian11 charon: 09[NET] sending packet: from 193.167.10.14[4500] to 193.167.10.13[4500] (269 bytes)
Jul 16 14:27:54 debian11 charon: 10[NET] received packet: from 193.167.10.13[4500] to 193.167.10.14[4500] (237 bytes)
Jul 16 14:27:54 debian11 charon: 10[ENC] parsed IKE_AUTH response 1 [ IDr AUTH SA TSi TSr N(AUTH_LFT) N(MOBIKE_SUP) N(ADD_4_ADDR) N(ADD_4_ADDR) ]
Jul 16 14:27:54 debian11 charon: 10[IKE] authentication of '193.167.10.13' with pre-shared key successful
Jul 16 14:27:54 debian11 charon: 10[IKE] IKE_SA ipsec-example[1] established between 193.167.10.14[193.167.10.14]...193.167.10.13[193.167.10.13]
Jul 16 14:27:54 debian11 charon: 10[IKE] scheduling reauthentication in -543s
Jul 16 14:27:54 debian11 charon: 10[IKE] maximum IKE_SA lifetime -3s
Jul 16 14:27:54 debian11 charon: 10[CFG] selected proposal: ESP:AES_GCM_16_256/NO_EXT_SEQ
Jul 16 14:27:54 debian11 charon: 10[IKE] CHILD_SA ipsec-example{1} established with SPIs ceea3102_i c6ea8633_o and TS 10.10.1.0/24 === 10.10.2.0/24
Jul 16 14:27:54 debian11 charon: 10[IKE] received AUTH_LIFETIME of -839s, scheduling reauthentication in -1379s
Jul 16 14:27:54 debian11 charon: 10[IKE] peer supports MOBIKE

Data Transfer in the Tunnel

Once the establishment of the IPsec tunnel is done, I conducted the following tests from the client:

  • Wait for 5 seconds.
  • Send 3 Internet Control Message Protocol (ICMP) Echo Request packets from the client to the server using the ping command to test data transfer via ESP.
  • Wait for 35 seconds.
  • Send 3 ICMP Echo Request packets from the client to the server using the ping command to re-test data transfer via ESP.

A packet capture was launched on the external interface eth2 of Gateway 1. Let’s go over a breakdown.

Packet Capture of the Tunnel Establishment and Data Transfer

I’ve set up a filter on ISAKMP, ICMP and ESP protocols.

Packet #1 is an IKE_SA_INIT request packet from Gateway 1 to Gateway 2.

IKE_SA_INIT Request Packet

As we can observe (even though not the entire payload is visbile), it contains the SA with cryptographic parameters. At this stage, only the SPI associated with the IKE SA tunnel originator (Gateway 1) has been generated.

Packet #2 is an IKE_SA_INIT response packet from Gateway 2 to Gateway 1.

IKE_SA_INIT Response Packet

As we can observe (even though not the entire payload is visbile), it contains the SA with cryptographic parameters. At this stage, both SPIs associated with the IKE SAs have been generated.

Packets #3 and #4 correspond to the IKE_AUTH request and response messages, respectively. Much of the payload of these packets is encrypted as it negotiates the ESP SAs. Note that StrongSwan activates NAT-T by default for IKE, so the IKE packet is encapsulated in a UDP segment transmitted with port 4500.

Packets #5 and #6, #8 and #9, #11 and #12 correspond to the first 3 pairs of ICMP Echo Request and Echo Reply packets encapsulated in ESP packets and therefore encrypted. These packets contain two interesting pieces of information: the ESP SPI and the ESP sequence number. Packets #7, #10, and #13 correspond to the decapsulated and unencrypted ICMP Echo Reply responses transmitted by Gateway 2 to the client.

Packets #14 and #15 correspond to IKE INFORMATIONAL messages occurring approximately 10 seconds after the last ICMP data packet. This is the result of the dpddelay=10s parameter we configured to check the tunnel state in case of inactivity after 10 seconds. Indeed, 10 seconds later, in the absence of transmitted data, a new exchange of this type occurs via packets #16 and #17.

About 30 seconds after the tunnel establishment (which occurred from packet #4), we can see a bilateral IKE INFORMATIONAL exchange starting from packet #18 to renegotiate the ESP SAs. This results in an IKE CREATE_CHILD_SA exchange via packets #22 and #23. This is the consequence of the lifetime=30s parameter we configured.

Packets #24 and #25, #27 and #28, #30 and #31 correspond to the next 3 pairs of ICMP Echo Request and Echo Reply packets encapsulated in ESP packets and therefore encrypted. These packets show that the ESP SPI has changed. Indeed, this is the result of the IKE CREATE_CHILD_SA renegotiation that occurred in packets #22 and #23.
Packets #26, #29, and #32 correspond to the decapsulated and unencrypted ICMP Echo Reply responses transmitted by Gateway 2 to the client.

The IKE behavior with checks and renegotiations continues in the same manner then with subsequent packets.

Conclusion

We have reviewed how IPsec is designed around a suite of protocols essential for establishing a secure tunnel. The practical implementation, using IPsec ESP in tunnel mode with PSK via StrongSwan on Debian, allowed us to verify the theory and understand step-by-step the different stages in the life of an IPsec tunnel.

Sources

Translations