2017-11-12 14:18:50 +00:00
|
|
|
# -*- coding: UTF-8 -*-
|
|
|
|
#/**
|
|
|
|
# * Software Name : pycrate
|
2018-02-09 21:23:26 +00:00
|
|
|
# * Version : 0.3
|
2017-11-12 14:18:50 +00:00
|
|
|
# *
|
|
|
|
# * Copyright 2017. Benoit Michau. ANSSI.
|
|
|
|
# *
|
|
|
|
# * This program is free software; you can redistribute it and/or
|
|
|
|
# * modify it under the terms of the GNU General Public License
|
|
|
|
# * as published by the Free Software Foundation; either version 2
|
|
|
|
# * of the License, or (at your option) any later version.
|
|
|
|
# *
|
|
|
|
# * This program 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 General Public License for more details.
|
|
|
|
# *
|
|
|
|
# * You should have received a copy of the GNU General Public License
|
|
|
|
# * along with this program; if not, write to the Free Software
|
|
|
|
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
# * 02110-1301, USA.
|
|
|
|
# *
|
|
|
|
# *--------------------------------------------------------
|
|
|
|
# * File Name : pycrate_mobile/NASLTE.py
|
|
|
|
# * Created : 2017-11-08
|
|
|
|
# * Authors : Benoit Michau
|
|
|
|
# *--------------------------------------------------------
|
|
|
|
#*/
|
|
|
|
|
|
|
|
from pycrate_core.utils import *
|
|
|
|
|
|
|
|
from .TS24301_EMM import EMMTypeMOClasses, EMMTypeMTClasses, \
|
|
|
|
EMMSecProtNASMessage, EMMServiceRequest
|
|
|
|
from .TS24301_ESM import ESMTypeClasses
|
|
|
|
from .TS24011_PPSMS import PPSMSCPTypeClasses
|
|
|
|
|
|
|
|
|
|
|
|
def parse_NASLTE_MO(buf, inner=True):
|
|
|
|
"""Parses a Mobile Originated LTE NAS message bytes' buffer
|
|
|
|
|
|
|
|
Args:
|
|
|
|
buf: uplink LTE NAS message bytes' buffer
|
|
|
|
inner: if True, decode NASMessage within security header if possible
|
|
|
|
decode ESMContainer within EMM message if possible
|
|
|
|
decode NASContainer within EMM NAS Transport message if possible
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
element, err: 2-tuple
|
|
|
|
element: Element instance, if err is null (no error)
|
|
|
|
element: None, if err is not null (standard LTE NAS error code)
|
|
|
|
"""
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
|
|
|
pd = ord(buf[:1])
|
|
|
|
except:
|
|
|
|
# error 111, unspecified protocol error
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
pd = buf[0]
|
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
shdr = pd>>4
|
|
|
|
pd &= 0xf
|
|
|
|
|
|
|
|
if shdr in (1, 2, 3, 4):
|
|
|
|
# EMM security protected NAS message
|
|
|
|
Msg = EMMSecProtNASMessage()
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
# error 96, invalid mandatory info
|
|
|
|
return None, 96
|
|
|
|
#
|
|
|
|
if inner and shdr in (1, 3):
|
|
|
|
# parse clear-text NAS message container
|
2018-02-09 20:58:36 +00:00
|
|
|
cont, err = parse_NASLTE_MO(Msg[3].get_val(), inner=inner)
|
2017-11-12 14:18:50 +00:00
|
|
|
if cont is not None:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg.replace(Msg[3], cont)
|
2017-11-12 14:18:50 +00:00
|
|
|
return Msg, err
|
|
|
|
else:
|
|
|
|
return Msg, 0
|
|
|
|
|
|
|
|
elif shdr == 12:
|
|
|
|
# EMM service request message
|
|
|
|
Msg = EMMServiceRequest()
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
return None, 96
|
|
|
|
return Msg, 0
|
|
|
|
|
|
|
|
else:
|
|
|
|
# sec hdr == 0 or undefined
|
|
|
|
# no security, straight LTE NAS message
|
|
|
|
#
|
|
|
|
if pd == 7:
|
|
|
|
# EMM
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = ord(buf[1:2])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = buf[1]
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg = EMMTypeMOClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
# error 97, message type non-existent or not implemented
|
|
|
|
return None, 97
|
|
|
|
elif pd == 2:
|
|
|
|
# ESM
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = ord(buf[2:3])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = buf[2]
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg = ESMTypeClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 97
|
|
|
|
else:
|
|
|
|
return None, 97
|
|
|
|
#
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
# error 96, invalid mandatory info
|
|
|
|
return None, 96
|
|
|
|
#
|
|
|
|
if inner and pd == 7:
|
2018-02-09 20:58:36 +00:00
|
|
|
if typ in (65, 66, 67, 68, 77):
|
2017-11-12 14:18:50 +00:00
|
|
|
esmc = Msg['ESMContainer']
|
|
|
|
if not esmc.get_trans():
|
|
|
|
# ESM Container present in Msg
|
|
|
|
cont, err = parse_NASLTE_MO(esmc[-1].get_val(), inner=inner)
|
|
|
|
if err:
|
|
|
|
return Msg, err
|
|
|
|
else:
|
|
|
|
esmc.replace(esmc[-1], cont)
|
|
|
|
#esmc[-2].set_valauto(cont.get_len)
|
2018-02-09 20:58:36 +00:00
|
|
|
elif typ in (98, 99):
|
2017-11-12 14:18:50 +00:00
|
|
|
# PP-SMS
|
|
|
|
nasc = Msg['NASContainer']
|
|
|
|
ppsmsb = nasc[1].get_val()
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
pd, typ = unpack('>BB', ppsmsb[:2])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return Msg, 111
|
|
|
|
pd &= 0xF
|
2018-02-09 20:58:36 +00:00
|
|
|
if pd == 9 and typ in (1, 4, 16):
|
|
|
|
cont = PPSMSCPTypeClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
try:
|
|
|
|
cont.from_bytes(ppsmsb)
|
|
|
|
except:
|
|
|
|
return Msg, 96
|
|
|
|
nasc.replace(nasc[1], cont)
|
|
|
|
#
|
|
|
|
return Msg, 0
|
|
|
|
|
|
|
|
|
|
|
|
def parse_NASLTE_MT(buf, inner=True):
|
|
|
|
"""Parses a Mobile Terminated LTE NAS message bytes' buffer
|
|
|
|
|
|
|
|
Args:
|
|
|
|
buf: downlink LTE NAS message bytes' buffer
|
|
|
|
inner: if True, decode NASMessage within security header if possible
|
|
|
|
decode ESMContainer within EMM message if possible
|
|
|
|
decode NASContainer within EMM NAS Transport message if possible
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
element, err: 2-tuple
|
|
|
|
element: Element instance, if err is null (no error)
|
|
|
|
element: None, if err is not null (standard LTE NAS error code)
|
|
|
|
"""
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
|
|
|
pd = ord(buf[0])
|
|
|
|
except:
|
|
|
|
# error 111, unspecified protocol error
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
pd = buf[0]
|
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
shdr = pd>>4
|
|
|
|
pd &= 0xf
|
|
|
|
|
|
|
|
if shdr in (1, 2, 3, 4):
|
|
|
|
# EMM security protected NAS message
|
|
|
|
Msg = EMMSecProtNASMessage()
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
# error 96, invalid mandatory info
|
|
|
|
return None, 96
|
|
|
|
#
|
|
|
|
if inner and shdr in (1, 3):
|
|
|
|
# parse clear-text NAS message container
|
2018-02-09 20:58:36 +00:00
|
|
|
cont, err = parse_NASLTE_MT(Msg[3].get_val(), inner=inner)
|
2017-11-12 14:18:50 +00:00
|
|
|
if cont is not None:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg.replace(Msg[3], cont)
|
2017-11-12 14:18:50 +00:00
|
|
|
return Msg, err
|
|
|
|
else:
|
|
|
|
return Msg, 0
|
|
|
|
|
|
|
|
elif shdr == 12:
|
|
|
|
# EMM service request message
|
|
|
|
Msg = EMMServiceRequest()
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
return None, 96
|
|
|
|
return Msg, 0
|
|
|
|
|
|
|
|
else:
|
|
|
|
# sec hdr == 0 or undefined
|
|
|
|
# no security, straight LTE NAS message
|
|
|
|
#
|
|
|
|
if pd == 7:
|
|
|
|
# EMM
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = ord(buf[1])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = buf[1]
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg = EMMTypeMTClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
# error 97, message type non-existent or not implemented
|
|
|
|
return None, 97
|
|
|
|
elif pd == 2:
|
|
|
|
# ESM
|
|
|
|
if python_version < 3:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = ord(buf[2])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
else:
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
typ = buf[2]
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 111
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
Msg = ESMTypeClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return None, 97
|
|
|
|
else:
|
|
|
|
return None, 97
|
|
|
|
#
|
|
|
|
try:
|
|
|
|
Msg.from_bytes(buf)
|
|
|
|
except:
|
|
|
|
# error 96, invalid mandatory info
|
|
|
|
return None, 96
|
|
|
|
#
|
|
|
|
if inner and pd == 7:
|
2018-02-09 20:58:36 +00:00
|
|
|
if typ in (65, 66, 67, 68, 77):
|
2017-11-12 14:18:50 +00:00
|
|
|
# ESM Container
|
|
|
|
esmc = Msg['ESMContainer']
|
|
|
|
if not esmc.get_trans():
|
|
|
|
# ESM Container present in Msg
|
|
|
|
cont, err = parse_NASLTE_MO(esmc[-1].get_val(), inner=inner)
|
|
|
|
if err:
|
|
|
|
return Msg, err
|
|
|
|
else:
|
|
|
|
esmc.replace(esmc[-1], cont)
|
|
|
|
#esmc[-2].set_valauto(cont.get_len)
|
2018-02-09 20:58:36 +00:00
|
|
|
elif typ in (98, 99):
|
2017-11-12 14:18:50 +00:00
|
|
|
# PP-SMS
|
|
|
|
nasc = Msg['NASContainer']
|
|
|
|
ppsmsb = nasc[1].get_val()
|
|
|
|
try:
|
2018-02-09 20:58:36 +00:00
|
|
|
pd, typ = unpack('>BB', ppsmsb[:2])
|
2017-11-12 14:18:50 +00:00
|
|
|
except:
|
|
|
|
return Msg, 111
|
|
|
|
pd &= 0xF
|
2018-02-09 20:58:36 +00:00
|
|
|
if pd == 9 and typ in (1, 4, 16):
|
|
|
|
cont = PPSMSCPTypeClasses[typ]()
|
2017-11-12 14:18:50 +00:00
|
|
|
try:
|
|
|
|
cont.from_bytes(ppsmsb)
|
|
|
|
except:
|
|
|
|
return Msg, 96
|
|
|
|
nasc.replace(nasc[1], cont)
|
|
|
|
#
|
|
|
|
return Msg, 0
|
|
|
|
|