Merge remote-tracking branch 'origin/nr-ue-nas-auth-failure' into integration_2025_w19 (!3381)
Add 5GMM Authentication Failure enc/dec lib and unit test This MR is introducing the 5GMM Authentication Failure message library as per 8.2.4 of 3GPP TS 24.501. This message is sent from UE to network under certain conditions. The message is also introduced in stack and is send if the received ngKSI already in use. - add new library for 5GMM Authentication Failure enc/dec and unit test - introduce handler and generate function for NAS Authentication Failure store ngKSI - send Authentication Failure if ngKSI is already associated with one of the 5G security contexts stored in the UE Closes #852
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 <string.h>
|
||||
#include <arpa/inet.h> // For htons and ntohs
|
||||
#include <stdlib.h> // 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);
|
||||
}
|
||||
@@ -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 <stdint.h>
|
||||
#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 */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "NasKeySetIdentifier.h"
|
||||
|
||||
#ifndef FGS_AUTHENTICATION_REQUEST_H_
|
||||
#define FGS_AUTHENTICATION_REQUEST_H_
|
||||
|
||||
typedef struct {
|
||||
// NAS key set identifier (Mandatory)
|
||||
NasKeySetIdentifier ngKSI;
|
||||
// ABBA (Mandatory)
|
||||
int abba;
|
||||
} fgs_authentication_request_t;
|
||||
|
||||
#endif /* ! defined(FGS_AUTHENTICATION_REQUEST_H_) */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "RegistrationComplete.h"
|
||||
#include "RegistrationRequest.h"
|
||||
#include "fgs_service_request.h"
|
||||
#include "fgmm_authentication_failure.h"
|
||||
|
||||
/* Message types defintions for:
|
||||
(a) 5GS Mobility Management (5GMM) (IDs 0x41 - 0x68)
|
||||
@@ -222,6 +223,7 @@ typedef struct {
|
||||
fgs_service_request_msg_t service_request;
|
||||
fgmm_identity_response_msg fgs_identity_response;
|
||||
fgs_authentication_response_msg fgs_auth_response;
|
||||
fgmm_auth_failure_t fgmm_auth_failure;
|
||||
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
|
||||
fgs_security_mode_complete_msg fgs_security_mode_complete;
|
||||
registration_complete_msg registration_complete;
|
||||
|
||||
@@ -73,6 +73,11 @@ int mm_msg_encode(const fgmm_nas_message_plain_t *p, uint8_t *buffer, uint32_t l
|
||||
case FGS_AUTHENTICATION_RESPONSE:
|
||||
enc_msg = encode_fgs_authentication_response(&p->mm_msg.fgs_auth_response, buffer, len);
|
||||
break;
|
||||
case FGS_AUTHENTICATION_FAILURE: {
|
||||
byte_array_t ba = {.buf = buffer, .len = len};
|
||||
enc_msg = encode_fgmm_auth_failure(&ba, &p->mm_msg.fgmm_auth_failure);
|
||||
break;
|
||||
}
|
||||
case FGS_SECURITY_MODE_COMPLETE:
|
||||
enc_msg = encode_fgs_security_mode_complete(&p->mm_msg.fgs_security_mode_complete, buffer, len);
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,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)
|
||||
@@ -230,11 +231,47 @@ 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_regression_registration_accept();
|
||||
test_service_request();
|
||||
test_service_accept();
|
||||
test_service_reject();
|
||||
test_auth_failure();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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/)
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "RegistrationAccept.h"
|
||||
#include "SORTransparentContainer.h"
|
||||
#include "FGSIdentityResponse.h"
|
||||
#include "fgmm_authentication_request.h"
|
||||
#include "T.h"
|
||||
#include "aka_functions.h"
|
||||
#include "assertions.h"
|
||||
@@ -839,6 +840,58 @@ static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialN
|
||||
free(res.value);
|
||||
}
|
||||
|
||||
/** @brief Send Authentication Failure message from the UE to the AMF to
|
||||
* indicate that authentication of the network has failed */
|
||||
static void generateAuthenticationFailure(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, cause_id_t cause)
|
||||
{
|
||||
int size = sizeof(fgmm_msg_header_t);
|
||||
fgmm_nas_message_plain_t plain = {0};
|
||||
|
||||
// Plain 5GMM header
|
||||
plain.header = set_mm_header(FGS_AUTHENTICATION_FAILURE, PLAIN_5GS_MSG);
|
||||
size += sizeof(plain.header);
|
||||
// 5GMM Cause (Mandatory)
|
||||
fgmm_auth_failure_t *mm_msg = &plain.mm_msg.fgmm_auth_failure;
|
||||
mm_msg->cause = cause;
|
||||
size += 1;
|
||||
initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data));
|
||||
initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size);
|
||||
}
|
||||
|
||||
static void handle_fgmm_authentication_request(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, byte_array_t *buffer)
|
||||
{
|
||||
LOG_D(NAS, "Received NAS Authentication Request\n");
|
||||
fgs_authentication_request_t msg = {0};
|
||||
int size = 0;
|
||||
int decoded = 0;
|
||||
|
||||
// decode plain 5GMM message header
|
||||
fgmm_msg_header_t mm_header = {0};
|
||||
if ((decoded = decode_5gmm_msg_header(&mm_header, buffer->buf + size, buffer->len - size)) < 0) {
|
||||
LOG_E(NAS, "decode_5gmm_msg_header failure in NAS Authentication Request handling\n");
|
||||
return;
|
||||
}
|
||||
size += decoded;
|
||||
// NAS key set identifier (Mandatory)
|
||||
if ((decoded = decode_nas_key_set_identifier(&msg.ngKSI, 0, buffer->buf[decoded])) < 0) {
|
||||
LOG_E(NAS, "decode_nas_key_set_identifier failure in NAS Authentication Request handling\n");
|
||||
return;
|
||||
}
|
||||
size += decoded;
|
||||
if (!nas->ksi) {
|
||||
nas->ksi = malloc_or_fail(sizeof(*nas->ksi));
|
||||
*nas->ksi = msg.ngKSI.naskeysetidentifier;
|
||||
LOG_D(NAS, "Stored NAS Key Set Identifier %d\n", *nas->ksi);
|
||||
} else if (*nas->ksi == msg.ngKSI.naskeysetidentifier) {
|
||||
/* If the ngKSI value received is already associated with one
|
||||
of the 5G security contexts stored in the UE, send failure message */
|
||||
LOG_E(NAS, "Invalid NAS Key Set Identifier: send Authentication Failure\n");
|
||||
generateAuthenticationFailure(nas, initialNasMsg, ngKSI_already_in_use);
|
||||
return;
|
||||
}
|
||||
generateAuthenticationResp(nas, initialNasMsg, buffer->buf);
|
||||
}
|
||||
|
||||
int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32])
|
||||
{
|
||||
MessageDef *message_p;
|
||||
@@ -1720,9 +1773,11 @@ void *nas_nrue(void *args_p)
|
||||
case FGS_IDENTITY_REQUEST:
|
||||
generateIdentityResponse(&initialNasMsg, *(pdu_buffer + 3), nas->uicc);
|
||||
break;
|
||||
case FGS_AUTHENTICATION_REQUEST:
|
||||
generateAuthenticationResp(nas, &initialNasMsg, pdu_buffer);
|
||||
case FGS_AUTHENTICATION_REQUEST: {
|
||||
byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length};
|
||||
handle_fgmm_authentication_request(nas, &initialNasMsg, &buffer);
|
||||
break;
|
||||
}
|
||||
case FGS_SECURITY_MODE_COMMAND:
|
||||
handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
|
||||
@@ -102,6 +102,8 @@ typedef struct {
|
||||
int t3448;
|
||||
// Timer t3446 in seconds (-1 = disabled)
|
||||
int t3446;
|
||||
/* NAS Key Set Identifier associated to the security context */
|
||||
uint8_t *ksi;
|
||||
} nr_ue_nas_t;
|
||||
|
||||
nr_ue_nas_t *get_ue_nas_info(module_id_t module_id);
|
||||
|
||||
Reference in New Issue
Block a user