Commit 6a7210731f for strongswan.org

commit 6a7210731f6dd2889d22bf20310ab0ed7274d0d8
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Mon Jul 27 15:24:53 2026 +0200

    eap-peap: Return auth-cfg with details on TLS and inner EAP method

    For some reason this plugin was not changed with the first referenced
    merge commit.  So this commit adds the missing `get_auth` method and
    basically the same implementation as the previous commit to expose
    details on the inner EAP method including the EAP-Identity.

    It also forwards the phase 2 EAP method type to EAP-TNC like the eap-ttls
    plugin does to allow a more informed decision on the client's identity.
    This was overlooked in the second referenced commit.

    Fixes: ec5752747557 ("Merge branch 'eap-constraints'")
    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

diff --git a/src/libcharon/plugins/eap_peap/eap_peap.c b/src/libcharon/plugins/eap_peap/eap_peap.c
index 3573cba7c6..cd942f135d 100644
--- 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_create_empty(void)
 				.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_create_empty(void)
 /**
  * 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(private_eap_peap_t * this,
 	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))
diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c
index 95213a3286..f6c087ab2b 100644
--- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c
+++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c
@@ -52,6 +52,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
 	 */
@@ -166,6 +171,12 @@ METHOD(tls_application_t, process, status_t,
 	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_t,
 	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(identification_t *server,
 				.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),
 	);

diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.h b/src/libcharon/plugins/eap_peap/eap_peap_peer.h
index 53c25cdd6b..7d16957432 100644
--- 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);
 };

 /**
diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.c b/src/libcharon/plugins/eap_peap/eap_peap_server.c
index 4d489a13a3..010fee447b 100644
--- 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;

 /**
@@ -77,6 +79,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
 	 */
@@ -133,8 +145,11 @@ static status_t start_phase2_auth(private_eap_peap_server_t *this)
 /**
  * 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))
 	{
@@ -147,6 +162,8 @@ static status_t start_phase2_tnc(private_eap_peap_server_t *this)
 			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 */
@@ -225,7 +242,7 @@ METHOD(tls_application_t, process, status_t,
 		{
 			/* only accept SUCCESS once after a successful inner method */
 			this->phase2_result = EAP_FAILURE;
-			return start_phase2_tnc(this);
+			return start_phase2_tnc(this, this->phase2_type);
 		}
 		return FAILED;
 	}
@@ -252,6 +269,10 @@ METHOD(tls_application_t, process, status_t,
 	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)
 		{
@@ -278,9 +299,22 @@ METHOD(tls_application_t, process, status_t,

 		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);
@@ -288,10 +322,9 @@ METHOD(tls_application_t, process, status_t,
 		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
 		{
@@ -312,11 +345,26 @@ METHOD(tls_application_t, process, status_t,
 	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;
@@ -414,11 +462,18 @@ METHOD(eap_peap_server_t, set_tls, void,
 	this->tls = tls;
 }

+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);
@@ -442,10 +497,12 @@ eap_peap_server_t *eap_peap_server_create(identification_t *server,
 				.destroy = _destroy,
 			},
 			.set_tls = _set_tls,
+			.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,
diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.h b/src/libcharon/plugins/eap_peap/eap_peap_server.h
index 3abe88bea6..8080e9f23b 100644
--- a/src/libcharon/plugins/eap_peap/eap_peap_server.h
+++ b/src/libcharon/plugins/eap_peap/eap_peap_server.h
@@ -47,6 +47,13 @@ struct eap_peap_server_t {
 	 * @param tls		TLS connection
 	 */
 	void (*set_tls)(eap_peap_server_t *this, tls_t *tls);
+
+	/**
+	 * 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);
 };

 /**