Hello, I've prepared strongswan 5.9.8-5+deb12u6 for bookworm-security, and it's ready for review.
DSA-6487-1 already shipped these fixes in strongswan 6.0.1-6+deb13u7 in Trixie. CVE-2026-78133 is on that list too, but the code it fixes arrived in 6.0.0, so strongswan 5.9.8 in Bookworm doesn't have it. The debdiff against 5.9.8-5+deb12u5 is attached. - CVE-2026-78123: Checking a PKCS#7 signature could read past the end of a buffer when the signer was identified by a subject key instead of an issuer and serial. This build makes sure that structure is actually there. - CVE-2026-78124: Enumerating certificates out of a PKCS#7 container leaked them, and IKEv1 can trigger that. This build frees them. - CVE-2026-78126: EAP-AKA crashed if the client sent a synchronization failure before the server had issued a challenge. This build ignores that message unless a challenge is in progress. - CVE-2026-78127: Logging an IKE message leaked a small amount of memory when the debug string didn't fit in the buffer. This build frees that enumerator. - CVE-2026-78129: A PKCS#5 blob with a huge iteration count, key length, or salt could stall a thread. strongswan 6.0.1-6+deb13u7 in Trixie already rejects iteration counts above 1000000, keys above 64 bytes, and salts above 128 bytes, and this build does the same. - CVE-2026-78130: An attribute certificate with no issuer name and no authority key identifier crashed while it was being checked. This build treats that certificate as untrusted. - CVE-2026-78131: Parsing an attribute certificate with a lot of names or key identifiers leaked. This build frees those. - CVE-2026-78132: A crafted attribute certificate could make the parser loop forever. This build rejects it. - CVE-2026-78134: EAP-TTLS and EAP-PEAP could leave the IKE SA bound to the identity the peer claimed, instead of the one the inner method authenticated. This build returns that inner identity. get_auth was already on the EAP method struct, and the extra pointer sits at the end of the plugin's private struct, so there are no new exported symbols. - CVE-2026-78135: The old CREATE_CHILD_SA check only ran when no tasks were queued, so during EAP it never fired and a Child SA could be installed on an IKE SA that wasn't up yet. This build rejects that request while the IKE SA is still coming up. I built this in a Bookworm schroot. Against strongswan 5.9.8-5+deb12u5 from the archive, the PKCS#7 and attribute-certificate bugs still fire, EAP-AKA still crashes, a huge PKCS#5 iteration count still stalls, the IKE log still leaks, EAP-TTLS still keeps the outer identity, and a CREATE_CHILD_SA during EAP still installs a Child SA. None of that happens with 5.9.8-5+deb12u6. The package test suite is clean on both versions, and a normal connection still comes up. Here is my Salsa fork: https://salsa.debian.org/tsimonq2/strongswan/-/tree/debian/bookworm Here is the Debusine work request: https://debusine.debian.net/debian/developers/work-request/1558827/ Feedback is welcome. If nothing showstopping comes up, I'll upload this and issue the DLA on Monday morning (November 2nd, 2026). Best regards, Simon Quigley [email protected]
diff -Nru strongswan-5.9.8/debian/changelog strongswan-5.9.8/debian/changelog --- strongswan-5.9.8/debian/changelog 2026-05-27 01:58:30.000000000 -0500 +++ strongswan-5.9.8/debian/changelog 2026-10-29 11:10:51.000000000 -0500 @@ -1,3 +1,25 @@ +strongswan (5.9.8-5+deb12u6) bookworm-security; urgency=high + + * Non-maintainer upload by the LTS Team. + * CVE-2026-78123: Fix undefined memory access when verifying PKCS#7 + containers. + * CVE-2026-78124: Fix memory leaks after enumerating certificates in + PKCS#7 containers. + * CVE-2026-78126: Fix a NULL-pointer dereference in EAP-AKA. + * CVE-2026-78127: Fix a memory leak in IKE message logging. + * CVE-2026-78129: Reject oversized PKCS#5 parameters that can stall + a thread. + * CVE-2026-78130: Fix a NULL-pointer dereference when an attribute + certificate has no issuer. + * CVE-2026-78131: Fix memory leaks when parsing x509 attribute + certificates. + * CVE-2026-78132: Fix an infinite loop when parsing x509 attribute + certificates. + * CVE-2026-78134: Bind the inner EAP identity to the IKE SA. + * CVE-2026-78135: Reject CREATE_CHILD_SA on an unestablished IKE SA. + + -- Simon Quigley <[email protected]> Thu, 29 Oct 2026 11:10:51 -0500 + strongswan (5.9.8-5+deb12u5) bookworm-security; urgency=medium * d/patches: add fix for double-free when cloning empty IDs (CVE-2026-47895) diff -Nru strongswan-5.9.8/debian/patches/0017-openssl-Fix-undefined-memory-access-when-verifying-P.patch strongswan-5.9.8/debian/patches/0017-openssl-Fix-undefined-memory-access-when-verifying-P.patch --- strongswan-5.9.8/debian/patches/0017-openssl-Fix-undefined-memory-access-when-verifying-P.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0017-openssl-Fix-undefined-memory-access-when-verifying-P.patch 2026-10-27 11:22:33.000000000 -0500 @@ -0,0 +1,48 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78123/strongswan-5.0.2-6.0.7_openssl_pkcs7_info_init.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 2918eb8a6d4b3167f26ac011e87c3a7ecc7dbe56 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Mon, 1 Jun 2026 17:51:35 +0200 +Subject: [PATCH] openssl: Fix undefined memory access when verifying PKCS#7 + containers + +If the signerInfo or recipientInfo structure doesn't contain +issuerAndSerialNumber but instead a subjectKeyIdentifier, then the called +functions will leave the passed name and serial numbers unchanged. While +openssl_x509_name2id() prevents a NULL-pointer dereference, it tries to +DER-encode the object at the passed pointer via i2d_X509_NAME(). +Depending on the stack contents, this likely causes a segmentation fault. + +Fixes: 3c820cdc232a ("Implement PKCS#7 decryption using openssl") +Fixes: c61723c69fb5 ("Implement OpenSSL PKCS#7 signed-data parsing and verification") +Fixes: CVE-2026-78123 +--- + src/libstrongswan/plugins/openssl/openssl_pkcs7.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c ++++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c +@@ -221,8 +221,8 @@ static auth_cfg_t *verify_signature(CMS_ + auth_cfg_t *auth, *found = NULL; + identification_t *issuer, *serial; + chunk_t attrs = chunk_empty, sig, attr; +- X509_NAME *name; +- ASN1_INTEGER *snr; ++ X509_NAME *name = NULL; ++ ASN1_INTEGER *snr = NULL; + int i; + + if (CMS_SignerInfo_get0_signer_id(si, NULL, &name, &snr) != 1) +@@ -612,8 +612,8 @@ static bool decrypt(private_openssl_pkcs + identification_t *serial, *issuer; + private_key_t *private; + X509_ALGOR *alg; +- X509_NAME *name; +- ASN1_INTEGER *sn; ++ X509_NAME *name = NULL; ++ ASN1_INTEGER *sn = NULL; + u_char zero = 0; + int oid; + diff -Nru strongswan-5.9.8/debian/patches/0018-openssl-Fix-memory-leaks-after-enumerating-certifica.patch strongswan-5.9.8/debian/patches/0018-openssl-Fix-memory-leaks-after-enumerating-certifica.patch --- strongswan-5.9.8/debian/patches/0018-openssl-Fix-memory-leaks-after-enumerating-certifica.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0018-openssl-Fix-memory-leaks-after-enumerating-certifica.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,31 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78124/strongswan-5.0.2-6.0.7_openssl_pkcs7_certs_leak.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 2a3a678be189e51465d17c611982a9e5f379b016 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Mon, 15 Jun 2026 16:02:01 +0200 +Subject: [PATCH] openssl: Fix memory leaks after enumerating certificates in + PKCS#7 container + +This can be triggered via IKEv1. + +Fixes: 04884be3b5f7 ("Implement openssl PKCS#7 certficiate enumeration") +Fixes: CVE-2026-78124 +--- + src/libstrongswan/plugins/openssl/openssl_pkcs7.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c ++++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c +@@ -132,6 +132,10 @@ typedef struct { + METHOD(enumerator_t, cert_destroy, void, + cert_enumerator_t *this) + { ++ if (this->certs) ++ { ++ sk_X509_pop_free(this->certs, X509_free); ++ } + DESTROY_IF(this->cert); + free(this); + } diff -Nru strongswan-5.9.8/debian/patches/0019-eap-aka-Only-accept-AKA-Synchronization-Failure-if-e.patch strongswan-5.9.8/debian/patches/0019-eap-aka-Only-accept-AKA-Synchronization-Failure-if-e.patch --- strongswan-5.9.8/debian/patches/0019-eap-aka-Only-accept-AKA-Synchronization-Failure-if-e.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0019-eap-aka-Only-accept-AKA-Synchronization-Failure-if-e.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,34 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78126/strongswan-4.4.0-6.0.7_eap_aka_sync_fail.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 632a7498f834ff07ecf7a3dd604c06f6b89dd768 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Thu, 4 Jun 2026 10:00:02 +0200 +Subject: [PATCH] eap-aka: Only accept AKA-Synchronization-Failure if expected + +This fixes a NULL-pointer dereference if the client sends such an error +before the server issued a challenge and allocated this->rand. + +Fixes: 26e246769224 ("ported EAP-AKA branch into trunk") +Fixes: 4735965fc048 ("EAP servers check if the received EAP message was expected") +Fixes: CVE-2026-78126 +--- + src/libcharon/plugins/eap_aka/eap_aka_server.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/src/libcharon/plugins/eap_aka/eap_aka_server.c ++++ b/src/libcharon/plugins/eap_aka/eap_aka_server.c +@@ -505,6 +505,12 @@ static status_t process_synchronize(priv + simaka_attribute_t type; + chunk_t data, auts = chunk_empty; + ++ if (this->pending != AKA_CHALLENGE) ++ { ++ DBG1(DBG_IKE, "received %N, but not expected", ++ simaka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); ++ return FAILED; ++ } + if (this->synchronized) + { + DBG1(DBG_IKE, "received %N, but peer did already resynchronize", diff -Nru strongswan-5.9.8/debian/patches/0020-message-Avoid-memory-leak-if-string-buffer-for-messa.patch strongswan-5.9.8/debian/patches/0020-message-Avoid-memory-leak-if-string-buffer-for-messa.patch --- strongswan-5.9.8/debian/patches/0020-message-Avoid-memory-leak-if-string-buffer-for-messa.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0020-message-Avoid-memory-leak-if-string-buffer-for-messa.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,112 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78127/strongswan-5.3.1-6.0.7_message_log_leak.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 1d758b2cd2f13af02319274c4e48cd7a2dc62e42 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Mon, 8 Jun 2026 09:19:42 +0200 +Subject: [PATCH] message: Avoid memory leak if string buffer for message is + too small + +This leaked 40 or 80 bytes per parsed message for the enumerators that +were not destroyed. While triggering an OOM condition will require quite +a lot of messages and the DoS protection also helps avoiding that this +is triggered quickly, it all depends on the memory constraints of the +system and the time available to the attacker. Also, if IKEv1 is allowed, +it could get quicker as the lack of message IDs doesn't allow dismissing +unexpected messages before parsing them. + +Fixes: 092958c89d52 ("fixed payload debug message") +Fixes: 6a4a47511f75 ("Show contents of the CP payload in message_t stringification") +Fixes: CVE-2026-78127 +--- + src/libcharon/encoding/message.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +--- a/src/libcharon/encoding/message.c ++++ b/src/libcharon/encoding/message.c +@@ -1301,7 +1301,7 @@ static char* get_string(private_message_ + payload->get_type(payload)); + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1327,7 +1327,7 @@ static char* get_string(private_message_ + } + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1357,7 +1357,7 @@ static char* get_string(private_message_ + eap->get_code(eap), method); + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1398,7 +1398,8 @@ static char* get_string(private_message_ + attribute->get_type(attribute)); + if (written >= len || written < 0) + { +- return buf; ++ attributes->destroy(attributes); ++ goto err; + } + pos += written; + len -= written; +@@ -1410,7 +1411,7 @@ static char* get_string(private_message_ + written = snprintf(pos, len, ")"); + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1432,7 +1433,7 @@ static char* get_string(private_message_ + } + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1447,7 +1448,7 @@ static char* get_string(private_message_ + frag->get_total_fragments(frag)); + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; +@@ -1460,16 +1461,16 @@ static char* get_string(private_message_ + written = snprintf(pos, len, "(%d)", unknown->get_type(unknown)); + if (written >= len || written < 0) + { +- return buf; ++ goto err; + } + pos += written; + len -= written; + } + } +- enumerator->destroy(enumerator); +- +- /* remove last space */ + snprintf(pos, len, " ]"); ++ ++err: ++ enumerator->destroy(enumerator); + return buf; + } + diff -Nru strongswan-5.9.8/debian/patches/0021-pkcs5-Validate-parsed-parameters-to-avoid-DoS-attack.patch strongswan-5.9.8/debian/patches/0021-pkcs5-Validate-parsed-parameters-to-avoid-DoS-attack.patch --- strongswan-5.9.8/debian/patches/0021-pkcs5-Validate-parsed-parameters-to-avoid-DoS-attack.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0021-pkcs5-Validate-parsed-parameters-to-avoid-DoS-attack.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,152 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78129/strongswan-5.6.3-6.0.7_pkcs5_params_dos.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From e7a3a51459e795136c249bfe83978b41d7d5ecdd Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Tue, 23 Jun 2026 11:55:31 +0200 +Subject: [PATCH] pkcs5: Validate parsed parameters to avoid DoS attacks + +With the unbounded iterations, an attacker can craft a PKCS#7 file and +send it during IKEv1 to block the processing thread practically for an +unlimited amount of time. + +As the key length is used for an allocation on the stack, not limiting +it could cause a crash. We validate it after parsing the params, but +since `encryption_algorithm_from_oid()` only returns trusted key lengths +that are lower than the limit, that's fine. + +The unlimited salt length had no direct impact (the maximum is bound by +the accepted message size), but we now limit it as well before cloning. + +Fixes: 4076e3ee9121 ("Extract PKCS#5 handling from pkcs8 plugin to separate helper class") +Fixes: fd1ff46f6143 ("Added support for PKCS#5 v2 schemes when decrypting PKCS#8 files.") +Fixes: cab127cba66c ("Added support for encrypted PKCS#8 files (for some PKCS#5 v1.5 schemes).") +Fixes: CVE-2026-78129 +--- + src/libstrongswan/crypto/pkcs5.c | 65 +++++++++++++++++++++++++++++++- + 1 file changed, 64 insertions(+), 1 deletion(-) + +--- a/src/libstrongswan/crypto/pkcs5.c ++++ b/src/libstrongswan/crypto/pkcs5.c +@@ -14,6 +14,8 @@ + * for more details. + */ + ++#include <inttypes.h> ++ + #include "pkcs5.h" + + #include <utils/debug.h> +@@ -22,6 +24,15 @@ + #include <asn1/asn1_parser.h> + #include <credentials/containers/pkcs12.h> + ++/** maximum accepted length for salts in parsed parameters */ ++#define PKCS5_SALT_LEN_MAX 128 ++ ++/** maximum accepted iteration count in parsed parameters */ ++#define PKCS5_ITERATIONS_MAX 1000000 ++ ++/** maximum key length accepted in parsed parameters */ ++#define PKCS5_KEY_LEN_MAX 64 ++ + typedef struct private_pkcs5_t private_pkcs5_t; + + /** +@@ -380,6 +391,41 @@ METHOD(pkcs5_t, decrypt, bool, + } + + /** ++ * Make sure the salt has an appropriate length ++ */ ++static bool validate_salt_length(chunk_t salt) ++{ ++ if (salt.len > PKCS5_SALT_LEN_MAX) ++ { ++ DBG1(DBG_ASN, " salt length %zu exceeds maximum of %zu bytes", ++ salt.len, (size_t)PKCS5_SALT_LEN_MAX); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/** ++ * Validate that parsed parameters are in an allowed range ++ */ ++static bool validate_params(private_pkcs5_t *this) ++{ ++ if (!this->iterations || this->iterations > PKCS5_ITERATIONS_MAX) ++ { ++ DBG1(DBG_ASN, " iteration count %" PRIu64 " is out of range " ++ "(1-%" PRIu64 ")", this->iterations, ++ (uint64_t)PKCS5_ITERATIONS_MAX); ++ return FALSE; ++ } ++ if (this->keylen > PKCS5_KEY_LEN_MAX) ++ { ++ DBG1(DBG_ASN, " key length %zu exceeds maximum of %zu bytes", ++ this->keylen, (size_t)PKCS5_KEY_LEN_MAX); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++/** + * ASN.1 definition of a PBEParameter structure + */ + static const asn1Object_t pbeParameterObjects[] = { +@@ -399,7 +445,7 @@ static bool parse_pbes1_params(private_p + asn1_parser_t *parser; + chunk_t object; + int objectID; +- bool success; ++ bool success = FALSE; + + parser = asn1_parser_create(pbeParameterObjects, blob); + parser->set_top_level(parser, level0); +@@ -410,6 +456,10 @@ static bool parse_pbes1_params(private_p + { + case PBEPARAM_SALT: + { ++ if (!validate_salt_length(object)) ++ { ++ goto end; ++ } + this->salt = chunk_clone(object); + break; + } +@@ -421,6 +471,11 @@ static bool parse_pbes1_params(private_p + } + } + success = parser->success(parser); ++ if (success) ++ { ++ success = validate_params(this); ++ } ++end: + parser->destroy(parser); + return success; + } +@@ -471,6 +526,10 @@ static bool parse_pbkdf2_params(private_ + { + case PBKDF2_SALT: + { ++ if (!validate_salt_length(object)) ++ { ++ goto end; ++ } + this->salt = chunk_clone(object); + break; + } +@@ -500,6 +559,10 @@ static bool parse_pbkdf2_params(private_ + } + } + success = parser->success(parser); ++ if (success) ++ { ++ success = validate_params(this); ++ } + end: + parser->destroy(parser); + return success; diff -Nru strongswan-5.9.8/debian/patches/0022-x509-Avoid-NULL-pointer-dereference-if-issuerName-is.patch strongswan-5.9.8/debian/patches/0022-x509-Avoid-NULL-pointer-dereference-if-issuerName-is.patch --- strongswan-5.9.8/debian/patches/0022-x509-Avoid-NULL-pointer-dereference-if-issuerName-is.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0022-x509-Avoid-NULL-pointer-dereference-if-issuerName-is.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,46 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78130/strongswan-5.1.3-6.0.7_x509_ac_issuer_null.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 4dae392b32a2c56441fd7ca50ad32a0874455995 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Fri, 19 Jun 2026 11:57:48 +0200 +Subject: [PATCH] x509: Avoid NULL-pointer dereference if issuerName is missing + in attribute certificate + +If neither authoritiyKeyIdentifier nor issuerName are encoded in an +attribute certificate, the validation in `acert_validator.c:verify()` +will cause a NULL-pointer dereference via `issued_by()` (the lookup +with NULL identity will enumerate all trusted certificates). + +Fixes: 26930a8c3e42 ("certificate factory can load certs from file") +Fixes: CVE-2026-78130 +--- + src/libstrongswan/plugins/x509/x509_ac.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/src/libstrongswan/plugins/x509/x509_ac.c ++++ b/src/libstrongswan/plugins/x509/x509_ac.c +@@ -911,7 +911,11 @@ METHOD(certificate_t, has_issuer, id_mat + { + return ID_MATCH_PERFECT; + } +- return this->issuerName->matches(this->issuerName, issuer); ++ if (this->issuerName) ++ { ++ return this->issuerName->matches(this->issuerName, issuer); ++ } ++ return ID_MATCH_NONE; + } + + METHOD(certificate_t, issued_by, bool, +@@ -948,7 +952,8 @@ METHOD(certificate_t, issued_by, bool, + } + else + { +- if (!this->issuerName->equals(this->issuerName, ++ if (!this->issuerName || ++ !this->issuerName->equals(this->issuerName, + issuer->get_subject(issuer))) + { + return FALSE; diff -Nru strongswan-5.9.8/debian/patches/0023-x509-Fix-memory-leaks-when-parsing-attribute-certifi.patch strongswan-5.9.8/debian/patches/0023-x509-Fix-memory-leaks-when-parsing-attribute-certifi.patch --- strongswan-5.9.8/debian/patches/0023-x509-Fix-memory-leaks-when-parsing-attribute-certifi.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0023-x509-Fix-memory-leaks-when-parsing-attribute-certifi.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,80 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78131/strongswan-5.5.3-6.0.7_x509_ac_leaks.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 7012f6263df493b62268954675b0311248780309 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Fri, 12 Jun 2026 15:55:43 +0200 +Subject: [PATCH] x509: Fix memory leaks when parsing attribute certificates + +This can be triggered by an attribute certificate with lots of GeneralName +entries or AuthorityKeyIdentifier extensions. There is no verification +before the certificate is parsed. + +Fixes: 3134379ac7f1 ("x509: Fix some whitespaces and do some minor style cleanups in acert") +Fixes: 26930a8c3e42 ("certificate factory can load certs from file") +Fixes: CVE-2026-78131 +--- + src/libstrongswan/plugins/x509/x509_ac.c | 33 +++++++----------------- + 1 file changed, 9 insertions(+), 24 deletions(-) + +--- a/src/libstrongswan/plugins/x509/x509_ac.c ++++ b/src/libstrongswan/plugins/x509/x509_ac.c +@@ -186,41 +186,25 @@ extern bool x509_parse_generalNames(chun + static bool parse_directoryName(chunk_t blob, int level, bool implicit, + identification_t **name) + { +- identification_t *directoryName; +- enumerator_t *enumerator; +- bool first = TRUE; + linked_list_t *list; + + list = linked_list_create(); + if (!x509_parse_generalNames(blob, level, implicit, list)) + { +- list->destroy(list); ++ list->destroy_offset(list, offsetof(identification_t, destroy)); + return FALSE; + } +- +- enumerator = list->create_enumerator(list); +- while (enumerator->enumerate(enumerator, &directoryName)) +- { +- if (first) +- { +- *name = directoryName; +- first = FALSE; +- } +- else +- { +- DBG1(DBG_ASN, "more than one directory name - first selected"); +- directoryName->destroy(directoryName); +- break; +- } +- } +- enumerator->destroy(enumerator); +- list->destroy(list); +- +- if (first) ++ if (list->remove_first(list, (void**)name) != SUCCESS) + { + DBG1(DBG_ASN, "no directoryName found"); ++ list->destroy(list); + return FALSE; + } ++ if (list->get_count(list)) ++ { ++ DBG1(DBG_ASN, "more than one directory name - first selected"); ++ } ++ list->destroy_offset(list, offsetof(identification_t, destroy)); + return TRUE; + } + +@@ -540,6 +524,7 @@ static bool parse_certificate(private_x5 + DBG2(DBG_ASN, " need to parse crlDistributionPoints"); + break; + case OID_AUTHORITY_KEY_ID: ++ chunk_free(&this->authKeyIdentifier); + this->authKeyIdentifier = + x509_parse_authorityKeyIdentifier(object, + level, &this->authKeySerialNumber); diff -Nru strongswan-5.9.8/debian/patches/0024-x509-Prevent-infinite-loop-when-parsing-ietfAttrSynt.patch strongswan-5.9.8/debian/patches/0024-x509-Prevent-infinite-loop-when-parsing-ietfAttrSynt.patch --- strongswan-5.9.8/debian/patches/0024-x509-Prevent-infinite-loop-when-parsing-ietfAttrSynt.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0024-x509-Prevent-infinite-loop-when-parsing-ietfAttrSynt.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,72 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78132/strongswan-5.1.3-6.0.7_x509_ac_ietfattr_loop.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From d925e4625626a70611a979d4ab231c6e2d313e4a Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Wed, 1 Jul 2026 16:24:23 +0200 +Subject: [PATCH] x509: Prevent infinite loop when parsing ietfAttrSyntax in + attribute certificates + +This is the same issue that was fixed with 407fcca200fd ("asn1-parser: +Fix CHOICE parsing") for other CHOICE elements. This one was missed and +can be triggered pre-auth by sending an attribute certificate to a peer. +Since it's parsed before verifying it, the certificate doesn't have to +be valid. + +For versions older than 5.5.3, this patch requires prior application of +the fix for CVE-2017-9023, which introduced proper CHOICE handling in +the ASN.1 parser. + +Fixes: a17598bc6992 ("x509: Integrate IETF attribute handling, and obsolete ietf_attributes_t") +Fixes: CVE-2026-78132 +--- + src/libstrongswan/plugins/x509/x509_ac.c | 36 +++++++++++------------- + 1 file changed, 17 insertions(+), 19 deletions(-) + +--- a/src/libstrongswan/plugins/x509/x509_ac.c ++++ b/src/libstrongswan/plugins/x509/x509_ac.c +@@ -249,26 +249,24 @@ static void parse_roleSyntax(chunk_t blo + */ + static const asn1Object_t ietfAttrSyntaxObjects[] = + { +- { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ +- { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT | +- ASN1_BODY }, /* 1 */ +- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ +- { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ +- { 2, "octets", ASN1_OCTET_STRING, ASN1_OPT | +- ASN1_BODY }, /* 4 */ +- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ +- { 2, "oid", ASN1_OID, ASN1_OPT | +- ASN1_BODY }, /* 6 */ +- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ +- { 2, "string", ASN1_UTF8STRING, ASN1_OPT | +- ASN1_BODY }, /* 8 */ +- { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ +- { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ +- { 0, "exit", ASN1_EOC, ASN1_EXIT } ++ { 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ ++ { 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 1 */ ++ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ ++ { 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */ ++ { 2, "value choice", ASN1_EOC, ASN1_CHOICE }, /* 4 */ ++ { 3, "octets", ASN1_OCTET_STRING, ASN1_OPT|ASN1_BODY }, /* 5 */ ++ { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 6 */ ++ { 3, "oid", ASN1_OID, ASN1_OPT|ASN1_BODY }, /* 7 */ ++ { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 8 */ ++ { 3, "string", ASN1_UTF8STRING, ASN1_OPT|ASN1_BODY }, /* 9 */ ++ { 3, "end choice", ASN1_EOC, ASN1_END|ASN1_CH }, /* 10 */ ++ { 2, "end choices", ASN1_EOC, ASN1_END|ASN1_CHOICE }, /* 11 */ ++ { 1, "end loop", ASN1_EOC, ASN1_END }, /* 12 */ ++ { 0, "exit", ASN1_EOC, ASN1_EXIT } + }; +-#define IETF_ATTR_OCTETS 4 +-#define IETF_ATTR_OID 6 +-#define IETF_ATTR_STRING 8 ++#define IETF_ATTR_OCTETS 5 ++#define IETF_ATTR_OID 7 ++#define IETF_ATTR_STRING 9 + + /** + * Parse group memberships, IETF attributes diff -Nru strongswan-5.9.8/debian/patches/0025-eap-ttls-peap-Return-auth-cfg-with-details-on-TLS-an.patch strongswan-5.9.8/debian/patches/0025-eap-ttls-peap-Return-auth-cfg-with-details-on-TLS-an.patch --- strongswan-5.9.8/debian/patches/0025-eap-ttls-peap-Return-auth-cfg-with-details-on-TLS-an.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0025-eap-ttls-peap-Return-auth-cfg-with-details-on-TLS-an.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,688 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78134/strongswan-5.5.1-5.9.9_eap_inner_auth_cfg.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From 7926256cacd4526264107cc8198d16b452a28673 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Mon, 27 Jul 2026 15:05:45 +0200 +Subject: [PATCH] eap-ttls/peap: Return auth-cfg with details on TLS and inner + EAP method + +This fixes several issues with binding identities to the IKE SA. + +If the client is authenticated with a certificate, the previous code still +used the client's proclaimed inner EAP-Identity when starting the EAP-TNC +method. So that method would potentially operate on an unverified +identity. + +Second, if the inner EAP method overrides the client identity (the only +one is currently EAP-MSCHAPV2), the missing merge meant that the outer +IKE/EAP identity could potentially be unconfirmed. + +For inner methods that don't override the identity (e.g. EAP-MD5), not +propagating the inner EAP-Identity could potentially have the same +effect. + +While the EAP-TTLS implementation returned the auth-cfg of the TLS +exchange since the first referenced commit, this was mainly intended to +enforce public key constraints. So it didn't cover the phase 2 EAP +methods. For some reason EAP-PEAP did not get that method at all in that +changeset, so we'll add that now. + +Additionally, the EAP-PEAP implementation now forwards the phase 2 EAP +method type to EAP-TNC like the EAP-TTLS implementation already did, +which allows a more informed decision on the client's identity. + +Fixes: 0864a31d13ff ("eap-ttls: Support EAP auth information getter in EAP-TTLS") +Fixes: 79f2102cb442 ("implemented server side support for EAP-TTLS") +Fixes: 2a421163bf4f ("make TNC client authentication type available to IMVs") +Fixes: 1be296dfb2af ("implemented the PEAP tunneling protocol as an EAP plugin") +Fixes: CVE-2026-78134 +--- + src/libcharon/plugins/eap_peap/eap_peap.c | 49 ++++++++++- + .../plugins/eap_peap/eap_peap_peer.c | 20 +++++ + .../plugins/eap_peap/eap_peap_peer.h | 7 ++ + .../plugins/eap_peap/eap_peap_server.c | 81 ++++++++++++++++--- + .../plugins/eap_peap/eap_peap_server.h | 7 ++ + src/libcharon/plugins/eap_ttls/eap_ttls.c | 43 +++++++++- + .../plugins/eap_ttls/eap_ttls_peer.c | 19 +++++ + .../plugins/eap_ttls/eap_ttls_peer.h | 7 ++ + .../plugins/eap_ttls/eap_ttls_server.c | 56 +++++++++++-- + .../plugins/eap_ttls/eap_ttls_server.h | 7 ++ + 10 files changed, 278 insertions(+), 18 deletions(-) + +--- a/src/libcharon/plugins/eap_peap/eap_peap.c ++++ b/src/libcharon/plugins/eap_peap/eap_peap.c +@@ -40,6 +40,25 @@ struct private_eap_peap_t { + * TLS stack, wrapped by EAP helper + */ + tls_eap_t *tls_eap; ++ ++ /** ++ * Role ++ */ ++ bool is_server; ++ ++ /** ++ * Actual server/client implementation ++ */ ++ union { ++ tls_application_t *application; ++ eap_peap_server_t *server; ++ eap_peap_peer_t *client; ++ } impl; ++ ++ /** ++ * Cached auth data for TLS and inner EAP methods ++ */ ++ auth_cfg_t *auth; + }; + + /** Maximum number of EAP-PEAP messages/fragments allowed */ +@@ -113,10 +132,34 @@ METHOD(eap_method_t, is_mutual, bool, + return TRUE; + } + ++METHOD(eap_method_t, get_auth, auth_cfg_t*, ++ private_eap_peap_t *this) ++{ ++ if (!this->auth) ++ { ++ auth_cfg_t *inner; ++ ++ this->auth = auth_cfg_create(); ++ this->auth->merge(this->auth, ++ this->tls_eap->get_auth(this->tls_eap), FALSE); ++ if (this->is_server) ++ { ++ inner = this->impl.server->get_auth(this->impl.server); ++ } ++ else ++ { ++ inner = this->impl.client->get_auth(this->impl.client); ++ } ++ this->auth->merge(this->auth, inner, FALSE); ++ } ++ return this->auth; ++} ++ + METHOD(eap_method_t, destroy, void, + private_eap_peap_t *this) + { + this->tls_eap->destroy(this->tls_eap); ++ DESTROY_IF(this->auth); + free(this); + } + +@@ -135,6 +178,7 @@ static private_eap_peap_t *eap_peap_crea + .get_type = _get_type, + .is_mutual = _is_mutual, + .get_msk = _get_msk, ++ .get_auth = _get_auth, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, + .destroy = _destroy, +@@ -147,7 +191,7 @@ static private_eap_peap_t *eap_peap_crea + /** + * Generic private constructor + */ +-static eap_peap_t *eap_peap_create(private_eap_peap_t * this, ++static eap_peap_t *eap_peap_create(private_eap_peap_t *this, + identification_t *server, + identification_t *peer, bool is_server, + tls_application_t *application) +@@ -157,6 +201,9 @@ static eap_peap_t *eap_peap_create(priva + bool include_length; + tls_t *tls; + ++ this->is_server = is_server; ++ this->impl.application = application; ++ + if (is_server && !lib->settings->get_bool(lib->settings, + "%s.plugins.eap-peap.request_peer_auth", FALSE, + lib->ns)) +--- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c ++++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c +@@ -53,6 +53,11 @@ struct private_eap_peap_peer_t { + eap_method_t *ph2_method; + + /** ++ * Auth data for phase 2 methods ++ */ ++ auth_cfg_t *auth; ++ ++ /** + * Pending outbound EAP message + */ + eap_payload_t *out; +@@ -166,6 +171,12 @@ METHOD(tls_application_t, process, statu + switch (status) + { + case SUCCESS: ++ if (this->ph2_method->get_auth) ++ { ++ this->auth->merge(this->auth, ++ this->ph2_method->get_auth(this->ph2_method), ++ FALSE); ++ } + this->ph2_method->destroy(this->ph2_method); + this->ph2_method = NULL; + /* fall through to NEED_MORE */ +@@ -220,11 +231,18 @@ METHOD(tls_application_t, build, status_ + return INVALID_STATE; + } + ++METHOD(eap_peap_peer_t, get_auth, auth_cfg_t*, ++ private_eap_peap_peer_t *this) ++{ ++ return this->auth; ++} ++ + METHOD(tls_application_t, destroy, void, + private_eap_peap_peer_t *this) + { + this->server->destroy(this->server); + this->peer->destroy(this->peer); ++ this->auth->destroy(this->auth); + DESTROY_IF(this->ph2_method); + DESTROY_IF(this->out); + this->avp->destroy(this->avp); +@@ -247,10 +265,12 @@ eap_peap_peer_t *eap_peap_peer_create(id + .build = _build, + .destroy = _destroy, + }, ++ .get_auth = _get_auth, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + .ph1_method = eap_method, ++ .auth = auth_cfg_create(), + .avp = eap_peap_avp_create(FALSE), + ); + +--- a/src/libcharon/plugins/eap_peap/eap_peap_peer.h ++++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.h +@@ -38,6 +38,13 @@ struct eap_peap_peer_t { + * Implements the TLS application data handler. + */ + tls_application_t application; ++ ++ /** ++ * Get authentication details of this EAP method and its inner method(s). ++ * ++ * @return auth method, internal data ++ */ ++ auth_cfg_t *(*get_auth)(eap_peap_peer_t *this); + }; + + /** +--- a/src/libcharon/plugins/eap_peap/eap_peap_server.c ++++ b/src/libcharon/plugins/eap_peap/eap_peap_server.c +@@ -20,6 +20,8 @@ + #include <utils/debug.h> + #include <daemon.h> + ++#include <sa/eap/eap_inner_method.h> ++ + typedef struct private_eap_peap_server_t private_eap_peap_server_t; + + /** +@@ -73,6 +75,16 @@ struct private_eap_peap_server_t { + eap_method_t *ph2_method; + + /** ++ * Type of the completed phase 2 EAP method ++ */ ++ eap_type_t phase2_type; ++ ++ /** ++ * Auth data for phase 2 method ++ */ ++ auth_cfg_t *auth; ++ ++ /** + * Pending outbound EAP message + */ + eap_payload_t *out; +@@ -127,8 +139,11 @@ static status_t start_phase2_auth(privat + /** + * If configured, start EAP-TNC protocol + */ +-static status_t start_phase2_tnc(private_eap_peap_server_t *this) ++static status_t start_phase2_tnc(private_eap_peap_server_t *this, ++ eap_type_t auth_type) + { ++ eap_inner_method_t *inner_method; ++ + if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings, + "%s.plugins.eap-peap.phase2_tnc", FALSE, lib->ns)) + { +@@ -140,6 +155,8 @@ static status_t start_phase2_tnc(private + DBG1(DBG_IKE, "%N method not available", eap_type_names, EAP_TNC); + return FAILED; + } ++ inner_method = (eap_inner_method_t *)this->ph2_method; ++ inner_method->set_auth_type(inner_method, auth_type); + this->start_phase2_tnc = FALSE; + + /* synchronize EAP message identifiers of inner protocol with outer */ +@@ -213,9 +230,13 @@ METHOD(tls_application_t, process, statu + DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N]", + eap_code_short_names, code); + in->destroy(in); +- /* if EAP_SUCCESS check if to continue phase2 with EAP-TNC */ +- return (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ? +- start_phase2_tnc(this) : FAILED; ++ if (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ++ { ++ /* only accept SUCCESS once after a successful inner method */ ++ this->phase2_result = EAP_FAILURE; ++ return start_phase2_tnc(this, this->phase2_type); ++ } ++ return FAILED; + } + + if (this->ph2_method) +@@ -240,6 +261,10 @@ METHOD(tls_application_t, process, statu + if (!received_vendor && received_type == EAP_IDENTITY) + { + chunk_t eap_id; ++ bool peer_auth; ++ ++ peer_auth = lib->settings->get_bool(lib->settings, ++ "%s.plugins.eap-peap.request_peer_auth", FALSE, lib->ns); + + if (this->ph2_method == NULL) + { +@@ -266,9 +291,22 @@ METHOD(tls_application_t, process, statu + + if (this->ph2_method->get_msk(this->ph2_method, &eap_id) == SUCCESS) + { +- this->peer->destroy(this->peer); +- this->peer = identification_create_from_data(eap_id); +- DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer); ++ identification_t *id; ++ ++ id = identification_create_from_data(eap_id); ++ if (peer_auth && !id->equals(id, this->peer)) ++ { ++ DBG1(DBG_IKE, "received tunneled EAP identity '%Y', keeping " ++ "certificate-authenticated identity '%Y'", id, this->peer); ++ id->destroy(id); ++ } ++ else ++ { ++ DBG1(DBG_IKE, "received EAP identity '%Y'", id); ++ this->auth->add(this->auth, AUTH_RULE_EAP_IDENTITY, id); ++ this->peer->destroy(this->peer); ++ this->peer = id->clone(id); ++ } + } + + in->destroy(in); +@@ -276,10 +314,9 @@ METHOD(tls_application_t, process, statu + this->ph2_method = NULL; + + /* Start Phase 2 of EAP-PEAP authentication */ +- if (lib->settings->get_bool(lib->settings, +- "%s.plugins.eap-peap.request_peer_auth", FALSE, lib->ns)) ++ if (peer_auth) + { +- return start_phase2_tnc(this); ++ return start_phase2_tnc(this, EAP_TLS); + } + else + { +@@ -300,11 +337,26 @@ METHOD(tls_application_t, process, statu + switch (status) + { + case SUCCESS: ++ if (this->ph2_method->get_auth) ++ { ++ identification_t *id; ++ auth_cfg_t *auth; ++ ++ auth = this->ph2_method->get_auth(this->ph2_method); ++ id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); ++ if (id) ++ { ++ this->peer->destroy(this->peer); ++ this->peer = id->clone(id); ++ } ++ this->auth->merge(this->auth, auth, FALSE); ++ } + DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful", + eap_type_names, EAP_PEAP, this->peer, + eap_type_names, type); + this->ph2_method->destroy(this->ph2_method); + this->ph2_method = NULL; ++ this->phase2_type = type; + + /* EAP-PEAP requires the sending of an inner EAP_SUCCESS message */ + this->phase2_result = EAP_SUCCESS; +@@ -393,11 +445,18 @@ METHOD(tls_application_t, build, status_ + return INVALID_STATE; + } + ++METHOD(eap_peap_server_t, get_auth, auth_cfg_t*, ++ private_eap_peap_server_t *this) ++{ ++ return this->auth; ++} ++ + METHOD(tls_application_t, destroy, void, + private_eap_peap_server_t *this) + { + this->server->destroy(this->server); + this->peer->destroy(this->peer); ++ this->auth->destroy(this->auth); + DESTROY_IF(this->ph2_method); + DESTROY_IF(this->out); + this->avp->destroy(this->avp); +@@ -420,10 +479,12 @@ eap_peap_server_t *eap_peap_server_creat + .build = _build, + .destroy = _destroy, + }, ++ .get_auth = _get_auth, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + .ph1_method = eap_method, ++ .auth = auth_cfg_create(), + .start_phase2 = TRUE, + .start_phase2_tnc = TRUE, + .start_phase2_id = lib->settings->get_bool(lib->settings, +--- a/src/libcharon/plugins/eap_peap/eap_peap_server.h ++++ b/src/libcharon/plugins/eap_peap/eap_peap_server.h +@@ -38,6 +38,13 @@ struct eap_peap_server_t { + * Implements the TLS application data handler. + */ + tls_application_t application; ++ ++ /** ++ * Get authentication details of this EAP method and its inner method(s). ++ * ++ * @return auth method, internal data ++ */ ++ auth_cfg_t *(*get_auth)(eap_peap_server_t *this); + }; + + /** +--- a/src/libcharon/plugins/eap_ttls/eap_ttls.c ++++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c +@@ -40,6 +40,25 @@ struct private_eap_ttls_t { + * TLS stack, wrapped by EAP helper + */ + tls_eap_t *tls_eap; ++ ++ /** ++ * Role ++ */ ++ bool is_server; ++ ++ /** ++ * Actual server/client implementation ++ */ ++ union { ++ tls_application_t *application; ++ eap_ttls_server_t *server; ++ eap_ttls_peer_t *client; ++ } impl; ++ ++ /** ++ * Cached auth data for TLS and inner EAP methods ++ */ ++ auth_cfg_t *auth; + }; + + /** Maximum number of EAP-TTLS messages/fragments allowed */ +@@ -116,13 +135,31 @@ METHOD(eap_method_t, is_mutual, bool, + METHOD(eap_method_t, get_auth, auth_cfg_t*, + private_eap_ttls_t *this) + { +- return this->tls_eap->get_auth(this->tls_eap); ++ if (!this->auth) ++ { ++ auth_cfg_t *inner; ++ ++ this->auth = auth_cfg_create(); ++ this->auth->merge(this->auth, ++ this->tls_eap->get_auth(this->tls_eap), FALSE); ++ if (this->is_server) ++ { ++ inner = this->impl.server->get_auth(this->impl.server); ++ } ++ else ++ { ++ inner = this->impl.client->get_auth(this->impl.client); ++ } ++ this->auth->merge(this->auth, inner, FALSE); ++ } ++ return this->auth; + } + + METHOD(eap_method_t, destroy, void, + private_eap_ttls_t *this) + { + this->tls_eap->destroy(this->tls_eap); ++ DESTROY_IF(this->auth); + free(this); + } + +@@ -153,6 +190,10 @@ static eap_ttls_t *eap_ttls_create(ident + .destroy = _destroy, + }, + }, ++ .is_server = is_server, ++ .impl = { ++ .application = application, ++ }, + ); + if (is_server && !lib->settings->get_bool(lib->settings, + "%s.plugins.eap-ttls.request_peer_auth", FALSE, +--- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c ++++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +@@ -55,6 +55,11 @@ struct private_eap_ttls_peer_t { + eap_method_t *method; + + /** ++ * Auth data for phase 2 method ++ */ ++ auth_cfg_t *auth; ++ ++ /** + * Pending outbound EAP message + */ + eap_payload_t *out; +@@ -215,6 +220,11 @@ METHOD(tls_application_t, process, statu + switch (status) + { + case SUCCESS: ++ if (this->method->get_auth) ++ { ++ this->auth->merge(this->auth, ++ this->method->get_auth(this->method), FALSE); ++ } + this->method->destroy(this->method); + this->method = NULL; + /* fall through to NEED_MORE */ +@@ -276,11 +286,18 @@ METHOD(tls_application_t, build, status_ + return INVALID_STATE; + } + ++METHOD(eap_ttls_peer_t, get_auth, auth_cfg_t*, ++ private_eap_ttls_peer_t *this) ++{ ++ return this->auth; ++} ++ + METHOD(tls_application_t, destroy, void, + private_eap_ttls_peer_t *this) + { + this->server->destroy(this->server); + this->peer->destroy(this->peer); ++ this->auth->destroy(this->auth); + DESTROY_IF(this->method); + DESTROY_IF(this->out); + this->avp->destroy(this->avp); +@@ -302,10 +319,12 @@ eap_ttls_peer_t *eap_ttls_peer_create(id + .build = _build, + .destroy = _destroy, + }, ++ .get_auth = _get_auth, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + .start_phase2 = TRUE, ++ .auth = auth_cfg_create(), + .avp = eap_ttls_avp_create(), + ); + +--- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h ++++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.h +@@ -37,6 +37,13 @@ struct eap_ttls_peer_t { + * Implements the TLS application data handler. + */ + tls_application_t application; ++ ++ /** ++ * Get authentication details of this EAP method and its inner method(s). ++ * ++ * @return auth method, internal data ++ */ ++ auth_cfg_t *(*get_auth)(eap_ttls_peer_t *this); + }; + + /** +--- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c ++++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +@@ -61,6 +61,11 @@ struct private_eap_ttls_server_t { + eap_method_t *method; + + /** ++ * Auth data for phase 2 method ++ */ ++ auth_cfg_t *auth; ++ ++ /** + * Pending outbound EAP message + */ + eap_payload_t *out; +@@ -220,6 +225,10 @@ METHOD(tls_application_t, process, statu + if (!received_vendor && received_type == EAP_IDENTITY) + { + chunk_t eap_id; ++ bool peer_auth; ++ ++ peer_auth = lib->settings->get_bool(lib->settings, ++ "%s.plugins.eap-ttls.request_peer_auth", FALSE, lib->ns); + + if (this->method == NULL) + { +@@ -244,9 +253,22 @@ METHOD(tls_application_t, process, statu + + if (this->method->get_msk(this->method, &eap_id) == SUCCESS) + { +- this->peer->destroy(this->peer); +- this->peer = identification_create_from_data(eap_id); +- DBG1(DBG_IKE, "received EAP identity '%Y'", this->peer); ++ identification_t *id; ++ ++ id = identification_create_from_data(eap_id); ++ if (peer_auth && !id->equals(id, this->peer)) ++ { ++ DBG1(DBG_IKE, "received tunneled EAP identity '%Y', keeping " ++ "certificate-authenticated identity '%Y'", id, this->peer); ++ id->destroy(id); ++ } ++ else ++ { ++ DBG1(DBG_IKE, "received EAP identity '%Y'", id); ++ this->auth->add(this->auth, AUTH_RULE_EAP_IDENTITY, id); ++ this->peer->destroy(this->peer); ++ this->peer = id->clone(id); ++ } + } + + in->destroy(in); +@@ -254,8 +276,7 @@ METHOD(tls_application_t, process, statu + this->method = NULL; + + /* Start Phase 2 of EAP-TTLS authentication */ +- if (lib->settings->get_bool(lib->settings, +- "%s.plugins.eap-ttls.request_peer_auth", FALSE, lib->ns)) ++ if (peer_auth) + { + return start_phase2_tnc(this, EAP_TLS); + } +@@ -278,6 +299,20 @@ METHOD(tls_application_t, process, statu + switch (status) + { + case SUCCESS: ++ if (this->method->get_auth) ++ { ++ identification_t *id; ++ auth_cfg_t *auth; ++ ++ auth = this->method->get_auth(this->method); ++ id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); ++ if (id) ++ { ++ this->peer->destroy(this->peer); ++ this->peer = id->clone(id); ++ } ++ this->auth->merge(this->auth, auth, FALSE); ++ } + DBG1(DBG_IKE, "%N phase2 authentication of '%Y' with %N successful", + eap_type_names, EAP_TTLS, this->peer, + eap_type_names, type); +@@ -348,11 +383,18 @@ METHOD(tls_application_t, build, status_ + return INVALID_STATE; + } + ++METHOD(eap_ttls_server_t, get_auth, auth_cfg_t*, ++ private_eap_ttls_server_t *this) ++{ ++ return this->auth; ++} ++ + METHOD(tls_application_t, destroy, void, + private_eap_ttls_server_t *this) + { + this->server->destroy(this->server); + this->peer->destroy(this->peer); ++ this->auth->destroy(this->auth); + DESTROY_IF(this->method); + DESTROY_IF(this->out); + this->avp->destroy(this->avp); +@@ -374,11 +416,13 @@ eap_ttls_server_t *eap_ttls_server_creat + .build = _build, + .destroy = _destroy, + }, ++ .get_auth = _get_auth, + }, + .server = server->clone(server), +- .peer = peer->clone(peer), ++ .auth = auth_cfg_create(), + .start_phase2 = TRUE, + .start_phase2_tnc = TRUE, ++ .peer = peer->clone(peer), + .avp = eap_ttls_avp_create(), + ); + +--- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.h ++++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.h +@@ -37,6 +37,13 @@ struct eap_ttls_server_t { + * Implements the TLS application data handler. + */ + tls_application_t application; ++ ++ /** ++ * Get authentication details of this EAP method and its inner method(s). ++ * ++ * @return auth method, internal data ++ */ ++ auth_cfg_t *(*get_auth)(eap_ttls_server_t *this); + }; + + /** diff -Nru strongswan-5.9.8/debian/patches/0026-ikev2-Properly-reject-CREATE_CHILD_SA-requests-on-un.patch strongswan-5.9.8/debian/patches/0026-ikev2-Properly-reject-CREATE_CHILD_SA-requests-on-un.patch --- strongswan-5.9.8/debian/patches/0026-ikev2-Properly-reject-CREATE_CHILD_SA-requests-on-un.patch 1969-12-31 18:00:00.000000000 -0600 +++ strongswan-5.9.8/debian/patches/0026-ikev2-Properly-reject-CREATE_CHILD_SA-requests-on-un.patch 2026-10-27 11:22:34.000000000 -0500 @@ -0,0 +1,69 @@ +Origin: https://download.strongswan.org/security/CVE-2026-78135/strongswan-5.9.7-6.0.7_early_create_child_sa.patch +Reviewed-by: Simon Quigley <[email protected]> +Last-Update: 2026-10-26 + +From a34fb034926ccfebe556eb66aae5572a3b0b7e14 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner <[email protected]> +Date: Mon, 27 Jul 2026 08:53:50 +0200 +Subject: [PATCH] ikev2: Properly reject CREATE_CHILD_SA requests on + unestablished IKE_SAs + +The previous check was not actually enforced as long as there were still +tasks in the passive queue (it was originally added to fix an issue on +initiators, so the passive queue was expected to be empty). This allowed +an unauthenticated attacker to potentially establish a usable Child SA +if certain preconditions were met. + +First, it required that the initiator is authenticated with EAP so the +authentication and the creation of the first Child SA is deferred. +Second, the responder must either not configure an IP address pool or +an explicit remote TS, otherwise, traffic selector negotiation fails. + +Note that the half-open IKE SA and the installed IPsec SA will be removed +after the default timeout of 30 seconds. + +Fixes: 8503077175cd ("ikev2: Reject CREATE_CHILD_SA exchange on unestablished IKE_SAs") +Fixes: c60c7694d2d8 ("merged tasking branch into trunk") +Fixes: CVE-2026-78135 +--- + src/libcharon/sa/ikev2/task_manager_v2.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +--- a/src/libcharon/sa/ikev2/task_manager_v2.c ++++ b/src/libcharon/sa/ikev2/task_manager_v2.c +@@ -1129,9 +1129,18 @@ static status_t process_request(private_ + delete_payload_t *delete; + ike_sa_state_t state; + ++ state = this->ike_sa->get_state(this->ike_sa); ++ if (message->get_exchange_type(message) == CREATE_CHILD_SA && ++ (state == IKE_CREATED || state == IKE_CONNECTING)) ++ { ++ DBG1(DBG_IKE, "received CREATE_CHILD_SA request for " ++ "unestablished IKE_SA, rejected"); ++ return FAILED; ++ } ++ ++ /* create tasks depending on request type, if not already some queued */ + if (array_count(this->passive_tasks) == 0) +- { /* create tasks depending on request type, if not already some queued */ +- state = this->ike_sa->get_state(this->ike_sa); ++ { + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: +@@ -1172,14 +1181,6 @@ static status_t process_request(private_ + { /* FIXME: we should prevent this on mediation connections */ + bool notify_found = FALSE, ts_found = FALSE; + +- if (state == IKE_CREATED || +- state == IKE_CONNECTING) +- { +- DBG1(DBG_IKE, "received CREATE_CHILD_SA request for " +- "unestablished IKE_SA, rejected"); +- return FAILED; +- } +- + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { diff -Nru strongswan-5.9.8/debian/patches/series strongswan-5.9.8/debian/patches/series --- strongswan-5.9.8/debian/patches/series 2026-05-27 01:58:30.000000000 -0500 +++ strongswan-5.9.8/debian/patches/series 2026-10-27 11:22:34.000000000 -0500 @@ -14,3 +14,13 @@ 0014-constraints-Case-insensitive-matching-and-reject-exc.patch 0015-gmp-Avoid-crash-and-timing-leaks-in-PKCS-1-v1.5-decr.patch 0016-identification-Fix-double-free-when-cloning-empty-ID.patch +0017-openssl-Fix-undefined-memory-access-when-verifying-P.patch +0018-openssl-Fix-memory-leaks-after-enumerating-certifica.patch +0019-eap-aka-Only-accept-AKA-Synchronization-Failure-if-e.patch +0020-message-Avoid-memory-leak-if-string-buffer-for-messa.patch +0021-pkcs5-Validate-parsed-parameters-to-avoid-DoS-attack.patch +0022-x509-Avoid-NULL-pointer-dereference-if-issuerName-is.patch +0023-x509-Fix-memory-leaks-when-parsing-attribute-certifi.patch +0024-x509-Prevent-infinite-loop-when-parsing-ietfAttrSynt.patch +0025-eap-ttls-peap-Return-auth-cfg-with-details-on-TLS-an.patch +0026-ikev2-Properly-reject-CREATE_CHILD_SA-requests-on-un.patch
OpenPGP_signature.asc
Description: OpenPGP digital signature
