From 7e8a10a9273081e39d1357e03d47d9145dbd46ba Mon Sep 17 00:00:00 2001 From: Ben Janis Date: Mon, 12 Jan 2026 16:50:18 -0500 Subject: [PATCH] Initial insecure reference design release --- .gitignore | 340 ++++++++++++++++++++++ LICENSE.txt | 202 +++++++++++++ Makefile | 25 ++ README.md | 21 ++ ectf26_design/pyproject.toml | 33 +++ ectf26_design/src/__init__.py | 0 ectf26_design/src/gen_secrets.py | 103 +++++++ firmware/Dockerfile | 45 +++ firmware/Makefile | 106 +++++++ firmware/build.sh | 4 + firmware/firmware.ld | 74 +++++ firmware/inc/commands.h | 162 +++++++++++ firmware/inc/filesystem.h | 152 ++++++++++ firmware/inc/host_messaging.h | 102 +++++++ firmware/inc/security.h | 52 ++++ firmware/inc/simple_crypto.h | 72 +++++ firmware/inc/simple_flash.h | 66 +++++ firmware/inc/simple_uart.h | 51 ++++ firmware/inc/status_led.h | 22 ++ firmware/inc/ti_msp_dl_config.h | 146 ++++++++++ firmware/secrets_to_c_header.py | 116 ++++++++ firmware/src/HSM.c | 229 +++++++++++++++ firmware/src/commands.c | 323 ++++++++++++++++++++ firmware/src/filesystem.c | 131 +++++++++ firmware/src/host_messaging.c | 221 ++++++++++++++ firmware/src/security.c | 37 +++ firmware/src/simple_crypto.c | 109 +++++++ firmware/src/simple_flash.c | 103 +++++++ firmware/src/simple_uart.c | 51 ++++ firmware/src/startup_mspm0l222x_ticlang.c | 174 +++++++++++ firmware/src/ti_msp_dl_config.c | 169 +++++++++++ 31 files changed, 3441 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 Makefile create mode 100644 README.md create mode 100644 ectf26_design/pyproject.toml create mode 100644 ectf26_design/src/__init__.py create mode 100644 ectf26_design/src/gen_secrets.py create mode 100644 firmware/Dockerfile create mode 100644 firmware/Makefile create mode 100644 firmware/build.sh create mode 100644 firmware/firmware.ld create mode 100644 firmware/inc/commands.h create mode 100644 firmware/inc/filesystem.h create mode 100644 firmware/inc/host_messaging.h create mode 100644 firmware/inc/security.h create mode 100644 firmware/inc/simple_crypto.h create mode 100644 firmware/inc/simple_flash.h create mode 100644 firmware/inc/simple_uart.h create mode 100644 firmware/inc/status_led.h create mode 100644 firmware/inc/ti_msp_dl_config.h create mode 100644 firmware/secrets_to_c_header.py create mode 100644 firmware/src/HSM.c create mode 100644 firmware/src/commands.c create mode 100644 firmware/src/filesystem.c create mode 100644 firmware/src/host_messaging.c create mode 100644 firmware/src/security.c create mode 100644 firmware/src/simple_crypto.c create mode 100644 firmware/src/simple_flash.c create mode 100644 firmware/src/simple_uart.c create mode 100644 firmware/src/startup_mspm0l222x_ticlang.c create mode 100644 firmware/src/ti_msp_dl_config.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68a4e70 --- /dev/null +++ b/.gitignore @@ -0,0 +1,340 @@ +## Project .gitignore ## + +.DS_Store +.vscode/ +**/gcc + +!device/lib + +## Begin Generic .gitignore ## + +# Created by https://www.toptal.com/developers/gitignore/api/python,c,c++,git,pycharm +# Edit at https://www.toptal.com/developers/gitignore?templates=python,c,c++,git,pycharm + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex +*.bin + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### C++ ### +# Prerequisites + +# Compiled Object files +*.slo + +# Precompiled Headers + +# Compiled Dynamic libraries + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai + +# Executables + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv* +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# WolfSSL +wolfssl/ + +# PyCharm +# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# End of https://www.toptal.com/developers/gitignore/api/python,c,c++,git,pycharm + +## Project Post-.gitignore ## + +!device/lib +*.secrets +*.secrets.txt +**/secrets.h +uv.lock diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..c7e8076 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 The MITRE Corporation. All rights reserved + Approved for Public Release; Distribution Unlimited. Case Number 25-03257-Code + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f531063 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +# This file is a helper script to make repetitive build actions easier +# Invoking `make docker` will build the docker image. +# `make docker-nc` will build the docker image without using the Docker cache. +# `make secrets` will generate secrets for group 1234. +# `make firmware` will make the firmware image. +# `make clean` will remove build artifacts, both in the firmware +# directory and the final output directory. + +docker: + docker build -t build-hsm ./firmware/ + +docker-nc: + docker build --no-cache -t build-hsm ./firmware/ + +global.secrets: + @if [ -z "${GROUPS}" ]; then echo 'Must pass valid groups like:\r\n\tmake global.secrets GROUPS=1234\r\nor, if multiple groups defined:\r\n\tmake global.secrets GROUPS="1234 5678"' && false; fi + uvx --with-editable ./ectf26_design --from ectf26_design secrets global.secrets $(GROUPS) + +%.hsm: + @if [ ! -f global.secrets ]; then echo 'Must generate global secrets first with\r\n\tmake global.secrets' && false; fi + @if [ -z "${PIN}" ] || [ -z "${PERMS}" ]; then echo "Must provide PIN and permissions for HSM. For example:\r\n\tmake $@ PIN=123456 PERMS='1234=RWC'" && false; fi + docker run --rm -v ./firmware:/hsm -v ./global.secrets:/secrets/global.secrets:ro -v ./$@:/out -e HSM_PIN=${PIN} -e PERMISSIONS='${PERMS}' build-hsm $(BUILDDIR) + +clean: + rm -rfI *.hsm/ global.secrets diff --git a/README.md b/README.md new file mode 100644 index 0000000..fa488fe --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# eCTF Insecure Example + +This repository holds the insecure example design for an eCTF Hardware Security Module. +The rules for the 2026 eCTF can be found here: https://rules.ectf.mitre.org/. Your team +should **NOT fork this repo**. Instead clone it and push to a new __private__ repo. + +## Layout + +- `firmware/` - Source code to build the firmware + - `Makefile` - This makefile is invoked by the eCTF tools when creating an HSM. + - `Dockerfile` - Describes the build environment used by eCTF build tools. + - `secrets_to_c_header.py` - Python file to convert from global secrets to firmware-parsable header file + - `inc/` - Directory with c header files + - `src/` - Directory with c source files + - `wolfssl/` - Location to place wolfssl library for included Crypto Example + - `firmware.ld` - Defines memory layout of built firmware +- `ectf26_design/` - Pip-installable module for generating secrets + - `src/` - Secrets gen source code + - `gen_secrets.py` - Generates shared secrets + - `pyproject.toml` - File that tells pip how to install this module +- `Makefile` - Helper script to simplify repetitive build steps diff --git a/ectf26_design/pyproject.toml b/ectf26_design/pyproject.toml new file mode 100644 index 0000000..d7ec421 --- /dev/null +++ b/ectf26_design/pyproject.toml @@ -0,0 +1,33 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "ectf26_design" +version = "2026.0+example" +requires-python = ">=3.12" + +# TODO: add your custom dependencies to this list +dependencies = [ + "loguru", +] + +[project.scripts] +secrets = "gen_secrets:main" + + +[tool.black] +include = '\.pyi?$' +exclude = ''' +/( + \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist +)/ +''' \ No newline at end of file diff --git a/ectf26_design/src/__init__.py b/ectf26_design/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ectf26_design/src/gen_secrets.py b/ectf26_design/src/gen_secrets.py new file mode 100644 index 0000000..9c51e7c --- /dev/null +++ b/ectf26_design/src/gen_secrets.py @@ -0,0 +1,103 @@ +""" +Author: Ben Janis +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 argparse +import json +from pathlib import Path + +from loguru import logger + + +def gen_secrets(groups: list[int]) -> bytes: + """Generate the contents secrets file + + This will be passed to the Encoder, ectf26_design.gen_secrets, + and the build process of the firmware + + NOTE: you should NOT write to secrets files within this function. + All generated secrets must be contained in the returned bytes + object. + + :param groups: List of permission groups that will be valid in this + deployment. + + :returns: Contents of the secrets file + """ + # TODO: Update this function to generate any system-wide secrets needed by + # your design + + # Create the secrets object + # You can change this to generate any secret material + # The secrets file will never be shared with attackers + secrets = { + "groups": groups, + "some_secrets": "EXAMPLE", + } + + # NOTE: if you choose to use JSON for your file type, you will not + # be able to store binary data, and must either use a different file + # type or encode the binary data to hex, base64, or another type of + # ASCII-only encoding + return json.dumps(secrets).encode() + + +def parse_args(): + """Define and parse the command line arguments + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "--force", + "-f", + action="store_true", + help="Force creation of secrets file, overwriting existing file", + ) + parser.add_argument( + "secrets_file", + type=Path, + help="Path to the secrets file to be created", + ) + parser.add_argument( + "groups", + nargs="+", + type=lambda x: int(x, 0), + help="Supported group IDs", + ) + return parser.parse_args() + + +def main(): + """Main function of gen_secrets + + You will likely not have to change this function + """ + # Parse the command line arguments + args = parse_args() + + secrets = gen_secrets(args.groups) + + # Print the generated secrets for your own debugging + # Attackers will NOT have access to the output of this, but feel free to remove + # + # NOTE: Printing sensitive data is generally not good security practice + logger.debug(f"Generated secrets: {secrets}") + + # Open the file, erroring if the file exists unless the --force arg is provided + with open(args.secrets_file, "wb" if args.force else "xb") as f: + # Dump the secrets to the file + f.write(secrets) + + # For your own debugging. Feel free to remove + logger.success(f"Wrote secrets to {str(args.secrets_file.absolute())}") + + +if __name__ == "__main__": + main() diff --git a/firmware/Dockerfile b/firmware/Dockerfile new file mode 100644 index 0000000..78b4ae1 --- /dev/null +++ b/firmware/Dockerfile @@ -0,0 +1,45 @@ +# Dockerfile for the 2026 eCTF +# Make any changes here to set up your build environment (e.g., installing crypto +# libraries, dependencies, the compiler for a different language) + +FROM ubuntu:24.04 + +LABEL version="0.2" +LABEL description="Example HSM Docker Container for the 2026 eCTF" + +ARG DEBIAN_FRONTEND=noninteractive +WORKDIR /root + +# Install Requisite Packages +# do this first because it takes the longest +RUN apt-get update && apt-get upgrade -y && apt-get install -y \ + python3 \ + make \ + wget \ + build-essential \ + unzip + +ENV MSPM0_SDK_INSTALL_DIR=/opt/mspm0-sdk-mspm0_sdk_2_06_00_05 +ENV TICLANG_ARMCOMPILER=/opt/ti-cgt-armllvm_4.0.3.LTS + +# Install MSPM0 SDK +RUN wget https://github.com/TexasInstruments/mspm0-sdk/archive/refs/tags/mspm0_sdk_2_06_00_05.zip && \ + unzip mspm0_sdk_2_06_00_05.zip -d /opt && \ + rm -f -r mspm0_sdk_2_06_00_05.zip ${MSPM0_SDK_INSTALL_DIR}/docs ${MSPM0_SDK_INSTALL_DIR}/examples + +# Install TI-Clang for curr machine's arch +RUN if [ $(uname -m) = "x86_64" ]; then \ + wget -O ti_cgt_armllvm_4.0.3.LTS_linux_installer.bin https://dr-download.ti.com/software-development/ide-configuration-compiler-or-debugger/MD-ayxs93eZNN/4.0.3.LTS/ti_cgt_armllvm_4.0.3.LTS_linux-x64_installer.bin --ca-certificate=SSLCerts/mitre-chain.pem; \ + elif [ $(uname -m) = "aarch64" ] || [ $(uname -m) = "arm64" ]; then \ + wget -O ti_cgt_armllvm_4.0.3.LTS_linux_installer.bin https://dr-download.ti.com/software-development/ide-configuration-compiler-or-debugger/MD-ayxs93eZNN/4.0.3.LTS/ti_cgt_armllvm_4.0.3.LTS_linux-arm64_installer.bin --ca-certificate=SSLCerts/mitre-chain.pem; \ + else \ + $(false); \ + fi && \ + chmod +x ti_cgt_armllvm_4.0.3.LTS_linux_installer.bin && \ + ./ti_cgt_armllvm_4.0.3.LTS_linux_installer.bin --mode unattended --prefix /opt && \ + rm -f ti_cgt_armllvm_4.0.3.LTS_linux_installer.bin + +WORKDIR /hsm + +ENTRYPOINT ["bash", "/hsm/build.sh"] + diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..00d5e1c --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,106 @@ +MSPM0_SDK_INSTALL_DIR ?= $(abspath ../../../../../..) + +include $(MSPM0_SDK_INSTALL_DIR)/tools/imports_mak/imports.mak.linux + +CC = "$(TICLANG_ARMCOMPILER)/bin/tiarmclang" +LNK = "$(TICLANG_ARMCOMPILER)/bin/tiarmclang" +OBJCOPY = "$(TICLANG_ARMCOMPILER)/bin/tiarmobjcopy" +BUILDDIR ?= /tmp/build +VPATH = "src" +LINKERFILE = "firmware.ld" + +# to download wolfssl for the simple crypto example, `cd ./firmware/ && git clone https://github.com/wolfSSL/wolfssl` +# then set this variable to 1 +CRYPTO_EXAMPLE = 0 + +OBJECTS = $(BUILDDIR)/HSM.so \ + $(BUILDDIR)/simple_uart.so \ + $(BUILDDIR)/ti_msp_dl_config.so \ + $(BUILDDIR)/startup_mspm0l222x_ticlang.so \ + $(BUILDDIR)/simple_flash.so \ + $(BUILDDIR)/host_messaging.so \ + $(BUILDDIR)/security.so \ + $(BUILDDIR)/filesystem.so \ + $(BUILDDIR)/commands.so + +ifeq ($(CRYPTO_EXAMPLE), 1) +OBJECTS += $(BUILDDIR)/simple_crypto.so + +# change C flags +CFLAGS += -DCRYPTO_EXAMPLE=1 +CFLAGS += -DNO_WOLFSSL_DIR +CFLAGS += -DWOLFSSL_AES_DIRECT +CFLAGS += -DSINGLE_THREADED +# From https://www.wolfssl.com/documentation/manuals/wolfssl/chapter02.html#building-with-gcc-arm +CFLAGS += -DHAVE_PK_CALLBACKS +CFLAGS += -DWOLFSSL_USER_IO +CFLAGS += -DNO_WRITEV -DTIME_T_NOT_64BIT +CFLAGS += -DNO_FILESYSTEM +# tells wolfssl that we will handle RNG on the baremetal target +# user will need to implement the callbacks +CFLAGS += -DNO_DEV_RANDOM +CFLAGS += -DWC_NO_DEFAULT_DEVID +CFLAGS += -DWOLF_CRYPTO_CB + +WOLFSSL_INC = wolfssl/wolfcrypt/src +CFLAGS += -I./wolfssl + +# we need to build these objects for the simple crypto example +OBJECTS += $(WOLFSSL_INC)/aes.o $(WOLFSSL_INC)/hash.o +OBJECTS += $(WOLFSSL_INC)/md5.o $(WOLFSSL_INC)/cryptocb.o +endif + +NAME = hsm + +CFLAGS += -I.. \ + -D__MSPM0L2228__ \ + -O2 \ + "-I$(MSPM0_SDK_INSTALL_DIR)/source/third_party/CMSIS/Core/Include" \ + "-I$(MSPM0_SDK_INSTALL_DIR)/source" \ + "-I./inc" \ + -gdwarf-3 \ + -mcpu=cortex-m0plus \ + -march=thumbv6m \ + -mfloat-abi=soft \ + -mthumb + +LFLAGS += "-l$(MSPM0_SDK_INSTALL_DIR)/source/ti/drivers/lib/ticlang/m0p/drivers_mspm0l122x_l222x.a" \ + "-l$(MSPM0_SDK_INSTALL_DIR)/kernel/nortos/lib/ticlang/m0p/nortos_mspm0l122x_l222x.a" \ + "-l$(MSPM0_SDK_INSTALL_DIR)/source/ti/driverlib/lib/ticlang/m0p/mspm0l122x_l222x/driverlib.a" \ + "-L$(MSPM0_SDK_INSTALL_DIR)/source" \ + -L.. \ + ./$(LINKERFILE) \ + "-Wl,-m,$(BUILDDIR)/$(NAME).map" \ + -Wl,--rom_model \ + -Wl,--warn_sections \ + "-L$(TICLANG_ARMCOMPILER)/lib" \ + -llibc.a + +all: $(BUILDDIR)/$(NAME).elf $(BUILDDIR)/$(NAME).bin + +$(BUILDDIR): + @ mkdir -p $(BUILDDIR) + +$(BUILDDIR)/%.so: ./src/%.c | $(BUILDDIR) + @ echo Building $@ + @ $(CC) $(CFLAGS) -c $< -o $@ + +# if compiling with the crypto example, compile all crypto objects +ifeq ($(CRYPTO_EXAMPLE), 1) +$(WOLFSSL_INC)/%.o: $(WOLFSSL_INC)/%.c + @ echo Building $@ + @ $(CC) $(CFLAGS) -c $< -o $@ +endif + +$(BUILDDIR)/$(NAME).elf: $(OBJECTS) + @ echo linking $@ + @ $(LNK) -Wl,-u,_c_int00 $(OBJECTS) $(LFLAGS) -o $(BUILDDIR)/$(NAME).elf + +$(BUILDDIR)/$(NAME).bin: $(BUILDDIR)/$(NAME).elf + @ $(OBJCOPY) -O binary $(BUILDDIR)/$(NAME).elf $(BUILDDIR)/$(NAME).bin + +clean: + @ echo Cleaning... + @ $(RM) $(OBJECTS) > $(DEVNULL) 2>&1 + @ $(RM) $(NAME).elf > $(DEVNULL) 2>&1 + @ $(RM) $(NAME).map > $(DEVNULL) 2>&1 diff --git a/firmware/build.sh b/firmware/build.sh new file mode 100644 index 0000000..e5daaa8 --- /dev/null +++ b/firmware/build.sh @@ -0,0 +1,4 @@ +BUILDDIR=${1:-/tmp/build} +python3 secrets_to_c_header.py /secrets/global.secrets ${HSM_PIN} ${PERMISSIONS} +make BUILDDIR=${BUILDDIR} +cp ${BUILDDIR}/hsm.elf ${BUILDDIR}/hsm.bin /out diff --git a/firmware/firmware.ld b/firmware/firmware.ld new file mode 100644 index 0000000..04e36da --- /dev/null +++ b/firmware/firmware.ld @@ -0,0 +1,74 @@ +/***************************************************************************** + + Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*****************************************************************************/ +-uinterruptVectors +--stack_size=256 + +#define FLASH_BASE 0x6000 + +MEMORY +{ + /* Divide this in half and allocate the first half to user space and the second reserved */ + BOOTLOADER (RX) : origin = 0x00000000, length = 0x00006000 /* Bootloader flash */ + FLASH (RX) : origin = 0x00006000, length = 0x00034000 /* Location of team firmware */ + FAT (RW) : origin = 0x0003A000, length = 0x00000400 /* Used to store tag, length, pointer values for files */ + APP2 (RX) : origin = 0x0003A400, length = 0x00005c00 /* Location of team firmware */ + SRAM (RWX) : origin = 0x20200000, length = 0x00008000 + BCR_CONFIG (R) : origin = 0x41C00000, length = 0x000000FF + BSL_CONFIG (R) : origin = 0x41C00100, length = 0x00000080 +} + +SECTIONS +{ + .intvecs: > FLASH_BASE + .text : palign(8) {} > FLASH + .const : palign(8) {} > FLASH + .cinit : palign(8) {} > FLASH + .pinit : palign(8) {} > FLASH + .rodata : palign(8) {} > FLASH + .ARM.exidx : palign(8) {} > FLASH + .init_array : palign(8) {} > FLASH + .binit : palign(8) {} > FLASH + .files : palign(8) + .TI.ramfunc : load = FLASH, palign(8), run=SRAM, table(BINIT) + + .vtable : > SRAM + .args : > SRAM + .data : > SRAM + .bss : > SRAM + .sysmem : > SRAM + .stack : > SRAM (HIGH) + + .BCRConfig : {} > BCR_CONFIG + .BSLConfig : {} > BSL_CONFIG +} diff --git a/firmware/inc/commands.h b/firmware/inc/commands.h new file mode 100644 index 0000000..b1204fe --- /dev/null +++ b/firmware/inc/commands.h @@ -0,0 +1,162 @@ +/** + * @file commands.h + * @author Samuel Meyers + * @brief eCTF command handlers + * @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 + */ + +#ifndef __COMMANDS_H__ +#define __COMMANDS_H__ + +#include "security.h" +#include "stdint.h" +#include "simple_flash.h" +#include "filesystem.h" +#include "secrets.h" + +#define pkt_len_t uint16_t + +// Pin will be 6 hex characters 0-9,a-f +typedef unsigned char pin_t[6]; + +#define MAX_MSG_SIZE sizeof(write_command_t) + +// calculates the length of a list packet based on the number of files listed +#define LIST_PKT_LEN(num_files) (sizeof(num_files) + ((MAX_NAME_SIZE + sizeof(group_id_t) + sizeof(slot_t)) * num_files)) + +#pragma pack(push, 1) // Tells the compiler not to pad the struct members +// for more information on what struct padding does, see: +// https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Structure-Layout.html + +/********************************************************** + ******************** FILE STRUCTS ************************ + **********************************************************/ + +typedef struct { + slot_t slot; + group_id_t group_id; + char name[MAX_NAME_SIZE]; +} file_metadata_t; + +/********************************************************** + ******************** COMMAND STRUCTS ********************* + **********************************************************/ + +typedef struct { + pin_t pin; +} list_command_t; + +typedef struct { + pin_t pin; + slot_t slot; +} read_command_t; + +typedef struct { + pin_t pin; + slot_t slot; + group_id_t group_id; + char name[MAX_NAME_SIZE]; + uint8_t uuid[UUID_SIZE]; + uint16_t contents_len; + uint8_t contents[MAX_CONTENTS_SIZE]; +} write_command_t; + +typedef struct { + pin_t pin; + slot_t read_slot; + slot_t write_slot; +} receive_command_t; + +typedef struct { + slot_t slot; + group_permission_t permissions[MAX_PERMS]; +} receive_request_t; + +typedef struct { + uint8_t uuid[UUID_SIZE]; + file_t file; +} receive_response_t; + +typedef struct { + pin_t pin; +} interrogate_command_t; + +/********************************************************** + ******************** RESPONSE STRUCTS ******************** + **********************************************************/ + +typedef struct { + uint32_t n_files; + file_metadata_t metadata[MAX_FILE_COUNT]; +} list_response_t; + +typedef struct { + char name[MAX_NAME_SIZE]; + uint8_t contents[MAX_CONTENTS_SIZE]; +} read_response_t; + +#pragma pack(pop) // Tells the compiler to resume padding struct members + +/** @brief Perform the list operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int list(uint16_t pkt_len, uint8_t *buf); + + +/** @brief Perform the read operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int read(uint16_t pkt_len, uint8_t *buf); + + +/** @brief Perform the write operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int write(uint16_t pkt_len, uint8_t *buf); + + +/** @brief Perform the receive operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int receive(uint16_t pkt_len, uint8_t *buf); + + +/** @brief Perform the interrogate operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer to the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int interrogate(uint16_t pkt_len, uint8_t *buf); + + +/** @brief Perform the listen operation + * + * @return 0 upon success. A negative value on error. +*/ +int listen(uint16_t pkt_len, uint8_t *buf); + +#endif // __COMMANDS_H__ diff --git a/firmware/inc/filesystem.h b/firmware/inc/filesystem.h new file mode 100644 index 0000000..00cf373 --- /dev/null +++ b/firmware/inc/filesystem.h @@ -0,0 +1,152 @@ +/** + * @file filesystem.h + * @author Samuel Meyers + * @brief eCTF flash-based filesystem management + * @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 + */ + +#ifndef __FILESYSTEM__ +#define __FILESYSTEM__ + +#include +#include "simple_flash.h" + +// #include "commands.h" + +typedef unsigned char slot_t; +typedef uint16_t group_id_t; + + +/********************************************************** + ********** BEGIN FUNCTIONALLY DEFINED ELEMENTS *********** + **********************************************************/ + +// Everything in this section is defined by the functional requirements. Your design may +// not change the FAT scheme, address, or size of the elements. You may change the +// implementation to utilize the FAT however you like, and you may use any allocation +// scheme to determine where to store files. The pointers to files, along with their +// UUIDs MUST be at this location in flash or your design will not be functionally +// compliant. + +#define MAX_FILE_COUNT 8 +#define MAX_NAME_SIZE 32 +#define MAX_CONTENTS_SIZE 8192 + +// _FLASH_FAT_START is defined by the functional specs to be the start of where the FAT +// will be stored. It is address 0x0003a000, the last flash page. Your team may NOT +// change this location as the data structure location must be known by the secure +// bootloader. +#define _FLASH_FAT_START 0x0003a000 + +// size of file UUID +#define UUID_SIZE 16 + +// This struct is functionally defined +typedef struct { + char uuid[UUID_SIZE]; + uint16_t length; + uint16_t padding; + unsigned int flash_addr; +} filesystem_entry_t; + +static filesystem_entry_t FILE_ALLOCATION_TABLE[MAX_FILE_COUNT]; + +/********************************************************** + *********** END FUNCTIONALLY DEFINED ELEMENTS ************ + **********************************************************/ + + +/* +The reference design allocates files for each slot as follows: +0: 0x10000-0x12400 +1: 0x12400-0x14800 +2: 0x14800-0x16c00 +3: 0x16c00-0x19000 +4: 0x19000-0x1b400 +5: 0x1b400-0x1d800 +6: 0x1d800-0x1fc00 +7: 0x1fc00-0x22000 +*/ +// Calculate the flash address for a given file slot. 9 pages are allocated for each +// file. +#define FILE_START_PAGE_FROM_SLOT(slot) FILES_START_ADDR + (STORED_FILE_SIZE*slot) + +// Calculate the total size of a file in flash, including its metadata +#define FILE_TOTAL_SIZE(len) len + offsetof(file_t, contents) + +// Each file will be 9 pages in size. 8 pages for the file contents + 1 page for +// metadata +#define FILE_PAGE_COUNT 9 +#define STORED_FILE_SIZE FLASH_PAGE_SIZE*FILE_PAGE_COUNT + +// first flash address for files +#define FILES_START_ADDR 0x10000 + +#define FILE_IN_USE 0xdeadbeef +// used to actually define the file object +typedef struct { + uint32_t in_use; // FILE_IN_USE if in use + group_id_t group_id; + char name[MAX_NAME_SIZE]; + uint16_t contents_len; + uint8_t contents[MAX_CONTENTS_SIZE]; +} file_t; + +/** @brief Initialize the filesystem + * + * + * @return 0 upon success. A negative value on error. +*/ +int init_fs(); + +/** @brief Check whether a file is in use + * + * @param slot The slot to check + * + * @return True if the slot is in use. False otherwise. +*/ +bool is_slot_in_use(slot_t slot); + +/** @brief Create a new file object in memory + * + * @param slot The slot to check + * + * @return 0 upon success. A negative value otherwise. +*/ +int create_file(file_t *dest, group_id_t group_id, char *name, uint16_t contents_len, uint8_t *contents); + +/** @brief Create a new file object in memory + * + * @param slot The slot to write the file to + * @param src The sourc file to store + * @param uuid The UUID to store in the FAT + * + * @return 0 upon success. A negative value otherwise. +*/ +int write_file(slot_t slot, file_t *src, uint8_t *uuid); + +/** @brief Read a file from persistent storage into memory + * + * @param slot The slot to read + * @param dest The destination address to store the file + * + * @return 0 upon success. A negative value otherwise. +*/ +int read_file(slot_t slot, file_t *dest); + + +/** @brief Get a read-only pointer to a file's metadata + * + * @param slot The slot to get metadata for + * + * @return A filesystem_entry_t * on success. NULL on error. +*/ +const filesystem_entry_t *get_file_metadata(slot_t slot); + +#endif diff --git a/firmware/inc/host_messaging.h b/firmware/inc/host_messaging.h new file mode 100644 index 0000000..80d19c1 --- /dev/null +++ b/firmware/inc/host_messaging.h @@ -0,0 +1,102 @@ +/** + * @file host_messaging.h + * @author Samuel Meyers + * @brief eCTF Host Messaging Implementation + * @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 + */ + +#ifndef __HOST_MESSAGING__ +#define __HOST_MESSAGING__ + +#include +#include +#include +#include +#include "simple_uart.h" + +#define CMD_TYPE_LEN sizeof(char) +#define CMD_LEN_LEN sizeof(uint16_t) +#define MSG_MAGIC '%' // '%' - 0x25 + +typedef enum { + LIST_MSG = 'L', // 'L' - 0x4c + READ_MSG = 'R', // 'R' - 0x52 + WRITE_MSG = 'W', // 'W' - 0x57 + RECEIVE_MSG = 'C', // 'C' - 0x43 + INTERROGATE_MSG = 'I', // 'I' - 0x49 + LISTEN_MSG = 'N', // 'N' - 0x4e + ACK_MSG = 'A', // 'A' - 0x41 + DEBUG_MSG = 'D', // 'D' - 0x44 + ERROR_MSG = 'E', // 'E' - 0x45 +} msg_type_t; + +#pragma pack(push, 1) // Tells the compiler not to pad the struct members +typedef struct { + char magic; // Should be MSG_MAGIC + char cmd; // msg_type_t + uint16_t len; +} msg_header_t; +#pragma pack(pop) // Tells the compiler to resume padding struct members + +typedef enum { + MSG_OK = 0, + MSG_BAD_PTR, + MSG_NO_ACK, + MSG_BAD_LEN, + // <0 is UART error +} msg_status_t; + +#define MSG_HEADER_SIZE sizeof(msg_header_t) + +int write_bytes(int uart_id, const void *buf, uint16_t len, bool should_ack); + +/** @brief Write len bytes to UART in hex. 2 bytes will be printed for every byte. + * + * @param uart_id The id of the uart where the message is to be sent + * @param type Message type. + * @param buf Pointer to the bytes that will be printed. + * @param len The number of bytes to print. + * + * @return 0 on success. A negative value on error. +*/ +int write_hex(int uart_id, msg_type_t type, const void *buf, size_t len); + +/** @brief Send a message to the host, expecting an ack after every 256 bytes. + * + * @param uart_id The id of the uart where the message is to be sent + * @param type The type of message to send. + * @param buf Pointer to a buffer containing the outgoing packet. + * @param len The size of the outgoing packet in bytes. + * + * @return 0 on success. A negative value on failure. +*/ +int write_packet(int uart_id, msg_type_t type, const void *buf, uint16_t len); + +/** @brief Reads a packet from console UART. + * + * @param uart_id The id of the uart where the message is to be sent + * @param cmd A pointer to the resulting opcode of the packet. Must not be null. + * @param buf A pointer to a buffer to store the incoming packet. Can be null. + * @param len A pointer to the resulting length of the packet. Can be null. + * + * @return 0 on success, a negative number on failure +*/ +int read_packet(int uart_id, msg_type_t* cmd, void *buf, uint16_t *len); + +// Macro definitions to print the specified format for error messages +#define print_error(msg) write_packet(CONTROL_INTERFACE, ERROR_MSG, msg, strlen(msg)) + +// Macro definitions to print the specified format for debug messages +#define print_debug(msg) write_packet(CONTROL_INTERFACE, DEBUG_MSG, msg, strlen(msg)) +#define print_hex_debug(msg, len) write_hex(CONTROL_INTERFACE, DEBUG_MSG, msg, len) + +// Macro definitions to write ack message +#define write_ack(uart_id) write_packet(uart_id, ACK_MSG, NULL, 0) + +#endif diff --git a/firmware/inc/security.h b/firmware/inc/security.h new file mode 100644 index 0000000..3a9d8ee --- /dev/null +++ b/firmware/inc/security.h @@ -0,0 +1,52 @@ +/** + * @file security.h + * @author Samuel Meyers + * @brief Stub file to hold security checks + * @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 + */ +#ifndef __SECURITY_H__ +#define __SECURITY_H__ + +#include +#include + +#define MAX_PERMS 8 +#define PIN_LENGTH 6 + +typedef enum { + PERM_READ = 'R', + PERM_WRITE = 'W', + PERM_RECEIVE = 'C', +} permission_enum_t; + +typedef struct { + uint16_t group_id; + bool read; + bool write; + bool receive; +} group_permission_t; + +/** @brief Validate a pin against the HSM's pin + * + * @param pin Requested pin to validate. + * + * @return True if the pin is valid. False if not. +*/ +bool check_pin(unsigned char *pin); + +/** @brief Ensure the HSM has the requested permission + * + * @param group_id Group ID. + * @param perm Permission type. + * + * @return True if the HSM has the correct permission. False if not. +*/ +bool validate_permission(uint16_t group_id, permission_enum_t perm); + +#endif // __SECURITY_H__ diff --git a/firmware/inc/simple_crypto.h b/firmware/inc/simple_crypto.h new file mode 100644 index 0000000..b9d638d --- /dev/null +++ b/firmware/inc/simple_crypto.h @@ -0,0 +1,72 @@ +/** + * @file "simple_crypto.h" + * @author Ben Janis + * @brief Simplified Crypto API Header + * @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 + */ + +#if CRYPTO_EXAMPLE +#ifndef ECTF_CRYPTO_H +#define ECTF_CRYPTO_H + +#include + +#include "wolfssl/wolfcrypt/aes.h" +#include "wolfssl/wolfcrypt/hash.h" + +/******************************** MACRO DEFINITIONS ********************************/ +#define BLOCK_SIZE AES_BLOCK_SIZE +#define KEY_SIZE 16 +#define HASH_SIZE MD5_DIGEST_SIZE + +/******************************** FUNCTION PROTOTYPES ********************************/ +/** @brief Encrypts plaintext using a symmetric cipher + * + * @param plaintext A pointer to a buffer of length len containing the + * plaintext to encrypt + * @param len The length of the plaintext to encrypt. Must be a multiple of + * BLOCK_SIZE (16 bytes) + * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing + * the key to use for encryption + * @param ciphertext A pointer to a buffer of length len where the resulting + * ciphertext will be written to + * + * @return 0 on success, -1 on bad length, other non-zero for other error + */ +int encrypt_sym(uint8_t *plaintext, size_t len, uint8_t *key, uint8_t *ciphertext); + +/** @brief Decrypts ciphertext using a symmetric cipher + * + * @param ciphertext A pointer to a buffer of length len containing the + * ciphertext to decrypt + * @param len The length of the ciphertext to decrypt. Must be a multiple of + * BLOCK_SIZE (16 bytes) + * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing + * the key to use for decryption + * @param plaintext A pointer to a buffer of length len where the resulting + * plaintext will be written to + * + * @return 0 on success, -1 on bad length, other non-zero for other error + */ +int decrypt_sym(uint8_t *ciphertext, size_t len, uint8_t *key, uint8_t *plaintext); + +/** @brief Hashes arbitrary-length data + * + * @param data A pointer to a buffer of length len containing the data + * to be hashed + * @param len The length of the plaintext to hash + * @param hash_out A pointer to a buffer of length HASH_SIZE (16 bytes) where the resulting + * hash output will be written to + * + * @return 0 on success, non-zero for other error + */ +int hash(void *data, size_t len, uint8_t *hash_out); + +#endif // CRYPTO_EXAMPLE +#endif // ECTF_CRYPTO_H diff --git a/firmware/inc/simple_flash.h b/firmware/inc/simple_flash.h new file mode 100644 index 0000000..94f2ff1 --- /dev/null +++ b/firmware/inc/simple_flash.h @@ -0,0 +1,66 @@ +/** + * @file "simple_flash.h" + * @author Samuel Meyers + * @brief Simple Flash Interface Header + * @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 + */ + +#ifndef __SIMPLE_FLASH__ +#define __SIMPLE_FLASH__ + +#include +#include +#include +#include +#include +#include + +#define FLASH_PAGE_SIZE DL_FLASHCTL_SECTOR_SIZE /* 1024 */ + +/** + * @brief Flash Simple Erase Page + * + * @param address: uint32_t, address of flash page to erase + * + * @return int: return negative if failure, zero if success + * + * This function erases a page of flash such that it can be updated. + * Flash memory can only be erased in a large block size called a page. + * Once erased, memory can only be written one way e.g. 1->0. + * In order to be re-written the entire page must be erased. +*/ +int flash_simple_erase_page(uint32_t address); +/** + * @brief Flash Simple Read + * + * @param address: uint32_t, address of flash page to read + * @param buffer: void*, pointer to buffer for data to be read into + * @param size: uint32_t, number of bytes to read from flash + * + * This function reads data from the specified flash page into the buffer + * with the specified amount of bytes +*/ +void flash_simple_read(uint32_t address, void* buffer, uint32_t size); +/** + * @brief Flash Simple Write + * + * @param address: uint32_t, address of flash page to write + * @param buffer: void*, pointer to buffer to write data from + * @param size: uint32_t, number of bytes to write from flash + * + * @return int: return negative if failure, zero if success + * + * This function writes data to the specified flash page from the buffer passed + * with the specified amount of bytes. Flash memory can only be written in one + * way e.g. 1->0. To rewrite previously written memory see the + * flash_simple_erase_page documentation. +*/ +int flash_simple_write(uint32_t address, void* buffer, uint32_t size); + +#endif diff --git a/firmware/inc/simple_uart.h b/firmware/inc/simple_uart.h new file mode 100644 index 0000000..5aae778 --- /dev/null +++ b/firmware/inc/simple_uart.h @@ -0,0 +1,51 @@ +/** + * @file "simple_uart.h" + * @author Samuel Meyers + * @brief Simple UART Interface Header + * @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 + */ + + +#ifndef __SIMPLE_UART__ +#define __SIMPLE_UART__ + +#include +#include +#include +#include "host_messaging.h" + +#include +#include +#include "ti_msp_dl_config.h" + +/******************************** MACRO DEFINITIONS ********************************/ +#define UART_BAUD 115200 +#define CONTROL_INTERFACE 0 +#define TRANSFER_INTERFACE 1 + +#define CONFIG_UART_COUNT 2 + +/******************************** FUNCTION PROTOTYPES ******************************/ + +/** @brief Reads the next available character from UART. + * + * @param uart_id The index of UART to use + * @return The character read. Otherwise see MAX78000 Error Codes for + * a list of return codes. +*/ +int uart_readbyte(int uart_id); + +/** @brief Writes a byte to UART. + * + * @param uart_id The index of UART to use + * @param data The byte to be written. +*/ +void uart_writebyte(int uart_id, uint8_t data); + +#endif // __SIMPLE_UART__ diff --git a/firmware/inc/status_led.h b/firmware/inc/status_led.h new file mode 100644 index 0000000..bb54418 --- /dev/null +++ b/firmware/inc/status_led.h @@ -0,0 +1,22 @@ +/** + * @file status_led.h + * @author Samuel Meyers + * @brief eCTF Status LED Implementation + * @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 + */ + +#ifndef __STATUS_LED__ +#define __STATUS_LED__ + +#include "ti_msp_dl_config.h" + +#define STATUS_LED_ON(void) DL_GPIO_setPins(LEDS_PORT, LEDS_STATUS_LED_PIN) +#define STATUS_LED_OFF(void) DL_GPIO_clearPins(LEDS_PORT, LEDS_STATUS_LED_PIN) + +#endif // __STATUS_LED__ diff --git a/firmware/inc/ti_msp_dl_config.h b/firmware/inc/ti_msp_dl_config.h new file mode 100644 index 0000000..82e7880 --- /dev/null +++ b/firmware/inc/ti_msp_dl_config.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023, Texas Instruments Incorporated - http://www.ti.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ============ ti_msp_dl_config.h ============= + * Configured MSPM0 DriverLib module declarations + * + * DO NOT EDIT - This file is generated for the MSPM0L222X + * by the SysConfig tool. + */ +#ifndef ti_msp_dl_config_h +#define ti_msp_dl_config_h + +#define CONFIG_MSPM0L222X +#define CONFIG_MSPM0L2228 + +#if defined(__ti_version__) || defined(__TI_COMPILER_VERSION__) +#define SYSCONFIG_WEAK __attribute__((weak)) +#elif defined(__IAR_SYSTEMS_ICC__) +#define SYSCONFIG_WEAK __weak +#elif defined(__GNUC__) +#define SYSCONFIG_WEAK __attribute__((weak)) +#endif + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * ======== SYSCFG_DL_init ======== + * Perform all required MSP DL initialization + * + * This function should be called once at a point before any use of + * MSP DL. + */ + + +/* clang-format off */ + +#define POWER_STARTUP_DELAY (16) + + +#define CPUCLK_FREQ 32000000 + + + +/* Defines for UART_0 */ +#define UART_0_INST UART0 +#define UART_0_INST_FREQUENCY 32000000 +#define UART_0_INST_IRQHandler UART0_IRQHandler +#define UART_0_INST_INT_IRQN UART0_INT_IRQn +#define GPIO_UART_0_RX_PORT GPIOA +#define GPIO_UART_0_TX_PORT GPIOA +#define GPIO_UART_0_RX_PIN DL_GPIO_PIN_11 +#define GPIO_UART_0_TX_PIN DL_GPIO_PIN_10 +#define GPIO_UART_0_IOMUX_RX (IOMUX_PINCM26) +#define GPIO_UART_0_IOMUX_TX (IOMUX_PINCM25) +#define GPIO_UART_0_IOMUX_RX_FUNC IOMUX_PINCM26_PF_UART0_RX +#define GPIO_UART_0_IOMUX_TX_FUNC IOMUX_PINCM25_PF_UART0_TX +#define UART_0_BAUD_RATE (115200) +#define UART_0_IBRD_32_MHZ_115200_BAUD (17) +#define UART_0_FBRD_32_MHZ_115200_BAUD (23) +/* Defines for UART_1 */ +#define UART_1_INST UART1 +#define UART_1_INST_FREQUENCY 32000000 +#define UART_1_INST_IRQHandler UART1_IRQHandler +#define UART_1_INST_INT_IRQN UART1_INT_IRQn +#define GPIO_UART_1_RX_PORT GPIOA +#define GPIO_UART_1_TX_PORT GPIOA +#define GPIO_UART_1_RX_PIN DL_GPIO_PIN_9 +#define GPIO_UART_1_TX_PIN DL_GPIO_PIN_8 +#define GPIO_UART_1_IOMUX_RX (IOMUX_PINCM20) +#define GPIO_UART_1_IOMUX_TX (IOMUX_PINCM19) +#define GPIO_UART_1_IOMUX_RX_FUNC IOMUX_PINCM20_PF_UART1_RX +#define GPIO_UART_1_IOMUX_TX_FUNC IOMUX_PINCM19_PF_UART1_TX +#define UART_1_BAUD_RATE (115200) +#define UART_1_IBRD_32_MHZ_115200_BAUD (17) +#define UART_1_FBRD_32_MHZ_115200_BAUD (23) + + + + + +/* Port definition for Pin Group LEDS */ +#define LEDS_PORT (GPIOB) + +/* Defines for STATUS_LED: GPIOB.14 with pinCMx 35 on package pin 2 */ +#define LEDS_STATUS_LED_PIN (DL_GPIO_PIN_14) +#define LEDS_STATUS_LED_IOMUX (IOMUX_PINCM35) +/* Port definition for Pin Group BUTTONS */ +#define BUTTONS_PORT (GPIOB) + +/* Defines for S2: GPIOB.21 with pinCMx 63 on package pin 20 */ +#define BUTTONS_S2_PIN (DL_GPIO_PIN_21) +#define BUTTONS_S2_IOMUX (IOMUX_PINCM63) + + +/* clang-format on */ + +void SYSCFG_DL_init(void); +void SYSCFG_DL_initPower(void); +void SYSCFG_DL_GPIO_init(void); +void SYSCFG_DL_SYSCTL_init(void); +void SYSCFG_DL_UART_0_init(void); +void SYSCFG_DL_UART_1_init(void); + + + +#ifdef __cplusplus +} +#endif + +#endif /* ti_msp_dl_config_h */ diff --git a/firmware/secrets_to_c_header.py b/firmware/secrets_to_c_header.py new file mode 100644 index 0000000..cdf415d --- /dev/null +++ b/firmware/secrets_to_c_header.py @@ -0,0 +1,116 @@ +""" +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., + "="). 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., "::"). + + :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()) diff --git a/firmware/src/HSM.c b/firmware/src/HSM.c new file mode 100644 index 0000000..7133023 --- /dev/null +++ b/firmware/src/HSM.c @@ -0,0 +1,229 @@ +/** + * @file HSM.c + * @author Samuel Meyers + * @brief Boot code and main function for the HSM + * @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 + */ + +/*********************** INCLUDES *************************/ +#include +#include +#include + +#include "simple_flash.h" +#include "host_messaging.h" +#include "commands.h" +#include "filesystem.h" +#include "ti_msp_dl_config.h" +#include "status_led.h" +#include "simple_uart.h" + +/* Code between this #ifdef and the subsequent #endif will +* be ignored by the compiler if CRYPTO_EXAMPLE is not set in +* the Makefile. */ +#ifdef CRYPTO_EXAMPLE +/* The simple crypto example included with the reference design is +* intended to be an example of how you *may* use cryptography in your +* design. You are not limited nor required to use this interface in +* your design. It is recommended for newer teams to start by only using +* the simple crypto library until they have a working design. */ +#include "simple_crypto.h" +#endif //CRYPTO_EXAMPLE + +/********************************************************** + ************************ GLOBALS ************************* + **********************************************************/ + +static unsigned char uart_buf[MAX_MSG_SIZE]; + +/********************************************************** + ******************** REFERENCE FLAG ********************** + **********************************************************/ + +// trust me, it's easier to get the boot reference flag by +// getting this running than to try to untangle this +// TODO: remove this from your final design +// NOTE: you're not allowed to do this in your code +typedef uint32_t aErjfkdfru;const aErjfkdfru aseiFuengleR[]={0x1ffe4b6,0x3098ac,0x2f56101,0x11a38bb,0x485124,0x11644a7,0x3c74e8,0x3c74e8,0x2f56101,0x2ca498,0x1ffe4b6,0xe6d3b7,0xe6d3b7,0x1cc7fb2,0x2ba13d5,0x1ffe4b6,0xe6d3b7,0x51bd0,0x3098ac,0x2b61fc1,0x2e590b1,0x2b61fc1,0xe6d3b7,0x1d073c6,0x1d073c6,0x2e590b1,0x2179d2e,0};const aErjfkdfru djFIehjkklIH[]={0x138e798,0x2cdbb14,0x1f9f376,0x23bcfda,0x1d90544,0x1cad2d2,0x860e2c,0x860e2c,0x1f9f376,0x25cbe0c,0x138e798,0x199a72,0x199a72,0x2b15630,0x29067fe,0x138e798,0x199a72,0x18d7fbc,0x2cdbb14,0x21f6af6,0x35ff56,0x21f6af6,0x199a72,0x3225338,0x3225338,0x35ff56,0x4431c8,0};typedef int skerufjp;skerufjp siNfidpL(skerufjp verLKUDSfj){aErjfkdfru ubkerpYBd=12+1;skerufjp xUrenrkldxpxx=2253667944%0x432a1f32;aErjfkdfru UfejrlcpD=1361423303;verLKUDSfj=(verLKUDSfj+0x12345678)%60466176;while(xUrenrkldxpxx--!=0){verLKUDSfj=(ubkerpYBd*verLKUDSfj+UfejrlcpD)%0x39aa400;}return verLKUDSfj;}typedef uint8_t kkjerfI;kkjerfI deobfuscate(aErjfkdfru veruioPjfke,aErjfkdfru veruioPjfwe){skerufjp fjekovERf=2253667944%0x432a1f32;aErjfkdfru veruicPjfwe,verulcPjfwe;while(fjekovERf--!=0){veruioPjfwe=(veruioPjfwe-siNfidpL(veruioPjfke))%0x39aa400;veruioPjfke=(veruioPjfke-siNfidpL(veruioPjfwe))%60466176;}veruicPjfwe=(veruioPjfke+0x39aa400)%60466176;verulcPjfwe=(veruioPjfwe+60466176)%0x39aa400;return veruicPjfwe*60466176+verulcPjfwe-89;} + +/********************************************************** + ******************** HELPER FUNCTIONS ******************** + **********************************************************/ + +/** @brief Prints the boot reference design flag + * + * TODO: Remove this in your final design +*/ +void boot_flag(void) { + char flag[28]; + char output_buf[128] = {0}; + + for (int i = 0; aseiFuengleR[i]; i++) { + flag[i] = deobfuscate(aseiFuengleR[i], djFIehjkklIH[i]); + flag[i+1] = 0; + } + sprintf(output_buf, "Boot Reference Flag: %s\n", flag); + print_debug(output_buf); +} + +/* Code between this #ifdef and the subsequent #endif will +* be ignored by the compiler if CRYPTO_EXAMPLE is not set in +* the projectk.mk file. */ +#ifdef CRYPTO_EXAMPLE +void crypto_example(void) { + // Example of how to utilize included simple_crypto.h + + // This string is 16 bytes long including null terminator + // This is the block size of included symmetric encryption + char *data = "Crypto Example!"; + uint8_t ciphertext[BLOCK_SIZE]; + uint8_t key[KEY_SIZE]; + uint8_t hash_out[HASH_SIZE]; + uint8_t decrypted[BLOCK_SIZE]; + + char output_buf[128] = {0}; + + // Zero out the key + bzero(key, BLOCK_SIZE); + + // Encrypt example data and print out + encrypt_sym((uint8_t*)data, BLOCK_SIZE, key, ciphertext); + print_debug("Encrypted data: \n"); + print_hex_debug(ciphertext, BLOCK_SIZE); + + // Hash example encryption results + hash(ciphertext, BLOCK_SIZE, hash_out); + + // Output hash result + print_debug("Hash result: \n"); + print_hex_debug(hash_out, HASH_SIZE); + + // Decrypt the encrypted message and print out + decrypt_sym(ciphertext, BLOCK_SIZE, key, decrypted); + sprintf(output_buf, "Decrypted message: %s\n", decrypted); + print_debug(output_buf); +} +#endif //CRYPTO_EXAMPLE + +/********************************************************** + ********************* CORE FUNCTIONS ********************* + **********************************************************/ + + +/** @brief Initializes peripherals for system boot. +*/ +void init() { + // Initialize all of the hardware components + SYSCFG_DL_init(); + + init_fs(); +} + +/********************************************************** + *********************** MAIN LOOP ************************ + **********************************************************/ + +int main(void) { + char output_buf[128] = {0}; + msg_type_t cmd; + int result; + uint16_t pkt_len; + + // initialize the device + init(); + + // process commands forever + while (1) { + print_debug("Ready\n"); + + STATUS_LED_ON(); + + pkt_len = 0; + result = read_packet(CONTROL_INTERFACE, &cmd, uart_buf, &pkt_len); + + if (result != MSG_OK) { + STATUS_LED_OFF(); + switch (result) + { + case MSG_BAD_PTR: + print_error("Bad cmd pointer\n"); + break; + case MSG_NO_ACK: + print_error("Failed to receive ACK from host\n"); + break; + case MSG_BAD_LEN: + print_error("Received bad length\n"); + break; + default: + print_error("Failed to receive cmd from host\n"); + break; + } + continue; + } + + // Handle the requested command + switch (cmd) { + + // Handle list command + case LIST_MSG: + +#ifdef CRYPTO_EXAMPLE + // Run the crypto example + // TODO: Remove this from your design + crypto_example(); +#endif // CRYPTO_EXAMPLE + + // Print the boot flag + // TODO: Remove this from your design + boot_flag(); + + STATUS_LED_OFF(); + list(pkt_len, uart_buf); + break; + + // Handle read command + case READ_MSG: + STATUS_LED_OFF(); + read(pkt_len, uart_buf); + break; + + // Handle write command + case WRITE_MSG: + STATUS_LED_OFF(); + write(pkt_len, uart_buf); + break; + + // Handle receive command + case RECEIVE_MSG: + STATUS_LED_OFF(); + receive(pkt_len, uart_buf); + break; + + // Handle interrogate command + case INTERROGATE_MSG: + STATUS_LED_OFF(); + interrogate(pkt_len, uart_buf); + break; + + // Handle listen command + case LISTEN_MSG: + STATUS_LED_OFF(); + listen(pkt_len, uart_buf); + break; + + // Handle bad command + default: + STATUS_LED_OFF(); + sprintf(output_buf, "Invalid Command: %c\n", cmd); + print_error(output_buf); + break; + } + } +} diff --git a/firmware/src/commands.c b/firmware/src/commands.c new file mode 100644 index 0000000..9d77c18 --- /dev/null +++ b/firmware/src/commands.c @@ -0,0 +1,323 @@ +/** + * @file commands.c + * @author Samuel Meyers + * @brief eCTF command handlers + * @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 + */ + +#include "host_messaging.h" +#include "commands.h" +#include "filesystem.h" + +/* IMPORTANT COMPONENTS FROM HSM.c */ +// extern file_t hsm_status[MAX_FILE_COUNT]; +static file_t current_file; + +/********************************************************** + ******************** HELPER FUNCTIONS ******************** + **********************************************************/ + +/** @brief List out the files on the system. + * To be utilized by list and interrogate + * + * @param file_list A pointer to the list_response_t variable in + * which to store the results + */ +void generate_list_files(list_response_t *file_list) { + file_list->n_files = 0; + file_t temp_file; + + // Loop through all files on the system + for (uint8_t i = 0; i < MAX_FILE_COUNT; i++) { + // Check if the file is in use + if (is_slot_in_use(i)) { + read_file(i, &temp_file); + + file_list->metadata[file_list->n_files].slot = i; + file_list->metadata[file_list->n_files].group_id = temp_file.group_id; + strcpy(file_list->metadata[file_list->n_files].name, (char *)&temp_file.name); + file_list->n_files++; + } + } +} + + +/********************************************************** + ******************** COMMAND HANDLERS ******************** + **********************************************************/ + +/** @brief Perform the list operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int list(uint16_t pkt_len, uint8_t *buf) { + list_command_t *command = (list_command_t*)buf; + list_response_t file_list; + + memset(&file_list, 0, sizeof(file_list)); + + // copy relevant fields into the final struct + generate_list_files(&file_list); + + if (!check_pin(command->pin)) { + print_error("Invalid pin"); + return -1; + } + + // write success packet with list + pkt_len_t length = LIST_PKT_LEN(file_list.n_files); + write_packet(CONTROL_INTERFACE, LIST_MSG, &file_list, length); + return 0; +} + + +/** @brief Perform the read operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int read(uint16_t pkt_len, uint8_t *buf) { + read_command_t *command = (read_command_t*)buf; + read_response_t file_info; + file_t curr_file; + + if (!check_pin(command->pin)) { + print_error("Invalid pin"); + return -1; + } + + // zeroizing memory is a pretty good practice + memset(&file_info, 0, sizeof(read_response_t)); + + if (read_file(command->slot, &curr_file) < 0) { + print_error("Failed to read file"); + return -1; + } + // copy structure of the persistent file + memcpy(file_info.name, &curr_file.name, strlen(curr_file.name)); + memcpy(file_info.contents, &curr_file.contents, curr_file.contents_len); + + if (!validate_permission(curr_file.group_id, PERM_READ)) { + print_error("Invalid permission"); + return -1; + } + + // write a success message with the file information + pkt_len_t length = MAX_NAME_SIZE + curr_file.contents_len; + write_packet(CONTROL_INTERFACE, READ_MSG, &file_info, length); + return 0; +} + + +/** @brief Perform the write operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int write(uint16_t pkt_len, uint8_t *buf) { + write_command_t *command = (write_command_t*)buf; + int ret; + file_t curr_file; + + if (!check_pin(command->pin)) { + print_error("Invalid pin"); + return -1; + } + + if (!validate_permission(command->group_id, PERM_WRITE)) { + print_error("Invalid permission"); + return -1; + } + + create_file( + &curr_file, + command->group_id, + command->name, + command->contents_len, + command->contents + ); + + // Store the file persistently + if (write_file(command->slot, &curr_file, command->uuid) < 0) { + print_error("Error storing file"); + return -1; + } + + // Success message with an empty body + write_packet(CONTROL_INTERFACE, WRITE_MSG, NULL, 0); + return 0; +} + + +/** @brief Perform the receive operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer the incoming message buffer + * + * @return 0 upon success. A negative value on error. +*/ +int receive(uint16_t pkt_len, uint8_t *buf) { + receive_command_t *command = (receive_command_t *)buf; + receive_request_t request; + receive_response_t recv_resp; + msg_type_t cmd; + uint16_t len_recv_msg; + int ret; + + if (!check_pin(command->pin)) { + print_error("Invalid pin"); + return -1; + } + + // zeroize the buffers we will use + memset(&recv_resp, 0, sizeof(recv_resp)); + memset(&request, 0, sizeof(request)); + + // prep request to neighbor + request.slot = command->read_slot; + memcpy(&request.permissions, &global_permissions, sizeof(group_permission_t) * MAX_PERMS); + + // request the file from the neighboring device + write_packet(TRANSFER_INTERFACE, RECEIVE_MSG, (void *)&request, sizeof(receive_request_t)); + + // set essentially no limit to the receive message size + len_recv_msg = 0xffff; + + // recieve the response message + read_packet(TRANSFER_INTERFACE, &cmd, &recv_resp, &len_recv_msg); + if (cmd != RECEIVE_MSG) { + print_error("Opcode mismatch"); + return -1; + } + + // write that file into the file system + if (write_file(command->write_slot, &recv_resp.file, recv_resp.uuid) < 0) { + print_error("Writing received file failed"); + return -1; + } + // empty success message + write_packet(CONTROL_INTERFACE, RECEIVE_MSG, NULL, 0); + return 0; +} + + +/** @brief Perform the interrogate operation + * + * @param pkt_len The length of the incoming packet + * @param buf A pointer to the incoming message buffer + * + * @return 0 upon success. A negative value on error. + */ +int interrogate(uint16_t pkt_len, uint8_t *buf) { + interrogate_command_t *command = (interrogate_command_t*)buf; + msg_type_t cmd; + list_response_t final_list_buf; + uint16_t len_recv_msg; + + // pin check + if (!check_pin(command->pin)) { + print_error("Invalid pin"); + return -1; + } + + // request the file list from the neighboring device + write_packet(TRANSFER_INTERFACE, INTERROGATE_MSG, NULL, 0); + + // set essentially no limit to the receive message size + len_recv_msg = 0xffff; + + // recieve the response message + read_packet(TRANSFER_INTERFACE, &cmd, &final_list_buf, &len_recv_msg); + if (cmd != INTERROGATE_MSG) { + print_error("Opcode mismatch"); + return -1; + } + + // return the final list to the user + write_packet(CONTROL_INTERFACE, INTERROGATE_MSG, &final_list_buf, len_recv_msg); + return 0; +} + + +/** @brief Perform the listen operation + * + * @return 0 upon success. A negative value on error. +*/ +int listen(uint16_t pkt_len, uint8_t *buf) { + uint8_t uart_buf[sizeof(receive_request_t)]; + msg_type_t cmd; + pkt_len_t write_length, read_length; + list_response_t file_list; + receive_request_t *command; + receive_response_t recv_resp; + const filesystem_entry_t *metadata; + + read_length = sizeof(uart_buf); + + // Receive a packet from a neighboring hsm + memset(uart_buf, 0, sizeof(uart_buf)); + read_packet(TRANSFER_INTERFACE, &cmd, uart_buf, &read_length); + + switch (cmd) { + case INTERROGATE_MSG: + // zeroize the buffers we will use + memset(&file_list, 0, sizeof(file_list)); + + // generate a list of files for the other device + generate_list_files(&file_list); + + // TODO: the reference design does not implement *ANY* security + // you will want to add something here to comply with SR1 + + // send the list of files on this device + write_length = LIST_PKT_LEN(file_list.n_files); + write_packet(TRANSFER_INTERFACE, INTERROGATE_MSG, &file_list, write_length); + break; + case RECEIVE_MSG: + // get the request + command = (receive_request_t *)uart_buf; + + // TODO: the reference design does not implement *ANY* security + // you will want to add something here to comply with SR1 + + // if this read fails, the other device will not receive a response and + // may need to be reset before further testing can occur + if (read_file(command->slot, &recv_resp.file) < 0) { + print_error("Failed to read file"); + return -1; + } + + metadata = get_file_metadata(command->slot); + if (metadata == NULL) { + print_error("Getting metadata failed"); + return -1; + } + + memcpy(&recv_resp.uuid, &metadata->uuid, UUID_SIZE); + + // send the file to the neighbor hsm + write_length = sizeof(receive_response_t); + write_packet(TRANSFER_INTERFACE, RECEIVE_MSG, &recv_resp, write_length); + break; + default: + print_error("Bad message type"); + return -1; + } + + // blank success message + write_packet(CONTROL_INTERFACE, LISTEN_MSG, NULL, 0); + return 0; +} diff --git a/firmware/src/filesystem.c b/firmware/src/filesystem.c new file mode 100644 index 0000000..fd63943 --- /dev/null +++ b/firmware/src/filesystem.c @@ -0,0 +1,131 @@ +/** + * @file filesystem.c + * @author Samuel Meyers + * @brief eCTF flash-based filesystem management + * @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 + */ + +#include + +#include "filesystem.h" +#include "simple_flash.h" + +int load_fat() { + flash_simple_read((uint32_t)_FLASH_FAT_START, FILE_ALLOCATION_TABLE, sizeof(FILE_ALLOCATION_TABLE)); + return 0; +} + +int store_fat() { + flash_simple_erase_page(_FLASH_FAT_START); + return flash_simple_write((uint32_t)_FLASH_FAT_START, FILE_ALLOCATION_TABLE, sizeof(FILE_ALLOCATION_TABLE)); +} + +/** @brief Initialize the filesystem + * + * + * @return 0 upon success. A negative value on error. +*/ +int init_fs() { + return load_fat(); +} + +/** @brief Check whether a file is in use + * + * @param slot The slot to check + * + * @return True if the slot is in use. False otherwise. +*/ +bool is_slot_in_use(slot_t slot) { + file_t temp_file; + return (!read_file(slot, &temp_file) && temp_file.in_use == FILE_IN_USE); +} + +/** @brief Create a new file object in memory + * + * @param slot The slot to check + * + * @return 0 upon success. A negative value otherwise. +*/ +int create_file( + file_t *dest, + group_id_t group_id, + char *name, + uint16_t contents_len, + uint8_t *contents +) { + memset(dest, 0, sizeof(file_t)); + + dest->in_use = FILE_IN_USE; + dest->group_id = group_id; + dest->contents_len = contents_len; + + // name must be null terminated, and the contents are defined by a length + strcpy(dest->name, name); + memcpy(dest->contents, contents, contents_len); + + return 0; +} + +/** @brief Create a new file object in memory + * + * @param slot The slot to write the file to + * @param src The sourc file to store + * @param uuid The UUID to store in the FAT + * + * @return 0 upon success. A negative value otherwise. +*/ +int write_file(slot_t slot, file_t *src, uint8_t *uuid) { + unsigned int length, flash_addr; + + flash_addr = FILE_START_PAGE_FROM_SLOT(slot); + length = FILE_TOTAL_SIZE(src->contents_len); + // Update the FAT for the new file + memcpy(&FILE_ALLOCATION_TABLE[slot].uuid, uuid, UUID_SIZE); + FILE_ALLOCATION_TABLE[slot].flash_addr = flash_addr; + FILE_ALLOCATION_TABLE[slot].length = length; + store_fat(); + + // erase the pages that will store the file + for (int i = 0; i < FILE_PAGE_COUNT; i++) { + flash_simple_erase_page(flash_addr + (FLASH_PAGE_SIZE * i)); + } + + // now write the file + return flash_simple_write(FILE_ALLOCATION_TABLE[slot].flash_addr, src, length); +} + +/** @brief Read a file from persistent storage into memory + * + * @param slot The slot to read + * @param dest The destination address to store the file + * + * @return 0 upon success. A negative value otherwise. +*/ +int read_file(slot_t slot, file_t *dest) { + int flash_addr, file_size; + + flash_addr = FILE_ALLOCATION_TABLE[slot].flash_addr; + file_size = FILE_ALLOCATION_TABLE[slot].length; + if (flash_addr < 0 || file_size < 0) { + return -1; + } + flash_simple_read(flash_addr, dest, file_size); + + return 0; +} + +/** @brief Get a read-only pointer to a file's metadata + * + * @param slot The slot to get metadata for + * + * @return A filesystem_entry_t * on success. NULL on error. +*/ +const filesystem_entry_t *get_file_metadata(slot_t slot) { + return &FILE_ALLOCATION_TABLE[slot]; +} diff --git a/firmware/src/host_messaging.c b/firmware/src/host_messaging.c new file mode 100644 index 0000000..063ebaf --- /dev/null +++ b/firmware/src/host_messaging.c @@ -0,0 +1,221 @@ +/** + * @file host_messaging.c + * @author Samuel Meyers + * @brief eCTF Host Messaging Implementation + * @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 + */ + +#include + +#include "host_messaging.h" + + +/** @brief Read len bytes from UART, acknowledging after every 256 bytes. + * + * @param buf Pointer to a buffer where the incoming bytes should be stored. + * @param len The number of bytes to be read. + * + * @return MSG_OK on success. A negative value on error. +*/ +int read_bytes(int uart_id, void *buf, uint16_t len) { + int result; + int i; + + for (i = 0; i < len; i++) { + if (i % 256 == 0 && i != 0) { // Send an ACK after receiving 256 bytes + write_ack(uart_id); + } + result = uart_readbyte(uart_id); + if (result < 0) { // if there was an error, return immediately + return result; + } + ((uint8_t *)buf)[i] = result; + } + + return MSG_OK; +} + +/** @brief Read a msg header from UART. + * + * @param hdr Pointer to a buffer where the incoming bytes should be stored. +*/ +void read_header(int uart_id, msg_header_t *hdr) { + hdr->magic = uart_readbyte(uart_id); + // Any bytes until '%' will be read, but ignored. + // Once we receive a '%', continue with processing the rest of the message. + while (hdr->magic != MSG_MAGIC) { + hdr->magic = uart_readbyte(uart_id); + } + hdr->cmd = uart_readbyte(uart_id); + read_bytes(uart_id, &hdr->len, sizeof(hdr->len)); +} + +/** @brief Receive an ACK from UART. + * + * @return MSG_OK on success. A negative value on error. +*/ +int read_ack(int uart_id) { + msg_header_t ack_buf = {0}; + + read_header(uart_id, &ack_buf); + if (ack_buf.cmd == ACK_MSG) { + return MSG_OK; + } else { + return MSG_NO_ACK; + } +} + +/** @brief Write len bytes to console + * + * @param buf Pointer to a buffer that stores the outgoing bytes. + * @param len The number of bytes to write. + * @param should_Ack True if the device should expect an ACK. This should be false for + * debug and ACK messages. + * + * @return MSG_OK on success, else other msg_status_t +*/ +int write_bytes(int uart_id, const void *buf, uint16_t len, bool should_ack) { + for (int i = 0; i < len; i++) { + if (i % 256 == 0 && i != 0) { // Expect an ACK after sending every 256 bytes + if (should_ack && read_ack(uart_id) < 0) { + return MSG_NO_ACK; + } + } + uart_writebyte(uart_id, ((uint8_t *)buf)[i]); + } + + fflush(stdout); + + return MSG_OK; +} + +/** @brief Write len bytes to UART in hex. 2 bytes will be printed for every byte. + * + * @param uart_id The id of the uart where the message is to be sent + * @param type Message type. + * @param buf Pointer to the bytes that will be printed. + * @param len The number of bytes to print. + * + * @return MSG_OK on success, else other msg_status_t +*/ +int write_hex(int uart_id, msg_type_t type, const void *buf, size_t len) { + msg_header_t hdr; + int i; + + char hexbuf[128]; + + hdr.magic = MSG_MAGIC; + hdr.cmd = type; + hdr.len = len*2; + + write_bytes(uart_id, &hdr, MSG_HEADER_SIZE, false /* should_ack */); + if (type != DEBUG_MSG && read_ack(uart_id) != MSG_OK) { + // If the header was not ack'd, don't send the message + return MSG_NO_ACK; + } + + for (i = 0; i < len; i++) { + if (i % (256 / 2) == 0 && i != 0) { + if (type != DEBUG_MSG && read_ack(uart_id) != MSG_OK) { + // If the block was not ack'd, don't send the rest of the message + return MSG_NO_ACK; + } + } + snprintf(hexbuf, sizeof(hexbuf), "%02x", ((uint8_t *)buf)[i]); + write_bytes(uart_id, hexbuf, 2, false); + } + return MSG_OK; +} + +/** @brief Send a message to the host, expecting an ack after every 256 bytes. + * + * @param uart_id The id of the uart where the message is to be sent + * @param type The type of message to send. + * @param buf Pointer to a buffer containing the outgoing packet. + * @param len The size of the outgoing packet in bytes. + * + * @return MSG_OK on success, else other msg_status_t +*/ +int write_packet(int uart_id, msg_type_t type, const void *buf, uint16_t len) { + msg_header_t hdr; + int result; + + hdr.magic = MSG_MAGIC; + hdr.cmd = type; + hdr.len = len; + + result = write_bytes(uart_id, &hdr, MSG_HEADER_SIZE, false); + + // ACKs don't need a response + if (type == ACK_MSG) { + return result; + } + + // If the header was not ack'd, don't send the message + if (type != DEBUG_MSG && read_ack(uart_id) != MSG_OK) { + return MSG_NO_ACK; + } + + // If there is data to write, write it + if (len > 0) { + result = write_bytes(uart_id, buf, len, type != DEBUG_MSG); + // If we still need to ACK the last block (write_bytes does not handle the final ACK) + if (type != DEBUG_MSG && read_ack(uart_id) != MSG_OK) { + return MSG_NO_ACK; + } + } + + return MSG_OK; +} + +/** @brief Reads a packet from console UART. + * + * @param uart_id The id of the uart where the message is to be sent + * @param cmd A pointer to the resulting opcode of the packet. Must not be null. + * @param buf A pointer to a buffer to store the incoming packet. Can be null. + * @param len A pointer to the resulting length of the packet. Can be null. + * + * @return MSG_OK on success, else other msg_status_t +*/ +int read_packet(int uart_id, msg_type_t* cmd, void *buf, uint16_t *len) { + msg_header_t header = {0}; + + // cmd must be a valid pointer + if (cmd == NULL) { + return MSG_BAD_PTR; + } + + read_header(uart_id, &header); + + *cmd = header.cmd; + + if (len != NULL) { + if (*len && header.len > *len) { + *len = 0; + return MSG_BAD_LEN; + } + + *len = header.len; + } + + if (header.cmd != ACK_MSG) { + write_ack(uart_id); // ACK the header + if (header.len && buf != NULL) { + if (read_bytes(uart_id, buf, header.len) != MSG_OK) { + return MSG_NO_ACK; + } + } + if (header.len) { + if (write_ack(uart_id) != MSG_OK) { // ACK the final block (not handled by read_bytes) + return MSG_NO_ACK; + } + } + } + return MSG_OK; +} diff --git a/firmware/src/security.c b/firmware/src/security.c new file mode 100644 index 0000000..e742c66 --- /dev/null +++ b/firmware/src/security.c @@ -0,0 +1,37 @@ +/** + * @file security.c + * @author Samuel Meyers + * @brief Stub file to hold security checks + * @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 + */ +#include "security.h" +#include "host_messaging.h" + +bool check_pin(unsigned char *pin) { + print_debug("Checking PIN\n"); + + // TODO: the reference design doesn't implement *ANY* security. + // This function currently does nothing. Your team should add the + // appropriate security checks here to implement the security + // requirements. + return true; +} + +bool validate_permission(uint16_t group_id, permission_enum_t perm) { + char output_buf[128] = {0}; + + sprintf(output_buf, "Checking %c permissions for group: %hx\n", perm, group_id); + print_debug(output_buf); + + // TODO: the reference design doesn't implement *ANY* security. + // This function currently does nothing. Your team should add the + // appropriate security checks here to implement the security + // requirements. + return true; +} diff --git a/firmware/src/simple_crypto.c b/firmware/src/simple_crypto.c new file mode 100644 index 0000000..d20ffda --- /dev/null +++ b/firmware/src/simple_crypto.c @@ -0,0 +1,109 @@ +/** + * @file "simple_crypto.c" + * @author Ben Janis + * @brief Simplified Crypto API Implementation + * @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 + */ + +#if CRYPTO_EXAMPLE + +#include "simple_crypto.h" +#include "security.h" +#include +#include + + +/******************************** FUNCTION PROTOTYPES ********************************/ +/** @brief Encrypts plaintext using a symmetric cipher + * + * @param plaintext A pointer to a buffer of length len containing the + * plaintext to encrypt + * @param len The length of the plaintext to encrypt. Must be a multiple of + * BLOCK_SIZE (16 bytes) + * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing + * the key to use for encryption + * @param ciphertext A pointer to a buffer of length len where the resulting + * ciphertext will be written to + * + * @return 0 on success, -1 on bad length, other non-zero for other error + */ +int encrypt_sym(uint8_t *plaintext, size_t len, uint8_t *key, uint8_t *ciphertext) { + Aes ctx; // Context for encryption + int result; // Library result + + // Ensure valid length + if (len <= 0 || len % BLOCK_SIZE) + return -1; + + // Set the key for encryption + result = wc_AesSetKey(&ctx, key, 16, NULL, AES_ENCRYPTION); + if (result != 0) + return result; // Report error + + + // Encrypt each block + for (int i = 0; i < len - 1; i += BLOCK_SIZE) { + result = wc_AesEncryptDirect(&ctx, ciphertext + i, plaintext + i); + if (result != 0) + return result; // Report error + } + return 0; +} + +/** @brief Decrypts ciphertext using a symmetric cipher + * + * @param ciphertext A pointer to a buffer of length len containing the + * ciphertext to decrypt + * @param len The length of the ciphertext to decrypt. Must be a multiple of + * BLOCK_SIZE (16 bytes) + * @param key A pointer to a buffer of length KEY_SIZE (16 bytes) containing + * the key to use for decryption + * @param plaintext A pointer to a buffer of length len where the resulting + * plaintext will be written to + * + * @return 0 on success, -1 on bad length, other non-zero for other error + */ +int decrypt_sym(uint8_t *ciphertext, size_t len, uint8_t *key, uint8_t *plaintext) { + Aes ctx; // Context for decryption + int result; // Library result + + // Ensure valid length + if (len <= 0 || len % BLOCK_SIZE) + return -1; + + // Set the key for decryption + result = wc_AesSetKey(&ctx, key, 16, NULL, AES_DECRYPTION); + if (result != 0) + return result; // Report error + + // Decrypt each block + for (int i = 0; i < len - 1; i += BLOCK_SIZE) { + result = wc_AesDecryptDirect(&ctx, plaintext + i, ciphertext + i); + if (result != 0) + return result; // Report error + } + return 0; +} + +/** @brief Hashes arbitrary-length data + * + * @param data A pointer to a buffer of length len containing the data + * to be hashed + * @param len The length of the plaintext to hash + * @param hash_out A pointer to a buffer of length HASH_SIZE (16 bytes) where the resulting + * hash output will be written to + * + * @return 0 on success, non-zero for other error + */ +int hash(void *data, size_t len, uint8_t *hash_out) { + // Pass values to hash + return wc_Md5Hash((uint8_t *)data, len, hash_out); +} + +#endif diff --git a/firmware/src/simple_flash.c b/firmware/src/simple_flash.c new file mode 100644 index 0000000..54ffc80 --- /dev/null +++ b/firmware/src/simple_flash.c @@ -0,0 +1,103 @@ +/** + * @file "simple_flash.c" + * @author Samuel Meyers + * @brief Simple Flash Interface Implementation + * @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 + */ + +#include "simple_flash.h" + +/** + * @brief Flash Simple Erase Page + * + * @param address: uint32_t, address of flash page to erase + * + * @return int: return negative if failure, zero if success + * + * This function erases a page of flash such that it can be updated. + * Flash memory can only be erased in a large block size called a page (or sector). + * Once erased, memory can only be written one way e.g. 1->0. + * In order to be re-written the entire page must be erased. +*/ +int flash_simple_erase_page(uint32_t address) { + volatile DL_FLASHCTL_COMMAND_STATUS cmdStatus; + DL_FlashCTL_executeClearStatus(FLASHCTL); + DL_FlashCTL_unprotectSector(FLASHCTL, address, DL_FLASHCTL_REGION_SELECT_MAIN); + + cmdStatus = DL_FlashCTL_eraseMemoryFromRAM( + FLASHCTL, address, DL_FLASHCTL_COMMAND_SIZE_SECTOR); + if (cmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) { + return -1; + } + // returns a boolean, so handle that accordingly + bool ret = DL_FlashCTL_waitForCmdDone(FLASHCTL); + if (ret == false) { + return -1; + } + return 0; +} + +/** + * @brief Flash Simple Read + * + * @param address: uint32_t, address of flash page to read + * @param buffer: void*, pointer to buffer for data to be read into + * @param size: uint32_t, number of bytes to read from flash + * + * This function reads data from the specified flash page into the buffer + * with the specified amount of bytes +*/ +void flash_simple_read(uint32_t address, void* buffer, uint32_t size) { + // flash is memory mapped, and the flash controller has no read functionality + memcpy(buffer, (void *)address, size); +} + +/** + * @brief Flash Simple Write + * + * @param address: uint32_t, address of flash page to write + * @param buffer: void*, pointer to buffer to write data from + * @param size: uint32_t, number of bytes to write from flash + * + * @return int: return negative if failure, zero if success + * + * This function writes data to the specified flash page from the buffer passed + * with the specified amount of bytes. Flash memory can only be written in one + * way e.g. 1->0. To rewrite previously written memory see the + * flash_simple_erase_page documentation. +*/ +int flash_simple_write(uint32_t address, void* buffer, uint32_t size) { + volatile DL_FLASHCTL_COMMAND_STATUS cmdStatus; + DL_FlashCTL_executeClearStatus(FLASHCTL); + DL_FlashCTL_unprotectSector(FLASHCTL, address, DL_FLASHCTL_REGION_SELECT_MAIN); + + // program function expects size to be the number of 32-bit words + uint32_t size_32b = (size % 4 == 0) ? (size / 4) : (size / 4) + 1; + // it also expects it to be an even number + size_32b = (size_32b % 2 == 0) ? size_32b : size_32b + 1; + + // write the data into a correctly sized region to ensure no undefined behavior + uint32_t write_data[size_32b]; + memset(write_data, 0xff, size_32b*4); + memcpy(write_data, buffer, size); + + // if memory section is corrected, make sure to write the ECC (you have been warned) + cmdStatus = DL_FlashCTL_programMemoryBlockingFromRAM64WithECCGenerated( + FLASHCTL, address, (uint32_t *)write_data, size_32b, DL_FLASHCTL_REGION_SELECT_MAIN + ); + if (cmdStatus == DL_FLASHCTL_COMMAND_STATUS_FAILED) { + return -1; + } + // returns a boolean, so handle that accordingly + bool ret = DL_FlashCTL_waitForCmdDone(FLASHCTL); + if (ret == false) { + return -1; + } + return 0; +} diff --git a/firmware/src/simple_uart.c b/firmware/src/simple_uart.c new file mode 100644 index 0000000..fb8915b --- /dev/null +++ b/firmware/src/simple_uart.c @@ -0,0 +1,51 @@ +/** + * @file "simple_uart.c" + * @author Samuel Meyers + * @brief UART Interrupt Handler Implementation + * @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 + */ + +#include "simple_uart.h" + +/********************************************************** + *************** HARDWARE ABSTRACTIONS ******************** + **********************************************************/ + +// This holds the two UART configurations necessary for communication +UART_Regs *uart_inst[] = {UART_0_INST, UART_1_INST}; + +UART_Regs *get_uart_handle(int uart_id) { + if (uart_id < 0 || uart_id > CONFIG_UART_COUNT) { + // Default on bad input is 0 + return uart_inst[0]; + } + else { + return uart_inst[uart_id]; + } +} + +/** @brief Reads the next available character from UART. + * + * @param uart_id The index of UART to use + * @return The character read. +*/ +int uart_readbyte(int uart_id){ + uint8_t data = DL_UART_receiveDataBlocking(get_uart_handle(uart_id)); + return data; +} + +/** @brief Writes a byte to UART. + * + * @param uart_id The index of UART to use + * @param data The byte to be written. +*/ +void uart_writebyte(int uart_id, uint8_t data) { + DL_UART_transmitDataBlocking(get_uart_handle(uart_id), data); +} + diff --git a/firmware/src/startup_mspm0l222x_ticlang.c b/firmware/src/startup_mspm0l222x_ticlang.c new file mode 100644 index 0000000..66ab1cf --- /dev/null +++ b/firmware/src/startup_mspm0l222x_ticlang.c @@ -0,0 +1,174 @@ +/***************************************************************************** + + Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*****************************************************************************/ + +#include +#include + +#include "status_led.h" + +/* Linker variable that marks the top of the stack. */ +extern unsigned long __STACK_END; + +/* External declaration for the reset handler that is to be called when the */ +/* processor is started */ +extern __NO_RETURN void __PROGRAM_START(void); + +/* Forward declaration of the default fault handlers. */ +void Default_Handler (void) __attribute__((weak)); +extern void Reset_Handler (void) __attribute__((weak)); + +/* Processor Exceptions */ +extern void NMI_Handler (void) __attribute__((weak, alias("Default_Handler"))); +extern void HardFault_Handler (void) __attribute__((weak, alias("Default_Handler"))); +extern void SVC_Handler (void) __attribute__((weak, alias("Default_Handler"))); +extern void PendSV_Handler (void) __attribute__((weak, alias("Default_Handler"))); +extern void SysTick_Handler (void) __attribute__((weak, alias("Default_Handler"))); + +/* Device Specific Interrupt Handlers */ +extern void GROUP0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void GROUP1_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMG12_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void UART4_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void ADC0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void SPI0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void SPI1_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void UART2_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void UART3_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void UART0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void UART1_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMA0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMG8_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMG0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMG4_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void TIMG5_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void I2C0_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void I2C1_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void I2C2_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void AESADV_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void LCD_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void LFSS_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); +extern void DMA_IRQHandler (void) __attribute__((weak, alias("Default_Handler"))); + +/* Interrupt vector table. Note that the proper constructs must be placed on this to */ +/* ensure that it ends up at physical address 0x0000.0000 or at the start of */ +/* the program if located at a start address other than 0. */ +#if defined(__ARM_ARCH) && (__ARM_ARCH != 0) +void (*const interruptVectors[])(void) __attribute((used)) +__attribute__((section(".intvecs"))) = +#elif defined(__TI_ARM__) +#pragma RETAIN(interruptVectors) +#pragma DATA_SECTION(interruptVectors, ".intvecs") +void (*const interruptVectors[])(void) = +#else +#error "Compiler not supported" +#endif + { + (void (*)(void))((uint32_t) &__STACK_END), + /* The initial stack pointer */ + Reset_Handler, /* The reset handler */ + NMI_Handler, /* The NMI handler */ + HardFault_Handler, /* The hard fault handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + SVC_Handler, /* SVCall handler */ + 0, /* Reserved */ + 0, /* Reserved */ + PendSV_Handler, /* The PendSV handler */ + SysTick_Handler, /* SysTick handler */ + GROUP0_IRQHandler, /* GROUP0 interrupt handler */ + GROUP1_IRQHandler, /* GROUP1 interrupt handler */ + TIMG12_IRQHandler, /* TIMG12 interrupt handler */ + UART4_IRQHandler, /* UART4 interrupt handler */ + ADC0_IRQHandler, /* ADC0 interrupt handler */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + 0, /* Reserved */ + SPI0_IRQHandler, /* SPI0 interrupt handler */ + SPI1_IRQHandler, /* SPI1 interrupt handler */ + 0, /* Reserved */ + 0, /* Reserved */ + UART2_IRQHandler, /* UART2 interrupt handler */ + UART3_IRQHandler, /* UART3 interrupt handler */ + UART0_IRQHandler, /* UART0 interrupt handler */ + UART1_IRQHandler, /* UART1 interrupt handler */ + 0, /* Reserved */ + TIMA0_IRQHandler, /* TIMA0 interrupt handler */ + 0, /* Reserved */ + TIMG8_IRQHandler, /* TIMG8 interrupt handler */ + TIMG0_IRQHandler, /* TIMG0 interrupt handler */ + TIMG4_IRQHandler, /* TIMG4 interrupt handler */ + TIMG5_IRQHandler, /* TIMG5 interrupt handler */ + I2C0_IRQHandler, /* I2C0 interrupt handler */ + I2C1_IRQHandler, /* I2C1 interrupt handler */ + I2C2_IRQHandler, /* I2C2 interrupt handler */ + 0, /* Reserved */ + AESADV_IRQHandler, /* AESADV interrupt handler*/ + LCD_IRQHandler, /* LCD interrupt handler */ + LFSS_IRQHandler, /* LFSS interrupt handler */ + DMA_IRQHandler /* DMA interrupt handler */ + }; + +/* Forward declaration of the default fault handlers. */ +/* This is the code that gets called when the processor first starts execution */ +/* following a reset event. Only the absolutely necessary set is performed, */ +/* after which the application supplied entry() routine is called. Any fancy */ +/* actions (such as making decisions based on the reset cause register, and */ +/* resetting the bits in that register) are left solely in the hands of the */ +/* application. */ +void Reset_Handler(void) +{ + /* Jump to the ticlang C Initialization Routine. */ + __asm( + " .global _c_int00\n" + " b _c_int00"); +} + +/* This is the code that gets called when the processor receives an unexpected */ +/* interrupt. This simply enters an infinite loop, preserving the system state */ +/* for examination by a debugger. */ +// Note: we have added LEDs to this step for debugging purposes. It will light +// LED3 and LED4 to red +void Default_Handler(void) +{ + STATUS_LED_OFF(); + /* Enter an infinite loop. */ + while (1) { + } +} diff --git a/firmware/src/ti_msp_dl_config.c b/firmware/src/ti_msp_dl_config.c new file mode 100644 index 0000000..3d415c0 --- /dev/null +++ b/firmware/src/ti_msp_dl_config.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * ============ ti_msp_dl_config.c ============= + * Configured MSPM0 DriverLib module definitions + * + * DO NOT EDIT - This file is generated for the MSPM0L222X + * by the SysConfig tool. + */ + +#include "ti_msp_dl_config.h" + +/* + * ======== SYSCFG_DL_init ======== + * Perform any initialization needed before using any board APIs + */ +SYSCONFIG_WEAK void SYSCFG_DL_init(void) +{ + SYSCFG_DL_initPower(); + SYSCFG_DL_GPIO_init(); + /* Module-Specific Initializations*/ + SYSCFG_DL_SYSCTL_init(); + SYSCFG_DL_UART_0_init(); + SYSCFG_DL_UART_1_init(); +} + +SYSCONFIG_WEAK void SYSCFG_DL_initPower(void) +{ + DL_GPIO_reset(GPIOA); + DL_GPIO_reset(GPIOB); + DL_UART_Main_reset(UART_0_INST); + DL_UART_Main_reset(UART_1_INST); + + DL_GPIO_enablePower(GPIOA); + DL_GPIO_enablePower(GPIOB); + DL_UART_Main_enablePower(UART_0_INST); + DL_UART_Main_enablePower(UART_1_INST); + delay_cycles(POWER_STARTUP_DELAY); +} + +SYSCONFIG_WEAK void SYSCFG_DL_GPIO_init(void) +{ + + DL_GPIO_initPeripheralOutputFunction( + GPIO_UART_0_IOMUX_TX, GPIO_UART_0_IOMUX_TX_FUNC); + DL_GPIO_initPeripheralInputFunction( + GPIO_UART_0_IOMUX_RX, GPIO_UART_0_IOMUX_RX_FUNC); + DL_GPIO_initPeripheralOutputFunction( + GPIO_UART_1_IOMUX_TX, GPIO_UART_1_IOMUX_TX_FUNC); + DL_GPIO_initPeripheralInputFunction( + GPIO_UART_1_IOMUX_RX, GPIO_UART_1_IOMUX_RX_FUNC); + + DL_GPIO_initDigitalOutput(LEDS_STATUS_LED_IOMUX); + + DL_GPIO_initDigitalInputFeatures(BUTTONS_S2_IOMUX, + DL_GPIO_INVERSION_DISABLE, DL_GPIO_RESISTOR_PULL_UP, + DL_GPIO_HYSTERESIS_DISABLE, DL_GPIO_WAKEUP_DISABLE); + + DL_GPIO_setPins(GPIOB, LEDS_STATUS_LED_PIN); + DL_GPIO_enableOutput(GPIOB, LEDS_STATUS_LED_PIN); + +} + + +SYSCONFIG_WEAK void SYSCFG_DL_SYSCTL_init(void) +{ + + //Low Power Mode is configured to be SLEEP0 + DL_SYSCTL_setBORThreshold(DL_SYSCTL_BOR_THRESHOLD_LEVEL_0); + + DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE); + DL_SYSCTL_setMCLKDivider(DL_SYSCTL_MCLK_DIVIDER_DISABLE); + +} + + +static const DL_UART_Main_ClockConfig gUART_0ClockConfig = { + .clockSel = DL_UART_MAIN_CLOCK_BUSCLK, + .divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1 +}; + +static const DL_UART_Main_Config gUART_0Config = { + .mode = DL_UART_MAIN_MODE_NORMAL, + .direction = DL_UART_MAIN_DIRECTION_TX_RX, + .flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE, + .parity = DL_UART_MAIN_PARITY_NONE, + .wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, + .stopBits = DL_UART_MAIN_STOP_BITS_ONE +}; + +SYSCONFIG_WEAK void SYSCFG_DL_UART_0_init(void) +{ + DL_UART_Main_setClockConfig(UART_0_INST, (DL_UART_Main_ClockConfig *) &gUART_0ClockConfig); + + DL_UART_Main_init(UART_0_INST, (DL_UART_Main_Config *) &gUART_0Config); + /* + * Configure baud rate by setting oversampling and baud rate divisors. + * Target baud rate: 115200 + * Actual baud rate: 115211.52 + */ + DL_UART_Main_setOversampling(UART_0_INST, DL_UART_OVERSAMPLING_RATE_16X); + DL_UART_Main_setBaudRateDivisor(UART_0_INST, UART_0_IBRD_32_MHZ_115200_BAUD, UART_0_FBRD_32_MHZ_115200_BAUD); + + + + DL_UART_Main_enable(UART_0_INST); +} +static const DL_UART_Main_ClockConfig gUART_1ClockConfig = { + .clockSel = DL_UART_MAIN_CLOCK_BUSCLK, + .divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1 +}; + +static const DL_UART_Main_Config gUART_1Config = { + .mode = DL_UART_MAIN_MODE_NORMAL, + .direction = DL_UART_MAIN_DIRECTION_TX_RX, + .flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE, + .parity = DL_UART_MAIN_PARITY_NONE, + .wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, + .stopBits = DL_UART_MAIN_STOP_BITS_ONE +}; + +SYSCONFIG_WEAK void SYSCFG_DL_UART_1_init(void) +{ + DL_UART_Main_setClockConfig(UART_1_INST, (DL_UART_Main_ClockConfig *) &gUART_1ClockConfig); + + DL_UART_Main_init(UART_1_INST, (DL_UART_Main_Config *) &gUART_1Config); + /* + * Configure baud rate by setting oversampling and baud rate divisors. + * Target baud rate: 115200 + * Actual baud rate: 115211.52 + */ + DL_UART_Main_setOversampling(UART_1_INST, DL_UART_OVERSAMPLING_RATE_16X); + DL_UART_Main_setBaudRateDivisor(UART_1_INST, UART_1_IBRD_32_MHZ_115200_BAUD, UART_1_FBRD_32_MHZ_115200_BAUD); + + + + DL_UART_Main_enable(UART_1_INST); +} +