Merge branch 'zecke/features/auth'

Introduce another authentication scheme using MILENAGE. In the
future reading from /dev/urandom will be replaced with libcrypto.
diff --git a/openbsc/include/openbsc/bsc_msc.h b/openbsc/include/openbsc/bsc_msc.h
index 763bae5..39258d3 100644
--- a/openbsc/include/openbsc/bsc_msc.h
+++ b/openbsc/include/openbsc/bsc_msc.h
@@ -60,6 +60,6 @@
 
 void bsc_msc_lost(struct bsc_msc_connection *);
 
-struct msgb *bsc_msc_id_get_resp(const char *token);
+struct msgb *bsc_msc_id_get_resp(int fixed, const char *token, const uint8_t *res, int len);
 
 #endif
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index ae940b3..72773a9 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -84,6 +84,7 @@
 
 	/* do we know anything about this BSC? */
 	int authenticated;
+	uint8_t last_rand[16];
 
 	/* the fd we use to communicate */
 	struct osmo_wqueue write_queue;
@@ -147,6 +148,8 @@
 struct bsc_config {
 	struct llist_head entry;
 
+	uint8_t key[16];
+	uint8_t key_present;
 	char *token;
 	int nr;
 
@@ -304,6 +307,9 @@
 
 	/* control interface */
 	struct ctrl_handle *ctrl;
+
+	/* for random values */
+	int random_fd;
 };
 
 struct bsc_nat_ussd_con {
@@ -319,6 +325,7 @@
 /* create and init the structures */
 struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token);
 struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num);
+struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len);
 void bsc_config_free(struct bsc_config *);
 void bsc_config_add_lac(struct bsc_config *cfg, int lac);
 void bsc_config_del_lac(struct bsc_config *cfg, int lac);
diff --git a/openbsc/include/openbsc/osmo_msc_data.h b/openbsc/include/openbsc/osmo_msc_data.h
index 2d863aa..ed38187 100644
--- a/openbsc/include/openbsc/osmo_msc_data.h
+++ b/openbsc/include/openbsc/osmo_msc_data.h
@@ -59,6 +59,9 @@
 
 	/* Connection data */
 	char *bsc_token;
+	uint8_t bsc_key[16];
+	uint8_t bsc_key_present;
+
 	int ping_timeout;
 	int pong_timeout;
 	struct osmo_timer_list ping_timer;
diff --git a/openbsc/src/libbsc/bsc_msc.c b/openbsc/src/libbsc/bsc_msc.c
index a24efab..829ee2b 100644
--- a/openbsc/src/libbsc/bsc_msc.c
+++ b/openbsc/src/libbsc/bsc_msc.c
@@ -276,7 +276,7 @@
 	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, const uint8_t *res, int len)
 {
 	struct msgb *msg;
 
@@ -291,8 +291,26 @@
 		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);
+		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);
+	}
+
 	return msg;
 }
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_msc.c b/openbsc/src/osmo-bsc/osmo_bsc_msc.c
index 129b23e..773ee14 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_msc.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_msc.c
@@ -23,6 +23,7 @@
 #include <openbsc/bsc_nat.h>
 #include <osmocom/ctrl/control_cmd.h>
 #include <osmocom/ctrl/control_if.h>
+#include <osmocom/crypt/auth.h>
 #include <openbsc/debug.h>
 #include <openbsc/gsm_data.h>
 #include <openbsc/ipaccess.h>
@@ -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 @@
 		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 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;
 
-	msg = bsc_msc_id_get_resp(data->bsc_token);
+	if (data->bsc_key_present)
+		valid = answer_challenge(data, inp, &vec);
+
+	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 06ad77d..9a17cd0 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c
@@ -107,6 +107,9 @@
 	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 @@
 	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 @@
 	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 4357485..581193e 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -21,6 +21,8 @@
  *
  */
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
@@ -31,6 +33,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #define _GNU_SOURCE
 #include <getopt.h>
@@ -48,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>
 
@@ -185,9 +190,9 @@
 	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,
@@ -199,7 +204,41 @@
 		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)
@@ -357,7 +396,7 @@
 
 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, NULL, 0);
 	if (!msg)
 		return;
 
@@ -956,11 +995,57 @@
 	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);
-	const int len = TLVP_LEN(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",
@@ -980,27 +1065,38 @@
 		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;
+	/*
+	 * 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;
 
-		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' len %d on fd: %d.\n", token,
+			bsc->write_queue.bfd.fd, len);
+		bsc_close_connection(bsc);
+		return;
 	}
 
-	LOGP(DNAT, LOGL_ERROR, "No bsc found for token '%s' on fd: %d.\n", token,
-	     bsc->write_queue.bfd.fd);
+	/* 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;
+	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)
@@ -1185,12 +1281,12 @@
 		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,
+			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");
@@ -1357,7 +1453,7 @@
 	bsc->last_id = 0;
 
 	send_id_ack(bsc);
-	send_id_req(bsc);
+	send_id_req(nat, bsc);
 	send_mgcp_reset(bsc);
 
 	/*
@@ -1532,6 +1628,12 @@
 	/* 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);
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
index d95227d..d7ec545 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 @@
 	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);
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
index 821e522..981168c 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 @@
 {
 	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 @@
 	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 @@
 	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);