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 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;
}