pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35570?usp=email )
Change subject: mme: Add code to derive NAS token from NAS ul_count ...................................................................... mme: Add code to derive NAS token from NAS ul_count NAS Token is derived from kasme and NAS ul_count as specified in 3GPP TS 33.401 A.9, and its LSB 16 bits passed to the network when mapping the GUTI to RAI+PTMSI+PTIMSI_SIG. Take the chance to move guti2rai_ptmsi() up to before the place it is used. Change-Id: I5e6003a2fe3e74cc93cfe4a288e6c114aa288d0b --- M library/S1AP_Emulation.ttcn M mme/LTE_CryptoFunctionDefs.cc M mme/LTE_CryptoFunctions.ttcn M mme/MME_Tests.ttcn M mme/key_derivation.c M mme/key_derivation.h 6 files changed, 100 insertions(+), 37 deletions(-) Approvals: Jenkins Builder: Verified fixeria: Looks good to me, but someone else must approve daniel: Looks good to me, approved diff --git a/library/S1AP_Emulation.ttcn b/library/S1AP_Emulation.ttcn index 1ef4a76..e3e3216 100644 --- a/library/S1AP_Emulation.ttcn +++ b/library/S1AP_Emulation.ttcn @@ -438,6 +438,7 @@ var S1APEM_Config s1cfg; var charstring vlr_name, mme_name; var integer ai; + var octetstring kasme; alt { /* Configuration primitive from client */ @@ -544,8 +545,13 @@ f_create_expect_proc(procedureCode, vc_conn); S1AP_PROC.reply(S1APEM_register_proc:{procedureCode, vc_conn}) to vc_conn; } + [] S1AP_PROC.getcall(S1APEM_derive_nas_token:{?, ?, -}) -> param(kasme, vc_conn) { + var integer assoc_id := f_assoc_id_by_comp(vc_conn); + var OCT32 nas_token := f_kdf_nas_token(kasme, S1apAssociationTable[assoc_id].nus.tx_count) + S1apAssociationTable[assoc_id].nus.tx_count := S1apAssociationTable[assoc_id].nus.tx_count + 1; + S1AP_PROC.reply(S1APEM_derive_nas_token:{kasme, vc_conn, nas_token}) to vc_conn; + } } - } } @@ -566,10 +572,12 @@ signature S1APEM_register(in MME_UE_S1AP_ID mme_id, in ENB_UE_S1AP_ID enb_id, in S1AP_ConnHdlr hdlr); signature S1APEM_register_proc(in integer procedureCode, in S1AP_ConnHdlr hdlr); +signature S1APEM_derive_nas_token(in octetstring kasme, in S1AP_ConnHdlr hdlr, out OCT32 nas_token); type port S1APEM_PROC_PT procedure { inout S1APEM_register; inout S1APEM_register_proc; + inout S1APEM_derive_nas_token; } with { extension "internal" }; /* Function that can be used as create_cb and will use the expect table */ @@ -669,6 +677,17 @@ log(procedureCode); } +/* Derive NAS Token (and post-increment ul_count): */ +function f_s1apem_derive_nas_token(in octetstring kasme) runs on S1AP_ConnHdlr return OCT32 +{ + var OCT32 nas_token; + S1AP_PROC.call(S1APEM_derive_nas_token:{kasme, self, -}) { + [] S1AP_PROC.getreply(S1APEM_derive_nas_token:{kasme, self, ?}) -> param(nas_token) { + return nas_token; + }; + } +} + private function f_expect_table_init() runs on S1AP_Emulation_CT { var integer i; diff --git a/mme/LTE_CryptoFunctionDefs.cc b/mme/LTE_CryptoFunctionDefs.cc index da2d521..7f82224 100644 --- a/mme/LTE_CryptoFunctionDefs.cc +++ b/mme/LTE_CryptoFunctionDefs.cc @@ -184,6 +184,14 @@ return OCTETSTRING(sizeof(kenb), kenb); } +OCTETSTRING f__kdf__nas__token(const OCTETSTRING &kasme, const INTEGER &ul_count) +{ + TTCN_Buffer ttcn_buf_kasme(kasme); + uint8_t nas_token[32]; + + mme_kdf_nas_token(ttcn_buf_kasme.get_data(), (int)ul_count, nas_token); + return OCTETSTRING(sizeof(nas_token), nas_token); +} } // namespace diff --git a/mme/LTE_CryptoFunctions.ttcn b/mme/LTE_CryptoFunctions.ttcn index 18a3755..f0ea990 100644 --- a/mme/LTE_CryptoFunctions.ttcn +++ b/mme/LTE_CryptoFunctions.ttcn @@ -40,6 +40,8 @@ external function f_kdf_nh(in OCT16 kasme, in OCT32 sync_inp) return OCT32; +external function f_kdf_nas_token(in OCT16 kasme, in integer ul_count) return OCT32; + /********************************************************************************* * mid-level API *********************************************************************************/ diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn index f4f41e2..50b89b3 100644 --- a/mme/MME_Tests.ttcn +++ b/mme/MME_Tests.ttcn @@ -83,6 +83,7 @@ hexstring imsi, charstring ue_ip, NAS_EPS_Types.GUTI guti optional, + octetstring kasme optional, /* TEI (Control) local side, S11 (SGW) */ OCT4 s11_teic_local, @@ -289,6 +290,7 @@ imsi := f_gen_imsi(imsi_suffix), ue_ip := "192.168.123.50", guti := omit, + kasme := omit, s11_teic_local := '00000000'O, s11_teic_remote := omit, s5c_teic_local := '00000000'O, @@ -585,11 +587,11 @@ const OCT3 plmn_id := '00F110'O; const OCT6 sqn := '000000000020'O; const OCT6 ak := substr(autn, 0, 6) xor4b sqn; - var octetstring kasme := f_kdf_kasme(ck, ik, plmn_id, sqn, ak); + g_pars.ue_pars.kasme := f_kdf_kasme(ck, ik, plmn_id, sqn, ak); var S1APEM_Config cfg := { set_nas_keys := { - k_nas_int := f_kdf_nas_int(1, kasme), - k_nas_enc := f_kdf_nas_enc(1, kasme) + k_nas_int := f_kdf_nas_int(1, g_pars.ue_pars.kasme), + k_nas_enc := f_kdf_nas_enc(1, g_pars.ue_pars.kasme) } }; S1AP.send(cfg); @@ -856,6 +858,31 @@ } } + +/* 3GPP TS 23.401 D.3.5, TS 23.003 2.8.2.1 */ +private function guti2rai_ptmsi(in NAS_EPS_Types.GUTI guti, in OCT2 truncated_nas_token, out RoutingAreaIdentity rai, out OCT4 ptmsi, out OCT3 ptmsi_sig) runs on ConnHdlr { + var bitstring mtmsi_bits := oct2bit(guti.mTMSI); + var bitstring ptmsi_bits; + var bitstring ptmsi_sig_bits; + + rai := valueof(ts_RoutingAreaIdentity(guti.mccDigit1 & guti.mccDigit2 & guti.mccDigit3, + guti.mncDigit3 & guti.mncDigit1 & guti.mncDigit2, + guti.mMEGI, guti.mMEC)); + /* 3GPP TS 23.003 2.8.2.0: "P-TMSI shall be of 32 bits length where the two topmost bits are + * reserved and always set to '11'. Hence, for a UE which may handover to GERAN/UTRAN (based on + * subscription and UE capabilities), the corresponding bits in the M-TMSI are set to '11'" + */ + ptmsi_bits := '11'B & substr(mtmsi_bits, 2, 6) & oct2bit(guti.mMEC) & substr(mtmsi_bits, 16, 16); + ptmsi_sig_bits := substr(mtmsi_bits, 8, 8) & oct2bit(truncated_nas_token); + ptmsi := bit2oct(ptmsi_bits); + ptmsi_sig := bit2oct(ptmsi_sig_bits); + /* TODO: The UE shall fill the remaining 2 octets of the <P-TMSI signature> according to clauses 9.1.1, 9.4.1, 10.2.1, or + * 10.5.1 of 3GPP TS.33.401 [89] , as appropriate, for RAU/Attach procedures.*/ +} + +/* Test UE attached to EUTRAN reselecting a GERAN cell. In this scenario, the + * new SGSN will attempt to obtain information of the UE from the old SGSN (MME) + * through Gn interface using SGSN Context Request/Response procedure (OS#6294). */ private function f_gtp_sgsn_context_4g_to_2g(OCT4 new_sgsn_local_teid := '12345678'O) runs on ConnHdlr { var template (value) GTPC_PDUs SGSNContextReqPDU; var RoutingAreaIdentity rai; @@ -864,7 +891,11 @@ var Gtp1cUnitdata gtpc_pdu; var OCT4 old_mme_local_teid; - guti2rai_ptmsi(g_pars.ue_pars.guti, rai, ptmsi, ptmsi_sig); + /* Derive NAS Token (and post-increment ul_count): */ + var OCT32 nas_token := f_s1apem_derive_nas_token(g_pars.ue_pars.kasme); + var OCT2 truncated_nas_token := substr(nas_token, 30, 2); + + guti2rai_ptmsi(g_pars.ue_pars.guti, truncated_nas_token, rai, ptmsi, ptmsi_sig); SGSNContextReqPDU := ts_SGSNContextReqPDU(rai, new_sgsn_local_teid, f_inet_addr(mp_gn_local_ip), ptmsi := ts_PTMSI(ptmsi), ptmsi_sig := ts_PTMSI_sig(ptmsi_sig)); @@ -880,10 +911,10 @@ setverdict(pass); } [] GTP.receive { - setverdict(fail, "unexpected GTPC message from MME"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("unexpected GTPC message from MME")); } [] T.timeout { - setverdict(fail, "no SGSN Context Response from MME"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("no SGSN Context Response from MME")); } } @@ -1312,36 +1343,6 @@ vc_conn.done; } -/* Test UE attached to EUTRAN reselecting a GERAN cell. In this scenario, the - * new SGSN will attempt to obtain information of the UE from the old SGSN (MME) - * through Gn interface using SGSN Context Request/Response procedure (OS#6294). */ -/* TS 23.003 2.8.2.1 */ -private function guti2rai_ptmsi(in NAS_EPS_Types.GUTI guti, out RoutingAreaIdentity rai, out OCT4 ptmsi, out OCT3 ptmsi_sig) runs on ConnHdlr { - var bitstring mtmsi_bits := oct2bit(guti.mTMSI); - var bitstring ptmsi_bits; - var bitstring ptmsi_sig_bits; - - rai := valueof(ts_RoutingAreaIdentity(guti.mccDigit1 & guti.mccDigit2 & guti.mccDigit3, - guti.mncDigit3 & guti.mncDigit1 & guti.mncDigit2, - guti.mMEGI, guti.mMEC)); - /* 3GPP TS 23.003 2.8.2.0: "P-TMSI shall be of 32 bits length where the two topmost bits are - * reserved and always set to '11'. Hence, for a UE which may handover to GERAN/UTRAN (based on - * subscription and UE capabilities), the corresponding bits in the M-TMSI are set to '11'" - */ - ptmsi_bits := '11'B & substr(mtmsi_bits, 2, 6) & oct2bit(guti.mMEC) & substr(mtmsi_bits, 16, 16); - ptmsi_sig_bits := substr(mtmsi_bits, 8, 8) & oct2bit('0000'O); - ptmsi := bit2oct(ptmsi_bits); - ptmsi_sig := bit2oct(ptmsi_sig_bits); - /* TODO: The UE shall fill the remaining 2 octets of the <P-TMSI signature> according to clauses 9.1.1, 9.4.1, 10.2.1, or - * 10.5.1 of 3GPP TS.33.401 [89] , as appropriate, for RAU/Attach procedures.*/ - /* TODO: 3GPP TS 33.401 9.1.1 The 16 least significant bits available in - * the P-TMSI signature field shall be filled with the truncated NAS-token - * according to 3GPP TS 23.003 [3].The truncated NAS-token is defined as the 16 - * least significant bits of the NAS-token. - * The NAS-token is derived as specified in Annex A.9. The UE shall use the uplink NAS COUNT value that it would use - * in the next NAS message to calculate the NAS-token and increase the stored uplink NAS COUNT value by 1.*/ - /* TODO: mMEC "also copied into the 8 Most Significant Bits of the NRI field within the P-TMSI" */ -} private function f_TC_ue_cell_reselect_eutran_to_geran(ConnHdlrPars pars) runs on ConnHdlr { f_init_handler(pars); f_gtp_register_imsi(g_pars.ue_pars.imsi); diff --git a/mme/key_derivation.c b/mme/key_derivation.c index 36e4c91..8d5d8a4 100644 --- a/mme/key_derivation.c +++ b/mme/key_derivation.c @@ -80,3 +80,19 @@ gnutls_hmac_fast(GNUTLS_MAC_SHA256, k, 32, s, 14, kasme); } + +/* TS33.401 Annex A.9: NAS token derivation for inter-RAT mobility */ +void mme_kdf_nas_token(const uint8_t *kasme, uint32_t ul_count, uint8_t *nas_token) +{ + uint8_t s[7]; + + s[0] = 0x17; /* FC Value */ + + ul_count = htonl(ul_count); + memcpy(s+1, &ul_count, 4); + + s[5] = 0x00; + s[6] = 0x04; + + gnutls_hmac_fast(GNUTLS_MAC_SHA256, kasme, 32, s, 7, nas_token); +} diff --git a/mme/key_derivation.h b/mme/key_derivation.h index 496f52b..ae15b65 100644 --- a/mme/key_derivation.h +++ b/mme/key_derivation.h @@ -19,3 +19,5 @@ void mme_kdf_enb(const uint8_t *kasme, uint32_t ul_count, uint8_t *kenb); void mme_kdf_nh(const uint8_t *kasme, const uint8_t *sync_input, uint8_t *kenb); + +void mme_kdf_nas_token(const uint8_t *kasme, uint32_t ul_count, uint8_t *nas_token); -- To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35570?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: I5e6003a2fe3e74cc93cfe4a288e6c114aa288d0b Gerrit-Change-Number: 35570 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pes...@sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillm...@sysmocom.de> Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de> Gerrit-Reviewer: pespin <pes...@sysmocom.de> Gerrit-MessageType: merged