CVE-2022-4967: Insufficient Information (NVD-CWE-noinfo)
value: strongSwan versions 5.9.2 through 5.9.5 are affected by authorization bypass through improper validation of certificate with host mismatch (CWE-297). When certificates are used to authenticate clients in TLS-based EAP methods, the IKE or EAP identity supplied by a client is not enforced to be contained in the client's certificate. So clients can authenticate with any trusted certificate and claim an arbitrary IKE/EAP identity as their own. This is problematic if the identity is used to make policy decisions. A fix was released in strongSwan version 5.9.6 in August 2022 (e4b4aabc4996fc61c37deab7858d07bc4d220136).
CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-05-14T11:57Z
Repository: https://github.com/strongswan/strongswan
Language: C
Files changed: src/libtls/tls_peer.c, src/libtls/tls_server.c
Commit date: 2022-02-15 16:53:25 +0100
Commit message: libtls: Enforce client/server identity when looking for public key

The client already enforces that the server identity is contained in the
received certificate.  But on the server, the referenced commit changed
the lookup from the configured (or adopted if %any was configured) client
identity to the subject DN of the received client certificate.  So any
client with a trusted certificate was accepted.

Fixes: d2fc9b0961c6 ("tls-server: Mutual authentication support for TLS 1.3")
Closes strongswan/strongswan#873

Diff: diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c
index f3854eba5..58a36dbd2 100644
--- a/src/libtls/tls_peer.c
+++ b/src/libtls/tls_peer.c
@@ -163,11 +163,11 @@ struct private_tls_peer_t {
 	chunk_t cert_types;
 };
 
 /* Implemented in tls_server.c */
 bool tls_write_key_share(bio_writer_t **key_share, diffie_hellman_t *dh);
-public_key_t *tls_find_public_key(auth_cfg_t *peer_auth);
+public_key_t *tls_find_public_key(auth_cfg_t *peer_auth, identification_t *id);
 
 /**
  * Verify the DH group/key type requested by the server is valid.
  */
 static bool verify_requested_key_type(private_tls_peer_t *this,
@@ -639,11 +639,11 @@ static status_t process_cert_verify(private_tls_peer_t *this,
 									bio_reader_t *reader)
 {
 	public_key_t *public;
 	chunk_t msg;
 
-	public = tls_find_public_key(this->server_auth);
+	public = tls_find_public_key(this->server_auth, this->server);
 	if (!public)
 	{
 		DBG1(DBG_TLS, "no trusted certificate found for '%Y' to verify TLS server",
 			 this->server);
 		this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
@@ -688,11 +688,11 @@ static status_t process_modp_key_exchange(private_tls_peer_t *this,
 	{
 		DBG1(DBG_TLS, "short DH prime received (%zu bytes)", prime.len);
 		this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
 		return NEED_MORE;
 	}
-	public = tls_find_public_key(this->server_auth);
+	public = tls_find_public_key(this->server_auth, this->server);
 	if (!public)
 	{
 		DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
 		this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
 		return NEED_MORE;
@@ -795,11 +795,11 @@ static status_t process_ec_key_exchange(private_tls_peer_t *this,
 			 tls_named_group_names, curve);
 		this->alert->add(this->alert, TLS_FATAL, TLS_HANDSHAKE_FAILURE);
 		return NEED_MORE;
 	}
 
-	public = tls_find_public_key(this->server_auth);
+	public = tls_find_public_key(this->server_auth, this->server);
 	if (!public)
 	{
 		DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
 		this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
 		return NEED_MORE;
@@ -1619,11 +1619,11 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this,
 	{
 		this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
 		return NEED_MORE;
 	}
 
-	public = tls_find_public_key(this->server_auth);
+	public = tls_find_public_key(this->server_auth, this->server);
 	if (!public)
 	{
 		DBG1(DBG_TLS, "no TLS public key found for server '%Y'", this->server);
 		this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);
 		return NEED_MORE;
diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c
index bbfe54249..4efe04e08 100644
--- a/src/libtls/tls_server.c
+++ b/src/libtls/tls_server.c
@@ -171,23 +171,22 @@ struct private_tls_server_t {
 };
 
 /**
  * Find a trusted public key to encrypt/verify key exchange data
  */
-public_key_t *tls_find_public_key(auth_cfg_t *peer_auth)
+public_key_t *tls_find_public_key(auth_cfg_t *peer_auth, identification_t *id)
 {
 	public_key_t *public = NULL, *current;
 	certificate_t *cert, *found;
 	enumerator_t *enumerator;
 	auth_cfg_t *auth;
 
 	cert = peer_auth->get(peer_auth, AUTH_HELPER_SUBJECT_CERT);
 	if (cert)
 	{
 		enumerator = lib->credmgr->create_public_enumerator(lib->credmgr,
-											KEY_ANY, cert->get_subject(cert),
-											peer_auth, TRUE);
+												KEY_ANY, id, peer_auth, TRUE);
 		while (enumerator->enumerate(enumerator, &current, &auth))
 		{
 			found = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
 			if (found && cert->equals(cert, found))
 			{
@@ -921,11 +920,11 @@ static status_t process_cert_verify(private_tls_server_t *this,
 									bio_reader_t *reader)
 {
 	public_key_t *public;
 	chunk_t msg;
 
-	public = tls_find_public_key(this->peer_auth);
+	public = tls_find_public_key(this->peer_auth, this->peer);
 	if (!public)
 	{
 		DBG1(DBG_TLS, "no trusted certificate found for '%Y' to verify TLS peer",
 			 this->peer);
 		this->alert->add(this->alert, TLS_FATAL, TLS_CERTIFICATE_UNKNOWN);

Vulnerable code: public_key_t *tls_find_public_key(auth_cfg_t *peer_auth);
	public = tls_find_public_key(this->server_auth);
	public = tls_find_public_key(this->server_auth);
	public = tls_find_public_key(this->server_auth);
	public = tls_find_public_key(this->server_auth);
public_key_t *tls_find_public_key(auth_cfg_t *peer_auth)
											KEY_ANY, cert->get_subject(cert),
											peer_auth, TRUE);
	public = tls_find_public_key(this->peer_auth);
Fixed code: public_key_t *tls_find_public_key(auth_cfg_t *peer_auth, identification_t *id);
	public = tls_find_public_key(this->server_auth, this->server);
	public = tls_find_public_key(this->server_auth, this->server);
	public = tls_find_public_key(this->server_auth, this->server);
	public = tls_find_public_key(this->server_auth, this->server);
public_key_t *tls_find_public_key(auth_cfg_t *peer_auth, identification_t *id)
												KEY_ANY, id, peer_auth, TRUE);
	public = tls_find_public_key(this->peer_auth, this->peer);