diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 3e5210644c..ba334d4290 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -458,6 +458,20 @@ nr_ue_nas_t *get_ue_nas_info(module_id_t module_id) return &nr_ue_nas[module_id]; } +static FGSRegistrationType set_fgs_ksi(nr_ue_nas_t *nas) +{ + if (nas->fiveGMM_mode == FGS_IDLE) { + /** + * the UE is IDLE, therefore ngKSI was deleted, along all K_AMF, ciphering key, integrity key + * (i.e. the 5G NAS security context associated with the ngKSI is no longer valid) + * see 4.4.2 of 3GPP TS 24.501 + */ + return NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE; + } + return 0x0; +} + + static FGSRegistrationType set_fgs_registration_type(nr_ue_nas_t *nas) { if (nas->fiveGMM_state == FGS_REGISTERED && nas->fiveGMM_mode == FGS_IDLE && nas->t3512) { @@ -485,59 +499,126 @@ static FGSRegistrationType set_fgs_registration_type(nr_ue_nas_t *nas) return INITIAL_REGISTRATION; } +/** + * @brief Generate 5GS Registration Request (8.2.6 of 3GPP TS 24.501) + */ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) { + LOG_I(NAS, "Generate Initial NAS Message: Registration Request\n"); int size = sizeof(fgmm_msg_header_t); - fgmm_nas_message_plain_t plain = {0}; + fgmm_nas_msg_security_protected_t sp = {0}; - // Plain 5GMM header - plain.header = set_mm_header(FGS_REGISTRATION_REQUEST, PLAIN_5GS_MSG); - size += sizeof(plain.header); - - // Plain 5GMM msg - registration_request_msg *mm_msg = &plain.mm_msg.registration_request; - if (nas->fiveGMM_state == FGS_DEREGISTERED) { - mm_msg->fgsregistrationtype = INITIAL_REGISTRATION; - } else { - mm_msg->fgsregistrationtype = MOBILITY_REGISTRATION_UPDATING; + /** Check whether the UE has a valid current 5G NAS security context + and set security protected 5GS NAS message header (see 9.1.1 of 3GPP TS 24.501) */ + bool has_security_context = nas->security_container && nas->security_container->integrity_context; + if (has_security_context) { + sp.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; + sp.header.security_header_type = INTEGRITY_PROTECTED; + sp.header.sequence_number = nas->security.nas_count_ul & 0xff; + size += 7; } - mm_msg->naskeysetidentifier.naskeysetidentifier = 1; + + // Plain 5GMM message + sp.plain.header = set_mm_header(FGS_REGISTRATION_REQUEST, PLAIN_5GS_MSG); + size += sizeof(sp.plain.header); + registration_request_msg *rr = &sp.plain.mm_msg.registration_request; + + // 5GMM Registration Type + rr->fgsregistrationtype = set_fgs_registration_type(nas); size += 1; - if (nas->guti) { - size += fill_guti(&mm_msg->fgsmobileidentity, nas->guti); + if (rr->fgsregistrationtype == REG_TYPE_RESERVED) { + // currently only REG_TYPE_RESERVED is supported + LOG_E(NAS, "Initial NAS Message: Registration Request failed\n"); + return; + } + // NAS Key Set Identifier + rr->naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE; + rr->naskeysetidentifier.naskeysetidentifier = set_fgs_ksi(nas); + size += 1; + + // 5GMM Mobile Identity + if(nas->guti){ + size += fill_guti(&rr->fgsmobileidentity, nas->guti); + LOG_D(NAS, + "5G-GUTI in registration request: MCC: %u%u%u, MNC: %u%u, AMF Region ID: %u, AMF Set ID: %u, AMF Pointer: %u, 5G-TMSI: " + "%u\n", + nas->guti->mccdigit1, + nas->guti->mccdigit2, + nas->guti->mccdigit3, + nas->guti->mncdigit1, + nas->guti->mncdigit2, + nas->guti->amfregionid, + nas->guti->amfsetid, + nas->guti->amfpointer, + nas->guti->tmsi); } else { - size += fill_suci(&mm_msg->fgsmobileidentity, nas->uicc); + size += fill_suci(&rr->fgsmobileidentity, nas->uicc); + Suci5GSMobileIdentity_t *suci = &rr->fgsmobileidentity.suci; + LOG_D(NAS, + "SUCI in registration request: SUPI type: %d Type of Identity: %u MCC: %u%u%u, MNC: %u%u%u, \ + Routing Indicator %d%d%d%d Protection Scheme ID: %u, Home Network PKI: %u, Scheme Output: %s\n", + suci->supiformat, + suci->typeofidentity, + suci->mccdigit1, + suci->mccdigit2, + suci->mccdigit3, + suci->mncdigit1, + suci->mncdigit2, + nas->uicc->nmc_size == 2 ? 0 : suci->mncdigit3, + suci->routingindicatordigit1, + suci->routingindicatordigit2, + suci->routingindicatordigit3, + suci->routingindicatordigit4, + suci->protectionschemeId, + suci->homenetworkpki, + suci->schemeoutput); } -#if 0 - /* This cannot be sent in clear, the core network Open5GS rejects the UE. - * TODO: do we have to send this at some point? - * For the time being, let's keep it here for later proper fix. - */ - mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_5GMM_CAPABILITY_PRESENT; - mm_msg->registration_request.fgmmcapability.iei = REGISTRATION_REQUEST_5GMM_CAPABILITY_IEI; - mm_msg->registration_request.fgmmcapability.length = 1; - mm_msg->registration_request.fgmmcapability.value = 0x7; - size += 3; -#endif - - mm_msg->presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT; - mm_msg->nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI; - mm_msg->nruesecuritycapability.length = 8; - mm_msg->nruesecuritycapability.fg_EA = 0xe0; - mm_msg->nruesecuritycapability.fg_IA = 0x60; - mm_msg->nruesecuritycapability.EEA = 0; - mm_msg->nruesecuritycapability.EIA = 0; + // Security Capability + rr->presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT; + rr->nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI; + rr->nruesecuritycapability.length = 8; + rr->nruesecuritycapability.fg_EA = 0xe0; + rr->nruesecuritycapability.fg_IA = 0x60; + rr->nruesecuritycapability.EEA = 0; + rr->nruesecuritycapability.EIA = 0; size += 10; - // encode the message initialNasMsg->nas_data = malloc16_clear(size * sizeof(*initialNasMsg->nas_data)); + if (has_security_context) { + // security protected encoding + int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size); + initialNasMsg->length = + security_header_len + + mm_msg_encode(&sp.plain, initialNasMsg->nas_data + security_header_len, size - security_header_len); + /* integrity protection */ + nas_stream_cipher_t stream_cipher; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); + uint8_t mac[4]; + stream_cipher.context = nas->security_container->integrity_context; + stream_cipher.count = nas->security.nas_count_ul++; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + // Security protected header is cleartext except the SN field + uint8_t cleartext_len = sizeof(sp.header) - 1; + // Message to be integrity protected + stream_cipher.message = initialNasMsg->nas_data + cleartext_len; + // Length of integrity protected message in bits + stream_cipher.blength = (initialNasMsg->length - cleartext_len) << 3; + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); + uint8_t mac_len = sizeof(sp.header.message_authentication_code); + uint8_t mac_start_octet = 2; + LOG_D(NAS, "Integrity protected initial NAS message: mac = %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); + for (int i = 0; i < mac_len; i++) { + initialNasMsg->nas_data[mac_start_octet + i] = mac[i]; + } + } else { + // plain encoding + initialNasMsg->length = mm_msg_encode(&sp.plain, initialNasMsg->nas_data, size); + LOG_D(NAS, "Plain Initial NAS Message: Registration Request\n"); + } nas->registration_request_buf = initialNasMsg->nas_data; - - initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size); nas->registration_request_len = initialNasMsg->length; - /* set NAS 5GMM state */ - nas->fiveGMM_state = FGS_REGISTERED_INITIATED; } void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) @@ -563,6 +644,8 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) // 5G-S-TMSI size += fill_fgstmsi(&mm_msg->fiveg_s_tmsi, nas->guti); + /* message encoding */ + initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data)); if (security_protected) { fgmm_nas_msg_security_protected_t sp = {0}; @@ -575,9 +658,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) // Payload: plain message sp.plain = plain; - // Allocate NAS message for encoding - initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data)); - // security protected encoding int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size); initialNasMsg->length = @@ -611,8 +691,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas) initialNasMsg->nas_data[2 + i] = mac[i]; } else { // plain encoding - // Allocate NAS message for encoding - initialNasMsg->nas_data = malloc_or_fail(size * sizeof(*initialNasMsg->nas_data)); initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size); LOG_I(NAS, "PLAIN_5GS_MSG initial NAS message: Service Request with length %d \n", initialNasMsg->length); }