==================================================================
CVE-2026-14957: FIPS mode assertion failure malicious CERT payload
==================================================================

This alert (and any updates) are available at the following URLs:
https://libreswan.org/security/CVE-2026-14957

The Libreswan Project used Claude to do a security audit of its codebase
which found one vulnerability where a badly formatted X.509 certificate
can cause an assertion failure that crashes the daemon process. Repeated
sending can cause a denial of service.

Severity: Medium
Vulnerable versions : 3.0 - 5.3.1
Not vulnerable      : 5.3.2 or later

Vulnerability details
=====================
In FIPS mode, libreswan adds an assertation check after calling
CERT_ExtractPublicKey() to ensure its output is not NULL, but the function
returns NULL whwn public key extraction fails, for example if the exponent
is set to 0. No RCE is possible.

This assertion check for NULL is only called when the OS and libreswan
are running in FIPS mode. To test if libreswan is running in FIPS mode
using the following command:

    sudo ipsec fipsstatus

If libreswan is only using PreSharedKey (PSK) authentication, and the
libreswan NSS database contains no CA certificates, then CERT payloads
are ignored and libreswan is not vulnerable. To test whether libreswan
currently has ant loaded CA certificates, issue the command:

    sudo ipsec listcacerts


Exploitation
============
Exploitation is only possible when the OS and libreswan are running
in FIPS mode and at least one CA certificate is loaded. Sending of
a corrupt CERT payload can be done before a peer is authenticated.
Both IKEv1 and IKEv2 are vulnerable.


Workaround
==========
No workaround is available, unless one would be willing to disable FIPS mode.

History
=======
* 17-06-2026 Guillaume Winter shared a Claude audit review
* 09-07-2026 Advanced notice given to supported customers and distributions.
* 15-07-2026 Public announcement and release of libreswan 5.3.2.

Credits
=======
This vulnerability was found by Claude and reported by Guillaume Winter.

Upgrading
=========
To address this vulnerability, please upgrade to libreswan 5.3.2 or later.

Patches
=======
For those who cannot upgrade, patches for libreswan 4.15 and 5.3 are
available at: https://libreswan.org/security/CVE-2026-21413/

About libreswan (https://libreswan.org/)
========================================
Libreswan is a free implementation of the Internet Key Exchange (IKE)
protocols IKEv1 and IKEv2. It is a descendant (continuation fork) of
openswan 2.6.38. IKE is used to establish IPsec VPN connections.

IPsec uses strong cryptography to provide both authentication and
encryption services. These services allow you to build secure tunnels
through untrusted networks. Everything passing through the untrusted
network is encrypted by the IPsec gateway machine, and decrypted by
the gateway at the other end of the tunnel. The resulting tunnel is a
virtual private network (VPN).


Patch for 5.x
=========================================

diff --git a/programs/pluto/nss_cert_verify.c b/programs/pluto/nss_cert_verify.c
index 32cd1b01ac..51998cab9c 100644
--- a/programs/pluto/nss_cert_verify.c
+++ b/programs/pluto/nss_cert_verify.c
@@ -405,16 +405,23 @@ static void add_decoded_cert(CERTCertDBHandle *handle,
 	 */
 	if (is_fips_mode()) {
 		SECKEYPublicKey *pk = CERT_ExtractPublicKey(cert);
-		passert(pk != NULL);
-		unsigned key_bit_size = pk->u.rsa.modulus.len * BITS_IN_BYTE;
-		if (pk->keyType == rsaKey && key_bit_size < FIPS_MIN_RSA_KEY_SIZE) {
-			llog(RC_LOG, logger,
-			     "FIPS: rejecting peer cert with key size %u under %u: %s",
-			     key_bit_size, FIPS_MIN_RSA_KEY_SIZE,
-			     cert->subjectName);
-			SECKEY_DestroyPublicKey(pk);
-			CERT_DestroyCertificate(cert);
-			return;
+		if (pk == NULL) {
+			llog_nss_error(RC_LOG, logger,
+				       "extracting certificate public key using CERT_ExtractPublicKey() failed");
+ 			return;
+ 		}
+
+		if (pk->keyType == rsaKey) {
+			unsigned key_bit_size = pk->u.rsa.modulus.len * BITS_IN_BYTE;
+			if (key_bit_size < FIPS_MIN_RSA_KEY_SIZE) {
+				llog(RC_LOG, logger,
+				     "FIPS: rejecting peer cert with key size %u under %u: %s",
+				     key_bit_size, FIPS_MIN_RSA_KEY_SIZE,
+				     cert->subjectName);
+				SECKEY_DestroyPublicKey(pk);
+				CERT_DestroyCertificate(cert);
+				return;
+			}
 		}
 		SECKEY_DestroyPublicKey(pk);
 	}
