diff --git a/build-dist-ledger b/build-dist-ledger index ed487a8e..c62d0297 100755 --- a/build-dist-ledger +++ b/build-dist-ledger @@ -34,7 +34,7 @@ fi echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKPOINT\e[32m, minimum difficulty \e[93m$DIFFICULTY\e[32m, network \e[93m$NETWORK\e[32m and UI iteration \e[93m$UI_ITERATION\e[32m...\e[0m" echo -e "\e[33mCopying files and creating directories...\e[0m" rm -rf $DEST_DIR -cp -Rf $ROOT_DIR/dist $DEST_DIR +cp -Rf $ROOT_DIR/dist/ledger $DEST_DIR rm -rf $FIRMWARE_DIR mkdir -p $FIRMWARE_DIR diff --git a/build-dist-sgx b/build-dist-sgx new file mode 100755 index 00000000..31052197 --- /dev/null +++ b/build-dist-sgx @@ -0,0 +1,58 @@ +#!/bin/bash + +pushd $(dirname $0) > /dev/null +ROOT_DIR=$(pwd) + +if [[ $# -lt 4 ]]; then + echo "Usage: $0 " + exit 1 +fi + +# Check docker images exist +CHECK_IMAGE=$ROOT_DIR/docker/check-image + +for img in hsm:sgx hsm:mware hsm:packer; do + DOCKER_IMAGE=$img + source $CHECK_IMAGE +done + +DEST_DIR=$1 +CHECKPOINT=$2 +DIFFICULTY=$3 +NETWORK=$4 +HSM_DIR=$DEST_DIR/hsm +BIN_DIR=$DEST_DIR/bin +SCRIPTS_DIR=$DEST_DIR/scripts + +if [[ -e $DEST_DIR ]]; then + echo -e "\e[31mDestination directory $DEST_DIR exists" + exit 1 +fi + +echo -e "\e[32mBuilding into \e[93m$DEST_DIR\e[32m with checkpoint \e[93m$CHECKPOINT\e[32m, minimum difficulty \e[93m$DIFFICULTY\e[32m, network \e[93m$NETWORK\e[32m and UI iteration \e[93m$UI_ITERATION\e[32m...\e[0m" +echo -e "\e[33mCopying files and creating directories...\e[0m" +rm -rf $DEST_DIR +cp -Rf $ROOT_DIR/dist/sgx $DEST_DIR + +rm -rf $BIN_DIR +mkdir -p $BIN_DIR + +echo +echo -e "\e[33mBuilding middleware...\e[0m" +$ROOT_DIR/middleware/build/dist_sgx +cp $ROOT_DIR/middleware/bin/adm_sgx.tgz $BIN_DIR +cp $ROOT_DIR/middleware/bin/manager_sgx.tgz $BIN_DIR +echo + +echo -e "\e[33mBuilding SGX apps...\e[0m" +# TODO: decide what to do with the enclave signing key +#(randomizing seems like a reasonable option +# since we don't actually need it in our current scheme) +$ROOT_DIR/firmware/build/build-sgx $CHECKPOINT $DIFFICULTY $NETWORK > /dev/null +cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx $HSM_DIR/ +cp $ROOT_DIR/firmware/src/sgx/bin/hsmsgx_enclave.signed $HSM_DIR/ + +echo +echo -e "\e[32mBuild complete.\e[0m" + +popd > /dev/null diff --git a/dist/.gitignore b/dist/ledger/.gitignore similarity index 93% rename from dist/.gitignore rename to dist/ledger/.gitignore index 7ecf1847..685f5b90 100644 --- a/dist/.gitignore +++ b/dist/ledger/.gitignore @@ -1,5 +1,6 @@ bin firmware +export public-keys.txt public-keys.json pin.txt diff --git a/dist/Dockerfile b/dist/ledger/Dockerfile similarity index 100% rename from dist/Dockerfile rename to dist/ledger/Dockerfile diff --git a/dist/README-cli.md b/dist/ledger/README-cli.md similarity index 94% rename from dist/README-cli.md rename to dist/ledger/README-cli.md index 171126f8..95e2bffb 100644 --- a/dist/README-cli.md +++ b/dist/ledger/README-cli.md @@ -1,4 +1,4 @@ -# powHSM Setup and onboarding +# powHSM for Ledger Nano S Setup and onboarding ## Prerequisites diff --git a/dist/README.md b/dist/ledger/README.md similarity index 88% rename from dist/README.md rename to dist/ledger/README.md index f970ceea..4bd9e5f6 100644 --- a/dist/README.md +++ b/dist/ledger/README.md @@ -1,17 +1,17 @@ -# powHSM distribution +# powHSM for Ledger Nano S distribution This document describes the artifacts provided to build a distributable version of the powHSM software for Ledger Nano S. This distributable version includes both Ledger apps and middleware binaries, as well as scripts for both setting up and onboarding a brand new Ledger Nano S; and also for upgrading an existing Ledger Nano S with powHSM to a newer Signer version. ## Prerequisites -You will need all of the docker images built (see the [quickstart guide](../QUICKSTART.md) for details on this). +You will need all of the docker images built (see the [quickstart guide](../../QUICKSTART.md) for details on this). ## Generating a distribution To generate a full distribution into a fresh directory, issue: ``` -~/repo> ./build-dist +~/repo> ./build-dist-ledger ``` where `` is the target directory (which must not exist); ``, `` and `` are the build parameters for the signer app; `` is the signer version iteration with which the UI must be built; and `` is the basename of the authorizers header file. The script will build the Ledger apps (signer and UI) as well as the required middleware. Then it will output all of the necessary distribution artifacts, including the aforementioned builds, to the destination path given. @@ -19,7 +19,7 @@ where `` is the target directory (which must not exist); ` ./build-dist /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet 43 testing +~/repo> ./build-dist-ledger /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet 43 testing ``` ## Using a distribution diff --git a/dist/scripts/run_with_docker b/dist/ledger/scripts/run_with_docker similarity index 94% rename from dist/scripts/run_with_docker rename to dist/ledger/scripts/run_with_docker index 446803b5..c7fab848 100755 --- a/dist/scripts/run_with_docker +++ b/dist/ledger/scripts/run_with_docker @@ -3,7 +3,7 @@ pushd $(dirname $0)/.. > /dev/null DIST_DIR=$(pwd) popd > /dev/null -DOCKER_IMAGE=hsm2:setup +DOCKER_IMAGE=powhsmledger:setup QUIET="" echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." diff --git a/dist/scripts/setup b/dist/ledger/scripts/setup similarity index 98% rename from dist/scripts/setup rename to dist/ledger/scripts/setup index 7d91a3d0..2f0fa29c 100755 --- a/dist/scripts/setup +++ b/dist/ledger/scripts/setup @@ -160,7 +160,7 @@ function verify_attestation() { error } -echo -e "\e[1;32mWelcome to the powHSM Setup for RSK \e[0m" +echo -e "\e[1;32mWelcome to the Ledger Nano S powHSM Setup for RSK \e[0m" echo checkForPinFile checkFirmware diff --git a/dist/scripts/target.id b/dist/ledger/scripts/target.id similarity index 100% rename from dist/scripts/target.id rename to dist/ledger/scripts/target.id diff --git a/dist/scripts/upgrade-existing b/dist/ledger/scripts/upgrade-existing similarity index 98% rename from dist/scripts/upgrade-existing rename to dist/ledger/scripts/upgrade-existing index 5e1c33c2..7e8bd339 100755 --- a/dist/scripts/upgrade-existing +++ b/dist/ledger/scripts/upgrade-existing @@ -134,7 +134,7 @@ function verify_attestation() { error } -echo -e "\e[1;32mWelcome to the powHSM Upgrade for RSK \e[0m" +echo -e "\e[1;32mWelcome to the Ledger Nano S powHSM Upgrade for RSK \e[0m" echo -e "\e[1;32mPlease make sure your HSM is onboarded before continuing with the firmware upgrade.\e[0m" echo checkFirmware diff --git a/dist/setup-new-device b/dist/ledger/setup-new-device similarity index 100% rename from dist/setup-new-device rename to dist/ledger/setup-new-device diff --git a/dist/upgrade-existing-device b/dist/ledger/upgrade-existing-device similarity index 100% rename from dist/upgrade-existing-device rename to dist/ledger/upgrade-existing-device diff --git a/dist/sgx/.gitignore b/dist/sgx/.gitignore new file mode 100644 index 00000000..0c8fd78d --- /dev/null +++ b/dist/sgx/.gitignore @@ -0,0 +1,3 @@ +bin +export +hsm/hsmsgx* diff --git a/dist/sgx/Dockerfile b/dist/sgx/Dockerfile new file mode 100644 index 00000000..1805e567 --- /dev/null +++ b/dist/sgx/Dockerfile @@ -0,0 +1,17 @@ +FROM debian:bookworm-slim + +WORKDIR /hsm2 + +RUN apt-get update && \ + apt-get install -y binutils gnupg2 curl + +# Download and install libssl1.1 from debian main repository +RUN curl -L -o libssl1.1.deb https://ftp.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.1w-0+deb11u1_amd64.deb && \ + dpkg -i libssl1.1.deb && \ + rm libssl1.1.deb + +# Install SGX runtime dependencies +RUN echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main' | tee /etc/apt/sources.list.d/intel-sgx.list && \ + curl -fsSL https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | apt-key add - && \ + apt-get update && \ + apt-get install -y libsgx-enclave-common diff --git a/dist/sgx/README-cli.md b/dist/sgx/README-cli.md new file mode 100644 index 00000000..4d7cdf4d --- /dev/null +++ b/dist/sgx/README-cli.md @@ -0,0 +1,17 @@ +# powHSM for SGX Setup and onboarding + +## Prerequisites + +The computer on which the powHSM setup and onboarding is to be executed needs the following installed: + +- Docker + +### Setup + +To setup a brand new powHSM, within the `/path/to/dist` directory, issue: + +``` +/path/to/dist> ./setup-new-powhsm +``` + +and follow the instructions. diff --git a/dist/sgx/README.md b/dist/sgx/README.md new file mode 100644 index 00000000..14e18af6 --- /dev/null +++ b/dist/sgx/README.md @@ -0,0 +1,41 @@ +# powHSM for SGX distribution + +This document describes the artifacts provided to build a distributable version of the powHSM software for Intel SGX. This distributable version includes both SGX apps and middleware binaries, as well as scripts for setting up and onboarding a brand new installation. + +## Prerequisites + +You will need all of the docker images built (see the [quickstart guide](../QUICKSTART.md) for details on this). + +## Generating a distribution + +To generate a full distribution into a fresh directory, issue: + +``` +~/repo> ./build-dist-sgx +``` + +where `` is the target directory (which must not exist); ``, `` and `` are the build parameters for the SGX enclave application. The script will build the SGX apps (host and enclave) as well as the required middleware. Then it will output all of the necessary distribution artifacts, including the aforementioned builds, to the destination path given. + +For example, to build a distribution with checkpoint `0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac`, minimum cumulative difficulty of `0x7c50933098` and `testnet` network, issue: + +``` +~/repo> ./build-dist-sgx /path/to/output 0x00f06dcff26ec8b4d373fbd53ee770e9348d9bd6a247ad4c86e82ceb3c2130ac 0x7c50933098 testnet +``` + +## Using a distribution + +### Prerequisites + +The computer on which the distrbution is to be used needs the following installed: + +- Docker + +### Scripts + +As mentioned, a distribution can be used to setup a new device. To setup a brand new installation, within the `/path/to/dist` directory, issue: + +``` +/path/to/dist> ./setup-new-powhsm +``` + +and follow the instructions. diff --git a/dist/sgx/hsm/run b/dist/sgx/hsm/run new file mode 100755 index 00000000..44d972af --- /dev/null +++ b/dist/sgx/hsm/run @@ -0,0 +1,27 @@ +#!/bin/bash + +BINDIR=$(realpath $(dirname $0)) +WORKDIR=$(realpath $BINDIR/..) +DOCKER_IMAGE=powhsmsgx:runner + +QUIET="" +echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." +if [[ "$2" != "-v" ]]; then + QUIET="-q" + echo -e "Run with '-v' if you want to see progress detail\e[94m" +fi +docker build -t $DOCKER_IMAGE $BINDIR $QUIET +echo -e "\e[96mDocker image build done.\e[0m" +echo + +DOCKER_CNT=powhsmsgx-runner +DOCKER_USER="$(id -u):$(id -g)" +PORT=7777 +DOCKER_PORT="$PORT:$PORT" + +docker run -ti --rm --name $DOCKER_CNT --user $DOCKER_USER -v $WORKDIR:/hsm \ + --device=/dev/sgx_enclave:/dev/sgx_enclave \ + --device=/dev/sgx_provision:/dev/sgx_provision \ + -w /hsm -p$DOCKER_PORT $DOCKER_IMAGE \ + bin/hsmsgx ./bin/hsmsgx_enclave.signed -p$PORT -b0.0.0.0 + # TODO: We need to resolve binding so that not everyone can connect to the service! diff --git a/dist/sgx/scripts/run_with_docker b/dist/sgx/scripts/run_with_docker new file mode 100755 index 00000000..d0eeb75f --- /dev/null +++ b/dist/sgx/scripts/run_with_docker @@ -0,0 +1,24 @@ +#!/bin/bash + +pushd $(dirname $0)/.. > /dev/null +DIST_DIR=$(pwd) +popd > /dev/null +DOCKER_IMAGE=powhsmsgx:setup + +QUIET="" +echo -e "\e[96mBuilding docker image $DOCKER_IMAGE (this will take a few minutes)..." +if [[ "$2" != "-v" ]]; then + QUIET="-q" + echo -e "Run with '-v' if you want to see progress detail\e[94m" +fi +docker build -t $DOCKER_IMAGE $DIST_DIR $QUIET +echo -e "\e[96mDocker image build done.\e[0m" +echo + +DOCKER_USER="$(id -u):$(id -g)" + +docker run -ti --rm --user $DOCKER_USER \ + --device=/dev/sgx_enclave:/dev/sgx_enclave \ + --device=/dev/sgx_provision:/dev/sgx_provision \ + -v $DIST_DIR:/setup -v /:/fs -w /setup \ + $DOCKER_IMAGE $1 diff --git a/dist/sgx/scripts/setup b/dist/sgx/scripts/setup new file mode 100755 index 00000000..b118e26f --- /dev/null +++ b/dist/sgx/scripts/setup @@ -0,0 +1,157 @@ +#!/bin/bash + +pushd $(dirname $0)/.. > /dev/null +ROOT_DIR="$(pwd)" +popd > /dev/null + +# HSM binaries directory +HSMBIN_DIR=$ROOT_DIR/hsm + +# HSM binaries +HSMSGX_BINARY=hsmsgx +HSMSGX_ENCLAVE_BINARY=hsmsgx_enclave.signed + +# Middleware binaries +ADMIN_DIR="$ROOT_DIR/bin/adm_sgx" +ADMIN_BUNDLE="$ADMIN_DIR.tgz" +ADMIN="$ADMIN_DIR/adm_sgx" + +function cleanBinaries() { + rm -rf $ADMIN_DIR +} + +function expandBinaries() { + cleanBinaries + + mkdir -p $ADMIN_DIR + tar -xzmf $ADMIN_BUNDLE -C $ADMIN_DIR +} + +# Potentially existing file with an existing pin +PIN_FILE="$ROOT_DIR/pin.txt" + +# Directory where public keys will be saved after onboarding is done +EXPORT_DIR="$ROOT_DIR/export" +PUBLIC_KEY_FILE="$EXPORT_DIR/public-keys.txt" +PUBLIC_KEY_FILE_JSON="$EXPORT_DIR/public-keys.json" + +function checkHsmBinaries() { + # Check for HSM binary files + FILES="$HSMBIN_DIR/hsmsgx $HSMBIN_DIR/hsmsgx_enclave.signed" + for f in ${FILES}; do + if [[ ! -e $f ]]; then + echo -e "\e[1;31m HSM binary file '$(basename $f)' does not exist. \e[0m" + cleanBinaries + exit 1 + fi + done +} + +function error() { + if [ $? -ne 0 ]; then + echo -e "\e[1;31m Error comunicating with the dongle. Please check connection and restart the process. \e[0m" + cleanBinaries + exit 1 + fi +} + +function checkForPinFile() { + if [[ -e $PIN_FILE ]]; then + echo -e "\e[1;31m Legacy pin file '$(basename $PIN_FILE)' found. Please backup and remove before continuing. \e[0m" + cleanBinaries + exit 1 + fi +} + +function selectInstallationDir() { + while true; do + echo -e "\e[1;32mEnter the absolute path to the installation directory (empty directory name to abort)\e[0m" + while true; do + read -p "> " INSTALL_DIR + if [[ "$INSTALL_DIR" == "" ]]; then + echo -e "\e[1;31mAborted.\e[0m" + exit 1 + fi + REAL_INSTALL_DIR=$(realpath /fs/$INSTALL_DIR) + INSTALL_DIR=/$(realpath $REAL_INSTALL_DIR --relative-to=/fs/) + + if [ -d "$REAL_INSTALL_DIR" ]; then + echo -e "\e[1;31mDirectory exists: $INSTALL_DIR. Try again or enter empty directory name to abort.\e[0m" + else + if ! mkdir "$REAL_INSTALL_DIR"; then + echo -e "\e[1;31mCould not create directory: $INSTALL_DIR. Try again or enter empty directory name to abort.\e[0m" + else + echo -e "\e[1;33mpowHSM will be installed to $INSTALL_DIR\e[0m" + break + fi + fi + done + echo -e "\e[1;32mProceed? [Y/N]\e[0m" + read -p "> " proceed + if [[ "Y" == "$proceed" ]] || [[ "y" == "$proceed" ]]; then + break; + else + rmdir $REAL_INSTALL_DIR + fi + done +} + +function installPowHsm() { + mkdir $REAL_INSTALL_DIR/bin + cp -R $HSMBIN_DIR/* $REAL_INSTALL_DIR/bin + cp -R $ROOT_DIR/Dockerfile $REAL_INSTALL_DIR/bin +} + +function startPowHsm() { + pushd $REAL_INSTALL_DIR > /dev/null + bin/$HSMSGX_BINARY bin/$HSMSGX_ENCLAVE_BINARY > /dev/null 2> /dev/null & + HSMSGX_PID=$! + popd > /dev/null +} + +function stopPowHsm() { + kill $HSMSGX_PID +} + +function createOutputDir() { + rm -rf $EXPORT_DIR + mkdir -p $EXPORT_DIR +} + +function onboard() { + $ADMIN onboard + error +} + +function keys() { + $ADMIN pubkeys -o $PUBLIC_KEY_FILE + error +} + + +echo -e "\e[1;32mWelcome to the SGX powHSM Setup for RSK \e[0m" +checkForPinFile +checkHsmBinaries +expandBinaries +selectInstallationDir +echo +echo -e "\e[1;32mInstalling the powHSM...\e[0m" +installPowHsm +echo +echo -e "\e[1;32mStarting the powHSM...\e[0m" +startPowHsm +echo +echo -e "\e[1;33mOnboarding the powHSM... \e[0m" +onboard +echo -e "\e[1;33mOnboarding complete.\e[0m" +echo +echo -e "\e[1;32mGathering public keys\e[0m" +createOutputDir +keys +echo +echo -e "\e[1;32mStopping the powHSM...\e[0m" +stopPowHsm +cleanBinaries +echo +echo -e "\e[1;32mpowHSM Setup complete. Find the installation in $INSTALL_DIR.\e[0m" +exit 0 diff --git a/dist/sgx/setup-new-powhsm b/dist/sgx/setup-new-powhsm new file mode 100755 index 00000000..1398782a --- /dev/null +++ b/dist/sgx/setup-new-powhsm @@ -0,0 +1,3 @@ +#!/bin/bash + +$(dirname $0)/scripts/run_with_docker ./scripts/setup $1 diff --git a/middleware/build/dist_sgx b/middleware/build/dist_sgx new file mode 100755 index 00000000..a2b6c432 --- /dev/null +++ b/middleware/build/dist_sgx @@ -0,0 +1,12 @@ +#!/bin/bash + +BUILDDIR=$(dirname $0) +BINDIR=$(realpath $BUILDDIR/../bin/) + +echo "Building SGX distribution binaries..." + +QUIET=1 $BUILDDIR/manager_sgx && \ +QUIET=1 $BUILDDIR/adm_sgx && \ +echo "" && \ +sha256sum $BINDIR/manager_sgx.tgz && \ +sha256sum $BINDIR/adm_sgx.tgz diff --git a/middleware/tests/sgx/test_hsm2dongle.py b/middleware/tests/sgx/test_hsm2dongle.py index b3a48ba4..81a5779d 100644 --- a/middleware/tests/sgx/test_hsm2dongle.py +++ b/middleware/tests/sgx/test_hsm2dongle.py @@ -88,3 +88,54 @@ def test_get_retries(self): self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x05, 0xDD]) self.assertEqual(5, self.hsm2dongle.get_retries()) self.assert_exchange_called(bytes([0x80, 0xA2])) + + def test_onboard_ok(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + self.assertTrue(self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b"12345678")) + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678") + + def test_onboard_seed_invalid_type(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(1234, b"12345678") + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_seed_invalid_length(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(b"abcd", b"12345678") + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_pin_invalid_type(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0x01]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), 4444) + + self.assertFalse(self.dongle.exchange.called) + + def test_onboard_error_result(self): + self.dongle.exchange.return_value = bytes([0xAA, 0xBB, 0xCC]) + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b'12345678') + + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678") + + def test_onboard_error_xchg(self): + self.dongle.exchange.side_effect = RuntimeError("SomethingWentWrong") + + with self.assertRaises(HSM2DongleError): + self.hsm2dongle.onboard(bytes.fromhex("aa"*32), b'12345678') + + self.assert_exchange_called(bytes([0x80, 0xA0, 0x00]) + + bytes.fromhex("aa"*32) + + b"12345678")