Commit d810f12404 for strongswan.org

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

    charon-tkm: Add facility to map signature schemes to TKM identifiers

diff --git a/src/charon-tkm/src/charon-tkm.c b/src/charon-tkm/src/charon-tkm.c
index 4ed23ff56c..047d86393b 100644
--- a/src/charon-tkm/src/charon-tkm.c
+++ b/src/charon-tkm/src/charon-tkm.c
@@ -342,6 +342,13 @@ int main(int argc, char *argv[])
 		goto deinit;
 	}

+	if (!register_sig_mapping())
+	{
+		DBG1(DBG_DMN, "no signature scheme mapping defined - aborting %s",
+			 dmn_name);
+		goto deinit;
+	}
+
 	if (!register_ke_mapping())
 	{
 		DBG1(DBG_DMN, "no KE group mapping defined - aborting %s", dmn_name);
@@ -435,6 +442,7 @@ int main(int argc, char *argv[])

 deinit:
 	destroy_proposal_mapping();
+	destroy_sig_mapping();
 	destroy_ke_mapping();
 	destroy_ca_mapping();
 	libcharon_deinit();
diff --git a/src/charon-tkm/src/tkm/tkm_keymat.c b/src/charon-tkm/src/tkm/tkm_keymat.c
index b10b27a3b0..094007c73a 100644
--- a/src/charon-tkm/src/tkm/tkm_keymat.c
+++ b/src/charon-tkm/src/tkm/tkm_keymat.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2022 Tobias Brunner
+ * Copyright (C) 2015-2026 Tobias Brunner
  * Copyright (C) 2012 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
  *
@@ -20,6 +20,7 @@
 #include <tkm/constants.h>
 #include <tkm/client.h>
 #include <collections/array.h>
+#include <collections/hashtable.h>
 #include <crypto/hashers/hash_algorithm_set.h>

 #include "tkm.h"
@@ -33,6 +34,7 @@ typedef struct private_tkm_keymat_t private_tkm_keymat_t;

 static array_t *ike_proposal_map = NULL;
 static array_t *esp_proposal_map = NULL;
+static hashtable_t *scheme_map = NULL;

 /**
  * Private data of a keymat_t object.
@@ -588,6 +590,124 @@ void destroy_proposal_mapping()
 	esp_proposal_map = NULL;
 }

+static u_int hash(void *key)
+{
+	signature_scheme_t s = *(signature_scheme_t*)key;
+	return chunk_hash(chunk_from_thing(s));
+}
+
+static bool equals(void *key, void *other_key)
+{
+	return *(signature_scheme_t*)key == *(signature_scheme_t*)other_key;
+}
+
+/**
+ * Destroy a mapping hashtable and all its key/value pairs
+ */
+static void destroy_map(hashtable_t *map)
+{
+	enumerator_t *enumerator;
+	char *key, *value;
+
+	enumerator = map->create_enumerator(map);
+	while (enumerator->enumerate(enumerator, &key, &value))
+	{
+		free(key);
+		free(value);
+	}
+	enumerator->destroy(enumerator);
+	map->destroy(map);
+}
+
+/*
+ * Described in header
+ */
+uint64_t siga_from_signature_scheme(signature_scheme_t scheme)
+{
+	uint64_t *siga_id_ptr = NULL;
+
+	if (scheme_map)
+	{
+		siga_id_ptr = scheme_map->get(scheme_map, &scheme);
+	}
+	return siga_id_ptr ? *siga_id_ptr : 0;
+}
+
+/*
+ * Described in header
+ */
+int register_sig_mapping()
+{
+	int count;
+	char *sig_id_str, *tkm_id_str;
+	signature_scheme_t scheme, *sig_id;
+	uint64_t id, *tkm_id;
+	hashtable_t *map;
+	enumerator_t *enumerator;
+	bool valid = TRUE;
+
+	map = hashtable_create((hashtable_hash_t)hash,
+						   (hashtable_equals_t)equals, 16);
+
+	enumerator = lib->settings->create_key_value_enumerator(lib->settings,
+															"%s.sig_mapping",
+															lib->ns);
+
+	while (enumerator->enumerate(enumerator, &sig_id_str, &tkm_id_str))
+	{
+		if (!enum_from_name(signature_scheme_names, sig_id_str, &scheme))
+		{
+			DBG1(DBG_CFG, "unknown signature scheme: '%s'", sig_id_str);
+			valid = FALSE;
+			break;
+		}
+		if (map->get(map, &scheme))
+		{
+			DBG1(DBG_CFG, "duplicate signature scheme mapping for %N",
+				 signature_scheme_names, scheme);
+			valid = FALSE;
+			break;
+		}
+		id = settings_value_as_uint64(tkm_id_str, 0);
+		if (!id)
+		{
+			DBG1(DBG_CFG, "invalid TKM signature identifier: '%s'", tkm_id_str);
+			valid = FALSE;
+			break;
+		}
+
+		sig_id = malloc_thing(signature_scheme_t);
+		*sig_id = scheme;
+		tkm_id = malloc_thing(uint64_t);
+		*tkm_id = id;
+
+		map->put(map, sig_id, tkm_id);
+	}
+	enumerator->destroy(enumerator);
+
+	count = map->get_count(map);
+
+	if (valid && count > 0)
+	{
+		scheme_map = map;
+		return count;
+	}
+	destroy_map(map);
+	return 0;
+}
+
+/*
+ * Described in header
+ */
+void destroy_sig_mapping()
+{
+	if (scheme_map)
+	{
+		destroy_map(scheme_map);
+		scheme_map = NULL;
+	}
+}
+
 /*
  * Described in header
  */
diff --git a/src/charon-tkm/src/tkm/tkm_keymat.h b/src/charon-tkm/src/tkm/tkm_keymat.h
index 43e4f1bb0a..c9f787c0f5 100644
--- a/src/charon-tkm/src/tkm/tkm_keymat.h
+++ b/src/charon-tkm/src/tkm/tkm_keymat.h
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2022-2026 Tobias Brunner
  * Copyright (C) 2012 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
  *
@@ -79,6 +80,26 @@ int register_proposal_mapping();
  */
 void destroy_proposal_mapping();

+/**
+ * Map a signature scheme to a TKM signature algorithm id.
+ *
+ * @param scheme	signature scheme to map
+ * @return			mapped TKM id, 0 if not supported
+ */
+uint64_t siga_from_signature_scheme(signature_scheme_t scheme);
+
+/**
+ * Loads signature scheme identifier to TKM id mapping from config.
+ *
+ * @return			number of registered mappings
+ */
+int register_sig_mapping();
+
+/**
+ * Destroy signature scheme identifier to TKM id mapping.
+ */
+void destroy_sig_mapping();
+
 /**
  * Create TKM keymat instance.
  *
diff --git a/src/charon-tkm/tests/keymat_tests.c b/src/charon-tkm/tests/keymat_tests.c
index ae3ebb1a15..54bfbefcf4 100644
--- a/src/charon-tkm/tests/keymat_tests.c
+++ b/src/charon-tkm/tests/keymat_tests.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2013-2026 Tobias Brunner
  * Copyright (C) 2012 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
  *
@@ -28,6 +29,13 @@
 #include "tkm_keymat.h"
 #include "tkm_types.h"

+START_TEST(test_siga_from_signature_scheme)
+{
+	ck_assert_int_eq((uint64_t)1, siga_from_signature_scheme(SIGN_RSA_EMSA_PKCS1_SHA1));
+	ck_assert_int_eq((uint64_t)2, siga_from_signature_scheme(SIGN_RSA_EMSA_PKCS1_SHA2_256));
+}
+END_TEST
+
 START_TEST(test_derive_ike_keys)
 {
 	proposal_t *proposal = proposal_create_from_string(PROTO_IKE,
@@ -350,6 +358,10 @@ Suite *make_keymat_tests()

 	s = suite_create("keymat");

+	tc = tcase_create("sig mapping");
+	tcase_add_test(tc, test_siga_from_signature_scheme);
+	suite_add_tcase(s, tc);
+
 	tc = tcase_create("derive IKE keys");
 	tcase_add_test(tc, test_derive_ike_keys);
 	tcase_add_test(tc, test_derive_ike_keys_multi_ke);
diff --git a/src/charon-tkm/tests/tests.c b/src/charon-tkm/tests/tests.c
index f3bc7b0413..b5c90f1940 100644
--- a/src/charon-tkm/tests/tests.c
+++ b/src/charon-tkm/tests/tests.c
@@ -84,7 +84,14 @@ static bool test_runner_init(bool init)
 							   "aes256-sha512-prfsha512", lib->ns, 1);
 		lib->settings->set_str(lib->settings, "%s.proposal_mapping.esp.%d",
 							   "aes256-sha512-esn-noesn", lib->ns, 1);
+		lib->settings->set_int(lib->settings, "%s.sig_mapping.%N", 1,
+							   lib->ns, signature_scheme_names,
+							   SIGN_RSA_EMSA_PKCS1_SHA1);
+		lib->settings->set_int(lib->settings, "%s.sig_mapping.%N", 2,
+							   lib->ns, signature_scheme_names,
+							   SIGN_RSA_EMSA_PKCS1_SHA2_256);
 		register_proposal_mapping();
+		register_sig_mapping();
 		register_ke_mapping();

 		plugin_loader_add_plugindirs(BUILDDIR "/src/libstrongswan/plugins",
@@ -107,6 +114,7 @@ static bool test_runner_init(bool init)
 	}

 	destroy_proposal_mapping();
+	destroy_sig_mapping();
 	destroy_ke_mapping();
 	libcharon_deinit();
 	return result;
diff --git a/testing/tests/tkm/host2host-initiator-multi-ke/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/host2host-initiator-multi-ke/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/host2host-initiator-multi-ke/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/host2host-initiator-multi-ke/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/host2host-initiator/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/host2host-initiator/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/host2host-initiator/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/host2host-initiator/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/host2host-responder-multi-ke/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/host2host-responder-multi-ke/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/host2host-responder-multi-ke/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/host2host-responder-multi-ke/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/host2host-responder/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/host2host-responder/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/host2host-responder/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/host2host-responder/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/host2host-xfrmproxy/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/host2host-xfrmproxy/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/host2host-xfrmproxy/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/host2host-xfrmproxy/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/multi-level-ca/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/multi-level-ca/hosts/moon/etc/strongswan.conf.in
index 9051db9690..38e10b7558 100644
--- a/testing/tests/tkm/multi-level-ca/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/multi-level-ca/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/multiple-clients/hosts/sun/etc/strongswan.conf.in b/testing/tests/tkm/multiple-clients/hosts/sun/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/multiple-clients/hosts/sun/etc/strongswan.conf.in
+++ b/testing/tests/tkm/multiple-clients/hosts/sun/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/net2net-initiator/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/net2net-initiator/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/net2net-initiator/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/net2net-initiator/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/net2net-xfrmproxy/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/net2net-xfrmproxy/hosts/moon/etc/strongswan.conf.in
index 0554bc34d3..dc3832679d 100644
--- a/testing/tests/tkm/net2net-xfrmproxy/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/net2net-xfrmproxy/hosts/moon/etc/strongswan.conf.in
@@ -2,9 +2,15 @@

 charon-tkm {
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf.in
index 9d7b528eca..f2009f243a 100644
--- a/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/xfrmproxy-expire/hosts/moon/etc/strongswan.conf.in
@@ -4,9 +4,15 @@ charon-tkm {
   # remove rekeyed inbound SA a bit quicker for the test scenario
   delete_rekeyed_delay = 2
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512
diff --git a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf.in b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf.in
index 9d7b528eca..f2009f243a 100644
--- a/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf.in
+++ b/testing/tests/tkm/xfrmproxy-rekey/hosts/moon/etc/strongswan.conf.in
@@ -4,9 +4,15 @@ charon-tkm {
   # remove rekeyed inbound SA a bit quicker for the test scenario
   delete_rekeyed_delay = 2
   ke_mapping {
+    # modp3072
     15 = 1
+    # modp4096
     16 = 2
   }
+  sig_mapping {
+    RSA_EMSA_PKCS1_SHA1 = 1
+    RSA_EMSA_PKCS1_SHA2_256 = 2
+  }
   proposal_mapping {
     ike {
       1 = aes256-sha512-prfsha512