Important notices
Before you add a new report, we ask you kindly to acknowledge the following:
Describe the bug
When establishing an IPsec IKEv2 site-to-site tunnel between OPNsense (initiator
or responder for IKE_SA) and a pfSense peer (strongSwan based), OPNsense fails to
include the configured Perfect Forward Secrecy (PFS) Diffie-Hellman group (e.g.,
ECP_521) in the ESP proposal for the initial Child SA created during the IKE_AUTH
exchange. This occurs even when the swanctl.conf on OPNsense correctly specifies
a PFS group in the esp_proposals for the child connection.
As a result, the peer (pfSense) receives a P2 proposal from OPNsense without the
PFS group and establishes the Child SA without PFS (evident from the peer's
logs and the resulting IPsec status).
Interestingly, if the peer (pfSense) later initiates a CREATE_CHILD_SA (e.g., for
a Child SA rekey), OPNsense correctly responds to pfSense's proposal (which includes
a PFS group), and that specific rekeyed Child SA can be established with PFS. The
issue is specifically with the P2 proposal OPNsense sends for the first Child SA
established with IKE_AUTH.
This has been observed with strongSwan 5.9.14 on OPNsense OPNsense 25.1.5_5-amd64.
PFS negotiation worked with the legacy IPSec setup on OPNsense. I have only noticed
this issue since migrating to the new IPSEC connection setup in OPNsense; the pfSense side
has remained unchanged, so I suspect that the fault lies with OPNsense or there has
been some other regression.
To Reproduce
Steps to reproduce the behavior:
- Configure an IPsec IKEv2 site-to-site tunnel on OPNsense.
- Phase 1: Standard IKEv2 settings,
aes256-sha512-ec521 [DH21, NIST EC]
- Phase 2 (Child Connection):
- Go to
VPN > IPsec > Connections, edit the relevant connection.
- Under "Children", edit the child SA.
- For "ESP proposals", select only one proposal that explicitly includes
a PFS group. For example:
aes256gcm16-ecp521 (AES-GCM 256 with 16-byte ICV and ECP521 for
PFS)
- OR
aes256-sha512-ecp521 (AES-CBC 256 with SHA512 and ECP521 for
PFS)
start_action is set to trap
- Configure the peer (e.g., pfSense) with matching P1 settings and a P2 configuration
that expects the same ESP proposal with the PFS group (e.g., AES256-GCM with ECP521
PFS, or AES256-CBC/SHA512 with ECP521 PFS).
- Restart the IPsec service on both OPNsense and the peer to force a fresh IKE_SA
and initial Child SA establishment.
- Observe the logs on the peer (pfSense). The
received proposals for P2 from
OPNsense will be missing the ECP_521 (or other configured PFS group) component.
- Observe the OPNsense logs. The
selected proposal for the initial Child SA will
also reflect the non-PFS version.
- Check the IPsec status on the peer; it will likely show no PFS group for the
active P2 SA.
Expected behavior
OPNsense should send the P2 ESP proposal including the configured PFS DH group (e.g.,
ECP_521) as part of the SA payload in the IKE_AUTH message (for the first Child
SA). The peer should receive this complete proposal, and the initial Child SA should
be established with PFS.
The OPNsense swanctl.conf should accurately reflect what is sent over the wire.
If esp_proposals = aes256gcm16-ecp521 is set, then aes256gcm16-ecp521 should
be offered.
Describe alternatives you considered
- Using AES-CBC with PFS (
aes256-sha512-ecp521): The issue persists. OPNsense
still fails to send the ecp521 component in its initial P2 proposal.
- Allowing non-PFS fallback on peer: This allows the tunnel to establish but
without the desired PFS security for the initial Child SA.
- Relying on Child SA rekeys: If the peer (pfSense) initiates a Child SA rekey
(CREATE_CHILD_SA) with a PFS proposal, OPNsense responds correctly, and that
rekeyed SA can have PFS. This is not ideal as the tunnel lacks PFS for the duration
of the first Child SA (~1 hour).
Screenshots
I added some (redacted) screenshots to my blog post here:
https://du.nkel.dev/blog/2021-11-19_pfsense_opnsense_ipsec_cgnat/#opnsense-ipsec
Note that the ECP_521 shown in the P2 of the pfSense screenshot is after the
first negotiation. It is initially lacking.
Relevant log files
1. OPNsense `swanctl.conf` (showing correct P2 configuration)
# This file is automatically generated. Do not edit
connections {
7f92e3a1-0d2a-49fc-9084-ec093f479d4e {
proposals = aes256-sha512-ecp521
unique = replace
aggressive = no
version = 2
mobike = no
local_addrs = jashdejvmiuqlachhsqaxs.siteb.example.com
remote_addrs = 31.31.31.31
encap = no
rekey_time = 27000
dpd_delay = 20
dpd_timeout = 120
send_certreq = no
keyingtries = 0
local-a3a7c6c9-1f84-473d-947b-2d00473db2ac {
round = 0
auth = psk
id = alex@jashdejvmiuqlachhsqaxs.siteb.example.com
}
remote-64c7f988-efcd-4e91-8012-6c4c03cf8450 {
round = 0
auth = psk
id = 31.31.31.31
}
children {
2cd5a0f4-1c3e-48c6-a58a-038a3891d957 {
esp_proposals = aes256-sha512-ecp521
sha256_96 = no
start_action = trap
close_action = none
dpd_action = trap
mode = tunnel
policies = yes
local_ts = 192.168.128.0/17
remote_ts = 192.168.0.0/17
rekey_time = 3600
updown = /usr/local/opnsense/scripts/ipsec/updown_event.py --connection_child 2cd5a0f4-1c3e-48c6-a58a-038a3891d957
}
}
}
}
pools {
}
secrets {
ike-ccf1e472-b163-4f35-9f02-05c8cfafac82 {
id-0 = alex@jashdejvmiuqlachhsqaxs.siteb.example.com
id-1 = 31.31.31.31
secret = 0LUDGZwTSmQIHRLsZlyCx3fDSlMKkRr7Fovx4jKbwBJry4dXVZ1ooBUO8LUDGZwTSmQZlylMKkRr7=
}
}
# Include config snippets
include conf.d/*.conf
(values redacted or replaced with rendom uids)
2. OPNsense charon log excerpt:
Line at 2025-05-11T12:13:18 shows that PFS (ECP_521) is missing.
2025-05-11T12:13:18 Informational charon 15[CFG] <339d9b96-da93-48b6-ab54-33438ac4b423|3> selected proposal: ESP:AES_CBC_256/HMAC_SHA2_512_256/NO_EXT_SEQ
Broader log excerpt
2025-05-11T12:13:18 Informational charon 15[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|3> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (320 bytes)
2025-05-11T12:13:18 Informational charon 15[ENC] <339d9b96-da93-48b6-ab54-33438ac4b423|3> generating IKE_AUTH response 1 [ IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr ]
2025-05-11T12:13:18 Notice charon [UPDOWN] received up-client event for reqid 1
2025-05-11T12:13:18 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> CHILD_SA ab662ff1-5110-4d46-86ad-02c695bc67a1{5} established with SPIs c5c8cfc2_i c679466d_o and TS 192.168.128.0/17 === 192.168.0.0/17
2025-05-11T12:13:18 Informational charon 15[CFG] <339d9b96-da93-48b6-ab54-33438ac4b423|3> selected proposal: ESP:AES_CBC_256/HMAC_SHA2_512_256/NO_EXT_SEQ
2025-05-11T12:13:18 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> maximum IKE_SA lifetime 27423s
2025-05-11T12:13:18 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> scheduling rekeying in 24723s
2025-05-11T12:13:18 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> IKE_SA 339d9b96-da93-48b6-ab54-33438ac4b423[3] established between 111.111.111.111[alex@jashdejvmiuqlachhsqaxs.siteb.example.com]...31.31.31.31[31.31.31.31]
2025-05-11T12:13:17 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|2> destroying duplicate IKE_SA for peer '31.31.31.31', received INITIAL_CONTACT
2025-05-11T12:13:17 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> authentication of 'alex@jashdejvmiuqlachhsqaxs.siteb.example.com' (myself) with pre-shared key
2025-05-11T12:13:17 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding
2025-05-11T12:13:17 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|3> authentication of '31.31.31.31' with pre-shared key successful
2025-05-11T12:13:17 Informational charon 15[CFG] <339d9b96-da93-48b6-ab54-33438ac4b423|3> selected peer config '339d9b96-da93-48b6-ab54-33438ac4b423'
2025-05-11T12:13:17 Informational charon 15[CFG] <3> looking for peer configs matching 111.111.111.111[alex@jashdejvmiuqlachhsqaxs.siteb.example.com]...31.31.31.31[31.31.31.31]
2025-05-11T12:13:17 Informational charon 15[ENC] <3> parsed IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr N(MULT_AUTH) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
2025-05-11T12:13:17 Informational charon 15[NET] <3> received packet: from 31.31.31.31[500] to 111.111.111.111[500] (464 bytes)
2025-05-11T12:13:17 Informational charon 15[NET] <3> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (348 bytes)
2025-05-11T12:13:17 Informational charon 15[ENC] <3> generating 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) ]
2025-05-11T12:13:17 Informational charon 15[CFG] <3> selected proposal: IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521
2025-05-11T12:13:17 Informational charon 15[IKE] <3> 31.31.31.31 is initiating an IKE_SA
2025-05-11T12:13:17 Informational charon 15[ENC] <3> parsed 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) ]
2025-05-11T12:13:17 Informational charon 15[NET] <3> received packet: from 31.31.31.31[500] to 111.111.111.111[500] (340 bytes)
2025-05-11T12:13:15 Informational charon 15[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|2> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (96 bytes)
2025-05-11T12:13:15 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|2> retransmit 1 of request with message ID 0
2025-05-11T12:13:11 Informational charon 15[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|2> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (96 bytes)
2025-05-11T12:13:11 Informational charon 15[ENC] <339d9b96-da93-48b6-ab54-33438ac4b423|2> generating INFORMATIONAL request 0 [ ]
2025-05-11T12:13:11 Informational charon 15[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|2> sending DPD request
2025-05-11T11:23:42 Informational charon 14[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|1> IKE_SA deleted
2025-05-11T11:23:42 Informational charon 14[ENC] <339d9b96-da93-48b6-ab54-33438ac4b423|1> parsed INFORMATIONAL response 2 [ ]
2025-05-11T11:23:42 Informational charon 14[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|1> received packet: from 31.31.31.31[500] to 111.111.111.111[500] (96 bytes)
2025-05-11T11:23:42 Informational charon 14[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|1> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (96 bytes)
2025-05-11T11:23:42 Informational charon 14[ENC] <339d9b96-da93-48b6-ab54-33438ac4b423|1> generating INFORMATIONAL request 2 [ D ]
2025-05-11T11:23:42 Informational charon 14[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|1> sending DELETE for IKE_SA 339d9b96-da93-48b6-ab54-33438ac4b423[1]
2025-05-11T11:23:42 Informational charon 14[IKE] <339d9b96-da93-48b6-ab54-33438ac4b423|1> deleting IKE_SA 339d9b96-da93-48b6-ab54-33438ac4b423[1] between 111.111.111.111[alex@jashdejvmiuqlachhsqaxs.siteb.example.com]...31.31.31.31[31.31.31.31]
2025-05-11T11:23:33 Informational charon 14[NET] <339d9b96-da93-48b6-ab54-33438ac4b423|2> sending packet: from 111.111.111.111[500] to 31.31.31.31[500] (368 bytes)
2025-05-11T11:23:33 Informational charon 14[ENC] <339d9b96-da93-48b6-ab54-33438ac4b423|2> generating CREATE_CHILD_SA response 2 [ N(ESP_TFC_PAD_N) SA No KE TSi TSr ]
3. pfSense log excerpt:
This one is from an earlier connection attempt, where I tested with AES256gcm16. Notice that the proposed payload from OPNsense does not include the PFS ECP_521 (but pfSense expects it).
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selected proposal: ESP:AES_GCM_16_256/NO_EXT_SEQ
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> configured proposals: ESP:AES_GCM_16_256/ECP_521/NO_EXT_SEQ
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> received proposals: ESP:AES_GCM_16_256/NO_EXT_SEQ
This looks the same for AES-CBC. Unfortunately, I am having trouble getting the full logs from my remote pfSense side because the pfSense logs are clipped at 50 lines, and this is not enough for a full connection initialization.
Broader pfSense log for the above
May 11 11:09:57 charon 88717 15[CFG] vici client 1873 disconnected
May 11 11:09:57 charon 88717 05[CFG] vici client 1873 requests: list-sas
May 11 11:09:57 charon 88717 05[CFG] vici client 1873 registered for: list-sa
May 11 11:09:57 charon 88717 15[CFG] vici client 1873 connected
May 11 11:09:54 charon 88717 05[NET] <con2|2195> sending packet: from 31.31.31.31[500] to 111.111.111.111[500] (272 bytes)
May 11 11:09:54 charon 88717 05[ENC] <con2|2195> generating IKE_AUTH response 1 [ IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr ]
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> CHILD_SA con2{4993} state change: INSTALLING => INSTALLED
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> CHILD_SA con2{4993} established with SPIs cc84ae1f_i c1a3abd5_o and TS 192.168.0.0/17|/0 === 192.168.128.0/17|/0
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> SPI 0xc1a3abd5, src 31.31.31.31 dst 111.111.111.111
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> adding outbound ESP SA
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> SPI 0xcc84ae1f, src 111.111.111.111 dst 31.31.31.31
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> adding inbound ESP SA
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> using AES_GCM_16 for encryption
May 11 11:09:54 charon 88717 05[CHD] <con2|2195> CHILD_SA con2{4993} state change: CREATED => INSTALLING
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> config: 192.168.128.0/17|/0, received: 192.168.128.0/17|/0 => match: 192.168.128.0/17|/0
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selecting traffic selectors for other:
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> config: 192.168.0.0/17|/0, received: 192.168.0.0/17|/0 => match: 192.168.0.0/17|/0
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selecting traffic selectors for us:
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selected proposal: ESP:AES_GCM_16_256/NO_EXT_SEQ
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> configured proposals: ESP:AES_GCM_16_256/ECP_521/NO_EXT_SEQ
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> received proposals: ESP:AES_GCM_16_256/NO_EXT_SEQ
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> proposal matches
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selecting proposal:
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> found matching child config "con2" with prio 10
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> candidate "con2" with prio 5+5
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> 192.168.128.0/17|/0
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> proposing traffic selectors for other:
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> 192.168.0.0/17|/0
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> proposing traffic selectors for us:
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> looking for a child config for 192.168.0.0/17|/0 === 192.168.128.0/17|/0
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> maximum IKE_SA lifetime 27252s
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> scheduling rekeying in 24372s
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> IKE_SA con2[2195] state change: CONNECTING => ESTABLISHED
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> IKE_SA con2[2195] established between 31.31.31.31[31.31.31.31]...111.111.111.111[alex@jashdejvmiuqlachhsqaxs.siteb.example.com]
May 11 11:09:54 charon 88717 05[CHD] <con2|2194> CHILD_SA con2{4992} state change: INSTALLED => DESTROYING
May 11 11:09:54 charon 88717 05[IKE] <con2|2194> IKE_SA con2[2194] state change: ESTABLISHED => DESTROYING
May 11 11:09:54 charon 88717 05[IKE] <con2|2194> destroying duplicate IKE_SA for peer 'alex@jashdejvmiuqlachhsqaxs.siteb.example.com', received INITIAL_CONTACT
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> successfully created shared key MAC
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> authentication of '31.31.31.31' (myself) with pre-shared key
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding
May 11 11:09:54 charon 88717 05[IKE] <con2|2195> authentication of 'alex@jashdejvmiuqlachhsqaxs.siteb.example.com' with pre-shared key successful
May 11 11:09:54 charon 88717 05[CFG] <con2|2195> selected peer config 'con2'
May 11 11:09:54 charon 88717 05[CFG] <2195> candidate "con2", match: 20/20/3100 (me/other/ike)
May 11 11:09:54 charon 88717 05[CFG] <2195> looking for peer configs matching 31.31.31.31[31.31.31.31]...111.111.111.111[alex@jashdejvmiuqlachhsqaxs.siteb.example.com]
May 11 11:09:54 charon 88717 05[ENC] <2195> parsed IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr N(MULT_AUTH) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
May 11 11:09:54 charon 88717 12[IKE] <con2|2194> nothing to initiate
May 11 11:09:54 charon 88717 12[IKE] <con2|2194> activating new tasks
May 11 11:09:54 charon 88717 12[CHD] <con2|2194> CHILD_SA con2{4992} state change: INSTALLING => INSTALLED
May 11 11:09:54 charon 88717 12[IKE] <con2|2194> CHILD_SA con2{4992} established with SPIs ca5f90d2_i c3b8b594_o and TS 192.168.0.0/17|/0 === 192.168.128.0/17|/0
May 11 11:09:54 charon 88717 12[CHD] <con2|2194> SPI 0xc3b8b594, src 31.31.31.31 dst 111.111.111.111
Alternate pfSense log with `aes256-sha512-ecp521` on both sides
P1 is successfully using DH21 (AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/**ECP_521**), but P2 selects a proposal without **ECP_521**
May 11 14:49:47 charon 3118 13[CHD] <con2|1> CHILD_SA con2{1} state change: INSTALLING => INSTALLED
May 11 14:49:47 charon 3118 13[IKE] <con2|1> CHILD_SA con2{1} established with SPIs c58fcb37_i c1cb61df_o and TS 192.168.0.0/17|/0 === 192.168.128.0/17|/0
May 11 14:49:47 charon 3118 13[CHD] <con2|1> SPI 0xc1cb61df, src 31.31.31.31 dst 111.111.111.111
May 11 14:49:47 charon 3118 13[CHD] <con2|1> adding outbound ESP SA
May 11 14:49:47 charon 3118 13[CHD] <con2|1> SPI 0xc58fcb37, src 111.111.111.111 dst 31.31.31.31
May 11 14:49:47 charon 3118 13[CHD] <con2|1> adding inbound ESP SA
May 11 14:49:47 charon 3118 13[CHD] <con2|1> using HMAC_SHA2_512_256 for integrity
May 11 14:49:47 charon 3118 13[CHD] <con2|1> using AES_CBC for encryption
May 11 14:49:47 charon 3118 13[CHD] <con2|1> CHILD_SA con2{1} state change: CREATED => INSTALLING
May 11 14:49:47 charon 3118 13[CFG] <con2|1> selected proposal: ESP:AES_CBC_256/HMAC_SHA2_512_256/NO_EXT_SEQ
May 11 14:49:47 charon 3118 13[IKE] <con2|1> received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding
May 11 14:49:47 charon 3118 13[IKE] <con2|1> maximum IKE_SA lifetime 28097s
May 11 14:49:47 charon 3118 13[IKE] <con2|1> scheduling rekeying in 25217s
May 11 14:49:47 charon 3118 13[IKE] <con2|1> IKE_SA con2[1] established between 31.31.31.31[31.31.31.31]...111.111.111.111[jashdejvmiuqlachhsqaxs.siteb.example.com]
May 11 14:49:47 charon 3118 13[IKE] <con2|1> authentication of 'jashdejvmiuqlachhsqaxs.siteb.example.com' with pre-shared key successful
May 11 14:49:47 charon 3118 13[ENC] <con2|1> parsed IKE_AUTH response 1 [ IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr ]
May 11 14:49:47 charon 3118 13[NET] <con2|1> received packet: from 111.111.111.111[500] to 31.31.31.31[500] (320 bytes)
May 11 14:49:47 charon 3118 13[NET] <con2|1> sending packet: from 31.31.31.31[500] to 111.111.111.111[500] (368 bytes)
May 11 14:49:47 charon 3118 13[ENC] <con2|1> generating IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH N(ESP_TFC_PAD_N) SA TSi TSr N(MULT_AUTH) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
May 11 14:49:47 charon 3118 13[IKE] <con2|1> establishing CHILD_SA con2{1}
May 11 14:49:47 charon 3118 13[IKE] <con2|1> authentication of '31.31.31.31' (myself) with pre-shared key
May 11 14:49:47 charon 3118 13[CFG] <con2|1> selected proposal: IKE:AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/ECP_521
May 11 14:49:47 charon 3118 13[ENC] <con2|1> 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) ]
May 11 14:49:47 charon 3118 13[NET] <con2|1> received packet: from 111.111.111.111[500] to 31.31.31.31[500] (348 bytes)
May 11 14:49:47 charon 3118 13[NET] <con2|1> sending packet: from 31.31.31.31[500] to 111.111.111.111[500] (340 bytes)
Additional context
- The issue is consistent for the initial Child SA created during the IKE_AUTH
exchange, regardless of whether OPNsense or the peer initiates the IKE_SA.
- Phase 1 (IKE SA) negotiates correctly, including its own DH group (ECP_521).
- The problem appears to be specific to how OPNsense (strongSwan 5.9.14) formulates
the outgoing P2 proposal payload to include the PFS DH group.
- Both AES-GCM and AES-CBC P2 proposals (when configured with ECP_521 on OPNsense)
exhibit this behavior where the ECP_521 is not sent/received by the peer for the
initial Child SA.
- I debugged this over the last 2 weeks without success, which is why I am now adding this here as a bug.
Environment
OPNsense Version: 25.1.5_5 (amd64)
Hardware: Protectli FW4B - 4 Port Intel® J3160
strongSwan Version (OPNsense): 5.9.14
Peer Device: pfSense
Peer strongSwan Version: pfSense 2.7.2, strongSwan 5.9.11_3
Important notices
Before you add a new report, we ask you kindly to acknowledge the following:
I have read the contributing guide lines at https://github.com/opnsense/core/blob/master/CONTRIBUTING.md
I am convinced that my issue is new after having checked both open and closed
issues at https://github.com/opnsense/core/issues?q=is%3Aissue+ipsec+pfs+proposal+strongswan
(Example search query)
Describe the bug
When establishing an IPsec IKEv2 site-to-site tunnel between OPNsense (initiator
or responder for IKE_SA) and a pfSense peer (strongSwan based), OPNsense fails to
include the configured Perfect Forward Secrecy (PFS) Diffie-Hellman group (e.g.,
ECP_521) in the ESP proposal for the initial Child SA created during the IKE_AUTH
exchange. This occurs even when the
swanctl.confon OPNsense correctly specifiesa PFS group in the
esp_proposalsfor the child connection.As a result, the peer (pfSense) receives a P2 proposal from OPNsense without the
PFS group and establishes the Child SA without PFS (evident from the peer's
logs and the resulting IPsec status).
Interestingly, if the peer (pfSense) later initiates a
CREATE_CHILD_SA(e.g., fora Child SA rekey), OPNsense correctly responds to pfSense's proposal (which includes
a PFS group), and that specific rekeyed Child SA can be established with PFS. The
issue is specifically with the P2 proposal OPNsense sends for the first Child SA
established with IKE_AUTH.
This has been observed with strongSwan 5.9.14 on OPNsense
OPNsense 25.1.5_5-amd64.PFS negotiation worked with the legacy IPSec setup on OPNsense. I have only noticed
this issue since migrating to the new IPSEC connection setup in OPNsense; the pfSense side
has remained unchanged, so I suspect that the fault lies with OPNsense or there has
been some other regression.
To Reproduce
Steps to reproduce the behavior:
aes256-sha512-ec521 [DH21, NIST EC]VPN > IPsec > Connections, edit the relevant connection.a PFS group. For example:
aes256gcm16-ecp521(AES-GCM 256 with 16-byte ICV and ECP521 forPFS)
aes256-sha512-ecp521(AES-CBC 256 with SHA512 and ECP521 forPFS)
start_actionis set totrapthat expects the same ESP proposal with the PFS group (e.g., AES256-GCM with ECP521
PFS, or AES256-CBC/SHA512 with ECP521 PFS).
and initial Child SA establishment.
received proposalsfor P2 fromOPNsense will be missing the
ECP_521(or other configured PFS group) component.selected proposalfor the initial Child SA willalso reflect the non-PFS version.
active P2 SA.
Expected behavior
OPNsense should send the P2 ESP proposal including the configured PFS DH group (e.g.,
ECP_521) as part of the SA payload in the IKE_AUTH message (for the first ChildSA). The peer should receive this complete proposal, and the initial Child SA should
be established with PFS.
The OPNsense
swanctl.confshould accurately reflect what is sent over the wire.If
esp_proposals = aes256gcm16-ecp521is set, thenaes256gcm16-ecp521shouldbe offered.
Describe alternatives you considered
aes256-sha512-ecp521): The issue persists. OPNsensestill fails to send the
ecp521component in its initial P2 proposal.without the desired PFS security for the initial Child SA.
(
CREATE_CHILD_SA) with a PFS proposal, OPNsense responds correctly, and thatrekeyed SA can have PFS. This is not ideal as the tunnel lacks PFS for the duration
of the first Child SA (~1 hour).
Screenshots
I added some (redacted) screenshots to my blog post here:
https://du.nkel.dev/blog/2021-11-19_pfsense_opnsense_ipsec_cgnat/#opnsense-ipsec
Note that the
ECP_521shown in the P2 of the pfSense screenshot is after thefirst negotiation. It is initially lacking.
Relevant log files
1. OPNsense `swanctl.conf` (showing correct P2 configuration)
(values redacted or replaced with rendom uids)
2. OPNsense charon log excerpt:
Line at 2025-05-11T12:13:18 shows that PFS (ECP_521) is missing.
Broader log excerpt
3. pfSense log excerpt:
This one is from an earlier connection attempt, where I tested with AES256gcm16. Notice that the proposed payload from OPNsense does not include the PFS ECP_521 (but pfSense expects it).
This looks the same for AES-CBC. Unfortunately, I am having trouble getting the full logs from my remote pfSense side because the pfSense logs are clipped at 50 lines, and this is not enough for a full connection initialization.
Broader pfSense log for the above
Alternate pfSense log with `aes256-sha512-ecp521` on both sides
P1 is successfully using DH21 (AES_CBC_256/HMAC_SHA2_512_256/PRF_HMAC_SHA2_512/**ECP_521**), but P2 selects a proposal without **ECP_521**Additional context
exchange, regardless of whether OPNsense or the peer initiates the IKE_SA.
the outgoing P2 proposal payload to include the PFS DH group.
exhibit this behavior where the ECP_521 is not sent/received by the peer for the
initial Child SA.
Environment
OPNsense Version: 25.1.5_5 (amd64)
Hardware: Protectli FW4B - 4 Port Intel® J3160
strongSwan Version (OPNsense): 5.9.14
Peer Device: pfSense
Peer strongSwan Version: pfSense 2.7.2, strongSwan 5.9.11_3