From 19206d485a7d2ea425f5f60b82be996f6d22912b Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sat, 29 Aug 2026 01:36:24 +0200 Subject: [PATCH] Fix IPsec host key generation with modern Libreswan https://github.com/webmin/webmin/issues/2132 --- CHANGELOG.md | 1 + ipsec/ipsec-lib.pl | 39 ++++++++++++++++++++++++++++++--------- ipsec/newkey.cgi | 10 +++++++++- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baa7b8fc3..2c8380d2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Add DNF 4 and 5 package hold management to the Software Package Updates module * Fix DNF update confirmations by previewing packages and dependencies that will be installed or updated * Fix PostgreSQL initialization on EL systems to use SCRAM-SHA-256 authentication by default +* Fix IPsec host key generation with modern Libreswan [#2132](https://github.com/webmin/webmin/issues/2132) #### 2.660 (August 20, 2026) * Add support for creating `vfsv1` Linux quota files for limits above 4 TiB, while preserving existing quota file formats diff --git a/ipsec/ipsec-lib.pl b/ipsec/ipsec-lib.pl index dd1fc79c6..4c01ff315 100755 --- a/ipsec/ipsec-lib.pl +++ b/ipsec/ipsec-lib.pl @@ -139,13 +139,33 @@ return $? || $out =~ /not running/i ? 0 : 1; # Returns this system's public key sub get_public_key { -local $out = `$config{'ipsec'} showhostkey --file '$config{'secrets'}' --left 2>&1`; +local $ckaid = &get_libreswan_key_id(); +local $out; +if ($ckaid) { + # Modern Libreswan reads the selected host key from NSS + $out = `$config{'ipsec'} showhostkey --left --ckaid '$ckaid' 2>&1`; + } +else { + # Legacy implementations read the host key from ipsec.secrets + $out = `$config{'ipsec'} showhostkey --file '$config{'secrets'}' --left 2>&1`; + } if ($out =~ /leftrsasigkey=(\S+)/) { return $1; } return undef; } +# get_libreswan_key_id() +# Returns the CKAID of the first Libreswan host key, or undef +sub get_libreswan_key_id +{ +local $out; +local ($version, $program) = &get_ipsec_version(\$out); +return undef if (!$program || lc($program) ne "libreswan"); +local $keys = `$config{'ipsec'} showhostkey --list 2>&1`; +return $keys =~ /\bckaid:\s*([a-f0-9]+)/i ? $1 : undef; +} + # get_public_key_dns() # Returns the flags, protocol, algorithm and key data for the public key, # suitable for creating a DNS KEY record @@ -292,16 +312,17 @@ return $out =~ /(FreeS\/WAN|Openswan|StrongSWAN|Libreswan)\s+([^ \n\(]+)/i ? ($2 sub got_secret { local $gotkey; -open(SEC, "<".$config{'secrets'}) || return 0; -while() { - s/\r|\n//g; - s/#.*$//; - if (/Modulus:\s*(\S+)/) { - $gotkey = 1; +if (open(SEC, "<".$config{'secrets'})) { + while() { + s/\r|\n//g; + s/#.*$//; + if (/Modulus:\s*(\S+)/) { + $gotkey = 1; + } } + close(SEC); } -close(SEC); -return $gotkey; +return ($gotkey || &get_libreswan_key_id()) ? 1 : 0; } # expand_conf(&config) diff --git a/ipsec/newkey.cgi b/ipsec/newkey.cgi index 9c64e1e0b..ad45b3e84 100755 --- a/ipsec/newkey.cgi +++ b/ipsec/newkey.cgi @@ -6,7 +6,15 @@ require './ipsec-lib.pl'; &ReadParse(); &error_setup($text{'newkey_err'}); $in{'host'} =~ /^[a-z0-9\.\-]+$/i || &error($text{'newkey_ehost'}); -$out = &backquote_logged("$config{'ipsec'} newhostkey --output '$config{'secrets'}' --hostname '$in{'host'}' 2>&1"); +($ipsec_version, $ipsec_program) = &get_ipsec_version(\$out); +if ($ipsec_program && lc($ipsec_program) eq "libreswan") { + # Modern Libreswan stores host keys in its NSS database + $out = &backquote_logged("$config{'ipsec'} newhostkey 2>&1"); + } +else { + # Legacy implementations write the key to ipsec.secrets + $out = &backquote_logged("$config{'ipsec'} newhostkey --output '$config{'secrets'}' --hostname '$in{'host'}' 2>&1"); + } $? && &error("
$out
"); &webmin_log("newkey"); &redirect("");