open5gs/lib/nas/eps/support/nas-message.py

1040 lines
40 KiB
Python
Raw Normal View History

# The MIT License
2023-03-04 14:47:40 +00:00
# Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
2019-04-27 14:54:30 +00:00
# This file is part of Open5GS.
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2019-04-27 14:54:30 +00:00
from docx import Document
import re, os, sys, string
import datetime
import getopt
import getpass
version = "0.1.0"
msg_list = {}
type_list = {}
verbosity = 0
filename = ""
outdir = './'
cachedir = './cache/'
2017-03-31 00:06:07 +00:00
currentdir = './'
FAIL = '\033[91m'
INFO = '\033[93m'
ENDC = '\033[0m'
def d_print(string):
if verbosity > 0:
sys.stdout.write(string)
def d_info(string):
sys.stdout.write(INFO + string + ENDC + "\n")
def d_error(string):
sys.stderr.write(FAIL + string + ENDC + "\n")
sys.exit(0)
def write_file(f, string):
f.write(string)
d_print(string)
def output_header_to_file(f):
now = datetime.datetime.now()
f.write("""/*
* The MIT License
*
2023-03-04 14:47:40 +00:00
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
2019-04-27 14:54:30 +00:00
*
* This file is part of Open5GS.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
2019-04-27 14:54:30 +00:00
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
2019-04-27 14:54:30 +00:00
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
""")
f.write("/*******************************************************************************\n")
2019-06-11 09:28:25 +00:00
f.write(" * This file had been created by nas-message.py script v%s\n" % (version))
f.write(" * Please do not modify this file but regenerate it via script.\n")
f.write(" * Created on: %s by %s\n * from %s\n" % (str(now), getpass.getuser(), filename))
f.write(" ******************************************************************************/\n\n")
def usage():
2021-06-21 13:36:38 +00:00
print("Python generating NAS Message encoder/decoder v%s" % (version))
print("Usage: python nas-message.py [options]")
print("Available options:")
print("-d Enable script debug")
print("-f [file] Input file to parse")
print("-o [dir] Output files to given directory")
print("-c [dir] Cache files to given directory")
print("-h Print this help and return")
def v_upper(v):
2017-04-26 00:19:13 +00:00
return re.sub('_TO_UE', '', re.sub('_FROM_UE', '', re.sub('3GPP', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper())))
def v_lower(v):
return re.sub('3gpp', '', re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower())
def get_cells(cells):
2021-06-21 13:36:38 +00:00
iei = cells[0].text
2023-03-04 14:47:40 +00:00
value = cells[1].text.encode('ascii', 'ignore').decode('utf-8')
value = re.sub("\s*$", "", re.sub("\s*\n*\s*\([^\)]*\)*", "", re.sub("\"|'s", "", value)))
2021-06-21 13:36:38 +00:00
type = re.sub("^NAS ", "", re.sub("'s", "", re.sub('\s*\n\s*[a-zA-Z0-9.]*', '', cells[2].text)))
2020-05-23 02:24:48 +00:00
if type == "message container":
type = "EPS message container"
2021-06-21 13:36:38 +00:00
reference = re.sub('[a-zA-Z0-9\'\-\s]*\n\s*', '', cells[2].text)
presence = cells[3].text
format = cells[4].text
length = cells[5].text
return { "iei" : iei, "value" : value, "type" : type, "reference" : reference, "presence" : presence, "format" : format, "length" : length }
def write_cells_to_file(name, cells):
write_file(f, name + ".append({ \"iei\" : \"" + cells["iei"] + \
"\", \"value\" : \"" + cells["value"] + \
"\", \"type\" : \"" + cells["type"] + \
"\", \"reference\" : \"" + cells["reference"] + \
"\", \"presence\" : \"" + cells["presence"] + \
"\", \"format\" : \"" + cells["format"] + \
"\", \"length\" : \"" + cells["length"] + "\"})\n")
try:
opts, args = getopt.getopt(sys.argv[1:], "df:ho:c:", ["debug", "file", "help", "output", "cache"])
except getopt.GetoptError as err:
# print help information and exit:
usage()
sys.exit(2)
for o, a in opts:
if o in ("-d", "--debug"):
verbosity = 1
if o in ("-f", "--file"):
filename = a
if o in ("-o", "--output"):
outdir = a
if outdir.rfind('/') != len(outdir):
outdir += '/'
if o in ("-c", "--cache"):
cache = a
if cachedir.rfind('/') != len(cachedir):
cachedir += '/'
if o in ("-h", "--help"):
usage()
sys.exit(2)
# Message Type List
msg_list["ATTACH REQUEST"] = { "type" : "65" }
msg_list["ATTACH ACCEPT"]= { "type" : "66" }
msg_list["ATTACH COMPLETE"] = { "type" : "67" }
msg_list["ATTACH REJECT"] = { "type" : "68" }
2017-04-25 09:28:46 +00:00
msg_list["DETACH REQUEST FROM UE"] = { "type" : "69.1" }
msg_list["DETACH REQUEST TO UE"] = { "type" : "69.2" }
msg_list["DETACH ACCEPT"] = { "type" : "70" }
msg_list["TRACKING AREA UPDATE REQUEST"] = { "type" : "72" }
msg_list["TRACKING AREA UPDATE ACCEPT"] = { "type" : "73" }
msg_list["TRACKING AREA UPDATE COMPLETE"] = { "type" : "74" }
msg_list["TRACKING AREA UPDATE REJECT"] = { "type" : "75" }
msg_list["EXTENDED SERVICE REQUEST"] = { "type" : "76" }
2017-04-26 00:49:37 +00:00
msg_list["SERVICE REQUEST"] = { "type" : "77.1" }
msg_list["SERVICE REJECT"] = { "type" : "78" }
msg_list["GUTI REALLOCATION COMMAND"] = { "type" : "80" }
msg_list["GUTI REALLOCATION COMPLETE"] = { "type" : "81" }
msg_list["AUTHENTICATION REQUEST"] = { "type" : "82" }
msg_list["AUTHENTICATION RESPONSE"] = { "type" : "83" }
msg_list["AUTHENTICATION REJECT"] = { "type" : "84" }
msg_list["AUTHENTICATION FAILURE"] = { "type" : "92" }
msg_list["IDENTITY REQUEST"] = { "type" : "85" }
msg_list["IDENTITY RESPONSE"] = { "type" : "86" }
msg_list["SECURITY MODE COMMAND"] = { "type" : "93" }
msg_list["SECURITY MODE COMPLETE"] = { "type" : "94" }
msg_list["SECURITY MODE REJECT"] = { "type" : "95" }
msg_list["EMM STATUS"] = { "type" : "96" }
msg_list["EMM INFORMATION"] = { "type" : "97" }
msg_list["DOWNLINK NAS TRANSPORT"] = { "type" : "98" }
msg_list["UPLINK NAS TRANSPORT"] = { "type" : "99" }
msg_list["CS SERVICE NOTIFICATION"] = { "type" : "100" }
msg_list["DOWNLINK GENERIC NAS TRANSPORT"] = { "type" : "104" }
msg_list["UPLINK GENERIC NAS TRANSPORT"] = { "type" : "101" }
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST"] = { "type" : "193" }
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT ACCEPT"] = { "type" : "194" }
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT REJECT"] = { "type" : "195" }
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT REQUEST"] = { "type" : "197" }
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT ACCEPT"] = { "type" : "198" }
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT REJECT"] = { "type" : "199" }
msg_list["MODIFY EPS BEARER CONTEXT REQUEST"] = { "type" : "201" }
msg_list["MODIFY EPS BEARER CONTEXT ACCEPT"] = { "type" : "202" }
msg_list["MODIFY EPS BEARER CONTEXT REJECT"] = { "type" : "203" }
msg_list["DEACTIVATE EPS BEARER CONTEXT REQUEST"] = { "type" : "205" }
msg_list["DEACTIVATE EPS BEARER CONTEXT ACCEPT"] = { "type" : "206" }
msg_list["PDN CONNECTIVITY REQUEST"] = { "type" : "208" }
msg_list["PDN CONNECTIVITY REJECT"] = { "type" : "209" }
msg_list["PDN DISCONNECT REQUEST"] = { "type" : "210" }
msg_list["PDN DISCONNECT REJECT"] = { "type" : "211" }
msg_list["BEARER RESOURCE ALLOCATION REQUEST"] = { "type" : "212" }
msg_list["BEARER RESOURCE ALLOCATION REJECT"] = { "type" : "213" }
msg_list["BEARER RESOURCE MODIFICATION REQUEST"] = { "type" : "214" }
msg_list["BEARER RESOURCE MODIFICATION REJECT"] = { "type" : "215" }
msg_list["ESM INFORMATION REQUEST"] = { "type" : "217" }
msg_list["ESM INFORMATION RESPONSE"] = { "type" : "218" }
msg_list["ESM STATUS"] = { "type" : "232" }
# Table number for Message List
2017-04-12 14:02:06 +00:00
msg_list["ATTACH ACCEPT"]["table"] = 0
msg_list["ATTACH COMPLETE"]["table"] = 1
msg_list["ATTACH REJECT"]["table"] = 2
msg_list["ATTACH REQUEST"]["table"] = 3
msg_list["AUTHENTICATION FAILURE"]["table"] = 4
msg_list["AUTHENTICATION REJECT"]["table"] = 5
msg_list["AUTHENTICATION REQUEST"]["table"] = 6
msg_list["AUTHENTICATION RESPONSE"]["table"] = 7
2017-04-26 06:14:56 +00:00
msg_list["CS SERVICE NOTIFICATION"]["table"] = 8
msg_list["DETACH ACCEPT"]["table"] = 9
2017-04-25 09:28:46 +00:00
msg_list["DETACH REQUEST FROM UE"]["table"] = 11
msg_list["DETACH REQUEST TO UE"]["table"] = 12
2017-04-26 06:14:56 +00:00
msg_list["DOWNLINK NAS TRANSPORT"]["table"] = 13
2017-04-13 15:17:56 +00:00
msg_list["EMM INFORMATION"]["table"] = 14
2017-04-14 09:09:39 +00:00
msg_list["EMM STATUS"]["table"] = 15
msg_list["EXTENDED SERVICE REQUEST"]["table"] = 16
2017-04-26 06:14:56 +00:00
msg_list["GUTI REALLOCATION COMMAND"]["table"] = 17
msg_list["GUTI REALLOCATION COMPLETE"]["table"] = 18
2017-04-12 14:02:06 +00:00
msg_list["IDENTITY REQUEST"]["table"] = 19
msg_list["IDENTITY RESPONSE"]["table"] = 20
msg_list["SECURITY MODE COMMAND"]["table"] = 21
msg_list["SECURITY MODE COMPLETE"]["table"] = 22
msg_list["SECURITY MODE REJECT"]["table"] = 23
msg_list["SERVICE REJECT"]["table"] = 25
msg_list["SERVICE REQUEST"]["table"] = 26
msg_list["TRACKING AREA UPDATE ACCEPT"]["table"] = 27
msg_list["TRACKING AREA UPDATE COMPLETE"]["table"] = 28
msg_list["TRACKING AREA UPDATE REJECT"]["table"] = 29
msg_list["TRACKING AREA UPDATE REQUEST"]["table"] = 30
2017-04-26 06:14:56 +00:00
msg_list["UPLINK NAS TRANSPORT"]["table"] = 31
msg_list["DOWNLINK GENERIC NAS TRANSPORT"]["table"] = 32
msg_list["UPLINK GENERIC NAS TRANSPORT"]["table"] = 33
2017-04-12 14:02:06 +00:00
2017-04-26 06:40:46 +00:00
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT ACCEPT"]["table"] = 36
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT REJECT"]["table"] = 37
msg_list["ACTIVATE DEDICATED EPS BEARER CONTEXT REQUEST"]["table"] = 38
2017-04-13 01:06:58 +00:00
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT ACCEPT"]["table"] = 39
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT REJECT"]["table"] = 40
msg_list["ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST"]["table"] = 41
2017-04-26 06:45:46 +00:00
msg_list["BEARER RESOURCE ALLOCATION REJECT"]["table"] = 42
msg_list["BEARER RESOURCE ALLOCATION REQUEST"]["table"] = 43
msg_list["BEARER RESOURCE MODIFICATION REJECT"]["table"] = 44
msg_list["BEARER RESOURCE MODIFICATION REQUEST"]["table"] = 45
2017-04-26 07:07:27 +00:00
msg_list["DEACTIVATE EPS BEARER CONTEXT ACCEPT"]["table"] = 46
msg_list["DEACTIVATE EPS BEARER CONTEXT REQUEST"]["table"] = 47
2017-04-12 14:02:06 +00:00
msg_list["ESM INFORMATION REQUEST"]["table"] = 49
msg_list["ESM INFORMATION RESPONSE"]["table"] = 50
2017-04-26 07:07:27 +00:00
msg_list["ESM STATUS"]["table"] = 51
msg_list["MODIFY EPS BEARER CONTEXT ACCEPT"]["table"] = 52
msg_list["MODIFY EPS BEARER CONTEXT REJECT"]["table"] = 53
msg_list["MODIFY EPS BEARER CONTEXT REQUEST"]["table"] = 54
2017-04-12 14:02:06 +00:00
msg_list["PDN CONNECTIVITY REJECT"]["table"] = 56
msg_list["PDN CONNECTIVITY REQUEST"]["table"] = 57
msg_list["PDN DISCONNECT REJECT"]["table"] = 58
msg_list["PDN DISCONNECT REQUEST"]["table"] = 59
for key in msg_list.keys():
if "table" not in msg_list[key].keys():
continue;
d_info("[" + key + "]")
2019-07-06 13:52:09 +00:00
cachefile = cachedir + "nas-msg-" + msg_list[key]["type"] + ".py"
if os.path.isfile(cachefile) and os.access(cachefile, os.R_OK):
2021-06-21 13:36:38 +00:00
exec(open(cachefile).read())
print("Read from " + cachefile)
else:
document = Document(filename)
f = open(cachefile, 'w')
ies = []
write_file(f, "ies = []\n")
table = document.tables[msg_list[key]["table"]]
2017-04-07 10:45:43 +00:00
start_row = 0
for start_row, row in enumerate(table.rows):
cells = get_cells(row.cells);
if cells["type"].find('Message type') != -1:
break
2017-04-26 00:33:26 +00:00
if cells["type"].find('KSI and sequence number') != -1:
start_row -= 1
break
2017-04-07 10:45:43 +00:00
assert start_row <= 4, "Can't find message type"
half_length = True;
2017-04-07 10:45:43 +00:00
for row in table.rows[start_row+1:]:
cells = get_cells(row.cells)
if cells is None:
continue
if cells["length"] == "1/2":
if half_length is True:
half_length = False;
else:
half_length = True;
continue;
ies.append(cells)
write_cells_to_file("ies", cells)
msg_list[key]["ies"] = ies
write_file(f, "msg_list[key][\"ies\"] = ies\n")
f.close()
2017-03-20 14:43:52 +00:00
tmp = [(k, v["type"]) for k, v in msg_list.items()]
2017-04-25 09:28:46 +00:00
sorted_msg_list = sorted(tmp, key=lambda tup: float(tup[1]))
2017-03-20 14:43:52 +00:00
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
for ie in msg_list[k]["ies"]:
2017-03-21 01:37:41 +00:00
key = ie["type"]
if key in type_list.keys() and (type_list[key]["presence"] != ie["presence"] or type_list[key]["format"] != ie["format"] or type_list[key]["length"] != ie["length"]):
d_print("KEY type different : %s\n" % key)
d_print("%s.%s %s %s %s\n" % (v_lower(type_list[key]["message"]), type_list[key]["value"], type_list[key]["presence"], type_list[key]["format"], type_list[key]["length"]))
d_print("%s.%s %s %s %s\n\n" % (v_lower(k), ie["value"], ie["presence"], ie["format"], ie["length"]))
continue
type_list[key] = { "reference" : ie["reference"], "presence" : ie["presence"], "format" : ie["format"], "length" : ie["length"], "message" : k, "value" : ie["value"] }
2017-03-20 14:43:52 +00:00
d_info("[Type List]")
2019-06-11 09:28:25 +00:00
typefile = currentdir + "type-list.py"
2017-03-31 00:06:07 +00:00
if os.path.isfile(typefile) and os.access(typefile, os.R_OK):
2021-06-21 13:36:38 +00:00
exec(open(typefile).read())
print("Read from " + typefile)
2017-03-20 14:43:52 +00:00
tmp = [(k, v["reference"]) for k, v in type_list.items()]
sorted_type_list = sorted(tmp, key=lambda tup: tup[1])
2019-09-13 12:07:47 +00:00
f = open(outdir + 'ies.h', 'w')
2017-03-21 04:50:40 +00:00
output_header_to_file(f)
2019-09-13 12:07:47 +00:00
f.write("""#if !defined(OGS_NAS_INSIDE) && !defined(OGS_NAS_COMPILATION)
#error "This header cannot be included directly."
#endif
2017-03-21 04:50:40 +00:00
2020-05-22 01:24:21 +00:00
#ifndef OGS_NAS_EPS_IES_H
#define OGS_NAS_EPS_IES_H
2017-03-21 04:50:40 +00:00
#ifdef __cplusplus
extern "C" {
2019-06-11 09:28:25 +00:00
#endif
2017-03-21 04:50:40 +00:00
2020-05-23 02:24:48 +00:00
int ogs_nas_eps_encode_optional_type(ogs_pkbuf_t *pkbuf, uint8_t type);
2017-03-21 04:50:40 +00:00
""")
for (k, v) in sorted_type_list:
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf);\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-21 04:50:40 +00:00
f.write("\n")
for (k, v) in sorted_type_list:
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s);\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-21 04:50:40 +00:00
f.write("\n")
f.write("""#ifdef __cplusplus
}
2019-06-11 09:28:25 +00:00
#endif
2017-03-21 04:50:40 +00:00
2020-05-22 01:24:21 +00:00
#endif /* OGS_NAS_EPS_IES_H */
2017-03-21 04:50:40 +00:00
""")
f.close()
2019-09-13 12:07:47 +00:00
f = open(outdir + 'ies.c', 'w')
2017-03-20 14:43:52 +00:00
output_header_to_file(f)
2020-05-22 01:24:21 +00:00
f.write("""#include "ogs-nas-eps.h"
2017-03-20 14:43:52 +00:00
2020-05-23 02:24:48 +00:00
int ogs_nas_eps_encode_optional_type(ogs_pkbuf_t *pkbuf, uint8_t type)
2017-03-20 14:43:52 +00:00
{
int size = sizeof(uint8_t);
2017-03-20 14:43:52 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
memcpy(pkbuf->data - size, &type, size);
2017-03-20 14:43:52 +00:00
return size;
}
""")
for (k, v) in sorted_type_list:
# d_print("%s = %s\n" % (k, type_list[k]))
f.write("/* %s %s\n" % (type_list[k]["reference"], k))
f.write(" * %s %s %s */\n" % (type_list[k]["presence"], type_list[k]["format"], type_list[k]["length"]))
2020-05-22 01:24:21 +00:00
if (type_list[k]["format"] == "TV" or type_list[k]["format"] == "T") and type_list[k]["length"] == "1":
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = sizeof(ogs_nas_%s_t);\n\n" % v_lower(k))
f.write(" if (ogs_pkbuf_pull(pkbuf, size) == NULL) {\n")
f.write(" ogs_error(\"ogs_pkbuf_pull() failed [size:%d]\", (int)size);\n")
f.write(" return -1;\n")
f.write(" }\n\n")
2020-08-22 03:33:45 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
2020-08-22 03:33:45 +00:00
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
f.write(" return size;\n")
2017-03-20 14:43:52 +00:00
f.write("}\n\n")
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = sizeof(ogs_nas_%s_t);\n\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
f.write(" memcpy(pkbuf->data - size, %s, size);\n\n" % v_lower(k))
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n")
elif type_list[k]["format"] == "TV" or type_list[k]["format"] == "V":
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
if type_list[k]["length"] == "4":
f.write(" int size = 3;\n\n")
2017-03-20 14:43:52 +00:00
else:
f.write(" int size = sizeof(ogs_nas_%s_t);\n\n" % v_lower(k))
f.write(" if (ogs_pkbuf_pull(pkbuf, size) == NULL) {\n")
f.write(" ogs_error(\"ogs_pkbuf_pull() failed [size:%d]\", (int)size);\n")
f.write(" return -1;\n")
f.write(" }\n\n")
2019-04-27 14:54:30 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % v_lower(k))
2017-03-20 14:43:52 +00:00
if "decode" in type_list[k]:
f.write("%s" % type_list[k]["decode"])
2019-04-27 14:54:30 +00:00
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n")
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
if type_list[k]["length"] == "4":
f.write(" int size = 3;\n")
2017-03-20 14:43:52 +00:00
else:
f.write(" int size = sizeof(ogs_nas_%s_t);\n" % v_lower(k))
2019-09-13 12:07:47 +00:00
f.write(" ogs_nas_%s_t target;\n\n" % v_lower(k))
2017-03-20 14:43:52 +00:00
f.write(" memcpy(&target, %s, size);\n" % v_lower(k))
if "encode" in type_list[k]:
f.write("%s" % type_list[k]["encode"])
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
f.write(" memcpy(pkbuf->data - size, &target, size);\n\n")
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n")
2017-04-07 14:36:08 +00:00
elif type_list[k]["format"] == "LV-E" or type_list[k]["format"] == "TLV-E":
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = 0;\n")
f.write(" ogs_nas_%s_t *source = (ogs_nas_%s_t *)pkbuf->data;\n\n" % (v_lower(k), v_lower(k)))
2020-04-26 19:36:05 +00:00
f.write(" %s->length = be16toh(source->length);\n" % v_lower(k))
f.write(" size = %s->length + sizeof(%s->length);\n\n" % (v_lower(k), v_lower(k)))
f.write(" if (ogs_pkbuf_pull(pkbuf, size) == NULL) {\n")
f.write(" ogs_error(\"ogs_pkbuf_pull() failed [size:%d]\", (int)size);\n")
f.write(" return -1;\n")
f.write(" }\n\n")
2019-04-27 14:54:30 +00:00
f.write(" %s->buffer = pkbuf->data - size + sizeof(%s->length);\n\n" % (v_lower(k), v_lower(k)))
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, (void*)%s->buffer, %s->length);\n\n" % (v_lower(k), v_lower(k)));
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n")
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = 0;\n")
f.write(" int target;\n\n")
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(%s);\n" % v_lower(k))
f.write(" ogs_assert(%s->buffer);\n\n" % v_lower(k))
f.write(" size = sizeof(%s->length);\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
2020-04-26 19:36:05 +00:00
f.write(" target = htobe16(%s->length);\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" memcpy(pkbuf->data - size, &target, size);\n\n")
f.write(" size = %s->length;\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
f.write(" memcpy(pkbuf->data - size, %s->buffer, size);\n\n" % v_lower(k))
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
f.write(" return %s->length + sizeof(%s->length);\n" % (v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("}\n\n");
else:
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = 0;\n")
f.write(" ogs_nas_%s_t *source = (ogs_nas_%s_t *)pkbuf->data;\n\n" % (v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write(" %s->length = source->length;\n" % v_lower(k))
f.write(" size = %s->length + sizeof(%s->length);\n\n" % (v_lower(k), v_lower(k)))
f.write(" if (ogs_pkbuf_pull(pkbuf, size) == NULL) {\n")
f.write(" ogs_error(\"ogs_pkbuf_pull() failed [size:%d]\", (int)size);\n")
f.write(" return -1;\n")
f.write(" }\n\n")
f.write(" if (sizeof(*%s) < size) return -1;\n" % v_lower(k))
2019-04-27 14:54:30 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % v_lower(k))
2017-03-20 14:43:52 +00:00
if "decode" in type_list[k]:
f.write("%s" % type_list[k]["decode"])
2019-04-27 14:54:30 +00:00
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n")
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = %s->length + sizeof(%s->length);\n" % (v_lower(k), v_lower(k)))
2019-09-13 12:07:47 +00:00
f.write(" ogs_nas_%s_t target;\n\n" % v_lower(k))
f.write(" memcpy(&target, %s, sizeof(ogs_nas_%s_t));\n" % (v_lower(k), v_lower(k)))
2017-03-20 14:43:52 +00:00
if "encode" in type_list[k]:
f.write("%s" % type_list[k]["encode"])
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
f.write(" memcpy(pkbuf->data - size, &target, size);\n\n")
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, pkbuf->data - size, size);\n\n");
2017-03-20 14:43:52 +00:00
f.write(" return size;\n")
f.write("}\n\n");
f.close()
2019-09-13 12:07:47 +00:00
f = open(outdir + 'message.h', 'w')
output_header_to_file(f)
2019-09-13 12:07:47 +00:00
f.write("""#if !defined(OGS_NAS_INSIDE) && !defined(OGS_NAS_COMPILATION)
#error "This header cannot be included directly."
#endif
2020-05-22 01:24:21 +00:00
#ifndef OGS_NAS_EPS_MESSAGE_H
#define OGS_NAS_EPS_MESSAGE_H
#ifdef __cplusplus
extern "C" {
2019-06-11 09:28:25 +00:00
#endif
2019-09-13 12:07:47 +00:00
#define OGS_NAS_PROTOCOL_DISCRIMINATOR_ESM 0x2
#define OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM 0x7
2019-09-13 12:07:47 +00:00
#define OGS_NAS_EPS_BEARER_IDENTITY_UNASSIGNED 0
2017-04-09 05:26:19 +00:00
2019-09-13 12:07:47 +00:00
typedef struct ogs_nas_emm_header_s {
2019-04-27 14:54:30 +00:00
ED2(uint8_t security_header_type:4;,
uint8_t protocol_discriminator:4;)
uint8_t message_type;
2019-09-13 12:07:47 +00:00
} __attribute__ ((packed)) ogs_nas_emm_header_t;
2017-04-07 13:23:38 +00:00
2019-09-13 12:07:47 +00:00
typedef struct ogs_nas_esm_header_s {
2019-04-27 14:54:30 +00:00
ED2(uint8_t eps_bearer_identity:4;,
uint8_t protocol_discriminator:4;)
uint8_t procedure_transaction_identity;
uint8_t message_type;
2019-09-13 12:07:47 +00:00
} __attribute__ ((packed)) ogs_nas_esm_header_t;
2020-05-23 02:24:48 +00:00
typedef struct ogs_nas_eps_security_header_s {
2019-04-27 14:54:30 +00:00
ED2(uint8_t security_header_type:4;,
uint8_t protocol_discriminator:4;)
uint32_t message_authentication_code;
uint8_t sequence_number;
2020-05-23 02:24:48 +00:00
} __attribute__ ((packed)) ogs_nas_eps_security_header_t;
""")
for (k, v) in sorted_msg_list:
2017-04-26 00:49:37 +00:00
if k.find("TO UE") == -1 and k != "SERVICE REQUEST":
2020-05-23 02:24:48 +00:00
f.write("#define OGS_NAS_EPS_" + v_upper(k) + " " + v.split('.')[0] + "\n")
f.write("\n")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-03-21 03:04:15 +00:00
if len(msg_list[k]["ies"]) == 0:
continue;
2017-03-21 03:04:15 +00:00
f.write("\n/*******************************************************\n")
f.write(" * %s\n" % k)
2017-03-21 03:04:15 +00:00
f.write(" ******************************************************/")
2023-03-04 14:47:40 +00:00
for i, ie in enumerate([ies for ies in msg_list[k]["ies"] if ies["presence"] != "M"]):
f.write("\n#define OGS_NAS_EPS_%s_%s_PRESENT ((uint64_t)1<<%d)" % (v_upper(k), v_upper(ie["value"]), i))
2023-03-04 14:47:40 +00:00
for i, ie in enumerate([ies for ies in msg_list[k]["ies"] if ies["presence"] != "M"]):
2020-05-23 02:24:48 +00:00
f.write("\n#define OGS_NAS_EPS_%s_%s_TYPE 0x%s" % (v_upper(k), v_upper(ie["value"]), re.sub('-', '0', ie["iei"])))
2017-03-21 03:04:15 +00:00
2020-05-23 02:24:48 +00:00
f.write("\n\ntypedef struct ogs_nas_eps_%s_s {\n" % v_lower(k))
2017-03-21 03:04:15 +00:00
mandatory_fields = False;
optional_fields = False;
for ie in msg_list[k]["ies"]:
2017-03-21 03:04:15 +00:00
if ie["presence"] == "M" and mandatory_fields is False:
f.write(" /* Mandatory fields */\n")
mandatory_fields = True;
2023-03-04 14:47:40 +00:00
if ie["presence"] != "M" and optional_fields is False:
f.write("\n /* Optional fields */\n")
2023-03-04 14:47:40 +00:00
f.write(" uint64_t presencemask;\n");
optional_fields = True;
2019-09-13 12:07:47 +00:00
f.write(" ogs_nas_" + v_lower(ie["type"]) + "_t " + \
v_lower(ie["value"]) + ";\n")
2020-05-23 02:24:48 +00:00
f.write("} ogs_nas_eps_%s_t;\n\n" % v_lower(k))
f.write("\n")
2019-09-13 12:07:47 +00:00
f.write("""typedef struct ogs_nas_emm_message_s {
ogs_nas_emm_header_t h;
union {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-03-21 03:04:15 +00:00
if len(msg_list[k]["ies"]) == 0:
continue;
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) < 192:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t %s;\n" % (v_lower(k), v_lower(k)))
2017-04-07 13:23:38 +00:00
f.write(""" };
2019-09-13 12:07:47 +00:00
} ogs_nas_emm_message_t;
2017-03-21 03:04:15 +00:00
2019-09-13 12:07:47 +00:00
typedef struct ogs_nas_esm_message_s {
ogs_nas_esm_header_t h;
2017-04-07 13:23:38 +00:00
union {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
if len(msg_list[k]["ies"]) == 0:
continue;
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) >= 192:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t %s;\n" % (v_lower(k), v_lower(k)))
f.write(""" };
2019-09-13 12:07:47 +00:00
} ogs_nas_esm_message_t;
2017-04-07 13:23:38 +00:00
2020-05-23 02:24:48 +00:00
typedef struct ogs_nas_eps_message_s {
ogs_nas_eps_security_header_t h;
2017-04-07 13:23:38 +00:00
union {
2019-09-13 12:07:47 +00:00
ogs_nas_emm_message_t emm;
ogs_nas_esm_message_t esm;
2017-04-07 13:23:38 +00:00
};
2020-05-23 02:24:48 +00:00
} ogs_nas_eps_message_t;
2020-05-23 02:24:48 +00:00
ogs_pkbuf_t *ogs_nas_emm_encode(ogs_nas_eps_message_t *message);
ogs_pkbuf_t *ogs_nas_esm_encode(ogs_nas_eps_message_t *message);
int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf);
int ogs_nas_esm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf);
ogs_pkbuf_t *ogs_nas_eps_plain_encode(ogs_nas_eps_message_t *message);
#ifdef __cplusplus
}
2019-06-11 09:28:25 +00:00
#endif
2020-05-22 01:24:21 +00:00
#endif /* OGS_NAS_EPS_MESSAGE_H */
""")
2017-03-21 04:50:40 +00:00
f.close()
2017-03-21 04:50:40 +00:00
2019-09-13 12:07:47 +00:00
f = open(outdir + 'decoder.c', 'w')
output_header_to_file(f)
2020-05-22 01:24:21 +00:00
f.write("""#include "ogs-nas-eps.h"
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue
if len(msg_list[k]["ies"]) == 0:
continue
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf);\n" % v_lower(k))
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
2017-03-21 03:04:15 +00:00
continue
if len(msg_list[k]["ies"]) == 0:
continue
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_decode_%s(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf)\n{\n" % v_lower(k))
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) < 192:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t *%s = &message->emm.%s;\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-04-07 13:23:38 +00:00
else:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t *%s = &message->esm.%s;\n" % (v_lower(k), v_lower(k), v_lower(k)))
2019-04-27 14:54:30 +00:00
f.write(" int decoded = 0;\n")
f.write(" int size = 0;\n\n")
f.write(" ogs_trace(\"[NAS] Decode %s\\n\");\n\n" % v_upper(k))
for ie in [ies for ies in msg_list[k]["ies"] if ies["presence"] == "M"]:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_decode_%s(&%s->%s, pkbuf);\n" % (v_lower(ie["type"]), v_lower(k), v_lower(ie["value"])))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_eps_decode_%s() failed\");\n" % v_lower(ie["type"]))
f.write(" return size;\n")
f.write(" }\n\n")
f.write(" decoded += size;\n\n")
optional_fields = False;
2023-03-04 14:47:40 +00:00
for ie in [ies for ies in msg_list[k]["ies"] if ies["presence"] != "M"]:
if optional_fields is False:
2020-05-22 01:24:21 +00:00
f.write(""" while (pkbuf->len > 0) {
2019-04-27 14:54:30 +00:00
uint8_t *buffer = pkbuf->data;
uint8_t type = (*buffer) >= 0x80 ? ((*buffer) & 0xf0) : (*buffer);
2019-04-27 14:54:30 +00:00
size = sizeof(uint8_t);
if (ogs_pkbuf_pull(pkbuf, size) == NULL) {
ogs_error("ogs_pkbuf_pull() failed [size:%d]", (int)size);
return OGS_ERROR;
}
decoded += size;
2020-05-22 01:24:21 +00:00
switch (type) {
""")
optional_fields = True;
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_EPS_%s_%s_TYPE:\n" % (v_upper(k), v_upper(ie["value"])))
2020-08-22 03:33:45 +00:00
if (ie["format"] == "TV" or ie["format"] == "T") and ie["length"] == "1":
f.write(" decoded--;\n")
f.write(" ogs_assert(ogs_pkbuf_push(pkbuf, 1));\n")
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_decode_%s(&%s->%s, pkbuf);\n" % (v_lower(ie["type"]), v_lower(k), v_lower(ie["value"])))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_eps_decode_%s() failed\");\n" % v_lower(ie["type"]))
f.write(" return size;\n")
f.write(" }\n\n")
2020-05-23 02:24:48 +00:00
f.write(" %s->presencemask |= OGS_NAS_EPS_%s_%s_PRESENT;\n" % (v_lower(k), v_upper(k), v_upper(ie["value"])))
2020-05-22 01:24:21 +00:00
f.write(" decoded += size;\n")
f.write(" break;\n")
2023-03-04 14:47:40 +00:00
if [ies for ies in msg_list[k]["ies"] if ies["presence"] != "M"]:
2020-05-22 01:24:21 +00:00
f.write(""" default:
ogs_warn("Unknown type(0x%x) or not implemented\\n", type);
break;
}
}
2017-03-21 03:04:15 +00:00
""")
f.write(""" return decoded;
}
2017-03-21 03:04:15 +00:00
""")
2020-05-23 02:24:48 +00:00
f.write("""int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf)
{
int size = 0;
int decoded = 0;
2019-04-27 14:54:30 +00:00
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
2019-09-13 12:07:47 +00:00
size = sizeof(ogs_nas_emm_header_t);
if (ogs_pkbuf_pull(pkbuf, size) == NULL) {
ogs_error("ogs_pkbuf_pull() failed [size:%d]", (int)size);
return OGS_ERROR;
}
[SEC] Several vulnerabilities have been resolved. 1. Reachable assertion in ogs_nas_5gmm_decode Location: lib/nas/5gs/decoder.c:4445 ```c int ogs_nas_5gmm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` When a NAS payload is received over `src/amf/context.c:1675`NGAP that has no data, the ogs_assert(pkbuf->len) assertion will be triggered. 2.Reachable assertion in ogs_nas_emm_decode ``` int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` Nearly identical to (1), but for LTE. 3. Reachable assertion in nas_eps_send_emm_to_esm ``` int nas_eps_send_emm_to_esm(mme_ue_t *mme_ue, ogs_nas_esm_message_container_t *esm_message_container) { int rv; ogs_pkbuf_t *esmbuf = NULL; if (!mme_ue_cycle(mme_ue)) { ogs_error("UE(mme-ue) context has already been removed"); return OGS_NOTFOUND; } ogs_assert(esm_message_container); ogs_assert(esm_message_container->length); ``` The ESM message payload may be 0-length, as the length is determined by a field in the NAS payload (which can be chosen arbitrarily by an attacker). This leads to the length assertion above being triggered. 5. Reachable assertion and incorrect hash calculation in ogs_kdf_hash_mme ``` void ogs_kdf_hash_mme(const uint8_t *message, uint8_t message_len, uint8_t *hash_mme) { uint8_t key[32]; uint8_t output[OGS_SHA256_DIGEST_SIZE]; ogs_assert(message); ogs_assert(message_len); ogs_assert(hash_mme); memset(key, 0, 32); ogs_hmac_sha256(key, 32, message, message_len, output, OGS_SHA256_DIGEST_SIZE); memcpy(hash_mme, output+24, OGS_HASH_MME_LEN); } ``` When handling NAS attach requests or TAU requests, the ogs_kdf_hash_mme function is passed the NAS payload. However, the length field is represented as an unsigned 8-bit integer, which the passed length of the packet may overflow. This leads to the passed value being truncated. When the passed value is a multiple of 256, the above assertion (ogs_assert(message_len)) is triggered. Otherwise, the hash is computed on only the first n bits of the message (where n = actual_message_len % 256).
2024-02-03 01:37:36 +00:00
memset(message, 0, sizeof(ogs_nas_eps_message_t));
2019-04-27 14:54:30 +00:00
memcpy(&message->emm.h, pkbuf->data - size, size);
decoded += size;
if (message->emm.h.security_header_type >=
2020-05-22 01:24:21 +00:00
OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE) {
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, 1));
decoded -= 1;
2020-05-23 02:24:48 +00:00
size = ogs_nas_eps_decode_service_request(message, pkbuf);
ogs_assert(size >= 0);
2017-04-26 00:49:37 +00:00
decoded += size;
goto out;
}
2020-05-22 01:24:21 +00:00
switch (message->emm.h.message_type) {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-04-26 00:49:37 +00:00
if float(msg_list[k]["type"]) < 192 and k.find("TO UE") == -1 and k != "SERVICE REQUEST":
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_EPS_%s:\n" % v_upper(k))
2017-04-07 13:23:38 +00:00
if len(msg_list[k]["ies"]) != 0:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_decode_%s(message, pkbuf);\n" % v_lower(k))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_5gs_decode_%s() failed\");\n" % v_lower(k))
f.write(" return size;\n")
f.write(" }\n\n")
2020-05-22 01:24:21 +00:00
f.write(" decoded += size;\n")
f.write(" break;\n")
2020-05-22 01:24:21 +00:00
f.write(""" default:
ogs_error("Unknown message type (0x%x) or not implemented",
message->emm.h.message_type);
break;
}
2017-04-26 00:49:37 +00:00
out:
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, decoded));
2019-04-27 14:54:30 +00:00
return OGS_OK;
}
""")
2020-05-23 02:24:48 +00:00
f.write("""int ogs_nas_esm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf)
2017-04-07 13:23:38 +00:00
{
int size = 0;
int decoded = 0;
2017-04-07 13:23:38 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
2017-04-07 13:23:38 +00:00
2019-09-13 12:07:47 +00:00
size = sizeof(ogs_nas_esm_header_t);
if (ogs_pkbuf_pull(pkbuf, size) == NULL) {
ogs_error("ogs_pkbuf_pull() failed [size:%d]", (int)size);
return OGS_ERROR;
}
[SEC] Several vulnerabilities have been resolved. 1. Reachable assertion in ogs_nas_5gmm_decode Location: lib/nas/5gs/decoder.c:4445 ```c int ogs_nas_5gmm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` When a NAS payload is received over `src/amf/context.c:1675`NGAP that has no data, the ogs_assert(pkbuf->len) assertion will be triggered. 2.Reachable assertion in ogs_nas_emm_decode ``` int ogs_nas_emm_decode(ogs_nas_eps_message_t *message, ogs_pkbuf_t *pkbuf) { int size = 0; int decoded = 0; ogs_assert(pkbuf); ogs_assert(pkbuf->data); ogs_assert(pkbuf->len); ``` Nearly identical to (1), but for LTE. 3. Reachable assertion in nas_eps_send_emm_to_esm ``` int nas_eps_send_emm_to_esm(mme_ue_t *mme_ue, ogs_nas_esm_message_container_t *esm_message_container) { int rv; ogs_pkbuf_t *esmbuf = NULL; if (!mme_ue_cycle(mme_ue)) { ogs_error("UE(mme-ue) context has already been removed"); return OGS_NOTFOUND; } ogs_assert(esm_message_container); ogs_assert(esm_message_container->length); ``` The ESM message payload may be 0-length, as the length is determined by a field in the NAS payload (which can be chosen arbitrarily by an attacker). This leads to the length assertion above being triggered. 5. Reachable assertion and incorrect hash calculation in ogs_kdf_hash_mme ``` void ogs_kdf_hash_mme(const uint8_t *message, uint8_t message_len, uint8_t *hash_mme) { uint8_t key[32]; uint8_t output[OGS_SHA256_DIGEST_SIZE]; ogs_assert(message); ogs_assert(message_len); ogs_assert(hash_mme); memset(key, 0, 32); ogs_hmac_sha256(key, 32, message, message_len, output, OGS_SHA256_DIGEST_SIZE); memcpy(hash_mme, output+24, OGS_HASH_MME_LEN); } ``` When handling NAS attach requests or TAU requests, the ogs_kdf_hash_mme function is passed the NAS payload. However, the length field is represented as an unsigned 8-bit integer, which the passed length of the packet may overflow. This leads to the passed value being truncated. When the passed value is a multiple of 256, the above assertion (ogs_assert(message_len)) is triggered. Otherwise, the hash is computed on only the first n bits of the message (where n = actual_message_len % 256).
2024-02-03 01:37:36 +00:00
memset(message, 0, sizeof(ogs_nas_eps_message_t));
2019-04-27 14:54:30 +00:00
memcpy(&message->esm.h, pkbuf->data - size, size);
2017-04-07 13:23:38 +00:00
decoded += size;
2020-05-22 01:24:21 +00:00
switch (message->esm.h.message_type) {
2017-04-07 13:23:38 +00:00
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) >= 192:
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_EPS_%s:\n" % v_upper(k))
2017-04-07 13:23:38 +00:00
if len(msg_list[k]["ies"]) != 0:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_decode_%s(message, pkbuf);\n" % v_lower(k))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_5gs_decode_%s() failed\");\n" % v_lower(k))
f.write(" return size;\n")
f.write(" }\n\n")
2020-05-22 01:24:21 +00:00
f.write(" decoded += size;\n")
f.write(" break;\n")
2017-04-07 13:23:38 +00:00
2020-05-22 01:24:21 +00:00
f.write(""" default:
ogs_error("Unknown message type (0x%x) or not implemented",
message->esm.h.message_type);
break;
2017-04-07 13:23:38 +00:00
}
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, decoded));
2017-04-07 13:23:38 +00:00
2019-04-27 14:54:30 +00:00
return OGS_OK;
2017-04-07 13:23:38 +00:00
}
""")
f.close()
2019-09-13 12:07:47 +00:00
f = open(outdir + 'encoder.c', 'w')
output_header_to_file(f)
2020-05-22 01:24:21 +00:00
f.write("""#include "ogs-nas-eps.h"
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
if len(msg_list[k]["ies"]) == 0:
continue
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_eps_message_t *message);\n" % v_lower(k))
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-03-21 03:04:15 +00:00
if len(msg_list[k]["ies"]) == 0:
continue
2020-05-23 02:24:48 +00:00
f.write("int ogs_nas_eps_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_eps_message_t *message)\n{\n" % v_lower(k))
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) < 192:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t *%s = &message->emm.%s;\n" % (v_lower(k), v_lower(k), v_lower(k)))
2017-04-07 13:23:38 +00:00
else:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_eps_%s_t *%s = &message->esm.%s;\n" % (v_lower(k), v_lower(k), v_lower(k)))
2019-04-27 14:54:30 +00:00
f.write(" int encoded = 0;\n")
f.write(" int size = 0;\n\n")
f.write(" ogs_trace(\"[NAS] Encode %s\");\n\n" % v_upper(k))
for ie in [ies for ies in msg_list[k]["ies"] if ies["presence"] == "M"]:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_encode_%s(pkbuf, &%s->%s);\n" % (v_lower(ie["type"]), v_lower(k), v_lower(ie["value"])))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(size >= 0);\n")
f.write(" encoded += size;\n\n")
2023-03-04 14:47:40 +00:00
for ie in [ies for ies in msg_list[k]["ies"] if ies["presence"] != "M"]:
2020-05-23 02:24:48 +00:00
f.write(" if (%s->presencemask & OGS_NAS_EPS_%s_%s_PRESENT) {\n" % (v_lower(k), v_upper(k), v_upper(ie["value"])))
2017-03-20 08:07:27 +00:00
if ie["length"] == "1" and ie["format"] == "TV":
2020-05-23 02:24:48 +00:00
f.write(" %s->%s.type = (OGS_NAS_EPS_%s_%s_TYPE >> 4);\n\n" % (v_lower(k), v_lower(ie["value"]), v_upper(k), v_upper(ie["value"])))
2020-05-22 01:24:21 +00:00
elif ie["length"] == "1" and ie["format"] == "T":
2020-05-23 02:24:48 +00:00
f.write(" %s->%s.type = OGS_NAS_EPS_%s_%s_TYPE;\n\n" % (get_value(k), get_value(ie["value"]), v_upper(k), v_upper(ie["value"])))
2017-03-20 08:07:27 +00:00
else:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_encode_optional_type(pkbuf, OGS_NAS_EPS_%s_%s_TYPE);\n" % (v_upper(k), v_upper(ie["value"])))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(size >= 0);\n")
2017-03-20 08:07:27 +00:00
f.write(" encoded += size;\n\n")
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_encode_%s(pkbuf, &%s->%s);\n" % (v_lower(ie["type"]), v_lower(k), v_lower(ie["value"])))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(size >= 0);\n")
f.write(" encoded += size;\n")
f.write(" }\n\n")
2017-03-20 08:07:27 +00:00
f.write(""" return encoded;
}
2017-03-21 03:04:15 +00:00
""")
2020-05-23 02:24:48 +00:00
f.write("""ogs_pkbuf_t *ogs_nas_emm_encode(ogs_nas_eps_message_t *message)
{
2019-11-30 07:45:09 +00:00
ogs_pkbuf_t *pkbuf = NULL;
2019-04-27 14:54:30 +00:00
int size = 0;
int encoded = 0;
2019-04-27 14:54:30 +00:00
ogs_assert(message);
2019-04-27 14:54:30 +00:00
/* The Packet Buffer(ogs_pkbuf_t) for NAS message MUST make a HEADROOM.
* When calculating AES_CMAC, we need to use the headroom of the packet. */
2019-11-30 07:45:09 +00:00
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
if (!pkbuf) {
ogs_error("ogs_pkbuf_alloc() failed");
return NULL;
}
2019-11-30 07:45:09 +00:00
ogs_pkbuf_reserve(pkbuf, OGS_NAS_HEADROOM);
ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN-OGS_NAS_HEADROOM);
2019-09-13 12:07:47 +00:00
size = sizeof(ogs_nas_emm_header_t);
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
2019-11-30 07:45:09 +00:00
memcpy(pkbuf->data - size, &message->emm.h, size);
encoded += size;
if (message->emm.h.security_header_type >=
2020-05-22 01:24:21 +00:00
OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE) {
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, 1));
encoded -= 1;
2020-05-23 02:24:48 +00:00
size = ogs_nas_eps_encode_service_request(pkbuf, message);
2019-04-27 14:54:30 +00:00
ogs_assert(size >= 0);
2017-04-26 00:49:37 +00:00
encoded += size;
goto out;
}
2020-05-22 01:24:21 +00:00
switch (message->emm.h.message_type) {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-04-26 00:49:37 +00:00
if float(msg_list[k]["type"]) < 192 and k.find("FROM UE") == -1 and k != "SERVICE REQUEST":
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_EPS_%s:\n" % v_upper(k))
2017-04-07 13:23:38 +00:00
if len(msg_list[k]["ies"]) != 0:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_encode_%s(pkbuf, message);\n" % v_lower(k))
2020-05-22 01:24:21 +00:00
f.write(" ogs_assert(size >= 0);\n")
f.write(" encoded += size;\n")
f.write(" break;\n")
f.write(""" default:
ogs_error("Unknown message type (0x%x) or not implemented",
message->emm.h.message_type);
ogs_pkbuf_free(pkbuf);
return NULL;
2017-04-07 13:23:38 +00:00
}
2017-04-26 00:49:37 +00:00
out:
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, encoded));
2019-11-30 07:45:09 +00:00
pkbuf->len = encoded;
2017-04-07 13:23:38 +00:00
2019-11-30 07:45:09 +00:00
return pkbuf;
2017-04-07 13:23:38 +00:00
}
""")
2020-05-23 02:24:48 +00:00
f.write("""ogs_pkbuf_t *ogs_nas_esm_encode(ogs_nas_eps_message_t *message)
2017-04-07 13:23:38 +00:00
{
2019-11-30 07:45:09 +00:00
ogs_pkbuf_t *pkbuf = NULL;
2019-04-27 14:54:30 +00:00
int size = 0;
int encoded = 0;
2017-04-07 13:23:38 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(message);
2017-04-07 13:23:38 +00:00
2019-04-27 14:54:30 +00:00
/* The Packet Buffer(ogs_pkbuf_t) for NAS message MUST make a HEADROOM.
2017-04-07 13:23:38 +00:00
* When calculating AES_CMAC, we need to use the headroom of the packet. */
2019-11-30 07:45:09 +00:00
pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN);
if (!pkbuf) {
ogs_error("ogs_pkbuf_alloc() failed");
return NULL;
}
2019-11-30 07:45:09 +00:00
ogs_pkbuf_reserve(pkbuf, OGS_NAS_HEADROOM);
ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN-OGS_NAS_HEADROOM);
2017-04-07 13:23:38 +00:00
2019-09-13 12:07:47 +00:00
size = sizeof(ogs_nas_esm_header_t);
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
memcpy(pkbuf->data - size, &message->esm.h, size);
2017-04-07 13:23:38 +00:00
encoded += size;
2020-05-22 01:24:21 +00:00
switch (message->esm.h.message_type) {
2017-04-07 13:23:38 +00:00
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
2017-04-25 09:28:46 +00:00
if float(msg_list[k]["type"]) >= 192:
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_EPS_%s:\n" % v_upper(k))
2017-04-07 13:23:38 +00:00
if len(msg_list[k]["ies"]) != 0:
2020-05-23 02:24:48 +00:00
f.write(" size = ogs_nas_eps_encode_%s(pkbuf, message);\n" % v_lower(k))
2020-05-22 01:24:21 +00:00
f.write(" ogs_assert(size >= 0);\n")
f.write(" encoded += size;\n")
f.write(" break;\n")
f.write(""" default:
ogs_error("Unknown message type (0x%x) or not implemented",
message->esm.h.message_type);
ogs_pkbuf_free(pkbuf);
return NULL;
}
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, encoded));
pkbuf->len = encoded;
2019-11-30 07:45:09 +00:00
return pkbuf;
2017-03-21 03:19:46 +00:00
}
2020-05-23 02:24:48 +00:00
ogs_pkbuf_t *ogs_nas_eps_plain_encode(ogs_nas_eps_message_t *message)
2017-04-07 13:23:38 +00:00
{
2019-04-27 14:54:30 +00:00
ogs_assert(message);
2017-04-07 13:23:38 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(message->emm.h.protocol_discriminator ==
message->esm.h.protocol_discriminator);
2017-04-07 13:23:38 +00:00
if (message->emm.h.protocol_discriminator ==
2019-09-13 12:07:47 +00:00
OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM)
2019-11-30 07:45:09 +00:00
return ogs_nas_emm_encode(message);
2017-04-07 13:23:38 +00:00
else if (message->emm.h.protocol_discriminator ==
2019-09-13 12:07:47 +00:00
OGS_NAS_PROTOCOL_DISCRIMINATOR_ESM)
2019-11-30 07:45:09 +00:00
return ogs_nas_esm_encode(message);
2017-04-07 13:23:38 +00:00
2019-11-30 07:45:09 +00:00
return NULL;
2017-04-07 13:23:38 +00:00
}
""")
2017-04-07 13:23:38 +00:00
f.close()
2017-03-20 14:43:52 +00:00