add some 5G MM structures and routines

This commit is contained in:
p1-bmu 2021-04-27 17:30:12 +02:00
parent 013b3fccbb
commit c4333e4b59
9 changed files with 1132 additions and 79 deletions

View File

@ -366,7 +366,7 @@ class GNBd(object):
return None, ran_ue_id
elif FgsIdType == FGSIDTYPE_GUTI:
# TODO: should ensure PLMN and AMF identifiers correspond
return self.Server.get_ued(mtmsi=FgsId['5GTMSI'].get_val()), ran_ue_id
return self.Server.get_ued(fgtmsi=FgsId['5GTMSI'].get_val()), ran_ue_id
else:
self._log('WNG', 'Unable to get UE id from NAS message, 5GSID of '\
'unexpected type %i' % FgsIdType)

View File

@ -28,11 +28,11 @@
# *--------------------------------------------------------
#*/
from .utils import *
from .HdlrUEIuCS import *
from .HdlrUEIuPS import *
from .HdlrUES1 import *
from .HdlrUENG import *
from .utils import *
class UEd(SigStack):
@ -75,10 +75,11 @@ class UEd(SigStack):
IMSI = None
IMEI = None
IMEISV = None
# temporary identities (TMSI / PTMSI / MTMSI are uint32)
# temporary identities (TMSI / PTMSI / MTMSI / FGTMSI are uint32)
TMSI = None # CS domain
PTMSI = None # PS domain
MTMSI = None # EPS / 5GS domains
MTMSI = None # EPS domain
FGTMSI = None # 5GS domain
#--------------------------------------------------------------------------#
# CorenetServer reference
@ -118,11 +119,17 @@ class UEd(SigStack):
if imsi:
self.IMSI = imsi
elif 'tmsi' in kw:
# CS domain, 3G
self.TMSI = kw['tmsi']
elif 'ptmsi' in kw:
# PS domain, 3G
self.PTMSI = kw['ptmsi']
elif 'mtmsi' in kw:
# EPS domain, 4G
self.MTMSI = kw['mtmsi']
elif 'fgtmsi' in kw:
# 5GS domain, 5G
self.FGTMSI = kw['fgtmsi']
#
# init capabilities
self.Cap = {}
@ -405,6 +412,8 @@ class UEd(SigStack):
def get_new_tmsi(self):
# use the Python random generator
# WARNING: not good for randomness, but good enough for corenet
# and at least with some good uniqueness
return random.getrandbits(32)
def set_tmsi(self, tmsi):
@ -438,12 +447,23 @@ class UEd(SigStack):
del self.Server.MTMSI[self.MTMSI]
except Exception:
pass
# set the new PTMSI
# set the new MTMSI
self.MTMSI = mtmsi
# update the Server LUT
self.Server.MTMSI[mtmsi] = self.IMSI
# TODO: handle 5G NAS identities
def set_fgtmsi(self, fgtmsi):
# delete current 5GTMSI from the Server LUT
if self.FGTMSI is not None:
try:
del self.Server.FGTMSI[self.FGTMSI]
except Exception:
pass
# set the new 5G TMSI
self.FGTMSI = fgtmsi
# update the Server LUT
self.Server.FGTMSI[fgtmsi] = self.FGTMSI
#--------------------------------------------------------------------------#
# UE location
@ -771,3 +791,4 @@ class UEd(SigStack):
return '\n\n'.join(txt)
else:
return ''

View File

@ -3,7 +3,7 @@
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2020. Benoit Michau. ANSSI.
# * Copyright 2020. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
@ -29,9 +29,9 @@
from .utils import *
from .ProcCNNgap import *
# load all required 5GS NAS protocol handlers and SMS handler
#from .ProcCNFGMM import *
#from .HdlrUESMS import *
from .ProcCNFGMM import *
from .ProcCNFGSM import *
from .HdlrUESMS import *
class UEFGMMd(SigStack):
@ -55,17 +55,27 @@ class UEFGMMd(SigStack):
# additional time for letting background task happen in priority
_WAIT_ADD = 0.005
# list of 5GMM message types that do not require NAS security to be
# activated to be processed
SEC_NOTNEED = {}
# to disable completely the check for secured NAS message
SEC_DISABLED = False
#--------------------------------------------------------------------------#
# FGMM timers
#--------------------------------------------------------------------------#
# MT Deregistration
T3522 = 1
# Registration
T3550 = 1
# UE Config Update
T3555 = 2
# AKA, SMC
T3560 = 2
# Identification
T3570 = 1
# NSSAI Auth
T3575 = 2
def _log(self, logtype, msg):
self.NG._log(logtype, '[5GMM] %s' % msg)
@ -89,13 +99,11 @@ class UEFGMMd(SigStack):
"""process a NAS 5GMM message (NasRx) sent by the UE,
and return a list (possibly empty) of NGAP procedure(s) to be sent back
to the gNB
NasRx has 2 additional attributes (_sec [bool], _ulcnt [uint])
"""
# TODO
return []
def init_proc(self, ProcClass, encod=None, fgmm_preempt=False, sec=True):
def init_proc(self, ProcClass, encod=None, fgmm_preempt=False):
"""initialize a CN-initiated 5GMM procedure of class `ProcClass' and
given encoder(s), and return the procedure
"""
@ -133,7 +141,7 @@ class UEFGMMd(SigStack):
else:
return True
def run_proc(self, ProcClass, sec=True, **IEs):
def run_proc(self, ProcClass, **IEs):
"""run a network-initiated procedure ProcClass in the context of the 5GMM stack,
after setting the given IEs in the NAS message to be sent to the UE
@ -147,7 +155,7 @@ class UEFGMMd(SigStack):
if not self._net_init_con():
return False, None
#
Proc = self.init_proc(ProcClass, encod={ProcClass.Init: IEs}, fgmm_preempt=True, sec=sec)
Proc = self.init_proc(ProcClass, encod={ProcClass.Init: IEs}, fgmm_preempt=True)
try:
NgapTxProc = Proc.output()
except Exception:
@ -190,15 +198,6 @@ class UEFGSMd(SigStack):
# to bypass the process() server loop with a custom NAS PDU handler
RX_HOOK = None
# list of ESM message types that do not require NAS security to be
# activated to be processed
SEC_NOTNEED = {
}
# to disable completely the check for secured NAS message
SEC_DISABLED = False
def _log(self, logtype, msg):
self.NG._log(logtype, '[5GSM] %s' % msg)
@ -224,8 +223,6 @@ class UEFGSMd(SigStack):
and return a list (possibly empty) of NGAP procedure(s) to be sent back
to the gNB
NasRx has 2 additional attributes (_sec [bool], _ulcnt [uint])
FGMMProc [FMMSigProc or None], indicates if the NAS FGSM message is handled in
the context of an FGMM procedure
"""
@ -361,6 +358,7 @@ class UENGd(SigStack):
self.reset_sec_ctx()
#
self.connected = Event()
self.nasinit = Event() # state for initial NAS message
if gnbd is not None:
self.set_ran(gnbd)
else:
@ -369,12 +367,13 @@ class UENGd(SigStack):
# init 5GMM and 5GSM sig stacks
self.FGMM = UEFGMMd(ued, self)
self.FGSM = UEFGSMd(ued, self)
#self.SMS = UESMSd(ued, self)
self.SMS = UESMSd(ued, self)
def set_ran(self, gnbd):
self.SEC['KSI'] = None
self.GNB = gnbd
self.connected.set()
self.nasinit.set()
def unset_ran(self):
self.GNB.unset_ue_ng(self.CtxId)
@ -382,6 +381,7 @@ class UENGd(SigStack):
self.SEC['KSI'] = None
self.clear()
self.connected.clear()
self.nasinit.clear()
def set_ran_unconnected(self, gnbd):
# required for paging
@ -575,13 +575,15 @@ class UENGd(SigStack):
return self.ret_ngap_dnt(NAS.FGMMStatus(val={'5GMMCause':err}, sec=False))
#
# 5GS NAS security handling
sh, pd = NasRxSec[0]['SecHdr'].get_val(), NasRxSec[0]['EPD'].get_val()
if sh == 0:
# clear-text NAS message
NasRxSec._sec = False
NasRxSec._ulcnt = 0
if self.UE.TRACE_NAS_EPS:
self._log('TRACE_NAS_5G_UL', '\n' + NasRxSec.show())
if self.UE.TRACE_NAS_5GS:
self._log('TRACE_NAS_5GS_UL', '\n' + NasRxSec.show())
if pd == 126:
NgapTxProc = self.FGMM.process(NasRxSec)
else:
@ -707,7 +709,6 @@ class UENGd(SigStack):
else:
return []
def _ngap_nas_sec_err(self):
# TODO: maybe release the NG-UE link ?
return []
@ -716,6 +717,7 @@ class UENGd(SigStack):
# clears all NAS EPS procedures
self.FGMM.clear()
self.FGSM.clear()
self.SMS.clear()
#--------------------------------------------------------------------------#
# network-initiated method (fg task, to be used from the interpreter)

View File

@ -68,17 +68,18 @@ class UEEMMd(SigStack):
# list of EMM message types that do not require NAS security to be
# activated to be processed
SEC_NOTNEED = {'EMMAttachRequest',
'EMMIdentityResponse', # only for IMSI
'EMMAuthenticationResponse',
'EMMAuthenticationFailure',
'EMMSecurityModeReject',
'EMMDetachRequestMO', # if sent before security activation
'EMMDetachAccept',
'EMMTrackingAreaUpdateRequest',
'EMMServiceRequest',
'EMMExtServiceRequest'
}
SEC_NOTNEED = {
'EMMAttachRequest',
'EMMIdentityResponse', # only for IMSI
'EMMAuthenticationResponse',
'EMMAuthenticationFailure',
'EMMSecurityModeReject',
'EMMDetachRequestMO', # if sent before security activation
'EMMDetachAccept',
'EMMTrackingAreaUpdateRequest',
'EMMServiceRequest',
'EMMExtServiceRequest'
}
# to disable completely the check for secured NAS message
SEC_DISABLED = False

View File

@ -0,0 +1,794 @@
# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2021. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_corenet/ProcCNFGMM.py
# * Created : 2021-04-27
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
__all__ = [
'FGMMSigProc',
#
'FGMMPrimAKA',
'FGMMSecurityModeControl',
'FGMMIdentification',
'FGMMGenericUEConfigUpdate',
'FGMMMONASTransport',
'FGMMMTNASTransport',
'FGMMNSSAA',
#
'FGMMRegistration',
'FGMMMODeregistration',
'FGMMMTDeregistration',
'FGMMServiceRequest',
'FGMMCtrlPlaneServiceRequest',
#
'FGMMProcUeDispatcher',
'FGMMProcUeDispatcherStr',
'FGMMProcCnDispatcher',
'FGMMProcCnDispatcherStr'
]
from .utils import *
from .ProcProto import *
from .ProcCNNgap import *
TESTING = False
#------------------------------------------------------------------------------#
# NAS 5GS Mobility Management signalling procedure
# TS 24.501, version h21
# Core Network side
#------------------------------------------------------------------------------#
class FGMMSigProc(NASSigProc):
"""5GS Mobility Management signalling procedure handler
instance attributes:
- Name : procedure name
- FGMM : reference to the UEFGMMd instance running this procedure
- NG : reference to the UENGd instance connecting the UE
- Cont : 2-tuple of CN-initiated NAS message(s) and UE-initiated NAS
message(s)
- Timer: timer in sec. for this procedure
- Encod: custom NAS message encoders with fixed values
- Decod: custom NAS message decoders with transform functions
"""
# tacking all exchanged NAS message within the procedure
TRACK_PDU = True
# potential timer
Timer = None
TimerDefault = 4
# network initiator message id
Init = None
if TESTING:
def __init__(self, encod=None):
self._prepare(encod)
self._log('DBG', 'instantiating procedure')
def _log(self, logtype, msg):
log('[TESTING] [%s] [FGMMSigProc] [%s] %s' % (logtype, self.Name, msg))
else:
def __init__(self, fgmmd, encod=None, fgmm_preempt=False, sec=True):
self._prepare(encod)
self.FGMM = fgmmd
self.NG = fgmmd.NG
self.UE = fgmmd.UE
self._fgmm_preempt = fgmm_preempt
if fgmm_preempt:
self.FGMM.ready.clear()
self._log('DBG', 'instantiating procedure')
def _log(self, logtype, msg):
self.FGMM._log(logtype, '[%s] %s' % (self.Name, msg))
def output(self):
self._log('ERR', 'output() not implemented')
return []
def process(self, pdu):
if self.TRACK_PDU:
self._pdu.append( (time(), 'UL', pdu) )
self.UEInfo = {}
self.decode_msg(pdu, self.UEInfo)
#
self._log('ERR', 'process() not implemented')
return []
def postprocess(self, Proc=None):
self._log('ERR', 'postprocess() not implemented')
self.rm_from_fgmm_stack()
return []
def abort(self):
# abort this procedure, and all procedures started within this one
ind = self.FGMM.Proc.index(self)
if ind >= 0:
for p in self.FGMM.Proc[ind+1:]:
p.abort()
del self.FGMM.Proc[ind:]
if self._fgmm_preempt:
# release the FGMM stack
self.FGMM.ready.set()
self._log('INF', 'aborting')
def rm_from_fgmm_stack(self):
# remove the procedure from the FGMM stack of procedures
try:
if self.FGMM.Proc[-1] == self:
del self.FGMM.Proc[-1]
except Exception:
self._log('WNG', 'FGMM stack corrupted')
else:
if self._fgmm_preempt:
# release the FGMM stack
self.FGMM.ready.set()
def init_timer(self):
if self.Timer is not None:
self.TimerValue = getattr(self.FGMM, self.Timer, self.TimerDefault)
self.TimerStart = time()
self.TimerStop = self.TimerStart + self.TimerValue
def get_timer(self):
if self.Timer is None:
return None
else:
return getattr(self.FGMM, self.Timer)
def fgmm_preempt(self):
self._fgmm_preempt = True
self.FGMM.ready.clear()
#--------------------------------------------------------------------------#
# common helpers
#--------------------------------------------------------------------------#
# None yet
#------------------------------------------------------------------------------#
# 5GMM common procedures: TS 24.501, section 5.4
#------------------------------------------------------------------------------#
class FGMMPrimAKA(FGMMSigProc):
"""Primary authentication and key agreement procedure: TS 24.501, section 5.4.1
CN-initiated
CN message:
5GMMAuthenticationRequest (PD 126, Type 86), IEs:
- Type1V : spare
- Type1V : NAS_KSI
- Type4LV : ABBA
- Type3TV : RAND (T: 33)
- Type4TLV : AUTN (T: 32)
- Type6TLVE : EAPMsg (T: 120)
5GMMAuthenticationReject (PD 126, Type 88), IEs:
- Type6TLVE : EAPMsg (T: 120)
5GMMAuthenticationResult (PD 126, Type 90), IEs:
- Type1V : spare
- Type1V : NAS_KSI
- Type6LVE : EAPMsg
- Type4TLV : ABBA (T: 56)
UE message:
5GMMAuthenticationResponse (PD 126, Type 87), IEs:
- Type4TLV : RES (T: 45)
- Type6TLVE : EAPMsg (T: 120)
5GMMAuthenticationFailure (PD 126, Type 89), IEs:
- Type3V : 5GMMCause
- Type4TLV : AUTS (T: 48)
"""
Cont = (
(TS24501_FGMM.FGMMAuthenticationRequest, TS24501_FGMM.FGMMAuthenticationReject),
(TS24501_FGMM.FGMMAuthenticationResponse, TS24501_FGMM.FGMMAuthenticationFailure)
)
Init = (126, 86)
Timer = 'T3560'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
class FGMMSecurityModeControl(FGMMSigProc):
"""Security mode control procedure: TS 24.501, section 5.4.2
CN-initiated
CM message:
5GMMSecurityModeCommand (PD 126, Type 93), IEs:
- Type3V : NASSecAlgo
- Type1V : spare
- Type1V : NAS_KSI
- Type4LV : UESecCap
- Type1TV : IMEISVReq (T: 14)
- Type3TV : EPSNASSecAlgo (T: 87)
- Type4TLV : Add5GSecInfo (T: 54)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : ABBA (T: 56)
- Type4TLV : S1UESecCap (T: 25)
UE message:
5GMMSecurityModeComplete (PD 126, Type 94), IEs:
- Type6TLVE : IMEISV (T: 119)
- Type6TLVE : NASContainer (T: 113)
- Type6TLVE : PEI (T: 120)
5GMMSecurityModeReject (PD 126, Type 95), IEs:
- Type3V : 5GMMCause
"""
Cont = (
(TS24501_FGMM.FGMMSecurityModeCommand, ),
(TS24501_FGMM.FGMMSecurityModeComplete, TS24501_FGMM.FGMMSecurityModeReject)
)
Init = (126, 93)
Timer = 'T3560'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
class FGMMIdentification(FGMMSigProc):
"""Identification procedure: TS 24.501, section 5.4.3
CN-initiated
CN message:
5GMMIdentityRequest (PD 126, Type 91), IEs:
- Type1V : spare
- Type1V : 5GSIDType
UE message:
5GMMIdentityResponse (PD 126, Type 92), IEs:
- Type6LVE : 5GSID
"""
Cont = (
(NAS.FGMMIdentityRequest, ),
(NAS.FGMMIdentityResponse, )
)
Init = (126, 91)
Timer = 'T3570'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
class FGMMGenericUEConfigUpdate(FGMMSigProc):
"""Generic UE configuration update procedure: TS 24.501, section 5.4.4
CN-initiated
CN message:
5GMMConfigurationUpdateCommand (PD 126, Type 84), IEs:
- Type1TV : ConfigUpdateInd (T: 13)
- Type6TLVE : GUTI (T: 119)
- Type4TLV : 5GSTAIList (T: 84)
- Type4TLV : AllowedNSSAI (T: 21)
- Type4TLV : SAList (T: 39)
- Type4TLV : NetFullName (T: 67)
- Type4TLV : NetShortName (T: 69)
- Type3TV : LocalTimeZone (T: 70)
- Type3TV : UnivTimeAndTimeZone (T: 71)
- Type4TLV : DLSavingTime (T: 73)
- Type6TLVE : LADNInfo (T: 121)
- Type1TV : MICOInd (T: 11)
- Type1TV : NetSlicingInd (T: 9)
- Type4TLV : ConfiguredNSSAI (T: 49)
- Type4TLV : RejectedNSSAI (T: 17)
- Type6TLVE : OperatorAccessCatDefs (T: 118)
- Type1TV : SMSInd (T: 15)
- Type4TLV : T3447 (T: 108)
- Type6TLVE : CAGInfoList (T: 117)
- Type4TLV : UERadioCapID (T: 103)
- Type1TV : UERadioCapIDDelInd (T: 10)
- Type4TLV : 5GSRegResult (T: 68)
- Type4TLV : Trunc5GSTMSIConfig (T: 27)
- Type1TV : AddConfigInd (T: 12)
UE message:
5GMMConfigurationUpdateComplete (PD 126, Type 85), IEs:
None
"""
Cont = (
(NAS.FGMMConfigurationUpdateCommand, ),
(NAS.FGMMConfigurationUpdateComplete, )
)
Init = (126, 84)
Timer = 'T3555'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
class FGMMMONASTransport(FGMMSigProc):
"""UE-initiated NAS transport procedure: TS 24.501, section 5.4.5.2
UE-initiated
CN message:
None
UE message:
5GMMULNASTransport (PD 126, Type 103), IEs:
- Type1V : spare
- Type1V : PayloadContainerType
- Type6LVE : PayloadContainer
- Type3TV : PDUSessID (T: 18)
- Type3TV : OldPDUSessID (T: 89)
- Type1TV : RequestType (T: 8)
- Type4TLV : SNSSAI (T: 34)
- Type4TLV : DNN (T: 37)
- Type4TLV : AddInfo (T: 36)
- Type1TV : MAPDUSessInfo (T: 10)
- Type1TV : ReleaseAssistInd (T: 15)
"""
Cont = (
None,
(NAS.FGMMULNASTransport,)
)
Init = (126, 103)
'''TODO
def process(self, pdu):
return []
'''
class FGMMMTNASTransport(FGMMSigProc):
"""Network-initiated NAS transport procedure: TS 24.501, section 5.4.5.3
CN-initiated
CN message:
5GMMDLNASTransport (PD 126, Type 104), IEs:
- Type1V : spare
- Type1V : PayloadContainerType
- Type6LVE : PayloadContainer
- Type3TV : PDUSessID (T: 18)
- Type4TLV : AddInfo (T: 36)
- Type3TV : 5GMMCause (T: 88)
- Type4TLV : BackOffTimer (T: 55)
UE message:
None
"""
Cont = (
(NAS.FGMMDLNASTransport, ),
None
)
Init = (126, 104)
'''TODO
def output(self):
return []
'''
class FGMMNSSAA(FGMMSigProc):
"""Network slice-specific authentication and authorization procedure: TS 24.501, section 5.4.7
CN-initiated
CN message:
5GMMNetworkSliceSpecAuthCommand (PD 126, Type 80), IEs:
- Type4LV : SNSSAI
- Type6LVE : EAPMsg
5GMMNetworkSliceSpecAuthResult (PD 126, Type 82), IEs:
- Type4LV : SNSSAI
- Type6LVE : EAPMsg
UE message:
5GMMNetworkSliceSpecAuthComplete (PD 126, Type 81), IEs:
- Type4LV : SNSSAI
- Type6LVE : EAPMsg
"""
Cont = (
(NAS.FGMMNetworkSliceSpecAuthCommand, NAS.FGMMNetworkSliceSpecAuthResult),
(NAS.FGMMNetworkSliceSpecAuthComplete, )
)
Init = (126, 80)
Timer = 'T3575'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
#------------------------------------------------------------------------------#
# 5GMM specific procedures: TS 24.501, section 5.5
#------------------------------------------------------------------------------#
class FGMMRegistration(FGMMSigProc):
"""Registration procedure: TS 24.501, section 5.5.1
UE-initiated
CN message:
5GMMRegistrationAccept (PD 126, Type 66), IEs:
- Type4LV : 5GSRegResult
- Type6TLVE : GUTI (T: 119)
- Type4TLV : EquivPLMNList (T: 74)
- Type4TLV : 5GSTAIList (T: 84)
- Type4TLV : AllowedNSSAI (T: 21)
- Type4TLV : RejectedNSSAI (T: 17)
- Type4TLV : ConfiguredNSSAI (T: 49)
- Type4TLV : 5GSNetFeat (T: 33)
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : PDUSessReactResult (T: 38)
- Type6TLVE : PDUSessReactResultErr (T: 114)
- Type6TLVE : LADNInfo (T: 121)
- Type1TV : MICOInd (T: 11)
- Type1TV : NetSlicingInd (T: 9)
- Type4TLV : SAList (T: 39)
- Type4TLV : T3512 (T: 94)
- Type4TLV : Non3GPPDeregTimer (T: 93)
- Type4TLV : T3502 (T: 22)
- Type4TLV : EmergNumList (T: 52)
- Type6TLVE : ExtEmergNumList (T: 122)
- Type6TLVE : SORTransContainer (T: 115)
- Type6TLVE : EAPMsg (T: 120)
- Type1TV : NSSAIInclMode (T: 10)
- Type6TLVE : OperatorAccessCatDefs (T: 118)
- Type4TLV : 5GSDRXParam (T: 81)
- Type1TV : Non3GPPNWProvPol (T: 13)
- Type4TLV : EPSBearerCtxtStat (T: 96)
- Type4TLV : ExtDRXParam (T: 110)
- Type4TLV : T3447 (T: 108)
- Type4TLV : T3448 (T: 107)
- Type4TLV : T3324 (T: 106)
- Type4TLV : UERadioCapID (T: 103)
- Type4TLV : PendingNSSAI (T: 57)
- Type6TLVE : CipheringKeyData (T: 116)
- Type6TLVE : CAGInfoList (T: 117)
- Type4TLV : Trunc5GSTMSIConfig (T: 27)
- Type4TLV : WUSAssistInfo (T: 26)
- Type4TLV : NBN1ModeDRXParam (T: 41)
5GMMRegistrationReject (PD 126, Type 68), IEs:
- Type3V : 5GMMCause
- Type4TLV : T3346 (T: 95)
- Type4TLV : T3502 (T: 22)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : RejectedNSSAI (T: 105)
- Type6TLVE : CAGInfoList (T: 117)
UE message:
5GMMRegistrationRequest (PD 126, Type 65), IEs:
- Type1V : NAS_KSI
- Type1V : 5GSRegType
- Type6LVE : 5GSID
- Type1TV : NonCurrentNativeNAS_KSI (T: 12)
- Type4TLV : 5GMMCap (T: 16)
- Type4TLV : UESecCap (T: 46)
- Type4TLV : NSSAI (T: 47)
- Type3TV : TAI (T: 82)
- Type4TLV : EPSUENetCap (T: 23)
- Type4TLV : ULDataStat (T: 64)
- Type4TLV : PDUSessStat (T: 80)
- Type1TV : MICOInd (T: 11)
- Type4TLV : UEStatus (T: 43)
- Type6TLVE : AddGUTI (T: 119)
- Type4TLV : AllowedPDUSessStat (T: 37)
- Type4TLV : UEUsage (T: 24)
- Type4TLV : 5GSDRXParam (T: 81)
- Type6TLVE : EPSNASContainer (T: 112)
- Type6TLVE : LADNInd (T: 116)
- Type1TV : PayloadContainerType (T: 8)
- Type6TLVE : PayloadContainer (T: 123)
- Type1TV : NetSlicingInd (T: 9)
- Type4TLV : 5GSUpdateType (T: 83)
- Type4TLV : MSCm2 (T: 65)
- Type4TLV : SuppCodecs (T: 66)
- Type6TLVE : NASContainer (T: 113)
- Type4TLV : EPSBearerCtxtStat (T: 96)
- Type4TLV : ExtDRXParam (T: 110)
- Type4TLV : T3324 (T: 106)
- Type4TLV : UERadioCapID (T: 103)
- Type4TLV : MappedNSSAI (T: 53)
- Type4TLV : AddInfoReq (T: 72)
- Type4TLV : WUSAssistInfo (T: 26)
- Type2 : N5GCInd (T: 10)
- Type4TLV : NBN1ModeDRXParam (T: 48)
5GMMRegistrationComplete (PD 126, Type 67), IEs:
- Type6TLVE : SORTransContainer (T: 115)
"""
Cont = (
(NAS.FGMMRegistrationAccept, NAS.FGMMRegistrationReject),
(NAS.FGMMRegistrationRequest, NAS.FGMMRegistrationComplete)
)
Init = (126, 65)
Timer = 'T3550'
'''TODO
def process(self, pdu):
return []
def output(self):
return []
'''
class FGMMMODeregistration(FGMMSigProc):
"""UE-initiated de-registration procedure: TS 24.501, section 5.5.2.2
UE-initiated
CN message:
5GMMMODeregistrationAccept (PD 126, Type 70), IEs:
None
UE message:
5GMMMODeregistrationRequest (PD 126, Type 69), IEs:
- Type1V : NAS_KSI
- Type1V : DeregistrationType
- Type6LVE : 5GSID
"""
Cont = (
(NAS.FGMMMODeregistrationAccept, ),
(NAS.FGMMMODeregistrationRequest, )
)
Init = (126, 69)
'''TODO
def process(self, pdu):
return []
def output(self):
return []
'''
class FGMMMTDeregistration(FGMMSigProc):
"""Network-initiated de-registration procedure: TS 24.501, section 5.5.2.3
CN-initiated
CN message:
5GMMMTDeregistrationRequest (PD 126, Type 71), IEs:
- Type1V : spare
- Type1V : DeregistrationType
- Type3TV : 5GMMCause (T: 88)
- Type4TLV : T3346 (T: 95)
- Type4TLV : RejectedNSSAI (T: 109)
UE message:
5GMMMTDeregistrationAccept (PD 126, Type 71), IEs:
None
"""
Cont = (
(NAS.FGMMMTDeregistrationRequest, ),
(NAS.FGMMMTDeregistrationAccept, )
)
Init = (126, 71)
Timer = 'T3522'
'''TODO
def output(self):
return []
def process(self, pdu):
return []
'''
#------------------------------------------------------------------------------#
# 5GMM connection management procedures: TS 24.501, section 5.6
#------------------------------------------------------------------------------#
class FGMMServiceRequest(FGMMSigProc):
"""Service request procedure: TS 24.501, section 5.6.1
UE-initiated
CN message:
5GMMServiceAccept (PD 126, Type 78), IEs:
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : PDUSessReactResult (T: 38)
- Type6TLVE : PDUSessReactResultErr (T: 114)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : T3448 (T: 107)
5GMMServiceAccept (PD 126, Type 77), IEs:
- Type3V : 5GMMCause
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : T3346 (T: 95)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : T3448 (T: 107)
- Type6TLVE : CAGInfoList (T: 117)
UE message:
5GMMServiceRequest (PD 126, Type 76), IEs:
- Type1V : ServiceType
- Type1V : NAS_KSI
- Type6LVE : 5GSID
- Type4TLV : ULDataStat (T: 64)
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : AllowedPDUSessStat (T: 37)
- Type6TLVE : NASContainer (T: 113)
"""
Cont = (
(NAS.FGMMServiceAccept, NAS.FGMMServiceReject),
(NAS.FGMMServiceRequest, )
)
Init = (126, 76)
'''TODO
def process(self, pdu):
return []
def output(self):
return []
'''
class FGMMCtrlPlaneServiceRequest(FGMMSigProc):
"""Service request procedure: TS 24.501, section 5.6.1
UE-initiated
CN message:
5GMMServiceAccept (PD 126, Type 78), IEs:
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : PDUSessReactResult (T: 38)
- Type6TLVE : PDUSessReactResultErr (T: 114)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : T3448 (T: 107)
5GMMServiceAccept (PD 126, Type 77), IEs:
- Type3V : 5GMMCause
- Type4TLV : PDUSessStat (T: 80)
- Type4TLV : T3346 (T: 95)
- Type6TLVE : EAPMsg (T: 120)
- Type4TLV : T3448 (T: 107)
- Type6TLVE : CAGInfoList (T: 117)
UE message:
5GMMControlPlaneServiceRequest (PD 126, Type 79), IEs:
- Type1V : NAS_KSI
- Type1V : CtrlPlaneServiceType
- Type4TLV : CIoTSmallDataContainer (T: 111)
- Type1TV : PayloadContainerType (T: 8)
- Type6TLVE : PayloadContainer (T: 123)
- Type3TV : PDUSessID (T: 18)
- Type4TLV : PDUSessStat (T: 80)
- Type1TV : ReleaseAssistInd (T: 15)
- Type4TLV : ULDataStat (T: 64)
- Type6TLVE : NASContainer (T: 113)
- Type4TLV : AddInfo (T: 36)
"""
Cont = (
(NAS.FGMMServiceAccept, NAS.FGMMServiceReject),
(NAS.FGMMControlPlaneServiceRequest, )
)
Init = (126, 79)
'''TODO
def process(self, pdu):
return []
def output(self):
return []
'''
FGMMPrimAKA.init(filter_init=1)
FGMMSecurityModeControl.init(filter_init=1)
FGMMIdentification.init(filter_init=1)
FGMMGenericUEConfigUpdate.init(filter_init=1)
FGMMMONASTransport.init(filter_init=1)
FGMMMTNASTransport.init(filter_init=1)
FGMMNSSAA.init(filter_init=1)
FGMMRegistration.init(filter_init=1)
FGMMMODeregistration.init(filter_init=1)
FGMMMTDeregistration.init(filter_init=1)
FGMMServiceRequest.init(filter_init=1)
FGMMCtrlPlaneServiceRequest.init(filter_init=1)
# 5G MM UE-initiated procedures dispatcher
FGMMProcUeDispatcher = {
103 : FGMMMONASTransport,
65 : FGMMRegistration,
69 : FGMMMODeregistration,
76 : FGMMServiceRequest,
79 : FGMMCtrlPlaneServiceRequest,
}
FGMMProcUeDispatcherStr = {ProcClass.Cont[1][0]()._name: ProcClass \
for ProcClass in FGMMProcUeDispatcher.values()}
# 5G MM CN-initiated procedures dispatcher
FGMMProcCnDispatcher = {
86 : FGMMPrimAKA,
93 : FGMMSecurityModeControl,
91 : FGMMIdentification,
84 : FGMMGenericUEConfigUpdate,
104 : FGMMMTNASTransport,
80 : FGMMNSSAA,
71 : FGMMMTDeregistration,
}
FGMMProcCnDispatcherStr = {ProcClass.Cont[0][0]()._name: ProcClass \
for ProcClass in FGMMProcCnDispatcher.values()}

View File

@ -0,0 +1,179 @@
# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2021. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_corenet/ProcCNFGSM.py
# * Created : 2021-04-27
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
__all__ = [
'FGSMSigProc',
]
from .utils import *
from .ProcProto import *
from .ProcCNNgap import *
TESTING = False
#------------------------------------------------------------------------------#
# NAS 5GS Session Management signalling procedure
# TS 24.501, version h21
# Core Network side
#------------------------------------------------------------------------------#
class FGSMSigProc(NASSigProc):
"""5GS Session Management signalling procedure handler
instance attributes:
- Name : procedure name
- FGSM : reference to the UEFGSMd instance running this procedure
- NG : reference to the UENGd instance connecting the UE
- Cont : 2-tuple of CN-initiated NAS message(s) and UE-initiated NAS
message(s)
- Timer: timer in sec. for this procedure
- Encod: custom NAS message encoders with fixed values
- Decod: custom NAS message decoders with transform functions
"""
# tacking all exchanged NAS message within the procedure
TRACK_PDU = True
# potential timer
Timer = None
TimerDefault = 2
if TESTING:
def __init__(self, encod=None):
self._prepare(encod)
self._log('DBG', 'instantiating procedure')
def _log(self, logtype, msg):
log('[TESTING] [%s] [FGSMSigProc] [%s] %s' % (logtype, self.Name, msg))
else:
def __init__(self, fgsmd, encod=None, sec=True, ebi=0, FGMMProc=None):
self._prepare(encod)
self.FGSM = fgsmd
self.NG = fgsmd.NG
self.UE = fgsmd.UE
self._ebi = ebi
self._FGMMProc = FGMMProc
self._log('DBG', 'instantiating procedure')
def _log(self, logtype, msg):
self.FGSM._log(logtype, '[%s [%i]] %s' % (self.Name, self._ebi, msg))
def decode_msg(self, msg, ret):
NASSigProc.decode_msg(self, msg, ret)
# add PDUSessionID and PTI into ret
ret['PDUSessID'] = msg[0][1].get_val()
ret['PTI'] = msg[0][2].get_val()
def set_msg(self, pd, typ, **kw):
"""prepare a specific encoder dict for a given NAS message
"""
# select the encoder and duplicate it
try:
Encod = self.Encod[(pd, typ)]
except Exception:
return
FGSMHeader = {}
if 'PDUSessID' in kw:
FGSMHeader['PDUSessID'] = kw['PDUSessID']
del kw['PDUSessID']
if 'PTI' in kw:
FGSMHeader['PTI'] = kw['PTI']
del kw['PTI']
if FGSMHeader:
kw['FGSMHeader'] = FGSMHeader
Encod.update(kw)
def output(self):
self._log('ERR', 'output() not implemented')
return None
def process(self, pdu):
if self.TRACK_PDU:
self._pdu.append( (time(), 'UL', pdu) )
self.UEInfo = {}
self.decode_msg(pdu, self.UEInfo)
#
self._log('ERR', 'process() not implemented')
return None
def postprocess(self, Proc=None):
self._log('ERR', 'postprocess() not implemented')
self.rm_from_fgsm_stack()
return None
def abort(self):
# abort this procedure, and all procedures started within this one
ProcStack = self.FGSM.Proc[self._ebi]
ind = ProcStack.index(self)
if ind >= 0:
for p in ProcStack[ind+1:]:
p.abort()
del ProcStack[ind:]
self._log('INF', 'aborting')
def rm_from_fgsm_stack(self):
# remove the procedure from the FGSM stack of procedures
try:
ProcStack = self.FGSM.Proc[self._ebi]
if ProcStack[-1] == self:
del ProcStack[-1]
except Exception:
self._log('WNG', 'FGSM stack corrupted')
def init_timer(self):
if self.Timer is not None:
self.TimerValue = getattr(self.FGSM, self.Timer, self.TimerDefault)
self.TimerStart = time()
self.TimerStop = self.TimerStart + self.TimerValue
def get_timer(self):
if self.Timer is None:
return None
else:
return getattr(self.FGSM, self.Timer)
#--------------------------------------------------------------------------#
# common helpers
#--------------------------------------------------------------------------#
# None yet
#------------------------------------------------------------------------------#
# Network-requested 5G SM procedures: TS 24.501, section 6.3
#------------------------------------------------------------------------------#
#------------------------------------------------------------------------------#
# UE-requested 5G SM procedures: TS 24.501, section 6.4
#------------------------------------------------------------------------------#

View File

@ -489,8 +489,10 @@ class NASSigProc(SigProc):
mhdr = msg[0]
if mhdr[0]._name == 'TIPD':
mid = (mhdr[0]['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
elif 'ProtDisc' in mhdr._by_name:
mid = (mhdr['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
mid = (mhdr['EPD'].get_val(), mhdr['Type'].get_val())
mies = msg[1:]
ContLUT[mid] = (0, i)
if mid not in cls.Encod:
@ -520,8 +522,10 @@ class NASSigProc(SigProc):
mhdr = msg[0]
if mhdr[0]._name == 'TIPD':
mid = (mhdr[0]['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
elif 'ProtDisc' in mhdr._by_name:
mid = (mhdr['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
mid = (mhdr['EPD'].get_val(), mhdr['Type'].get_val())
mies = msg[1:]
ContLUT[mid] = (1, i)
if mid not in cls.Encod:
@ -553,8 +557,10 @@ class NASSigProc(SigProc):
mhdr = msg[0]
if mhdr[0]._name == 'TIPD':
mid = (mhdr[0]['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
elif 'ProtDisc' in mhdr._by_name:
mid = (mhdr['ProtDisc'].get_val(), mhdr['Type'].get_val())
else:
mid = (mhdr['EPD'].get_val(), mhdr['Type'].get_val())
Filter.add(mid)
FilterStr.add(msg._name)
if Filter:

View File

@ -342,10 +342,11 @@ class CorenetServer(object):
# UE, indexed by TMSI when the IMSI is unknown (at attachment),
# and their UEd handler instance are set in ._UEpre, created at init
#
# TMSI / P-TMSI / M-TMSI to IMSI conversion
TMSI = {}
PTMSI = {}
MTMSI = {}
# TMSI / P-TMSI / M-TMSI / 5G-TMSI to IMSI conversion
TMSI = {}
PTMSI = {}
MTMSI = {}
FGTMSI = {}
#
# This is a filter which enables the potential attachment of non-preconfigured
# UE to the CorenetServer
@ -1315,7 +1316,7 @@ class CorenetServer(object):
def get_ued(self, **kw):
"""return a UEd instance or None, according to the UE identity provided
kw: imsi (digit-str), tmsi (uint32), ptmsi (uint32) or mtmsi (uint32)
kw: imsi (digit-str), tmsi (uint32), ptmsi (uint32), mtmsi (uint32) or fgtmsi (uint32)
If an imsi is provided, returns the UEd instance in case the IMSI is allowed
If a tmsi or ptmsi is provided, returns
@ -1333,7 +1334,7 @@ class CorenetServer(object):
return self.UE[imsi]
elif self.UE_ATTACH_FILTER and re.match(self.UE_ATTACH_FILTER, imsi) and \
'*' in self.ConfigUE:
self._log('WNG', 'attaching an UE without dedicated configuration, IMSI %s' % imsi)
self._log('WNG', 'attaching a UE without dedicated configuration, IMSI %s' % imsi)
self.UE[imsi] = UEd(self, imsi, config=self.ConfigUE['*'])
return self.UE[imsi]
else:
@ -1359,6 +1360,13 @@ class CorenetServer(object):
else:
# creating a UEd instance which will request IMSI
return self.create_dummy_ue(mtmsi=mtmsi)
elif 'fgtmsi' in kw:
fgtmsi = kw['fgtmsi']
if fgtmsi in self.FGTMSI:
return self.UE[self.FGTMSI[fgtmsi]]
else:
# creating a UEd instance which will request SUPI
return self.create_dummy_ue(fgtmsi=fgtmsi)
return None
def create_dummy_ue(self, **kw):
@ -1390,18 +1398,20 @@ class CorenetServer(object):
# go over all UE and abort() NAS signalling procedures in timeout
T = time()
for ue in self.UE.values():
if ue.IuCS is not None:
if ue.IuCS.MM.Proc:
for P in ue.IuCS.MM.Proc:
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
#if ue.IuCS.CC.Proc:
# for P in ue.IuCS.CC.Proc.values():
# if hasattr(P, 'TimerStop') and T > P.TimerStop:
# P._log('WNG', 'timeout: aborting')
# P.abort()
if ue.IuCS.CC.Proc:
for P in ue.IuCS.CC.Proc.values():
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.IuCS.SMS.Proc:
for P in tuple(ue.IuCS.SMS.Proc.values()):
@ -1409,11 +1419,11 @@ class CorenetServer(object):
P._log('WNG', 'timeout: aborting')
P.abort()
#if ue.IuCS.SS.Proc:
# for P in ue.IuCS.SS.Proc.values():
# if hasattr(P, 'TimerStop') and T > P.TimerStop:
# P._log('WNG', 'timeout: aborting')
# P.abort()
if ue.IuCS.SS.Proc:
for P in ue.IuCS.SS.Proc.values():
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.IuPS is not None:
@ -1424,11 +1434,11 @@ class CorenetServer(object):
P._log('WNG', 'timeout: aborting')
P.abort()
#if ue.IuPS.SM.Proc:
# for P in tuple(ue.IuPS.SM.Proc.values()):
# if hasattr(P, 'TimerStop') and T > P.TimerStop:
# P._log('WNG', 'timeout: aborting')
# P.abort()
if ue.IuPS.SM.Proc:
for P in tuple(ue.IuPS.SM.Proc.values()):
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.S1 is not None:
@ -1449,6 +1459,26 @@ class CorenetServer(object):
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.NG is not None:
if ue.NG.FGMM.Proc:
for P in ue.NG.FGMM.Proc:
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.NG.FGSM.Proc:
for P in tuple(ue.NG.FGSM.Proc.values()):
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
if ue.NG.SMS.Proc:
for P in tuple(ue.NG.SMS.Proc.values()):
if hasattr(P, 'TimerStop') and T > P.TimerStop:
P._log('WNG', 'timeout: aborting')
P.abort()
def get_gtp_teid(self):
if self._GTP_TEID_UL > 4294967294:

View File

@ -475,32 +475,52 @@ def print_pduies(desc):
print(' None')
def print_nasies(nasmsg):
def print_nasies(nasmsg, indent=''):
# go after the header (last field: Type), and print IE type, tag if defined,
# and name
# WNG: Type1V (Uint4), Type2 (Uint8), Type3V(Buf) are not wrapped
hdr = nasmsg[0]
if 'ProtDisc' in hdr._by_name:
pd = hdr['ProtDisc'].get_val()
elif 'EPD' in hdr._by_name:
pd = hdr['EPD'].get_val()
else:
pd = hdr[0]['ProtDisc'].get_val()
typ = hdr['Type'].get_val()
print('%s (PD %i, Type %i), IEs:' % (nasmsg._name, pd, typ))
print('%s%s (PD %i, Type %i), IEs:' % (indent, nasmsg._name, pd, typ))
#
if len(nasmsg._content) == 1:
print(' None')
print('%s None' % indent)
else:
for ie in nasmsg._content[1:]:
if ie.get_trans():
# optional IE
print('- %-9s : %s (T: %i)'\
% (ie.__class__.__name__, ie._name, ie[0].get_val()))
print('%s- %-9s : %s (T: %i)'\
% (indent, ie.__class__.__name__, ie._name, ie[0].get_val()))
elif isinstance(ie, TS24007.IE):
# mandatory IE
print('- %-9s : %s' % (ie.__class__.__name__, ie._name))
print('%s- %-9s : %s' % (indent, ie.__class__.__name__, ie._name))
elif ie.get_bl() == 4:
# uint / spare bits
print('- %-9s : %s' % ('Type1V', 'spare'))
print('%s- %-9s : %s' % (indent, 'Type1V', 'spare'))
else:
assert()
def print_nasproc_docs(nasproc):
msgcn, msgue = nasproc.Cont
print('CN message:')
if msgcn is None:
print(' None')
else:
for m in msgcn:
print_nasies(m(), indent=' ')
print(' ')
print('UE message:')
if msgue is None:
print(' None')
else:
for m in msgue:
print_nasies(m(), indent=' ')
print(' ')