diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index c1a28a18f3..3b51ec748c 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(fgs_5gmm_lib OBJECT RegistrationComplete.c FGSUplinkNasTransport.c FGSDeregistrationRequestUEOriginating.c + fgmm_authentication_failure.c ) target_link_libraries(fgs_5gmm_lib PUBLIC fgs_5gmm_ies_lib) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.c new file mode 100644 index 0000000000..2dc865ab4c --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.c @@ -0,0 +1,101 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "fgmm_authentication_failure.h" +#include +#include // For htons and ntohs +#include // For malloc and free +#include "fgmm_lib.h" +#include "common/utils/ds/byte_array.h" +#include "common/utils/utils.h" + +#define MIN_AUTH_FAILURE_LEN 1 +#define AUTH_FAILURE_PARAM_LEN 16 +#define AUTH_FAIL_PARAM_IEI 0x30 + +/** @brief Encode Authentication Failure (8.2.4 of 3GPP TS 24.501) */ +int encode_fgmm_auth_failure(byte_array_t *buffer, const fgmm_auth_failure_t *msg) +{ + if (buffer->len < MIN_AUTH_FAILURE_LEN) { + PRINT_NAS_ERROR("Missing mandatory IE in Authentication Failure"); + return -1; // missing mandatory IE + } + // 5GMM cause (Mandatory) + int encoded = encode_fgs_nas_cause(buffer, &msg->cause); + // Authentication failure parameter (see 8.2.4.2 3GPP TS 24.501) + if (msg->cause == Synch_failure) { + // Authentication failure parameter shall be present with cause Synch Failure + if (msg->authentication_failure_param.len == 0) { + PRINT_NAS_ERROR("Authentication Failure Cause is synch failure but Authentication Failure Parameter is not available"); + return -1; + } + if (buffer->len - encoded < msg->authentication_failure_param.len + 2) { + PRINT_NAS_ERROR("Invalid buffer for encoding of Authentication Failure Parameter"); + return -1; + } + // Encode the IEI + buffer->buf[encoded++] = AUTH_FAIL_PARAM_IEI; + buffer->buf[encoded++] = msg->authentication_failure_param.len; + for (int i = 0; i < msg->authentication_failure_param.len; i++) { + buffer->buf[encoded++] = msg->authentication_failure_param.buf[i]; + } + } + return encoded; +} + +/** @brief Decode Authentication Failure (8.2.4 of 3GPP TS 24.501) */ +int decode_fgmm_auth_failure(fgmm_auth_failure_t *msg, const byte_array_t *buffer) +{ + if (buffer->len < MIN_AUTH_FAILURE_LEN) { + return -1; // missing mandatory IE + } + byte_array_t ba = *buffer; // Local copy of buffer + // 5GMM Cause (Mandatory) + uint32_t decoded = decode_fgs_nas_cause(&msg->cause, buffer); + // Authentication Failure Parameters (Optional) + if (msg->cause == Synch_failure) { + uint8_t iei = buffer->buf[decoded++]; + if (iei == AUTH_FAIL_PARAM_IEI) { + msg->authentication_failure_param.len = ba.buf[decoded++]; + if (msg->authentication_failure_param.len > AUTH_FAILURE_PARAM_LEN - 2) { // maximum length of contents is 14 octets + PRINT_NAS_ERROR("Length of Authentication Failure Parameter contents is too large"); + return -1; + } + msg->authentication_failure_param.buf = malloc_or_fail(msg->authentication_failure_param.len); + for (int i = 0; i < msg->authentication_failure_param.len; i++) { + msg->authentication_failure_param.buf[i] = buffer->buf[decoded++]; + } + } + } + return decoded; +} + +bool eq_fgmm_auth_failure(const fgmm_auth_failure_t *a, const fgmm_auth_failure_t *b) +{ + _NAS_EQ_CHECK_INT(a->cause, b->cause); + eq_byte_array(&a->authentication_failure_param, &b->authentication_failure_param); + return true; +} + +void free_fgmm_auth_failure(const fgmm_auth_failure_t *msg) +{ + free(msg->authentication_failure_param.buf); +} \ No newline at end of file diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.h new file mode 100644 index 0000000000..71d047b656 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_failure.h @@ -0,0 +1,41 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef FGMM_AUTH_FAILURE_H +#define FGMM_AUTH_FAILURE_H + +#include +#include "fgmm_lib.h" +#include "common/utils/ds/byte_array.h" + +typedef struct { + // 5GMM cause (Mandatory) + cause_id_t cause; + // Authentication failure parameter (Optional) + byte_array_t authentication_failure_param; +} fgmm_auth_failure_t; + +int decode_fgmm_auth_failure(fgmm_auth_failure_t *msg, const byte_array_t *buffer); +int encode_fgmm_auth_failure(byte_array_t *buffer, const fgmm_auth_failure_t *msg); +bool eq_fgmm_auth_failure(const fgmm_auth_failure_t *a, const fgmm_auth_failure_t *b); +void free_fgmm_auth_failure(const fgmm_auth_failure_t *msg); + +#endif /* FGMM_AUTH_FAILURE_H */ diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c index 323cffe7e7..1b607589d9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c @@ -26,6 +26,7 @@ #include "common/utils/ds/byte_array.h" #define GPRS_TIMER_LENGTH 3 // octets +#define FGS_NAS_CAUSE_LENGTH 1 /** * Encode PDU Session Status and PDU session reactivation result (optional IEs) @@ -158,3 +159,27 @@ int decode_eap_msg_ie(const byte_array_t *buffer) PRINT_NAS_ERROR("EAP message IE in NAS Service Reject is not handled\n"); return eap_msg_len + 2; // content length + 2 octets for the length IE } + +int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause) +{ + uint32_t encoded = 0; + + if (buffer->len < FGS_NAS_CAUSE_LENGTH) + return -1; + + buffer->buf[encoded++] = *cause; + + return encoded; +} + +int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer) +{ + int decoded = 0; + + if (buffer->len < FGS_NAS_CAUSE_LENGTH) + return -1; // nothing to decode + + *cause = buffer->buf[decoded++]; + + return decoded; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h index b757620506..25118f2742 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h @@ -165,5 +165,7 @@ int encode_gprs_timer_ie(byte_array_t *buffer, nas_service_IEI_t iei, const gprs int decode_gprs_timer_ie(gprs_timer_t *timer, const byte_array_t *buffer); bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b); int decode_eap_msg_ie(const byte_array_t *buffer); +int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause); +int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer); #endif /* FGS_LIB_H */ \ No newline at end of file diff --git a/openair3/NAS/NR_UE/5GS/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/CMakeLists.txt index e04abb02db..9a7feabb72 100644 --- a/openair3/NAS/NR_UE/5GS/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(fgs_lib PUBLIC fgs_5gsm_lib fgs_5gmm_ies_lib nas_common_ies_lib + ds ) target_include_directories(fgs_lib PUBLIC . 5GMM/MSG 5GMM/IES) diff --git a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c index a73ee9b2be..faea1c8df0 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -6,6 +6,7 @@ #include "fgs_service_request.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" +#include "fgmm_authentication_failure.h" #include "nr_nas_msg.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) @@ -170,10 +171,46 @@ static void test_service_reject(void) free_fgs_service_reject(&orig); } +/** @brief Test NAS Authentication Failure enc/dec */ +static void test_auth_failure(void) +{ + // Dummy NAS Authentication Failure message + uint8_t afp[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + const fgmm_auth_failure_t orig = { + .cause = Synch_failure, + .authentication_failure_param.len = 6, + .authentication_failure_param.buf = afp, + }; + + // Expected encoded data + uint8_t expected_enc[] = {0x15, 0x30, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + + // Buffer + uint8_t buf[16] = {0}; + byte_array_t buffer = {.buf = buf, .len = sizeof(buf)}; + + // Encode + int encoded_length = encode_fgmm_auth_failure(&buffer, &orig); + AssertFatal(encoded_length == sizeofArray(expected_enc), "encode_fgmm_auth_failure() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + AssertFatal(memcmp(buffer.buf, expected_enc, encoded_length) == 0, "Encoding mismatch!\n"); + + // Decode + fgmm_auth_failure_t dec = {0}; + int decoded_length = decode_fgmm_auth_failure(&dec, &buffer); + AssertFatal(decoded_length >= 0, "decode_fgmm_auth_failure() failed\n"); + + // Compare original and decoded messages + AssertFatal(eq_fgmm_auth_failure(&orig, &dec), "test_auth_failure() failed: original and decoded messages do not match\n"); + free_fgmm_auth_failure(&dec); +} + int main() { test_service_request(); test_service_accept(); test_service_reject(); + test_auth_failure(); return 0; } diff --git a/openair3/NAS/NR_UE/CMakeLists.txt b/openair3/NAS/NR_UE/CMakeLists.txt index 5e7d5da428..ec391092e5 100644 --- a/openair3/NAS/NR_UE/CMakeLists.txt +++ b/openair3/NAS/NR_UE/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(nr_nas PUBLIC fgs_5gmm_ies_lib nas_common_ies_lib nas_utils + ds ) target_include_directories(nr_nas PUBLIC . 5GS/)