Commit e8c4187652 for strongswan.org

commit e8c4187652dda54c86fb8d86a57396b71713bb28
Author: Tobias Brunner <tobias@strongswan.org>
Date:   Fri Aug 28 11:26:13 2026 +0200

    charon-tkm: Use mapped signature scheme and pass AUTH payload without algorithm identifier

    This makes the authentication creation and verification symmetric. Before,
    it was necessary to parse/skip the identifier when verifying while already
    none had to be added when creating a signature.

    The changes also fix issues with potentially multiple calls to `sign()`
    by storing the IKE_SA_INIT message directly in the misused auth octets.
    So it doesn't have to be freed by `sign()` but is done automatically by
    the caller.

diff --git a/src/charon-tkm/src/tkm/tkm_keymat.c b/src/charon-tkm/src/tkm/tkm_keymat.c
index 094007c73a..11bc62e97d 100644
--- a/src/charon-tkm/src/tkm/tkm_keymat.c
+++ b/src/charon-tkm/src/tkm/tkm_keymat.c
@@ -66,6 +66,11 @@ struct private_tkm_keymat_t {
 	 */
 	ae_id_type ae_ctx_id;

+	/**
+	 * Authentication method from AUTH payload.
+	 */
+	auth_method_t auth_method;
+
 	/**
 	 * AUTH payload chunk.
 	 */
@@ -403,16 +408,15 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
 		return TRUE;
 	}

-	INIT(sign,
+	/* add IKE_SA_INIT at the end of the struct so it gets freed with it */
+	INIT_EXTRA(sign, ike_sa_init.len,
 		 .isa_id = this->isa_ctx_id,
-		 .init_message = chunk_clone(ike_sa_init),
 	);
+	memcpy(sign->init_message_data, ike_sa_init.ptr, ike_sa_init.len);

-	/*
-	 * store signature info in AUTH octets, which is passed to the private key
-	 * sign() operation
-	 */
-	*octets = chunk_create((u_char *)sign, sizeof(sign_info_t));
+	/* store signature info in AUTH octets, which is passed to the private key
+	 * sign() operation */
+	*octets = chunk_create((u_char*)sign, sizeof(sign_info_t) + ike_sa_init.len);
 	return TRUE;
 }

@@ -498,15 +502,21 @@ METHOD(tkm_keymat_t, get_isa_id, isa_id_type,
 }

 METHOD(tkm_keymat_t, set_auth_payload, void,
-	private_tkm_keymat_t *this, const chunk_t * const payload)
+	private_tkm_keymat_t *this, const auth_method_t method,
+	const chunk_t * const payload)
 {
+	this->auth_method = method;
 	this->auth_payload = chunk_clone(*payload);
 }

-METHOD(tkm_keymat_t, get_auth_payload, chunk_t*,
-	private_tkm_keymat_t *this)
+METHOD(tkm_keymat_t, get_auth_payload, chunk_t,
+	private_tkm_keymat_t *this, auth_method_t *method)
 {
-	return &this->auth_payload;
+	if (method)
+	{
+		*method = this->auth_method;
+	}
+	return this->auth_payload;
 }

 METHOD(tkm_keymat_t, get_peer_init_msg, chunk_t*,
diff --git a/src/charon-tkm/src/tkm/tkm_keymat.h b/src/charon-tkm/src/tkm/tkm_keymat.h
index c9f787c0f5..6ca9035862 100644
--- a/src/charon-tkm/src/tkm/tkm_keymat.h
+++ b/src/charon-tkm/src/tkm/tkm_keymat.h
@@ -24,6 +24,7 @@
 #ifndef TKM_KEYMAT_H_
 #define TKM_KEYMAT_H_

+#include <sa/authenticator.h>
 #include <sa/ikev2/keymat_v2.h>

 typedef struct tkm_keymat_t tkm_keymat_t;
@@ -46,18 +47,22 @@ struct tkm_keymat_t {
 	isa_id_type (*get_isa_id)(tkm_keymat_t * const this);

 	/**
-	 * Set IKE AUTH payload.
+	 * Set IKE AUTH payload method and data.
 	 *
+	 * @param method		authentication method
 	 * @param payload		AUTH payload
 	 */
-	void (*set_auth_payload)(tkm_keymat_t *this, const chunk_t * const payload);
+	void (*set_auth_payload)(tkm_keymat_t *this, const auth_method_t method,
+							 const chunk_t * const payload);

 	/**
 	 * Get IKE AUTH payload.
 	 *
+	 * @param[out] method	authentication method
 	 * @return				AUTH payload if set, chunk_empty otherwise
 	 */
-	chunk_t* (*get_auth_payload)(tkm_keymat_t * const this);
+	chunk_t (*get_auth_payload)(tkm_keymat_t * const this,
+								auth_method_t *method);

 	/**
 	 * Get IKE init message of peer.
diff --git a/src/charon-tkm/src/tkm/tkm_listener.c b/src/charon-tkm/src/tkm/tkm_listener.c
index 7e4a0ecf0d..55989d508b 100644
--- a/src/charon-tkm/src/tkm/tkm_listener.c
+++ b/src/charon-tkm/src/tkm/tkm_listener.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2026 Tobias Brunner
  * Copyright (C) 2012 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
  *
@@ -22,6 +23,7 @@
 #include <collections/array.h>
 #include <collections/hashtable.h>
 #include <encoding/payloads/auth_payload.h>
+#include <sa/ikev2/authenticators/pubkey_authenticator.h>
 #include <utils/chunk.h>
 #include <tkm/types.h>
 #include <tkm/constants.h>
@@ -281,7 +283,10 @@ METHOD(listener_t, authorize, bool,
 	tkm_keymat_t *keymat;
 	isa_id_type isa_id;
 	cc_id_type cc_id;
-	chunk_t *auth, *other_init_msg;
+	chunk_t auth, *other_init_msg;
+	auth_method_t method;
+	signature_params_t *params = NULL;
+	siga_id_type siga_id;
 	signature_type signature;
 	blob_id_type init_message_id = 0;

@@ -308,13 +313,28 @@ METHOD(listener_t, authorize, bool,
 		goto cc_reset;
 	}

-	auth = keymat->get_auth_payload(keymat);
-	if (!auth->ptr)
+	auth = keymat->get_auth_payload(keymat, &method);
+	if (!auth.ptr)
 	{
 		DBG1(DBG_IKE, "no AUTHENTICATION data available");
 		goto cc_reset;
 	}

+	params = pubkey_authenticator_parse_auth_data(method, NULL, &auth);
+	if (!params)
+	{
+		DBG1(DBG_IKE, "authentication method not supported or payload invalid");
+		goto cc_reset;
+	}
+
+	siga_id = siga_from_signature_scheme(params->scheme);
+	if (!siga_id)
+	{
+		DBG1(DBG_IKE, "unable to map signature scheme %N to SigA context id",
+			 signature_scheme_names, params->scheme);
+		goto cc_reset;
+	}
+
 	other_init_msg = keymat->get_peer_init_msg(keymat);
 	if (!other_init_msg->ptr)
 	{
@@ -335,8 +355,9 @@ METHOD(listener_t, authorize, bool,
 		goto cc_reset;
 	}

-	chunk_to_sequence(auth, &signature, sizeof(signature_type));
-	if (ike_isa_auth(isa_id, cc_id, init_message_id, 1, signature) != TKM_OK)
+	chunk_to_sequence(&auth, &signature, sizeof(signature_type));
+	if (ike_isa_auth(isa_id, cc_id, init_message_id, siga_id,
+					 signature) != TKM_OK)
 	{
 		DBG1(DBG_IKE, "TKM based authentication failed"
 			 " for ISA context %llu", isa_id);
@@ -359,6 +380,7 @@ cc_reset:
 	{
 		tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_BLOB, init_message_id);
 	}
+	signature_params_destroy(params);
 	return TRUE; /* stay registered */
 }

@@ -384,10 +406,12 @@ METHOD(listener_t, message, bool,
 														 PLV2_AUTH);
 	if (auth_payload)
 	{
+		auth_method_t method;
 		chunk_t auth_data;

+		method = auth_payload->get_auth_method(auth_payload);
 		auth_data = auth_payload->get_data(auth_payload);
-		keymat->set_auth_payload(keymat, &auth_data);
+		keymat->set_auth_payload(keymat, method, &auth_data);
 	}
 	else
 	{
diff --git a/src/charon-tkm/src/tkm/tkm_private_key.c b/src/charon-tkm/src/tkm/tkm_private_key.c
index 78adc38ad3..11c61756d2 100644
--- a/src/charon-tkm/src/tkm/tkm_private_key.c
+++ b/src/charon-tkm/src/tkm/tkm_private_key.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2026 Tobias Brunner
  * Copyright (C) 2012-2013 Reto Buerki
  * Copyright (C) 2012-2013 Adrian-Ken Rueegsegger
  *
@@ -23,6 +24,7 @@
 #include "tkm.h"
 #include "tkm_utils.h"
 #include "tkm_types.h"
+#include "tkm_keymat.h"
 #include "tkm_private_key.h"

 typedef struct private_tkm_private_key_t private_tkm_private_key_t;
@@ -66,8 +68,9 @@ METHOD(private_key_t, sign, bool,
 {
 	signature_type sig;
 	blob_id_type msg_id;
-	sign_info_t sign;
-	isa_id_type isa_id;
+	sign_info_t *sign;
+	siga_id_type siga_id;
+	chunk_t init;
 	bool success = FALSE;

 	if (data.ptr == NULL)
@@ -75,19 +78,26 @@ METHOD(private_key_t, sign, bool,
 		DBG1(DBG_LIB, "unable to get signature information");
 		return FALSE;
 	}
-	sign = *(sign_info_t*)(data.ptr);
+	sign = (sign_info_t*)data.ptr;
+	init = chunk_skip(data, sizeof(sign_info_t));
+
+	siga_id = siga_from_signature_scheme(scheme);
+	if (!siga_id)
+	{
+		DBG1(DBG_LIB, "unable to map signature scheme %N to SigA context id",
+			 signature_scheme_names, scheme);
+		return FALSE;
+	}

 	msg_id = tkm->idmgr->acquire_id(tkm->idmgr, TKM_CTX_BLOB);
 	if (!msg_id)
 	{
 		DBG1(DBG_LIB, "unable to acquire blob context id for init message");
-		chunk_free(&sign.init_message);
 		return FALSE;
 	}

-	isa_id = sign.isa_id;
-	if (chunk_to_blob(msg_id, &sign.init_message) &&
-		ike_isa_sign(isa_id, 1, msg_id, 1, &sig) == TKM_OK)
+	if (chunk_to_blob(msg_id, &init) &&
+		ike_isa_sign(sign->isa_id, 1, msg_id, siga_id, &sig) == TKM_OK)
 	{
 		sequence_to_chunk(sig.data, sig.size, signature);
 		success = TRUE;
@@ -98,7 +108,6 @@ METHOD(private_key_t, sign, bool,
 	}

 	tkm->idmgr->release_id(tkm->idmgr, TKM_CTX_BLOB, msg_id);
-	chunk_free(&sign.init_message);
 	return success;
 }

diff --git a/src/charon-tkm/src/tkm/tkm_types.h b/src/charon-tkm/src/tkm/tkm_types.h
index bca533cb25..b319a5a8fb 100644
--- a/src/charon-tkm/src/tkm/tkm_types.h
+++ b/src/charon-tkm/src/tkm/tkm_types.h
@@ -125,10 +125,9 @@ struct sign_info_t {
 	isa_id_type isa_id;

 	/**
-	 * Init message.
+	 * Actual init message data.
 	 */
-	chunk_t init_message;
-
+	u_char init_message_data[];
 };

 #endif /** TKM_TYPES_H_ @}*/