EAP-SIM/AKA: Fix check for anonymous decorated identity

eap_sim_anonymous_username() gets called with an argument that is not a
null terminated C string and as such, os_strrchr() and os_strlen()
cannot be used with it. The previous implementation resulted in use of
uninitialized values and a potential read beyond the end of the buffer.

Credit to OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=32277
Fixes: 73d9891bd722 ("EAP-SIM/AKA peer: Support decorated anonymous identity prefix")
Signed-off-by: Jouni Malinen <j@w1.fi>

Bug: 182510351
Test: compiles, unit test
Change-Id: I41364c8c550f1c6ab853c3d74cfda1c5f628feb0
diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c
index 58861cd..ea38e6a 100644
--- a/src/eap_common/eap_sim_common.c
+++ b/src/eap_common/eap_sim_common.c
@@ -1209,10 +1209,23 @@
 	}
 }
 
+static const u8 * get_last_char(const u8 *val, size_t len, char c)
+{
+	while (len > 0) {
+		const u8 *pos = &val[len - 1];
+
+		if (*pos == (u8) c)
+			return pos;
+		len--;
+	}
+
+	return NULL;
+}
+
 int eap_sim_anonymous_username(const u8 *id, size_t id_len)
 {
 	static const char *anonymous_id_prefix = "anonymous@";
-	const char *decorated;
+	const u8 *decorated;
 	size_t anonymous_id_len = os_strlen(anonymous_id_prefix);
 
 	if (id_len > anonymous_id_len &&
@@ -1226,12 +1239,14 @@
 	if (id_len > 1 && id[0] == '@')
 		return 1; /* '@realm' */
 
-	/* RFC 7542 decorated username, for example;
-	   homerealm.example.org!anonymous@otherrealm.example.net */
-	decorated = os_strrchr((const char *)id, '!');
-	if (decorated && os_strlen(decorated + 1) > 1) {
-		return eap_sim_anonymous_username((const u8 *)(decorated + 1),
-				os_strlen(decorated + 1));
+	/* RFC 7542 decorated username, for example:
+	 * homerealm.example.org!anonymous@otherrealm.example.net */
+	decorated = get_last_char(id, id_len, '!');
+	if (decorated) {
+		decorated++;
+		return eap_sim_anonymous_username(decorated,
+						  id + id_len - decorated);
 	}
 	return 0;
 }
+