diff options
author | Eric Wild <ewild@sysmocom.de> | 2021-05-17 15:27:05 +0200 |
---|---|---|
committer | Hoernchen <ewild@sysmocom.de> | 2021-05-19 17:49:52 +0000 |
commit | 26f4a62642cd8ed984501b892e3d284a4f886790 (patch) | |
tree | e701074571614d55c4ac7ee982bdf3b888ab245a | |
parent | 1451f9f8602f19840d13951f89504ae4b1f1363f (diff) |
msc: add first a5/4 tests
All msc tests involving classmarks suffer from the same problem: if a
existing subscriber is reused the old classmarks will stick, since the
msc only overwrites updated parts of the cm when receiving a new cm, so
"downgrading" the existing classmark information is not possible.
This is circumvented here here by using different imsi suffixes,
the last param passed to f_start_handler.
Additionally the handler will now properly respond to cm requests
by the msc, i.e. in case the early cm is not sufficient for a5/4
because it lacks cm3, so the msc attempts once to query the cm,
hoping to get a cm3.
Related: SYS#5324
Change-Id: Idc055a006b325f58a5eafa88bc4415181b3500a2
-rw-r--r-- | library/BSSMAP_Templates.ttcn | 19 | ||||
-rw-r--r-- | msc/BSC_ConnectionHandler.ttcn | 62 | ||||
-rw-r--r-- | msc/MSC_Tests.ttcn | 82 | ||||
-rw-r--r-- | msc/expected-results.xml | 3 | ||||
-rwxr-xr-x | msc/gen_links.sh | 1 | ||||
-rwxr-xr-x | msc/regen_makefile.sh | 4 |
6 files changed, 165 insertions, 6 deletions
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn index 1949fd67..c6698b16 100644 --- a/library/BSSMAP_Templates.ttcn +++ b/library/BSSMAP_Templates.ttcn @@ -1498,6 +1498,13 @@ template BSSMAP_IE_ClassmarkInformationType2 ts_CM2_default := { } } + +template BSSMAP_IE_ClassmarkInformationType3 ts_CM3_default := { + elementIdentifier := '13'O, + lengthIndicator := 0, /* overwritten */ + classmark3ValuePart := '01'O /* A5/4 supported */ +} + template PDU_BSSAP ts_BSSMAP_ClassmarkUpd(template BSSMAP_IE_ClassmarkInformationType2 cm2 := ts_CM2_default, template BSSMAP_IE_ClassmarkInformationType3 cm3 := omit) modifies ts_BSSAP_BSSMAP := { @@ -1540,6 +1547,18 @@ modifies ts_BSSAP_BSSMAP := { } } +template PDU_BSSAP tr_BSSMAP_ClassmarkRequest +modifies tr_BSSAP_BSSMAP := { + pdu := { + bssmap := { + classmarkRequest := { + messageType := '58'O, + talkerPriority := * + } + } + } +} + /* return Layer3 octetstring inside BSSAP PDU */ function f_bssap_extract_l3(PDU_BSSAP bssap) return template octetstring { if (ischosen(bssap.pdu.bssmap)) { diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn index 8ca8264c..8eb3f733 100644 --- a/msc/BSC_ConnectionHandler.ttcn +++ b/msc/BSC_ConnectionHandler.ttcn @@ -12,6 +12,7 @@ module BSC_ConnectionHandler { +import from TCCOpenSecurity_Functions all; import from General_Types all; import from Osmocom_Types all; import from Native_Functions all; @@ -111,7 +112,7 @@ type record BSC_ConnHdlrPars { }; /* get a one-octet bitmaks of supported algorithms based on Classmark information */ -function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2) return OCT1 { +function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2, template (omit) BSSMAP_IE_ClassmarkInformationType3 cm3 := omit) return OCT1 { var BIT8 res := '00000001'B; /* A5/0 always supported */ if (cm2.a5_1 == '0'B) { @@ -123,7 +124,12 @@ function f_alg_mask_from_cm(BSSMAP_IE_ClassmarkInformationType2 cm2) return OCT1 if (cm2.classmarkInformationType2_oct5.a5_3 == '1'B) { res := res or4b '00001000'B; } - /* TODO: CM3 for A5/4 and beyond */ + if (not istemplatekind(cm3, "omit")) { + var BSSMAP_IE_ClassmarkInformationType3 v := valueof(cm3); + var BIT8 tmp := oct2bit(v.classmark3ValuePart[0]) and4b '00001111'B; + res := res or4b (tmp << 4); + } + return bit2oct(res); } @@ -155,6 +161,15 @@ function f_alg_from_mask(OCT1 mask_in) return integer { return -1; } +/* return true for A5/x supported by OCT1 bitmask */ +function f_alg_supported_by_mask(OCT1 mask_in, integer whicha5) return boolean { + var BIT8 mask := oct2bit(mask_in); + if (mask and4b ('00000001'B << whicha5) != '00000000'B) { + return true; + } + return false; +} + /* altstep for the global guard timer */ private altstep as_Tguard() runs on BSC_ConnHdlr { [] g_Tguard.timeout { @@ -420,6 +435,7 @@ var GSUP_IE auth_tuple; g_pars.vec.autn, g_pars.vec.res)); GSUP.send(ts_GSUP_SAI_RES(g_pars.imsi, auth_tuple)); + g_pars.vec.kc := f_auth3g_kc(); } else { g_pars.vec := f_gen_auth_vec_2g(); auth_tuple := valueof(ts_GSUP_IE_AuthTuple2G(g_pars.vec.rand, @@ -532,15 +548,49 @@ function f_expect_common_id() runs on BSC_ConnHdlr } } +function f_auth3g_kc() runs on BSC_ConnHdlr return OCT8 { + var integer i; + var octetstring res := g_pars.vec.ck[0] xor4b g_pars.vec.ck[0 + 8] xor4b g_pars.vec.ik[0] xor4b g_pars.vec.ik[0 + 8]; + for (i := 1; i < 8; i := i + 1) { + var octetstring a := g_pars.vec.ck[i] xor4b g_pars.vec.ck[i + 8] xor4b g_pars.vec.ik[i] xor4b g_pars.vec.ik[i + 8]; + res := res & a; + } + + return res; +} + + function f_mm_common() runs on BSC_ConnHdlr { f_mm_auth(); if (g_pars.ran_is_geran) { if (g_pars.net.expect_ciph) { - var OCT1 a5_net := f_alg_mask_from_cm(g_pars.cm2); + var OCT1 a5_net := f_alg_mask_from_cm(g_pars.cm2, g_pars.cm3); var OCT1 a5_intersect := g_pars.net.kc_support and4b a5_net; + var boolean has_a54 := f_alg_supported_by_mask(a5_intersect, 4); + + var PDU_BSSAP pdu; alt { - [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(a5_intersect, g_pars.vec.kc)) { + [] BSSAP.receive(tr_BSSMAP_CipherModeCmd(a5_intersect, g_pars.vec.kc)) -> value pdu { + var PDU_BSSMAP_CipherModeCommand ciphmodcmd := pdu.pdu.bssmap.cipherModeCommand; + if (g_pars.use_umts_aka and has_a54) { + var OCT32 fulloutput := f_calculate_HMAC_SHA256(g_pars.vec.ck & g_pars.vec.ik, '32'O, 32); + var OCT16 kc128 := substr(fulloutput, 0, 16); + if (not ispresent(ciphmodcmd.kC128)) { + setverdict(fail, "kc128 missing in CiphModCmd"); + mtc.stop; + } + if (ciphmodcmd.kC128.kC128_Value != kc128) { + setverdict(fail, "kc128 wrong in CiphModCmd?!", kc128); + mtc.stop; + } + } else { + if (ispresent(ciphmodcmd.kC128)) { + setverdict(fail, "kc128 present in CiphModCmd, but should not exist!"); + mtc.stop; + } + } + var OCT1 a5_chosen := f_best_alg_from_mask(a5_intersect); var integer a5_nr := f_alg_from_mask(a5_chosen); BSSAP.send(ts_BSSMAP_CipherModeCompl(int2oct(a5_nr+1, 1))); @@ -549,6 +599,10 @@ function f_mm_common() runs on BSC_ConnHdlr setverdict(fail, "Wrong ciphering algorithm mask in CiphModCmd"); mtc.stop; } + [] BSSAP.receive(tr_BSSMAP_ClassmarkRequest) { + BSSAP.send(ts_BSSMAP_ClassmarkUpd(g_pars.cm2, g_pars.cm3)) + repeat; + } } /* FIXME: Send the best available algorithm */ } diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn index 0fdc3761..b7917823 100644 --- a/msc/MSC_Tests.ttcn +++ b/msc/MSC_Tests.ttcn @@ -2009,6 +2009,84 @@ testcase TC_lu_imsi_auth_tmsi_encr_13_2() runs on MTC_CT { vc_conn.done; } +/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with only A5/1 support */ +private function f_tc_lu_imsi_auth_tmsi_encr_0134_1(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + pars.net.expect_auth := true; + pars.net.expect_ciph := true; + pars.net.kc_support := '03'O; /* A5/0 + A5/1 */ + pars.cm1.a5_1 := '0'B; + pars.cm2.a5_1 := '0'B; + pars.cm2.classmarkInformationType2_oct5.a5_3 := '0'B; + pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B; + pars.cm2.classmarkInformationType2_oct5.cm3 := '0'B; + pars.cm3 := omit; + pars.use_umts_aka := true; + + f_init_handler(pars, 15.0); + f_perform_lu(); +} +testcase TC_lu_imsi_auth_tmsi_encr_0134_1() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + f_vty_config(MSCVTY, "network", "encryption a5 0 1 3 4"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_1), 39); + vc_conn.done; +} + +/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with A5/3 + A5/4 support */ +private function f_tc_lu_imsi_auth_tmsi_encr_0134_34(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + pars.net.expect_auth := true; + pars.net.expect_ciph := true; + pars.net.kc_support := '19'O; /* A5/3 + A5/4 */ + pars.cm1.a5_1 := '1'B; + pars.cm2.a5_1 := '1'B; + pars.cm2.classmarkInformationType2_oct5.a5_3 := '1'B; + pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B; + pars.cm2.classmarkInformationType2_oct5.cm3 := '1'B; + pars.cm3 := valueof(ts_CM3_default); + pars.use_umts_aka := true; + + f_init_handler(pars, 15.0); + f_perform_lu(); +} +testcase TC_lu_imsi_auth_tmsi_encr_0134_34() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + f_vty_config(MSCVTY, "network", "encryption a5 0 1 3 4"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_34), 40); + vc_conn.done; +} + +/* A5/0 + A5/1 + A5/3 + a5/4 only permitted on network side, and MS with A5/3 support but no CM3 */ +private function f_tc_lu_imsi_auth_tmsi_encr_0134_34_no_cm3(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + pars.net.expect_auth := true; + pars.net.expect_ciph := true; + pars.net.kc_support := '19'O; /* A5/3 + A5/4 */ + pars.cm1.a5_1 := '1'B; + pars.cm2.a5_1 := '1'B; + pars.cm2.classmarkInformationType2_oct5.a5_3 := '1'B; + pars.cm2.classmarkInformationType2_oct5.a5_2 := '0'B; + pars.cm2.classmarkInformationType2_oct5.cm3 := '0'B; + pars.cm3 := omit; + pars.use_umts_aka := true; + + f_init_handler(pars, 15.0); + f_perform_lu(); +} +testcase TC_lu_imsi_auth_tmsi_encr_0134_34_no_cm3() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + f_vty_config(MSCVTY, "network", "authentication required"); + f_vty_config(MSCVTY, "network", "encryption a5 0 1 3 4"); + + vc_conn := f_start_handler(refers(f_tc_lu_imsi_auth_tmsi_encr_0134_34_no_cm3), 41); + vc_conn.done; +} + /* A5/0 + A5/1 + A5/3 only permitted on network side, and MS with only A5/2 support */ private function f_tc_lu_imsi_auth_tmsi_encr_013_2(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { pars.net.expect_auth := true; @@ -6458,6 +6536,10 @@ control { execute( TC_lu_imsi_auth_tmsi_encr_3_1_no_cm() ); execute( TC_lu_imsi_auth_tmsi_encr_13_2() ); execute( TC_lu_imsi_auth_tmsi_encr_013_2() ); + execute( TC_lu_imsi_auth_tmsi_encr_0134_1() ); + execute( TC_lu_imsi_auth_tmsi_encr_0134_34() ); + execute( TC_lu_imsi_auth_tmsi_encr_0134_34_no_cm3() ); + execute( TC_mo_release_timeout() ); execute( TC_lu_and_mt_call_no_dlcx_resp() ); execute( TC_reset_two() ); diff --git a/msc/expected-results.xml b/msc/expected-results.xml index a01cd224..4e2eeba4 100644 --- a/msc/expected-results.xml +++ b/msc/expected-results.xml @@ -56,6 +56,9 @@ <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_3_1_no_cm' time='MASKED'/> <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_13_2' time='MASKED'/> <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_013_2' time='MASKED'/> + <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_0134_1' time='MASKED'/> + <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_0134_34' time='MASKED'/> + <testcase classname='MSC_Tests' name='TC_lu_imsi_auth_tmsi_encr_0134_34_no_cm3' time='MASKED'/> <testcase classname='MSC_Tests' name='TC_mo_release_timeout' time='MASKED'/> <testcase classname='MSC_Tests' name='TC_lu_and_mt_call_no_dlcx_resp' time='MASKED'/> <testcase classname='MSC_Tests' name='TC_reset_two' time='MASKED'/> diff --git a/msc/gen_links.sh b/msc/gen_links.sh index 221110ea..b112a67f 100755 --- a/msc/gen_links.sh +++ b/msc/gen_links.sh @@ -11,6 +11,7 @@ gen_links $DIR $FILES DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h" FILES+=" TCCEncoding_Functions.ttcn TCCEncoding.cc " # GSM 7-bit coding +FILES+=" TCCOpenSecurity_Functions.ttcn TCCOpenSecurity.cc TCCOpenSecurity_Functions.hh" gen_links $DIR $FILES DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src diff --git a/msc/regen_makefile.sh b/msc/regen_makefile.sh index 6ee3ef5e..cbb491d0 100755 --- a/msc/regen_makefile.sh +++ b/msc/regen_makefile.sh @@ -1,9 +1,9 @@ #!/bin/sh -FILES="*.ttcn *.ttcnpp SCCP_EncDec.cc SCTPasp_PT.cc TCCConversion.cc TCCInterface.cc UD_PT.cc MNCC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc SDP_EncDec.cc RTP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc TELNETasp_PT.cc Native_FunctionDefs.cc SMPP_EncDec.cc SMPP_CodecPort_CtrlFunctDef.cc MAP_EncDec.cc SS_EncDec.cc TCCEncoding.cc SGsAP_CodecPort_CtrlFunctDef.cc RANAP_EncDec.cc *.c *.asn" +FILES="*.ttcn *.ttcnpp SCCP_EncDec.cc SCTPasp_PT.cc TCCConversion.cc TCCInterface.cc UD_PT.cc MNCC_EncDec.cc IPL4asp_PT.cc IPL4asp_discovery.cc SDP_EncDec.cc RTP_EncDec.cc IPA_CodecPort_CtrlFunctDef.cc RTP_CodecPort_CtrlFunctDef.cc MGCP_CodecPort_CtrlFunctDef.cc TELNETasp_PT.cc Native_FunctionDefs.cc SMPP_EncDec.cc SMPP_CodecPort_CtrlFunctDef.cc MAP_EncDec.cc SS_EncDec.cc TCCEncoding.cc SGsAP_CodecPort_CtrlFunctDef.cc RANAP_EncDec.cc TCCOpenSecurity.cc *.c *.asn" export CPPFLAGS_TTCN3="-DIPA_EMULATION_MGCP -DIPA_EMULATION_CTRL -DIPA_EMULATION_GSUP -DIPA_EMULATION_SCCP -DRAN_EMULATION_BSSAP -DRAN_EMULATION_MGCP -DRAN_EMULATION_CTRL -DRAN_EMULATION_RANAP -DUSE_MTP3_DISTRIBUTOR" ../regen-makefile.sh MSC_Tests.ttcn $FILES -sed -i -e 's/^LINUX_LIBS = -lxml2 -lsctp/LINUX_LIBS = -lxml2 -lsctp -lfftranscode/' Makefile +sed -i -e 's/^LINUX_LIBS = -lxml2 -lsctp/LINUX_LIBS = -lxml2 -lsctp -lfftranscode -lssl/' Makefile |