Commit 31196a88 authored by aligungr's avatar aligungr

Mobile storage refactor

parent 4097d4e6
...@@ -109,9 +109,9 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) ...@@ -109,9 +109,9 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg)
{"cm-state", ToJson(m_base->nasTask->mm->m_cmState)}, {"cm-state", ToJson(m_base->nasTask->mm->m_cmState)},
{"rm-state", ToJson(m_base->nasTask->mm->m_rmState)}, {"rm-state", ToJson(m_base->nasTask->mm->m_rmState)},
{"mm-state", ToJson(m_base->nasTask->mm->m_mmSubState)}, {"mm-state", ToJson(m_base->nasTask->mm->m_mmSubState)},
{"sim-inserted", m_base->nasTask->mm->m_validSim}, {"sim-inserted", m_base->nasTask->mm->m_storage.isSimValid()},
{"stored-suci", ToJson(m_base->nasTask->mm->m_storedSuci)}, {"stored-suci", ToJson(m_base->nasTask->mm->m_storage.m_storedSuci)},
{"stored-guti", ToJson(m_base->nasTask->mm->m_storedGuti)}, {"stored-guti", ToJson(m_base->nasTask->mm->m_storage.m_storedGuti)},
{"pdu-sessions", Json::Arr(std::move(pduSessions))}, {"pdu-sessions", Json::Arr(std::move(pduSessions))},
}); });
sendResult(msg.address, json.dumpYaml()); sendResult(msg.address, json.dumpYaml());
...@@ -127,8 +127,8 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg) ...@@ -127,8 +127,8 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg)
} }
case app::UeCliCommand::DE_REGISTER: { case app::UeCliCommand::DE_REGISTER: {
m_base->nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF m_base->nasTask->mm->sendDeregistration(msg.cmd->isSwitchOff ? nas::ESwitchOff::SWITCH_OFF
: nas::ESwitchOff::NORMAL_DE_REGISTRATION, : nas::ESwitchOff::NORMAL_DE_REGISTRATION,
msg.cmd->dueToDisable5g); msg.cmd->dueToDisable5g);
if (!msg.cmd->isSwitchOff) if (!msg.cmd->isSwitchOff)
sendResult(msg.address, "De-registration procedure triggered"); sendResult(msg.address, "De-registration procedure triggered");
else else
......
...@@ -17,7 +17,7 @@ namespace nr::ue ...@@ -17,7 +17,7 @@ namespace nr::ue
void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg) void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg)
{ {
if (!m_validSim) if (!m_storage.isSimValid())
{ {
m_logger->warn("Authentication request is ignored. USIM is invalid"); m_logger->warn("Authentication request is ignored. USIM is invalid");
return; return;
...@@ -67,17 +67,17 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms ...@@ -67,17 +67,17 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
if (USE_SQN_HACK) if (USE_SQN_HACK)
{ {
auto ak = calculateMilenage(OctetString::FromSpare(6), receivedRand).ak; auto ak = calculateMilenage(OctetString::FromSpare(6), receivedRand).ak;
m_sqn = OctetString::Xor(receivedAutn.subCopy(0, 6), ak); m_storage.m_sqn = OctetString::Xor(receivedAutn.subCopy(0, 6), ak);
} }
auto milenage = calculateMilenage(m_sqn, receivedRand); auto milenage = calculateMilenage(m_storage.m_sqn, receivedRand);
auto &res = milenage.res; auto &res = milenage.res;
auto &ck = milenage.ck; auto &ck = milenage.ck;
auto &ik = milenage.ik; auto &ik = milenage.ik;
auto &milenageAk = milenage.ak; auto &milenageAk = milenage.ak;
auto &milenageMac = milenage.mac_a; auto &milenageMac = milenage.mac_a;
auto sqnXorAk = OctetString::Xor(m_sqn, milenageAk); auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk);
auto ckPrimeIkPrime = auto ckPrimeIkPrime =
keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_base->config->plmn), sqnXorAk); keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_base->config->plmn), sqnXorAk);
auto &ckPrime = ckPrimeIkPrime.first; auto &ckPrime = ckPrimeIkPrime.first;
...@@ -92,7 +92,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms ...@@ -92,7 +92,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
auto mk = keys::CalculateMk(ckPrime, ikPrime, m_base->config->supi.value()); auto mk = keys::CalculateMk(ckPrime, ikPrime, m_base->config->supi.value());
auto kaut = mk.subCopy(16, 32); auto kaut = mk.subCopy(16, 32);
m_logger->debug("ueData.sqn: %s", m_sqn.toHexString().c_str()); m_logger->debug("ueData.sqn: %s", m_storage.m_sqn.toHexString().c_str());
m_logger->debug("ueData.op(C): %s", m_base->config->opC.toHexString().c_str()); m_logger->debug("ueData.op(C): %s", m_base->config->opC.toHexString().c_str());
m_logger->debug("ueData.K: %s", m_base->config->key.toHexString().c_str()); m_logger->debug("ueData.K: %s", m_base->config->key.toHexString().c_str());
m_logger->debug("calculated res: %s", res.toHexString().c_str()); m_logger->debug("calculated res: %s", res.toHexString().c_str());
...@@ -188,25 +188,25 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms ...@@ -188,25 +188,25 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
auto kAusf = keys::CalculateKAusfForEapAkaPrime(mk); auto kAusf = keys::CalculateKAusfForEapAkaPrime(mk);
m_logger->debug("kAusf: %s", kAusf.toHexString().c_str()); m_logger->debug("kAusf: %s", kAusf.toHexString().c_str());
m_nonCurrentNsCtx = NasSecurityContext{}; m_storage.m_nonCurrentNsCtx = NasSecurityContext{};
m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_nonCurrentNsCtx->keys.rand = std::move(receivedRand); m_storage.m_nonCurrentNsCtx->keys.rand = std::move(receivedRand);
m_nonCurrentNsCtx->keys.res = std::move(res); m_storage.m_nonCurrentNsCtx->keys.res = std::move(res);
m_nonCurrentNsCtx->keys.resStar = {}; m_storage.m_nonCurrentNsCtx->keys.resStar = {};
m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf); m_storage.m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf);
m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy();
keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx); keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx);
m_logger->debug("kSeaf: %s", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str()); m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str());
m_logger->debug("kAmf: %s", m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
// Send Response // Send Response
{ {
auto *akaPrimeResponse = auto *akaPrimeResponse =
new eap::EapAkaPrime(eap::ECode::RESPONSE, receivedEap.id, eap::ESubType::AKA_CHALLENGE); new eap::EapAkaPrime(eap::ECode::RESPONSE, receivedEap.id, eap::ESubType::AKA_CHALLENGE);
akaPrimeResponse->attributes.putRes(m_nonCurrentNsCtx->keys.res); akaPrimeResponse->attributes.putRes(m_storage.m_nonCurrentNsCtx->keys.res);
akaPrimeResponse->attributes.putMac(OctetString::FromSpare(16)); // Dummy mac for now akaPrimeResponse->attributes.putMac(OctetString::FromSpare(16)); // Dummy mac for now
akaPrimeResponse->attributes.putKdf(1); akaPrimeResponse->attributes.putKdf(1);
...@@ -254,48 +254,49 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & ...@@ -254,48 +254,49 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &
if (USE_SQN_HACK) if (USE_SQN_HACK)
{ {
auto ak = calculateMilenage(OctetString::FromSpare(6), rand).ak; auto ak = calculateMilenage(OctetString::FromSpare(6), rand).ak;
m_sqn = OctetString::Xor(autn.subCopy(0, 6), ak); m_storage.m_sqn = OctetString::Xor(autn.subCopy(0, 6), ak);
} }
auto milenage = calculateMilenage(m_sqn, rand); auto milenage = calculateMilenage(m_storage.m_sqn, rand);
auto &res = milenage.res; auto &res = milenage.res;
auto &ck = milenage.ck; auto &ck = milenage.ck;
auto &ik = milenage.ik; auto &ik = milenage.ik;
auto ckIk = OctetString::Concat(ck, ik); auto ckIk = OctetString::Concat(ck, ik);
auto &milenageAk = milenage.ak; auto &milenageAk = milenage.ak;
auto &milenageMac = milenage.mac_a; auto &milenageMac = milenage.mac_a;
auto sqnXorAk = OctetString::Xor(m_sqn, milenageAk); auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk);
auto snn = keys::ConstructServingNetworkName(m_base->config->plmn); auto snn = keys::ConstructServingNetworkName(m_base->config->plmn);
m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(), m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(),
ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(), ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(),
milenageMac.toHexString().c_str()); milenageMac.toHexString().c_str());
m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_sqn.toHexString().c_str()); m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_storage.m_sqn.toHexString().c_str());
auto autnCheck = validateAutn(milenageAk, milenageMac, autn); auto autnCheck = validateAutn(milenageAk, milenageMac, autn);
if (IGNORE_CONTROLS_FAILURES || autnCheck == EAutnValidationRes::OK) if (IGNORE_CONTROLS_FAILURES || autnCheck == EAutnValidationRes::OK)
{ {
// Create new partial native NAS security context and continue with key derivation // Create new partial native NAS security context and continue with key derivation
m_nonCurrentNsCtx = NasSecurityContext{}; m_storage.m_nonCurrentNsCtx = NasSecurityContext{};
m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc; m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi; m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_nonCurrentNsCtx->keys.rand = rand.copy(); m_storage.m_nonCurrentNsCtx->keys.rand = rand.copy();
m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res); m_storage.m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res);
m_nonCurrentNsCtx->keys.res = std::move(res); m_storage.m_nonCurrentNsCtx->keys.res = std::move(res);
m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk); m_storage.m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk);
m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy(); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy();
keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx); keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx);
m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(), m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]",
m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(), m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(),
m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str()); m_storage.m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(),
m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
// Send response // Send response
nas::AuthenticationResponse resp; nas::AuthenticationResponse resp;
resp.authenticationResponseParameter = nas::IEAuthenticationResponseParameter{}; resp.authenticationResponseParameter = nas::IEAuthenticationResponseParameter{};
resp.authenticationResponseParameter->rawData = m_nonCurrentNsCtx->keys.resStar.copy(); resp.authenticationResponseParameter->rawData = m_storage.m_nonCurrentNsCtx->keys.resStar.copy();
sendNasMessage(resp); sendNasMessage(resp);
} }
else if (autnCheck == EAutnValidationRes::MAC_FAILURE) else if (autnCheck == EAutnValidationRes::MAC_FAILURE)
...@@ -317,7 +318,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest & ...@@ -317,7 +318,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &
void NasMm::receiveAuthenticationResult(const nas::AuthenticationResult &msg) void NasMm::receiveAuthenticationResult(const nas::AuthenticationResult &msg)
{ {
if (msg.abba.has_value()) if (msg.abba.has_value())
m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy();
if (msg.eapMessage.eap->code == eap::ECode::SUCCESS) if (msg.eapMessage.eap->code == eap::ECode::SUCCESS)
receiveEapSuccessMessage(*msg.eapMessage.eap); receiveEapSuccessMessage(*msg.eapMessage.eap);
...@@ -350,9 +351,9 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg) ...@@ -350,9 +351,9 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg)
// The UE shall set the update status to 5U3 ROAMING NOT ALLOWED, // The UE shall set the update status to 5U3 ROAMING NOT ALLOWED,
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
// Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI The USIM shall be considered invalid // Delete the stored 5G-GUTI, TAI list, last visited registered TAI and ngKSI. The USIM shall be considered invalid
// until switching off the UE or the UICC containing the USIM is removed // until switching off the UE or the UICC containing the USIM is removed
invalidateSim(); m_storage.invalidateSim();
// The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if // The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if
// they were running) .. // they were running) ..
m_timers->t3510.stop(); m_timers->t3510.stop();
...@@ -372,7 +373,7 @@ void NasMm::receiveEapSuccessMessage(const eap::Eap &eap) ...@@ -372,7 +373,7 @@ void NasMm::receiveEapSuccessMessage(const eap::Eap &eap)
void NasMm::receiveEapFailureMessage(const eap::Eap &eap) void NasMm::receiveEapFailureMessage(const eap::Eap &eap)
{ {
m_logger->err("EAP failure received. Deleting non-current NAS security context"); m_logger->err("EAP failure received. Deleting non-current NAS security context");
m_nonCurrentNsCtx = {}; m_storage.m_nonCurrentNsCtx = {};
} }
void NasMm::receiveEapResponseMessage(const eap::Eap &eap) void NasMm::receiveEapResponseMessage(const eap::Eap &eap)
......
...@@ -25,9 +25,9 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers}, ...@@ -25,9 +25,9 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers},
m_cmState = ECmState::CM_IDLE; m_cmState = ECmState::CM_IDLE;
m_mmState = EMmState::MM_DEREGISTERED; m_mmState = EMmState::MM_DEREGISTERED;
m_mmSubState = EMmSubState::MM_DEREGISTERED_NA; m_mmSubState = EMmSubState::MM_DEREGISTERED_NA;
m_uState = E5UState::U1_UPDATED; m_storage.m_uState = E5UState::U1_UPDATED;
m_autoBehaviour = base->config->autoBehaviour; m_autoBehaviour = base->config->autoBehaviour;
m_validSim = base->config->supi.has_value(); m_storage.initialize(base->config->supi.has_value());
} }
void NasMm::onStart(NasSm *sm) void NasMm::onStart(NasSm *sm)
...@@ -52,7 +52,7 @@ void NasMm::performMmCycle() ...@@ -52,7 +52,7 @@ void NasMm::performMmCycle()
if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NA) if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NA)
{ {
if (m_validSim) if (m_storage.isSimValid())
{ {
if (m_cmState == ECmState::CM_IDLE) if (m_cmState == ECmState::CM_IDLE)
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH);
...@@ -168,15 +168,15 @@ void NasMm::switchCmState(ECmState state) ...@@ -168,15 +168,15 @@ void NasMm::switchCmState(ECmState state)
void NasMm::switchUState(E5UState state) void NasMm::switchUState(E5UState state)
{ {
E5UState oldState = m_uState; E5UState oldState = m_storage.m_uState;
m_uState = state; m_storage.m_uState = state;
onSwitchUState(oldState, m_uState); onSwitchUState(oldState, m_storage.m_uState);
if (m_base->nodeListener) if (m_base->nodeListener)
{ {
m_base->nodeListener->onSwitch(app::NodeType::UE, m_base->config->getNodeName(), app::StateType::U5, m_base->nodeListener->onSwitch(app::NodeType::UE, m_base->config->getNodeName(), app::StateType::U5,
ToJson(oldState).str(), ToJson(m_uState).str()); ToJson(oldState).str(), ToJson(m_storage.m_uState).str());
} }
if (state != oldState) if (state != oldState)
...@@ -192,12 +192,12 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol ...@@ -192,12 +192,12 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol
// 5GMM-DEREGISTERED for any other state except 5GMM-NULL. // 5GMM-DEREGISTERED for any other state except 5GMM-NULL.
if (oldState == EMmState::MM_DEREGISTERED && newState != EMmState::MM_DEREGISTERED && newState != EMmState::MM_NULL) if (oldState == EMmState::MM_DEREGISTERED && newState != EMmState::MM_DEREGISTERED && newState != EMmState::MM_NULL)
{ {
if (m_currentNsCtx.has_value() || m_nonCurrentNsCtx.has_value()) if (m_storage.m_currentNsCtx.has_value() || m_storage.m_nonCurrentNsCtx.has_value())
{ {
m_logger->debug("Deleting NAS security context"); m_logger->debug("Deleting NAS security context");
m_currentNsCtx = {}; m_storage.m_currentNsCtx = {};
m_nonCurrentNsCtx = {}; m_storage.m_nonCurrentNsCtx = {};
} }
} }
} }
...@@ -283,20 +283,4 @@ void NasMm::onTimerExpire(nas::NasTimer &timer) ...@@ -283,20 +283,4 @@ void NasMm::onTimerExpire(nas::NasTimer &timer)
} }
} }
void NasMm::invalidateAcquiredParams()
{
m_storedGuti = {};
m_lastVisitedRegisteredTai = {};
m_taiList = {};
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
}
void NasMm::invalidateSim()
{
m_logger->warn("USIM is removed or invalidated");
m_validSim = false;
invalidateAcquiredParams();
}
} // namespace nr::ue } // namespace nr::ue
...@@ -17,13 +17,13 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms ...@@ -17,13 +17,13 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms
if (msg.guti.has_value() && msg.guti->type == nas::EIdentityType::GUTI) if (msg.guti.has_value() && msg.guti->type == nas::EIdentityType::GUTI)
{ {
m_storedGuti = msg.guti.value(); m_storage.m_storedSuci = {};
m_storedSuci = {}; m_storage.m_storedGuti = *msg.guti;
m_timers->t3519.stop(); m_timers->t3519.stop();
} }
if (msg.taiList.has_value()) if (msg.taiList.has_value())
m_taiList = msg.taiList.value(); m_storage.m_taiList = msg.taiList.value();
if (msg.configurationUpdateIndication.has_value()) if (msg.configurationUpdateIndication.has_value())
{ {
......
...@@ -30,10 +30,10 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g) ...@@ -30,10 +30,10 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g)
request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED; request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED;
request->deRegistrationType.switchOff = switchOff; request->deRegistrationType.switchOff = switchOff;
if (m_currentNsCtx.has_value()) if (m_storage.m_currentNsCtx.has_value())
{ {
request->ngKSI.tsc = m_currentNsCtx->tsc; request->ngKSI.tsc = m_storage.m_currentNsCtx->tsc;
request->ngKSI.ksi = m_currentNsCtx->ngKsi; request->ngKSI.ksi = m_storage.m_currentNsCtx->ngKsi;
} }
else else
{ {
...@@ -76,7 +76,7 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina ...@@ -76,7 +76,7 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina
m_timers->t3521.stop(); m_timers->t3521.stop();
m_timers->t3519.stop(); m_timers->t3519.stop();
m_storedSuci = {}; m_storage.m_storedSuci = {};
switchRmState(ERmState::RM_DEREGISTERED); switchRmState(ERmState::RM_DEREGISTERED);
...@@ -162,7 +162,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi ...@@ -162,7 +162,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
case nas::EMmCause::ILLEGAL_ME: case nas::EMmCause::ILLEGAL_ME:
case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: { case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateSim(); m_storage.invalidateSim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
break; break;
} }
...@@ -175,13 +175,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi ...@@ -175,13 +175,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
//} //}
case nas::EMmCause::TA_NOT_ALLOWED: { case nas::EMmCause::TA_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateAcquiredParams(); m_storage.discardUsim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE);
break; break;
} }
case nas::EMmCause::N1_MODE_NOT_ALLOWED: { case nas::EMmCause::N1_MODE_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateAcquiredParams(); m_storage.discardUsim();
switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA);
break; break;
} }
...@@ -198,7 +198,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi ...@@ -198,7 +198,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
nas::utils::EnumToString(msg.mmCause->value)); nas::utils::EnumToString(msg.mmCause->value));
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED); switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateSim(); m_storage.invalidateSim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
break; break;
} }
......
...@@ -43,15 +43,15 @@ void NasMm::receiveIdentityRequest(const nas::IdentityRequest &msg) ...@@ -43,15 +43,15 @@ void NasMm::receiveIdentityRequest(const nas::IdentityRequest &msg)
nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci() nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci()
{ {
if (m_timers->t3519.isRunning()) if (m_timers->t3519.isRunning())
return m_storedSuci; return m_storage.m_storedSuci;
m_storedSuci = generateSuci(); m_storage.m_storedSuci = generateSuci();
m_timers->t3519.start(); m_timers->t3519.start();
if (m_storedSuci.type == nas::EIdentityType::NO_IDENTITY) if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY)
return {}; return {};
return m_storedSuci; return m_storage.m_storedSuci;
} }
nas::IE5gsMobileIdentity NasMm::generateSuci() nas::IE5gsMobileIdentity NasMm::generateSuci()
...@@ -93,8 +93,8 @@ nas::IE5gsMobileIdentity NasMm::generateSuci() ...@@ -93,8 +93,8 @@ nas::IE5gsMobileIdentity NasMm::generateSuci()
nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId() nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId()
{ {
if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY) if (m_storage.m_storedGuti.type != nas::EIdentityType::NO_IDENTITY)
return m_storedGuti; return m_storage.m_storedGuti;
else else
{ {
auto suci = getOrGenerateSuci(); auto suci = getOrGenerateSuci();
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <crypt/milenage.hpp> #include <crypt/milenage.hpp>
#include <nas/nas.hpp> #include <nas/nas.hpp>
#include <nas/timer.hpp> #include <nas/timer.hpp>
#include <ue/nas/storage.hpp>
#include <ue/nts.hpp> #include <ue/nts.hpp>
#include <ue/types.hpp> #include <ue/types.hpp>
#include <utils/nts.hpp> #include <utils/nts.hpp>
...@@ -28,31 +29,22 @@ class NasMm ...@@ -28,31 +29,22 @@ class NasMm
UeTimers *m_timers; UeTimers *m_timers;
std::unique_ptr<Logger> m_logger; std::unique_ptr<Logger> m_logger;
NasSm *m_sm; NasSm *m_sm;
MobileStorage m_storage{};
bool m_autoBehaviour;
ERmState m_rmState; ERmState m_rmState;
ECmState m_cmState; ECmState m_cmState;
EMmState m_mmState; EMmState m_mmState;
EMmSubState m_mmSubState; EMmSubState m_mmSubState;
E5UState m_uState;
nas::IE5gsMobileIdentity m_storedSuci{};
nas::IE5gsMobileIdentity m_storedGuti{};
// The very last registration request (or null)
std::unique_ptr<nas::RegistrationRequest> m_lastRegistrationRequest{}; std::unique_ptr<nas::RegistrationRequest> m_lastRegistrationRequest{};
// The very last de-registration request (or null)
std::unique_ptr<nas::DeRegistrationRequestUeOriginating> m_lastDeregistrationRequest{}; std::unique_ptr<nas::DeRegistrationRequestUeOriginating> m_lastDeregistrationRequest{};
// Indicates that the last de-registration request is issued due to disable 5G services
bool m_lastDeregDueToDisable5g{}; bool m_lastDeregDueToDisable5g{};
// Last time PLMN search is triggered
std::optional<nas::IE5gsTrackingAreaIdentity> m_lastVisitedRegisteredTai{};
std::optional<nas::IE5gsTrackingAreaIdentityList> m_taiList{};
std::optional<NasSecurityContext> m_currentNsCtx;
std::optional<NasSecurityContext> m_nonCurrentNsCtx;
bool m_autoBehaviour;
bool m_validSim;
long m_lastPlmnSearchTrigger{}; long m_lastPlmnSearchTrigger{};
OctetString m_sqn{};
friend class UeCmdHandler; friend class UeCmdHandler;
...@@ -91,8 +83,6 @@ class NasMm ...@@ -91,8 +83,6 @@ class NasMm
void onSwitchRmState(ERmState oldState, ERmState newState); void onSwitchRmState(ERmState oldState, ERmState newState);
void onSwitchCmState(ECmState oldState, ECmState newState); void onSwitchCmState(ECmState oldState, ECmState newState);
void onSwitchUState(E5UState oldState, E5UState newState); void onSwitchUState(E5UState oldState, E5UState newState);
void invalidateAcquiredParams();
void invalidateSim();
/* Transport */ /* Transport */
void sendMmStatus(nas::EMmCause cause); void sendMmStatus(nas::EMmCause cause);
......
...@@ -19,19 +19,16 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll ...@@ -19,19 +19,16 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll
// The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE // The UE shall mark the 5G NAS security context on the USIM or in the non-volatile memory as invalid when the UE
// initiates an initial registration procedure // initiates an initial registration procedure
if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION) if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION)
{ m_storage.discardCurrentSecurity();
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
}
switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA); switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA);
nas::IENasKeySetIdentifier ngKsi; nas::IENasKeySetIdentifier ngKsi;
if (m_currentNsCtx.has_value()) if (m_storage.m_currentNsCtx.has_value())
{ {
ngKsi.tsc = m_currentNsCtx->tsc; ngKsi.tsc = m_storage.m_currentNsCtx->tsc;
ngKsi.ksi = m_currentNsCtx->ngKsi; ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi;
} }
auto request = std::make_unique<nas::RegistrationRequest>(); auto request = std::make_unique<nas::RegistrationRequest>();
...@@ -52,8 +49,8 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll ...@@ -52,8 +49,8 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll
request->mobileIdentity = getOrGeneratePreferredId(); request->mobileIdentity = getOrGeneratePreferredId();
if (m_lastVisitedRegisteredTai.has_value()) if (m_storage.m_lastVisitedRegisteredTai.has_value())
request->lastVisitedRegisteredTai = m_lastVisitedRegisteredTai.value(); request->lastVisitedRegisteredTai = m_storage.m_lastVisitedRegisteredTai.value();
m_timers->t3510.start(); m_timers->t3510.start();
m_timers->t3502.stop(); m_timers->t3502.stop();
...@@ -73,7 +70,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) ...@@ -73,7 +70,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg)
bool sendCompleteMes = false; bool sendCompleteMes = false;
m_taiList = msg.taiList; m_storage.m_taiList = msg.taiList;
if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value())) if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value()))
{ {
...@@ -83,7 +80,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg) ...@@ -83,7 +80,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg)
if (msg.mobileIdentity.has_value() && msg.mobileIdentity->type == nas::EIdentityType::GUTI) if (msg.mobileIdentity.has_value() && msg.mobileIdentity->type == nas::EIdentityType::GUTI)
{ {
m_storedGuti = msg.mobileIdentity.value(); m_storage.m_storedGuti = msg.mobileIdentity.value();
m_timers->t3519.stop(); m_timers->t3519.stop();
sendCompleteMes = true; sendCompleteMes = true;
...@@ -122,6 +119,8 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) ...@@ -122,6 +119,8 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
} }
auto unhandledRejectCase = [cause, this]() { auto unhandledRejectCase = [cause, this]() {
m_storage.discardUsim();
m_logger->err("Registration rejected with unhandled MMCause: %s", nas::utils::EnumToString(cause)); m_logger->err("Registration rejected with unhandled MMCause: %s", nas::utils::EnumToString(cause));
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA); switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchRmState(ERmState::RM_DEREGISTERED); switchRmState(ERmState::RM_DEREGISTERED);
...@@ -134,11 +133,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) ...@@ -134,11 +133,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA || cause == nas::EMmCause::TA_NOT_ALLOWED || cause == nas::EMmCause::ROAMING_NOT_ALLOWED_IN_TA ||
cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA) cause == nas::EMmCause::NO_SUITIBLE_CELLS_IN_TA)
{ {
m_storedGuti = {}; m_storage.discardUsim();
m_lastVisitedRegisteredTai = {};
m_taiList = {};
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
// TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again. // TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again.
// due to RLS. // due to RLS.
...@@ -168,11 +163,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg) ...@@ -168,11 +163,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
} }
else if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED) else if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED)
{ {
m_storedGuti = {}; m_storage.discardUsim();
m_lastVisitedRegisteredTai = {};
m_taiList = {};
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA); switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA);
switchRmState(ERmState::RM_DEREGISTERED); switchRmState(ERmState::RM_DEREGISTERED);
......
...@@ -22,7 +22,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) ...@@ -22,7 +22,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
m_logger->err("Rejecting Security Mode Command with cause: %s", nas::utils::EnumToString(cause)); m_logger->err("Rejecting Security Mode Command with cause: %s", nas::utils::EnumToString(cause));
}; };
if (!m_nonCurrentNsCtx.has_value()) if (!m_storage.m_nonCurrentNsCtx.has_value())
{ {
reject(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); reject(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE);
return; return;
...@@ -58,7 +58,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) ...@@ -58,7 +58,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
// Assign ABBA (if any) // Assign ABBA (if any)
if (msg.abba.has_value()) if (msg.abba.has_value())
m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy(); m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba->rawData.copy();
// Check selected algorithms // Check selected algorithms
{ {
...@@ -68,17 +68,17 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg) ...@@ -68,17 +68,17 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
} }
// Assign selected algorithms to security context, and derive NAS keys // Assign selected algorithms to security context, and derive NAS keys
m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity; m_storage.m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity;
m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering; m_storage.m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering;
keys::DeriveNasKeys(*m_nonCurrentNsCtx); keys::DeriveNasKeys(*m_storage.m_nonCurrentNsCtx);
m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(), m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_storage.m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(),
m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str()); m_storage.m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str());
m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_nonCurrentNsCtx->integrity, m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_storage.m_nonCurrentNsCtx->integrity,
(int)m_nonCurrentNsCtx->ciphering); (int)m_storage.m_nonCurrentNsCtx->ciphering);
// Set non-current NAS Security Context as current one. // Set non-current NAS Security Context as current one.
m_currentNsCtx = m_nonCurrentNsCtx->deepCopy(); m_storage.m_currentNsCtx = m_storage.m_nonCurrentNsCtx->deepCopy();
// Prepare response // Prepare response
nas::SecurityModeComplete resp; nas::SecurityModeComplete resp;
......
...@@ -21,10 +21,11 @@ void NasMm::sendNasMessage(const nas::PlainMmMessage &msg) ...@@ -21,10 +21,11 @@ void NasMm::sendNasMessage(const nas::PlainMmMessage &msg)
// TODO trigger on send // TODO trigger on send
OctetString pdu{}; OctetString pdu{};
if (m_currentNsCtx.has_value() && (m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 || if (m_storage.m_currentNsCtx.has_value() &&
m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0)) (m_storage.m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 ||
m_storage.m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0))
{ {
auto secured = nas_enc::Encrypt(*m_currentNsCtx, msg); auto secured = nas_enc::Encrypt(*m_storage.m_currentNsCtx, msg);
nas::EncodeNasMessage(*secured, pdu); nas::EncodeNasMessage(*secured, pdu);
} }
else else
...@@ -62,7 +63,7 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) ...@@ -62,7 +63,7 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg)
{ {
// If any NAS signalling message is received as not integrity protected even though the secure exchange of NAS // If any NAS signalling message is received as not integrity protected even though the secure exchange of NAS
// messages has been established by the network, then the NAS shall discard this message // messages has been established by the network, then the NAS shall discard this message
if (m_currentNsCtx.has_value()) if (m_storage.m_currentNsCtx.has_value())
{ {
m_logger->err( m_logger->err(
"Not integrity protected NAS message received after security establishment. Ignoring received " "Not integrity protected NAS message received after security establishment. Ignoring received "
...@@ -100,14 +101,14 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg) ...@@ -100,14 +101,14 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg)
return; return;
} }
if (!m_currentNsCtx.has_value()) if (!m_storage.m_currentNsCtx.has_value())
{ {
m_logger->warn("Secured NAS message received while no security context"); m_logger->warn("Secured NAS message received while no security context");
sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE); sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE);
return; return;
} }
auto decrypted = nas_enc::Decrypt(*m_currentNsCtx, securedMm); auto decrypted = nas_enc::Decrypt(*m_storage.m_currentNsCtx, securedMm);
if (decrypted == nullptr) if (decrypted == nullptr)
{ {
m_logger->err("MAC mismatch in NAS encryption. Ignoring received NAS Message."); m_logger->err("MAC mismatch in NAS encryption. Ignoring received NAS Message.");
......
//
// This file is a part of UERANSIM open source project.
// Copyright (c) 2021 ALİ GÜNGÖR.
//
// The software and all associated files are licensed under GPL-3.0
// and subject to the terms and conditions defined in LICENSE file.
//
#include "storage.hpp"
namespace nr::ue
{
} // namespace nr::ue
//
// This file is a part of UERANSIM open source project.
// Copyright (c) 2021 ALİ GÜNGÖR.
//
// The software and all associated files are licensed under GPL-3.0
// and subject to the terms and conditions defined in LICENSE file.
//
#include <nas/nas.hpp>
#include <ue/types.hpp>
#pragma once
namespace nr::ue
{
class MobileStorage
{
private:
bool m_simIsValid{};
public:
// Location related
nas::IE5gsMobileIdentity m_storedGuti{};
std::optional<nas::IE5gsTrackingAreaIdentity> m_lastVisitedRegisteredTai{};
E5UState m_uState{};
// Identity related
nas::IE5gsMobileIdentity m_storedSuci{};
// Plmn related
std::optional<nas::IE5gsTrackingAreaIdentityList> m_taiList{};
// Security related
std::optional<NasSecurityContext> m_currentNsCtx{};
std::optional<NasSecurityContext> m_nonCurrentNsCtx{};
OctetString m_sqn{};
public:
void initialize(bool hasSupi)
{
m_simIsValid = hasSupi;
}
void discardLocation()
{
m_storedGuti = {};
m_lastVisitedRegisteredTai = {};
}
void discardPlmn()
{
m_taiList = {};
}
void discardSecurity()
{
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
}
void discardCurrentSecurity()
{
m_currentNsCtx = {};
// normally NON-current nsCtx is not stored in USIM
}
void discardUsim()
{
discardLocation();
discardPlmn();
discardSecurity();
}
void invalidateSim()
{
// TODO: log
discardUsim();
m_simIsValid = false;
}
[[nodiscard]] bool isSimValid() const
{
return m_simIsValid;
}
};
} // namespace nr::ue
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment