Merge branch 'zecke/features/auth'
Introduce another authentication scheme using MILENAGE. In the future reading from /dev/urandom will be replaced with libcrypto.
This commit is contained in:
commit
8ee53ed9ec
|
@ -60,6 +60,6 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *);
|
||||||
|
|
||||||
void bsc_msc_lost(struct bsc_msc_connection *);
|
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
|
#endif
|
||||||
|
|
|
@ -84,6 +84,7 @@ struct bsc_connection {
|
||||||
|
|
||||||
/* do we know anything about this BSC? */
|
/* do we know anything about this BSC? */
|
||||||
int authenticated;
|
int authenticated;
|
||||||
|
uint8_t last_rand[16];
|
||||||
|
|
||||||
/* the fd we use to communicate */
|
/* the fd we use to communicate */
|
||||||
struct osmo_wqueue write_queue;
|
struct osmo_wqueue write_queue;
|
||||||
|
@ -147,6 +148,8 @@ enum bsc_cfg_ctr {
|
||||||
struct bsc_config {
|
struct bsc_config {
|
||||||
struct llist_head entry;
|
struct llist_head entry;
|
||||||
|
|
||||||
|
uint8_t key[16];
|
||||||
|
uint8_t key_present;
|
||||||
char *token;
|
char *token;
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
|
@ -304,6 +307,9 @@ struct bsc_nat {
|
||||||
|
|
||||||
/* control interface */
|
/* control interface */
|
||||||
struct ctrl_handle *ctrl;
|
struct ctrl_handle *ctrl;
|
||||||
|
|
||||||
|
/* for random values */
|
||||||
|
int random_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bsc_nat_ussd_con {
|
struct bsc_nat_ussd_con {
|
||||||
|
@ -319,6 +325,7 @@ struct bsc_nat_ussd_con {
|
||||||
/* create and init the structures */
|
/* create and init the structures */
|
||||||
struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token);
|
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_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_free(struct bsc_config *);
|
||||||
void bsc_config_add_lac(struct bsc_config *cfg, int lac);
|
void bsc_config_add_lac(struct bsc_config *cfg, int lac);
|
||||||
void bsc_config_del_lac(struct bsc_config *cfg, int lac);
|
void bsc_config_del_lac(struct bsc_config *cfg, int lac);
|
||||||
|
|
|
@ -59,6 +59,9 @@ struct osmo_msc_data {
|
||||||
|
|
||||||
/* Connection data */
|
/* Connection data */
|
||||||
char *bsc_token;
|
char *bsc_token;
|
||||||
|
uint8_t bsc_key[16];
|
||||||
|
uint8_t bsc_key_present;
|
||||||
|
|
||||||
int ping_timeout;
|
int ping_timeout;
|
||||||
int pong_timeout;
|
int pong_timeout;
|
||||||
struct osmo_timer_list ping_timer;
|
struct osmo_timer_list ping_timer;
|
||||||
|
|
|
@ -276,7 +276,7 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
|
||||||
osmo_timer_schedule(&con->reconnect_timer, 5, 0);
|
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;
|
struct msgb *msg;
|
||||||
|
|
||||||
|
@ -291,8 +291,26 @@ struct msgb *bsc_msc_id_get_resp(const char *token)
|
||||||
return NULL;
|
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);
|
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);
|
IPAC_IDTAG_UNITNAME, (uint8_t *) token);
|
||||||
|
}
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <openbsc/bsc_nat.h>
|
#include <openbsc/bsc_nat.h>
|
||||||
#include <osmocom/ctrl/control_cmd.h>
|
#include <osmocom/ctrl/control_cmd.h>
|
||||||
#include <osmocom/ctrl/control_if.h>
|
#include <osmocom/ctrl/control_if.h>
|
||||||
|
#include <osmocom/crypt/auth.h>
|
||||||
#include <openbsc/debug.h>
|
#include <openbsc/debug.h>
|
||||||
#include <openbsc/gsm_data.h>
|
#include <openbsc/gsm_data.h>
|
||||||
#include <openbsc/ipaccess.h>
|
#include <openbsc/ipaccess.h>
|
||||||
|
@ -44,7 +45,7 @@
|
||||||
|
|
||||||
static void initialize_if_needed(struct bsc_msc_connection *conn);
|
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_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 send_ping(struct osmo_msc_data *data);
|
||||||
static void schedule_ping_pong(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)
|
if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
|
||||||
initialize_if_needed(data->msc_con);
|
initialize_if_needed(data->msc_con);
|
||||||
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
|
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) {
|
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
|
||||||
osmo_timer_del(&data->pong_timer);
|
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 msc_signal_data sig;
|
||||||
struct msgb *msg;
|
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)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
|
msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
|
||||||
|
|
|
@ -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);
|
vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE);
|
||||||
if (msc->bsc_token)
|
if (msc->bsc_token)
|
||||||
vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE);
|
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)
|
if (msc->core_ncc != -1)
|
||||||
vty_out(vty, " core-mobile-network-code %d%s",
|
vty_out(vty, " core-mobile-network-code %d%s",
|
||||||
msc->core_ncc, VTY_NEWLINE);
|
msc->core_ncc, VTY_NEWLINE);
|
||||||
|
@ -231,6 +234,30 @@ DEFUN(cfg_net_bsc_token,
|
||||||
return CMD_SUCCESS;
|
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,
|
DEFUN(cfg_net_bsc_ncc,
|
||||||
cfg_net_bsc_ncc_cmd,
|
cfg_net_bsc_ncc_cmd,
|
||||||
"core-mobile-network-code <1-999>",
|
"core-mobile-network-code <1-999>",
|
||||||
|
@ -871,6 +898,8 @@ int bsc_vty_init_extra(void)
|
||||||
install_node(&msc_node, config_write_msc);
|
install_node(&msc_node, config_write_msc);
|
||||||
vty_install_default(MSC_NODE);
|
vty_install_default(MSC_NODE);
|
||||||
install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
|
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_ncc_cmd);
|
||||||
install_element(MSC_NODE, &cfg_net_bsc_mcc_cmd);
|
install_element(MSC_NODE, &cfg_net_bsc_mcc_cmd);
|
||||||
install_element(MSC_NODE, &cfg_net_bsc_lac_cmd);
|
install_element(MSC_NODE, &cfg_net_bsc_lac_cmd);
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
@ -31,6 +33,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
@ -48,6 +51,8 @@
|
||||||
#include <osmocom/ctrl/control_cmd.h>
|
#include <osmocom/ctrl/control_cmd.h>
|
||||||
#include <osmocom/ctrl/control_if.h>
|
#include <osmocom/ctrl/control_if.h>
|
||||||
|
|
||||||
|
#include <osmocom/crypt/auth.h>
|
||||||
|
|
||||||
#include <osmocom/core/application.h>
|
#include <osmocom/core/application.h>
|
||||||
#include <osmocom/core/talloc.h>
|
#include <osmocom/core/talloc.h>
|
||||||
|
|
||||||
|
@ -185,9 +190,9 @@ static void send_id_ack(struct bsc_connection *bsc)
|
||||||
bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS);
|
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,
|
IPAC_MSGT_ID_GET,
|
||||||
0x01, IPAC_IDTAG_UNIT,
|
0x01, IPAC_IDTAG_UNIT,
|
||||||
0x01, IPAC_IDTAG_MACADDR,
|
0x01, IPAC_IDTAG_MACADDR,
|
||||||
|
@ -199,7 +204,41 @@ static void send_id_req(struct bsc_connection *bsc)
|
||||||
0x01, IPAC_IDTAG_SERNR,
|
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);
|
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)
|
static struct msgb *nat_create_rlsd(struct nat_sccp_connection *conn)
|
||||||
|
@ -357,7 +396,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)
|
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)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -956,11 +995,57 @@ static void ipaccess_close_bsc(void *data)
|
||||||
bsc_close_connection(conn);
|
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)
|
static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
|
||||||
{
|
{
|
||||||
struct bsc_config *conf;
|
struct bsc_config *conf;
|
||||||
const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
|
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) {
|
if (bsc->cfg) {
|
||||||
LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
|
LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
|
||||||
|
@ -980,27 +1065,38 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) {
|
/*
|
||||||
/*
|
* New systems have fixed the structure of the message but
|
||||||
* Add the '\0' of the token for the memcmp, the IPA messages
|
* we need to support old ones too.
|
||||||
* for some reason added null termination.
|
*/
|
||||||
*/
|
if (len >= 2 && token[len - 2] == '\0')
|
||||||
const int token_len = strlen(conf->token) + 1;
|
len -= 1;
|
||||||
|
|
||||||
if (token_len == len && memcmp(conf->token, token, token_len) == 0) {
|
conf = bsc_config_by_token(bsc->nat, token, len);
|
||||||
rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]);
|
if (!conf) {
|
||||||
bsc->authenticated = 1;
|
LOGP(DNAT, LOGL_ERROR,
|
||||||
bsc->cfg = conf;
|
"No bsc found for token '%s' len %d on fd: %d.\n", token,
|
||||||
osmo_timer_del(&bsc->id_timeout);
|
bsc->write_queue.bfd.fd, len);
|
||||||
LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n",
|
bsc_close_connection(bsc);
|
||||||
conf->nr, bsc->write_queue.bfd.fd);
|
return;
|
||||||
start_ping_pong(bsc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGP(DNAT, LOGL_ERROR, "No bsc found for token '%s' on fd: %d.\n", token,
|
/* We have set a key and expect it to be present */
|
||||||
bsc->write_queue.bfd.fd);
|
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)
|
static void handle_con_stats(struct nat_sccp_connection *con)
|
||||||
|
@ -1185,12 +1281,12 @@ exit:
|
||||||
send_reset_ack(bsc);
|
send_reset_ack(bsc);
|
||||||
} else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
|
} else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
|
||||||
/* do we know who is handling this? */
|
/* 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;
|
struct tlv_parsed tvp;
|
||||||
int ret;
|
int ret;
|
||||||
ret = ipa_ccm_idtag_parse(&tvp,
|
ret = ipa_ccm_idtag_parse_off(&tvp,
|
||||||
(unsigned char *) msg->l2h + 2,
|
(unsigned char *) msg->l2h + 2,
|
||||||
msgb_l2len(msg) - 2);
|
msgb_l2len(msg) - 2, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
|
LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
|
||||||
"message with malformed TLVs\n");
|
"message with malformed TLVs\n");
|
||||||
|
@ -1357,7 +1453,7 @@ static int ipaccess_listen_bsc_cb(struct osmo_fd *bfd, unsigned int what)
|
||||||
bsc->last_id = 0;
|
bsc->last_id = 0;
|
||||||
|
|
||||||
send_id_ack(bsc);
|
send_id_ack(bsc);
|
||||||
send_id_req(bsc);
|
send_id_req(nat, bsc);
|
||||||
send_mgcp_reset(bsc);
|
send_mgcp_reset(bsc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1532,6 +1628,12 @@ int main(int argc, char **argv)
|
||||||
/* We need to add mode-set for amr codecs */
|
/* We need to add mode-set for amr codecs */
|
||||||
nat->sdp_ensure_amr_mode_set = 1;
|
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_info.copyright = openbsc_copyright;
|
||||||
vty_init(&vty_info);
|
vty_init(&vty_info);
|
||||||
logging_vty_add_cmds(&log_info);
|
logging_vty_add_cmds(&log_info);
|
||||||
|
|
|
@ -180,6 +180,24 @@ struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token)
|
||||||
return conf;
|
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)
|
void bsc_config_free(struct bsc_config *cfg)
|
||||||
{
|
{
|
||||||
llist_del(&cfg->entry);
|
llist_del(&cfg->entry);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* OpenBSC NAT interface to quagga VTY */
|
/* OpenBSC NAT interface to quagga VTY */
|
||||||
/* (C) 2010-2013 by Holger Hans Peter Freyther
|
/* (C) 2010-2015 by Holger Hans Peter Freyther
|
||||||
* (C) 2010-2013 by On-Waves
|
* (C) 2010-2015 by On-Waves
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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, " bsc %u%s", bsc->nr, VTY_NEWLINE);
|
||||||
vty_out(vty, " token %s%s", bsc->token, 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);
|
dump_lac(vty, &bsc->lac_list);
|
||||||
if (bsc->description)
|
if (bsc->description)
|
||||||
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
|
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;
|
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>",
|
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")
|
"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);
|
install_node(&bsc_node, config_write_bsc);
|
||||||
vty_install_default(NAT_BSC_NODE);
|
vty_install_default(NAT_BSC_NODE);
|
||||||
install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd);
|
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_lac_cmd);
|
||||||
install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd);
|
install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd);
|
||||||
install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd);
|
install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd);
|
||||||
|
|
Loading…
Reference in New Issue