Merge remote-tracking branch 'origin/bugfix-nas-security-msg-type' into integration_2025_w27 (!3494)
bugfix: read msg_type only after deciphering
There was a problem with accessing msg_type from the input buffer before
deciphering, giving obviously wrong value.
CI team: we should add a test in the CI with NAS ciphering + integrity
(connection to the core) set to not null (I suggest nea2/nia2). With
openair's core, this is done by setting this in the amf config file
(nia1 and nea2 at the top of the list):
supported_integrity_algorithms:
- "NIA2"
- "NIA1"
- "NIA0"
supported_encryption_algorithms:
- "NEA2"
- "NEA1"
- "NEA0"
And also put full security in the AS. This is done with this in the gnb
config file:
security = {
ciphering_algorithms = ( "nea2", "nea0" );
integrity_algorithms = ( "nia2", "nia1", "nia0" );
drb_ciphering = "yes";
drb_integrity = "yes"
};
Ideally we should test this with both openair UE and cots UE. But as a
strict minimum do for openair UE (this is where the bug was).
No need to do much traffic, a few ping is enough. But if you want to
check throughput with full security, why not.
This commit is contained in:
@@ -65,9 +65,9 @@ oc-cn5g:
|
|||||||
Host: avra
|
Host: avra
|
||||||
NetworkScript: echo "inet 172.21.6.102"
|
NetworkScript: echo "inet 172.21.6.102"
|
||||||
RunIperf3Server: False
|
RunIperf3Server: False
|
||||||
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran"
|
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran"
|
||||||
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran"
|
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran"
|
||||||
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran %%log_dir%%"
|
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran %%log_dir%%"
|
||||||
|
|
||||||
oc-cn5g-20897:
|
oc-cn5g-20897:
|
||||||
Host: cacofonix
|
Host: cacofonix
|
||||||
@@ -89,8 +89,8 @@ matix-cn5g:
|
|||||||
Host: matix
|
Host: matix
|
||||||
NetworkScript: docker exec prod-trf-gen ip a show dev eth0
|
NetworkScript: docker exec prod-trf-gen ip a show dev eth0
|
||||||
RunIperf3Server: False
|
RunIperf3Server: False
|
||||||
Deploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type start-basic"
|
Deploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type start-basic"
|
||||||
Undeploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type stop-basic"
|
Undeploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type stop-basic"
|
||||||
LogCollect:
|
LogCollect:
|
||||||
- "docker logs oai-smf > %%log_dir%%/oai-smf.log"
|
- "docker logs oai-smf > %%log_dir%%/oai-smf.log"
|
||||||
- "docker logs oai-amf > %%log_dir%%/oai-amf.log"
|
- "docker logs oai-amf > %%log_dir%%/oai-amf.log"
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ security = {
|
|||||||
# preferred ciphering algorithms
|
# preferred ciphering algorithms
|
||||||
# the first one of the list that an UE supports in chosen
|
# the first one of the list that an UE supports in chosen
|
||||||
# valid values: nea0, nea1, nea2, nea3
|
# valid values: nea0, nea1, nea2, nea3
|
||||||
ciphering_algorithms = ( "nea0" );
|
ciphering_algorithms = ( "nea2", "nea0" );
|
||||||
|
|
||||||
# preferred integrity algorithms
|
# preferred integrity algorithms
|
||||||
# the first one of the list that an UE supports in chosen
|
# the first one of the list that an UE supports in chosen
|
||||||
@@ -223,7 +223,7 @@ security = {
|
|||||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||||
drb_ciphering = "yes";
|
drb_ciphering = "yes";
|
||||||
drb_integrity = "no";
|
drb_integrity = "yes";
|
||||||
};
|
};
|
||||||
|
|
||||||
log_config :
|
log_config :
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ security = {
|
|||||||
# preferred ciphering algorithms
|
# preferred ciphering algorithms
|
||||||
# the first one of the list that an UE supports in chosen
|
# the first one of the list that an UE supports in chosen
|
||||||
# valid values: nea0, nea1, nea2, nea3
|
# valid values: nea0, nea1, nea2, nea3
|
||||||
ciphering_algorithms = ( "nea0" );
|
ciphering_algorithms = ( "nea2", "nea0" );
|
||||||
|
|
||||||
# preferred integrity algorithms
|
# preferred integrity algorithms
|
||||||
# the first one of the list that an UE supports in chosen
|
# the first one of the list that an UE supports in chosen
|
||||||
@@ -222,7 +222,7 @@ security = {
|
|||||||
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
|
||||||
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
|
||||||
drb_ciphering = "yes";
|
drb_ciphering = "yes";
|
||||||
drb_integrity = "no";
|
drb_integrity = "yes";
|
||||||
};
|
};
|
||||||
|
|
||||||
log_config :
|
log_config :
|
||||||
|
|||||||
@@ -301,7 +301,44 @@ static void nas_security_decrypt_payload(nr_ue_nas_t *nas, byte_array_t buffer,
|
|||||||
free(decrypted);
|
free(decrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer, fgs_nas_msg_t msg_type)
|
static fgs_nas_msg_t get_msg_type(uint8_t *pdu_buffer, uint32_t length)
|
||||||
|
{
|
||||||
|
if (pdu_buffer == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* get security header type */
|
||||||
|
if (length < 2)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
int security_header_type = pdu_buffer[1];
|
||||||
|
|
||||||
|
if (security_header_type == 0) {
|
||||||
|
/* plain NAS message */
|
||||||
|
if (length < 3)
|
||||||
|
goto error;
|
||||||
|
return pdu_buffer[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < 10)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
int msg_type = pdu_buffer[9];
|
||||||
|
|
||||||
|
if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) {
|
||||||
|
if (length < 17)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
msg_type = pdu_buffer[16];
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg_type;
|
||||||
|
|
||||||
|
error:
|
||||||
|
LOG_E(NAS, "[UE] Received invalid downlink message\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer)
|
||||||
{
|
{
|
||||||
if (nas->security_container == NULL)
|
if (nas->security_container == NULL)
|
||||||
return NAS_SECURITY_NO_SECURITY_CONTEXT;
|
return NAS_SECURITY_NO_SECURITY_CONTEXT;
|
||||||
@@ -314,9 +351,11 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b
|
|||||||
LOG_D(NAS, "Security type is: %s\n", print_info(security_type, security_header_type_s, sizeofArray(security_header_type_s)));
|
LOG_D(NAS, "Security type is: %s\n", print_info(security_type, security_header_type_s, sizeofArray(security_header_type_s)));
|
||||||
|
|
||||||
switch (security_type) {
|
switch (security_type) {
|
||||||
case PLAIN_5GS_MSG:
|
case PLAIN_5GS_MSG: {
|
||||||
|
fgs_nas_msg_t msg_type = get_msg_type(buffer.buf, buffer.len);
|
||||||
return unprotected_allowed(buffer, msg_type) ? NAS_SECURITY_UNPROTECTED : NAS_SECURITY_BAD_INPUT;
|
return unprotected_allowed(buffer, msg_type) ? NAS_SECURITY_UNPROTECTED : NAS_SECURITY_BAD_INPUT;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX:
|
case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX:
|
||||||
stream_security_container_delete(nas->security_container);
|
stream_security_container_delete(nas->security_container);
|
||||||
nas->security_container = NULL;
|
nas->security_container = NULL;
|
||||||
@@ -1707,43 +1746,6 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static fgs_nas_msg_t get_msg_type(uint8_t *pdu_buffer, uint32_t length)
|
|
||||||
{
|
|
||||||
if (pdu_buffer == NULL)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* get security header type */
|
|
||||||
if (length < 2)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
int security_header_type = pdu_buffer[1];
|
|
||||||
|
|
||||||
if (security_header_type == 0) {
|
|
||||||
/* plain NAS message */
|
|
||||||
if (length < 3)
|
|
||||||
goto error;
|
|
||||||
return pdu_buffer[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length < 10)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
int msg_type = pdu_buffer[9];
|
|
||||||
|
|
||||||
if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) {
|
|
||||||
if (length < 17)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
msg_type = pdu_buffer[16];
|
|
||||||
}
|
|
||||||
|
|
||||||
return msg_type;
|
|
||||||
|
|
||||||
error:
|
|
||||||
LOG_E(NAS, "[UE] Received invalid downlink message\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void send_nas_uplink_data_req(nr_ue_nas_t *nas, const as_nas_info_t *initial_nas_msg)
|
static void send_nas_uplink_data_req(nr_ue_nas_t *nas, const as_nas_info_t *initial_nas_msg)
|
||||||
{
|
{
|
||||||
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_UPLINK_DATA_REQ);
|
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_UPLINK_DATA_REQ);
|
||||||
@@ -2003,13 +2005,13 @@ void *nas_nrue(void *args_p)
|
|||||||
NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
||||||
|
|
||||||
byte_array_t ba = {.buf = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data, .len = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length};
|
byte_array_t ba = {.buf = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data, .len = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length};
|
||||||
fgs_nas_msg_t msg_type = get_msg_type(ba.buf, ba.len);
|
security_state_t security_state = nas_security_rx_process(nas, ba);
|
||||||
security_state_t security_state = nas_security_rx_process(nas, ba, msg_type);
|
|
||||||
if (security_state > NAS_SECURITY_INTEGRITY_PASSED) {
|
if (security_state > NAS_SECURITY_INTEGRITY_PASSED) {
|
||||||
LOG_E(NAS, "NAS integrity failed, discard incoming message: security state is %s\n", security_state_info[security_state].text);
|
LOG_E(NAS, "NAS integrity failed, discard incoming message: security state is %s\n", security_state_info[security_state].text);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fgs_nas_msg_t msg_type = get_msg_type(ba.buf, ba.len);
|
||||||
if (msg_type == FGS_REGISTRATION_ACCEPT) {
|
if (msg_type == FGS_REGISTRATION_ACCEPT) {
|
||||||
handle_registration_accept(nas, ba.buf, ba.len);
|
handle_registration_accept(nas, ba.buf, ba.len);
|
||||||
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||||
@@ -2071,13 +2073,13 @@ void *nas_nrue(void *args_p)
|
|||||||
uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data;
|
uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data;
|
||||||
int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length;
|
int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length;
|
||||||
byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length};
|
byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length};
|
||||||
fgs_nas_msg_t msg_type = get_msg_type(pdu_buffer, pdu_length);
|
security_state_t security_state = nas_security_rx_process(nas, buffer);
|
||||||
security_state_t security_state = nas_security_rx_process(nas, buffer, msg_type);
|
|
||||||
if (security_state > NAS_SECURITY_INTEGRITY_PASSED) {
|
if (security_state > NAS_SECURITY_INTEGRITY_PASSED) {
|
||||||
LOG_E(NAS, "NAS integrity failed, discard incoming message\n");
|
LOG_E(NAS, "NAS integrity failed, discard incoming message\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fgs_nas_msg_t msg_type = get_msg_type(pdu_buffer, pdu_length);
|
||||||
LOG_I(NAS,
|
LOG_I(NAS,
|
||||||
"[UE %ld] Received %s type %s with length %u\n",
|
"[UE %ld] Received %s type %s with length %u\n",
|
||||||
nas->UE_id,
|
nas->UE_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user