support A5/4 in Cipher Mode Command
Related: SYS#5324 Change-Id: I780a739b9bfbefd4f58be051794fe1a491823e67
This commit is contained in:
parent
a7f8020bfa
commit
6ce2edcac1
|
@ -32,6 +32,8 @@ struct geran_encr {
|
||||||
uint8_t alg_id;
|
uint8_t alg_id;
|
||||||
uint8_t key_len;
|
uint8_t key_len;
|
||||||
uint8_t key[MAX_A5_KEY_LEN];
|
uint8_t key[MAX_A5_KEY_LEN];
|
||||||
|
bool kc128_present;
|
||||||
|
uint8_t kc128[MAX_A5_KEY_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum complete_layer3_type {
|
enum complete_layer3_type {
|
||||||
|
|
|
@ -292,6 +292,14 @@ int msc_a_vlr_set_cipher_mode(void *_msc_a, bool umts_aka, bool retrieve_imeisv)
|
||||||
return msc_a_ran_enc_ciphering(msc_a, umts_aka, retrieve_imeisv);
|
return msc_a_ran_enc_ciphering(msc_a, umts_aka, retrieve_imeisv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t filter_a5(uint8_t a5_mask, bool umts_aka)
|
||||||
|
{
|
||||||
|
/* With GSM AKA: allow A5/0, 1, 3 = 0b00001011 = 0xb.
|
||||||
|
* UMTS aka: allow A5/0, 1, 3, 4 = 0b00011011 = 0x1b.
|
||||||
|
*/
|
||||||
|
return a5_mask & (umts_aka ? 0x1b : 0x0b);
|
||||||
|
}
|
||||||
|
|
||||||
static int msc_a_ran_enc_ciphering(struct msc_a *msc_a, bool umts_aka, bool retrieve_imeisv)
|
static int msc_a_ran_enc_ciphering(struct msc_a *msc_a, bool umts_aka, bool retrieve_imeisv)
|
||||||
{
|
{
|
||||||
struct gsm_network *net;
|
struct gsm_network *net;
|
||||||
|
@ -321,7 +329,7 @@ static int msc_a_ran_enc_ciphering(struct msc_a *msc_a, bool umts_aka, bool retr
|
||||||
.geran = {
|
.geran = {
|
||||||
.umts_aka = umts_aka,
|
.umts_aka = umts_aka,
|
||||||
.retrieve_imeisv = retrieve_imeisv,
|
.retrieve_imeisv = retrieve_imeisv,
|
||||||
.a5_encryption_mask = net->a5_encryption_mask,
|
.a5_encryption_mask = filter_a5(net->a5_encryption_mask, umts_aka),
|
||||||
|
|
||||||
/* for ran_a.c to store the GERAN key that is actually used */
|
/* for ran_a.c to store the GERAN key that is actually used */
|
||||||
.chosen_key = &msc_a->geran_encr,
|
.chosen_key = &msc_a->geran_encr,
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <osmocom/core/byteswap.h>
|
#include <osmocom/core/byteswap.h>
|
||||||
|
|
||||||
#include <osmocom/crypt/auth.h>
|
#include <osmocom/crypt/auth.h>
|
||||||
|
#include <osmocom/crypt/kdf.h>
|
||||||
|
|
||||||
#include <osmocom/gsm/tlv.h>
|
#include <osmocom/gsm/tlv.h>
|
||||||
#include <osmocom/gsm/gsm0808.h>
|
#include <osmocom/gsm/gsm0808.h>
|
||||||
|
@ -1019,6 +1020,9 @@ static int a5_n_to_gsm0808_chosen_enc_alg(uint8_t *dst, int a5_n)
|
||||||
case 3:
|
case 3:
|
||||||
*dst = GSM0808_ALG_ID_A5_3;
|
*dst = GSM0808_ALG_ID_A5_3;
|
||||||
return 0;
|
return 0;
|
||||||
|
case 4:
|
||||||
|
*dst = GSM0808_ALG_ID_A5_4;
|
||||||
|
return 0;
|
||||||
default:
|
default:
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
@ -1078,21 +1082,39 @@ static struct msgb *ran_a_make_cipher_mode_command(struct osmo_fsm_inst *fi, con
|
||||||
/* In case of UMTS AKA, the Kc for ciphering must be derived from the 3G auth
|
/* In case of UMTS AKA, the Kc for ciphering must be derived from the 3G auth
|
||||||
* tokens. vec->kc was calculated from the GSM algorithm and is not
|
* tokens. vec->kc was calculated from the GSM algorithm and is not
|
||||||
* necessarily a match for the UMTS AKA tokens. */
|
* necessarily a match for the UMTS AKA tokens. */
|
||||||
if (cm->geran.umts_aka)
|
if (cm->geran.umts_aka) {
|
||||||
|
int i;
|
||||||
osmo_auth_c3(ei->key, cm->vec->ck, cm->vec->ik);
|
osmo_auth_c3(ei->key, cm->vec->ck, cm->vec->ik);
|
||||||
else
|
|
||||||
|
for (i = 0; i < ei->perm_algo_len; i++) {
|
||||||
|
if (ei->perm_algo[i] != GSM0808_ALG_ID_A5_4)
|
||||||
|
continue;
|
||||||
|
/* A5/4 is included, so need to generate Kc128 */
|
||||||
|
osmo_kdf_kc128(cm->vec->ck, cm->vec->ik, cmc.kc128);
|
||||||
|
cmc.kc128_present = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
memcpy(ei->key, cm->vec->kc, sizeof(cm->vec->kc));
|
memcpy(ei->key, cm->vec->kc, sizeof(cm->vec->kc));
|
||||||
|
}
|
||||||
ei->key_len = sizeof(cm->vec->kc);
|
ei->key_len = sizeof(cm->vec->kc);
|
||||||
|
|
||||||
/* Store chosen GERAN key where the caller asked it to be stored.
|
/* Store chosen GERAN key where the caller asked it to be stored.
|
||||||
* alg_id remains unknown until we receive a Cipher Mode Complete from the BSC */
|
* alg_id remains unknown until we receive a Cipher Mode Complete from the BSC */
|
||||||
if (cm->geran.chosen_key) {
|
if (cm->geran.chosen_key) {
|
||||||
|
*cm->geran.chosen_key = (struct geran_encr){0};
|
||||||
|
|
||||||
if (ei->key_len > sizeof(cm->geran.chosen_key->key)) {
|
if (ei->key_len > sizeof(cm->geran.chosen_key->key)) {
|
||||||
LOG_RAN_A_ENC(fi, LOGL_ERROR, "Chosen key is larger than I can store\n");
|
LOG_RAN_A_ENC(fi, LOGL_ERROR, "Chosen key is larger than I can store\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memcpy(cm->geran.chosen_key->key, ei->key, ei->key_len);
|
memcpy(cm->geran.chosen_key->key, ei->key, ei->key_len);
|
||||||
cm->geran.chosen_key->key_len = ei->key_len;
|
cm->geran.chosen_key->key_len = ei->key_len;
|
||||||
|
|
||||||
|
if (cmc.kc128_present) {
|
||||||
|
memcpy(cm->geran.chosen_key->kc128, cmc.kc128, 16);
|
||||||
|
cm->geran.chosen_key->kc128_present = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_RAN_A_ENC(fi, LOGL_DEBUG, "Tx BSSMAP CIPHER MODE COMMAND to BSC, %u ciphers (%s) key %s\n",
|
LOG_RAN_A_ENC(fi, LOGL_DEBUG, "Tx BSSMAP CIPHER MODE COMMAND to BSC, %u ciphers (%s) key %s\n",
|
||||||
|
|
Loading…
Reference in New Issue