Commit 31196a88 authored by aligungr's avatar aligungr

Mobile storage refactor

parent 4097d4e6
......@@ -109,9 +109,9 @@ void UeCmdHandler::handleCmdImpl(NwUeCliCommand &msg)
{"cm-state", ToJson(m_base->nasTask->mm->m_cmState)},
{"rm-state", ToJson(m_base->nasTask->mm->m_rmState)},
{"mm-state", ToJson(m_base->nasTask->mm->m_mmSubState)},
{"sim-inserted", m_base->nasTask->mm->m_validSim},
{"stored-suci", ToJson(m_base->nasTask->mm->m_storedSuci)},
{"stored-guti", ToJson(m_base->nasTask->mm->m_storedGuti)},
{"sim-inserted", m_base->nasTask->mm->m_storage.isSimValid()},
{"stored-suci", ToJson(m_base->nasTask->mm->m_storage.m_storedSuci)},
{"stored-guti", ToJson(m_base->nasTask->mm->m_storage.m_storedGuti)},
{"pdu-sessions", Json::Arr(std::move(pduSessions))},
});
sendResult(msg.address, json.dumpYaml());
......
......@@ -17,7 +17,7 @@ namespace nr::ue
void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg)
{
if (!m_validSim)
if (!m_storage.isSimValid())
{
m_logger->warn("Authentication request is ignored. USIM is invalid");
return;
......@@ -67,17 +67,17 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
if (USE_SQN_HACK)
{
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 &ck = milenage.ck;
auto &ik = milenage.ik;
auto &milenageAk = milenage.ak;
auto &milenageMac = milenage.mac_a;
auto sqnXorAk = OctetString::Xor(m_sqn, milenageAk);
auto sqnXorAk = OctetString::Xor(m_storage.m_sqn, milenageAk);
auto ckPrimeIkPrime =
keys::CalculateCkPrimeIkPrime(ck, ik, keys::ConstructServingNetworkName(m_base->config->plmn), sqnXorAk);
auto &ckPrime = ckPrimeIkPrime.first;
......@@ -92,7 +92,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
auto mk = keys::CalculateMk(ckPrime, ikPrime, m_base->config->supi.value());
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.K: %s", m_base->config->key.toHexString().c_str());
m_logger->debug("calculated res: %s", res.toHexString().c_str());
......@@ -188,25 +188,25 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
auto kAusf = keys::CalculateKAusfForEapAkaPrime(mk);
m_logger->debug("kAusf: %s", kAusf.toHexString().c_str());
m_nonCurrentNsCtx = NasSecurityContext{};
m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_nonCurrentNsCtx->keys.rand = std::move(receivedRand);
m_nonCurrentNsCtx->keys.res = std::move(res);
m_nonCurrentNsCtx->keys.resStar = {};
m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf);
m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy();
m_storage.m_nonCurrentNsCtx = NasSecurityContext{};
m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_storage.m_nonCurrentNsCtx->keys.rand = std::move(receivedRand);
m_storage.m_nonCurrentNsCtx->keys.res = std::move(res);
m_storage.m_nonCurrentNsCtx->keys.resStar = {};
m_storage.m_nonCurrentNsCtx->keys.kAusf = std::move(kAusf);
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("kAmf: %s", m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
m_logger->debug("kSeaf: %s", m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str());
m_logger->debug("kAmf: %s", m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
// Send Response
{
auto *akaPrimeResponse =
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.putKdf(1);
......@@ -254,48 +254,49 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &
if (USE_SQN_HACK)
{
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 &ck = milenage.ck;
auto &ik = milenage.ik;
auto ckIk = OctetString::Concat(ck, ik);
auto &milenageAk = milenage.ak;
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);
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(),
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);
if (IGNORE_CONTROLS_FAILURES || autnCheck == EAutnValidationRes::OK)
{
// Create new partial native NAS security context and continue with key derivation
m_nonCurrentNsCtx = NasSecurityContext{};
m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_nonCurrentNsCtx->keys.rand = rand.copy();
m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res);
m_nonCurrentNsCtx->keys.res = std::move(res);
m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk);
m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy();
keys::DeriveKeysSeafAmf(*m_base->config, *m_nonCurrentNsCtx);
m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]", m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(),
m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(),
m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
m_storage.m_nonCurrentNsCtx = NasSecurityContext{};
m_storage.m_nonCurrentNsCtx->tsc = msg.ngKSI.tsc;
m_storage.m_nonCurrentNsCtx->ngKsi = msg.ngKSI.ksi;
m_storage.m_nonCurrentNsCtx->keys.rand = rand.copy();
m_storage.m_nonCurrentNsCtx->keys.resStar = keys::CalculateResStar(ckIk, snn, rand, res);
m_storage.m_nonCurrentNsCtx->keys.res = std::move(res);
m_storage.m_nonCurrentNsCtx->keys.kAusf = keys::CalculateKAusfFor5gAka(ck, ik, snn, sqnXorAk);
m_storage.m_nonCurrentNsCtx->keys.abba = msg.abba.rawData.copy();
keys::DeriveKeysSeafAmf(*m_base->config, *m_storage.m_nonCurrentNsCtx);
m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]",
m_storage.m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(),
m_storage.m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(),
m_storage.m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
// Send response
nas::AuthenticationResponse resp;
resp.authenticationResponseParameter = nas::IEAuthenticationResponseParameter{};
resp.authenticationResponseParameter->rawData = m_nonCurrentNsCtx->keys.resStar.copy();
resp.authenticationResponseParameter->rawData = m_storage.m_nonCurrentNsCtx->keys.resStar.copy();
sendNasMessage(resp);
}
else if (autnCheck == EAutnValidationRes::MAC_FAILURE)
......@@ -317,7 +318,7 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &
void NasMm::receiveAuthenticationResult(const nas::AuthenticationResult &msg)
{
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)
receiveEapSuccessMessage(*msg.eapMessage.eap);
......@@ -350,9 +351,9 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg)
// The UE shall set the update status to 5U3 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
invalidateSim();
m_storage.invalidateSim();
// The UE shall abort any 5GMM signalling procedure, stop any of the timers T3510, T3516, T3517, T3519 or T3521 (if
// they were running) ..
m_timers->t3510.stop();
......@@ -372,7 +373,7 @@ void NasMm::receiveEapSuccessMessage(const eap::Eap &eap)
void NasMm::receiveEapFailureMessage(const eap::Eap &eap)
{
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)
......
......@@ -25,9 +25,9 @@ NasMm::NasMm(TaskBase *base, UeTimers *timers) : m_base{base}, m_timers{timers},
m_cmState = ECmState::CM_IDLE;
m_mmState = EMmState::MM_DEREGISTERED;
m_mmSubState = EMmSubState::MM_DEREGISTERED_NA;
m_uState = E5UState::U1_UPDATED;
m_storage.m_uState = E5UState::U1_UPDATED;
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)
......@@ -52,7 +52,7 @@ void NasMm::performMmCycle()
if (m_mmSubState == EMmSubState::MM_DEREGISTERED_NA)
{
if (m_validSim)
if (m_storage.isSimValid())
{
if (m_cmState == ECmState::CM_IDLE)
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_PLMN_SEARCH);
......@@ -168,15 +168,15 @@ void NasMm::switchCmState(ECmState state)
void NasMm::switchUState(E5UState state)
{
E5UState oldState = m_uState;
m_uState = state;
E5UState oldState = m_storage.m_uState;
m_storage.m_uState = state;
onSwitchUState(oldState, m_uState);
onSwitchUState(oldState, m_storage.m_uState);
if (m_base->nodeListener)
{
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)
......@@ -192,12 +192,12 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol
// 5GMM-DEREGISTERED for any other state except 5GMM-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_currentNsCtx = {};
m_nonCurrentNsCtx = {};
m_storage.m_currentNsCtx = {};
m_storage.m_nonCurrentNsCtx = {};
}
}
}
......@@ -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
......@@ -17,13 +17,13 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms
if (msg.guti.has_value() && msg.guti->type == nas::EIdentityType::GUTI)
{
m_storedGuti = msg.guti.value();
m_storedSuci = {};
m_storage.m_storedSuci = {};
m_storage.m_storedGuti = *msg.guti;
m_timers->t3519.stop();
}
if (msg.taiList.has_value())
m_taiList = msg.taiList.value();
m_storage.m_taiList = msg.taiList.value();
if (msg.configurationUpdateIndication.has_value())
{
......
......@@ -30,10 +30,10 @@ void NasMm::sendDeregistration(nas::ESwitchOff switchOff, bool dueToDisable5g)
request->deRegistrationType.reRegistrationRequired = nas::EReRegistrationRequired::NOT_REQUIRED;
request->deRegistrationType.switchOff = switchOff;
if (m_currentNsCtx.has_value())
if (m_storage.m_currentNsCtx.has_value())
{
request->ngKSI.tsc = m_currentNsCtx->tsc;
request->ngKSI.ksi = m_currentNsCtx->ngKsi;
request->ngKSI.tsc = m_storage.m_currentNsCtx->tsc;
request->ngKSI.ksi = m_storage.m_currentNsCtx->ngKsi;
}
else
{
......@@ -76,7 +76,7 @@ void NasMm::receiveDeregistrationAccept(const nas::DeRegistrationAcceptUeOrigina
m_timers->t3521.stop();
m_timers->t3519.stop();
m_storedSuci = {};
m_storage.m_storedSuci = {};
switchRmState(ERmState::RM_DEREGISTERED);
......@@ -162,7 +162,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
case nas::EMmCause::ILLEGAL_ME:
case nas::EMmCause::FIVEG_SERVICES_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateSim();
m_storage.invalidateSim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
break;
}
......@@ -175,13 +175,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
//}
case nas::EMmCause::TA_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateAcquiredParams();
m_storage.discardUsim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_LIMITED_SERVICE);
break;
}
case nas::EMmCause::N1_MODE_NOT_ALLOWED: {
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateAcquiredParams();
m_storage.discardUsim();
switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA);
break;
}
......@@ -198,7 +198,7 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
nas::utils::EnumToString(msg.mmCause->value));
switchUState(E5UState::U3_ROAMING_NOT_ALLOWED);
invalidateSim();
m_storage.invalidateSim();
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
break;
}
......
......@@ -43,15 +43,15 @@ void NasMm::receiveIdentityRequest(const nas::IdentityRequest &msg)
nas::IE5gsMobileIdentity NasMm::getOrGenerateSuci()
{
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();
if (m_storedSuci.type == nas::EIdentityType::NO_IDENTITY)
if (m_storage.m_storedSuci.type == nas::EIdentityType::NO_IDENTITY)
return {};
return m_storedSuci;
return m_storage.m_storedSuci;
}
nas::IE5gsMobileIdentity NasMm::generateSuci()
......@@ -93,8 +93,8 @@ nas::IE5gsMobileIdentity NasMm::generateSuci()
nas::IE5gsMobileIdentity NasMm::getOrGeneratePreferredId()
{
if (m_storedGuti.type != nas::EIdentityType::NO_IDENTITY)
return m_storedGuti;
if (m_storage.m_storedGuti.type != nas::EIdentityType::NO_IDENTITY)
return m_storage.m_storedGuti;
else
{
auto suci = getOrGenerateSuci();
......
......@@ -11,6 +11,7 @@
#include <crypt/milenage.hpp>
#include <nas/nas.hpp>
#include <nas/timer.hpp>
#include <ue/nas/storage.hpp>
#include <ue/nts.hpp>
#include <ue/types.hpp>
#include <utils/nts.hpp>
......@@ -28,31 +29,22 @@ class NasMm
UeTimers *m_timers;
std::unique_ptr<Logger> m_logger;
NasSm *m_sm;
MobileStorage m_storage{};
bool m_autoBehaviour;
ERmState m_rmState;
ECmState m_cmState;
EMmState m_mmState;
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{};
// The very last de-registration request (or null)
std::unique_ptr<nas::DeRegistrationRequestUeOriginating> m_lastDeregistrationRequest{};
// Indicates that the last de-registration request is issued due to disable 5G services
bool m_lastDeregDueToDisable5g{};
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;
// Last time PLMN search is triggered
long m_lastPlmnSearchTrigger{};
OctetString m_sqn{};
friend class UeCmdHandler;
......@@ -91,8 +83,6 @@ class NasMm
void onSwitchRmState(ERmState oldState, ERmState newState);
void onSwitchCmState(ECmState oldState, ECmState newState);
void onSwitchUState(E5UState oldState, E5UState newState);
void invalidateAcquiredParams();
void invalidateSim();
/* Transport */
void sendMmStatus(nas::EMmCause cause);
......
......@@ -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
// initiates an initial registration procedure
if (registrationType == nas::ERegistrationType::INITIAL_REGISTRATION)
{
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
}
m_storage.discardCurrentSecurity();
switchMmState(EMmState::MM_REGISTERED_INITIATED, EMmSubState::MM_REGISTERED_INITIATED_NA);
nas::IENasKeySetIdentifier ngKsi;
if (m_currentNsCtx.has_value())
if (m_storage.m_currentNsCtx.has_value())
{
ngKsi.tsc = m_currentNsCtx->tsc;
ngKsi.ksi = m_currentNsCtx->ngKsi;
ngKsi.tsc = m_storage.m_currentNsCtx->tsc;
ngKsi.ksi = m_storage.m_currentNsCtx->ngKsi;
}
auto request = std::make_unique<nas::RegistrationRequest>();
......@@ -52,8 +49,8 @@ void NasMm::sendRegistration(nas::ERegistrationType registrationType, nas::EFoll
request->mobileIdentity = getOrGeneratePreferredId();
if (m_lastVisitedRegisteredTai.has_value())
request->lastVisitedRegisteredTai = m_lastVisitedRegisteredTai.value();
if (m_storage.m_lastVisitedRegisteredTai.has_value())
request->lastVisitedRegisteredTai = m_storage.m_lastVisitedRegisteredTai.value();
m_timers->t3510.start();
m_timers->t3502.stop();
......@@ -73,7 +70,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg)
bool sendCompleteMes = false;
m_taiList = msg.taiList;
m_storage.m_taiList = msg.taiList;
if (msg.t3512Value.has_value() && nas::utils::HasValue(msg.t3512Value.value()))
{
......@@ -83,7 +80,7 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg)
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();
sendCompleteMes = true;
......@@ -122,6 +119,8 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
}
auto unhandledRejectCase = [cause, this]() {
m_storage.discardUsim();
m_logger->err("Registration rejected with unhandled MMCause: %s", nas::utils::EnumToString(cause));
switchMmState(EMmState::MM_DEREGISTERED, EMmSubState::MM_DEREGISTERED_NA);
switchRmState(ERmState::RM_DEREGISTERED);
......@@ -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::NO_SUITIBLE_CELLS_IN_TA)
{
m_storedGuti = {};
m_lastVisitedRegisteredTai = {};
m_taiList = {};
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
m_storage.discardUsim();
// TODO Normally UE switches to PLMN SEARCH, but this leads to endless registration attempt again and again.
// due to RLS.
......@@ -168,11 +163,7 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
}
else if (cause == nas::EMmCause::N1_MODE_NOT_ALLOWED)
{
m_storedGuti = {};
m_lastVisitedRegisteredTai = {};
m_taiList = {};
m_currentNsCtx = {};
m_nonCurrentNsCtx = {};
m_storage.discardUsim();
switchMmState(EMmState::MM_NULL, EMmSubState::MM_NULL_NA);
switchRmState(ERmState::RM_DEREGISTERED);
......
......@@ -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));
};
if (!m_nonCurrentNsCtx.has_value())
if (!m_storage.m_nonCurrentNsCtx.has_value())
{
reject(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE);
return;
......@@ -58,7 +58,7 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
// Assign ABBA (if any)
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
{
......@@ -68,17 +68,17 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
}
// Assign selected algorithms to security context, and derive NAS keys
m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity;
m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering;
keys::DeriveNasKeys(*m_nonCurrentNsCtx);
m_storage.m_nonCurrentNsCtx->integrity = msg.selectedNasSecurityAlgorithms.integrity;
m_storage.m_nonCurrentNsCtx->ciphering = msg.selectedNasSecurityAlgorithms.ciphering;
keys::DeriveNasKeys(*m_storage.m_nonCurrentNsCtx);
m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(),
m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str());
m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_nonCurrentNsCtx->integrity,
(int)m_nonCurrentNsCtx->ciphering);
m_logger->debug("Derived kNasEnc[%s] kNasInt[%s]", m_storage.m_nonCurrentNsCtx->keys.kNasEnc.toHexString().c_str(),
m_storage.m_nonCurrentNsCtx->keys.kNasInt.toHexString().c_str());
m_logger->debug("Selected integrity[%d] ciphering[%d]", (int)m_storage.m_nonCurrentNsCtx->integrity,
(int)m_storage.m_nonCurrentNsCtx->ciphering);
// 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
nas::SecurityModeComplete resp;
......
......@@ -21,10 +21,11 @@ void NasMm::sendNasMessage(const nas::PlainMmMessage &msg)
// TODO trigger on send
OctetString pdu{};
if (m_currentNsCtx.has_value() && (m_currentNsCtx->integrity != nas::ETypeOfIntegrityProtectionAlgorithm::IA0 ||
m_currentNsCtx->ciphering != nas::ETypeOfCipheringAlgorithm::EA0))
if (m_storage.m_currentNsCtx.has_value() &&
(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);
}
else
......@@ -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
// 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(
"Not integrity protected NAS message received after security establishment. Ignoring received "
......@@ -100,14 +101,14 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg)
return;
}
if (!m_currentNsCtx.has_value())
if (!m_storage.m_currentNsCtx.has_value())
{
m_logger->warn("Secured NAS message received while no security context");
sendMmStatus(nas::EMmCause::MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE);
return;
}
auto decrypted = nas_enc::Decrypt(*m_currentNsCtx, securedMm);
auto decrypted = nas_enc::Decrypt(*m_storage.m_currentNsCtx, securedMm);
if (decrypted == nullptr)
{
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