lynxis lazus has submitted this change. ( https://gerrit.osmocom.org/c/osmo-msc/+/43480?usp=email )
Change subject: libvlr: allow to use the same key slot for multiple ciphering commands ......................................................................
libvlr: allow to use the same key slot for multiple ciphering commands
An established security context can be used multiple times. In difference to re-use of the same auth tuple, which is a serious security flaw, re-using a security context is completely fine as long the context is not used forever.
Change-Id: I5c628ef4b43f7c22f62d1405cbe1f717a7918548 --- M include/osmocom/vlr/vlr.h M src/libmsc/msc_vty.c M src/libvlr/vlr_access_req_fsm.c M src/libvlr/vlr_auth_fsm.c M src/libvlr/vlr_auth_fsm.h M src/libvlr/vlr_lu_fsm.c M tests/msc_vlr/msc_vlr_test_authen_reuse.c M tests/msc_vlr/msc_vlr_tests.c 8 files changed, 55 insertions(+), 2 deletions(-)
Approvals: Jenkins Builder: Verified pespin: Looks good to me, approved
diff --git a/include/osmocom/vlr/vlr.h b/include/osmocom/vlr/vlr.h index 9fe2642..eac99b0 100644 --- a/include/osmocom/vlr/vlr.h +++ b/include/osmocom/vlr/vlr.h @@ -83,6 +83,7 @@
struct vlr_auth_tuple { int auth_use_count; + int ciph_use_count; int key_seq; struct osmo_auth_vector vec; }; @@ -282,6 +283,8 @@ bool check_imei_rqd; int auth_tuple_max_reuse_count; bool auth_reuse_old_sets_on_error; + /* how often a security context / cksq is re-used before a new auth tuple is used */ + int ciph_sec_ctx_max_reuse; bool parq_retrieve_imsi; bool is_ps; uint8_t nri_bitlen; diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index ef5c91e..a5de12f 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -532,7 +532,9 @@ "Configure authentication tuple re-use\n" "0 to use each auth tuple at most once (default), >0 to limit re-use, -1 to re-use infinitely (vulnerable!).\n") { - gsmnet->vlr->cfg.auth_tuple_max_reuse_count = atoi(argv[0]); + int count = atoi(argv[0]); + gsmnet->vlr->cfg.auth_tuple_max_reuse_count = count; + gsmnet->vlr->cfg.ciph_sec_ctx_max_reuse = count; return CMD_SUCCESS; }
diff --git a/src/libvlr/vlr_access_req_fsm.c b/src/libvlr/vlr_access_req_fsm.c index b1a75fd..5d2b7f9 100644 --- a/src/libvlr/vlr_access_req_fsm.c +++ b/src/libvlr/vlr_access_req_fsm.c @@ -322,6 +322,11 @@ return; }
+ if (!auth_ciph_sec_ctx_use(vsub, par->key_seq)) { + LOGPFSML(fi, LOGL_ERROR, "Cannot start ciphering, auth tuple not available, even when it should!\n"); + proc_arq_fsm_done(fi, GSM48_REJECT_NETWORK_FAILURE); + } + if (vlr_set_ciph_mode(vsub->vlr, fi, par->msc_conn_ref, vsub->sec_ctx, vsub->vlr->cfg.retrieve_imeisv_ciphered)) { @@ -341,7 +346,7 @@ * are defined in 3GPP TS 33.102 */ /* For now we use a default value passed in to vlr_lu_fsm(). */ return par->authentication_required || - (par->is_ciphering_to_be_attempted && !auth_try_reuse_tuple(par->vsub, par->key_seq)); + (par->is_ciphering_to_be_attempted && !auth_ciph_sec_ctx_is_usable(par->vsub, par->key_seq)); }
/* after the IMSI is known */ @@ -458,6 +463,9 @@ switch (event) { case PR_ARQ_E_AUTH_RES: /* Node 2 */ + OSMO_ASSERT(par->vsub); + OSMO_ASSERT(par->vsub->last_tuple); + par->key_seq = par->vsub->last_tuple->key_seq; _proc_arq_vlr_node2(fi); return;
diff --git a/src/libvlr/vlr_auth_fsm.c b/src/libvlr/vlr_auth_fsm.c index 176ef22..192e390 100644 --- a/src/libvlr/vlr_auth_fsm.c +++ b/src/libvlr/vlr_auth_fsm.c @@ -681,6 +681,36 @@ return fi; }
+bool auth_ciph_sec_ctx_is_usable(const struct vlr_subscr *vsub, uint8_t key_seq) +{ + int max_reuse_count = vsub->vlr->cfg.ciph_sec_ctx_max_reuse; + struct vlr_auth_tuple *at = vsub->last_tuple; + + if (key_seq == 0x7) /* No key available */ + return false; + if (!at) + return false; + if ((max_reuse_count >= 0) && (at->ciph_use_count > max_reuse_count)) + return false; + if (at->key_seq != key_seq) + return false; + + return true; +} + +bool auth_ciph_sec_ctx_use(struct vlr_subscr *vsub, uint8_t key_seq) +{ + struct vlr_auth_tuple *at = vsub->last_tuple; + + if (!auth_ciph_sec_ctx_is_usable(vsub, key_seq)) + return false; + + OSMO_ASSERT(at); + at->ciph_use_count++; + + return true; +} + bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq) { int max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count; diff --git a/src/libvlr/vlr_auth_fsm.h b/src/libvlr/vlr_auth_fsm.h index 1cb25b6..7a45a1a 100644 --- a/src/libvlr/vlr_auth_fsm.h +++ b/src/libvlr/vlr_auth_fsm.h @@ -40,3 +40,5 @@ void vlr_auth_fsm_init(bool is_ps); void vlr_auth_fsm_set_log_subsys(int log_level); bool auth_try_reuse_tuple(struct vlr_subscr *vsub, uint8_t key_seq); +bool auth_ciph_sec_ctx_is_usable(const struct vlr_subscr *vsub, uint8_t key_seq); +bool auth_ciph_sec_ctx_use(struct vlr_subscr *vsub, uint8_t key_seq); diff --git a/src/libvlr/vlr_lu_fsm.c b/src/libvlr/vlr_lu_fsm.c index f286450..d3aaf3a 100644 --- a/src/libvlr/vlr_lu_fsm.c +++ b/src/libvlr/vlr_lu_fsm.c @@ -964,6 +964,12 @@ return; }
+ if (!auth_ciph_sec_ctx_use(vsub, vsub->last_tuple->key_seq)) { + LOGPFSML(fi, LOGL_ERROR, "Cannot start ciphering, auth tuple not available, even when it should!\n"); + lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE); + return; + } + if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref, vsub->sec_ctx, vsub->vlr->cfg.retrieve_imeisv_ciphered)) { diff --git a/tests/msc_vlr/msc_vlr_test_authen_reuse.c b/tests/msc_vlr/msc_vlr_test_authen_reuse.c index a3be7b6..a75f4fc 100644 --- a/tests/msc_vlr/msc_vlr_test_authen_reuse.c +++ b/tests/msc_vlr/msc_vlr_test_authen_reuse.c @@ -38,6 +38,7 @@ net->authentication_required = true; net->vlr->cfg.assign_tmsi = true; net->vlr->cfg.auth_tuple_max_reuse_count = set_max_reuse_count; + net->vlr->cfg.ciph_sec_ctx_max_reuse = set_max_reuse_count; net->vlr->cfg.auth_reuse_old_sets_on_error = false; rx_from_ran = via_ran;
diff --git a/tests/msc_vlr/msc_vlr_tests.c b/tests/msc_vlr/msc_vlr_tests.c index c609381..008edfe 100644 --- a/tests/msc_vlr/msc_vlr_tests.c +++ b/tests/msc_vlr/msc_vlr_tests.c @@ -679,6 +679,7 @@ net->vlr->cfg.retrieve_imeisv_early = false; net->vlr->cfg.retrieve_imeisv_ciphered = false; net->vlr->cfg.auth_tuple_max_reuse_count = 0; + net->vlr->cfg.ciph_sec_ctx_max_reuse = 0; net->vlr->cfg.auth_reuse_old_sets_on_error = false;
rx_from_ran = OSMO_RAT_GERAN_A;