nat: After we identified the bsc check the key

We are using the token to find the right bsc_config and
then we can use the last_rand of the bsc_connection to
calculate the expected result and try to compare it with
a time constant(???) memcmp.
This commit is contained in:
Holger Hans Peter Freyther 2015-06-08 18:33:28 +02:00
parent e2ac6b77fe
commit 694d98042f
3 changed files with 91 additions and 4 deletions

View File

@ -148,6 +148,8 @@ enum bsc_cfg_ctr {
struct bsc_config {
struct llist_head entry;
uint8_t key[16];
uint8_t key_present;
char *token;
int nr;

View File

@ -51,6 +51,8 @@
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/core/application.h>
#include <osmocom/core/talloc.h>
@ -993,11 +995,57 @@ static void ipaccess_close_bsc(void *data)
bsc_close_connection(conn);
}
/* Wishful thinking to generate a constant time compare */
static int constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count)
{
int x = 0, i;
for (i = 0; i < count; ++i)
x |= exp[i] ^ rel[i];
return x != 0;
}
static int verify_key(struct bsc_connection *conn, struct bsc_config *conf, const uint8_t *key, const int keylen)
{
struct osmo_auth_vector vec;
struct osmo_sub_auth_data auth = {
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_MILENAGE,
};
/* expect a specific keylen */
if (keylen != 8) {
LOGP(DNAT, LOGL_ERROR, "Key length is wrong: %d for bsc nr %d\n",
keylen, conf->nr);
return 0;
}
memcpy(auth.u.umts.opc, conf->key, 16);
memcpy(auth.u.umts.k, conf->key, 16);
memset(auth.u.umts.amf, 0, 2);
auth.u.umts.sqn = 0;
memset(&vec, 0, sizeof(vec));
osmo_auth_gen_vec(&vec, &auth, conn->last_rand);
if (vec.res_len != 8) {
LOGP(DNAT, LOGL_ERROR, "Res length is wrong: %d for bsc nr %d\n",
keylen, conf->nr);
return 0;
}
return constant_time_cmp(vec.res, key, 8) == 0;
}
static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
{
struct bsc_config *conf;
const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME);
const uint8_t *xres = TLVP_VAL(tvp, 0x24);
const int xlen = TLVP_LEN(tvp, 0x24);
if (bsc->cfg) {
LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
@ -1033,6 +1081,15 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
return;
}
/* We have set a key and expect it to be present */
if (conf->key_present && !verify_key(bsc, conf, xres, xlen - 1)) {
LOGP(DNAT, LOGL_ERROR,
"Wrong key for bsc nr %d fd: %d.\n", conf->nr,
bsc->write_queue.bfd.fd);
bsc_close_connection(bsc);
return;
}
rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]);
bsc->authenticated = 1;
bsc->cfg = conf;
@ -1227,9 +1284,9 @@ exit:
if (msg->l2h[0] == IPAC_MSGT_ID_RESP && msgb_l2len(msg) > 2) {
struct tlv_parsed tvp;
int ret;
ret = ipa_ccm_idtag_parse(&tvp,
ret = ipa_ccm_idtag_parse_off(&tvp,
(unsigned char *) msg->l2h + 2,
msgb_l2len(msg) - 2);
msgb_l2len(msg) - 2, 0);
if (ret < 0) {
LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
"message with malformed TLVs\n");

View File

@ -1,6 +1,6 @@
/* OpenBSC NAT interface to quagga VTY */
/* (C) 2010-2013 by Holger Hans Peter Freyther
* (C) 2010-2013 by On-Waves
/* (C) 2010-2015 by Holger Hans Peter Freyther
* (C) 2010-2015 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@ -151,6 +151,8 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
{
vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE);
if (bsc->key_present)
vty_out(vty, " auth-key %s%s", osmo_hexdump(bsc->key, 16), VTY_NEWLINE);
dump_lac(vty, &bsc->lac_list);
if (bsc->description)
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
@ -814,6 +816,30 @@ DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN",
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_auth_key, cfg_bsc_auth_key_cmd,
"auth-key KEY",
"Authentication (secret) key configuration\n"
"Non null security key\n")
{
struct bsc_config *conf = vty->index;
memset(conf->key, 0, sizeof(conf->key));
osmo_hexparse(argv[0], conf->key, sizeof(conf->key));
conf->key_present = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_no_auth_key, cfg_bsc_no_auth_key_cmd,
"no auth-key",
NO_STR "Authentication (secret) key configuration\n")
{
struct bsc_config *conf = vty->index;
memset(conf->key, 0, sizeof(conf->key));
conf->key_present = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
"Add the Location Area Code (LAC) of this BSC\n" "LAC\n")
{
@ -1202,6 +1228,8 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_node(&bsc_node, config_write_bsc);
vty_install_default(NAT_BSC_NODE);
install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_no_auth_key_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_lac_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd);
install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd);