From 0df2cba2576dd842518c99bcea30a8c6470088b9 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 29 Oct 2022 12:26:09 +0900 Subject: [PATCH] Support SMF Security Indication IE (#1851) --- configs/open5gs/smf.yaml.in | 15 +++- src/smf/context.c | 150 ++++++++++++++++++++++++++++++++++++ src/smf/context.h | 14 ++++ src/smf/ngap-build.c | 84 ++++++++++++++++++++ 4 files changed, 262 insertions(+), 1 deletion(-) diff --git a/configs/open5gs/smf.yaml.in b/configs/open5gs/smf.yaml.in index 9aeb8e903..9d7df1ad3 100644 --- a/configs/open5gs/smf.yaml.in +++ b/configs/open5gs/smf.yaml.in @@ -440,7 +440,20 @@ logger: # mnc: 70 # tac: 99 # - +# +# +# According to 3GPP TS38.413 Section 9.3.1.27, +# Security Indication IE may be instructed to 5G gNB. +# +# If you set the security_indication in smf.yaml, +# this information is delivered using PDU Session Resource Request Transfer IE +# +# security_indication: +# integrity_protection_indication: required|preferred|not-needed +# confidentiality_protection_indication: required|preferred|not-needed +# maximum_integrity_protected_data_rate_uplink: bitrate64kbs|maximum-UE-rate +# maximum_integrity_protected_data_rate_downlink: bitrate64kbs|maximum-UE-rate +# smf: sbi: - addr: 127.0.0.4 diff --git a/src/smf/context.c b/src/smf/context.c index cf09db526..9736d0fbc 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -202,6 +202,83 @@ static int smf_context_validation(void) } } + if (self.security_indication.integrity_protection_indication || + self.security_indication.confidentiality_protection_indication) { + if (!self.security_indication.integrity_protection_indication || + !self.security_indication.confidentiality_protection_indication) { + ogs_error("Invalid security_indication [%s,%s]", + self.security_indication.integrity_protection_indication ? + self.security_indication.integrity_protection_indication : + "No integrity_protection_indication", + self.security_indication.confidentiality_protection_indication ? + self.security_indication.confidentiality_protection_indication : + "No confidentiality_protection_indication"); + return OGS_ERROR; + } + if (smf_integrity_protection_indication_value2enum( + self.security_indication.integrity_protection_indication) < 0) { + ogs_error("Invalid integrity_protection_indication [%s]", + self.security_indication.integrity_protection_indication); + return OGS_ERROR; + } + if (smf_confidentiality_protection_indication_value2enum( + self.security_indication. + confidentiality_protection_indication) < 0) { + ogs_error("Invalid confidentiality_protection_indication [%s]", + self.security_indication.confidentiality_protection_indication); + return OGS_ERROR; + } + } + + if (self.security_indication.maximum_integrity_protected_data_rate_uplink) { + NGAP_IntegrityProtectionIndication_t integrityProtectionIndication; + if (smf_maximum_integrity_protected_data_rate_uplink_value2enum( + self.security_indication. + maximum_integrity_protected_data_rate_uplink) < 0) { + ogs_error("Invalid " + "maximum_integrity_protected_data_rate_uplink [%s]", + self.security_indication. + maximum_integrity_protected_data_rate_uplink); + return OGS_ERROR; + } + integrityProtectionIndication = + smf_integrity_protection_indication_value2enum( + self.security_indication.integrity_protection_indication); + if (integrityProtectionIndication == + NGAP_IntegrityProtectionIndication_required || + integrityProtectionIndication == + NGAP_IntegrityProtectionIndication_preferred) { + } else { + ogs_error("Invalid security_indication [%s:UL-%s]", + self.security_indication.integrity_protection_indication ? + self.security_indication.integrity_protection_indication : + "No integrity_protection_indication", + self.security_indication. + maximum_integrity_protected_data_rate_uplink ? + self.security_indication. + maximum_integrity_protected_data_rate_uplink : + "No integrity_protection_indication"); + return OGS_ERROR; + } + } + + if (self.security_indication.maximum_integrity_protected_data_rate_downlink) { + if (smf_maximum_integrity_protected_data_rate_downlink_value2enum( + self.security_indication. + maximum_integrity_protected_data_rate_downlink) < 0) { + ogs_error("Invalid " + "maximum_integrity_protected_data_rate_downlink [%s]", + self.security_indication. + maximum_integrity_protected_data_rate_downlink); + return OGS_ERROR; + } + if (!self.security_indication. + maximum_integrity_protected_data_rate_uplink) { + ogs_error("No maximum_integrity_protected_data_rate_uplink"); + return OGS_ERROR; + } + } + return OGS_OK; } @@ -825,6 +902,40 @@ int smf_context_parse_config(void) } while (ogs_yaml_iter_type(&info_array) == YAML_SEQUENCE_NODE); + } else if (!strcmp(smf_key, "security_indication")) { + ogs_yaml_iter_t security_indication_iter; + ogs_yaml_iter_recurse( + &smf_iter, &security_indication_iter); + while (ogs_yaml_iter_next(&security_indication_iter)) { + const char *security_indication_key = + ogs_yaml_iter_key(&security_indication_iter); + ogs_assert(security_indication_key); + if (!strcmp(security_indication_key, + "integrity_protection_indication")) { + self.security_indication. + integrity_protection_indication = + ogs_yaml_iter_value( + &security_indication_iter); + } else if (!strcmp(security_indication_key, + "confidentiality_protection_indication")) { + self.security_indication. + confidentiality_protection_indication = + ogs_yaml_iter_value( + &security_indication_iter); + } else if (!strcmp(security_indication_key, + "maximum_integrity_protected_data_rate_uplink")) { + self.security_indication. + maximum_integrity_protected_data_rate_uplink = + ogs_yaml_iter_value( + &security_indication_iter); + } else if (!strcmp(security_indication_key, + "maximum_integrity_protected_data_rate_downlink")) { + self.security_indication. + maximum_integrity_protected_data_rate_downlink = + ogs_yaml_iter_value( + &security_indication_iter); + } + } } else if (!strcmp(smf_key, "pfcp")) { /* handle config in pfcp library */ } else if (!strcmp(smf_key, "subnet")) { @@ -2981,3 +3092,42 @@ static void stats_remove_smf_session(void) num_of_smf_sess = num_of_smf_sess - 1; ogs_info("[Removed] Number of SMF-Sessions is now %d", num_of_smf_sess); } + +int smf_integrity_protection_indication_value2enum(const char *value) +{ + ogs_assert(value); + if (!strcmp(value, "required")) + return NGAP_IntegrityProtectionIndication_required; + else if (!strcmp(value, "preferred")) + return NGAP_IntegrityProtectionIndication_preferred; + else if (!strcmp(value, "not-needed")) + return NGAP_IntegrityProtectionIndication_not_needed; + else { + ogs_error("Invalid value[%s]", value); + return -1; + } +} +int smf_confidentiality_protection_indication_value2enum(const char *value) +{ + ogs_assert(value); + return smf_integrity_protection_indication_value2enum(value); +} +int smf_maximum_integrity_protected_data_rate_uplink_value2enum( + const char *value) +{ + ogs_assert(value); + if (!strcmp(value, "bitrate64kbs")) + return NGAP_MaximumIntegrityProtectedDataRate_bitrate64kbs; + else if (!strcmp(value, "maximum-UE-rate")) + return NGAP_MaximumIntegrityProtectedDataRate_maximum_UE_rate; + else { + ogs_error("Invalid value[%s]", value); + return -1; + } +} +int smf_maximum_integrity_protected_data_rate_downlink_value2enum( + const char *value) +{ + ogs_assert(value); + return smf_maximum_integrity_protected_data_rate_uplink_value2enum(value); +} diff --git a/src/smf/context.h b/src/smf/context.h index d6a7f3a7b..37d52c9b8 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -92,6 +92,13 @@ typedef struct smf_context_s { uint16_t mtu; /* MTU to advertise in PCO */ + struct { + const char *integrity_protection_indication; + const char *confidentiality_protection_indication; + const char *maximum_integrity_protected_data_rate_uplink; + const char *maximum_integrity_protected_data_rate_downlink; + } security_indication; + #define SMF_UE_IS_LAST_SESSION(__sMF) \ ((__sMF) && (ogs_list_count(&(__sMF)->sess_list)) == 1) ogs_list_t smf_ue_list; @@ -512,6 +519,13 @@ void smf_pf_identifier_pool_final(smf_bearer_t *bearer); void smf_pf_precedence_pool_init(smf_sess_t *sess); void smf_pf_precedence_pool_final(smf_sess_t *sess); +int smf_integrity_protection_indication_value2enum(const char *value); +int smf_confidentiality_protection_indication_value2enum(const char *value); +int smf_maximum_integrity_protected_data_rate_uplink_value2enum( + const char *value); +int smf_maximum_integrity_protected_data_rate_downlink_value2enum( + const char *value); + #ifdef __cplusplus } #endif diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index 69843c6f9..9554be276 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -33,6 +33,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( NGAP_GTPTunnel_t *gTPTunnel = NULL; NGAP_DataForwardingNotPossible_t *DataForwardingNotPossible = NULL; NGAP_PDUSessionType_t *PDUSessionType = NULL; + NGAP_SecurityIndication_t *SecurityIndication = NULL; NGAP_QosFlowSetupRequestList_t *QosFlowSetupRequestList = NULL; NGAP_QosFlowSetupRequestItem_t *QosFlowSetupRequestItem = NULL; NGAP_QosFlowIdentifier_t *qosFlowIdentifier = NULL; @@ -129,6 +130,89 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( ogs_assert_if_reached(); } + if (smf_self()->security_indication.integrity_protection_indication && + smf_self()->security_indication.confidentiality_protection_indication) { + + ie = CALLOC(1, + sizeof(NGAP_PDUSessionResourceSetupRequestTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&message.protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_SecurityIndication; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_PDUSessionResourceSetupRequestTransferIEs__value_PR_SecurityIndication; + + SecurityIndication = &ie->value.choice.SecurityIndication; + + SecurityIndication->integrityProtectionIndication = + smf_integrity_protection_indication_value2enum( + smf_self()->security_indication. + integrity_protection_indication); + ogs_assert(SecurityIndication->integrityProtectionIndication >= 0); + + SecurityIndication->confidentialityProtectionIndication = + smf_confidentiality_protection_indication_value2enum( + smf_self()->security_indication. + confidentiality_protection_indication); + ogs_assert(SecurityIndication-> + confidentialityProtectionIndication >= 0); + + if (smf_self()->security_indication. + maximum_integrity_protected_data_rate_uplink) { + + ogs_assert( + SecurityIndication->integrityProtectionIndication == + NGAP_IntegrityProtectionIndication_required || + SecurityIndication->integrityProtectionIndication == + NGAP_IntegrityProtectionIndication_preferred); + + SecurityIndication->maximumIntegrityProtectedDataRate_UL = + CALLOC(1, sizeof(NGAP_MaximumIntegrityProtectedDataRate_t)); + ogs_assert(SecurityIndication-> + maximumIntegrityProtectedDataRate_UL); + *(SecurityIndication->maximumIntegrityProtectedDataRate_UL) = + smf_maximum_integrity_protected_data_rate_uplink_value2enum( + smf_self()->security_indication. + maximum_integrity_protected_data_rate_uplink); + ogs_assert( + *(SecurityIndication-> + maximumIntegrityProtectedDataRate_UL) >= 0); + + if (smf_self()->security_indication. + maximum_integrity_protected_data_rate_downlink) { + NGAP_ProtocolExtensionContainer_9625P229_t *extContainer = NULL; + NGAP_SecurityIndication_ExtIEs_t *extIe = NULL; + NGAP_MaximumIntegrityProtectedDataRate_t + *MaximumIntegrityProtectedDataRate = NULL; + + extContainer = CALLOC(1, + sizeof(NGAP_ProtocolExtensionContainer_9625P229_t)); + ogs_assert(extContainer); + SecurityIndication->iE_Extensions = + (struct NGAP_ProtocolExtensionContainer *)extContainer; + + extIe = CALLOC(1, sizeof(NGAP_SecurityIndication_ExtIEs_t)); + ogs_assert(extIe); + ASN_SEQUENCE_ADD(&extContainer->list, extIe); + + extIe->id = + NGAP_ProtocolIE_ID_id_MaximumIntegrityProtectedDataRate_DL; + extIe->criticality = NGAP_Criticality_ignore; + extIe->extensionValue.present = NGAP_SecurityIndication_ExtIEs__extensionValue_PR_MaximumIntegrityProtectedDataRate; + + MaximumIntegrityProtectedDataRate = + &extIe->extensionValue.choice. + MaximumIntegrityProtectedDataRate; + + *MaximumIntegrityProtectedDataRate = + smf_maximum_integrity_protected_data_rate_downlink_value2enum( + smf_self()->security_indication. + maximum_integrity_protected_data_rate_downlink); + ogs_assert(*MaximumIntegrityProtectedDataRate >= 0); + } + } + } + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestTransferIEs_t)); ogs_assert(ie); ASN_SEQUENCE_ADD(&message.protocolIEs, ie);