pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email )
Change subject: Move ConnHdlr logic to its own file ...................................................................... Move ConnHdlr logic to its own file Similar to what we do in other testsuites, since we start to have considrable amount of logic. Change-Id: If7edf8ee63c71fbf949e2d340cf3881fd8e3ba41 --- M 5gc/C5G_Tests.ttcn A 5gc/ConnHdlr.ttcn 2 files changed, 379 insertions(+), 321 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/52/40752/1 diff --git a/5gc/C5G_Tests.ttcn b/5gc/C5G_Tests.ttcn index 3b84a58..5fc5d4d 100644 --- a/5gc/C5G_Tests.ttcn +++ b/5gc/C5G_Tests.ttcn @@ -45,6 +45,8 @@ import from NG_NAS_Functions all; import from NG_CryptoFunctions all; +import from ConnHdlr all; + /* (maximum) number of emulated eNBs */ const integer NUM_NGRAN := 1; @@ -68,35 +70,13 @@ charstring mp_local_gtpu_ip := "127.0.0.1"; } -/* parameters of emulated gNB / ng-eNB */ -type record NGRANParams { - GlobalRANNodeID global_ngran_id, - NGRAN_CGI cell_identity, - SupportedTAList supported_ta_list -} - -/* parameters of emulated UE */ -type record UeParams { - HEX15n imsi, - HEX16n imeisv, - octetstring usim_key, - octetstring usim_opc, - charstring ran_gtpu_ip, - OCT4 ran_gtpu_teid, - charstring cn_gtpu_ip optional, - OCT4 cn_gtpu_teid optional, - charstring ue_ip optional, - OCT32 kausf optional, - OCT32 kseaf optional, - OCT32 kamf optional -} - template (value) UeParams ts_UeParams(integer imsi_suffix) := { imsi := f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, lengthof(mp_imsi) - 6), imsi_suffix), imeisv := f_rnd_imeisv(), usim_key := mp_usim_key, usim_opc := mp_usim_opc, + apn := mp_apn, ran_gtpu_ip := mp_local_gtpu_ip, ran_gtpu_teid := int2oct(imsi_suffix, 4), cn_gtpu_ip := omit, @@ -119,21 +99,6 @@ var UeParams g_ue_pars[NUM_UE]; } -type component ConnHdlr extends NGAP_ConnHdlr { - var ConnHdlrPars g_pars; -} - -type record ConnHdlrPars { - /* copied over from MTC_CT on start of component */ - NGRANParams ngran_pars[NUM_NGRAN], - /* copied over from MTC_CT on start of component */ - UeParams ue_pars, - /* currently used 5GC (index into ngran_pars, NGAP, ...) */ - integer c5g_idx, - /* Currently set KSI */ - NAS_KeySetIdentifier kset_id -} - /* send incoming unit data messages (like reset) to global NGAP_UNIT port */ private function NGapForwardUnitdataCallback(NGAP_PDU msg) runs on NGAP_Emulation_CT return template NGAP_PDU { @@ -213,8 +178,6 @@ return pars; } -type function void_fn() runs on ConnHdlr; - /* start a connection handler with given parameters */ private function f_start_handler_with_pars(void_fn fn, ConnHdlrPars pars, integer ngap_idx := 0) runs on MTC_CT return ConnHdlr { @@ -245,44 +208,6 @@ fn.apply(); } -private template (value) NGAP_IEs.TAI ts_ngran_NGAP_TAI(NGRANParams ngran_pars) := { - pLMNIdentity := ngran_pars.global_ngran_id.globalGNB_ID.pLMNIdentity, - tAC := ngran_pars.supported_ta_list[0].tAC, - iE_Extensions := omit -} - -private function f_imsi_plmn_id() runs on ConnHdlr return PLMNIdentity { - var hexstring imsi := g_pars.ue_pars.imsi; - var GsmMcc mcc := substr(imsi, 0, 3); - var GsmMnc mnc := substr(imsi, 3, 2); - return f_enc_mcc_mnc(mcc, mnc); -} - -private function f_SUCI_IMSI() runs on ConnHdlr return octetstring { - var hexstring imsi := g_pars.ue_pars.imsi; - var PLMNIdentity plmn_id := f_imsi_plmn_id(); - var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi) - 10, 10)); - return plmn_id & '21430001'O & imsi_suffix; -} - -private function f_UE_SecurityCapability() runs on ConnHdlr return NG_UE_SecurityCapability { - var template (value) NG_UE_SecurityCapability ue_sec_cap; - ue_sec_cap := cs_NG_UE_SecurityCapabilityTLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */ - ngiaCap := '40'O /* ONLY NIA1 supported */); - return valueof(ue_sec_cap); -} - -private function f_ULI() runs on ConnHdlr return UserLocationInformation { - var template (value) UserLocationInformation p_ueLocInf - p_ueLocInf := m_uPTransportLayerInformation_userLocationInformationNR( - m_userLocationInformationNR( - g_pars.ngran_pars[g_pars.c5g_idx].cell_identity.nR_CGI, - ts_ngran_NGAP_TAI(g_pars.ngran_pars[g_pars.c5g_idx]) - - )); - return valueof(p_ueLocInf); -} - private function f_ngap_setup(integer idx := 0, template (omit) NGAP_IEs.Cause cause := omit) runs on MTC_CT { var template (present) NGAP_IEs.Cause exp_cause := ?; var boolean exp_fail := false; @@ -323,249 +248,6 @@ } } -private function f_tr_ConnHdlr_kset_id() runs on ConnHdlr return template (present) NAS_KeySetIdentifier { - /* KSI not yet set, expect whatever assignment from network: */ - if (g_pars.kset_id.nasKeySetId == tsc_NasKsi_NoKey) { - return cr_NAS_KeySetIdentifier(?, ?); - } else { - /* Expect specific kset_id. Upon transmitting it UE->Network, f_attach() - * has updated it to the expected value. */ - return g_pars.kset_id; - } -} - -/* 3GPP TS 24.501 5.4.1.3.2, 3GPP TS 33.501 6.1.3.2 */ -private altstep as_ngap_handle_auth(boolean allow_resync := true) runs on ConnHdlr { - var NG_NAS_DL_Message_Type rx_nas; - var template (present) NAS_KeySetIdentifier kset_id := f_tr_ConnHdlr_kset_id(); - [] NGAP.receive(cr_NG_AUTHENTICATION_REQUEST) -> value rx_nas { - var integer ret; - var integer my_sqn := 0; /* TODO: move to a ConnHdlr state attribute? */ - var OCT16 rand := bit2oct(rx_nas.authentication_Request.rand.randValue); - var OCT16 autn := bit2oct(rx_nas.authentication_Request.autn.aUTN); - var OCT2 abba := rx_nas.authentication_Request.abba.abbaValue; - var OCT16 ik; - var OCT16 ck; - var OCT8 res; - var OCT14 auts; - - g_pars.kset_id := rx_nas.authentication_Request.ngNasKeySetId; - - ret := f_milenage_check(g_pars.ue_pars.usim_key, - g_pars.ue_pars.usim_opc, - int2oct(my_sqn, 8), - rand, autn, ik, ck, res, auts); - if (ret == -1) { - Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, - log2str("fx_milenage_check() failed! -1")); - } - if (ret == -2) { - if (not allow_resync) { - Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, - log2str("fx_milenage_check() unexpected Resync!")); - } - log("Milenage: RX-SQN differs from SIM SQN: Re-Sync! AUTS=", auts); - /* 3GPP TS 24.501 5.4.1.3.6 d) */ - NGAP.send(cs_NG_AUTHENTICATION_FAILURE(cs_GMM_GSM_Cause(omit, int2bit(21, 8)), - cs_AuthFailParam(oct2bit(auts)))); - as_ngap_handle_auth(allow_resync := false); - return; - } - - var octetstring ssn := f_NG_NAS_ServingNetworkName_OCT(f_imsi_plmn_id(), omit); - g_pars.ue_pars.kausf := f_kdf_kausf(ck, ik, ssn, autn); - g_pars.ue_pars.kseaf := f_kdf_kseaf(g_pars.ue_pars.kausf, ssn); - g_pars.ue_pars.kamf := f_kdf_kamf(g_pars.ue_pars.kseaf, char2oct(hex2str(g_pars.ue_pars.imsi)), abba); - - var NGAPEM_Config cfg := { - set_nas_keys := { - k_nas_int := f_kdf_ng_nas_int(g_pars.ue_pars.kamf, NG_NAS_ALG_IP_NIA1), - k_nas_enc := f_kdf_ng_nas_enc(g_pars.ue_pars.kamf, NG_NAS_ALG_ENC_NEA0) - } - }; - NGAP.send(cfg); - - /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4 */ - var OCT16 res_star := f_kdf_xres_star(ssn, ck, ik, rand, res); - NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(oct2bit(res_star)))); - } -} - -private altstep as_ngap_handle_sec_mode() runs on ConnHdlr { - var NGAPEM_Config cfg; - var NG_NAS_DL_Message_Type rx_nas; - /* Make sure network selected specific algos we requested: */ - var template (present) NG_UE_SecurityCapability ue_sec_cap := - cr_NG_UE_SecurityCapabilityLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */ - ngiaCap := '40'O /* ONLY NIA1 supported */); - - [] NGAP.receive(cr_NG_SECURITY_MODE_COMMAND(p_UECap := ue_sec_cap)) -> value rx_nas { - /* Configure integrity protection: */ - cfg := { - set_nas_alg_int := NG_NAS_ALG_IP_NIA1 - }; - NGAP.send(cfg); - /* Configure Ciphering: */ - cfg := { - set_nas_alg_enc := NG_NAS_ALG_ENC_NEA0 - }; - NGAP.send(cfg); - - var template (value) NG_NAS_UL_Message_Type nas_ul_msg; - var NAS_PDU nas_pdu; - nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B), - g_pars.kset_id.nasKeySetId, - g_pars.kset_id.tsc, - cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */, - f_SUCI_IMSI()), - p_UESecurityCap := f_UE_SecurityCapability()); - nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); - NGAP.send(cs_NG_SECURITY_MODE_COMPLETE(cs_NG_MobileIdentityTLV_IMEISV(hex2oct(g_pars.ue_pars.imeisv)), - cs_ReplayedNASMessageContainerTLV(nas_pdu))); - } -} - -private altstep as_ngap_handle_configuration_update() runs on ConnHdlr { - var NG_NAS_DL_Message_Type rx_nas; - - [] NGAP.receive(cr_NG_CONFIGURATION_UPDATE_COMMAND) -> value rx_nas { - NGAP.send(cs_NG_CONFIGURATION_UPDATE_COMPLETE); - } -} - -/* Handle a PDUSessionResourceSetupRequestTransfer contained inside NGAP InitialContextSetupRequest and return a Result for InitialContextSetupResponse */ -private function f_pdu_handle_session_resource_setup_item(PDUSessionResourceSetupItemCxtReq req) runs on ConnHdlr return PDUSessionResourceSetupItemCxtRes -{ - var PDUSessionResourceSetupItemCxtRes resp; - var octetstring setup_trans_enc; - var NGAP_IEs.PDUSessionResourceSetupRequestTransfer setup_req_transf; - var NGAP_IEs.PDUSessionResourceSetupResponseTransfer setup_resp_transf; - var template (value) UPTransportLayerInformation utla; - var template (value) QosFlowPerTNLInformation qos; - - /* Parse PDUSessionResourceSetupRequestTransfer contained inside InitialContextSetupRequest's PDUSessionResourceSetup Item: */ - setup_req_transf := dec_NGAP_PDUSessionResourceSetupRequestTransfer(req.pDUSessionResourceSetupRequestTransfer); - for (var integer i := 0; i < lengthof(setup_req_transf.protocolIEs); i := i + 1) { - if (setup_req_transf.protocolIEs[i].id == id_UL_NGU_UP_TNLInformation) { - var UPTransportLayerInformation utli := setup_req_transf.protocolIEs[i].value_.uPTransportLayerInformation; - g_pars.ue_pars.cn_gtpu_ip := f_inet_ntoa(bit2oct(utli.gTPTunnel.transportLayerAddress)); - g_pars.ue_pars.cn_gtpu_teid := utli.gTPTunnel.gTP_TEID; - } - } - - /* Prepare Response for it: */ - utla := m_uPTransportLayerInformation_gTPTunnel( - m_gTPTunnel(p_tla := oct2bit(f_inet_addr(g_pars.ue_pars.ran_gtpu_ip)), - p_gtp_teid := g_pars.ue_pars.ran_gtpu_teid)); - qos := m_qosFlowPerTNLInformation(utla, { m_associatedQosFlowItem(1) }); - setup_resp_transf := valueof(m_pDUSessionResourceSetupResponseTransfer(qos)); - setup_trans_enc := enc_NGAP_PDUSessionResourceSetupResponseTransfer(setup_resp_transf) - resp := valueof(m_pDUSessionResourceSetupItemCxtRes(req.pDUSessionID, setup_trans_enc)); - return resp; -} - -private function f_pdu_handle_session_resource_setup_list(PDUSessionResourceSetupListCxtReq li_req) runs on ConnHdlr return PDUSessionResourceSetupListCxtRes -{ - var PDUSessionResourceSetupListCxtRes li_resp; - for (var integer i := 0; i < lengthof(li_req); i := i + 1) { - var PDUSessionResourceSetupItemCxtRes it_resp; - it_resp := f_pdu_handle_session_resource_setup_item(li_req[i]); - if (i == 0) { /* min 1 item in list doesn't allow previously allocating an empty list */ - li_resp := { it_resp }; - } else { - li_resp := li_resp & { it_resp }; - } - } - return li_resp; -} - -private altstep as_ngap_handle_InitialCtxReq_withPDUSessionList() runs on ConnHdlr { - var NGAP_PDU rx_ngap; - - [] NGAP.receive(mw_ngap_initMsg(mw_n2_InitialContextSetupRequest_withPDUSessionList)) -> value rx_ngap { - var AMF_UE_NGAP_ID amf_id := valueof(f_NGAP_get_AMF_UE_NGAP_ID(rx_ngap)); - var RAN_UE_NGAP_ID ran_id := valueof(f_NGAP_get_RAN_UE_NGAP_ID(rx_ngap)); - var InitialContextSetupRequest ctx_setup_req := rx_ngap.initiatingMessage.value_.initialContextSetupRequest; - var PDUSessionResourceSetupListCxtRes resources; - - for (var integer i := 0; i < lengthof(ctx_setup_req.protocolIEs); i := i + 1) { - if (ctx_setup_req.protocolIEs[i].id != id_PDUSessionResourceSetupListCxtReq) { - continue; - } - var PDUSessionResourceSetupListCxtReq li := ctx_setup_req.protocolIEs[i].value_.pDUSessionResourceSetupListCxtReq; - resources := f_pdu_handle_session_resource_setup_list(li); - } - NGAP.send(m_ngap_succMsg(m_n2_InitialContextSetupResponse(amf_id, ran_id, resources))); - } -} - -private function f_pdu_sess_establish() runs on ConnHdlr { - var template (value) NG_NAS_UL_Message_Type nas_ul_msg; - var NAS_PDU nas_pdu; - var NG_NAS_DL_Message_Type rx_nas, inner_nas; - - nas_ul_msg := cs_NG_PDU_SESSION_ESTABLISHMENT_REQUEST(cs_NG_PDU_SessionIdV('01'O), '01'O, - p_IntegrityProtMaxDataRate := cs_IntegrityProtMaxDataRateV('FF'O, 'FF'O), - p_PDU_SessionType := cs_PDU_SessionTypeTV('001'B), /* IPv4 */ - p_SSC_Mode := cs_SSC_ModeTV('001'B)); - nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); - nas_ul_msg := cs_NG_UL_NAS_TRANSPORT(cs_PayloadContainerType(tsc_PayloadContainerESMMsg), - cs_PayloadContainerLV(nas_pdu), - p_PDU_SessionId := cs_NG_PDU_SessionIdTV('01'O), - p_RequestType := cs_NG_Request_TypeTV('001'B), - p_DNN := cs_DNN_TLV(f_enc_dns_hostname(mp_apn))); - NGAP.send(nas_ul_msg); - as_ngap_handle_InitialCtxReq_withPDUSessionList(); - - /* PDU Session Establishment Accept: This DL NAS arrives contained in InitialCtxReq handled above: */ - NGAP.receive(cr_NG_DL_NAS_TRANSPORT) -> value rx_nas; - inner_nas := f_dec_NG_NAS_DL_Message_Payload_Container(rx_nas.dl_Nas_Transport.payloadContainerType.container, - rx_nas.dl_Nas_Transport.payload.payload); - g_pars.ue_pars.ue_ip := f_inet_ntoa(inner_nas.pdu_Session_Establishment_Accept.pduAddress.adressInfo); - log("5GC assigned CN GTPU Address: ", g_pars.ue_pars.cn_gtpu_ip, " TEID: ", g_pars.ue_pars.cn_gtpu_teid); - log("5GC assigned UE IP address: ", g_pars.ue_pars.ue_ip); -} - -private function f_register() runs on ConnHdlr { - var template (value) NGAP_PDU tx_pdu; - var template (value) NG_NAS_UL_Message_Type nas_ul_msg; - var NAS_PDU nas_pdu; - var NG_NAS_DL_Message_Type rx_nas; - - nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B), - g_pars.kset_id.nasKeySetId, - g_pars.kset_id.tsc, - cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */, - f_SUCI_IMSI()), - p_UESecurityCap := f_UE_SecurityCapability()); - nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); - tx_pdu := m_ngap_initMsg(m_n2_initialUeMessage(g_pars.c5g_idx, - nas_pdu, /* Registration request */ - f_ULI(), - mo_Signalling)); - NGAP.send(tx_pdu); - - /* Expect updated KSI from network following 5G Core standards - *(open5gs.git 70310979c58fe186e9eaa06bec9d9a31f24ff7a1): */ - if (g_pars.kset_id.nasKeySetId != tsc_NasKsi_NoKey) { - if (g_pars.kset_id.nasKeySetId == '110'B) { - g_pars.kset_id.nasKeySetId := '000'B; - } else { - g_pars.kset_id.nasKeySetId := int2bit(bit2int(g_pars.kset_id.nasKeySetId) + 1, 3); - } - } - - as_ngap_handle_auth(); - as_ngap_handle_sec_mode(); - - NGAP.receive(cr_NG_REGISTRATION_ACCEPT) -> value rx_nas; - NGAP.send(cs_NG_REGISTRATION_COMPLETE); - - as_ngap_handle_configuration_update(); - - f_pdu_sess_establish(); -} - /* NG Setup procedure to 5GC using a Global gNB ID containing unknown/foreign PLMN. * Related: https://github.com/open5gs/open5gs/issues/3544 */ testcase TC_ng_setup_unknown_global_gnb_id_plmn() runs on MTC_CT { diff --git a/5gc/ConnHdlr.ttcn b/5gc/ConnHdlr.ttcn new file mode 100644 index 0000000..0f06447 --- /dev/null +++ b/5gc/ConnHdlr.ttcn @@ -0,0 +1,376 @@ +/* 5GC (55G Core) test suite in TTCN-3, ConnHdlr + * (C) 2025 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de> + * All rights reserved. + * Author: Pau Espin Pedrol <pes...@sysmocom.de> + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +module ConnHdlr { + +import from General_Types all; +import from Native_Functions all; +import from IPL4asp_Types all; +import from Misc_Helpers all; + +import from Osmocom_Types all; +import from GSM_Types all; + +import from DNS_Helpers all; + +import from Milenage_Functions all; + +import from NGAP_PDU_Descriptions all; +import from NGAP_IEs all; +import from NGAP_PDU_Contents all; +import from NGAP_Constants all; + +import from NGAP_Types all; +import from NGAP_Pixits all; +import from NGAP_Templates all; +import from NGAP_Functions all; +import from NGAP_Emulation all; + +import from NAS_CommonTypeDefs all; +import from NAS_CommonTemplates all; +import from NG_NAS_Common all; +import from NG_NAS_TypeDefs all; +import from NG_NAS_MsgContainers all; +import from NG_NAS_Templates all; + +import from NG_NAS_Osmo_Templates all; +import from NG_NAS_Functions all; +import from NG_CryptoFunctions all; + +/* (maximum) number of emulated eNBs */ +const integer NUM_NGRAN := 1; + +/* (maximum) number of emulated UEs */ +const integer NUM_UE := 1; + +/* parameters of emulated gNB / ng-eNB */ +type record NGRANParams { + GlobalRANNodeID global_ngran_id, + NGRAN_CGI cell_identity, + SupportedTAList supported_ta_list +} + +/* parameters of emulated UE */ +type record UeParams { + HEX15n imsi, + HEX16n imeisv, + octetstring usim_key, + octetstring usim_opc, + charstring apn, + charstring ran_gtpu_ip, + OCT4 ran_gtpu_teid, + charstring cn_gtpu_ip optional, + OCT4 cn_gtpu_teid optional, + charstring ue_ip optional, + OCT32 kausf optional, + OCT32 kseaf optional, + OCT32 kamf optional +} + +type record ConnHdlrPars { + /* copied over from MTC_CT on start of component */ + NGRANParams ngran_pars[NUM_NGRAN], + /* copied over from MTC_CT on start of component */ + UeParams ue_pars, + /* currently used 5GC (index into ngran_pars, NGAP, ...) */ + integer c5g_idx, + /* Currently set KSI */ + NAS_KeySetIdentifier kset_id +} + +type component ConnHdlr extends NGAP_ConnHdlr { + var ConnHdlrPars g_pars; +} + +type function void_fn() runs on ConnHdlr; + +private template (value) NGAP_IEs.TAI ts_ngran_NGAP_TAI(NGRANParams ngran_pars) := { + pLMNIdentity := ngran_pars.global_ngran_id.globalGNB_ID.pLMNIdentity, + tAC := ngran_pars.supported_ta_list[0].tAC, + iE_Extensions := omit +} + +private function f_imsi_plmn_id() runs on ConnHdlr return PLMNIdentity { + var hexstring imsi := g_pars.ue_pars.imsi; + var GsmMcc mcc := substr(imsi, 0, 3); + var GsmMnc mnc := substr(imsi, 3, 2); + return f_enc_mcc_mnc(mcc, mnc); +} + +private function f_SUCI_IMSI() runs on ConnHdlr return octetstring { + var hexstring imsi := g_pars.ue_pars.imsi; + var PLMNIdentity plmn_id := f_imsi_plmn_id(); + var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi) - 10, 10)); + return plmn_id & '21430001'O & imsi_suffix; +} + +private function f_UE_SecurityCapability() runs on ConnHdlr return NG_UE_SecurityCapability { + var template (value) NG_UE_SecurityCapability ue_sec_cap; + ue_sec_cap := cs_NG_UE_SecurityCapabilityTLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */ + ngiaCap := '40'O /* ONLY NIA1 supported */); + return valueof(ue_sec_cap); +} + +private function f_ULI() runs on ConnHdlr return UserLocationInformation { + var template (value) UserLocationInformation p_ueLocInf + p_ueLocInf := m_uPTransportLayerInformation_userLocationInformationNR( + m_userLocationInformationNR( + g_pars.ngran_pars[g_pars.c5g_idx].cell_identity.nR_CGI, + ts_ngran_NGAP_TAI(g_pars.ngran_pars[g_pars.c5g_idx]) + + )); + return valueof(p_ueLocInf); +} + +private function f_tr_ConnHdlr_kset_id() runs on ConnHdlr return template (present) NAS_KeySetIdentifier { + /* KSI not yet set, expect whatever assignment from network: */ + if (g_pars.kset_id.nasKeySetId == tsc_NasKsi_NoKey) { + return cr_NAS_KeySetIdentifier(?, ?); + } else { + /* Expect specific kset_id. Upon transmitting it UE->Network, f_attach() + * has updated it to the expected value. */ + return g_pars.kset_id; + } +} + +/* 3GPP TS 24.501 5.4.1.3.2, 3GPP TS 33.501 6.1.3.2 */ +private altstep as_ngap_handle_auth(boolean allow_resync := true) runs on ConnHdlr { + var NG_NAS_DL_Message_Type rx_nas; + var template (present) NAS_KeySetIdentifier kset_id := f_tr_ConnHdlr_kset_id(); + [] NGAP.receive(cr_NG_AUTHENTICATION_REQUEST) -> value rx_nas { + var integer ret; + var integer my_sqn := 0; /* TODO: move to a ConnHdlr state attribute? */ + var OCT16 rand := bit2oct(rx_nas.authentication_Request.rand.randValue); + var OCT16 autn := bit2oct(rx_nas.authentication_Request.autn.aUTN); + var OCT2 abba := rx_nas.authentication_Request.abba.abbaValue; + var OCT16 ik; + var OCT16 ck; + var OCT8 res; + var OCT14 auts; + + g_pars.kset_id := rx_nas.authentication_Request.ngNasKeySetId; + + ret := f_milenage_check(g_pars.ue_pars.usim_key, + g_pars.ue_pars.usim_opc, + int2oct(my_sqn, 8), + rand, autn, ik, ck, res, auts); + if (ret == -1) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("fx_milenage_check() failed! -1")); + } + if (ret == -2) { + if (not allow_resync) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("fx_milenage_check() unexpected Resync!")); + } + log("Milenage: RX-SQN differs from SIM SQN: Re-Sync! AUTS=", auts); + /* 3GPP TS 24.501 5.4.1.3.6 d) */ + NGAP.send(cs_NG_AUTHENTICATION_FAILURE(cs_GMM_GSM_Cause(omit, int2bit(21, 8)), + cs_AuthFailParam(oct2bit(auts)))); + as_ngap_handle_auth(allow_resync := false); + return; + } + + var octetstring ssn := f_NG_NAS_ServingNetworkName_OCT(f_imsi_plmn_id(), omit); + g_pars.ue_pars.kausf := f_kdf_kausf(ck, ik, ssn, autn); + g_pars.ue_pars.kseaf := f_kdf_kseaf(g_pars.ue_pars.kausf, ssn); + g_pars.ue_pars.kamf := f_kdf_kamf(g_pars.ue_pars.kseaf, char2oct(hex2str(g_pars.ue_pars.imsi)), abba); + + var NGAPEM_Config cfg := { + set_nas_keys := { + k_nas_int := f_kdf_ng_nas_int(g_pars.ue_pars.kamf, NG_NAS_ALG_IP_NIA1), + k_nas_enc := f_kdf_ng_nas_enc(g_pars.ue_pars.kamf, NG_NAS_ALG_ENC_NEA0) + } + }; + NGAP.send(cfg); + + /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4 */ + var OCT16 res_star := f_kdf_xres_star(ssn, ck, ik, rand, res); + NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(oct2bit(res_star)))); + } +} + +private altstep as_ngap_handle_sec_mode() runs on ConnHdlr { + var NGAPEM_Config cfg; + var NG_NAS_DL_Message_Type rx_nas; + /* Make sure network selected specific algos we requested: */ + var template (present) NG_UE_SecurityCapability ue_sec_cap := + cr_NG_UE_SecurityCapabilityLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */ + ngiaCap := '40'O /* ONLY NIA1 supported */); + + [] NGAP.receive(cr_NG_SECURITY_MODE_COMMAND(p_UECap := ue_sec_cap)) -> value rx_nas { + /* Configure integrity protection: */ + cfg := { + set_nas_alg_int := NG_NAS_ALG_IP_NIA1 + }; + NGAP.send(cfg); + /* Configure Ciphering: */ + cfg := { + set_nas_alg_enc := NG_NAS_ALG_ENC_NEA0 + }; + NGAP.send(cfg); + + var template (value) NG_NAS_UL_Message_Type nas_ul_msg; + var NAS_PDU nas_pdu; + nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B), + g_pars.kset_id.nasKeySetId, + g_pars.kset_id.tsc, + cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */, + f_SUCI_IMSI()), + p_UESecurityCap := f_UE_SecurityCapability()); + nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); + NGAP.send(cs_NG_SECURITY_MODE_COMPLETE(cs_NG_MobileIdentityTLV_IMEISV(hex2oct(g_pars.ue_pars.imeisv)), + cs_ReplayedNASMessageContainerTLV(nas_pdu))); + } +} + +private altstep as_ngap_handle_configuration_update() runs on ConnHdlr { + var NG_NAS_DL_Message_Type rx_nas; + + [] NGAP.receive(cr_NG_CONFIGURATION_UPDATE_COMMAND) -> value rx_nas { + NGAP.send(cs_NG_CONFIGURATION_UPDATE_COMPLETE); + } +} + +/* Handle a PDUSessionResourceSetupRequestTransfer contained inside NGAP InitialContextSetupRequest and return a Result for InitialContextSetupResponse */ +private function f_pdu_handle_session_resource_setup_item(PDUSessionResourceSetupItemCxtReq req) runs on ConnHdlr return PDUSessionResourceSetupItemCxtRes +{ + var PDUSessionResourceSetupItemCxtRes resp; + var octetstring setup_trans_enc; + var NGAP_IEs.PDUSessionResourceSetupRequestTransfer setup_req_transf; + var NGAP_IEs.PDUSessionResourceSetupResponseTransfer setup_resp_transf; + var template (value) UPTransportLayerInformation utla; + var template (value) QosFlowPerTNLInformation qos; + + /* Parse PDUSessionResourceSetupRequestTransfer contained inside InitialContextSetupRequest's PDUSessionResourceSetup Item: */ + setup_req_transf := dec_NGAP_PDUSessionResourceSetupRequestTransfer(req.pDUSessionResourceSetupRequestTransfer); + for (var integer i := 0; i < lengthof(setup_req_transf.protocolIEs); i := i + 1) { + if (setup_req_transf.protocolIEs[i].id == id_UL_NGU_UP_TNLInformation) { + var UPTransportLayerInformation utli := setup_req_transf.protocolIEs[i].value_.uPTransportLayerInformation; + g_pars.ue_pars.cn_gtpu_ip := f_inet_ntoa(bit2oct(utli.gTPTunnel.transportLayerAddress)); + g_pars.ue_pars.cn_gtpu_teid := utli.gTPTunnel.gTP_TEID; + } + } + + /* Prepare Response for it: */ + utla := m_uPTransportLayerInformation_gTPTunnel( + m_gTPTunnel(p_tla := oct2bit(f_inet_addr(g_pars.ue_pars.ran_gtpu_ip)), + p_gtp_teid := g_pars.ue_pars.ran_gtpu_teid)); + qos := m_qosFlowPerTNLInformation(utla, { m_associatedQosFlowItem(1) }); + setup_resp_transf := valueof(m_pDUSessionResourceSetupResponseTransfer(qos)); + setup_trans_enc := enc_NGAP_PDUSessionResourceSetupResponseTransfer(setup_resp_transf) + resp := valueof(m_pDUSessionResourceSetupItemCxtRes(req.pDUSessionID, setup_trans_enc)); + return resp; +} + +private function f_pdu_handle_session_resource_setup_list(PDUSessionResourceSetupListCxtReq li_req) runs on ConnHdlr return PDUSessionResourceSetupListCxtRes +{ + var PDUSessionResourceSetupListCxtRes li_resp; + for (var integer i := 0; i < lengthof(li_req); i := i + 1) { + var PDUSessionResourceSetupItemCxtRes it_resp; + it_resp := f_pdu_handle_session_resource_setup_item(li_req[i]); + if (i == 0) { /* min 1 item in list doesn't allow previously allocating an empty list */ + li_resp := { it_resp }; + } else { + li_resp := li_resp & { it_resp }; + } + } + return li_resp; +} + +private altstep as_ngap_handle_InitialCtxReq_withPDUSessionList() runs on ConnHdlr { + var NGAP_PDU rx_ngap; + + [] NGAP.receive(mw_ngap_initMsg(mw_n2_InitialContextSetupRequest_withPDUSessionList)) -> value rx_ngap { + var AMF_UE_NGAP_ID amf_id := valueof(f_NGAP_get_AMF_UE_NGAP_ID(rx_ngap)); + var RAN_UE_NGAP_ID ran_id := valueof(f_NGAP_get_RAN_UE_NGAP_ID(rx_ngap)); + var InitialContextSetupRequest ctx_setup_req := rx_ngap.initiatingMessage.value_.initialContextSetupRequest; + var PDUSessionResourceSetupListCxtRes resources; + + for (var integer i := 0; i < lengthof(ctx_setup_req.protocolIEs); i := i + 1) { + if (ctx_setup_req.protocolIEs[i].id != id_PDUSessionResourceSetupListCxtReq) { + continue; + } + var PDUSessionResourceSetupListCxtReq li := ctx_setup_req.protocolIEs[i].value_.pDUSessionResourceSetupListCxtReq; + resources := f_pdu_handle_session_resource_setup_list(li); + } + NGAP.send(m_ngap_succMsg(m_n2_InitialContextSetupResponse(amf_id, ran_id, resources))); + } +} + +private function f_pdu_sess_establish() runs on ConnHdlr { + var template (value) NG_NAS_UL_Message_Type nas_ul_msg; + var NAS_PDU nas_pdu; + var NG_NAS_DL_Message_Type rx_nas, inner_nas; + + nas_ul_msg := cs_NG_PDU_SESSION_ESTABLISHMENT_REQUEST(cs_NG_PDU_SessionIdV('01'O), '01'O, + p_IntegrityProtMaxDataRate := cs_IntegrityProtMaxDataRateV('FF'O, 'FF'O), + p_PDU_SessionType := cs_PDU_SessionTypeTV('001'B), /* IPv4 */ + p_SSC_Mode := cs_SSC_ModeTV('001'B)); + nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); + nas_ul_msg := cs_NG_UL_NAS_TRANSPORT(cs_PayloadContainerType(tsc_PayloadContainerESMMsg), + cs_PayloadContainerLV(nas_pdu), + p_PDU_SessionId := cs_NG_PDU_SessionIdTV('01'O), + p_RequestType := cs_NG_Request_TypeTV('001'B), + p_DNN := cs_DNN_TLV(f_enc_dns_hostname(g_pars.ue_pars.apn))); + NGAP.send(nas_ul_msg); + as_ngap_handle_InitialCtxReq_withPDUSessionList(); + + /* PDU Session Establishment Accept: This DL NAS arrives contained in InitialCtxReq handled above: */ + NGAP.receive(cr_NG_DL_NAS_TRANSPORT) -> value rx_nas; + inner_nas := f_dec_NG_NAS_DL_Message_Payload_Container(rx_nas.dl_Nas_Transport.payloadContainerType.container, + rx_nas.dl_Nas_Transport.payload.payload); + g_pars.ue_pars.ue_ip := f_inet_ntoa(inner_nas.pdu_Session_Establishment_Accept.pduAddress.adressInfo); + log("5GC assigned CN GTPU Address: ", g_pars.ue_pars.cn_gtpu_ip, " TEID: ", g_pars.ue_pars.cn_gtpu_teid); + log("5GC assigned UE IP address: ", g_pars.ue_pars.ue_ip); +} + +function f_register() runs on ConnHdlr { + var template (value) NGAP_PDU tx_pdu; + var template (value) NG_NAS_UL_Message_Type nas_ul_msg; + var NAS_PDU nas_pdu; + var NG_NAS_DL_Message_Type rx_nas; + + nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B), + g_pars.kset_id.nasKeySetId, + g_pars.kset_id.tsc, + cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */, + f_SUCI_IMSI()), + p_UESecurityCap := f_UE_SecurityCapability()); + nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg)); + tx_pdu := m_ngap_initMsg(m_n2_initialUeMessage(g_pars.c5g_idx, + nas_pdu, /* Registration request */ + f_ULI(), + mo_Signalling)); + NGAP.send(tx_pdu); + + /* Expect updated KSI from network following 5G Core standards + *(open5gs.git 70310979c58fe186e9eaa06bec9d9a31f24ff7a1): */ + if (g_pars.kset_id.nasKeySetId != tsc_NasKsi_NoKey) { + if (g_pars.kset_id.nasKeySetId == '110'B) { + g_pars.kset_id.nasKeySetId := '000'B; + } else { + g_pars.kset_id.nasKeySetId := int2bit(bit2int(g_pars.kset_id.nasKeySetId) + 1, 3); + } + } + + as_ngap_handle_auth(); + as_ngap_handle_sec_mode(); + + NGAP.receive(cr_NG_REGISTRATION_ACCEPT) -> value rx_nas; + NGAP.send(cs_NG_REGISTRATION_COMPLETE); + + as_ngap_handle_configuration_update(); + + f_pdu_sess_establish(); +} + +} -- To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email Gerrit-MessageType: newchange Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: If7edf8ee63c71fbf949e2d340cf3881fd8e3ba41 Gerrit-Change-Number: 40752 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pes...@sysmocom.de>