Commit 5a48ca99 authored by Yann Garcia's avatar Yann Garcia
Browse files

Add support of AuthRequest failure with SYNC error from real UE; Enhance UpperTester

parent 98df199e
Loading
Loading
Loading
Loading
+33.6 KiB (35.6 KiB)

File changed.

No diff preview for this file type.

+21 −11
Changes for ccsrc/Externals/ia2_128.cc: 21 added lines, 11 removed lines.
Original line number Diff line number Diff line
@@ -32,18 +32,19 @@ int ia2_128::encrypt(const uint8_t algo_id,
                     unsigned char** cyphered,
                     uint32_t* cyphered_length) {
  loggers::get_instance().log(">>> ia2_128::encrypt: Starting encryption");
  loggers::get_instance().log_to_hexa(">>> ia2_128::encrypt: knas_enc", knas_enc, 16);
  loggers::get_instance().log_to_hexa(">>> ia2_128::encrypt: payload", payload, payload_length);
  loggers::get_instance().log(">>> ia2_128::encrypt: algo_id: %d", algo_id);
  loggers::get_instance().log(">>> ia2_128::encrypt: count: %u", count);
  loggers::get_instance().log(">>> ia2_128::encrypt: bearer: %d", bearer);
  loggers::get_instance().log(">>> ia2_128::encrypt: direction: %d", direction);
  loggers::get_instance().log(">>> ia2_128::encrypt: payload_length: %u", payload_length);

  // Input validation
  // Input validation (must run before the hex-dump logging below, which dereferences these pointers)
  if (!knas_enc || !payload || !cyphered || !cyphered_length) {
      loggers::get_instance().error("ia2_128::encrypt: Wrong input parameters");
      return -1;
  }
  loggers::get_instance().log_to_hexa(">>> ia2_128::encrypt: knas_enc", knas_enc, 16);
  loggers::get_instance().log_to_hexa(">>> ia2_128::encrypt: payload", payload, payload_length);

  if (payload_length == 0) {
      loggers::get_instance().error("ia2_128::encrypt: Wrong payload length");
@@ -124,18 +125,19 @@ int ia2_128::decrypt(const uint8_t algo_id,
                     unsigned char** payload,
                     uint32_t* payload_length) {
  loggers::get_instance().log(">>> ia2_128::decrypt: Starting decryption");
  loggers::get_instance().log_to_hexa(">>> ia2_128::decrypt: knas_enc", knas_enc, 16);
  loggers::get_instance().log_to_hexa(">>> ia2_128::decrypt: cyphered", cyphered, cyphered_length);
  loggers::get_instance().log(">>> ia2_128::decrypt: algo_id: %d", algo_id);
  loggers::get_instance().log(">>> ia2_128::decrypt: count: %u", count);
  loggers::get_instance().log(">>> ia2_128::decrypt: bearer: %d", bearer);
  loggers::get_instance().log(">>> ia2_128::decrypt: direction: %d", direction);
  loggers::get_instance().log(">>> ia2_128::decrypt: cyphered_length: %u", cyphered_length);

  // Input validation
  // Input validation (must run before the hex-dump logging below, which dereferences these pointers)
  if (!knas_enc || !cyphered || !payload || !payload_length) {
      loggers::get_instance().error("ia2_128::decrypt: Wrong input parameters");
      return -1;
  }
  loggers::get_instance().log_to_hexa(">>> ia2_128::decrypt: knas_enc", knas_enc, 16);
  loggers::get_instance().log_to_hexa(">>> ia2_128::decrypt: cyphered", cyphered, cyphered_length);

  if (cyphered_length == 0) {
      loggers::get_instance().error("ia2_128::encrypt: Wrong cyphered length");
@@ -215,19 +217,19 @@ int ia2_128::mac(const uint8_t algo_id,
                 const uint32_t payload_length,
                 unsigned char** mac,
                 uint32_t* mac_length) {
  loggers::get_instance().log_to_hexa(">>> ia2_128::mac: knas_int", knas_int, KEY_SIZE);
  loggers::get_instance().log(">>> ia2_128::mac: payload_length: %d", payload_length);
  loggers::get_instance().log_to_hexa(">>> ia2_128::mac: payload", payload, payload_length);
  loggers::get_instance().log(">>> ia2_128::mac: algo_id: %d", algo_id);
  loggers::get_instance().log(">>> ia2_128::mac: count: %u", count);
  loggers::get_instance().log(">>> ia2_128::mac: bearer: %d", bearer);
  loggers::get_instance().log(">>> ia2_128::mac: direction: %d", direction);

  // Input validation
  // Input validation (must run before the hex-dump logging below, which dereferences these pointers)
  if (!knas_int || !payload || !mac || !mac_length) {
    loggers::get_instance().error("ia2_128::mac: Wrong input parameters");
    return -1;
  }
  loggers::get_instance().log_to_hexa(">>> ia2_128::mac: knas_int", knas_int, KEY_SIZE);
  loggers::get_instance().log_to_hexa(">>> ia2_128::mac: payload", payload, payload_length);

  if (payload_length == 0) {
    loggers::get_instance().error("ia2_128::mac: Wrong payload length");
@@ -295,6 +297,7 @@ int ia2_128::mac(const uint8_t algo_id,
  // Truncate CMAC output to 4 bytes (take the first 4 bytes)
  std::memcpy(*mac, cmac_output, MAC_SIZE);
  loggers::get_instance().log_to_hexa("ia2_128::mac: mac: ", *mac, *mac_length);
  result = 0;

  cleanup:
    #pragma GCC diagnostic push
@@ -302,9 +305,16 @@ int ia2_128::mac(const uint8_t algo_id,
    CMAC_CTX_free(ctx);
    #pragma GCC diagnostic pop
    std::free(input_block);
    if (result != 0) {
      // A CMAC_* call above failed (goto cleanup): *mac was allocated (see malloc above)
      // but never filled in, so it must not be handed back to the caller as a valid MAC.
      std::free(*mac);
      *mac = nullptr;
      *mac_length = 0;
    }

  loggers::get_instance().log("<<< ia2_128::mac: result: 0");
  return 0;
  loggers::get_instance().log("<<< ia2_128::mac: result: %d", result);
  return result;
}

// ETSI TS 133 401 V18.3.0 (2025-04) Annex B.1.3 128-EEA2
+10 −0
Changes for ttcn/AtsNGAP/NGAP_UtProbe.ttcn: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@ module NGAP_UtProbe {
    import from UpperTesterPtcToMtcDefs all;
    import from UpperTesterFunctions all;
    import from NGAP_UtDispatcher all;
    import from LibNGAP_Pixits all;
    import from Lib_NG_NAS_Security_Functions all;

    modulepar charstring PX_UT_PROBE_AT_CMD := "ATI<CR>";
    modulepar float      PX_UT_PROBE_TIMEOUT := 15.0;
@@ -55,6 +57,14 @@ module NGAP_UtProbe {
        log("MODEM_RESTART: ", v_cnf);
        if (not v_cnf.Result) { setverdict(fail); stop; }

        v_cnf := fl_UT_ApplyCommandRetCnf(utPtcMtcPort, cas_UT_Req(PLMN_MANUAL, CNF_REQUIRED, cs_ManualPlmn("\"" & f_ConvertPLMNtoString(fl_NasNN_MCC2PlmnId(PX_NAS_MCC, PX_NAS_MNC)) & "\"")));
        log("PLMN_MANUAL: ", v_cnf);
        if (not v_cnf.Result) { setverdict(fail); stop; }

        v_cnf := fl_UT_ApplyCommandRetCnf(utPtcMtcPort, cas_UT_Req(PLMN_AUTOMATIC, CNF_REQUIRED));
        log("PLMN_AUTOMATIC: ", v_cnf);
        if (not v_cnf.Result) { setverdict(fail); stop; }

        v_cnf := fl_UT_ApplyCommandRetCnf(utPtcMtcPort, cas_UT_Req(CHECK_PLMN, CNF_REQUIRED));
        log("CHECK_PLMN (expected unsupported): ", v_cnf);
        if (v_cnf.Result) { setverdict(fail); stop; }
+78 −1
Changes for ttcn/LibNGAP/lib_system/LibNGAP_Functions.ttcn: 78 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -303,6 +303,80 @@ module LibNGAP_Functions {
        log(">>> f_await_registration_request");

        // REGISTRATION_REQUEST
        tc_ac.start;
        alt { // In case the UE rejected the authentication vector with a Synch failure and returned an AUTS for resync (per TS 24.501 §5.4.1.3.7)
            [] N2_gNBaMF_P.check(
                                 receive(
                                         mw_ngap_initMsg(
                                                         mw_n2_UplinkNASTransport(
                                                                                  -,
                                                                                  -,
                                                                                  decmatch(
                                                                                           mw_NG_AUTHENTICATION_FAILURE(
                                                                                                                        mw_GMM_GSM_Cause(
                                                                                                                                         -,
                                                                                                                                         int2bit(21, 8) // SYNC failure
                                         ))))))) {
                // the UE rejected the authentication vector with a Synch failure
                f_recv_NGAP_PDU(
                                mw_ngap_initMsg(
                                                mw_n2_UplinkNASTransport(
                                                                         -,
                                                                         -,
                                                                         decmatch(
                                                                                  mw_NG_AUTHENTICATION_FAILURE(
                                                                                                               mw_GMM_GSM_Cause(
                                                                                                                                -,
                                                                                                                                int2bit(21, 8) // SYNC failure
                                ))))));
                f_NASPDU_Get(vc_recvNGAP_PDU);
                // Re-calculate the security context with the AUTS value received from the UE
                // (TS 33.102 clause 6.3.3 "Re-synchronisation procedure"):
                //   AUTS = (SQN_MS xor AK*) (48 bits) || MAC-S (64 bits)
                //   AK*  = f5star(K, RAND)   -- RAND is the one from the rejected Authentication Request
                //   SQN_MS = (SQN_MS xor AK*) xor AK*
                //   MAC-S  = f1star(K, RAND, SQN_MS, AMF*) with a dummy AMF* of all zeros
                if (ispresent(vc_recvNgNasUl_Msg.authentication_Failure.authFailureParam)) {
                    var B112_Type v_auts        := vc_recvNgNasUl_Msg.authentication_Failure.authFailureParam.auts;
                    var B48_Type  v_sqn_ms_akstar := substr(v_auts, 0, 48);
                    var B64_Type  v_mac_s        := substr(v_auts, 48, 64);
                    log("f_await_registration_request: v_auts=", bit2oct(v_auts));

                    var B48_Type v_ak_star;
                    if (f_f5star(PX_SUBSCRIPTION_KEY, vc_ng_nas_security_params_type.AuthParams.RandValue, v_ak_star) != 0) {
                        log("*** " & __SCOPE__ & ": FAIL: 'f_f5star' failed to compute AK*");
                        setverdict(fail, "*** " & __SCOPE__ & ": FAIL: 'f_f5star' failed to compute AK*");
                    }
                    var B48_Type v_sqn_ms := v_sqn_ms_akstar xor4b v_ak_star;
                    log("f_await_registration_request: v_sqn_ms=", bit2oct(v_sqn_ms));

                    // Verify MAC-S; the resynchronisation MAC always uses a dummy AMF* of all zeros
                    // so it does not have to be sent in the clear (TS 33.102 clause 6.3.3)
                    var B64_Type v_mac_s_expected;
                    if (f_f1star(PX_SUBSCRIPTION_KEY, vc_ng_nas_security_params_type.AuthParams.RandValue, v_sqn_ms, int2bit(0, 16), v_mac_s_expected) != 0) {
                        log("*** " & __SCOPE__ & ": FAIL: 'f_f1star' failed to compute MAC-S");
                        setverdict(fail, "*** " & __SCOPE__ & ": FAIL: 'f_f1star' failed to compute MAC-S");
                    }
                    if (PX_CHECK_SECURITY and (v_mac_s != v_mac_s_expected)) {
                        log("*** " & __SCOPE__ & ": FAIL: MAC-S mismatch: received=", bit2oct(v_mac_s), ", expected=", bit2oct(v_mac_s_expected));
                        setverdict(fail, "*** " & __SCOPE__ & ": FAIL: MAC-S mismatch in resynchronisation");
                    }

                    // Advance the network's SQN past the UE's own counter so the Authentication Request
                    // that follows (f_send_authentication_request_await_authentication_response) is accepted
                    vc_NG_NAS_SQN := int2bit(bit2int(v_sqn_ms) + 1, 48);
                    log("f_await_registration_request: resynchronised vc_NG_NAS_SQN=", bit2oct(vc_NG_NAS_SQN));
                } else {
                    log("*** " & __SCOPE__ & ": FAIL: Authentication failure with no AUTS");
                    setverdict(fail, "*** " & __SCOPE__ & ": FAIL: Authentication failure with no AUTS");
                }
            }
            [] tc_ac.timeout {
                // No message received, let's consider the message was accepted and proceed with the test case execution
                log("*** " & __SCOPE__ & ": FAIL: No NAS message received");
                setverdict(fail, "*** " & __SCOPE__ & ": FAIL: No NAS message received");
            }
        }
        f_recv_NGAP_PDU(
                        mw_ngap_initMsg(
                                        mw_n2_initialUeMessage
@@ -621,7 +695,10 @@ module LibNGAP_Functions {
            f_force_opc(PX_OPERATOR_SECRET_KEY);
        }
        // Compute MAC_A
        var B48_Type  v_sqn   := PX_SQN;
        // Use vc_NG_NAS_SQN rather than PX_SQN directly: it starts at PX_SQN but is advanced by
        // f_await_registration_request whenever the UE rejects a vector with a Synch failure,
        // so a retried Authentication Request uses a SQN the UE will actually accept.
        var B48_Type  v_sqn   := vc_NG_NAS_SQN;
        var B16_Type  v_amf   := PX_AMF; // AMF: Authentication Management Field
        vc_ng_nas_security_params_type.AuthParams.RandValue := PX_RAND_VALUE;
        var B64_Type v_mac_a;
+7 −0
Changes for ttcn/LibNGAP/lib_system/LibNGAP_Interface.ttcn: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ module LibNGAP_Interface {
    import from NGAP_PDU_Contents language "ASN.1:1997" all;
    import from LibNGAP_Pixits all;

    // Lib_NG_NAS
    import from Lib_NG_NAS_Pixits all;

    // UpperTester
    import from UpperTesterPtcToMtcDefs all;
    import from UpperTesterCommon all;
@@ -65,6 +68,8 @@ module LibNGAP_Interface {
            var NG_NAS_UL_Message_Type vc_recvNgNasUl_Msg;
            var NG_NAS_DL_Message_Type vc_recvNgNasDl_Msg;
            var NG_NAS_SecurityParams_Type       vc_ng_nas_security_params_type := {};
            var B48_Type vc_NG_NAS_SQN := PX_SQN; // Network's current SQN for 5G-AKA vector generation (TS 33.102 clause 6.3.3);
                                                   // advanced by f_await_registration_request after a Synch failure/AUTS from the UE
            var boolean vc_serverStop:=false; 

            // test adapter params
@@ -99,6 +104,8 @@ module LibNGAP_Interface {
            timer tc_wait  := PX_NGAP_TWAIT;
            timer tc_noac  := PX_TNOAC;
            timer tc_delay := 0.3;  // delay next Request
            timer tc_ac    := PX_NGAP_TWAIT; // used by f_await_registration_request to bound the wait for either
                                              // an Authentication Failure (Synch failure) or the Registration Request
                                    // FSCOM: TTCN-3 timer are in seconds (ETSI ES 201 873-1 V4.16.1 (2024-10) Clause 12 Declaring timers)

            // Variables for storing default references
Loading