hlr_auc_gw: Add support for processing command line operations

This allows hlr_auc_gw to be used to run a single operation without
having to use it as a server. This can be useful, e.g., for generating
GSM authentication triplets for external programs. For example:
./hlr_auc_gw -m hlr_auc_gw.milenage_db "SIM-REQ-AUTH 232010000000000"

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2013-09-29 18:42:37 +03:00
parent 2b5b875f34
commit 3e6547b5e8

View file

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