|
@@ -62,6 +62,7 @@ static char *milenage_file = NULL;
|
|
|
static int update_milenage = 0;
|
|
|
static int sqn_changes = 0;
|
|
|
static int ind_len = 5;
|
|
|
+static int stdout_debug = 1;
|
|
|
|
|
|
/* GSM triplets */
|
|
|
struct gsm_triplet {
|
|
@@ -218,6 +219,9 @@ static int db_update_milenage_sqn(struct milenage_parameters *m)
|
|
|
{
|
|
|
char cmd[128], val[13], *pos;
|
|
|
|
|
|
+ if (sqlite_db == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
pos = val;
|
|
|
pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
|
|
|
*pos = '\0';
|
|
@@ -615,16 +619,15 @@ static struct milenage_parameters * get_milenage(const char *imsi)
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
- char *imsi)
|
|
|
+static int sim_req_auth(char *imsi, char *resp, size_t resp_len)
|
|
|
{
|
|
|
int count, max_chal, ret;
|
|
|
char *pos;
|
|
|
- char reply[1000], *rpos, *rend;
|
|
|
+ char *rpos, *rend;
|
|
|
struct milenage_parameters *m;
|
|
|
struct gsm_triplet *g;
|
|
|
|
|
|
- reply[0] = '\0';
|
|
|
+ resp[0] = '\0';
|
|
|
|
|
|
pos = strchr(imsi, ' ');
|
|
|
if (pos) {
|
|
@@ -635,11 +638,11 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
} else
|
|
|
max_chal = EAP_SIM_MAX_CHAL;
|
|
|
|
|
|
- rend = &reply[sizeof(reply)];
|
|
|
- rpos = reply;
|
|
|
+ rend = resp + resp_len;
|
|
|
+ rpos = resp;
|
|
|
ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
|
|
|
if (ret < 0 || ret >= rend - rpos)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
rpos += ret;
|
|
|
|
|
|
m = get_milenage(imsi);
|
|
@@ -647,7 +650,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
u8 _rand[16], sres[4], kc[8];
|
|
|
for (count = 0; count < max_chal; count++) {
|
|
|
if (random_get_bytes(_rand, 16) < 0)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
gsm_milenage(m->opc, m->ki, _rand, sres, kc);
|
|
|
*rpos++ = ' ';
|
|
|
rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
|
|
@@ -657,7 +660,7 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
|
|
|
}
|
|
|
*rpos = '\0';
|
|
|
- goto send;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
count = 0;
|
|
@@ -681,15 +684,11 @@ static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
printf("No GSM triplets found for %s\n", imsi);
|
|
|
ret = snprintf(rpos, rend - rpos, " FAILURE");
|
|
|
if (ret < 0 || ret >= rend - rpos)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
rpos += ret;
|
|
|
}
|
|
|
|
|
|
-send:
|
|
|
- printf("Send: %s\n", reply);
|
|
|
- if (sendto(s, reply, rpos - reply, 0,
|
|
|
- (struct sockaddr *) from, fromlen) < 0)
|
|
|
- perror("send");
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -715,11 +714,10 @@ static void inc_sqn(u8 *sqn)
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
- char *imsi)
|
|
|
+static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
|
|
|
{
|
|
|
/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
|
|
|
- char reply[1000], *pos, *end;
|
|
|
+ char *pos, *end;
|
|
|
u8 _rand[EAP_AKA_RAND_LEN];
|
|
|
u8 autn[EAP_AKA_AUTN_LEN];
|
|
|
u8 ik[EAP_AKA_IK_LEN];
|
|
@@ -733,16 +731,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
m = get_milenage(imsi);
|
|
|
if (m) {
|
|
|
if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
res_len = EAP_AKA_RES_MAX_LEN;
|
|
|
inc_sqn(m->sqn);
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
db_update_milenage_sqn(m);
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
sqn_changes = 1;
|
|
|
- printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
|
|
|
- m->sqn[0], m->sqn[1], m->sqn[2],
|
|
|
- m->sqn[3], m->sqn[4], m->sqn[5]);
|
|
|
+ if (stdout_debug) {
|
|
|
+ printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
|
|
|
+ m->sqn[0], m->sqn[1], m->sqn[2],
|
|
|
+ m->sqn[3], m->sqn[4], m->sqn[5]);
|
|
|
+ }
|
|
|
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
|
|
|
autn, ik, ck, res, &res_len);
|
|
|
} else {
|
|
@@ -760,18 +760,18 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
#endif /* AKA_USE_FIXED_TEST_VALUES */
|
|
|
}
|
|
|
|
|
|
- pos = reply;
|
|
|
- end = &reply[sizeof(reply)];
|
|
|
+ pos = resp;
|
|
|
+ end = resp + resp_len;
|
|
|
ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
|
|
|
if (ret < 0 || ret >= end - pos)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
pos += ret;
|
|
|
if (failed) {
|
|
|
ret = snprintf(pos, end - pos, "FAILURE");
|
|
|
if (ret < 0 || ret >= end - pos)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
pos += ret;
|
|
|
- goto done;
|
|
|
+ return 0;
|
|
|
}
|
|
|
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
|
|
|
*pos++ = ' ';
|
|
@@ -783,65 +783,84 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
*pos++ = ' ';
|
|
|
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
|
|
|
|
|
|
-done:
|
|
|
- printf("Send: %s\n", reply);
|
|
|
-
|
|
|
- if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
|
|
|
- fromlen) < 0)
|
|
|
- perror("send");
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
-static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
|
|
|
- char *imsi)
|
|
|
+static int aka_auts(char *imsi, char *resp, size_t resp_len)
|
|
|
{
|
|
|
char *auts, *__rand;
|
|
|
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
|
|
|
struct milenage_parameters *m;
|
|
|
|
|
|
+ resp[0] = '\0';
|
|
|
+
|
|
|
/* AKA-AUTS <IMSI> <AUTS> <RAND> */
|
|
|
|
|
|
auts = strchr(imsi, ' ');
|
|
|
if (auts == NULL)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
*auts++ = '\0';
|
|
|
|
|
|
__rand = strchr(auts, ' ');
|
|
|
if (__rand == NULL)
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
*__rand++ = '\0';
|
|
|
|
|
|
- printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
|
|
|
+ if (stdout_debug) {
|
|
|
+ printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
|
|
|
+ imsi, auts, __rand);
|
|
|
+ }
|
|
|
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
|
|
|
hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
|
|
|
printf("Could not parse AUTS/RAND\n");
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
m = get_milenage(imsi);
|
|
|
if (m == NULL) {
|
|
|
printf("Unknown IMSI: %s\n", imsi);
|
|
|
- return;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
|
|
|
printf("AKA-AUTS: Incorrect MAC-S\n");
|
|
|
} else {
|
|
|
memcpy(m->sqn, sqn, 6);
|
|
|
- printf("AKA-AUTS: Re-synchronized: "
|
|
|
- "SQN=%02x%02x%02x%02x%02x%02x\n",
|
|
|
- sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
|
|
|
+ if (stdout_debug) {
|
|
|
+ printf("AKA-AUTS: Re-synchronized: "
|
|
|
+ "SQN=%02x%02x%02x%02x%02x%02x\n",
|
|
|
+ sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
|
|
|
+ }
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
db_update_milenage_sqn(m);
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
sqn_changes = 1;
|
|
|
}
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int process_cmd(char *cmd, char *resp, size_t resp_len)
|
|
|
+{
|
|
|
+ if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
|
|
|
+ return sim_req_auth(cmd + 13, resp, resp_len);
|
|
|
+
|
|
|
+ if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
|
|
|
+ return aka_req_auth(cmd + 13, resp, resp_len);
|
|
|
+
|
|
|
+ if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
|
|
|
+ return aka_auts(cmd + 9, resp, resp_len);
|
|
|
+
|
|
|
+ printf("Unknown request: %s\n", cmd);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
|
|
|
static int process(int s)
|
|
|
{
|
|
|
- char buf[1000];
|
|
|
+ char buf[1000], resp[1000];
|
|
|
struct sockaddr_un from;
|
|
|
socklen_t fromlen;
|
|
|
ssize_t res;
|
|
@@ -863,14 +882,21 @@ static int process(int s)
|
|
|
|
|
|
printf("Received: %s\n", buf);
|
|
|
|
|
|
- if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
|
|
|
- sim_req_auth(s, &from, fromlen, buf + 13);
|
|
|
- else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
|
|
|
- aka_req_auth(s, &from, fromlen, buf + 13);
|
|
|
- else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
|
|
|
- aka_auts(s, &from, fromlen, buf + 9);
|
|
|
- else
|
|
|
- printf("Unknown request: %s\n", buf);
|
|
|
+ if (process_cmd(buf, resp, sizeof(resp)) < 0) {
|
|
|
+ printf("Failed to process request\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (resp[0] == '\0') {
|
|
|
+ printf("No response\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ printf("Send: %s\n", resp);
|
|
|
+
|
|
|
+ if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
|
|
|
+ fromlen) < 0)
|
|
|
+ perror("send");
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -898,8 +924,10 @@ static void cleanup(void)
|
|
|
os_free(prev);
|
|
|
}
|
|
|
|
|
|
- close(serv_sock);
|
|
|
- unlink(socket_path);
|
|
|
+ if (serv_sock >= 0)
|
|
|
+ close(serv_sock);
|
|
|
+ if (socket_path)
|
|
|
+ unlink(socket_path);
|
|
|
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
if (sqlite_db) {
|
|
@@ -926,7 +954,7 @@ static void usage(void)
|
|
|
"usage:\n"
|
|
|
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
|
|
|
"[-m<milenage file>] \\\n"
|
|
|
- " [-D<DB file>] [-i<IND len in bits>]\n"
|
|
|
+ " [-D<DB file>] [-i<IND len in bits>] [command]\n"
|
|
|
"\n"
|
|
|
"options:\n"
|
|
|
" -h = show this usage help\n"
|
|
@@ -936,7 +964,15 @@ static void usage(void)
|
|
|
" -g<triplet file> = path for GSM authentication triplets\n"
|
|
|
" -m<milenage file> = path for Milenage keys\n"
|
|
|
" -D<DB file> = path to SQLite database\n"
|
|
|
- " -i<IND len in bits> = IND length for SQN (default: 5)\n",
|
|
|
+ " -i<IND len in bits> = IND length for SQN (default: 5)\n"
|
|
|
+ "\n"
|
|
|
+ "If the optional command argument, like "
|
|
|
+ "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
|
|
|
+ "command is processed with response sent to stdout. Otherwise, "
|
|
|
+ "hlr_auc_gw opens\n"
|
|
|
+ "a control interface and processes commands sent through it "
|
|
|
+ "(e.g., by EAP server\n"
|
|
|
+ "in hostapd).\n",
|
|
|
default_socket_path);
|
|
|
}
|
|
|
|
|
@@ -946,6 +982,7 @@ int main(int argc, char *argv[])
|
|
|
int c;
|
|
|
char *gsm_triplet_file = NULL;
|
|
|
char *sqlite_db_file = NULL;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
if (os_program_init())
|
|
|
return -1;
|
|
@@ -1009,18 +1046,31 @@ int main(int argc, char *argv[])
|
|
|
if (milenage_file && read_milenage(milenage_file) < 0)
|
|
|
return -1;
|
|
|
|
|
|
- serv_sock = open_socket(socket_path);
|
|
|
- if (serv_sock < 0)
|
|
|
- return -1;
|
|
|
+ if (optind == argc) {
|
|
|
+ serv_sock = open_socket(socket_path);
|
|
|
+ if (serv_sock < 0)
|
|
|
+ return -1;
|
|
|
|
|
|
- printf("Listening for requests on %s\n", socket_path);
|
|
|
+ printf("Listening for requests on %s\n", socket_path);
|
|
|
|
|
|
- atexit(cleanup);
|
|
|
- signal(SIGTERM, handle_term);
|
|
|
- signal(SIGINT, handle_term);
|
|
|
+ atexit(cleanup);
|
|
|
+ signal(SIGTERM, handle_term);
|
|
|
+ signal(SIGINT, handle_term);
|
|
|
|
|
|
- for (;;)
|
|
|
- process(serv_sock);
|
|
|
+ for (;;)
|
|
|
+ process(serv_sock);
|
|
|
+ } else {
|
|
|
+ char buf[1000];
|
|
|
+ socket_path = NULL;
|
|
|
+ stdout_debug = 0;
|
|
|
+ if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
|
|
|
+ printf("FAIL\n");
|
|
|
+ ret = -1;
|
|
|
+ } else {
|
|
|
+ printf("%s\n", buf);
|
|
|
+ }
|
|
|
+ cleanup();
|
|
|
+ }
|
|
|
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
if (sqlite_db) {
|
|
@@ -1031,5 +1081,5 @@ int main(int argc, char *argv[])
|
|
|
|
|
|
os_program_deinit();
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|