From 2dd18bdd87a130a3536b12af874e331d93593e9b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 18:31:02 +0200 Subject: nat: Add size check for the payload The msgb will always have these bytes but it is better practice to verify that the message really has space for the two bytes. --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc/src') diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 4357485ff..537001ed5 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -1185,7 +1185,7 @@ exit: send_reset_ack(bsc); } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) { /* do we know who is handling this? */ - if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { + if (msg->l2h[0] == IPAC_MSGT_ID_RESP && msgb_l2len(msg) > 2) { struct tlv_parsed tvp; int ret; ret = ipa_ccm_idtag_parse(&tvp, -- cgit v1.2.3 From aa0cecd9b7986254983af6b6cbef291183709ca0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 09:54:45 +0200 Subject: nat: Factor out the config by token search In the upcoming authentication improvements it is nice to separate the finding of the config from the post-allow handling of it. --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 32 +++++++++++++------------------- openbsc/src/osmo-bsc_nat/bsc_nat_utils.c | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 19 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 537001ed5..2f186b2c6 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -980,27 +980,21 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc return; } - llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) { - /* - * Add the '\0' of the token for the memcmp, the IPA messages - * for some reason added null termination. - */ - const int token_len = strlen(conf->token) + 1; - - if (token_len == len && memcmp(conf->token, token, token_len) == 0) { - rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]); - bsc->authenticated = 1; - bsc->cfg = conf; - osmo_timer_del(&bsc->id_timeout); - LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n", - conf->nr, bsc->write_queue.bfd.fd); - start_ping_pong(bsc); - return; - } + conf = bsc_config_by_token(bsc->nat, token, len); + if (!conf) { + LOGP(DNAT, LOGL_ERROR, + "No bsc found for token '%s' on fd: %d.\n", token, + bsc->write_queue.bfd.fd); + return; } - LOGP(DNAT, LOGL_ERROR, "No bsc found for token '%s' on fd: %d.\n", token, - bsc->write_queue.bfd.fd); + rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]); + bsc->authenticated = 1; + bsc->cfg = conf; + osmo_timer_del(&bsc->id_timeout); + LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n", + conf->nr, bsc->write_queue.bfd.fd); + start_ping_pong(bsc); } static void handle_con_stats(struct nat_sccp_connection *con) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index d95227dca..d7ec545fa 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -180,6 +180,24 @@ struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token) return conf; } +struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len) +{ + struct bsc_config *conf; + + llist_for_each_entry(conf, &nat->bsc_configs, entry) { + /* + * Add the '\0' of the token for the memcmp, the IPA messages + * for some reason added null termination. + */ + const int token_len = strlen(conf->token) + 1; + + if (token_len == len && memcmp(conf->token, token, token_len) == 0) + return conf; + } + + return NULL; +} + void bsc_config_free(struct bsc_config *cfg) { llist_del(&cfg->entry); -- cgit v1.2.3 From 0363d1bb97663e83aa0dc3a1e6b425b1870dd271 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 11:55:02 +0200 Subject: nat: Close the connection after we couldn't find the user In case the token was not correct, just close the connection. It is not clear that forcing a new TCP connection is going to give us any extra security here. But with the upcoming auth handling it does make sense to have both case look similar. --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc/src') diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 2f186b2c6..921665433 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -985,6 +985,7 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc LOGP(DNAT, LOGL_ERROR, "No bsc found for token '%s' on fd: %d.\n", token, bsc->write_queue.bfd.fd); + bsc_close_connection(bsc); return; } -- cgit v1.2.3 From 8a8df80772a4bac0f3cb4d384f45a5d4c463fe11 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 10 Jun 2015 11:51:16 +0200 Subject: bsc/nat: Fix the structure of the identity request message Unfortunately the basic structure of the response is broken. There is a two byte length followed by data. The concept of a 'tag' happens to be the first byte of the data. This means we want to write strlen of the token, then we want to write the NUL and then we need to account for the tag in front. Introduce a flag if the new or old format should be used. This will allow to have new BSCs talk to old NATs without an additional change. In the long run we can clean that up. --- openbsc/src/libbsc/bsc_msc.c | 17 +++++++++++++++-- openbsc/src/osmo-bsc/osmo_bsc_msc.c | 2 +- openbsc/src/osmo-bsc_nat/bsc_nat.c | 15 +++++++++++---- 3 files changed, 27 insertions(+), 7 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libbsc/bsc_msc.c b/openbsc/src/libbsc/bsc_msc.c index a24efabb0..fc4530ce7 100644 --- a/openbsc/src/libbsc/bsc_msc.c +++ b/openbsc/src/libbsc/bsc_msc.c @@ -276,7 +276,7 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *con) osmo_timer_schedule(&con->reconnect_timer, 5, 0); } -struct msgb *bsc_msc_id_get_resp(const char *token) +struct msgb *bsc_msc_id_get_resp(int fixed, const char *token) { struct msgb *msg; @@ -291,8 +291,21 @@ struct msgb *bsc_msc_id_get_resp(const char *token) return NULL; } + /* + * The situation is bizarre. The encoding doesn't follow the + * TLV structure. It is more like a LV and old versions had + * it wrong but we want new versions to old servers so we + * introduce the quirk here. + */ msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP); - msgb_l16tv_put(msg, strlen(token) + 1, + if (fixed) { + msgb_put_u8(msg, 0); + msgb_put_u8(msg, strlen(token) + 2); + msgb_tv_fixed_put(msg, IPAC_IDTAG_UNITNAME, strlen(token) + 1, (uint8_t *) token); + } else { + msgb_l16tv_put(msg, strlen(token) + 1, IPAC_IDTAG_UNITNAME, (uint8_t *) token); + } + return msg; } diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c index 129b23e13..5127ca849 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c @@ -456,7 +456,7 @@ static void send_id_get_response(struct osmo_msc_data *data, int fd) struct msc_signal_data sig; struct msgb *msg; - msg = bsc_msc_id_get_resp(data->bsc_token); + msg = bsc_msc_id_get_resp(0, data->bsc_token); if (!msg) return; msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 921665433..841262c5a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -357,7 +357,7 @@ static void initialize_msc_if_needed(struct bsc_msc_connection *msc_con) static void send_id_get_response(struct bsc_msc_connection *msc_con) { - struct msgb *msg = bsc_msc_id_get_resp(nat->token); + struct msgb *msg = bsc_msc_id_get_resp(0, nat->token); if (!msg) return; @@ -960,7 +960,7 @@ 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); - const int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); + int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); if (bsc->cfg) { LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n", @@ -980,11 +980,18 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc return; } + /* + * New systems have fixed the structure of the message but + * we need to support old ones too. + */ + if (len >= 2 && token[len - 2] == '\0') + len -= 1; + conf = bsc_config_by_token(bsc->nat, token, len); if (!conf) { LOGP(DNAT, LOGL_ERROR, - "No bsc found for token '%s' on fd: %d.\n", token, - bsc->write_queue.bfd.fd); + "No bsc found for token '%s' len %d on fd: %d.\n", token, + bsc->write_queue.bfd.fd, len); bsc_close_connection(bsc); return; } -- cgit v1.2.3 From fce6971fe3673e8269414188fda0ce3b28b5cf03 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 11:56:59 +0200 Subject: nat: Provide access to /dev/urandom for the code Instead of doing open/read/close all the time, open the FD in the beginning and keep it open. To scare me even more I have seen /dev/urandom actually providing a short read and then blocking but it seems to be the best way to get the random byes we need for authentication. So one should/could run the cheap random generator on the system (e.g. haveged) or deal with the NAT process to block. --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'openbsc/src') diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 841262c5a..82562ba17 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -21,6 +21,8 @@ * */ #include +#include +#include #include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include #define _GNU_SOURCE #include @@ -1534,6 +1537,12 @@ int main(int argc, char **argv) /* We need to add mode-set for amr codecs */ nat->sdp_ensure_amr_mode_set = 1; + nat->random_fd = open("/dev/random", O_RDONLY); + if (nat->random_fd < 0) { + fprintf(stderr, "Failed to open /dev/urandom.\n"); + return -5; + } + vty_info.copyright = openbsc_copyright; vty_init(&vty_info); logging_vty_add_cmds(&log_info); -- cgit v1.2.3 From 9705671025eba34b70d73e9d4e78813e4f2d31da Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 16:28:15 +0200 Subject: nat: Send 16 bytes of rand to the BSC and remember it Generate 16 byte of random data to be used for A3A8 by the BSC in the response. We can't know which BSC it is at this point and I don't want to send another message once the token has been received so always send the data with an undefined code. The old BSCs don't parse the message and will happily ignore the RAND. /dev/urandom can give short reads on Linux so loop around it until the bytes have been read from the kernel. --- openbsc/src/osmo-bsc_nat/bsc_nat.c | 40 +++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 82562ba17..254ea42f2 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -188,9 +188,9 @@ static void send_id_ack(struct bsc_connection *bsc) bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS); } -static void send_id_req(struct bsc_connection *bsc) +static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc) { - static const uint8_t id_req[] = { + static const uint8_t s_id_req[] = { IPAC_MSGT_ID_GET, 0x01, IPAC_IDTAG_UNIT, 0x01, IPAC_IDTAG_MACADDR, @@ -202,7 +202,41 @@ static void send_id_req(struct bsc_connection *bsc) 0x01, IPAC_IDTAG_SERNR, }; + int toread, rounds; + uint8_t *mrand, *randoff; + uint8_t id_req[sizeof(s_id_req) + (2+16)]; + uint8_t *buf = &id_req[sizeof(s_id_req)]; + + /* copy the static data */ + memcpy(id_req, s_id_req, sizeof(s_id_req)); + + /* put the RAND with length, tag, value */ + buf = v_put(buf, 0x11); + buf = v_put(buf, 0x23); + mrand = bsc->last_rand; + randoff = mrand; + memset(randoff, 0, 16); + + for (toread = 16, rounds = 0; rounds < 5 && toread > 0; ++rounds) { + int rc = read(nat->random_fd, randoff, toread); + if (rc <= 0) + goto failed_random; + toread -= rc; + randoff += rc; + } + + if (toread != 0) + goto failed_random; + memcpy(buf, mrand, 16); + buf += 16; + bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS); + return; + +failed_random: + /* the timeout will trigger and close this connection */ + LOGP(DNAT, LOGL_ERROR, "Failed to read from urandom.\n"); + return; } static struct msgb *nat_create_rlsd(struct nat_sccp_connection *conn) @@ -1362,7 +1396,7 @@ static int ipaccess_listen_bsc_cb(struct osmo_fd *bfd, unsigned int what) bsc->last_id = 0; send_id_ack(bsc); - send_id_req(bsc); + send_id_req(nat, bsc); send_mgcp_reset(bsc); /* -- cgit v1.2.3 From e2ac6b77feecc5b7194a308bbd11e206c4a41fcb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 8 Jun 2015 18:02:10 +0200 Subject: bsc: Check for the rand and then generate a res Check if the NAT has sent 16 bytes of RAND and if a key has been configured in the system and then generate a result using milenage. The milenage res will be sent and noth the four byte GSM SRES derivation. --- openbsc/src/libbsc/bsc_msc.c | 7 ++++- openbsc/src/osmo-bsc/osmo_bsc_msc.c | 58 ++++++++++++++++++++++++++++++++++--- openbsc/src/osmo-bsc/osmo_bsc_vty.c | 29 +++++++++++++++++++ openbsc/src/osmo-bsc_nat/bsc_nat.c | 2 +- 4 files changed, 90 insertions(+), 6 deletions(-) (limited to 'openbsc/src') diff --git a/openbsc/src/libbsc/bsc_msc.c b/openbsc/src/libbsc/bsc_msc.c index fc4530ce7..829ee2b54 100644 --- a/openbsc/src/libbsc/bsc_msc.c +++ b/openbsc/src/libbsc/bsc_msc.c @@ -276,7 +276,7 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *con) osmo_timer_schedule(&con->reconnect_timer, 5, 0); } -struct msgb *bsc_msc_id_get_resp(int fixed, const char *token) +struct msgb *bsc_msc_id_get_resp(int fixed, const char *token, const uint8_t *res, int len) { struct msgb *msg; @@ -302,6 +302,11 @@ struct msgb *bsc_msc_id_get_resp(int fixed, const char *token) msgb_put_u8(msg, 0); msgb_put_u8(msg, strlen(token) + 2); msgb_tv_fixed_put(msg, IPAC_IDTAG_UNITNAME, strlen(token) + 1, (uint8_t *) token); + if (len > 0) { + msgb_put_u8(msg, 0); + msgb_put_u8(msg, len + 1); + msgb_tv_fixed_put(msg, 0x24, len, res); + } } else { msgb_l16tv_put(msg, strlen(token) + 1, IPAC_IDTAG_UNITNAME, (uint8_t *) token); diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c index 5127ca849..773ee1432 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ static void initialize_if_needed(struct bsc_msc_connection *conn); static void send_lacs(struct gsm_network *net, struct bsc_msc_connection *conn); -static void send_id_get_response(struct osmo_msc_data *data, int fd); +static void send_id_get_response(struct osmo_msc_data *data, int fd, struct msgb *inp); static void send_ping(struct osmo_msc_data *data); static void schedule_ping_pong(struct osmo_msc_data *data); @@ -302,7 +303,7 @@ static int ipaccess_a_fd_cb(struct osmo_fd *bfd) if (msg->l2h[0] == IPAC_MSGT_ID_ACK) initialize_if_needed(data->msc_con); else if (msg->l2h[0] == IPAC_MSGT_ID_GET) { - send_id_get_response(data, bfd->fd); + send_id_get_response(data, bfd->fd, msg); } else if (msg->l2h[0] == IPAC_MSGT_PONG) { osmo_timer_del(&data->pong_timer); } @@ -451,12 +452,61 @@ static void initialize_if_needed(struct bsc_msc_connection *conn) } } -static void send_id_get_response(struct osmo_msc_data *data, int fd) +static int answer_challenge(struct osmo_msc_data *data, struct msgb *inp, struct osmo_auth_vector *vec) +{ + int ret; + struct tlv_parsed tvp; + const uint8_t *mrand; + uint8_t mrand_len; + struct osmo_sub_auth_data auth = { + .type = OSMO_AUTH_TYPE_GSM, + .algo = OSMO_AUTH_ALG_MILENAGE, + }; + + ret = ipa_ccm_idtag_parse_off(&tvp, + inp->l2h + 1, + msgb_l2len(inp) - 1, 1); + if (ret < 0) { + LOGP(DMSC, LOGL_ERROR, "ignoring IPA response " + "message with malformed TLVs: %s\n", osmo_hexdump(inp->l2h + 1, + msgb_l2len(inp) - 1)); + return 0; + } + + mrand = TLVP_VAL(&tvp, 0x23); + mrand_len = TLVP_LEN(&tvp, 0x23); + if (mrand_len != 16) { + LOGP(DMSC, LOGL_ERROR, + "RAND is not 16 bytes. Was %d\n", + mrand_len); + return 0; + } + + /* copy the key */ + memcpy(auth.u.umts.opc, data->bsc_key, 16); + memcpy(auth.u.umts.k, data->bsc_key, 16); + memset(auth.u.umts.amf, 0, 2); + auth.u.umts.sqn = 0; + + /* generate the result */ + memset(vec, 0, sizeof(*vec)); + osmo_auth_gen_vec(vec, &auth, mrand); + return 1; +} + + +static void send_id_get_response(struct osmo_msc_data *data, int fd, struct msgb *inp) { struct msc_signal_data sig; struct msgb *msg; + struct osmo_auth_vector vec; + int valid = 0; + + if (data->bsc_key_present) + valid = answer_challenge(data, inp, &vec); - msg = bsc_msc_id_get_resp(0, data->bsc_token); + msg = bsc_msc_id_get_resp(valid, data->bsc_token, + vec.res, valid ? vec.res_len : 0); if (!msg) return; msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS); diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c index 06ad77d59..9a17cd064 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c @@ -107,6 +107,9 @@ static void write_msc(struct vty *vty, struct osmo_msc_data *msc) vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE); if (msc->bsc_token) vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE); + if (msc->bsc_key_present) + vty_out(vty, " auth-key %s%s", + osmo_hexdump(msc->bsc_key, sizeof(msc->bsc_key)), VTY_NEWLINE); if (msc->core_ncc != -1) vty_out(vty, " core-mobile-network-code %d%s", msc->core_ncc, VTY_NEWLINE); @@ -231,6 +234,30 @@ DEFUN(cfg_net_bsc_token, return CMD_SUCCESS; } +DEFUN(cfg_net_bsc_key, + cfg_net_bsc_key_cmd, + "auth-key KEY", + "Authentication (secret) key configuration\n" + "Security key\n") +{ + struct osmo_msc_data *data = osmo_msc_data(vty); + + osmo_hexparse(argv[0], data->bsc_key, sizeof(data->bsc_key)); + data->bsc_key_present = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_net_no_bsc_key, cfg_net_bsc_no_key_cmd, + "no auth-key", + NO_STR "Authentication (secret) key configuration\n") +{ + struct osmo_msc_data *data = osmo_msc_data(vty); + + memset(data->bsc_key, 0, sizeof(data->bsc_key)); + data->bsc_key_present = 0; + return CMD_SUCCESS; +} + DEFUN(cfg_net_bsc_ncc, cfg_net_bsc_ncc_cmd, "core-mobile-network-code <1-999>", @@ -871,6 +898,8 @@ int bsc_vty_init_extra(void) install_node(&msc_node, config_write_msc); vty_install_default(MSC_NODE); install_element(MSC_NODE, &cfg_net_bsc_token_cmd); + install_element(MSC_NODE, &cfg_net_bsc_key_cmd); + install_element(MSC_NODE, &cfg_net_bsc_no_key_cmd); install_element(MSC_NODE, &cfg_net_bsc_ncc_cmd); install_element(MSC_NODE, &cfg_net_bsc_mcc_cmd); install_element(MSC_NODE, &cfg_net_bsc_lac_cmd); diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 254ea42f2..983770925 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -394,7 +394,7 @@ static void initialize_msc_if_needed(struct bsc_msc_connection *msc_con) static void send_id_get_response(struct bsc_msc_connection *msc_con) { - struct msgb *msg = bsc_msc_id_get_resp(0, nat->token); + struct msgb *msg = bsc_msc_id_get_resp(0, nat->token, NULL, 0); if (!msg) return; -- cgit v1.2.3 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/src/osmo-bsc_nat/bsc_nat.c | 61 ++++++++++++++++++++++++++++++++-- openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 32 ++++++++++++++++-- 2 files changed, 89 insertions(+), 4 deletions(-) (limited to 'openbsc/src') 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