Refactor NAS 5GS Registration Request generation (3GPP TS 24.501)
* send integrity protected Initial NAS Message when UE in 5GMM-IDLE mode has valid current 5G NAS security context: > According to 4.4.2.5 TS 24.501: > when a UE in 5GMM-IDLE mode establishes a new NAS signalling connection and has a valid current 5G NAS > security context, the UE shall transmit the initial NAS message integrity protected with the current 5G NAS security > context and further protect this message as specified in subclause 4.4.6. * set NAS key set identifier IE to "no key is available (UE to network)" * previously set to 1 which has no impact * set now to 111 in order to trigger new authentication * See 9.11.3.32 of 3GPP TS 24.501 * Do 5GS Registration Type "mobility registration updating" when 5GMM state is De-registered
This commit is contained in:
+122
-44
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user