From 694d98042f1adfad0e54f97d0e4c8787c5fccbac Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 18:33:28 +0200 Subject: 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. --- openbsc/include/openbsc/bsc_nat.h | 2 ++ openbsc/src/osmo-bsc_nat/bsc_nat.c | 61 ++++++++++++++++++++++++++++++++-- openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 32 ++++++++++++++++-- 3 files changed, 91 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index c313e5244..72773a981 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -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; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 983770925..581193e5a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -51,6 +51,8 @@ #include #include +#include + #include #include @@ -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"); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 821e5226a..981168cc1 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -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); -- cgit v1.2.3