/******************************************************************************/ // @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: 2023-03-21 13:21:41 +0100 (Tue, 21 Mar 2023) $ // $Rev: 35672 $ /******************************************************************************/ module NG_NAS_SecurityFunctions { import from CommonDefs all; import from NAS_CommonTypeDefs all; import from NAS_AuthenticationCommon all; import from NG_NasEmu_CtrlAspTypes all; import from EUTRA_NR_SecurityFunctions all; import from Parameters all; import from NAS_5GC_Parameters all; import from EAP_TypeDefs all; //============================================================================ // constants and types type record NG_NAS_SecurityParams_Type { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // Keys shared with NR KDF_Type KDF, B3_Type KSIamf, // 3 bit KSIasme used when Authentication is performed by MME. B256_Type Ks, // = Ck || IK B256_Type KAMF, // NAS keys bitstring MK, // Master key MK in RFC 5448 to be used to derive other keys acc. TS 33.501 cl. 6.2.1 B256_Type KAUSF, B256_Type KSEAF, octetstring ABBA, // NAS Security structures NG_NAS_SecurityInfo_Type NAS_Integrity, NG_NAS_SecurityInfo_Type NAS_Ciphering, Common_AuthenticationParams_Type AuthParams }; //============================================================================ // TEMPLATES //---------------------------------------------------------------------------- const B4_Type tsc_NG_Integrity_Snow3G := '0001'B; /* @status APPROVED (NR5GC) */ const B4_Type tsc_NG_Integrity_AES := '0010'B; /* @status APPROVED (NR5GC) */ const B4_Type tsc_NG_Integrity_ZUC := '0011'B; /* @status APPROVED (NR5GC) */ const B4_Type tsc_NG_Encryption_Snow3G := '0001'B; /* @status APPROVED (NR5GC) */ const B4_Type tsc_NG_Encryption_AES := '0010'B; /* @status APPROVED (NR5GC) */ const B4_Type tsc_NG_Encryption_ZUC := '0011'B; /* @status APPROVED (NR5GC) */ template (value) NG_NAS_SecurityParams_Type cs_NG_NAS_SecurityParamsInit := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ KDF := tsc_KDF_HMAC_SHA_256, KSIamf := '111'B, //un initialised Ks := tsc_AuthUndefinedB256, KAMF := tsc_AuthUndefinedB256, MK := tsc_AuthUndefinedB256, KAUSF := tsc_AuthUndefinedB256, KSEAF := tsc_AuthUndefinedB256, ABBA := '0000'O, NAS_Integrity := cs_NG_NAS_SecurityInfo (px_NAS_5GC_IntegrityAlgorithm, tsc_AuthUndefinedB128), NAS_Ciphering := cs_NG_NAS_SecurityInfo (px_NAS_5GC_CipheringAlgorithm, tsc_AuthUndefinedB128), AuthParams := cs_CommonAuthParams_Init (px_eAuthRAND) }; template (value) NG_NAS_SecurityInfo_Type cs_NG_NAS_SecurityInfo(B4_Type p_Algo, B128_Key_Type p_Key) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ Algorithm := p_Algo, K_NAS := p_Key }; template (value) EAP_Message_Type cs_EAP_Request_AKAChallenge(O2_Type p_Length, template (value) EAP_AT_RAND p_RAND, template (value) EAP_AT_AUTN p_AUTN, template (value) EAP_AT_KDF p_KDF, template (value) EAP_AT_KDF_INPUT p_KDF_INPUT, template (value) EAP_AT_MAC p_MAC, O1_Type p_Id) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ akaChallenge_Req := { // @sic R5s200288 sic@ code := '01'O, // Request - RFC 4187 cl. 8.1 id := p_Id, // RFC 3748 cl. 4 @sic R5s201410 sic@ len := p_Length, // RFC 3748 cl. 4 type_ := '32'O, // RFC 5448 cl. 6.1 subtype := '01'O, // AKA-Challenge as in RFC 4187 cl. 11 reserved := '0000'O, // Set to 0 when sending, ignored by the receiver attributes := { rand := p_RAND, autn := p_AUTN, kdf := p_KDF, kdfInput := p_KDF_INPUT, mac := p_MAC, res := omit, auts := omit, padd := omit, permIdReq := omit, notification := omit, anyIdReq := omit, id := omit, versionList := omit, selectedVersion := omit, fullauthIdReq := omit, counter := omit, counterTooSmall := omit, nonceS := omit, clientErrorCode := omit, iv := omit, nextPseudonym := omit, nextReauthId := omit, checkCode := omit, resultInd := omit } } }; template (present) EAP_Message_Type cr_EAP_Response_AKAChallenge(O2_Type p_Length, template (present) EAP_AT_RES p_RES, template (present) EAP_AT_MAC p_MAC, template EAP_AT_RESULT_IND p_ResultInd := *, O1_Type p_Id) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ akaChallenge_Rsp := { // @sic R5200288, R5s200400 sic@ code := '02'O, // Response - RFC 4187 cl. 8.1 id := p_Id, // RFC 3748 cl. 4 @sic R5s201483 sic@ len := p_Length, // RFC 3748 cl. 4 type_ := '32'O, // RFC 5448 cl. 6.1 subtype := '01'O, // AKA-Challenge as in RFC 4187 cl. 11 reserved := ?, // Set to 0 when sending, ignored by the receiver attributes := { res := p_RES, mac := p_MAC, resultInd := p_ResultInd, // @sic R5-201142 sic@ padd := *, iv := *, checkCode := *, rand := omit, autn := omit, auts := omit, permIdReq := omit, notification := omit, anyIdReq := omit, id := omit, versionList := omit, selectedVersion := omit, fullauthIdReq := omit, counter := omit, counterTooSmall := omit, nonceS := omit, clientErrorCode := omit, nextPseudonym := omit, nextReauthId := omit, kdf := omit, kdfInput := omit } } }; template (value) EAP_Message_Type cs_EAP_Success (O1_Type p_Id := '00'O) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ success := { code := '03'O, // Success id := p_Id, // RFC 3748 cl. 4 len := '0004'O // RFC 3748 cl. 4.1 } }; template (value) EAP_Message_Type cs_EAP_Failure (O1_Type p_Id := '00'O) := { /* @status APPROVED (NR5GC) */ failure := { code := '04'O, // Failure id := p_Id, // RFC 3748 cl. 4 len := '0004'O // RFC 3748 cl. 4.1 } }; template (value) EAP_AT_RAND cs_EAP_AT_RAND (O16_Type p_Rand) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 4187 cl. 10.6 attributeType := '01'O, len := '05'O, reserved := '0000'O, rand := p_Rand }; template (value) EAP_AT_AUTN cs_EAP_AT_AUTN (O16_Type p_AUTN) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 4187 cl. 10.7 attributeType := '02'O, len := '05'O, reserved := '0000'O, autn := p_AUTN }; template (value) EAP_AT_KDF cs_EAP_AT_KDF := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 5448 cl. 3.2 attributeType := '18'O, len := '01'O, keyDerivationFunction := '0001'O // RFC 5448 cl. 3.3 }; template (value) EAP_AT_KDF_INPUT cs_EAP_AT_KDF_INPUT (octetstring p_Name, O2_Type p_ActualLength) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 5448 cl. 3.1 attributeType := '17'O, len := int2oct(lengthof(p_Name)/4 + 1, 1), actualNetworkNamelen := p_ActualLength, networkName := p_Name }; template (value) EAP_AT_MAC cs_EAP_AT_MAC (O16_Type p_MAC) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 4187 cl. 10.15 attributeType := '0B'O, len := '05'O, reserved := '0000'O, mac := p_MAC }; template (present) EAP_AT_RES cr_EAP_AT_RES (octetstring p_Res, O2_Type p_ActualLength) := { /* @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ // RFC 4187 cl. 10.8 attributeType := ('03'O), len := int2oct(lengthof(p_Res)/4 + 1, 1), reslen := p_ActualLength, res := p_Res }; //---------------------------------------------------------------------------- /* * @desc Used when building the network name from the PLMN * @param p_NAS_PlmnId * @return charstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function fl_Nas2SNN_MNC(NAS_PlmnId p_NAS_PlmnId) return charstring { var charstring v_MNC := ""; var hexstring v_PLMN_hexstring := oct2hex(p_NAS_PlmnId); if (v_PLMN_hexstring[2] == 'F'H) { v_MNC := "0"; } v_MNC := v_MNC & hex2str(v_PLMN_hexstring[5]) & hex2str(v_PLMN_hexstring[4]); if (v_PLMN_hexstring[2] != 'F'H) { // add last digit if not F v_MNC := v_MNC & hex2str(v_PLMN_hexstring[2]); } return v_MNC; } /* * @desc Used when building the network name from the PLMN * @param p_NAS_PlmnId * @return charstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function fl_Nas2SNN_MCC(NAS_PlmnId p_NAS_PlmnId) return charstring { var charstring v_MCC; var hexstring v_PLMN_hexstring := oct2hex(p_NAS_PlmnId); v_MCC := hex2str(v_PLMN_hexstring[1]) & hex2str(v_PLMN_hexstring[0]) & hex2str(v_PLMN_hexstring[3]); return v_MCC; } /* * @desc To build the Serving Network Name * @param p_PLMN * @param p_NID (default value: omit) * @return octetstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function fl_GetServingNetworkName (NAS_PlmnId p_PLMN, template (omit) hexstring p_NID := omit) return octetstring { var charstring v_P0 := "5G:mnc" & fl_Nas2SNN_MNC(p_PLMN) & ".mcc" & fl_Nas2SNN_MCC(p_PLMN) & ".3gppnetwork.org"; if (isvalue(p_NID)) { // @sic R5s220753 sic@ v_P0 := v_P0 & ":" & hex2str (valueof(p_NID)); } return char2oct (v_P0); } /* * @desc To build the NAI * @param p_PLMN * @param p_Identity * @return octetstring */ function fl_GetNAI (NAS_PlmnId p_PLMN, hexstring p_Identity := px_IMSI_Def) return octetstring { var charstring v_P0 := hex2str(p_Identity) & "@nai.5gc.mnc" & fl_Nas2SNN_MNC(p_PLMN) & ".mcc" & fl_Nas2SNN_MCC(p_PLMN) & ".3gppnetwork.org"; // @sic R5s230215 sic@ return char2oct (v_P0); } //============================================================================ // Group of S functions defined in Annex A of 33.501 //---------------------------------------------------------------------------- /* * @desc KAUSF derivation function; As per annex A.2 of 33.501 * @param p_AuthParams * @param p_KDF * @param p_Ks * @param p_PLMN * @param p_NID (default value: omit) * @return B256_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_Authentication_A2(Common_AuthenticationParams_Type p_AuthParams, KDF_Type p_KDF, B256_Type p_Ks, NAS_PlmnId p_PLMN, template (omit) hexstring p_NID := omit) return B256_Type { const octetstring const_S6A_FC := '6A'O; var octetstring v_S; var octetstring v_P0; // Generation of String v_S := const_S6A_FC; //FC = 0x6A v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@ v_S := (v_S & v_P0); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P0), 2)) ; //L0 = length of serving network ID (i.e. 0x00 0x03) v_S := ( v_S & ( substr (( bit2oct ( p_AuthParams.AUTN )) , 0,6 ))); //P1 = SQN XOR AK // to have MSB 6 bytes which is SQN xor AK and truncated as SQN xor AK is first 6 bytes of AUTN v_S := ( v_S & '0006'O ); //L1 = length of SQN XOR AK (i.e. 0x00 0x06) return fx_KeyDerivationFunction( p_KDF, p_Ks, v_S ); } //-------------------------------------------------------------------------- /* * @desc CK' and IK' derivation function; As per annex A.3 of 33.501 * @param p_AuthParams * @param p_KDF * @param p_Ks * @param p_PLMN * @param p_NID (default value: omit) * @return B256_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_Authentication_A3(Common_AuthenticationParams_Type p_AuthParams, KDF_Type p_KDF, B256_Type p_Ks, NAS_PlmnId p_PLMN, template (omit) hexstring p_NID := omit) return B256_Type { const octetstring const_S20_FC := '20'O; var octetstring v_S; var octetstring v_P0; // Generation of String v_S := const_S20_FC; //FC = 0x20 v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@ v_S := (v_S & v_P0); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P0), 2)) ; //L0 = length of serving network ID (i.e. 0x00 0x03) v_S := ( v_S & ( substr (( bit2oct ( p_AuthParams.AUTN )) , 0,6 ))); //P1 = SQN XOR AK // to have MSB 6 bytes which is SQN xor AK and truncated as SQN xor AK is first 6 bytes of AUTN v_S := ( v_S & '0006'O ); //L1 = length of SQN XOR AK (i.e. 0x00 0x06) return fx_KeyDerivationFunction( p_KDF, p_Ks, v_S ); } //-------------------------------------------------------------------------- /* * @desc RES* and XRES* derivation functions * As per annex A.4 of 33.501 * @param p_PLMN * @param p_AuthParams * @param p_KDF * @param p_Key * @param p_NID (default value: omit) * @return B128_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_Authentication_A4(NAS_PlmnId p_PLMN, Common_AuthenticationParams_Type p_AuthParams, KDF_Type p_KDF, B256_Type p_Key, template (omit) hexstring p_NID := omit) return B128_Type { const octetstring const_S6B_FC :='6B'O; var octetstring v_S; var octetstring v_P0; log(">>> f_NG_Authentication_A4: p_PLMN=", p_PLMN); log(">>> f_NG_Authentication_A4: p_AuthParams=", p_AuthParams); log(">>> f_NG_Authentication_A4: p_KDF=", p_KDF); log(">>> f_NG_Authentication_A4: p_Key=", p_Key); // Generation of String v_S := const_S6B_FC; //FC = 0x6B v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@ log("f_NG_Authentication_A4: v_P0=", v_P0); v_S := (v_S & v_P0); log("f_NG_Authentication_A4: v_S=", v_S); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P0), 2)) ; log("f_NG_Authentication_A4: v_S=", v_S); //L0 = length of serving network ID v_S := ( v_S & bit2oct ( p_AuthParams.RandValue ) ); log("f_NG_Authentication_A4: v_S=", v_S); //P1 = RAND v_S := ( v_S & '0010'O ); //L1 = length of RAND (i.e. 0x00 0x10) log("f_NG_Authentication_A4: v_S=", v_S); v_S := ( v_S & bit2oct (substr(p_AuthParams.XRES, 0, px_NAS_5GC_XRES_Length*8))); // @sic R5s190394 sic@ log("f_NG_Authentication_A4: v_S=", v_S); //P2 = RES or XRES v_S := ( v_S & int2oct(px_NAS_5GC_XRES_Length, 2) ); // @sic R5w190117 sic@ log("f_NG_Authentication_A4: v_S=", v_S); //L2 = length of RES/XRES (e.g. 0x00 0x10) var bitstring bs := fx_KeyDerivationFunction(p_KDF, p_Key, v_S); // Already 128 bits length return bs; //return substr(fx_KeyDerivationFunction(p_KDF, p_Key, v_S), 128, 128); // returns LSB 128 bits[truncated] of the key generated } //-------------------------------------------------------------------------- /* * @desc KSEAF derivation function * As per annex A.6 of 33.501 * @param p_PLMN * @param p_KAUSF * @param p_KDF_Type * @param p_NID (default value: omit) * @return B256_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_Authentication_A6(NAS_PlmnId p_PLMN, B256_Type p_KAUSF, KDF_Type p_KDF_Type, template (omit) hexstring p_NID := omit) return B256_Type { const octetstring const_S6C_FC :='6C'O; var octetstring v_S; var octetstring v_P0; // Generation of String v_S := const_S6C_FC; //FC = 0x6C v_P0 := fl_GetServingNetworkName(p_PLMN, p_NID); // @sic R5s220753 sic@ v_S := (v_S & v_P0); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P0), 2)) ; //L0 = length of serving network ID return fx_KeyDerivationFunction(p_KDF_Type, p_KAUSF, v_S); }; //-------------------------------------------------------------------------- /* * @desc KAMF derivation function * As per annex A.7 of 33.501 * @param p_SUPI * @param p_KSEAF * @param p_ABBA * @param p_KDF_Type * @return B256_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_Authentication_A7(charstring p_SUPI, B256_Type p_KSEAF, octetstring p_ABBA, KDF_Type p_KDF_Type) return B256_Type { const octetstring const_S6D_FC :='6D'O; var octetstring v_S; var octetstring v_P0 := char2oct(p_SUPI); // @sic R5s190109 sic@ var octetstring v_P1 := p_ABBA; // Generation of String v_S := const_S6D_FC; //FC = 0x6D v_S := (v_S & v_P0); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P0), 2)) ; //L0 = length of SUPI v_S := (v_S & v_P1); //P0 = serving network ID v_S := (v_S & int2oct(lengthof(v_P1), 2)) ; //L1 = length of ABBA return fx_KeyDerivationFunction(p_KDF_Type, p_KSEAF, v_S); } //-------------------------------------------------------------------------- /* * @desc SOR MAC-I AUSF derivation function * As per annex A.17 of 33.501 * @param p_SoRHeader * @param p_KAUSF * @param p_Counter * @param p_PLMNandAccessTechnologyList (default value: ''O) * @param p_KDF_Type * @return B128_Type * @status APPROVED (NR5GC) */ function f_NG_Authentication_A17(O1_Type p_SoRHeader, B256_Type p_KAUSF, O2_Type p_Counter, octetstring p_PLMNandAccessTechnologyList := ''O, KDF_Type p_KDF_Type) return B128_Type { const octetstring const_S77_FC :='77'O; var octetstring v_S; // Generation of String v_S := const_S77_FC; //FC = 0x77 v_S := (v_S & p_SoRHeader); //P0 = SOR Header v_S := (v_S & '0001'O); //L0 = length of SOR Header v_S := (v_S & p_Counter); //P1 = Counter v_S := (v_S & '0002'O) ; //L1 = length of Counter if (lengthof (p_PLMNandAccessTechnologyList) > 0) { //P2 & L2 are optional v_S := (v_S & p_PLMNandAccessTechnologyList); v_S := (v_S & int2oct(lengthof(p_PLMNandAccessTechnologyList), 2)) ; } return substr(fx_KeyDerivationFunction(p_KDF_Type, p_KAUSF, v_S), 128, 128); // returns LSB 128 bits[truncated] of the key generated } //-------------------------------------------------------------------------- /* * @desc SOR MAC-I UE derivation function * As per annex A.18 of 33.501 * @param p_KAUSF * @param p_Counter * @param p_KDF_Type * @return B128_Type * @status APPROVED (NR5GC) */ function f_NG_Authentication_A18(B256_Type p_KAUSF, O2_Type p_Counter, KDF_Type p_KDF_Type) return B128_Type { const octetstring const_S78_FC :='78'O; var octetstring v_S; // Generation of String v_S := const_S78_FC; //FC = 0x78 v_S := (v_S & '01'O); //P0 = SOR Ack v_S := (v_S & '0001'O); //L0 = length of SOR Ack v_S := (v_S & p_Counter); //P1 = Counter v_S := (v_S & '0002'O) ; //L1 = length of Counter return substr(fx_KeyDerivationFunction(p_KDF_Type, p_KAUSF, v_S), 128, 128); // returns LSB 128 bits[truncated] of the key generated } //-------------------------------------------------------------------------- /* * @desc HASH AMF derivation function * As per annex H.2 of 33.501 * @param p_NASMsg (encoded as octetstring) * @param p_KDF_Type * @return B64_Type */ function f_NG_HASH_AMF_H2(octetstring p_NASMsg, KDF_Type p_KDF_Type) return B64_Type { var B256_Type v_Key := int2bit(0, 256); var B256_Type v_Result := fx_KeyDerivationFunction(p_KDF_Type, v_Key, p_NASMsg); return substr(v_Result, 192, 64); }; //-------------------------------------------------------------------------- //============================================================================ // Initialisations: /* * @desc Function to be used before executing Authentication procedure in NG NAS. * The structure for NG_NAS_SecurityParams_Type passed as parameter shall have at least valid parameters for: * IMSI, PLMN, NAS_IntegrityInfo_Type.NAS_IntAlgo, NAS_CipheringInfo_Type.NAS_CipherAlgo * Execution of this fucntion will initialise following parameters * randValue, CK, IK, Ks, aUTN, XRES,KSIamf, KAMF, KNASenc & KNASint * @param p_Auth_Params * @param p_PLMN * @param p_Identity (default value: := px_IMSI_Def) * @param p_AuthenticationError (default value: noError) * @param p_Common_AuthenticationParams (default value: omit) * @param p_NID (default value: omit) * @return NG_NAS_SecurityParams_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_NAS_AuthenticationInit(NG_NAS_SecurityParams_Type p_Auth_Params, NAS_PlmnId p_PLMN, hexstring p_Identity := px_IMSI_Def, AuthenticationError_Type p_AuthenticationError := noError, template (omit) Common_AuthenticationParams_Type p_Common_AuthenticationParams := omit, template (omit) hexstring p_NID := omit) return NG_NAS_SecurityParams_Type { var NG_NAS_SecurityParams_Type v_Auth_Params := p_Auth_Params; var B128_Type v_XRESstar; // Generates Ck, Ik, AUTN, XRES if (isvalue(p_Common_AuthenticationParams)) { v_Auth_Params.AuthParams := valueof(p_Common_AuthenticationParams); } else { v_Auth_Params.AuthParams := f_AuthenticationInit(v_Auth_Params.AuthParams, p_AuthenticationError); // @sic R5-197217 sic@ } v_Auth_Params.Ks := v_Auth_Params.AuthParams.CK & v_Auth_Params.AuthParams.IK; // As per 33.501 clause 6.1.3.2 // Generates KAUSF v_Auth_Params.KAUSF := f_NG_Authentication_A2(v_Auth_Params.AuthParams, v_Auth_Params.KDF, v_Auth_Params.Ks, p_PLMN, p_NID); // @sic R5s220753 sic@ // Generates XRES* @sic R5s200400 sic@ v_XRESstar := f_NG_Authentication_A4(p_PLMN, v_Auth_Params.AuthParams, v_Auth_Params.KDF, v_Auth_Params.Ks, p_NID); // @sic R5s220753 sic@ // Store value for later comparison with value received in Response v_Auth_Params.AuthParams.XRES := v_XRESstar; // Now update the other parameters (common to 5GAKA and EAP) v_Auth_Params := fl_NG_NAS_AuthenticationInitOtherParams (v_Auth_Params, p_PLMN, hex2str(p_Identity), p_NID); // @sic R5s220753, R5s230215 sic@ return v_Auth_Params; } /* * @desc Function to initialise authentication parameters common to both 5G AKA and EAP * @param p_Auth_Params * @param p_PLMN * @param p_Identity * @param p_NID (default value: omit) * @return NG_NAS_SecurityParams_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function fl_NG_NAS_AuthenticationInitOtherParams(NG_NAS_SecurityParams_Type p_Auth_Params, NAS_PlmnId p_PLMN, charstring p_Identity, template (omit) hexstring p_NID := omit) return NG_NAS_SecurityParams_Type { var NG_NAS_SecurityParams_Type v_Auth_Params := p_Auth_Params; // update KSI v_Auth_Params.KSIamf := f_Authentication_IncrementKeySeq(v_Auth_Params.KSIamf); // Generate KSEAF v_Auth_Params.KSEAF := f_NG_Authentication_A6(p_PLMN, v_Auth_Params.KAUSF, v_Auth_Params.KDF, p_NID); //@sic R5s220753 sic@ // Generate KAMF v_Auth_Params.KAMF := f_NG_Authentication_A7(p_Identity, // @sic R5s190109, R5s230215 sic@ v_Auth_Params.KSEAF, v_Auth_Params.ABBA, v_Auth_Params.KDF); // Derive KNASenc key v_Auth_Params.NAS_Ciphering.K_NAS := f_NG_Authentication_A8(tsc_NAS_Enc_Alg, v_Auth_Params.NAS_Ciphering.Algorithm, v_Auth_Params.KAMF, v_Auth_Params.KDF); // Derive KNASint key v_Auth_Params.NAS_Integrity.K_NAS := f_NG_Authentication_A8(tsc_NAS_Int_Alg, v_Auth_Params.NAS_Integrity.Algorithm, v_Auth_Params.KAMF, v_Auth_Params.KDF); return v_Auth_Params; } /* * @desc Function to be used before executing Authentication procedure in NG EAP-AKA to generated * Key material and tokens according to TS 33.501 clause 6.1.3.1. * References: TS 33.501 clause 6.1.3.1. RFC 5448 and RFC 4187 * TS 33.102 for AUTN computation and TS TS 34.108 for XRES, CK, IK for Test USIM * @param p_Auth_Params * @param p_PLMN * @param p_Identity * @param p_Common_AuthenticationParams (default value: omit) * @param p_AuthenticationError (default value: noError) * @param p_NID (default value: omit) * @return NG_NAS_SecurityParams_Type * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_EAP_AuthenticationInit(NG_NAS_SecurityParams_Type p_Auth_Params, NAS_PlmnId p_PLMN, charstring p_Identity, template (omit) Common_AuthenticationParams_Type p_Common_AuthenticationParams := omit, AuthenticationError_Type p_AuthenticationError := noError, template (omit) hexstring p_NID := omit) return NG_NAS_SecurityParams_Type { var NG_NAS_SecurityParams_Type v_Auth_Params := p_Auth_Params; var B256_Type v_Ck_Ik_; var B128_Type v_Ck_; var B128_Type v_Ik_; var bitstring v_MK; var B256_Type v_K; var charstring v_S; if (isvalue(p_Common_AuthenticationParams)) { v_Auth_Params.AuthParams := valueof(p_Common_AuthenticationParams); } else { // Generates Ck, Ik, AUTN, XRES according to TS 33.102 and TS 34.108 v_Auth_Params.AuthParams := f_AuthenticationInit(v_Auth_Params.AuthParams, p_AuthenticationError); // @sic R5s201223 sic@ } v_Auth_Params.Ks := v_Auth_Params.AuthParams.CK & v_Auth_Params.AuthParams.IK; // Generates Ck' and IK' v_Ck_Ik_ := f_NG_Authentication_A3(v_Auth_Params.AuthParams, v_Auth_Params.KDF, v_Auth_Params.Ks, p_PLMN, p_NID); // @sic R5s220753 sic@ v_Ck_ := substr (v_Ck_Ik_, 0, 128); v_Ik_ := substr (v_Ck_Ik_, 128, 128); // RFC 5448 cl. 3.3 v_K := v_Ik_ & v_Ck_; v_S := "EAP-AKA'" & p_Identity; // Master Key v_MK := f_ExtendedEAPAKA_PRF (v_K, char2oct (v_S)); v_Auth_Params.MK := v_MK; // As per 33.501 clause 6.1.3.1 // KAUSF is EMSK in RFC 5448 cl. 3.3 v_Auth_Params.KAUSF := substr (v_MK, 1152, 256); // Now update the other parameters (common to 5GAKA and EAP) v_Auth_Params := fl_NG_NAS_AuthenticationInitOtherParams (v_Auth_Params, p_PLMN, p_Identity, p_NID); // @sic R5s220753, R5s230215 sic@ return v_Auth_Params; } /* * @desc Generate and encode EAP-AKA' challenge according TS 33.501 clause 6.1.3.1 and RFC 5448 * @param p_Auth_Params * @param p_PLMN * @param p_Id (default: '00'O) * @param p_NID (default value: omit) * @return octetstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_EAP_ChallengeReq(NG_NAS_SecurityParams_Type p_Auth_Params, NAS_PlmnId p_PLMN, O1_Type p_Id := '00'O, template (omit) hexstring p_NID := omit) return octetstring { var template (value) EAP_AT_RAND v_RAND; var template (value) EAP_AT_AUTN v_AUTN; // @sic R5s200400 sic@ var template (value) EAP_AT_KDF v_KDF; var template (value) EAP_AT_KDF_INPUT v_KDF_INPUT; var template (value) EAP_AT_MAC v_MAC; var O16_Type v_MACValue := '00000000000000000000000000000000'O; var bitstring v_K_aut; var template (value) EAP_Message_Type v_EAP_Message; var integer v_Msglen := 8; // @sic R5s200400 sic@ var octetstring v_NetworkName := fl_GetServingNetworkName (p_PLMN, p_NID); // @sic R5s220753 sic@ var bitstring v_EncodedMsg; var integer v_Len; var integer v_Paddinglen; var integer i; v_RAND := cs_EAP_AT_RAND (bit2oct(p_Auth_Params.AuthParams.RandValue)); v_Msglen := v_Msglen + 5*4; v_AUTN := cs_EAP_AT_AUTN (bit2oct(p_Auth_Params.AuthParams.AUTN)); v_Msglen := v_Msglen + 5*4; v_KDF := cs_EAP_AT_KDF; v_Msglen := v_Msglen + 4; v_Len := lengthof(v_NetworkName); if (v_Len mod 4 > 0) { v_Paddinglen := 4 - v_Len mod 4; for (i:=0; i < v_Paddinglen; i:=i+1) { v_NetworkName := v_NetworkName & '00'O; } } v_KDF_INPUT := cs_EAP_AT_KDF_INPUT (v_NetworkName, int2oct(v_Len, 2)); v_Msglen := v_Msglen + lengthof(v_NetworkName) + 4; v_MAC := cs_EAP_AT_MAC (v_MACValue); v_Msglen := v_Msglen + 5*4; // Build the message with MAC=0 v_EAP_Message := cs_EAP_Request_AKAChallenge(int2oct(v_Msglen, 2), v_RAND, v_AUTN, v_KDF, v_KDF_INPUT, v_MAC, p_Id); // @sic R5s201410 sic@ // Compute MAC according to RFC 5448 cl. 3.4.2 v_EncodedMsg := encvalue(v_EAP_Message); v_K_aut := substr(p_Auth_Params.MK, 128,256); // RFC 5448 cl. 3.3 K_aut to be used for computing MAC @sic R5s200400 sic@ v_MACValue := bit2oct(substr(f_HMAC_SHA_256(v_K_aut, bit2oct(v_EncodedMsg)), 0, 128)); // @sic R5s200400 sic@ v_MAC := cs_EAP_AT_MAC (v_MACValue); // Finally return the complete EAP-AKA' challenge with correct MAC return (bit2oct(encvalue(cs_EAP_Request_AKAChallenge (int2oct(v_Msglen, 2), v_RAND, v_AUTN, v_KDF, v_KDF_INPUT, v_MAC, p_Id)))); // @sic R5s201410 sic@ } /* * @desc Decode and check EAP-AKA' challenge according TS 24.501 clause 5.4.1.2.2 and RFC 5448 * This function only checks for a successful Authentication Response - it doesn't check for any EAP failure messages * @param p_Auth_Params (by reference) * @param p_ReceivedEAP * @param p_ResultInd (default value: *) * @param p_Id (default value: '00'O) * @return boolean * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function f_NG_EAP_SuccessfulAuthenticationResponse(inout NG_NAS_SecurityParams_Type p_Auth_Params, octetstring p_ReceivedEAP, template EAP_AT_RESULT_IND p_ResultInd := *, O1_Type p_Id := '00'O) return boolean { var boolean v_Result := false; var bitstring v_ReceivedEAP := oct2bit(p_ReceivedEAP); var O16_Type v_RxdMAC; var O16_Type v_MACValue := '00000000000000000000000000000000'O; var bitstring v_K_aut; var EAP_Message_Type v_EAP_Message; var B32_128_Type v_RESValue; var octetstring v_ModifiedEAP; var integer v_Len; var integer v_Paddinglen; var integer i; if (decvalue(v_ReceivedEAP, v_EAP_Message) != 0) { FatalError(__FILE__, __LINE__, "EAP message cannot be decoded"); } //get length in bits of received RES (as it's a variable length, need to compare the correct length) v_Len := oct2int(v_EAP_Message.akaChallenge_Rsp.attributes.res.reslen); // store this in the global info p_Auth_Params.AuthParams.XRESLength := v_Len / 8; // Get the RES value from the global info v_RESValue := substr(p_Auth_Params.AuthParams.XRES, 0, v_Len); // Now pad it so that it's (hopefully) the same length of the received value if (v_Len mod 8 > 0 or (v_Len/8) mod 4 > 0) { v_Paddinglen := 8 - v_Len mod 8; // pad to end of octet, in bits v_Paddinglen := (4 - ((v_Len + v_Paddinglen)/8) mod 4)*8; // pad to multiple of 4 octets, in bits for (i:=0; i < v_Paddinglen; i:=i+1) { v_RESValue := v_RESValue & '0'B; } } // Check message is AKAChallenge, length and AT_RES is correct if (match (v_EAP_Message, cr_EAP_Response_AKAChallenge(int2oct(lengthof(p_ReceivedEAP), 2), cr_EAP_AT_RES (bit2oct(v_RESValue), int2oct(v_Len, 2)), ?, p_ResultInd, p_Id))) { // @sic R5-201142, R5s201483 sic@ // Then test MAC v_RxdMAC := v_EAP_Message.akaChallenge_Rsp.attributes.mac.mac; // First build the message with MAC=0 v_ModifiedEAP := fl_NG_EAP_Response_ClearMACValue(p_ReceivedEAP); // @sic R5s210153 sic@ // Compute MAC according to RFC 5448 cl. 3.4.2 v_K_aut := substr(p_Auth_Params.MK, 128, 256); // RFC 5448 cl. 3.3 K_aut to be used for computing MAC @sic R5s200400 sic@ v_MACValue := bit2oct(substr(f_HMAC_SHA_256(v_K_aut, v_ModifiedEAP), 0, 128)); // @sic R5s200400, R5s210153 sic@ // Then test it against the received value if (match(v_RxdMAC, v_MACValue)) { // if the MAC also matches then the whole message is correct v_Result := true; } } return v_Result; } /* * @desc Local function to find then replace the value in the MAC attribute of the received EAP message with all 0s, * so that the MAC value can be calculated and checked in the TTCN. This function is required because * the EAP attributes are defined as a set * => the order of the attributes in the template received in the TTCN may not match order in undecoded message * @param p_ReceivedEAP * @return octetstring * @status APPROVED (IMS, NR5GC, NR5GC_IRAT, POS) */ function fl_NG_EAP_Response_ClearMACValue(octetstring p_ReceivedEAP) return octetstring { var octetstring v_ModifiedEAP := p_ReceivedEAP; var integer i := 8; /* according to RFC 4187 clause 8.1 the EAP-AKA header is 8 octets */ var integer k; while (p_ReceivedEAP[i] != '0B'O) { /* MAC attribute type is 11 according to RFC 4187 clause 11 */ i := i + (oct2int(p_ReceivedEAP[i+1]) * 4); if (i > lengthof(p_ReceivedEAP)) { FatalError(__FILE__, __LINE__, "no MAC attribute found"); } } i := i + 4; /* first 4 octets are type, length, reserved (RFC 4187 clause 10.15) */ for (k := 0; k < 16; k := k + 1) { v_ModifiedEAP[i+k] := '00'O; } return v_ModifiedEAP; } }