Browse Source

hlr_auc_gw: Allow Milenage RES length to be reduced

Some USIM use shorter RES length than the 64-bit default from Milenage.
Such cases did not interoperate with the hlr_auc_gw implementation. Make
it possible to configure the RES length 4..8 octets, i.e., 32 to 64
bits) to support such USIM.

Signed-off-by: Jouni Malinen <j@w1.fi>
Jouni Malinen 10 years ago
parent
commit
6812782462
2 changed files with 30 additions and 6 deletions
  1. 27 5
      hostapd/hlr_auc_gw.c
  2. 3 1
      hostapd/hlr_auc_gw.milenage_db

+ 27 - 5
hostapd/hlr_auc_gw.c

@@ -87,6 +87,7 @@ struct milenage_parameters {
 	u8 amf[2];
 	u8 amf[2];
 	u8 sqn[6];
 	u8 sqn[6];
 	int set;
 	int set;
+	size_t res_len;
 };
 };
 
 
 static struct milenage_parameters *milenage_db = NULL;
 static struct milenage_parameters *milenage_db = NULL;
@@ -96,6 +97,7 @@ static struct milenage_parameters *milenage_db = NULL;
 #define EAP_AKA_RAND_LEN 16
 #define EAP_AKA_RAND_LEN 16
 #define EAP_AKA_AUTN_LEN 16
 #define EAP_AKA_AUTN_LEN 16
 #define EAP_AKA_AUTS_LEN 14
 #define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MIN_LEN 4
 #define EAP_AKA_RES_MAX_LEN 16
 #define EAP_AKA_RES_MAX_LEN 16
 #define EAP_AKA_IK_LEN 16
 #define EAP_AKA_IK_LEN 16
 #define EAP_AKA_CK_LEN 16
 #define EAP_AKA_CK_LEN 16
@@ -124,7 +126,8 @@ static int db_table_create_milenage(sqlite3 *db)
 		"  ki CHAR(32) NOT NULL,"
 		"  ki CHAR(32) NOT NULL,"
 		"  opc CHAR(32) NOT NULL,"
 		"  opc CHAR(32) NOT NULL,"
 		"  amf CHAR(4) NOT NULL,"
 		"  amf CHAR(4) NOT NULL,"
-		"  sqn CHAR(12) NOT NULL"
+		"  sqn CHAR(12) NOT NULL,"
+		"  res_len INTEGER"
 		");";
 		");";
 
 
 	printf("Adding database table for milenage information\n");
 	printf("Adding database table for milenage information\n");
@@ -190,6 +193,10 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
 			printf("Invalid sqn value in database\n");
 			printf("Invalid sqn value in database\n");
 			return -1;
 			return -1;
 		}
 		}
+
+		if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
+			m->res_len = atoi(argv[i]);
+		}
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -206,8 +213,7 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
 	os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
 	os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
 		    "%llu", imsi);
 		    "%llu", imsi);
 	os_snprintf(cmd, sizeof(cmd),
 	os_snprintf(cmd, sizeof(cmd),
-		    "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
-		    imsi);
+		    "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
 	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
 	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
 			 NULL) != SQLITE_OK)
 			 NULL) != SQLITE_OK)
 		return NULL;
 		return NULL;
@@ -424,7 +430,7 @@ static int read_milenage(const char *fname)
 	while (fgets(buf, sizeof(buf), f)) {
 	while (fgets(buf, sizeof(buf), f)) {
 		line++;
 		line++;
 
 
-		/* Parse IMSI Ki OPc AMF SQN */
+		/* Parse IMSI Ki OPc AMF SQN [RES_len] */
 		buf[sizeof(buf) - 1] = '\0';
 		buf[sizeof(buf) - 1] = '\0';
 		if (buf[0] == '#')
 		if (buf[0] == '#')
 			continue;
 			continue;
@@ -515,7 +521,19 @@ static int read_milenage(const char *fname)
 			ret = -1;
 			ret = -1;
 			break;
 			break;
 		}
 		}
-		pos = pos2 + 1;
+
+		if (pos2) {
+			pos = pos2 + 1;
+			m->res_len = atoi(pos);
+			if (m->res_len &&
+			    (m->res_len < EAP_AKA_RES_MIN_LEN ||
+			     m->res_len > EAP_AKA_RES_MAX_LEN)) {
+				printf("%s:%d - Invalid RES_len (%s)\n",
+				       fname, line, pos);
+				ret = -1;
+				break;
+			}
+		}
 
 
 		m->next = milenage_db;
 		m->next = milenage_db;
 		milenage_db = m;
 		milenage_db = m;
@@ -798,6 +816,10 @@ static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
 		}
 		}
 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
 				  autn, ik, ck, res, &res_len);
 				  autn, ik, ck, res, &res_len);
+		if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
+		    m->res_len <= EAP_AKA_RES_MAX_LEN &&
+		    m->res_len < res_len)
+			res_len = m->res_len;
 	} else {
 	} else {
 		printf("Unknown IMSI: %s\n", imsi);
 		printf("Unknown IMSI: %s\n", imsi);
 #ifdef AKA_USE_FIXED_TEST_VALUES
 #ifdef AKA_USE_FIXED_TEST_VALUES

+ 3 - 1
hostapd/hlr_auc_gw.milenage_db

@@ -5,8 +5,10 @@
 # authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
 # authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
 # dummy values will need to be included in this file.
 # dummy values will need to be included in this file.
 
 
-# IMSI Ki OPc AMF SQN
+# IMSI Ki OPc AMF SQN [RES_len]
 232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
 232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+# Example using truncated 32-bit RES instead of 64-bit default
+232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
 
 
 # These values are from Test Set 19 which has the AMF separation bit set to 1
 # These values are from Test Set 19 which has the AMF separation bit set to 1
 # and as such, is suitable for EAP-AKA' test.
 # and as such, is suitable for EAP-AKA' test.