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_methodsfor 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");