mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-14 05:00:31 +00:00
Compare commits
8 Commits
develop
...
smc-auth-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
113475fa1e | ||
|
|
badb41f301 | ||
|
|
c5b41ba3fd | ||
|
|
4584d5aadc | ||
|
|
f38bf4f3ab | ||
|
|
a4ef158b01 | ||
|
|
d3727884e2 | ||
|
|
faa81c024b |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,4 +25,4 @@ tags
|
||||
nfapi_nr_interface_scf
|
||||
*.log
|
||||
*.out
|
||||
CMakeUserPresets.json
|
||||
CMakeUserPresets.json
|
||||
@@ -4,6 +4,7 @@ add_library(fgs_5gmm_ies_lib OBJECT
|
||||
FGSRegistrationResult.c
|
||||
FGMMCapability.c
|
||||
NrUESecurityCapability.c
|
||||
FGSNasCause.c
|
||||
FGCNasMessageContainer.c
|
||||
SORTransparentContainer.c
|
||||
)
|
||||
|
||||
64
openair3/NAS/NR_UE/5GS/5GMM/IES/FGSNasCause.c
Normal file
64
openair3/NAS/NR_UE/5GS/5GMM/IES/FGSNasCause.c
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file FGSNASSecurityModeReject.c
|
||||
|
||||
\brief security mode complete reject for gNB
|
||||
\author Eduard Vlad
|
||||
\email: eduard.vlad@rwth-aachen.de
|
||||
\date 2025
|
||||
*/
|
||||
|
||||
#include "FGSNasCause.h"
|
||||
#include "TLVEncoder.h"
|
||||
#include "TLVDecoder.h"
|
||||
|
||||
int encode_fgs_nas_cause(const FGSNasCause *emmcause, uint8_t iei, uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
uint32_t encoded = 0;
|
||||
/* Checking IEI and pointer */
|
||||
CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, FGS_NAS_CAUSE_MINIMUM_LENGTH, len);
|
||||
|
||||
/* Cause has no IE */
|
||||
if (iei > 0) {
|
||||
*buffer = iei;
|
||||
encoded++;
|
||||
}
|
||||
|
||||
*(buffer + encoded) = *emmcause;
|
||||
encoded++;
|
||||
return encoded;
|
||||
}
|
||||
|
||||
int decode_fgs_nas_cause(FGSNasCause *fgs_nas_cause, uint8_t iei, uint8_t *buffer, uint32_t len){
|
||||
int decoded = 0;
|
||||
|
||||
/* Cause has no IE */
|
||||
if (iei > 0) {
|
||||
CHECK_IEI_DECODER(iei, *buffer);
|
||||
decoded++;
|
||||
}
|
||||
|
||||
(*fgs_nas_cause) = *(buffer + decoded);
|
||||
decoded++;
|
||||
|
||||
return decoded;
|
||||
}
|
||||
44
openair3/NAS/NR_UE/5GS/5GMM/IES/FGSNasCause.h
Normal file
44
openair3/NAS/NR_UE/5GS/5GMM/IES/FGSNasCause.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file FGSNASSecurityModeReject.c
|
||||
|
||||
\brief security mode complete reject for gNB
|
||||
\author Eduard Vlad
|
||||
\email: eduard.vlad@rwth-aachen.de
|
||||
\date 2025
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FGS_NAS_CAUSE_H_
|
||||
#define FGS_NAS_CAUSE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t FGSNasCause;
|
||||
|
||||
#define FGS_NAS_CAUSE_MINIMUM_LENGTH 1
|
||||
#define FGS_NAS_CAUSE_MAXIMUM_LENGTH 1
|
||||
|
||||
int encode_fgs_nas_cause(const FGSNasCause *fgs_nas_cause, uint8_t iei, uint8_t *buffer, uint32_t len);
|
||||
int decode_fgs_nas_cause(FGSNasCause *fgs_nas_cause, uint8_t iei, uint8_t *buffer, uint32_t len);
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@ add_library(fgs_5gmm_lib OBJECT
|
||||
FGSIdentityResponse.c
|
||||
FGSAuthenticationResponse.c
|
||||
FGSNASSecurityModeComplete.c
|
||||
FGSNASSecurityModeReject.c
|
||||
RegistrationComplete.c
|
||||
FGSUplinkNasTransport.c
|
||||
FGSDeregistrationRequestUEOriginating.c
|
||||
|
||||
59
openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c
Normal file
59
openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file FGSNASSecurityModeReject.c
|
||||
|
||||
\brief security mode complete reject for gNB
|
||||
\author Eduard Vlad
|
||||
\email: eduard.vlad@rwth-aachen.de
|
||||
\date 2025
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FGSNASSecurityModeReject.h"
|
||||
#include "FGSNasCause.h"
|
||||
|
||||
int encode_fgs_security_mode_reject(const fgs_security_mode_reject_msg *fgs_security_mode_rej, uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
int encoded = 0;
|
||||
int encode_result = 0;
|
||||
|
||||
/* Encode the Cause, which has no IEI */
|
||||
if((encode_result = encode_fgs_nas_cause(&fgs_security_mode_rej->cause,0 , buffer + encoded, len - encoded)) < 0) {
|
||||
return encode_result;
|
||||
} else {
|
||||
encoded += encode_result;
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
int decode_fgs_security_mode_reject(fgs_security_mode_reject_msg *securitymodereject, uint8_t *buffer, uint32_t len){
|
||||
int decoded = 0;
|
||||
|
||||
/* Decode the Cause, which has no IEI */
|
||||
if((decoded = decode_fgs_nas_cause(&securitymodereject->cause, 0, buffer, len)) < 0) {
|
||||
return decoded;
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
57
openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h
Normal file
57
openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file FGSNASSecurityModeComplete.h
|
||||
|
||||
\brief security mode reject procedures for gNB
|
||||
\author Eduard Vlad
|
||||
\email: eduard.vlad@rwth-aachen.de
|
||||
\date 2025
|
||||
\version 0.1
|
||||
*/
|
||||
|
||||
#ifndef FGS_NAS_security_mode_reject_H_
|
||||
#define FGS_NAS_security_mode_reject_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "MessageType.h"
|
||||
#include "FGSNasCause.h"
|
||||
|
||||
/*
|
||||
* Message name: security mode reject
|
||||
* Description: The SECURITY MODE REJECT message is sent by the UE to the AMF to
|
||||
* indicate that the corresponding security mode command has been rejected.
|
||||
* See table 8.2.27.1.1.
|
||||
*
|
||||
* Significance: dual
|
||||
* Direction: UE to AMF
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
/* Mandatory fields */
|
||||
FGSNasCause cause;
|
||||
} fgs_security_mode_reject_msg;
|
||||
|
||||
int encode_fgs_security_mode_reject(const fgs_security_mode_reject_msg *fgs_security_mode_comp, uint8_t *buffer, uint32_t len);
|
||||
int decode_fgs_security_mode_reject(fgs_security_mode_reject_msg *securitymodereject, uint8_t *buffer, uint32_t len);
|
||||
|
||||
#endif /* ! defined(FGS_NAS_security_mode_reject_H_) */
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "FGSIdentityResponse.h"
|
||||
#include "FGSMobileIdentity.h"
|
||||
#include "FGSNASSecurityModeComplete.h"
|
||||
#include "FGSNASSecurityModeReject.h"
|
||||
#include "FGSUplinkNasTransport.h"
|
||||
#include "RegistrationComplete.h"
|
||||
#include "RegistrationRequest.h"
|
||||
@@ -224,6 +225,7 @@ typedef struct {
|
||||
fgs_authentication_response_msg fgs_auth_response;
|
||||
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
|
||||
fgs_security_mode_complete_msg fgs_security_mode_complete;
|
||||
fgs_security_mode_reject_msg fgs_security_mode_reject;
|
||||
registration_complete_msg registration_complete;
|
||||
fgs_uplink_nas_transport_msg uplink_nas_transport;
|
||||
} mm_msg; /* 5GS Mobility Management messages */
|
||||
|
||||
@@ -76,6 +76,9 @@ int mm_msg_encode(const fgmm_nas_message_plain_t *p, uint8_t *buffer, uint32_t l
|
||||
case FGS_SECURITY_MODE_COMPLETE:
|
||||
enc_msg = encode_fgs_security_mode_complete(&p->mm_msg.fgs_security_mode_complete, buffer, len);
|
||||
break;
|
||||
case FGS_SECURITY_MODE_REJECT:
|
||||
enc_msg = encode_fgs_security_mode_reject(&p->mm_msg.fgs_security_mode_reject, buffer, len);
|
||||
break;
|
||||
case FGS_UPLINK_NAS_TRANSPORT:
|
||||
enc_msg = encode_fgs_uplink_nas_transport(&p->mm_msg.uplink_nas_transport, buffer, len);
|
||||
break;
|
||||
|
||||
@@ -126,6 +126,149 @@ static const char *print_info(uint8_t id, const text_info_t *array, uint8_t arra
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the MAC of a Security Protected NAS message
|
||||
* @param[in] pdu_buffer The buffer containing the NAS message
|
||||
* @param[in] pdu_length The length of the NAS message
|
||||
* @param[out] mac The MAC of the NAS message
|
||||
* @return true if the MAC was successfully extracted, false otherwise
|
||||
*/
|
||||
bool nas_security_get_mac(uint8_t *pdu_buffer, int pdu_length, uint8_t *mac)
|
||||
{
|
||||
/* Check for Security Protected Header */
|
||||
/* at least 8 bytes for Security Protected MM Message */
|
||||
if (pdu_length < 8)
|
||||
return false;
|
||||
|
||||
/* Only message type, that is not protected (c.f.
|
||||
TS 24.501 9.3 Security Header Type) */
|
||||
if((Security_header_t)pdu_buffer[1] == PLAIN_5GS_MSG)
|
||||
return false;
|
||||
|
||||
/* Get the MAC [EPD][SecHdr][MAC0]..[MAC3] - success */
|
||||
for (int i = 0; i < 4; i++)
|
||||
mac[i] = pdu_buffer[2 + i];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Get the Security Header of a NAS message
|
||||
* @param[in] msg The buffer containing the NAS message
|
||||
* @param[in] msg_length The length of the NAS message
|
||||
* @param[out] sec_hdr The Security Header of the NAS message
|
||||
* @return true if the Security Header was successfully extracted, false otherwise
|
||||
*/
|
||||
bool nas_security_get_sec_hdr(uint8_t *msg, int msg_length, Security_header_t *sec_hdr)
|
||||
{
|
||||
/* Shortest message is [EPD][SecHdrType][Payl]*/
|
||||
if (msg_length < 3){
|
||||
LOG_E(NAS, "Invalid NAS message length %d\n", msg_length);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the SecHdr and check for validity */
|
||||
uint8_t sec_hdr_type = msg[1] & 0x0f;
|
||||
if(sec_hdr_type > INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX){
|
||||
LOG_E(NAS, "Invalid Security Header Type %d\n", sec_hdr_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ok. */
|
||||
*sec_hdr = (Security_header_t)sec_hdr_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief Compute the MAC of a NAS message
|
||||
* @param[in] nas The NAS context
|
||||
* @param[in] pdu_buffer The buffer containing the NAS message
|
||||
* @param[in] is_uplink True if the message is uplink, false Downlink
|
||||
* @param[in] is3gpp_access True if the message is 3GPP access, false otherwise
|
||||
* @param[in] pdu_length The length of the NAS message
|
||||
* @param[out] mac The MAC of the NAS message
|
||||
*/
|
||||
void nas_security_compute_mac(nr_ue_nas_t *nas, uint8_t *pdu_buffer, bool is_uplink, bool is3gpp_access, int pdu_length, uint8_t *mac)
|
||||
{
|
||||
/* Compute the MAC */
|
||||
nas_stream_cipher_t stream_cipher;
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
|
||||
/* Select the right count in the context */
|
||||
if(is_uplink)
|
||||
stream_cipher.count = nas->security.nas_count_ul;
|
||||
else
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
|
||||
/* 3GPP access is 1, non-3GPP access is 2 - see 3GPP TS 33.501 6.4.2.2 */
|
||||
stream_cipher.bearer = is3gpp_access ? 1 : 2;
|
||||
|
||||
/* Configure Direction for MAC protection */
|
||||
stream_cipher.direction = is_uplink ? 0 : 1;
|
||||
|
||||
/* Possibly encrypted message */
|
||||
stream_cipher.message = pdu_buffer;
|
||||
|
||||
/* length in bits */
|
||||
stream_cipher.blength = pdu_length << 3;
|
||||
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief: Decrypt the payload of a NAS message. The buffer is modified in place
|
||||
* @param[in] nas The NAS context
|
||||
* @param[in] pdu_buffer The buffer containing the full (header + payload) NAS message
|
||||
* @param[in] is_uplink True if the message is uplink, false Downlink
|
||||
* @param[in] is3gpp_access True if the message is 3GPP access, false otherwise
|
||||
* @param[in] pdu_length The length of the NAS message
|
||||
*/
|
||||
void nas_security_decrypt_payload(nr_ue_nas_t *nas, uint8_t *pdu_buffer, bool is_uplink, bool is3gpp_access, int pdu_length){
|
||||
Security_header_t sec_hdr;
|
||||
|
||||
if(!nas_security_get_sec_hdr(pdu_buffer, pdu_length, &sec_hdr)){
|
||||
LOG_E(NAS, "Failed to get Security Header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nothing to do for unencrypted msgs */
|
||||
if(sec_hdr == PLAIN_5GS_MSG || sec_hdr == INTEGRITY_PROTECTED){
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get integrity keys, and algorithms */
|
||||
nas_stream_cipher_t stream_cipher;
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
|
||||
/* Use the estimated count the right count in the context */
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
/* 3GPP access is 1, non-3GPP access is 2 - see 3GPP TS 33.501 6.4.2.2 */
|
||||
stream_cipher.bearer = is3gpp_access ? 1 : 2;
|
||||
|
||||
/* Decryption only in downlink direction */
|
||||
stream_cipher.direction = 1;
|
||||
|
||||
/* [EPD][SHR][MAC0]..[MAC3][PDU...]*/
|
||||
uint8_t *plain_payload = pdu_buffer + 7;
|
||||
stream_cipher.message = plain_payload;
|
||||
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (pdu_length - 7) << 3;
|
||||
|
||||
/* Allocate output buffer for body only */
|
||||
unsigned int plain_length = pdu_length - 7;
|
||||
uint8_t *decrypted = malloc(plain_length);
|
||||
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, decrypted);
|
||||
|
||||
/* Override and free the decrypted payload */
|
||||
memcpy(plain_payload, decrypted, plain_length);
|
||||
free(decrypted);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_buffer, int pdu_length)
|
||||
{
|
||||
if (nas->security_container == NULL)
|
||||
@@ -169,35 +312,18 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_b
|
||||
}
|
||||
|
||||
/* check integrity */
|
||||
uint8_t computed_mac[NAS_INTEGRITY_SIZE];
|
||||
nas_stream_cipher_t stream_cipher;
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
stream_cipher.bearer = 1; /* todo: don't hardcode */
|
||||
stream_cipher.direction = 1;
|
||||
stream_cipher.message = pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH - 1;
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (pdu_length - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH + 1) << 3;
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, computed_mac);
|
||||
|
||||
/* [EPD][SHD][MAC0]...[MAC3][SEQNO][PAYL]*/
|
||||
uint8_t *received_mac = pdu_buffer + 2;
|
||||
uint8_t computed_mac[4];
|
||||
nas_security_compute_mac(nas, pdu_buffer + 6, false, true, pdu_length - 6, computed_mac);
|
||||
|
||||
if (memcmp(received_mac, computed_mac, NAS_INTEGRITY_SIZE) != 0)
|
||||
return NAS_SECURITY_INTEGRITY_FAILED;
|
||||
|
||||
/* decipher */
|
||||
uint8_t payload_len = pdu_length - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
|
||||
uint8_t buf[payload_len];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
stream_cipher.bearer = 1; /* todo: don't hardcode */
|
||||
stream_cipher.direction = 1;
|
||||
stream_cipher.message = pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (payload_len) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(pdu_buffer + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH, buf, payload_len);
|
||||
nas_security_decrypt_payload(nas, pdu_buffer, false, true, pdu_length);
|
||||
|
||||
/* update estimated DL Counter */
|
||||
nas->security.nas_count_dl++;
|
||||
|
||||
return NAS_SECURITY_INTEGRITY_PASSED;
|
||||
@@ -917,8 +1043,56 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
}
|
||||
}
|
||||
|
||||
static void generateSecurityModeReject(as_nas_info_t *initialNasMsg, cause_id_t cause)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
// Set 5GMM plain header
|
||||
fgmm_nas_message_plain_t plain = {0};
|
||||
plain.header = set_mm_header(FGS_SECURITY_MODE_REJECT, PLAIN_5GS_MSG);
|
||||
size += 3; /* = sizeof(plain.header) */
|
||||
|
||||
// Set plain FGMM Security Mode Reject
|
||||
fgs_security_mode_reject_msg *smc_rej_msg = &plain.mm_msg.fgs_security_mode_reject;
|
||||
// Cause
|
||||
smc_rej_msg->cause = cause;
|
||||
size += 1; /* += sizeof(fgs_security_mode_reject_msg) */
|
||||
|
||||
// Encode the message, with total length = 4 (fixed)
|
||||
initialNasMsg->nas_data = malloc_or_fail(size); /* * sizeof(*initialNasMsg->nas_data) = 1*/
|
||||
|
||||
initialNasMsg->length =
|
||||
mm_msg_encode(&plain, (uint8_t *)initialNasMsg->nas_data, size);
|
||||
}
|
||||
|
||||
static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length)
|
||||
{
|
||||
/* Handle security mode command: must be authenticated, especially if no security
|
||||
context has been previously established. */
|
||||
uint8_t recv_mac[4];
|
||||
Security_header_t sec_hdr;
|
||||
|
||||
/* Must have valid security header*/
|
||||
if(!nas_security_get_sec_hdr(pdu, pdu_length, &sec_hdr)) {
|
||||
LOG_E(NAS, "Received Security Mode Command without integrity protection.\n");
|
||||
generateSecurityModeReject(initialNasMsg, Security_mode_rejected_unspecified);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Must be integrity protected with new context (=3), see 3GPP TS 24.501 5.4.2.2 */
|
||||
if(sec_hdr != INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX) {
|
||||
LOG_E(NAS, "Received Security Mode Command with invalid security header type %d.\n", sec_hdr);
|
||||
generateSecurityModeReject(initialNasMsg, Security_mode_rejected_unspecified);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Must have a MAC - checked after deriving keys */
|
||||
if(!nas_security_get_mac(pdu, pdu_length, recv_mac)) {
|
||||
LOG_E(NAS, "Received Security Mode Command with invalid MAC.\n");
|
||||
generateSecurityModeReject(initialNasMsg, Security_mode_rejected_unspecified);
|
||||
return;
|
||||
}
|
||||
|
||||
/* retrieve integrity and ciphering algorithms */
|
||||
AssertFatal(pdu_length > 10, "nas: bad pdu\n");
|
||||
int ciphering_algorithm = (pdu[10] >> 4) & 0x0f;
|
||||
@@ -944,8 +1118,37 @@ static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* todo: stream_security_container_delete() is not called anywhere, deal with that */
|
||||
nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int);
|
||||
if (integrity_algorithm != EIA0_ALG_ID) {
|
||||
nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int);
|
||||
} else {
|
||||
LOG_E(NAS, "Rejecting Invalid NULL integrity %d for 5G!\n",
|
||||
integrity_algorithm);
|
||||
nas->security_container = NULL;
|
||||
}
|
||||
|
||||
/* Handle the invalid container with a reject message */
|
||||
if(nas->security_container == NULL) {
|
||||
LOG_W(NAS, "Could not create security container!\n");
|
||||
generateSecurityModeReject(initialNasMsg, Security_mode_rejected_unspecified);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check MAC and delete context if it does not match */
|
||||
uint8_t computed_mac[4];
|
||||
nas_security_compute_mac(nas, pdu + 6, false, true, pdu_length - 6, computed_mac);
|
||||
|
||||
/* Teardown security container if mismatch. */
|
||||
if(memcmp(computed_mac, recv_mac, 4) != 0) {
|
||||
LOG_W(NAS, "MAC does not match\n");
|
||||
LOG_W(NAS, "Expected: %x %x %x %x\n", computed_mac[0], computed_mac[1], computed_mac[2], computed_mac[3]);
|
||||
LOG_W(NAS, "Received: %x %x %x %x\n", recv_mac[0], recv_mac[1], recv_mac[2], recv_mac[3]);
|
||||
stream_security_container_delete(nas->security_container);
|
||||
nas->security_container = NULL;
|
||||
|
||||
/* Signal rejection */
|
||||
generateSecurityModeReject(initialNasMsg, Security_mode_rejected_unspecified);
|
||||
return;
|
||||
}
|
||||
|
||||
nas_itti_kgnb_refresh_req(nas->UE_id, nas->security.kgnb);
|
||||
generateSecurityModeComplete(nas, initialNasMsg);
|
||||
|
||||
Reference in New Issue
Block a user