* [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519
@ 2025-05-15 8:06 Peter Müller
2025-05-15 8:09 ` [PATCH 2/2] Core Update 196: Adjust existing IPsec connections using ML-KEM Peter Müller
2025-05-15 8:16 ` [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Adolf Belka
0 siblings, 2 replies; 4+ messages in thread
From: Peter Müller @ 2025-05-15 8:06 UTC (permalink / raw)
To: IPFire: Development
In commit 887778e0888d51eb9942ae310a43f6d2813efad3, the post-quantum
key exchange algorithm ML-KEM was introduced, due to its support being
added in strongSwan 6.0. However, using PQC key exchanges is commonly
recommended only in conjunction with a traditional one, to avoid
encrypted traffic becoming subject to trivial decryption in case a PQC
algorithm proves weak, broken, or backdoored. OpenSSH, for instance,
combines ML-KEM 768 with Curve 25519 (mlkem768x25519-sha256), rather
than using ML-KEM alone.
This patch changes the chipher suites offered for IPsec connections to
always use ML-KEM as a hybrid with Curve 25519. This is possible due to
strongSwan 6.0 having added support for IKE intermediary key exchanges
(RFC 9370); see https://docs.strongswan.org/docs/latest/config/proposals.html#_key_exchange_methods
for additional information.
We can reasonably assume an IPsec peer supporting ML-KEM will also
support Curve 25519, as this has been around for much longer, and is
used quite commonly. Even if this is not the case, or if the IPsec peer
does not implement RFC 9370, any IPsec connection using our default
cipher selection will fall back to Curve 448, Curve 25519, or other,
hence continue working.
IPsec connections already created will need their ciphers to be changed
once during the Core Update routine where this patch will be
incorporated.
Tested-by: Peter Müller <peter.mueller@ipfire.org>
Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
---
html/cgi-bin/vpnmain.cgi | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/html/cgi-bin/vpnmain.cgi b/html/cgi-bin/vpnmain.cgi
index 4f81fecdf..154b94033 100644
--- a/html/cgi-bin/vpnmain.cgi
+++ b/html/cgi-bin/vpnmain.cgi
@@ -2374,11 +2374,11 @@ END
#use default advanced value
$cgiparams{'IKE_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[18];
$cgiparams{'IKE_INTEGRITY'} = 'sha2_512|sha2_256'; #[19];
- $cgiparams{'IKE_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
+ $cgiparams{'IKE_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
$cgiparams{'IKE_LIFETIME'} = '3'; #[16];
$cgiparams{'ESP_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[21];
$cgiparams{'ESP_INTEGRITY'} = 'sha2_512|sha2_256'; #[22];
- $cgiparams{'ESP_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
+ $cgiparams{'ESP_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
$cgiparams{'ESP_KEYLIFE'} = '1'; #[17];
$cgiparams{'COMPRESSION'} = 'off'; #[13];
$cgiparams{'ONLY_PROPOSED'} = 'on'; #[24];
@@ -2759,7 +2759,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
goto ADVANCED_ERROR;
}
foreach my $val (@temp) {
- if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
+ if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
$errormessage = $Lang::tr{'invalid input'};
goto ADVANCED_ERROR;
}
@@ -2800,7 +2800,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
goto ADVANCED_ERROR;
}
foreach my $val (@temp) {
- if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
+ if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
$errormessage = $Lang::tr{'invalid input'};
goto ADVANCED_ERROR;
}
@@ -2940,9 +2940,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
$checked{'IKE_INTEGRITY'}{'aesxcbc'} = '';
@temp = split('\|', $cgiparams{'IKE_INTEGRITY'});
foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; }
- $checked{'IKE_GROUPTYPE'}{'mlkem1024'} = '';
- $checked{'IKE_GROUPTYPE'}{'mlkem768'} = '';
- $checked{'IKE_GROUPTYPE'}{'mlkem512'} = '';
+ $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
+ $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
+ $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
$checked{'IKE_GROUPTYPE'}{'curve448'} = '';
$checked{'IKE_GROUPTYPE'}{'curve25519'} = '';
$checked{'IKE_GROUPTYPE'}{'768'} = '';
@@ -2983,9 +2983,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
$checked{'ESP_INTEGRITY'}{'aesxcbc'} = '';
@temp = split('\|', $cgiparams{'ESP_INTEGRITY'});
foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; }
- $checked{'ESP_GROUPTYPE'}{'mlkem1024'} = '';
- $checked{'ESP_GROUPTYPE'}{'mlkem768'} = '';
- $checked{'ESP_GROUPTYPE'}{'mlkem512'} = '';
+ $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
+ $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
+ $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
$checked{'ESP_GROUPTYPE'}{'curve448'} = '';
$checked{'ESP_GROUPTYPE'}{'curve25519'} = '';
$checked{'ESP_GROUPTYPE'}{'768'} = '';
@@ -3151,9 +3151,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
<td class='boldbase' width="15%">$Lang::tr{'grouptype'}</td>
<td class='boldbase'>
<select name='IKE_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
- <option value='mlkem1024' $checked{'IKE_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
- <option value='mlkem768' $checked{'IKE_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
- <option value='mlkem512' $checked{'IKE_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
+ <option value='x25519-ke1_mlkem1024' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
+ <option value='x25519-ke1_mlkem768' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
+ <option value='x25519-ke1_mlkem512' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
<option value='curve448' $checked{'IKE_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
<option value='curve25519' $checked{'IKE_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
<option value='e521' $checked{'IKE_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
@@ -3177,9 +3177,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
</td>
<td class='boldbase'>
<select name='ESP_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
- <option value='mlkem1024' $checked{'ESP_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
- <option value='mlkem768' $checked{'ESP_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
- <option value='mlkem512' $checked{'ESP_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
+ <option value='x25519-ke1_mlkem1024' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
+ <option value='x25519-ke1_mlkem768' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
+ <option value='x25519-ke1_mlkem512' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
<option value='curve448' $checked{'ESP_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
<option value='curve25519' $checked{'ESP_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
<option value='e521' $checked{'ESP_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
@@ -3757,7 +3757,7 @@ sub make_algos($$$$$) {
if ($mode eq "ike") {
push(@algo, $int);
- if ($grp =~ m/^mlkem(\d+)$/) {
+ if ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
push(@algo, "$grp");
} elsif ($grp =~ m/^e(.*)$/) {
push(@algo, "ecp$1");
@@ -3776,7 +3776,7 @@ sub make_algos($$$$$) {
if (!$pfs || $grp eq "none") {
# noop
- } elsif ($grp =~ m/^mlkem(\d+)$/) {
+ } elsif ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
push(@algo, "$grp");
} elsif ($grp =~ m/^e(.*)$/) {
push(@algo, "ecp$1");
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] Core Update 196: Adjust existing IPsec connections using ML-KEM
2025-05-15 8:06 [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Peter Müller
@ 2025-05-15 8:09 ` Peter Müller
2025-05-15 8:16 ` [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Adolf Belka
1 sibling, 0 replies; 4+ messages in thread
From: Peter Müller @ 2025-05-15 8:09 UTC (permalink / raw)
To: IPFire: Development
This causes existing IPsec connections using ML-KEM to always use it in
conjunction with Curve 25519, in line with the changes dfa7cd2bbac3c746569368d70fefaf1ff4e1fed2
implements for newly configured IPsec connections.
Again, we can reasonably assume an IPsec peer supporting ML-KEM also
supports Curve 25519. In case such a peer does not support RFC 9370, and
the IPsec connection was created using our default ciphers, it will fall
back to Curve 448, Curve 25519, or any other traditional algorithm.
This patch will break existing IPsec connections only if they are
exclusively using ML-KEM (which means the IPFire user reconfigured them
manually using the "advanced connection settings" section in the WebUI),
and the IPsec peer is configured in the same manner, and/or is an IPFire
machine not yet updated to Core Update 196. Any other IPFire-to-IPFire
IPsec connection will continue working, potentially falling back to
Curve 448 or 25519 until both peers are updated to Core Update 196,
after which ML-KEM in conjunction with Curve 25519 will be used again.
Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
---
config/rootfiles/core/196/update.sh | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/config/rootfiles/core/196/update.sh b/config/rootfiles/core/196/update.sh
index 0138fabcf..4f92b998b 100644
--- a/config/rootfiles/core/196/update.sh
+++ b/config/rootfiles/core/196/update.sh
@@ -32,6 +32,7 @@ for (( i=1; i<=$core; i++ )); do
done
# Stop services
+/etc/rc.d/init.d/ipsec stop
# Remove files
rm -rfv \
@@ -65,7 +66,14 @@ esac
# Apply SSH configuration
#/usr/local/bin/sshctrl
+# Change IPsec configuration of existing connections using ML-KEM
+# to always make use of hybrid key exchange in conjunction with Curve 25519.
+sed -i -e "s@-mlkem@-x25519-ke1_mlkem@g" /etc/ipsec.conf
+
# Start services
+if grep -q "ENABLED=on" /var/ipfire/vpn/settings; then
+ /etc/rc.d/init.d/ipsec start
+fi
# This update needs a reboot...
#touch /var/run/need_reboot
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519
2025-05-15 8:06 [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Peter Müller
2025-05-15 8:09 ` [PATCH 2/2] Core Update 196: Adjust existing IPsec connections using ML-KEM Peter Müller
@ 2025-05-15 8:16 ` Adolf Belka
2025-05-15 12:07 ` Adam Gibbons
1 sibling, 1 reply; 4+ messages in thread
From: Adolf Belka @ 2025-05-15 8:16 UTC (permalink / raw)
To: Peter Müller; +Cc: IPFire: Development-List
Hallo Peter,
Good to see you on the list again :+1:
This patch sounds a good approach to take.
Adolf.
On 15/05/2025 10:06, Peter Müller wrote:
> In commit 887778e0888d51eb9942ae310a43f6d2813efad3, the post-quantum
> key exchange algorithm ML-KEM was introduced, due to its support being
> added in strongSwan 6.0. However, using PQC key exchanges is commonly
> recommended only in conjunction with a traditional one, to avoid
> encrypted traffic becoming subject to trivial decryption in case a PQC
> algorithm proves weak, broken, or backdoored. OpenSSH, for instance,
> combines ML-KEM 768 with Curve 25519 (mlkem768x25519-sha256), rather
> than using ML-KEM alone.
>
> This patch changes the chipher suites offered for IPsec connections to
> always use ML-KEM as a hybrid with Curve 25519. This is possible due to
> strongSwan 6.0 having added support for IKE intermediary key exchanges
> (RFC 9370); see https://docs.strongswan.org/docs/latest/config/proposals.html#_key_exchange_methods
> for additional information.
>
> We can reasonably assume an IPsec peer supporting ML-KEM will also
> support Curve 25519, as this has been around for much longer, and is
> used quite commonly. Even if this is not the case, or if the IPsec peer
> does not implement RFC 9370, any IPsec connection using our default
> cipher selection will fall back to Curve 448, Curve 25519, or other,
> hence continue working.
>
> IPsec connections already created will need their ciphers to be changed
> once during the Core Update routine where this patch will be
> incorporated.
>
> Tested-by: Peter Müller <peter.mueller@ipfire.org>
> Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
> ---
> html/cgi-bin/vpnmain.cgi | 36 ++++++++++++++++++------------------
> 1 file changed, 18 insertions(+), 18 deletions(-)
>
> diff --git a/html/cgi-bin/vpnmain.cgi b/html/cgi-bin/vpnmain.cgi
> index 4f81fecdf..154b94033 100644
> --- a/html/cgi-bin/vpnmain.cgi
> +++ b/html/cgi-bin/vpnmain.cgi
> @@ -2374,11 +2374,11 @@ END
> #use default advanced value
> $cgiparams{'IKE_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[18];
> $cgiparams{'IKE_INTEGRITY'} = 'sha2_512|sha2_256'; #[19];
> - $cgiparams{'IKE_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
> + $cgiparams{'IKE_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
> $cgiparams{'IKE_LIFETIME'} = '3'; #[16];
> $cgiparams{'ESP_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[21];
> $cgiparams{'ESP_INTEGRITY'} = 'sha2_512|sha2_256'; #[22];
> - $cgiparams{'ESP_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
> + $cgiparams{'ESP_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
> $cgiparams{'ESP_KEYLIFE'} = '1'; #[17];
> $cgiparams{'COMPRESSION'} = 'off'; #[13];
> $cgiparams{'ONLY_PROPOSED'} = 'on'; #[24];
> @@ -2759,7 +2759,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> goto ADVANCED_ERROR;
> }
> foreach my $val (@temp) {
> - if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
> + if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
> $errormessage = $Lang::tr{'invalid input'};
> goto ADVANCED_ERROR;
> }
> @@ -2800,7 +2800,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> goto ADVANCED_ERROR;
> }
> foreach my $val (@temp) {
> - if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
> + if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
> $errormessage = $Lang::tr{'invalid input'};
> goto ADVANCED_ERROR;
> }
> @@ -2940,9 +2940,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> $checked{'IKE_INTEGRITY'}{'aesxcbc'} = '';
> @temp = split('\|', $cgiparams{'IKE_INTEGRITY'});
> foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; }
> - $checked{'IKE_GROUPTYPE'}{'mlkem1024'} = '';
> - $checked{'IKE_GROUPTYPE'}{'mlkem768'} = '';
> - $checked{'IKE_GROUPTYPE'}{'mlkem512'} = '';
> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
> $checked{'IKE_GROUPTYPE'}{'curve448'} = '';
> $checked{'IKE_GROUPTYPE'}{'curve25519'} = '';
> $checked{'IKE_GROUPTYPE'}{'768'} = '';
> @@ -2983,9 +2983,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> $checked{'ESP_INTEGRITY'}{'aesxcbc'} = '';
> @temp = split('\|', $cgiparams{'ESP_INTEGRITY'});
> foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; }
> - $checked{'ESP_GROUPTYPE'}{'mlkem1024'} = '';
> - $checked{'ESP_GROUPTYPE'}{'mlkem768'} = '';
> - $checked{'ESP_GROUPTYPE'}{'mlkem512'} = '';
> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
> $checked{'ESP_GROUPTYPE'}{'curve448'} = '';
> $checked{'ESP_GROUPTYPE'}{'curve25519'} = '';
> $checked{'ESP_GROUPTYPE'}{'768'} = '';
> @@ -3151,9 +3151,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> <td class='boldbase' width="15%">$Lang::tr{'grouptype'}</td>
> <td class='boldbase'>
> <select name='IKE_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
> - <option value='mlkem1024' $checked{'IKE_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
> - <option value='mlkem768' $checked{'IKE_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
> - <option value='mlkem512' $checked{'IKE_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
> + <option value='x25519-ke1_mlkem1024' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
> + <option value='x25519-ke1_mlkem768' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
> + <option value='x25519-ke1_mlkem512' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
> <option value='curve448' $checked{'IKE_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
> <option value='curve25519' $checked{'IKE_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
> <option value='e521' $checked{'IKE_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
> @@ -3177,9 +3177,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
> </td>
> <td class='boldbase'>
> <select name='ESP_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
> - <option value='mlkem1024' $checked{'ESP_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
> - <option value='mlkem768' $checked{'ESP_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
> - <option value='mlkem512' $checked{'ESP_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
> + <option value='x25519-ke1_mlkem1024' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
> + <option value='x25519-ke1_mlkem768' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
> + <option value='x25519-ke1_mlkem512' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
> <option value='curve448' $checked{'ESP_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
> <option value='curve25519' $checked{'ESP_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
> <option value='e521' $checked{'ESP_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
> @@ -3757,7 +3757,7 @@ sub make_algos($$$$$) {
> if ($mode eq "ike") {
> push(@algo, $int);
>
> - if ($grp =~ m/^mlkem(\d+)$/) {
> + if ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
> push(@algo, "$grp");
> } elsif ($grp =~ m/^e(.*)$/) {
> push(@algo, "ecp$1");
> @@ -3776,7 +3776,7 @@ sub make_algos($$$$$) {
>
> if (!$pfs || $grp eq "none") {
> # noop
> - } elsif ($grp =~ m/^mlkem(\d+)$/) {
> + } elsif ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
> push(@algo, "$grp");
> } elsif ($grp =~ m/^e(.*)$/) {
> push(@algo, "ecp$1");
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519
2025-05-15 8:16 ` [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Adolf Belka
@ 2025-05-15 12:07 ` Adam Gibbons
0 siblings, 0 replies; 4+ messages in thread
From: Adam Gibbons @ 2025-05-15 12:07 UTC (permalink / raw)
To: development, Adolf Belka, Peter Müller; +Cc: IPFire: Development-List
[-- Attachment #1: Type: text/plain, Size: 9284 bytes --]
Hi Peter and Adolf.
I agree, it's very good to see Peter on the list again :)
Adam.
On 15 May 2025 09:16:25 BST, Adolf Belka <adolf.belka@ipfire.org> wrote:
>Hallo Peter,
>
>Good to see you on the list again :+1:
>
>This patch sounds a good approach to take.
>
>Adolf.
>
>On 15/05/2025 10:06, Peter Müller wrote:
>> In commit 887778e0888d51eb9942ae310a43f6d2813efad3, the post-quantum
>> key exchange algorithm ML-KEM was introduced, due to its support being
>> added in strongSwan 6.0. However, using PQC key exchanges is commonly
>> recommended only in conjunction with a traditional one, to avoid
>> encrypted traffic becoming subject to trivial decryption in case a PQC
>> algorithm proves weak, broken, or backdoored. OpenSSH, for instance,
>> combines ML-KEM 768 with Curve 25519 (mlkem768x25519-sha256), rather
>> than using ML-KEM alone.
>>
>> This patch changes the chipher suites offered for IPsec connections to
>> always use ML-KEM as a hybrid with Curve 25519. This is possible due to
>> strongSwan 6.0 having added support for IKE intermediary key exchanges
>> (RFC 9370); see https://docs.strongswan.org/docs/latest/config/proposals.html#_key_exchange_methods
>> for additional information.
>>
>> We can reasonably assume an IPsec peer supporting ML-KEM will also
>> support Curve 25519, as this has been around for much longer, and is
>> used quite commonly. Even if this is not the case, or if the IPsec peer
>> does not implement RFC 9370, any IPsec connection using our default
>> cipher selection will fall back to Curve 448, Curve 25519, or other,
>> hence continue working.
>>
>> IPsec connections already created will need their ciphers to be changed
>> once during the Core Update routine where this patch will be
>> incorporated.
>>
>> Tested-by: Peter Müller <peter.mueller@ipfire.org>
>> Signed-off-by: Peter Müller <peter.mueller@ipfire.org>
>> ---
>> html/cgi-bin/vpnmain.cgi | 36 ++++++++++++++++++------------------
>> 1 file changed, 18 insertions(+), 18 deletions(-)
>>
>> diff --git a/html/cgi-bin/vpnmain.cgi b/html/cgi-bin/vpnmain.cgi
>> index 4f81fecdf..154b94033 100644
>> --- a/html/cgi-bin/vpnmain.cgi
>> +++ b/html/cgi-bin/vpnmain.cgi
>> @@ -2374,11 +2374,11 @@ END
>> #use default advanced value
>> $cgiparams{'IKE_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[18];
>> $cgiparams{'IKE_INTEGRITY'} = 'sha2_512|sha2_256'; #[19];
>> - $cgiparams{'IKE_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
>> + $cgiparams{'IKE_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[20];
>> $cgiparams{'IKE_LIFETIME'} = '3'; #[16];
>> $cgiparams{'ESP_ENCRYPTION'} = 'chacha20poly1305|aes256gcm128|aes256'; #[21];
>> $cgiparams{'ESP_INTEGRITY'} = 'sha2_512|sha2_256'; #[22];
>> - $cgiparams{'ESP_GROUPTYPE'} = 'mlkem1024|mlkem768|mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
>> + $cgiparams{'ESP_GROUPTYPE'} = 'x25519-ke1_mlkem1024|x25519-ke1_mlkem768|x25519-ke1_mlkem512|curve448|curve25519|e521|e384|4096|3072'; #[23];
>> $cgiparams{'ESP_KEYLIFE'} = '1'; #[17];
>> $cgiparams{'COMPRESSION'} = 'off'; #[13];
>> $cgiparams{'ONLY_PROPOSED'} = 'on'; #[24];
>> @@ -2759,7 +2759,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> goto ADVANCED_ERROR;
>> }
>> foreach my $val (@temp) {
>> - if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
>> + if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192)$/) {
>> $errormessage = $Lang::tr{'invalid input'};
>> goto ADVANCED_ERROR;
>> }
>> @@ -2800,7 +2800,7 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> goto ADVANCED_ERROR;
>> }
>> foreach my $val (@temp) {
>> - if ($val !~ /^(mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
>> + if ($val !~ /^(x25519-ke1_mlkem(1024|768|512)|curve448|curve25519|e521|e384|e256|e224|e192|e512bp|e384bp|e256bp|e224bp|768|1024|1536|2048|3072|4096|6144|8192|none)$/) {
>> $errormessage = $Lang::tr{'invalid input'};
>> goto ADVANCED_ERROR;
>> }
>> @@ -2940,9 +2940,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> $checked{'IKE_INTEGRITY'}{'aesxcbc'} = '';
>> @temp = split('\|', $cgiparams{'IKE_INTEGRITY'});
>> foreach my $key (@temp) {$checked{'IKE_INTEGRITY'}{$key} = "selected='selected'"; }
>> - $checked{'IKE_GROUPTYPE'}{'mlkem1024'} = '';
>> - $checked{'IKE_GROUPTYPE'}{'mlkem768'} = '';
>> - $checked{'IKE_GROUPTYPE'}{'mlkem512'} = '';
>> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
>> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
>> + $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
>> $checked{'IKE_GROUPTYPE'}{'curve448'} = '';
>> $checked{'IKE_GROUPTYPE'}{'curve25519'} = '';
>> $checked{'IKE_GROUPTYPE'}{'768'} = '';
>> @@ -2983,9 +2983,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> $checked{'ESP_INTEGRITY'}{'aesxcbc'} = '';
>> @temp = split('\|', $cgiparams{'ESP_INTEGRITY'});
>> foreach my $key (@temp) {$checked{'ESP_INTEGRITY'}{$key} = "selected='selected'"; }
>> - $checked{'ESP_GROUPTYPE'}{'mlkem1024'} = '';
>> - $checked{'ESP_GROUPTYPE'}{'mlkem768'} = '';
>> - $checked{'ESP_GROUPTYPE'}{'mlkem512'} = '';
>> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'} = '';
>> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'} = '';
>> + $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'} = '';
>> $checked{'ESP_GROUPTYPE'}{'curve448'} = '';
>> $checked{'ESP_GROUPTYPE'}{'curve25519'} = '';
>> $checked{'ESP_GROUPTYPE'}{'768'} = '';
>> @@ -3151,9 +3151,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> <td class='boldbase' width="15%">$Lang::tr{'grouptype'}</td>
>> <td class='boldbase'>
>> <select name='IKE_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
>> - <option value='mlkem1024' $checked{'IKE_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
>> - <option value='mlkem768' $checked{'IKE_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
>> - <option value='mlkem512' $checked{'IKE_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
>> + <option value='x25519-ke1_mlkem1024' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
>> + <option value='x25519-ke1_mlkem768' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
>> + <option value='x25519-ke1_mlkem512' $checked{'IKE_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
>> <option value='curve448' $checked{'IKE_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
>> <option value='curve25519' $checked{'IKE_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
>> <option value='e521' $checked{'IKE_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
>> @@ -3177,9 +3177,9 @@ if(($cgiparams{'ACTION'} eq $Lang::tr{'advanced'}) ||
>> </td>
>> <td class='boldbase'>
>> <select name='ESP_GROUPTYPE' multiple='multiple' size='6' style='width: 100%'>
>> - <option value='mlkem1024' $checked{'ESP_GROUPTYPE'}{'mlkem1024'}>ML-KEM 1024 (256 bit)</option>
>> - <option value='mlkem768' $checked{'ESP_GROUPTYPE'}{'mlkem768'}>ML-KEM 768 (192 bit)</option>
>> - <option value='mlkem512' $checked{'ESP_GROUPTYPE'}{'mlkem512'}>ML-KEM 512 (128 bit)</option>
>> + <option value='x25519-ke1_mlkem1024' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem1024'}>Curve 25519 x ML-KEM 1024 (256 bit)</option>
>> + <option value='x25519-ke1_mlkem768' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem768'}>Curve 25519 x ML-KEM 768 (192 bit)</option>
>> + <option value='x25519-ke1_mlkem512' $checked{'ESP_GROUPTYPE'}{'x25519-ke1_mlkem512'}>Curve 25519 x ML-KEM 512 (128 bit)</option>
>> <option value='curve448' $checked{'ESP_GROUPTYPE'}{'curve448'}>Curve 448 (224 bit)</option>
>> <option value='curve25519' $checked{'ESP_GROUPTYPE'}{'curve25519'}>Curve 25519 (128 bit)</option>
>> <option value='e521' $checked{'ESP_GROUPTYPE'}{'e521'}>ECP-521 (NIST)</option>
>> @@ -3757,7 +3757,7 @@ sub make_algos($$$$$) {
>> if ($mode eq "ike") {
>> push(@algo, $int);
>> - if ($grp =~ m/^mlkem(\d+)$/) {
>> + if ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
>> push(@algo, "$grp");
>> } elsif ($grp =~ m/^e(.*)$/) {
>> push(@algo, "ecp$1");
>> @@ -3776,7 +3776,7 @@ sub make_algos($$$$$) {
>> if (!$pfs || $grp eq "none") {
>> # noop
>> - } elsif ($grp =~ m/^mlkem(\d+)$/) {
>> + } elsif ($grp =~ m/^x25519-ke1_mlkem(\d+)$/) {
>> push(@algo, "$grp");
>> } elsif ($grp =~ m/^e(.*)$/) {
>> push(@algo, "ecp$1");
>
>
[-- Attachment #2: Type: text/html, Size: 10017 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-05-15 12:07 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-05-15 8:06 [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Peter Müller
2025-05-15 8:09 ` [PATCH 2/2] Core Update 196: Adjust existing IPsec connections using ML-KEM Peter Müller
2025-05-15 8:16 ` [PATCH 1/2] vpnmain.cgi: Use ML-KEM only as a hybrid with Curve 25519 Adolf Belka
2025-05-15 12:07 ` Adam Gibbons
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox