/******************************************************************************/ // @copyright Copyright Notification // No part may be reproduced except as authorized by written permission. // The copyright and the foregoing restriction extend to reproduction in all media. // (c) 2023, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). // All rights reserved. // @version: IWD_23wk37 // $Date: 2020-11-21 16:39:02 +0100 (Sat, 21 Nov 2020) $ // $Rev: 29257 $ /******************************************************************************/ module NG_NasEmu_Common { import from CommonDefs all; import from NAS_CommonTypeDefs all; import from NAS_CommonTemplates all; import from NG_NAS_TypeDefs all; import from NG_NAS_Common all; import from NG_NAS_MsgContainers all; import from NG_NasEmu_CtrlAspTypes all; import from NasEmu_Common4G5G all; import from NG_SecurityDefinitionsAndExternalFunctions all; //**************************************************************************** // NAS emulation: Local definitions //---------------------------------------------------------------------------- // local type definitions: type union NG_NasEmu_DecodedNasPduUL_Type { /* Return type for f_NasEmu_DecodeMsg @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ NG_NAS_UL_Message_Type Msg, Null_Type Invalid }; type record NG_NasEmu_DecodingInfo_Type { /* Return type for f_DecipherAndDecodeNasPdu @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ NG_NAS_MSG_Indication_Type NasIndication optional, /* omit when octetstring cannot be decoded */ boolean IntegrityError }; type integer NG_NasEmu_SN; /* sequence number as usual (1 octet) @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // local templates: template (value) NG_NasEmu_DecodingInfo_Type cs_NG_DecodingInfo_Init := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ NasIndication := omit, IntegrityError := false }; //**************************************************************************** // NAS emulation: global information //---------------------------------------------------------------------------- type record NG_NasSecurity_Type { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ NG_NAS_SecurityInfo_Type Integrity, NG_NAS_SecurityInfo_Type Ciphering, NasCountInfo_Type NasCount, B5_Type BearerId, boolean SecurityStarted /* can be set to true after the download of security keys since ciphering is assumed for all security protected NAS PDUs in UL */ }; /* * @desc initialise the global information * @return NG_NasSecurity_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_NasSecurity_Init() return NG_NasSecurity_Type { return valueof(cs_NG_NasSecurity_Init); // valueof cannot be avoided here } //**************************************************************************** // NAS emulation: Configuration primitives //---------------------------------------------------------------------------- template (present) NG_NAS_CTRL_REQ cr_NG_NAS_CTRL_Security_REQ := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Common := ?, Request := { Security := ? } }; template (present) NG_NAS_CTRL_REQ cr_NG_NAS_CTRL_NasCount_REQ := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Common := ?, Request := { NasCount := ? } }; //---------------------------------------------------------------------------- template (value) NG_NAS_CTRL_CNF cs_NG_NAS_CTRL_Security_CNF := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Common := cs_NasCtrlCnfAspCommonPart, Confirm := { Security := true } }; template (value) NG_NAS_CTRL_CNF cs_NG_NAS_CTRL_NasCountSet_CNF := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Common := cs_NasCtrlCnfAspCommonPart, Confirm := { NasCount := { Set := true } } }; template (value) NG_NAS_CTRL_CNF cs_NG_NAS_CTRL_NasCountGet_CNF(template (value) NasCountInfo_Type p_NasCountInfo) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Common := cs_NasCtrlCnfAspCommonPart, Confirm := { NasCount := { Get := p_NasCountInfo } } }; //---------------------------------------------------------------------------- template (value) NG_NasSecurity_Type cs_NG_NasSecurity_Init := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Integrity := { Algorithm := '0000'B, K_NAS := int2bit(0, 128) }, Ciphering := { Algorithm := '0000'B, K_NAS := int2bit(0, 128) }, NasCount := { UL := f_NasCountInit(), DL := f_NasCountInit() }, BearerId := '00001'B, /* 3GPP Access */ SecurityStarted := false }; //**************************************************************************** // Templates: NAS Signalling //---------------------------------------------------------------------------- template (value) NG_NAS_DL_Message_Type cs_NG_SecurityProtected_NasMsg(SecurityHeaderType p_SecurityHeaderType, MessageAuthenticationCode p_MessageAuthenticationCode, NAS_SequenceNumber p_NAS_SequenceNumber, template (value) NG_NAS_Message p_NAS_Message) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ security_Protected_Nas_Message := { protocolDiscriminator := tsc_EPD_GMM, spareHalfOctet := tsc_SpareHalfOctet, securityHeaderType := p_SecurityHeaderType, messageAuthenticationCode := p_MessageAuthenticationCode, sequenceNumber := p_NAS_SequenceNumber, plainNASMessage := p_NAS_Message } }; template (value) PayloadContainer cs_PayloadContainer (template (omit) IEI8_Type p_IEI, octetstring p_EncodedGSMMsg) := { /* 24.501 cl. 9.11.3.39 */ /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ iei := p_IEI, iel := int2oct(lengthof(p_EncodedGSMMsg), 2), payload := p_EncodedGSMMsg }; //**************************************************************************** // NAS emulation: auxiliary functions //---------------------------------------------------------------------------- /* * @desc estimate COUNT (in UL) based on SN of received PDU and previous COUNT * Note: at the beginning COUNT is intialised with 0 as well as the SN at the UE * => an overflow is assumed when (previous SN > received SN) * @param p_PrevCount * @param p_SequenceNumber * @return NasCount_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasSecurity_EstimateCOUNT(NasCount_Type p_PrevCount, NG_NasEmu_SN p_SequenceNumber) return NasCount_Type { var integer v_PrevCountValue := oct2int(p_PrevCount); var integer v_CountValue; var integer v_MaxSnPlus1; var integer v_PrevSnValue; var integer v_ReceivedSnValue; var integer v_OverflowCounter; /* Note: for normal (long) SN this is the overflow counter as described in 24.301; for 5 bit SN it includes the 3 most significant bits of the least significant octet (what normally is the SN) */ v_ReceivedSnValue := p_SequenceNumber; v_MaxSnPlus1 := 256; v_OverflowCounter := v_PrevCountValue / v_MaxSnPlus1; v_PrevSnValue := v_PrevCountValue mod v_MaxSnPlus1; if (v_ReceivedSnValue < v_PrevSnValue) { // => overflow v_OverflowCounter := (v_OverflowCounter + 1) mod 65536; } v_CountValue := (v_OverflowCounter * v_MaxSnPlus1) + v_ReceivedSnValue; return int2oct(v_CountValue, 4); }; //**************************************************************************** // NAS emulation: Encoding/Decoding //---------------------------------------------------------------------------- /* * @desc wrapper function for encvalue * @param p_NasMessage * @return bitstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_EncvalueNAS(template (value) NG_NAS_DL_Message_Type p_NasMessage) return bitstring { return encvalue(p_NasMessage); }; /* * @desc wrapper function for decvalue * @param p_EncodedNasMessage (by reference) * @param p_NAS_UL_Message (by reference) * @return integer * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_DecvalueNAS(inout bitstring p_EncodedNasMessage, out NG_NAS_UL_Message_Type p_NAS_UL_Message) return integer { return decvalue(p_EncodedNasMessage, p_NAS_UL_Message); }; //---------------------------------------------------------------------------- /* * @desc return a the decoded NAS PDU (v_DecodedNasPduUL.Msg) or v_DecodedNasPduUL.Invalid * @param p_EncodedMsg * @return NG_NasEmu_DecodedNasPduUL_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_DecodeMsg(octetstring p_EncodedMsg) return NG_NasEmu_DecodedNasPduUL_Type { var bitstring v_NasPduBitstring; var NG_NAS_UL_Message_Type v_NAS_UL_Message; var NG_NasEmu_DecodedNasPduUL_Type v_DecodedNasPduUL; v_NasPduBitstring := oct2bit(p_EncodedMsg); if (f_NG_NasEmu_DecvalueNAS(v_NasPduBitstring, v_NAS_UL_Message) != 0) { /* v_NasPduBitstring needed as a variable since being 'inout' in decvalue v_NAS_UL_Message is out parameter i.e. needs not to be initialised */ f_NasEmulationError(__FILE__, __LINE__, "NAS message cannot be decoded"); v_DecodedNasPduUL.Invalid := true; } else { v_DecodedNasPduUL.Msg := v_NAS_UL_Message; } return v_DecodedNasPduUL; } /* * @desc check whether NAS message contains piggybacked message and decode it * Note: function is called recursively * @param p_NAS_UL_Message * @param p_NasSecurityByRef * @param p_NasCount * @return template (omit) NG_NAS_UL_PduList_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_DecodePiggybacked(NG_NAS_UL_Message_Type p_NAS_UL_Message, NG_NasSecurity_Type p_NasSecurityByRef, NasCount_Type p_NasCount) return template (omit) NG_NAS_UL_PduList_Type { var template (omit) NG_NAS_UL_PduList_Type v_NAS_UL_PduList := omit; var template (omit) NG_NAS_UL_Pdu_Type v_NAS_UL_Pdu := omit; var octetstring v_PiggybackedOctetString := ''O; var octetstring v_CipheredString := ''O; var octetstring v_NonCleartextString := ''O; // for CP Service Req var octetstring v_CleartextString := ''O; // for CP Service Req var NG_NasEmu_DecodedNasPduUL_Type v_DecodedNasPduUL; if (ischosen(p_NAS_UL_Message.ul_Nas_Transport)) { if (p_NAS_UL_Message.ul_Nas_Transport.payloadContainerType.container == tsc_PayloadContainerESMMsg) { // @sic R5w190208 sic@ // only decode if ESM Msg (other container types must be decoded in test case) v_PiggybackedOctetString := p_NAS_UL_Message.ul_Nas_Transport.payload.payload; } } else if (ischosen(p_NAS_UL_Message.security_Mode_Complete)) { if (ispresent(p_NAS_UL_Message.security_Mode_Complete.nasMsg)) { // In this case, the value will be unciphered (as the whole message is ciphered) v_PiggybackedOctetString := p_NAS_UL_Message.security_Mode_Complete.nasMsg.replayedNASMsgContainerValue; } } else if (ischosen(p_NAS_UL_Message.registration_Request)) { if (ispresent(p_NAS_UL_Message.registration_Request.nasMsg)) { v_CipheredString := p_NAS_UL_Message.registration_Request.nasMsg.replayedNASMsgContainerValue; } } else if (ischosen(p_NAS_UL_Message.service_Request)) { if (ispresent(p_NAS_UL_Message.service_Request.nasMsg)) { v_CipheredString := p_NAS_UL_Message.service_Request.nasMsg.replayedNASMsgContainerValue; } } else if (ischosen(p_NAS_UL_Message.cp_Service_Request)) { // @sic R5s201387 Baseline Moving sic@ // This doesn't contain the whole NAS msg, so must be treated separately if (ispresent(p_NAS_UL_Message.cp_Service_Request.cIoTSmallDataContainer)) { // if this is present, nothing else will be v_NonCleartextString := p_NAS_UL_Message.cp_Service_Request.cIoTSmallDataContainer.encodedstring; if (p_NasSecurityByRef.SecurityStarted) { // if security not started, do nothing and leave piggybacked msg as omit, else... // Decipher NAS container v_NonCleartextString := fx_NG_NasDeciphering(v_NonCleartextString, p_NasSecurityByRef.Ciphering.Algorithm, p_NasSecurityByRef.Ciphering.K_NAS, p_NasCount, p_NasSecurityByRef.BearerId); // replace this IE with the unciphered version p_NAS_UL_Message.cp_Service_Request.cIoTSmallDataContainer.encodedstring := v_NonCleartextString; // now return this whole message as the piggybacked message (all is now decoded and deciphered) v_NAS_UL_PduList[0].Msg := p_NAS_UL_Message; v_NAS_UL_PduList[0].PiggybackedPduList := omit; } } else if (ispresent(p_NAS_UL_Message.cp_Service_Request.nasMsg)) { v_NonCleartextString := p_NAS_UL_Message.cp_Service_Request.nasMsg.replayedNASMsgContainerValue; if (p_NasSecurityByRef.SecurityStarted) { // if security not started, do nothing and leave piggybacked msg as omit, else... // Decipher NAS container v_NonCleartextString := fx_NG_NasDeciphering(v_NonCleartextString, p_NasSecurityByRef.Ciphering.Algorithm, p_NasSecurityByRef.Ciphering.K_NAS, p_NasCount, p_NasSecurityByRef.BearerId); // remove this IE from the whole message p_NAS_UL_Message.cp_Service_Request.nasMsg := omit; // re-encode the message (now only the cleartext part) v_CleartextString := bit2oct(encvalue(p_NAS_UL_Message)); // then put these 2 parts together so the whole message can be decoded v_PiggybackedOctetString := v_CleartextString & v_NonCleartextString; } } } else { // NAS message does not contain piggybacked NAS message or decoding must be done in test case } if (lengthof(v_CipheredString) > 0) { // Only for those initial NAS messages with a ciphered NAS message container if (p_NasSecurityByRef.SecurityStarted) { // if security not started, do nothing and leave piggybacked msg as omit, else... // Decipher complete NAS message v_PiggybackedOctetString := fx_NG_NasDeciphering(v_CipheredString, p_NasSecurityByRef.Ciphering.Algorithm, p_NasSecurityByRef.Ciphering.K_NAS, p_NasCount, p_NasSecurityByRef.BearerId); } } // Now decode piggybacked message, if there is one (or more) if (lengthof(v_PiggybackedOctetString) > 0) { v_DecodedNasPduUL := f_NG_NasEmu_DecodeMsg(v_PiggybackedOctetString); if (ischosen(v_DecodedNasPduUL.Invalid)) { // do nothing i.e. keep v_NAS_UL_Pdu as omit } else { v_NAS_UL_Pdu.Msg := v_DecodedNasPduUL.Msg; // recursive call: check whether piggybacked message contains further piggybacked messages v_NAS_UL_Pdu.PiggybackedPduList := f_NG_NasEmu_DecodePiggybacked(v_DecodedNasPduUL.Msg, p_NasSecurityByRef, p_NasCount); } v_NAS_UL_PduList[0] := v_NAS_UL_Pdu; // only one PDU piggybacked considered } return v_NAS_UL_PduList; } //---------------------------------------------------------------------------- /* * @desc encode piggybacked (GSM) message and add it to the NAS PDU * Note: if there is a piggybacked GSM message the whole IE of the GMM ie replaced (i.e. not only the octetstring) * @param p_NAS_DL_Pdu * @return octetstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NasEmu_EncodePiggybacked(NG_NAS_DL_Pdu_Type p_NAS_DL_Pdu) return octetstring { var template (value) NG_NAS_DL_Message_Type v_NAS_DL_Message := p_NAS_DL_Pdu.Msg; var NG_NAS_DL_PduList_Type v_PiggybackedPduList; var NG_NAS_DL_Pdu_Type v_PiggybackedPDU; var integer v_NoOfPiggybacked; var octetstring v_EncodedPiggybackedMsg; if (ispresent(p_NAS_DL_Pdu.PiggybackedPduList)) { v_PiggybackedPduList := p_NAS_DL_Pdu.PiggybackedPduList; v_NoOfPiggybacked := lengthof(v_PiggybackedPduList); } else { v_NoOfPiggybacked := 0; } if (v_NoOfPiggybacked > 0) { v_PiggybackedPDU := v_PiggybackedPduList[0]; v_EncodedPiggybackedMsg := bit2oct(f_NG_NasEmu_EncvalueNAS(v_PiggybackedPDU.Msg)); if (v_NoOfPiggybacked > 1) { f_NasEmulationError(__FILE__, __LINE__, "number of piggybacked PDUs is > 1 but only one piggy-backed message is considered"); } if (ispresent(v_PiggybackedPDU.PiggybackedPduList)) { f_NasEmulationError(__FILE__, __LINE__, "Only one piggy-backed message is considered"); /* piggybacking for the piggybacked PDU is ignored */ } if (ischosen(v_NAS_DL_Message.dl_Nas_Transport)) { v_NAS_DL_Message.dl_Nas_Transport.payload := cs_PayloadContainer(omit, v_EncodedPiggybackedMsg); } else { f_NasEmulationError(__FILE__, __LINE__, "NAS message can not carry piggy-backed NAS PDU"); /* piggy backed message is ignored */ } } return bit2oct(f_NG_NasEmu_EncvalueNAS(v_NAS_DL_Message)); } //**************************************************************************** // DL ASP Handling //---------------------------------------------------------------------------- /* * @desc encode and cipher NAS PDU * @param p_NasSecurityByRef (by reference) * @param p_NAS_MSG_Request * @return octetstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_EncodeAndCipher_NG_NasPdu(inout NG_NasSecurity_Type p_NasSecurityByRef, NG_NAS_MSG_Request_Type p_NAS_MSG_Request) return octetstring { var SecurityHeaderType v_SecurityStatus := p_NAS_MSG_Request.SecurityProtection.Status; var boolean v_ForceMacError := p_NAS_MSG_Request.SecurityProtection.ForceMacError; var octetstring v_EncodedNasPdu; var NasCount_Type v_CountDL; var MessageAuthenticationCode v_CalculatedMac; var NAS_SequenceNumber v_SequenceNumber; var octetstring v_Octet7toN; v_EncodedNasPdu := f_NG_NasEmu_EncodePiggybacked(p_NAS_MSG_Request.Pdu); if (v_SecurityStatus != tsc_SHT_NoSecurityProtection) { if (not p_NasSecurityByRef.SecurityStarted) { f_NasEmulationError(__FILE__, __LINE__, "security is not started"); /* => PDU will not be security protected */ } else { // INCREMENT DL NAS COUNT: v_CountDL := f_NasSecurity_IncrementCOUNT(p_NasSecurityByRef.NasCount.DL); p_NasSecurityByRef.NasCount.DL := v_CountDL; // APPLY CIPHERING (if necessary): if ((v_SecurityStatus == tsc_SHT_IntegrityProtected_Ciphered) or (v_SecurityStatus == tsc_SHT_IntegrityProtected_Ciphered_NewSecurityContext)) { v_EncodedNasPdu := fx_NG_NasCiphering(v_EncodedNasPdu, p_NasSecurityByRef.Ciphering.Algorithm, p_NasSecurityByRef.Ciphering.K_NAS, v_CountDL, p_NasSecurityByRef.BearerId); } // APPLY INTEGRITY PROTECTION: v_SequenceNumber := f_NasSecurity_ExtractSNfromCOUNT(v_CountDL); v_Octet7toN := v_SequenceNumber & v_EncodedNasPdu; v_CalculatedMac := fx_NG_NasIntegrityAlgorithm(v_Octet7toN, p_NasSecurityByRef.Integrity.Algorithm, p_NasSecurityByRef.Integrity.K_NAS, v_CountDL, p_NasSecurityByRef.BearerId, tsc_DirectionDL); if (v_ForceMacError) { v_CalculatedMac := not4b v_CalculatedMac; // O4_Type } // build up SECURITY PROTECTED NAS message v_EncodedNasPdu := bit2oct(f_NG_NasEmu_EncvalueNAS(cs_NG_SecurityProtected_NasMsg(v_SecurityStatus, v_CalculatedMac, v_SequenceNumber, v_EncodedNasPdu))); } } return v_EncodedNasPdu; } //**************************************************************************** // UL ASP Handling //---------------------------------------------------------------------------- template (value) NG_NAS_MSG_Indication_Type cs_NG_NAS_MSG_Indication(NG_NasSecurity_Type p_NasSecurityByRef, SecurityHeaderType p_NAS_SecurityStatus, NasCount_Type p_NasCount, NG_NAS_UL_Message_Type p_NAS_UL_Message) := { /* local type templates (uses f_NG_NasEmu_DecodePiggybacked) */ /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ SecurityProtection:= { Status := p_NAS_SecurityStatus, NasCount := p_NasCount }, Pdu := { Msg := p_NAS_UL_Message, PiggybackedPduList := f_NG_NasEmu_DecodePiggybacked(p_NAS_UL_Message, p_NasSecurityByRef, p_NasCount) } }; template (value) NG_NAS_MSG_Indication_Type cs_NG_NAS_PDU_Ind(SecurityHeaderType p_NAS_SecurityStatus, NasCount_Type p_NasCount, NG_NAS_UL_Message_Type p_NAS_UL_Message, template (omit) NG_NAS_UL_PduList_Type p_Piggybacked := omit) := { /* local type templates (used to hold both Registration Reqs) */ SecurityProtection:= { Status := p_NAS_SecurityStatus, NasCount := p_NasCount }, Pdu := { Msg := p_NAS_UL_Message, PiggybackedPduList := p_Piggybacked } }; /* * @desc Decipher and decode NAS PDU * Notes: * - When receiving a security protected NAS PDU firstly deceiphering is applied; integrity protection is applied on the deciphered NAS PDU; * - Deciphering is applied on the encoded NAS PDU only (but not on any other IE of SECURITY PROTECTED NAS MESSAGE) since the SN is used for deciphering; * - if the NAS PDU is security protected (without error) the UL NAS COUNT is incremented * @param p_NasSecurityByRef (by reference) * @param p_NAS_DedicatedInformation * @return template (value) NG_NasEmu_DecodingInfo_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_DecipherAndDecodeNasPdu(inout NG_NasSecurity_Type p_NasSecurityByRef, octetstring p_NAS_DedicatedInformation) return template (value) NG_NasEmu_DecodingInfo_Type { var template (value) NG_NasEmu_DecodingInfo_Type v_DecodingInfo := cs_NG_DecodingInfo_Init; // NasIndication := omit, IntegrityError := false var NG_NasEmu_DecodedNasPduUL_Type v_DecodedNasPduUL; var octetstring v_IntegrityProtectedOctets; var NG_SECURITY_PROTECTED_NAS_MESSAGE v_SecurityProtectedNasMsg; var MessageAuthenticationCode v_ContainedMac; var MessageAuthenticationCode v_CalculatedMac; var NG_NasEmu_SN v_SequenceNumber; var NG_NAS_Message v_EncodedNasPdu; var NasCount_Type v_CountUL; var SecurityHeaderType v_SecurityHeader; // Decode NAS message: message is either SECURITY_PROTECTED_NAS_MESSAGE or non-protected NAS message v_DecodedNasPduUL := f_NG_NasEmu_DecodeMsg(p_NAS_DedicatedInformation); if (ischosen(v_DecodedNasPduUL.Invalid)) { return v_DecodingInfo; // v_DecodingInfo is {omit, false} } if (ischosen(v_DecodedNasPduUL.Msg.security_Protected_Nas_Message)) { // SECURITY_PROTECTED_NAS_MESSAGE v_SecurityProtectedNasMsg := v_DecodedNasPduUL.Msg.security_Protected_Nas_Message; v_SecurityHeader := v_SecurityProtectedNasMsg.securityHeaderType; v_ContainedMac := v_SecurityProtectedNasMsg.messageAuthenticationCode; v_SequenceNumber := oct2int(v_SecurityProtectedNasMsg.sequenceNumber); v_EncodedNasPdu := v_SecurityProtectedNasMsg.plainNASMessage; v_CountUL := f_NG_NasSecurity_EstimateCOUNT(p_NasSecurityByRef.NasCount.UL, v_SequenceNumber); if ((not p_NasSecurityByRef.SecurityStarted) and (v_SecurityHeader != tsc_SHT_IntegrityProtected)) { /* Note: A UE is allowed to transmit a security protected Reg request (Security header set to '0001'B) * at the initial registration in case the USIM used has a valid security context */ f_NasEmulationError(__FILE__, __LINE__, "security protected PDU received but security is not started"); return v_DecodingInfo; // v_DecodingInfo is {omit, false} } else { if (p_NasSecurityByRef.SecurityStarted) { // CHECK INTEGRITY v_IntegrityProtectedOctets := v_SecurityProtectedNasMsg.sequenceNumber & v_EncodedNasPdu; v_CalculatedMac := fx_NG_NasIntegrityAlgorithm(v_IntegrityProtectedOctets, p_NasSecurityByRef.Integrity.Algorithm, p_NasSecurityByRef.Integrity.K_NAS, v_CountUL, p_NasSecurityByRef.BearerId, tsc_DirectionUL); if (v_ContainedMac == v_CalculatedMac) { p_NasSecurityByRef.NasCount.UL := v_CountUL; /* write back the latest count value */ } else { // UL NAS COUNT is not updated in case of integrity error v_DecodingInfo.IntegrityError := true; } // DECIPHERING: if ((v_SecurityHeader == tsc_SHT_IntegrityProtected_Ciphered) or (v_SecurityHeader == tsc_SHT_IntegrityProtected_Ciphered_NewSecurityContext)) { v_EncodedNasPdu := fx_NG_NasDeciphering(v_EncodedNasPdu, p_NasSecurityByRef.Ciphering.Algorithm, p_NasSecurityByRef.Ciphering.K_NAS, v_CountUL, p_NasSecurityByRef.BearerId); } } else { // NAS security not started yet, but e.g. in case of REG REQ p_NasSecurityByRef.NasCount.UL := v_CountUL; /* write back the latest count value */ } // Decode NAS message v_DecodedNasPduUL := f_NG_NasEmu_DecodeMsg(v_EncodedNasPdu); if (ischosen(v_DecodedNasPduUL.Invalid)) { // Do nothing: v_DecodingInfo.NasIndication remains omit } else { v_DecodingInfo.NasIndication := cs_NG_NAS_MSG_Indication(p_NasSecurityByRef, v_SecurityHeader, v_CountUL, v_DecodedNasPduUL.Msg); } } } else { // non security protected PDU v_DecodingInfo.NasIndication := cs_NG_NAS_MSG_Indication(p_NasSecurityByRef, tsc_SHT_NoSecurityProtection, p_NasSecurityByRef.NasCount.UL, /* Note: NAS-Count shall be ignored by the test case in case of non-protected messages */ v_DecodedNasPduUL.Msg); } return v_DecodingInfo; } //**************************************************************************** // Configuration Handling //---------------------------------------------------------------------------- /* * @desc handle configuration of the NAS emulation (NAS_CTRL_REQ) * @param p_Port * @param p_NasSecurityByRef (by reference) * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ altstep a_NG_NasEmu_ConfigurationHandler(NG_NASEMU_CTRL_PORT p_Port, inout NG_NasSecurity_Type p_NasSecurityByRef) { var NG_NAS_CTRL_REQ v_ConfigAsp; var NasCountInfo_Type v_NasCountInfo; [] p_Port.receive(cr_NG_NAS_CTRL_Security_REQ) -> value v_ConfigAsp { /* NAS SECURITY */ if (ischosen(v_ConfigAsp.Request.Security.StartRestart)) { /* Start NAS Security */ p_NasSecurityByRef.SecurityStarted := true; p_NasSecurityByRef.Integrity := v_ConfigAsp.Request.Security.StartRestart.Integrity; p_NasSecurityByRef.Ciphering := v_ConfigAsp.Request.Security.StartRestart.Ciphering; if (ispresent(v_ConfigAsp.Request.Security.StartRestart.NasCountReset)) { p_NasSecurityByRef.NasCount.UL := f_NasCountInit(); p_NasSecurityByRef.NasCount.DL := f_NasCountInit(); } } else { /* Release: Reset NAS Security */ p_NasSecurityByRef := f_NG_NasEmu_NasSecurity_Init(); } if (v_ConfigAsp.Common.ControlInfo.CnfFlag) { p_Port.send(cs_NG_NAS_CTRL_Security_CNF); } } [] p_Port.receive(cr_NG_NAS_CTRL_NasCount_REQ) -> value v_ConfigAsp { /* NAS COUNT */ if (ischosen(v_ConfigAsp.Request.NasCount.Set)) { v_NasCountInfo := v_ConfigAsp.Request.NasCount.Set; if (ispresent(v_NasCountInfo.UL)) { p_NasSecurityByRef.NasCount.UL := v_NasCountInfo.UL; } /* else: keep as it is */ if (ispresent(v_NasCountInfo.DL)) { p_NasSecurityByRef.NasCount.DL := v_NasCountInfo.DL; } /* else: keep as it is */ if (v_ConfigAsp.Common.ControlInfo.CnfFlag) { p_Port.send(cs_NG_NAS_CTRL_NasCountSet_CNF); } } else if (ischosen(v_ConfigAsp.Request.NasCount.Get)) { if (v_ConfigAsp.Common.ControlInfo.CnfFlag) { p_Port.send(cs_NG_NAS_CTRL_NasCountGet_CNF(p_NasSecurityByRef.NasCount)); } } } } }