Commit f9cd483cd9 for strongswan.org

commit f9cd483cd97182def563e17b86e4fbd3a90c03d2
Author: raghu netrakar <raghu@security.bugqore.com>
Date:   Thu Oct 15 21:06:45 2026 +0530

    simaka: Reject AT_MAC, AT_IV and AT_ENCR_DATA inside encrypted attributes

    parse_attributes() rejects attributes that must be encrypted when they
    appear in the clear, but there was no symmetric check for attributes that
    must never be encrypted.  AT_MAC, AT_IV and AT_ENCR_DATA are stored by
    reference (this->mac/iv/encr point into the buffer being parsed).  When
    one of them is placed inside AT_ENCR_DATA, decrypt() parses it out of the
    temporary plaintext buffer and then frees that buffer, leaving the pointer
    dangling.  For AT_MAC this is then used in verify(), which reads 16 bytes
    from the freed buffer and zeroes it, a heap use-after-free.

    Add is_unencrypted_attribute() as the counterpart to
    is_encrypted_attribute() and reject these attributes when encountered
    inside encrypted data.  In addition to the attributes mentioned,
    AT_RESULT_IND is also rejected because the RFCs explicitly state that
    it MUST NOT be sent encrypted.

    Closes strongswan/strongswan#3179

    Fixes: f81760dcd1ba ("A SIM/AKA message can be parsed twice, without and with decryption")

diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c
index 97f0954f7a..fb38104705 100644
--- a/src/libsimaka/simaka_message.c
+++ b/src/libsimaka/simaka_message.c
@@ -280,6 +280,23 @@ static bool is_encrypted_attribute(simaka_attribute_t type)
 	}
 }

+/**
+ * Determine if an attribute is never sent encrypted
+ */
+static bool is_unencrypted_attribute(simaka_attribute_t type)
+{
+	switch (type)
+	{
+		case AT_MAC:
+		case AT_IV:
+		case AT_ENCR_DATA:
+		case AT_RESULT_IND:
+			return TRUE;
+		default:
+			return FALSE;
+	}
+}
+
 /**
  * Error handling for invalid length
  */
@@ -329,7 +346,16 @@ static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
 		}
 		hdr = (attr_hdr_t*)in.ptr;

-		if (is_encrypted_attribute(hdr->type) && !this->encrypted)
+		if (this->encrypted)
+		{
+			if (is_unencrypted_attribute(hdr->type))
+			{
+				DBG1(DBG_LIB, "received encrypted %N", simaka_attribute_names,
+					 hdr->type);
+				return FALSE;
+			}
+		}
+		else if (is_encrypted_attribute(hdr->type))
 		{
 			DBG1(DBG_LIB, "received unencrypted %N", simaka_attribute_names,
 				 hdr->type);