From 910c2b286aec81666e57aef037a33a532ffef70d Mon Sep 17 00:00:00 2001 From: Alex Sears Date: Thu, 19 Aug 2021 13:14:56 -0400 Subject: [PATCH] TOOL-3: Setup Docker infra for Gen 1 Development (#45) * Add Dockerfile for building the firmware Setting up a local environment for building the firmware can be a painful process. This wraps that process up in a Dockerfile containing all the deps needed which is then used in the justfile to build the firmware. * Add just targets for signing and cleaning * Change sha target to take a sha and verify it directly * Add docs for verifying the firmware SHA sum * Add version param to sign just target * Update verify-sha output to be more explicit --- .gitignore | 2 ++ Dockerfile | 32 ++++++++++++++++++++++++++++++ README.md | 8 ++++++++ justfile | 46 +++++++++++++++++++++++++++++++++++++++++++ py/dynruntime.mk | 2 +- py/mkenv.mk | 2 +- py/mkrules.mk | 2 +- tools/makemanifest.py | 2 +- 8 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100644 justfile diff --git a/.gitignore b/.gitignore index 72bdd19..d602175 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ ports/stm32/secrets* ports/stm32/boards/Passport/bootloader/version_info.c ports/stm32/boards/Passport/bootloader/secrets* + +*.pem diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..94754d9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +FROM ubuntu:18.04 AS cross_build +RUN apt-get update && \ + apt-get install -y git make gcc-arm-none-eabi python3 gcc && \ + rm -rf /var/lib/apt/lists/* +COPY docs /workspace/passport-firmware/docs +COPY extmod /workspace/passport-firmware/extmod +COPY lib /workspace/passport-firmware/lib +COPY mpy-cross /workspace/passport-firmware/mpy-cross +COPY py /workspace/passport-firmware/py +WORKDIR /workspace/passport-firmware/mpy-cross +RUN make + +FROM ubuntu:18.04 AS cosign_build +WORKDIR /workspace +RUN apt-get update && \ + apt-get install -y git make libssl-dev gcc && \ + rm -rf /var/lib/apt/lists/* +COPY ports/stm32/boards/Passport/tools/cosign /workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign +COPY ports/stm32/boards/Passport/include /workspace/passport-firmware/ports/stm32/boards/Passport/include +COPY lib /workspace/passport-firmware/lib +COPY ports/stm32/boards/Passport/common /workspace/passport-firmware/ports/stm32/boards/Passport/common +WORKDIR /workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign +RUN make + +FROM ubuntu:18.04 AS firmware_builder +COPY --from=cosign_build \ + /workspace/passport-firmware/ports/stm32/boards/Passport/tools/cosign/x86/release/cosign /usr/bin/cosign +COPY --from=cross_build \ + /workspace/passport-firmware/mpy-cross/mpy-cross /usr/bin/mpy-cross +RUN apt-get update && \ + apt-get install -y make gcc-arm-none-eabi autotools-dev automake libtool python3 && \ + rm -rf /var/lib/apt/lists/* diff --git a/README.md b/README.md index d066794..0266640 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,14 @@ Code specific to Passport is included in the following folders: Please see [`DEVELOPMENT.md`](https://github.com/Foundation-Devices/passport/blob/main/DEVELOPMENT.md) for information on developing for Passport. +## Verifying Firmware SHA Sums + +To make building and verifying the firmware a simple process, there is a Dockerfile in the project that builds an image to be used to build the firmware. Using [`just`](https://github.com/casey/just), the following command can be used to verify the reproducability of the firmware. Make sure to substitute `` for the SHA string to verify. + +```shell +just verify-sha +``` + ## Open Source Components Passport's firmware incorporates open-source software from several third-party projects, as well as other first-party work we open-sourced. diff --git a/justfile b/justfile new file mode 100644 index 0000000..19d51e1 --- /dev/null +++ b/justfile @@ -0,0 +1,46 @@ +commit_sha := `git rev-parse HEAD` +base_path := 'ports/stm32' +firmware_path := base_path + '/build-Passport/firmware.bin' + +# build the firmware inside docker +docker-build: + #!/usr/bin/env bash + set -euxo pipefail + docker build -t foundation-devices/firmware-builder:{{ commit_sha }} . + docker run -it --rm -v "$PWD":/workspace \ + -w /workspace/{{ base_path }} \ + --entrypoint bash \ + foundation-devices/firmware-builder:{{ commit_sha }} \ + -c 'make BOARD=Passport MPY_CROSS=/usr/bin/mpy-cross' + +# run the built firmware through SHA256 +verify-sha sha: docker-build + #!/usr/bin/env bash + sha=$(shasum -a 256 {{ firmware_path }} | awk '{print $1}') + + echo -e "Expected SHA:\t{{ sha }}" + echo -e "Actual SHA:\t${sha}" + if [ "$sha" = "{{ sha }}" ]; then + echo "Hashes match!" + else + echo "ERROR: Hashes DO NOT match!" + fi + +# sign the built firmware using a private key and the cosign tool +sign keypath version filepath=firmware_path: docker-build + #!/usr/bin/env bash + set -euxo pipefail + + docker run -it --rm -v "$PWD":/workspace \ + -w /workspace \ + --entrypoint bash \ + foundation-devices/firmware-builder:{{ commit_sha }} \ + -c "cosign -f {{ filepath }} -k {{ keypath }} -v {{ version }}" + +# clean firmware build +clean: + docker run -it --rm -v "$PWD":/workspace \ + -w /workspace/{{ base_path }} \ + --entrypoint bash \ + foundation-devices/firmware-builder:{{ commit_sha }} \ + -c "make clean BOARD=Passport" diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 8b65745..5597170 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -7,7 +7,7 @@ ECHO = @echo RM = /bin/rm MKDIR = /bin/mkdir PYTHON = python3 -MPY_CROSS = $(MPY_DIR)/mpy-cross/mpy-cross +MPY_CROSS ?= $(MPY_DIR)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(MPY_DIR)/tools/mpy-tool.py MPY_LD = $(PYTHON) $(MPY_DIR)/tools/mpy_ld.py diff --git a/py/mkenv.mk b/py/mkenv.mk index 3efeb18..8db6344 100644 --- a/py/mkenv.mk +++ b/py/mkenv.mk @@ -63,7 +63,7 @@ endif MAKE_MANIFEST = $(PYTHON) $(TOP)/tools/makemanifest.py MAKE_FROZEN = $(PYTHON) $(TOP)/tools/make-frozen.py -MPY_CROSS = $(TOP)/mpy-cross/mpy-cross +MPY_CROSS ?= $(TOP)/mpy-cross/mpy-cross MPY_TOOL = $(PYTHON) $(TOP)/tools/mpy-tool.py MPY_LIB_DIR = $(TOP)/../micropython-lib diff --git a/py/mkrules.mk b/py/mkrules.mk index 68da3e7..0a16a15 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -100,7 +100,7 @@ $(HEADER_BUILD): ifneq ($(FROZEN_MANIFEST),) # to build frozen_content.c from a manifest $(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h - $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST) + $(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "MPY_CROSS=$(MPY_CROSS)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) $(FROZEN_MANIFEST) ifneq ($(FROZEN_DIR),) $(error FROZEN_DIR cannot be used in conjunction with FROZEN_MANIFEST) diff --git a/tools/makemanifest.py b/tools/makemanifest.py index 90cec2b..b634856 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -216,7 +216,7 @@ def main(): # Get paths to tools MAKE_FROZEN = VARS['MPY_DIR'] + '/tools/make-frozen.py' - MPY_CROSS = VARS['MPY_DIR'] + '/mpy-cross/mpy-cross' + MPY_CROSS = VARS['MPY_CROSS'] MPY_TOOL = VARS['MPY_DIR'] + '/tools/mpy-tool.py' # Ensure mpy-cross is built