aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-12-23 17:30:18 +0100
committerPhilipp Maier <pmaier@sysmocom.de>2018-02-19 11:43:07 +0100
commit51e4bf329844b8daa20239f77bb90cf04ce6dbb9 (patch)
tree714824807233bc013977d51adf5b266e72c616be
parent86a8031e9cf0b8660d4c34079d0aec1505b4823f (diff)
Permit set of multiple different A5 ciphers
So far, the administrator had to pick one particular cipher which would then be used throughout all subscribers/phones. This is a bit impractical, as e.g. not all phones support A5/3. Extend the VTY command syntax in a backwards-compatible way to permit for multiple ciphers. The bit-mask of permitted ciphers from the MSC (sent in ASSIGNMENT COMMAND) is intersected with the vty-configured mask a the BSC. Finally, the best (highest) possible cipher is chosen. Change-Id: I1d1c8131855bcab2392b4f27f6216bdb2fae10e0 Closes: OS#2461
-rw-r--r--include/osmocom/bsc/gsm_data.h3
-rw-r--r--src/libbsc/bsc_vty.c36
-rw-r--r--src/libbsc/net_init.c2
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c32
4 files changed, 52 insertions, 21 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index 04dc69673..77fda0045 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -1191,7 +1191,8 @@ struct gsm_network {
/* global parameters */
uint16_t country_code;
uint16_t network_code;
- int a5_encryption;
+ /* bit-mask of permitted encryption algorithms. LSB=A5/0, MSB=A5/7 */
+ uint8_t a5_encryption_mask;
int neci;
struct handover_cfg *ho;
diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
index 64a92b201..3ce310ad3 100644
--- a/src/libbsc/bsc_vty.c
+++ b/src/libbsc/bsc_vty.c
@@ -1,5 +1,5 @@
/* OpenBSC interface to quagga VTY */
-/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+/* (C) 2009-2017 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -192,13 +192,18 @@ static void dump_pchan_load_vty(struct vty *vty, char *prefix,
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{
struct pchan_load pl;
+ int i;
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
"and has %u BTS%s", net->country_code, net->network_code,
net->num_bts, VTY_NEWLINE);
vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
- VTY_NEWLINE);
+ vty_out(vty, " Encryption:");
+ for (i = 0; i < 8; i++) {
+ if (net->a5_encryption_mask & (1 << i))
+ vty_out(vty, " A5/%u", i);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
VTY_NEWLINE);
vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
@@ -917,11 +922,17 @@ static int config_write_bts(struct vty *v)
static int config_write_net(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ int i;
vty_out(vty, "network%s", VTY_NEWLINE);
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
- vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
+ vty_out(vty, " encryption a5");
+ for (i = 0; i < 8; i++) {
+ if (gsmnet->a5_encryption_mask & (1 << i))
+ vty_out(vty, " %u", i);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
@@ -4410,15 +4421,20 @@ DEFUN(cfg_net_mnc,
DEFUN(cfg_net_encryption,
cfg_net_encryption_cmd,
- "encryption a5 (0|1|2|3)",
- "Encryption options\n"
- "A5 encryption\n" "A5/0: No encryption\n"
- "A5/1: Encryption\n" "A5/2: Export-grade Encryption\n"
- "A5/3: 'New' Secure Encryption\n")
+ "encryption a5 <0-3> [<0-3>] [<0-3>] [<0-3>]",
+ "Encryption options\n"
+ "GSM A5 Air Interface Encryption\n"
+ "A5/n Algorithm Number\n"
+ "A5/n Algorithm Number\n"
+ "A5/n Algorithm Number\n"
+ "A5/n Algorithm Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ unsigned int i;
- gsmnet->a5_encryption = atoi(argv[0]);
+ gsmnet->a5_encryption_mask = 0;
+ for (i = 0; i < argc; i++)
+ gsmnet->a5_encryption_mask |= (1 << atoi(argv[i]));
return CMD_SUCCESS;
}
diff --git a/src/libbsc/net_init.c b/src/libbsc/net_init.c
index 90f668f2c..d560b0c9e 100644
--- a/src/libbsc/net_init.c
+++ b/src/libbsc/net_init.c
@@ -50,6 +50,8 @@ struct gsm_network *bsc_network_init(void *ctx,
net->country_code = country_code;
net->network_code = network_code;
+ /* Permit a compile-time default of A5/3 and A5/1 */
+ net->a5_encryption_mask = (1 << 3) | (1 << 1);
/* Use 30 min periodic update interval as sane default */
net->t3212 = 5;
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 83c884c44..b14968a50 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -567,6 +567,19 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc,
return 0;
}
+/* select the best cipher permitted by the intersection of both masks */
+static int select_best_cipher(uint8_t msc_mask, uint8_t bsc_mask)
+{
+ uint8_t intersection = msc_mask & bsc_mask;
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ if (intersection & (1 << i))
+ return i;
+ }
+ return -1;
+}
+
/*
* GSM 08.08 ยง 3.1.9.1 and 3.2.1.21...
* release our gsm_subscriber_connection and send message
@@ -626,8 +639,8 @@ static int bssmap_handle_cipher_mode(struct gsm_subscriber_connection *conn,
int include_imeisv = 1;
const uint8_t *enc_key;
uint16_t enc_key_len;
- uint8_t enc_bits_bsc;
uint8_t enc_bits_msc;
+ int chosen_cipher;
if (!conn) {
LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
@@ -668,27 +681,26 @@ static int bssmap_handle_cipher_mode(struct gsm_subscriber_connection *conn,
if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE))
include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1;
- /* FIXME: match up the list of permitted ciphering algorithms received from the MSC with a list
- * of ciphering algorithms configured for this BSC (the config of more than one is TODO). Finally
- * pick one of the remaining options. */
-
/* Identical to the GSM0808_IE_ENCRYPTION_INFORMATION above:
* a5_encryption == 0 --> 0x01
* a5_encryption == 1 --> 0x02
* a5_encryption == 2 --> 0x04 ... */
- enc_bits_bsc = 1 << network->a5_encryption;
enc_bits_msc = data[0];
- if (!(enc_bits_msc & enc_bits_bsc)) {
- LOGP(DMSC, LOGL_ERROR, "MSC does not permit A5/%d (permitted algorithms mask: 0x%x)\n",
- network->a5_encryption, enc_bits_msc);
+ /* The bit-mask of permitted ciphers from the MSC (sent in ASSIGNMENT COMMAND) is intersected
+ * with the vty-configured mask a the BSC. Finally, the best (highest) possible cipher is
+ * chosen. */
+ chosen_cipher = select_best_cipher(enc_bits_msc, network->a5_encryption_mask);
+ if (chosen_cipher < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Reject: no overlapping A5 ciphers between BSC (0x%02x) "
+ "and MSC (0x%02x)\n", network->a5_encryption_mask, enc_bits_msc);
reject_cause = GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED;
goto reject;
}
/* To complete the confusion, gsm0808_cipher_mode again expects the encryption as a number
* from 0 to 7. */
- if (gsm0808_cipher_mode(conn, network->a5_encryption, enc_key, enc_key_len,
+ if (gsm0808_cipher_mode(conn, chosen_cipher, enc_key, enc_key_len,
include_imeisv)) {
reject_cause = GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC;
goto reject;