open5gs/lib/nas/5gs/support/nas-message.py

1001 lines
38 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
2020-05-22 01:24:21 +00:00
version = "0.2.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):
return re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).upper()
def v_lower(v):
2020-05-22 01:24:21 +00:00
return re.sub('\'', '_', re.sub('/', '_', re.sub('-', '_', re.sub(' ', '_', v)))).lower()
def get_value(v):
return re.sub('5gs_', '', re.sub('5g_', '', re.sub('5gsm', 'gsm', re.sub('5gmm', 'gmm', 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)))
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
2020-06-17 05:22:28 +00:00
# Spec errata - workaround
if (type == "Request type" and value == "Request type"):
iei = "8-"
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
2020-05-22 01:24:21 +00:00
msg_list["REGISTRATION REQUEST"] = { "type" : "65" }
msg_list["REGISTRATION ACCEPT"] = { "type" : "66" }
msg_list["REGISTRATION COMPLETE"] = { "type" : "67" }
msg_list["REGISTRATION REJECT"] = { "type" : "68" }
msg_list["DEREGISTRATION REQUEST FROM UE"] = { "type" : "69" }
msg_list["DEREGISTRATION ACCEPT FROM UE"] = { "type" : "70" }
msg_list["DEREGISTRATION REQUEST TO UE"] = { "type" : "71" }
msg_list["DEREGISTRATION ACCEPT TO UE"] = { "type" : "72" }
msg_list["SERVICE REQUEST"] = { "type" : "76" }
msg_list["SERVICE REJECT"] = { "type" : "77" }
msg_list["SERVICE ACCEPT"] = { "type" : "78" }
msg_list["CONFIGURATION UPDATE COMMAND"] = { "type" : "84" }
msg_list["CONFIGURATION UPDATE COMPLETE"] = { "type" : "85" }
msg_list["AUTHENTICATION REQUEST"] = { "type" : "86" }
msg_list["AUTHENTICATION RESPONSE"] = { "type" : "87" }
msg_list["AUTHENTICATION REJECT"] = { "type" : "88" }
msg_list["AUTHENTICATION FAILURE"] = { "type" : "89" }
msg_list["AUTHENTICATION RESULT"] = { "type" : "90" }
msg_list["IDENTITY REQUEST"] = { "type" : "91" }
msg_list["IDENTITY RESPONSE"] = { "type" : "92" }
msg_list["SECURITY MODE COMMAND"] = { "type" : "93" }
msg_list["SECURITY MODE COMPLETE"] = { "type" : "94" }
msg_list["SECURITY MODE REJECT"] = { "type" : "95" }
2020-05-22 01:24:21 +00:00
msg_list["5GMM STATUS"] = { "type" : "100" }
msg_list["NOTIFICATION"] = { "type" : "101" }
msg_list["NOTIFICATION RESPONSE"] = { "type" : "102" }
msg_list["UL NAS TRANSPORT"] = { "type" : "103" }
msg_list["DL NAS TRANSPORT"] = { "type" : "104" }
msg_list["PDU SESSION ESTABLISHMENT REQUEST"] = { "type" : "193" }
msg_list["PDU SESSION ESTABLISHMENT ACCEPT"] = { "type" : "194" }
msg_list["PDU SESSION ESTABLISHMENT REJECT"] = { "type" : "195" }
msg_list["PDU SESSION AUTHENTICATION COMMAND"] = { "type" : "197" }
msg_list["PDU SESSION AUTHENTICATION COMPLETE"] = { "type" : "198" }
msg_list["PDU SESSION AUTHENTICATION RESULT"] = { "type" : "199" }
msg_list["PDU SESSION MODIFICATION REQUEST"] = { "type" : "201" }
msg_list["PDU SESSION MODIFICATION REJECT"] = { "type" : "202" }
msg_list["PDU SESSION MODIFICATION COMMAND"] = { "type" : "203" }
msg_list["PDU SESSION MODIFICATION COMPLETE"] = { "type" : "204" }
msg_list["PDU SESSION MODIFICATION COMMAND REJECT"] = { "type" : "205" }
msg_list["PDU SESSION RELEASE REQUEST"] = { "type" : "209" }
msg_list["PDU SESSION RELEASE REJECT"] = { "type" : "210" }
msg_list["PDU SESSION RELEASE COMMAND"] = { "type" : "211" }
msg_list["PDU SESSION RELEASE COMPLETE"] = { "type" : "212" }
msg_list["5GSM STATUS"] = { "type" : "214" }
# Table number for Message List
2020-05-22 01:24:21 +00:00
msg_list["AUTHENTICATION REQUEST"]["table"] = 0
msg_list["AUTHENTICATION RESPONSE"]["table"] = 1
msg_list["AUTHENTICATION RESULT"]["table"] = 2
msg_list["AUTHENTICATION FAILURE"]["table"] = 3
msg_list["AUTHENTICATION REJECT"]["table"] = 4
msg_list["REGISTRATION REQUEST"]["table"] = 5
msg_list["REGISTRATION ACCEPT"]["table"] = 6
msg_list["REGISTRATION COMPLETE"]["table"] = 7
msg_list["REGISTRATION REJECT"]["table"] = 8
msg_list["UL NAS TRANSPORT"]["table"] = 9
msg_list["DL NAS TRANSPORT"]["table"] = 10
msg_list["DEREGISTRATION REQUEST FROM UE"]["table"] = 11
msg_list["DEREGISTRATION ACCEPT FROM UE"]["table"] = 12
msg_list["DEREGISTRATION REQUEST TO UE"]["table"] = 13
msg_list["DEREGISTRATION ACCEPT TO UE"]["table"] = 14
msg_list["SERVICE REQUEST"]["table"] = 15
msg_list["SERVICE ACCEPT"]["table"] = 16
msg_list["SERVICE REJECT"]["table"] = 17
msg_list["CONFIGURATION UPDATE COMMAND"]["table"] = 18
msg_list["CONFIGURATION UPDATE COMPLETE"]["table"] = 19
2020-05-22 01:24:21 +00:00
msg_list["IDENTITY REQUEST"]["table"] = 20
msg_list["IDENTITY RESPONSE"]["table"] = 21
msg_list["NOTIFICATION"]["table"] = 22
msg_list["NOTIFICATION RESPONSE"]["table"] = 23
msg_list["SECURITY MODE COMMAND"]["table"] = 24
msg_list["SECURITY MODE COMPLETE"]["table"] = 25
msg_list["SECURITY MODE REJECT"]["table"] = 26
msg_list["5GMM STATUS"]["table"] = 28
2023-03-04 14:47:40 +00:00
msg_list["PDU SESSION ESTABLISHMENT REQUEST"]["table"] = 38
msg_list["PDU SESSION ESTABLISHMENT ACCEPT"]["table"] = 39
msg_list["PDU SESSION ESTABLISHMENT REJECT"]["table"] = 40
msg_list["PDU SESSION AUTHENTICATION COMMAND"]["table"] = 41
msg_list["PDU SESSION AUTHENTICATION COMPLETE"]["table"] = 42
msg_list["PDU SESSION AUTHENTICATION RESULT"]["table"] = 43
msg_list["PDU SESSION MODIFICATION REQUEST"]["table"] = 44
msg_list["PDU SESSION MODIFICATION REJECT"]["table"] = 45
msg_list["PDU SESSION MODIFICATION COMMAND"]["table"] = 46
msg_list["PDU SESSION MODIFICATION COMPLETE"]["table"] = 47
msg_list["PDU SESSION MODIFICATION COMMAND REJECT"]["table"] = 48
msg_list["PDU SESSION RELEASE REQUEST"]["table"] = 49
msg_list["PDU SESSION RELEASE REJECT"]["table"] = 50
msg_list["PDU SESSION RELEASE COMMAND"]["table"] = 51
msg_list["PDU SESSION RELEASE COMPLETE"]["table"] = 52
msg_list["5GSM STATUS"]["table"] = 53
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_5GS_IES_H
#define OGS_NAS_5GS_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_5gs_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_5gs_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf);\n" % (v_lower(k), v_lower(k), get_value(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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s);\n" % (v_lower(k), v_lower(k), get_value(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_5GS_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-5gs.h"
2017-03-20 14:43:52 +00:00
2020-05-23 02:24:48 +00:00
int ogs_nas_5gs_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_5gs_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), get_value(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-06-04 18:12:05 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % get_value(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
2020-06-04 18:12:05 +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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), get_value(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")
2020-05-22 01:24:21 +00:00
f.write(" memcpy(pkbuf->data - size, %s, size);\n\n" % get_value(k))
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")
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_5gs_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), get_value(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")
2020-05-22 01:24:21 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % get_value(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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), get_value(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))
2020-05-22 01:24:21 +00:00
f.write(" memcpy(&target, %s, size);\n" % get_value(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")
2020-06-04 18:12:05 +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_5gs_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), get_value(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-05-22 01:24:21 +00:00
f.write(" %s->length = be16toh(source->length);\n" % get_value(k))
f.write(" size = %s->length + sizeof(%s->length);\n\n" % (get_value(k), get_value(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-05-22 01:24:21 +00:00
f.write(" %s->buffer = pkbuf->data - size + sizeof(%s->length);\n\n" % (get_value(k), get_value(k)))
2019-04-27 14:54:30 +00:00
f.write(" ogs_trace(\" %s - \");\n" % v_upper(k))
2020-05-22 01:24:21 +00:00
f.write(" ogs_log_hexdump(OGS_LOG_TRACE, (void*)%s->buffer, %s->length);\n\n" % (get_value(k), get_value(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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), get_value(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = 0;\n")
f.write(" int target;\n\n")
2020-05-22 01:24:21 +00:00
f.write(" ogs_assert(%s);\n" % get_value(k))
f.write(" ogs_assert(%s->buffer);\n\n" % get_value(k))
f.write(" size = sizeof(%s->length);\n" % get_value(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
2020-05-22 01:24:21 +00:00
f.write(" target = htobe16(%s->length);\n" % get_value(k))
2019-04-27 14:54:30 +00:00
f.write(" memcpy(pkbuf->data - size, &target, size);\n\n")
2020-05-22 01:24:21 +00:00
f.write(" size = %s->length;\n" % get_value(k))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(ogs_pkbuf_pull(pkbuf, size));\n")
2020-05-22 01:24:21 +00:00
f.write(" memcpy(pkbuf->data - size, %s->buffer, size);\n\n" % get_value(k))
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");
2020-05-22 01:24:21 +00:00
f.write(" return %s->length + sizeof(%s->length);\n" % (get_value(k), get_value(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_5gs_decode_%s(ogs_nas_%s_t *%s, ogs_pkbuf_t *pkbuf)\n" % (v_lower(k), v_lower(k), get_value(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-05-22 01:24:21 +00:00
f.write(" %s->length = source->length;\n" % get_value(k))
f.write(" size = %s->length + sizeof(%s->length);\n\n" % (get_value(k), get_value(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" % get_value(k))
2020-05-22 01:24:21 +00:00
f.write(" memcpy(%s, pkbuf->data - size, size);\n\n" % get_value(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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_%s_t *%s)\n" % (v_lower(k), v_lower(k), get_value(k)))
2017-03-20 14:43:52 +00:00
f.write("{\n")
f.write(" int size = %s->length + sizeof(%s->length);\n" % (get_value(k), get_value(k)))
2019-09-13 12:07:47 +00:00
f.write(" ogs_nas_%s_t target;\n\n" % v_lower(k))
2020-05-22 01:24:21 +00:00
f.write(" memcpy(&target, %s, sizeof(ogs_nas_%s_t));\n" % (get_value(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_5GS_MESSAGE_H
#define OGS_NAS_5GS_MESSAGE_H
#ifdef __cplusplus
extern "C" {
2019-06-11 09:28:25 +00:00
#endif
2020-06-04 18:12:05 +00:00
#define OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GSM 0x2e
#define OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM 0x7e
2020-05-22 01:24:21 +00:00
#define OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED 0
2017-04-09 05:26:19 +00:00
2020-05-22 01:24:21 +00:00
typedef struct ogs_nas_5gmm_header_s {
uint8_t extended_protocol_discriminator;
uint8_t security_header_type;
2019-04-27 14:54:30 +00:00
uint8_t message_type;
2020-05-22 01:24:21 +00:00
} __attribute__ ((packed)) ogs_nas_5gmm_header_t;
2017-04-07 13:23:38 +00:00
2020-05-22 01:24:21 +00:00
typedef struct ogs_nas_5gsm_header_s {
uint8_t extended_protocol_discriminator;
uint8_t pdu_session_identity;
2019-04-27 14:54:30 +00:00
uint8_t procedure_transaction_identity;
uint8_t message_type;
2020-05-22 01:24:21 +00:00
} __attribute__ ((packed)) ogs_nas_5gsm_header_t;
2020-05-23 02:24:48 +00:00
typedef struct ogs_nas_5gs_security_header_s {
2020-05-22 01:24:21 +00:00
uint8_t extended_protocol_discriminator;
uint8_t security_header_type;
2019-04-27 14:54:30 +00:00
uint32_t message_authentication_code;
uint8_t sequence_number;
2020-05-23 02:24:48 +00:00
} __attribute__ ((packed)) ogs_nas_5gs_security_header_t;
""")
for (k, v) in sorted_msg_list:
f.write("#define OGS_NAS_5GS_" + 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(" ******************************************************/")
2020-06-17 05:22:28 +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_5GS_%s_%s_PRESENT ((uint64_t)1<<%d)" % (v_upper(k), v_upper(ie["value"]), i))
2020-06-17 05:22:28 +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_5GS_%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_5gs_%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;
2020-06-17 05:22:28 +00:00
if ie["presence"] != "M" and optional_fields is False:
f.write("\n /* Optional fields */\n")
2020-05-22 01:24:21 +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 " + \
2020-05-22 01:24:21 +00:00
get_value(ie["value"]) + ";\n")
2020-05-23 02:24:48 +00:00
f.write("} ogs_nas_5gs_%s_t;\n\n" % v_lower(k))
f.write("\n")
2020-05-22 01:24:21 +00:00
f.write("""typedef struct ogs_nas_5gmm_message_s {
ogs_nas_5gmm_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_5gs_%s_t %s;\n" % (v_lower(k), get_value(k)))
2017-04-07 13:23:38 +00:00
f.write(""" };
2020-05-22 01:24:21 +00:00
} ogs_nas_5gmm_message_t;
2017-03-21 03:04:15 +00:00
2020-05-22 01:24:21 +00:00
typedef struct ogs_nas_5gsm_message_s {
ogs_nas_5gsm_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_5gs_%s_t %s;\n" % (v_lower(k), get_value(k)))
f.write(""" };
2020-05-22 01:24:21 +00:00
} ogs_nas_5gsm_message_t;
2017-04-07 13:23:38 +00:00
2020-05-23 02:24:48 +00:00
typedef struct ogs_nas_5gs_message_s {
ogs_nas_5gs_security_header_t h;
2017-04-07 13:23:38 +00:00
union {
2020-05-22 01:24:21 +00:00
ogs_nas_5gmm_message_t gmm;
ogs_nas_5gsm_message_t gsm;
2017-04-07 13:23:38 +00:00
};
2020-05-23 02:24:48 +00:00
} ogs_nas_5gs_message_t;
2020-05-23 02:24:48 +00:00
ogs_pkbuf_t *ogs_nas_5gmm_encode(ogs_nas_5gs_message_t *message);
ogs_pkbuf_t *ogs_nas_5gsm_encode(ogs_nas_5gs_message_t *message);
int ogs_nas_5gmm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf);
int ogs_nas_5gsm_decode(ogs_nas_5gs_message_t *message, ogs_pkbuf_t *pkbuf);
ogs_pkbuf_t *ogs_nas_5gs_plain_encode(ogs_nas_5gs_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_5GS_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-5gs.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_5gs_decode_%s(ogs_nas_5gs_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_5gs_decode_%s(ogs_nas_5gs_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_5gs_%s_t *%s = &message->gmm.%s;\n" % (v_lower(k), get_value(k), get_value(k)))
2017-04-07 13:23:38 +00:00
else:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_5gs_%s_t *%s = &message->gsm.%s;\n" % (v_lower(k), get_value(k), get_value(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_5gs_decode_%s(&%s->%s, pkbuf);\n" % (v_lower(ie["type"]), get_value(k), get_value(ie["value"])))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_5gs_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;
2020-06-17 05:22:28 +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_5GS_%s_%s_TYPE:\n" % (v_upper(k), v_upper(ie["value"])))
2020-06-17 05:22:28 +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_5gs_decode_%s(&%s->%s, pkbuf);\n" % (v_lower(ie["type"]), get_value(k), get_value(ie["value"])))
f.write(" if (size < 0) {\n")
f.write(" ogs_error(\"ogs_nas_5gs_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_5GS_%s_%s_PRESENT;\n" % (get_value(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")
2020-06-17 05:22:28 +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:
2020-06-17 05:22:28 +00:00
ogs_error("Unknown type(0x%x) or not implemented\\n", type);
2020-05-22 01:24:21 +00:00
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_5gmm_decode(ogs_nas_5gs_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);
2020-05-22 01:24:21 +00:00
size = sizeof(ogs_nas_5gmm_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_5gs_message_t));
2020-05-22 01:24:21 +00:00
memcpy(&message->gmm.h, pkbuf->data - size, size);
decoded += size;
2020-05-22 01:24:21 +00:00
switch(message->gmm.h.message_type) {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
if float(msg_list[k]["type"]) < 192:
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_5GS_%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_5gs_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->gmm.h.message_type);
break;
}
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_5gsm_decode(ogs_nas_5gs_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
2020-05-22 01:24:21 +00:00
size = sizeof(ogs_nas_5gsm_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_5gs_message_t));
2020-05-22 01:24:21 +00:00
memcpy(&message->gsm.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->gsm.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_5GS_%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_5gs_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->gsm.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-5gs.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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_5gs_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_5gs_encode_%s(ogs_pkbuf_t *pkbuf, ogs_nas_5gs_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_5gs_%s_t *%s = &message->gmm.%s;\n" % (v_lower(k), get_value(k), get_value(k)))
2017-04-07 13:23:38 +00:00
else:
2020-05-23 02:24:48 +00:00
f.write(" ogs_nas_5gs_%s_t *%s = &message->gsm.%s;\n" % (v_lower(k), get_value(k), get_value(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_5gs_encode_%s(pkbuf, &%s->%s);\n" % (v_lower(ie["type"]), get_value(k), get_value(ie["value"])))
2019-04-27 14:54:30 +00:00
f.write(" ogs_assert(size >= 0);\n")
f.write(" encoded += size;\n\n")
2020-06-17 05:22:28 +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_5GS_%s_%s_PRESENT) {\n" % (get_value(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_5GS_%s_%s_TYPE >> 4);\n\n" % (get_value(k), get_value(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_5GS_%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_5gs_encode_optional_type(pkbuf, OGS_NAS_5GS_%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_5gs_encode_%s(pkbuf, &%s->%s);\n" % (v_lower(ie["type"]), get_value(k), get_value(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_5gmm_encode(ogs_nas_5gs_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);
2020-05-22 01:24:21 +00:00
size = sizeof(ogs_nas_5gmm_header_t);
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
2020-05-22 01:24:21 +00:00
memcpy(pkbuf->data - size, &message->gmm.h, size);
encoded += size;
2020-05-22 01:24:21 +00:00
switch(message->gmm.h.message_type) {
""")
for (k, v) in sorted_msg_list:
if "ies" not in msg_list[k]:
continue;
if float(msg_list[k]["type"]) < 192:
2020-05-23 02:24:48 +00:00
f.write(" case OGS_NAS_5GS_%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_5gs_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->gmm.h.message_type);
ogs_pkbuf_free(pkbuf);
return NULL;
2017-04-07 13:23:38 +00:00
}
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_5gsm_encode(ogs_nas_5gs_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
2020-05-22 01:24:21 +00:00
size = sizeof(ogs_nas_5gsm_header_t);
2019-11-30 07:45:09 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, size));
2020-05-22 01:24:21 +00:00
memcpy(pkbuf->data - size, &message->gsm.h, size);
2017-04-07 13:23:38 +00:00
encoded += size;
2020-05-22 01:24:21 +00:00
switch(message->gsm.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_5GS_%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_5gs_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->gsm.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_5gs_plain_encode(ogs_nas_5gs_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
2020-05-22 01:24:21 +00:00
ogs_assert(message->gmm.h.extended_protocol_discriminator ==
message->gsm.h.extended_protocol_discriminator);
2017-04-07 13:23:38 +00:00
2020-05-22 01:24:21 +00:00
if (message->gmm.h.extended_protocol_discriminator ==
2020-06-04 18:12:05 +00:00
OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM)
2020-05-22 01:24:21 +00:00
return ogs_nas_5gmm_encode(message);
else if (message->gmm.h.extended_protocol_discriminator ==
2020-06-04 18:12:05 +00:00
OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GSM)
2020-05-22 01:24:21 +00:00
return ogs_nas_5gsm_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