Files
2026-ectf-insecure-example/firmware/secrets_to_c_header.py
2026-01-12 16:57:35 -05:00

117 lines
4.0 KiB
Python

"""
Author: Samuel Meyers
Date: 2026
This source file is part of an example system for MITRE's 2026 Embedded CTF
(eCTF). This code is being provided only for educational purposes for the 2026 MITRE
eCTF competition, and may not meet MITRE standards for quality. Use this code at your
own risk!
Copyright: Copyright (c) 2026 The MITRE Corporation
"""
import os
import json
import argparse
from dataclasses import dataclass
@dataclass
class Permission:
"""Represents a permission for one group
"""
group_id: int=None
read: bool=False
write: bool=False
receive: bool=False
@classmethod
def deserialize(cls, perms: str):
"""Create a Permission object from a string
:param perm: A string representing a permission. The permission shall be a pair
of group ID and permissions separated by an equal sign (e.g.,
"<group_id>=<permission>"). The group ID shall be a 16-bit hexadecimal
number padded with 0s to be a total of 4 characters with no preceding '0x'
(e.g., 4b1d). The permission shall be a 3-character string where present
permissions are represented by their opcode and absent permissions are
represented by a '-' (e.g., "RWC", "RW-", "--C").
"""
group_id, perm_string = perms.split('=')
perm_obj = cls(
int(group_id, 16),
read = perm_string[0] == 'R',
write = perm_string[1] == 'W',
receive = perm_string[2] == 'C',
)
return perm_obj
def serialize(self):
ret = f'{self.group_id:04x}='
for perm, shorthand in {'read': 'R', 'write': 'W', 'receive': 'C'}.items():
ret += shorthand if getattr(self, perm) else "-"
return ret
class PermissionList(list):
"""Represents a set of permissions that an HSM can be built with.
"""
def __init__(self, *args):
for item in args:
if isinstance(item, Permission):
self.append(item)
@classmethod
def deserialize(cls, perms: str):
"""Create a list of permission objects from a string
representation
:param perm: A string representing the permission set. The string shall be a
colon-separated list of permissions (e.g., "<perm1>:<perm2>:<perm3>").
:returns: An instance of `PermissionList`
"""
ret = cls()
permissions_strings = perms.split(":")
for entry in permissions_strings:
perm_obj = Permission.deserialize(entry)
ret.append(perm_obj)
return ret
def serialize(self):
return ':'.join(perm.serialize() for perm in self)
def secrets_to_c_header(
permissions: PermissionList, path: str, hsm_pin: str, secrets: bytes
):
# TODO: Change this file to incorporate the secrets generated by gen_secrets.py
with open(os.path.join(path, "secrets.h"), 'w') as f:
f.write("#ifndef __SECRETS_H__\n")
f.write("#define __SECRETS_H__\n\n")
f.write('#include "security.h"\n\n')
f.write(f'#define HSM_PIN "{hsm_pin}"\n\n')
f.write("const static group_permission_t global_permissions[MAX_PERMS] = {\n")
for i, perm in enumerate(permissions):
f.write(
(f"\t{{{hex(perm.group_id)}, {str(perm.read).lower()}, "
f"{str(perm.write).lower()}, {str(perm.receive).lower()}}},\n")
)
f.write("};\n")
f.write("\n#endif // __SECRETS_H__\n")
if __name__ == '__main__':
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("secrets", type=argparse.FileType("rb"), help="Path to secrets file")
parser.add_argument("hsm_pin", type=str, help="User PIN for the HSM")
parser.add_argument("permissions", type=str, help="List of colon-separated permissions. E.g., \"1234=R--:4321=RWC\"")
return parser.parse_args()
args = parse_args()
perms = PermissionList.deserialize(args.permissions)
secrets_to_c_header(perms, './inc/', args.hsm_pin, args.secrets.read())