From e9b944244d8e3ccd84cd3a3ed8c7d13ca49034b1 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 01/25] Add nix/env.sh and show what app is being built in Makefile --- Makefile | 9 ++++++++- default.nix | 11 ++++++++++- nix/env.sh | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100755 nix/env.sh diff --git a/Makefile b/Makefile index 814b4237..ba1c1017 100644 --- a/Makefile +++ b/Makefile @@ -51,10 +51,17 @@ ifeq ($(COMMIT),) endif ICONNAME=icon.gif + ################ # Default rule # ################ -all: default +all: show-app default + + +.PHONY: show-app +show-app: + @echo ">>>>> Building $(APP) at commit $(COMMIT)" + ############ # Platform # diff --git a/default.nix b/default.nix index f8edda55..4d3ee579 100644 --- a/default.nix +++ b/default.nix @@ -26,7 +26,7 @@ let export APP='${if bakingApp then "tezos_baking" else "tezos_wallet"}' export COMMIT='${commit}' make clean - make + make all EOF mkdir -p "$out" @@ -45,4 +45,13 @@ in rec { cp '${baking}/bin/app.hex' baking.hex tar czf "$out" wallet.hex baking.hex ''; + + # Script that places you in the environment to run `make`, etc. + env-shell = pkgs.writeScriptBin "env-shell" '' + #!${pkgs.stdenv.shell} + export BOLOS_SDK='${bolosSdk}' + export BOLOS_ENV='${bolosEnv}' + export COMMIT='${commit}' + exec '${fhs}/bin/enter-fhs' + ''; } diff --git a/nix/env.sh b/nix/env.sh new file mode 100755 index 00000000..91a52d9c --- /dev/null +++ b/nix/env.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +commit=$(git describe --abbrev=8 --always 2>/dev/null) +echo >&2 "Git commit: $commit" +shell_dir="$(nix-build -A env-shell --no-out-link --argstr commit "$commit" "${NIX_BUILD_ARGS:-}")" +shell="$shell_dir/bin/env-shell" + +if [ $# -eq 0 ]; then + echo >&2 "Entering via $shell" + exec "$shell" +else + exec "$shell" < Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 02/25] Add watch script --- nix/watch.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 nix/watch.sh diff --git a/nix/watch.sh b/nix/watch.sh new file mode 100755 index 00000000..35cd7bd8 --- /dev/null +++ b/nix/watch.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -uo pipefail + +root="$(git rev-parse --show-toplevel)" + +fail() { unset ___empty; : "${___empty:?$1}"; } + +[ -z "${1:-}" ] && fail "No command given; try running $0 make" + +watchdirs=("$root/default.nix" "$root/nix" "$root/Makefile" "$root/src") + +inotifywait="$(nix-build '' -A inotify-tools --no-out-link)/bin/inotifywait" +while true; do + "$root/nix/env.sh" < Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 03/25] Improve install scripts --- install.sh | 13 +++++++------ nix/install.sh | 15 ++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/install.sh b/install.sh index 01a4c510..36dd0114 100755 --- a/install.sh +++ b/install.sh @@ -1,24 +1,25 @@ -#!/bin/sh -set -eux +#!/usr/bin/env bash +set -Eeuo pipefail -rootdir="$(cd "$(dirname "$0")"/; pwd)" +root="$(git rev-parse --show-toplevel)" app_name=Tezos if [ "${1:-}X" != X ]; then app_name="$1" fi -app_file=$rootdir/bin/app.hex +app_file="$root/bin/app.hex" if [ "${2:-}X" != X ]; then app_file="$2" fi if [ "${3:-}X" = X ]; then - version="$(git -C "$rootdir" describe --tags | cut -f1 -d- | cut -f2 -dv)" + version="$(git -C "$root" describe --tags | cut -f1 -d- | cut -f2 -dv)" else version="$3" fi + set -x python -m ledgerblue.loadApp \ --appFlags 0x00 \ @@ -33,5 +34,5 @@ python -m ledgerblue.loadApp \ --fileName "$app_file" \ --appName "$app_name" \ --appVersion "$version" \ - --icon "$(cat "$rootdir/dist/icon.hex")" \ + --icon "$(cat "$root/dist/icon.hex")" \ --targetVersion "" diff --git a/nix/install.sh b/nix/install.sh index a80ee37f..ff85c031 100755 --- a/nix/install.sh +++ b/nix/install.sh @@ -1,23 +1,24 @@ #!/usr/bin/env bash -set -Eeuxo pipefail +set -Eeuo pipefail -rootdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd ) +root="$(git rev-parse --show-toplevel)" -: "${VERSION:=${2:-"$(git -C "$rootdir" describe --tags | cut -f1 -d- | cut -f2 -dv)"}}" +: "${VERSION:=${2:-"$(git -C "$root" describe --tags | cut -f1 -d- | cut -f2 -dv)"}}" install-wallet() { - "$rootdir/install.sh" 'Tezos Wallet' "$("$rootdir/nix/build.sh" -A wallet)/bin/app.hex" "$VERSION" + "$root/install.sh" 'Tezos Wallet' "$("$root/nix/build.sh" -A wallet)/bin/app.hex" "$VERSION" } install-baking() { - "$rootdir/install.sh" 'Tezos Baking' "$("$rootdir/nix/build.sh" -A baking)/bin/app.hex" "$VERSION" + "$root/install.sh" 'Tezos Baking' "$("$root/nix/build.sh" -A baking)/bin/app.hex" "$VERSION" } -export rootdir +export root export VERSION export -f install-wallet export -f install-baking -nix-shell "$rootdir/nix/ledgerblue.nix" -A shell --run "$(cat < Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 04/25] Automatically detect NVRAM data size during install --- install.sh | 8 ++++---- nix/install.sh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index 36dd0114..ef6a63ef 100755 --- a/install.sh +++ b/install.sh @@ -8,9 +8,9 @@ if [ "${1:-}X" != X ]; then app_name="$1" fi -app_file="$root/bin/app.hex" +app_dir="$root" if [ "${2:-}X" != X ]; then - app_file="$2" + app_dir="$2" fi if [ "${3:-}X" = X ]; then @@ -23,7 +23,7 @@ fi set -x python -m ledgerblue.loadApp \ --appFlags 0x00 \ - --dataSize 0x80 \ + --dataSize "$(grep _nvram_data_size "$app_dir/debug/app.map" | tr -s ' ' | cut -f2 -d' ')" \ --tlv \ --curve ed25519 \ --curve secp256k1 \ @@ -31,7 +31,7 @@ python -m ledgerblue.loadApp \ --targetId "${TARGET_ID:-0x31100004}" \ --delete \ --path 44"'"/1729"'" \ - --fileName "$app_file" \ + --fileName "$app_dir/bin/app.hex" \ --appName "$app_name" \ --appVersion "$version" \ --icon "$(cat "$root/dist/icon.hex")" \ diff --git a/nix/install.sh b/nix/install.sh index ff85c031..da9f7a2f 100755 --- a/nix/install.sh +++ b/nix/install.sh @@ -6,10 +6,10 @@ root="$(git rev-parse --show-toplevel)" : "${VERSION:=${2:-"$(git -C "$root" describe --tags | cut -f1 -d- | cut -f2 -dv)"}}" install-wallet() { - "$root/install.sh" 'Tezos Wallet' "$("$root/nix/build.sh" -A wallet)/bin/app.hex" "$VERSION" + "$root/install.sh" 'Tezos Wallet' "$("$root/nix/build.sh" -A wallet)" "$VERSION" } install-baking() { - "$root/install.sh" 'Tezos Baking' "$("$root/nix/build.sh" -A baking)/bin/app.hex" "$VERSION" + "$root/install.sh" 'Tezos Baking' "$("$root/nix/build.sh" -A baking)" "$VERSION" } export root From bd7f8b24aeaf49e18d3ce69803c79b8dd6d57486 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 05/25] Clean up test/apdu.sh --- test/apdu.sh | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/apdu.sh b/test/apdu.sh index 1c3c0d01..df7647b6 100755 --- a/test/apdu.sh +++ b/test/apdu.sh @@ -1,9 +1,5 @@ #!/usr/bin/env bash -set -eu +set -Eeuo pipefail -DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -cd "$DIR" - -if ! nix-shell ledger-blue-shell.nix --pure --run 'python -m ledgerblue.runScript --apdu'; then - python -m ledgerblue.runScript --apdu -fi +root="$(git rev-parse --show-toplevel)" +nix-shell "$root/nix/ledgerblue.nix" -A shell --pure --run 'python -m ledgerblue.runScript --apdu' From 2a650cb87ee1c572c91ecec7959f55fd90d486fc Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 06/25] Change copy_string for reasons --- src/to_string.c | 8 ++++---- src/to_string.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/to_string.c b/src/to_string.c index f7122c21..7673657a 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -190,9 +190,9 @@ size_t microtez_to_string(char *dest, uint64_t number) { return off; } -void copy_string(char *dest, uint32_t buff_size, const char *src_in) { - const char *src = (const char *)PIC(src_in); +void copy_string(char *const dest, size_t const buff_size, char const *const src) { + char const *const src_in = (char const *)PIC(src); // I don't care that we will loop through the string twice, latency is not an issue - if (strlen(src) >= buff_size) THROW(EXC_WRONG_LENGTH); - strcpy(dest, src); + if (strlen(src_in) >= buff_size) THROW(EXC_WRONG_LENGTH); + strcpy(dest, src_in); } diff --git a/src/to_string.h b/src/to_string.h index 13bbe9b0..2943501d 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -26,4 +26,4 @@ void microtez_to_string_indirect(char *dest, uint32_t buff_size, const uint64_t // This is designed to be called with potentially unrelocated pointers from rodata tables // for the src argument, so performs PIC on src. -void copy_string(char *dest, uint32_t buff_size, const char *src); +void copy_string(char *const dest, size_t const buff_size, char const *const src); From ebe6592509bc1ed03ff51becf4735d7e90d2bac5 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 07/25] Clean up headers --- src/apdu.h | 1 - src/keys.c | 3 --- src/keys.h | 3 +-- src/main.c | 4 ++-- src/os_cx.h | 5 +++++ 5 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 src/os_cx.h diff --git a/src/apdu.h b/src/apdu.h index 385843af..f3bf9fbf 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -5,7 +5,6 @@ #include "keys.h" #include "ui.h" -// Order matters #include "os.h" #include diff --git a/src/keys.c b/src/keys.c index a6054627..787acaee 100644 --- a/src/keys.c +++ b/src/keys.c @@ -22,9 +22,6 @@ #include "globals.h" #include "protocol.h" -// Order matters -#include "os.h" - #include #include diff --git a/src/keys.h b/src/keys.h index 08a23f34..6d592e45 100644 --- a/src/keys.h +++ b/src/keys.h @@ -3,10 +3,9 @@ #include #include #include -#include "os.h" -#include "cx.h" #include "exception.h" +#include "os_cx.h" #include "types.h" // Throws upon error diff --git a/src/main.c b/src/main.c index 90707a7c..9daf7499 100644 --- a/src/main.c +++ b/src/main.c @@ -15,10 +15,10 @@ * limitations under the License. ********************************************************************************/ -#include "apdu.h" +#include "apdu_baking.h" #include "apdu_pubkey.h" #include "apdu_sign.h" -#include "apdu_baking.h" +#include "apdu.h" #include "globals.h" #include "memory.h" diff --git a/src/os_cx.h b/src/os_cx.h new file mode 100644 index 00000000..c1e92cb1 --- /dev/null +++ b/src/os_cx.h @@ -0,0 +1,5 @@ +#pragma once + +// Order matters +#include "os.h" +#include "cx.h" From c7a3bb59c8ac3ebe467350873b12150e4a7adfad Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 08/25] Centralize APDU instruction table --- src/apdu.h | 17 +++++++++++++---- src/apdu_baking.h | 4 ---- src/apdu_pubkey.h | 4 ---- src/apdu_sign.h | 3 --- src/globals.h | 2 -- src/main.c | 20 ++++++++++---------- src/types.h | 8 ++++++++ 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/apdu.h b/src/apdu.h index f3bf9fbf..0003892c 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -15,13 +15,22 @@ #endif #define OFFSET_CLA 0 -#define OFFSET_INS 1 -#define OFFSET_P1 2 +#define OFFSET_INS 1 // instruction code +#define OFFSET_P1 2 // user-defined 1-byte parameter #define OFFSET_CURVE 3 -#define OFFSET_LC 4 -#define OFFSET_CDATA 5 +#define OFFSET_LC 4 // length of CDATA +#define OFFSET_CDATA 5 // payload +// Instruction codes #define INS_VERSION 0x00 +#define INS_AUTHORIZE_BAKING 0x01 +#define INS_GET_PUBLIC_KEY 0x02 +#define INS_PROMPT_PUBLIC_KEY 0x03 +#define INS_SIGN 0x04 +#define INS_SIGN_UNSAFE 0x05 // Data that is already hashed. +#define INS_RESET 0x06 +#define INS_QUERY_AUTH_KEY 0x07 +#define INS_QUERY_HWM 0x08 #define INS_GIT 0x09 __attribute__((noreturn)) diff --git a/src/apdu_baking.h b/src/apdu_baking.h index 1d60df1e..b32e8fcd 100644 --- a/src/apdu_baking.h +++ b/src/apdu_baking.h @@ -2,10 +2,6 @@ #include -#define INS_RESET 0x06 -#define INS_QUERY_AUTH_KEY 0x07 -#define INS_QUERY_HWM 0x08 - unsigned int handle_apdu_reset(uint8_t instruction); unsigned int handle_apdu_query_auth_key(uint8_t instruction); unsigned int handle_apdu_hwm(uint8_t instruction); diff --git a/src/apdu_pubkey.h b/src/apdu_pubkey.h index ebda2972..460ca218 100644 --- a/src/apdu_pubkey.h +++ b/src/apdu_pubkey.h @@ -2,8 +2,4 @@ #include "apdu.h" -#define INS_AUTHORIZE_BAKING 0x01 -#define INS_GET_PUBLIC_KEY 0x02 -#define INS_PROMPT_PUBLIC_KEY 0x03 - unsigned int handle_apdu_get_public_key(uint8_t instruction); diff --git a/src/apdu_sign.h b/src/apdu_sign.h index dac7a31f..0e5ad17c 100644 --- a/src/apdu_sign.h +++ b/src/apdu_sign.h @@ -2,7 +2,4 @@ #include "apdu.h" -#define INS_SIGN 0x04 -#define INS_SIGN_UNSAFE 0x05 // Data that is already hashed. - unsigned int handle_apdu_sign(uint8_t instruction); diff --git a/src/globals.h b/src/globals.h index afb7c57a..62adcc96 100644 --- a/src/globals.h +++ b/src/globals.h @@ -15,8 +15,6 @@ void init_globals(void); # define TEZOS_BUFSIZE 256 #endif -#define INS_MAX 0x0B - #define PRIVATE_KEY_DATA_SIZE 32 struct priv_generate_key_pair { diff --git a/src/main.c b/src/main.c index 9daf7499..73a95d08 100644 --- a/src/main.c +++ b/src/main.c @@ -28,19 +28,19 @@ void app_main(void) { for (size_t i = 0; i < NUM_ELEMENTS(global.handlers); i++) { global.handlers[i] = handle_apdu_error; } - global.handlers[INS_VERSION] = handle_apdu_version; - global.handlers[INS_GET_PUBLIC_KEY] = handle_apdu_get_public_key; - global.handlers[INS_PROMPT_PUBLIC_KEY] = handle_apdu_get_public_key; + global.handlers[APDU_INS(INS_VERSION)] = handle_apdu_version; + global.handlers[APDU_INS(INS_GET_PUBLIC_KEY)] = handle_apdu_get_public_key; + global.handlers[APDU_INS(INS_PROMPT_PUBLIC_KEY)] = handle_apdu_get_public_key; #ifdef BAKING_APP - global.handlers[INS_AUTHORIZE_BAKING] = handle_apdu_get_public_key; - global.handlers[INS_RESET] = handle_apdu_reset; - global.handlers[INS_QUERY_AUTH_KEY] = handle_apdu_query_auth_key; - global.handlers[INS_QUERY_HWM] = handle_apdu_hwm; + global.handlers[APDU_INS(INS_AUTHORIZE_BAKING)] = handle_apdu_get_public_key; + global.handlers[APDU_INS(INS_RESET)] = handle_apdu_reset; + global.handlers[APDU_INS(INS_QUERY_AUTH_KEY)] = handle_apdu_query_auth_key; + global.handlers[APDU_INS(INS_QUERY_HWM)] = handle_apdu_hwm; #endif - global.handlers[INS_SIGN] = handle_apdu_sign; + global.handlers[APDU_INS(INS_SIGN)] = handle_apdu_sign; #ifndef BAKING_APP - global.handlers[INS_SIGN_UNSAFE] = handle_apdu_sign; + global.handlers[APDU_INS(INS_SIGN_UNSAFE)] = handle_apdu_sign; #endif - global.handlers[INS_GIT] = handle_apdu_git; + global.handlers[APDU_INS(INS_GIT)] = handle_apdu_git; main_loop(global.handlers); } diff --git a/src/types.h b/src/types.h index ba3b8a43..ab93d70a 100644 --- a/src/types.h +++ b/src/types.h @@ -119,3 +119,11 @@ struct parsed_operation_group { struct parsed_contract signing; struct parsed_operation operation; }; + +// Maximum number of APDU instructions +#define INS_MAX 0x0B + +#define APDU_INS(x) ({ \ + _Static_assert(x <= INS_MAX, "APDU instruction is out of bounds"); \ + x; \ +}) From 1091eb2fc45dc4c1ea862d23b674eccdcbb08f3b Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 09/25] Move throw_stack_size to globals.h --- src/apdu.h | 9 +-------- src/globals.h | 8 ++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/apdu.h b/src/apdu.h index 0003892c..ff6dc47c 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -1,8 +1,8 @@ #pragma once #include "exception.h" -#include "globals.h" #include "keys.h" +#include "types.h" #include "ui.h" #include "os.h" @@ -61,10 +61,3 @@ static inline void require_hid(void) { uint32_t handle_apdu_error(uint8_t instruction); uint32_t handle_apdu_version(uint8_t instruction); uint32_t handle_apdu_git(uint8_t instruction); - -static inline void throw_stack_size() { - uint8_t st; - // uint32_t tmp1 = (uint32_t)&st - (uint32_t)&app_stack_canary; - uint32_t tmp2 = (uint32_t)global.stack_root - (uint32_t)&st; - THROW(0x9000 + tmp2); -} diff --git a/src/globals.h b/src/globals.h index 62adcc96..03e747bc 100644 --- a/src/globals.h +++ b/src/globals.h @@ -109,3 +109,11 @@ extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; extern WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? #define N_data (*(WIDE nvram_data*)PIC(&N_data_real)) + + +static inline void throw_stack_size() { + uint8_t st; + // uint32_t tmp1 = (uint32_t)&st - (uint32_t)&app_stack_canary; + uint32_t tmp2 = (uint32_t)global.stack_root - (uint32_t)&st; + THROW(0x9000 + tmp2); +} From 160d6f31658c93345e30748a41c317b33a476de6 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 10/25] Add some helpful debug macros --- src/memory.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/memory.h b/src/memory.h index 42d3413e..dea9ea22 100644 --- a/src/memory.h +++ b/src/memory.h @@ -7,3 +7,8 @@ memcmp(a, b, sizeof(*a)); \ }) #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(*a)) + + +// Macro that produces a compile-error showing the sizeof the argument. +#define ERROR_WITH_NUMBER_EXPANSION(x) char (*__kaboom)[x] = 1; +#define SIZEOF_ERROR(x) ERROR_WITH_NUMBER_EXPANSION(sizeof(x)); From 5f3d29d9b7bbe2321a47f6444b3c78dd59653998 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 11/25] Refactor to use bip32_path struct --- src/apdu.c | 2 +- src/apdu_baking.c | 6 +++--- src/apdu_pubkey.c | 17 ++++++++--------- src/apdu_sign.c | 23 +++++++++++------------ src/baking_auth.c | 31 ++++++++++++++----------------- src/baking_auth.h | 7 +++---- src/globals.h | 6 ++---- src/keys.c | 32 +++++++++++++++++--------------- src/keys.h | 11 ++++++++--- src/operations.c | 10 +++++----- src/operations.h | 5 +++-- src/protocol.h | 6 +++++- src/types.h | 25 +++++++++++++++++++++++-- 13 files changed, 103 insertions(+), 78 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index 17d59501..31f3e4d3 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -55,7 +55,7 @@ void main_loop(apdu_handler handlers[INS_MAX]) { THROW(EXC_WRONG_LENGTH); } - uint8_t instruction = G_io_apdu_buffer[OFFSET_INS]; + const uint8_t instruction = G_io_apdu_buffer[OFFSET_INS]; const apdu_handler cb = (instruction >= INS_MAX) ? handle_apdu_error : handlers[instruction]; diff --git a/src/apdu_baking.c b/src/apdu_baking.c index b17e51bf..ac43444a 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -76,13 +76,13 @@ unsigned int handle_apdu_hwm(__attribute__((unused)) uint8_t instruction) { } unsigned int handle_apdu_query_auth_key(__attribute__((unused)) uint8_t instruction) { - uint32_t tx = 0; + uint8_t const length = N_data.bip32_path.length; - uint8_t length = N_data.path_length; + uint32_t tx = 0; G_io_apdu_buffer[tx++] = length; for (uint8_t i = 0; i < length; ++i) { - tx = send_word_big_endian(tx, N_data.bip32_path[i]); + tx = send_word_big_endian(tx, N_data.bip32_path.components[i]); } G_io_apdu_buffer[tx++] = 0x90; diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 244f4440..e90d2ea7 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -11,8 +11,8 @@ #include -static int provide_pubkey(void) { - int tx = 0; +static uint32_t provide_pubkey(void) { + uint32_t tx = 0; G_io_apdu_buffer[tx++] = global.u.pubkey.public_key.W_len; os_memmove(G_io_apdu_buffer + tx, global.u.pubkey.public_key.W, @@ -24,14 +24,14 @@ static int provide_pubkey(void) { } static bool pubkey_ok(void) { - int tx = provide_pubkey(); + uint32_t const tx = provide_pubkey(); delayed_send(tx); return true; } #ifdef BAKING_APP static bool baking_ok(void) { - authorize_baking(global.u.pubkey.curve, global.u.pubkey.bip32_path, global.u.pubkey.bip32_path_length); + authorize_baking(global.u.pubkey.curve, &global.u.pubkey.bip32_path); pubkey_ok(); return true; } @@ -54,18 +54,17 @@ unsigned int handle_apdu_get_public_key(uint8_t instruction) { #ifdef BAKING_APP if (G_io_apdu_buffer[OFFSET_LC] == 0 && instruction == INS_AUTHORIZE_BAKING) { global.u.pubkey.curve = N_data.curve; - global.u.pubkey.bip32_path_length = N_data.path_length; - memcpy(global.u.pubkey.bip32_path, N_data.bip32_path, sizeof(*global.u.pubkey.bip32_path) * global.u.pubkey.bip32_path_length); + copy_bip32_path(&global.u.pubkey.bip32_path, &N_data.bip32_path); } else { #endif - global.u.pubkey.bip32_path_length = read_bip32_path(G_io_apdu_buffer[OFFSET_LC], global.u.pubkey.bip32_path, dataBuffer); + read_bip32_path(&global.u.pubkey.bip32_path, dataBuffer, G_io_apdu_buffer[OFFSET_LC]); #ifdef BAKING_APP - if (global.u.pubkey.bip32_path_length == 0) { + if (global.u.pubkey.bip32_path.length == 0) { THROW(EXC_WRONG_LENGTH_FOR_INS); } } #endif - struct key_pair *pair = generate_key_pair(global.u.pubkey.curve, global.u.pubkey.bip32_path_length, global.u.pubkey.bip32_path); + struct key_pair *pair = generate_key_pair(global.u.pubkey.curve, &global.u.pubkey.bip32_path); memset(&pair->private_key, 0, sizeof(pair->private_key)); memcpy(&global.u.pubkey.public_key, &pair->public_key, sizeof(global.u.pubkey.public_key)); diff --git a/src/apdu_sign.c b/src/apdu_sign.c index d5347b37..f683b679 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -52,7 +52,7 @@ static int perform_signature(bool hash_first); #ifdef BAKING_APP static bool bake_auth_ok(void) { - authorize_baking(global.u.sign.curve, global.u.sign.bip32_path, global.u.sign.bip32_path_length); + authorize_baking(global.u.sign.curve, &global.u.sign.bip32_path); int tx = perform_signature(true); delayed_send(tx); return true; @@ -72,7 +72,7 @@ static bool sign_unsafe_ok(void) { #endif static void clear_data(void) { - global.u.sign.bip32_path_length = 0; + global.u.sign.bip32_path.length = 0; global.u.sign.message_data_length = 0; global.u.sign.is_hash_state_inited = false; global.u.sign.magic_number = 0; @@ -93,7 +93,7 @@ uint32_t baking_sign_complete(void) { case MAGIC_BYTE_BAKING_OP: guard_baking_authorized( global.u.sign.curve, global.u.sign.message_data, global.u.sign.message_data_length, - global.u.sign.bip32_path, global.u.sign.bip32_path_length); + &global.u.sign.bip32_path); return perform_signature(true); case MAGIC_BYTE_UNSAFE_OP: @@ -107,8 +107,7 @@ uint32_t baking_sign_complete(void) { struct parsed_operation_group *ops = parse_operations( global.u.sign.message_data, global.u.sign.message_data_length, - global.u.sign.curve, global.u.sign.bip32_path_length, global.u.sign.bip32_path, - allowed); + global.u.sign.curve, &global.u.sign.bip32_path, allowed); // With < nickel fee if (ops->total_fee > 50000) THROW(EXC_PARSE_ERROR); @@ -146,8 +145,9 @@ const char *const insecure_values[] = { // Return false if the transaction isn't easily parseable, otherwise prompt with given callbacks // and do not return, but rather throw ASYNC. static bool prompt_transaction(const void *data, size_t length, cx_curve_t curve, - size_t path_length, uint32_t *bip32_path, + bip32_path_t const *const bip32_path, ui_callback_t ok, ui_callback_t cxl) { + check_null(bip32_path); struct parsed_operation_group *ops; #ifndef TEZOS_DEBUG @@ -167,7 +167,7 @@ static bool prompt_transaction(const void *data, size_t length, cx_curve_t curve allow_operation(&allowed, OPERATION_TAG_TRANSACTION); // TODO: Add still other operations - ops = parse_operations(data, length, curve, path_length, bip32_path, allowed); + ops = parse_operations(data, length, curve, bip32_path, allowed); #ifndef TEZOS_DEBUG } CATCH_OTHER(e) { @@ -443,7 +443,7 @@ uint32_t wallet_sign_complete(uint8_t instruction) { } if (!prompt_transaction( global.u.sign.message_data, global.u.sign.message_data_length, global.u.sign.curve, - global.u.sign.bip32_path_length, global.u.sign.bip32_path, sign_ok, sign_reject)) { + &global.u.sign.bip32_path, sign_ok, sign_reject)) { goto unsafe; } case MAGIC_BYTE_UNSAFE_OP2: @@ -472,7 +472,7 @@ unsigned int handle_apdu_sign(uint8_t instruction) { clear_data(); memset(global.u.sign.message_data, 0, sizeof(global.u.sign.message_data)); global.u.sign.message_data_length = 0; - global.u.sign.bip32_path_length = read_bip32_path(dataLength, global.u.sign.bip32_path, dataBuffer); + read_bip32_path(&global.u.sign.bip32_path, dataBuffer, dataLength); global.u.sign.curve = curve_code_to_curve(G_io_apdu_buffer[OFFSET_CURVE]); return_ok(); #ifndef BAKING_APP @@ -482,7 +482,7 @@ unsigned int handle_apdu_sign(uint8_t instruction) { // FALL THROUGH #endif case P1_NEXT: - if (global.u.sign.bip32_path_length == 0) { + if (global.u.sign.bip32_path.length == 0) { THROW(EXC_WRONG_LENGTH_FOR_INS); } break; @@ -545,8 +545,7 @@ static int perform_signature(bool hash_first) { #endif } - struct key_pair *pair = generate_key_pair( - global.u.sign.curve, global.u.sign.bip32_path_length, global.u.sign.bip32_path); + struct key_pair *const pair = generate_key_pair(global.u.sign.curve, &global.u.sign.bip32_path); uint32_t tx; switch (global.u.sign.curve) { diff --git a/src/baking_auth.c b/src/baking_auth.c index 8709bc0e..c8ce2bd6 100644 --- a/src/baking_auth.c +++ b/src/baking_auth.c @@ -3,6 +3,7 @@ #include "apdu.h" #include "globals.h" #include "keys.h" +#include "memory.h" #include "protocol.h" #include "to_string.h" #include "ui_prompt.h" @@ -26,16 +27,14 @@ void write_highest_level(level_t lvl, bool is_endorsement) { change_idle_display(N_data.highest_level); } -void authorize_baking(cx_curve_t curve, uint32_t *bip32_path, uint8_t path_length) { - if (bip32_path == NULL || path_length > MAX_BIP32_PATH || path_length == 0) { - return; - } +void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path) { + check_null(bip32_path); + if (bip32_path->length > NUM_ELEMENTS(N_data.bip32_path.components) || bip32_path->length == 0) return; global.baking_auth.new_data.highest_level = N_data.highest_level; global.baking_auth.new_data.had_endorsement = N_data.had_endorsement; global.baking_auth.new_data.curve = curve; - memcpy(global.baking_auth.new_data.bip32_path, bip32_path, path_length * sizeof(*bip32_path)); - global.baking_auth.new_data.path_length = path_length; + copy_bip32_path(&global.baking_auth.new_data.bip32_path, bip32_path); nvm_write((void*)&N_data, &global.baking_auth.new_data, sizeof(N_data)); change_idle_display(N_data.highest_level); } @@ -49,21 +48,19 @@ bool is_level_authorized(level_t level, bool is_endorsement) { return is_endorsement && !N_data.had_endorsement; } -bool is_path_authorized(cx_curve_t curve, uint32_t *bip32_path, uint8_t path_length) { - return bip32_path != NULL && - path_length != 0 && - path_length == N_data.path_length && +bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path) { + check_null(bip32_path); + return curve == N_data.curve && - memcmp(bip32_path, N_data.bip32_path, path_length * sizeof(*bip32_path)) == 0; + bip32_path->length > 0 && + bip32_paths_eq(bip32_path, &N_data.bip32_path); } -void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, uint32_t *bip32_path, - uint8_t path_length) { - if (!is_path_authorized(curve, bip32_path, path_length)) THROW(EXC_SECURITY); +void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, bip32_path_t const *const bip32_path) { + if (!is_path_authorized(curve, bip32_path)) THROW(EXC_SECURITY); struct parsed_baking_data baking_info; if (!parse_baking_data(data, datalen, &baking_info)) THROW(EXC_PARSE_ERROR); - if (!is_level_authorized(baking_info.level, baking_info.is_endorsement)) THROW(EXC_WRONG_VALUES); } @@ -77,10 +74,10 @@ void update_high_water_mark(void *data, int datalen) { } void update_auth_text(void) { - if (N_data.path_length == 0) { + if (N_data.bip32_path.length == 0) { strcpy(global.ui.baking_auth_text, "No Key Authorized"); } else { - struct key_pair *pair = generate_key_pair(N_data.curve, N_data.path_length, N_data.bip32_path); + struct key_pair *pair = generate_key_pair(N_data.curve, &N_data.bip32_path); memset(&pair->private_key, 0, sizeof(pair->private_key)); pubkey_to_pkh_string( global.ui.baking_auth_text, sizeof(global.ui.baking_auth_text), diff --git a/src/baking_auth.h b/src/baking_auth.h index a3309804..bbbfea59 100644 --- a/src/baking_auth.h +++ b/src/baking_auth.h @@ -7,10 +7,9 @@ #include #include -void authorize_baking(cx_curve_t curve, uint32_t *bip32_path, uint8_t pathLength); -void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, uint32_t *bip32_path, - uint8_t path_length); -bool is_path_authorized(cx_curve_t curve, uint32_t *bip32_path, uint8_t path_length); +void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path); +void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, bip32_path_t const *const bip32_path); +bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path); void update_high_water_mark(void *data, int datalen); void write_highest_level(level_t level, bool is_endorsement); bool is_level_authorized(level_t level, bool is_endorsement); diff --git a/src/globals.h b/src/globals.h index 03e747bc..77f7e7a7 100644 --- a/src/globals.h +++ b/src/globals.h @@ -33,14 +33,12 @@ typedef struct { struct { cx_ecfp_public_key_t public_key; - uint8_t bip32_path_length; - uint32_t bip32_path[MAX_BIP32_PATH]; + bip32_path_t bip32_path; cx_curve_t curve; } pubkey; struct { - uint8_t bip32_path_length; - uint32_t bip32_path[MAX_BIP32_PATH]; + bip32_path_t bip32_path; cx_curve_t curve; uint8_t message_data[TEZOS_BUFSIZE]; diff --git a/src/keys.c b/src/keys.c index 787acaee..a0b2e387 100644 --- a/src/keys.c +++ b/src/keys.c @@ -20,41 +20,43 @@ #include "apdu.h" #include "blake2.h" #include "globals.h" +#include "memory.h" #include "protocol.h" +#include "types.h" #include #include -uint32_t read_bip32_path(uint32_t bytes, uint32_t *bip32_path, const uint8_t *buf) { - uint32_t path_length = *buf; - if (bytes < path_length * sizeof(uint32_t) + 1) THROW(EXC_WRONG_LENGTH_FOR_INS); +size_t read_bip32_path(bip32_path_t *const out, uint8_t const *const in, size_t const in_size) { + struct bip32_path_wire const *const buf_as_bip32 = (struct bip32_path_wire const *)in; - buf++; + if (in_size < sizeof(buf_as_bip32->length)) THROW(EXC_WRONG_LENGTH_FOR_INS); - if (path_length == 0 || path_length > MAX_BIP32_PATH) { - screen_printf("Invalid path\n"); - THROW(EXC_WRONG_VALUES); - } + size_t ix = 0; + out->length = CONSUME_UNALIGNED_BIG_ENDIAN(ix, uint8_t, &buf_as_bip32->length); + + if (in_size - ix < out->length * sizeof(*buf_as_bip32->components)) THROW(EXC_WRONG_LENGTH_FOR_INS); + if (out->length == 0 || out->length > NUM_ELEMENTS(out->components)) THROW(EXC_WRONG_VALUES); - for (size_t i = 0; i < path_length; i++) { - bip32_path[i] = READ_UNALIGNED_BIG_ENDIAN(uint32_t, (uint32_t*)buf); - buf += 4; + for (size_t i = 0; i < out->length; i++) { + out->components[i] = CONSUME_UNALIGNED_BIG_ENDIAN(ix, uint32_t, &buf_as_bip32->components[i]); } - return path_length; + return ix; } -struct key_pair *generate_key_pair(cx_curve_t curve, uint32_t path_length, uint32_t *bip32_path) { +struct key_pair *generate_key_pair(cx_curve_t const curve, bip32_path_t const *const bip32_path) { + check_null(bip32_path); struct priv_generate_key_pair *const priv = &global.priv.generate_key_pair; #if CX_APILEVEL > 8 if (curve == CX_CURVE_Ed25519) { os_perso_derive_node_bip32_seed_key( - HDW_ED25519_SLIP10, curve, bip32_path, path_length, + HDW_ED25519_SLIP10, curve, bip32_path->components, bip32_path->length, priv->privateKeyData, NULL, NULL, 0); } else { #endif - os_perso_derive_node_bip32(curve, bip32_path, path_length, priv->privateKeyData, NULL); + os_perso_derive_node_bip32(curve, bip32_path->components, bip32_path->length, priv->privateKeyData, NULL); #if CX_APILEVEL > 8 } #endif diff --git a/src/keys.h b/src/keys.h index 6d592e45..5e3e839a 100644 --- a/src/keys.h +++ b/src/keys.h @@ -8,10 +8,15 @@ #include "os_cx.h" #include "types.h" -// Throws upon error -uint32_t read_bip32_path(uint32_t bytes, uint32_t *bip32_path, const uint8_t *buf); +struct bip32_path_wire { + uint8_t length; + uint32_t components[0]; +} __attribute__((packed)); -struct key_pair *generate_key_pair(cx_curve_t curve, uint32_t path_size, uint32_t *bip32_path); +// throws +size_t read_bip32_path(bip32_path_t *const out, uint8_t const *const in, size_t const in_size); + +struct key_pair *generate_key_pair(cx_curve_t const curve, bip32_path_t const *const bip32_path); cx_ecfp_public_key_t *public_key_hash(uint8_t output[HASH_SIZE], cx_curve_t curve, const cx_ecfp_public_key_t *restrict public_key); diff --git a/src/operations.c b/src/operations.c index 88b52223..072a672b 100644 --- a/src/operations.c +++ b/src/operations.c @@ -105,9 +105,9 @@ static inline uint64_t parse_z(const void *data, size_t *ix, size_t length, uint val; \ }) -static inline void compute_pkh(cx_curve_t curve, size_t path_length, uint32_t *bip32_path, - struct parsed_operation_group *out) { - struct key_pair *pair = generate_key_pair(curve, path_length, bip32_path); +static inline void compute_pkh(cx_curve_t curve, bip32_path_t const *const bip32_path, + struct parsed_operation_group *const out) { + check_null(bip32_path); memset(&pair->private_key, 0, sizeof(pair->private_key)); cx_ecfp_public_key_t *key = public_key_hash(out->signing.hash, curve, &pair->public_key); @@ -135,7 +135,7 @@ static inline void parse_contract(struct parsed_contract *out, const struct cont } struct parsed_operation_group *parse_operations(const void *data, size_t length, cx_curve_t curve, - size_t path_length, uint32_t *bip32_path, + bip32_path_t const *const bip32_path, allowed_operation_set ops) { check_null(data); check_null(bip32_path); @@ -145,7 +145,7 @@ struct parsed_operation_group *parse_operations(const void *data, size_t length, out->operation.tag = OPERATION_TAG_NONE; - compute_pkh(curve, path_length, bip32_path, out); // sets up "signing" and "public_key" members + compute_pkh(curve, bip32_path, out); // sets up "signing" and "public_key" members size_t ix = 0; diff --git a/src/operations.h b/src/operations.h index 4092e60b..c3d909dc 100644 --- a/src/operations.h +++ b/src/operations.h @@ -31,5 +31,6 @@ static inline void clear_operation_set(allowed_operation_set *ops) { // Returns pointer to static data -- non-reentrant as hell. struct parsed_operation_group * -parse_operations(const void *data, size_t length, cx_curve_t curve, size_t path_length, - uint32_t *bip32_path, allowed_operation_set ops); +parse_operations(const void *data, size_t length, cx_curve_t curve, + bip32_path_t const *const bip32_path, + allowed_operation_set ops); diff --git a/src/protocol.h b/src/protocol.h index 2df05ab4..892ef81e 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -22,7 +22,7 @@ static inline uint8_t get_magic_byte(const uint8_t *data, size_t length) { #define READ_UNALIGNED_BIG_ENDIAN(type, in) \ ({ \ - const uint8_t *bytes = (uint8_t*)in; \ + uint8_t const *bytes = (uint8_t const *)in; \ uint8_t out_bytes[sizeof(type)]; \ type res; \ \ @@ -33,3 +33,7 @@ static inline uint8_t get_magic_byte(const uint8_t *data, size_t length) { \ res; \ }) + +// Same as READ_UNALIGNED_BIG_ENDIAN but helps keep track of how many bytes +// have been read by adding sizeof(type) to the given counter. +#define CONSUME_UNALIGNED_BIG_ENDIAN(counter, type, addr) ({ counter += sizeof(type); READ_UNALIGNED_BIG_ENDIAN(type, addr); }) diff --git a/src/types.h b/src/types.h index ab93d70a..dedb1904 100644 --- a/src/types.h +++ b/src/types.h @@ -4,6 +4,7 @@ #include "os_io_seproxyhal.h" #include +#include // Return number of bytes to transmit (tx) typedef uint32_t (*apdu_handler)(uint8_t instruction); @@ -25,14 +26,34 @@ struct key_pair { // Baking Auth #define MAX_BIP32_PATH 10 + +typedef struct { + uint8_t length; + uint32_t components[MAX_BIP32_PATH]; +} bip32_path_t; + +static inline void copy_bip32_path(bip32_path_t *const out, bip32_path_t const *const in) { + memcpy(out->components, in->components, in->length * sizeof(*in->components)); + out->length = in->length; +} + +static inline bool bip32_paths_eq(bip32_path_t const *const a, bip32_path_t const *const b) { + return a == b || ( + a != NULL && + b != NULL && + a->length == b->length && + memcmp(a->components, b->components, a->length * sizeof(*a->components)) == 0 + ); +} + typedef struct { cx_curve_t curve; level_t highest_level; bool had_endorsement; - uint8_t path_length; - uint32_t bip32_path[MAX_BIP32_PATH]; + bip32_path_t bip32_path; } nvram_data; + #define PKH_STRING_SIZE 40 #define PROTOCOL_HASH_BASE58_STRING_SIZE 52 // e.g. "ProtoBetaBetaBetaBetaBetaBetaBetaBetaBet11111a5ug96" plus null byte From 7da20afc458f20a57ea1258a60e83a425bbbe831 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 12/25] Clean up headers --- src/apdu_baking.c | 5 +---- src/apdu_pubkey.c | 4 +--- src/baking_auth.c | 4 +--- src/to_string.h | 4 +--- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/apdu_baking.c b/src/apdu_baking.c index ac43444a..6c580514 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -3,14 +3,11 @@ #include "apdu.h" #include "baking_auth.h" #include "globals.h" +#include "os_cx.h" #include "protocol.h" #include "to_string.h" #include "ui_prompt.h" -// Order matters -#include "cx.h" -#include "os.h" - #include static bool reset_ok(void); diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index e90d2ea7..b18eea46 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -2,13 +2,11 @@ #include "apdu.h" #include "baking_auth.h" +#include "cx.h" #include "globals.h" #include "keys.h" #include "ui.h" -// Order matters -#include "cx.h" - #include static uint32_t provide_pubkey(void) { diff --git a/src/baking_auth.c b/src/baking_auth.c index c8ce2bd6..1b829fe5 100644 --- a/src/baking_auth.c +++ b/src/baking_auth.c @@ -8,9 +8,7 @@ #include "to_string.h" #include "ui_prompt.h" -// Order matters -#include "os.h" -#include "cx.h" +#include "os_cx.h" #include diff --git a/src/to_string.h b/src/to_string.h index 2943501d..3eb5516d 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -5,9 +5,7 @@ #include "keys.h" #include "operations.h" - -#include "os.h" -#include "cx.h" +#include "os_cx.h" #include "ui.h" void pubkey_to_pkh_string(char *buff, uint32_t buff_size, cx_curve_t curve, From ac036ba6889ca2fac126c3c7a0c673ea411d1cc7 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 13/25] Add setup APDU --- src/apdu.h | 1 + src/apdu_baking.c | 16 ++++--- src/apdu_setup.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++ src/apdu_setup.h | 5 +++ src/baking_auth.c | 86 ++++++++++++++++++----------------- src/baking_auth.h | 10 ++--- src/globals.h | 29 ++++++++++++ src/main.c | 9 ++-- src/to_string.c | 65 ++++++++++++++++----------- src/to_string.h | 2 + src/types.h | 19 +++++++- src/ui.c | 2 +- 12 files changed, 271 insertions(+), 84 deletions(-) create mode 100644 src/apdu_setup.c create mode 100644 src/apdu_setup.h diff --git a/src/apdu.h b/src/apdu.h index ff6dc47c..bd3f65a5 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -32,6 +32,7 @@ #define INS_QUERY_AUTH_KEY 0x07 #define INS_QUERY_HWM 0x08 #define INS_GIT 0x09 +#define INS_SETUP 0x0A __attribute__((noreturn)) void main_loop(apdu_handler handlers[INS_MAX]); diff --git a/src/apdu_baking.c b/src/apdu_baking.c index 6c580514..c1cb7497 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -18,11 +18,8 @@ unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { if (dataLength != sizeof(int)) { THROW(EXC_WRONG_LENGTH_FOR_INS); } - level_t lvl = READ_UNALIGNED_BIG_ENDIAN(level_t, dataBuffer); - - if (!is_valid_level(lvl)) { - THROW(EXC_PARSE_ERROR); - } + level_t const lvl = READ_UNALIGNED_BIG_ENDIAN(level_t, dataBuffer); + if (!is_valid_level(lvl)) THROW(EXC_PARSE_ERROR); global.u.baking.reset_level = lvl; @@ -36,7 +33,12 @@ unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { } bool reset_ok(void) { - write_highest_level(global.u.baking.reset_level, false); // We have not yet had an endorsement at this level + UPDATE_NVRAM(ram, { + ram->hwm.main.highest_level = global.u.baking.reset_level; + ram->hwm.main.had_endorsement = false; + ram->hwm.test.highest_level = global.u.baking.reset_level; + ram->hwm.test.had_endorsement = false; + }); uint32_t tx = 0; G_io_apdu_buffer[tx++] = 0x90; @@ -64,7 +66,7 @@ uint32_t send_word_big_endian(uint32_t tx, uint32_t word) { unsigned int handle_apdu_hwm(__attribute__((unused)) uint8_t instruction) { uint32_t tx = 0; - level_t level = N_data.highest_level; + level_t level = N_data.hwm.main.highest_level; tx = send_word_big_endian(tx, level); G_io_apdu_buffer[tx++] = 0x90; diff --git a/src/apdu_setup.c b/src/apdu_setup.c new file mode 100644 index 00000000..d944dad8 --- /dev/null +++ b/src/apdu_setup.c @@ -0,0 +1,111 @@ +#include "apdu_setup.h" + +#include "apdu.h" +#include "cx.h" +#include "globals.h" +#include "keys.h" +#include "to_string.h" +#include "ui_prompt.h" +#include "ui.h" + +#include + +#define G global.u.setup + +struct setup_wire { + uint32_t main_chain_id; + struct { + uint32_t main; + uint32_t test; + } hwm; + struct bip32_path_wire bip32_path; +} __attribute__((packed)); + + +static size_t provide_pubkey(uint8_t *const io_buffer, cx_ecfp_public_key_t const *const pubkey) { + size_t tx = 0; + io_buffer[tx++] = pubkey->W_len; + memmove(io_buffer + tx, pubkey->W, pubkey->W_len); + tx += pubkey->W_len; + io_buffer[tx++] = 0x90; + io_buffer[tx++] = 0x00; + return tx; +} + +static bool ok(void) { + UPDATE_NVRAM(ram, { + ram->curve = G.curve; + copy_bip32_path(&ram->bip32_path, &G.bip32_path); + ram->main_chain_id = G.main_chain_id; + ram->hwm.main.highest_level = G.hwm.main; + ram->hwm.main.had_endorsement = false; + ram->hwm.test.highest_level = G.hwm.test; + ram->hwm.test.had_endorsement = false; + }); + delayed_send(provide_pubkey(G_io_apdu_buffer, &G.public_key)); + return true; +} + +static void pubkey_to_string(char *const out, size_t const out_size, cx_ecfp_public_key_t const *const pubkey) { + check_null(out); + check_null(pubkey); + pubkey_to_pkh_string(out, out_size, G.curve, pubkey); +} + +#define SET_STATIC_UI_VALUE(index, str) register_ui_callback(index, copy_string, STATIC_UI_VALUE(str)) + +__attribute__((noreturn)) static void prompt_setup( + ui_callback_t const ok_cb, + ui_callback_t const cxl_cb) +{ + static const size_t TYPE_INDEX = 0; + static const size_t ADDRESS_INDEX = 1; + static const size_t CHAIN_INDEX = 2; + static const size_t MAIN_HWM_INDEX = 3; + static const size_t TEST_HWM_INDEX = 4; + + static const char *const prompts[] = { + PROMPT("Setup"), + PROMPT("Address"), + PROMPT("Chain"), + PROMPT("Main Chain HWM"), + PROMPT("Test Chain HWM"), + NULL, + }; + + SET_STATIC_UI_VALUE(TYPE_INDEX, "Baking?"); + register_ui_callback(ADDRESS_INDEX, pubkey_to_string, &G.public_key); + register_ui_callback(CHAIN_INDEX, chain_id_to_string, &G.main_chain_id); + register_ui_callback(MAIN_HWM_INDEX, number_to_string_indirect32, &G.hwm.main); + register_ui_callback(TEST_HWM_INDEX, number_to_string_indirect32, &G.hwm.test); + + ui_prompt(prompts, NULL, ok_cb, cxl_cb); +} + +__attribute__((noreturn)) unsigned int handle_apdu_setup(__attribute__((unused)) uint8_t instruction) { + if (READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_P1]) != 0) THROW(EXC_WRONG_PARAM); + + uint32_t const buff_size = READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_LC]); + if (buff_size < sizeof(struct setup_wire)) THROW(EXC_WRONG_LENGTH_FOR_INS); + + uint8_t const curve_code = READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_CURVE]); + G.curve = curve_code_to_curve(curve_code); + + { + struct setup_wire const *const buff_as_setup = (struct setup_wire const *)&G_io_apdu_buffer[OFFSET_CDATA]; + + size_t consumed = 0; + G.main_chain_id.v = CONSUME_UNALIGNED_BIG_ENDIAN(consumed, uint32_t, (uint8_t const *)&buff_as_setup->main_chain_id); + G.hwm.main = CONSUME_UNALIGNED_BIG_ENDIAN(consumed, uint32_t, (uint8_t const *)&buff_as_setup->hwm.main); + G.hwm.test = CONSUME_UNALIGNED_BIG_ENDIAN(consumed, uint32_t, (uint8_t const *)&buff_as_setup->hwm.test); + consumed += read_bip32_path(&G.bip32_path, (uint8_t const *)&buff_as_setup->bip32_path, buff_size - consumed); + + if (consumed != buff_size) THROW(EXC_WRONG_LENGTH); + } + + struct key_pair *const pair = generate_key_pair(G.curve, &G.bip32_path); + memset(&pair->private_key, 0, sizeof(pair->private_key)); + memcpy(&G.public_key, &pair->public_key, sizeof(G.public_key)); + + prompt_setup(ok, delay_reject); +} diff --git a/src/apdu_setup.h b/src/apdu_setup.h new file mode 100644 index 00000000..a61beb1b --- /dev/null +++ b/src/apdu_setup.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +unsigned int handle_apdu_setup(uint8_t instruction); diff --git a/src/baking_auth.c b/src/baking_auth.c index 1b829fe5..bac39f22 100644 --- a/src/baking_auth.c +++ b/src/baking_auth.c @@ -16,34 +16,38 @@ bool is_valid_level(level_t lvl) { return !(lvl & 0xC0000000); } -void write_highest_level(level_t lvl, bool is_endorsement) { - if (!is_valid_level(lvl)) return; - memcpy(&global.baking_auth.new_data, &N_data, sizeof(global.baking_auth.new_data)); - global.baking_auth.new_data.highest_level = lvl; - global.baking_auth.new_data.had_endorsement = is_endorsement; - nvm_write((void*)&N_data, &global.baking_auth.new_data, sizeof(N_data)); - change_idle_display(N_data.highest_level); +static void write_high_watermark(parsed_baking_data_t const *const in) { + check_null(in); + if (!is_valid_level(in->level)) THROW(EXC_WRONG_VALUES); + UPDATE_NVRAM(ram, { + // If the chain matches the main chain *or* the main chain is not set, then use 'main' HWM. + high_watermark_t *const dest = select_hwm_by_chain(in->chain_id, ram); + dest->highest_level = in->level; + dest->had_endorsement = in->is_endorsement; + }); + change_idle_display(N_data.hwm.main.highest_level); } void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path) { check_null(bip32_path); if (bip32_path->length > NUM_ELEMENTS(N_data.bip32_path.components) || bip32_path->length == 0) return; - global.baking_auth.new_data.highest_level = N_data.highest_level; - global.baking_auth.new_data.had_endorsement = N_data.had_endorsement; - global.baking_auth.new_data.curve = curve; - copy_bip32_path(&global.baking_auth.new_data.bip32_path, bip32_path); - nvm_write((void*)&N_data, &global.baking_auth.new_data, sizeof(N_data)); - change_idle_display(N_data.highest_level); + UPDATE_NVRAM(ram, { + ram->curve = curve; + copy_bip32_path(&ram->bip32_path, bip32_path); + }); + change_idle_display(N_data.hwm.main.highest_level); } -bool is_level_authorized(level_t level, bool is_endorsement) { - if (!is_valid_level(level)) return false; - if (level > N_data.highest_level) return true; +static bool is_level_authorized(parsed_baking_data_t const *const baking_info) { + check_null(baking_info); + if (!is_valid_level(baking_info->level)) return false; + high_watermark_t const *const hwm = select_hwm_by_chain(baking_info->chain_id, &N_data); + return baking_info->level > hwm->highest_level - // Levels are tied. In order for this to be OK, this must be an endorsement, and we must not - // have previously seen an endorsement. - return is_endorsement && !N_data.had_endorsement; + // Levels are tied. In order for this to be OK, this must be an endorsement, and we must not + // have previously seen an endorsement. + || (baking_info->is_endorsement && !hwm->had_endorsement); } bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path) { @@ -55,20 +59,22 @@ bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path) } void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, bip32_path_t const *const bip32_path) { + check_null(data); + check_null(bip32_path); if (!is_path_authorized(curve, bip32_path)) THROW(EXC_SECURITY); - struct parsed_baking_data baking_info; - if (!parse_baking_data(data, datalen, &baking_info)) THROW(EXC_PARSE_ERROR); - if (!is_level_authorized(baking_info.level, baking_info.is_endorsement)) THROW(EXC_WRONG_VALUES); + parsed_baking_data_t baking_info; + if (!parse_baking_data(&baking_info, data, datalen)) THROW(EXC_PARSE_ERROR); + if (!is_level_authorized(&baking_info)) THROW(EXC_WRONG_VALUES); } void update_high_water_mark(void *data, int datalen) { - struct parsed_baking_data baking_info; - if (!parse_baking_data(data, datalen, &baking_info)) { + check_null(data); + parsed_baking_data_t baking_info; + if (!parse_baking_data(&baking_info, data, datalen)) { return; // Must be signing a delegation } - - write_highest_level(baking_info.level, baking_info.is_endorsement); + write_high_watermark(&baking_info); } void update_auth_text(void) { @@ -140,36 +146,36 @@ void prompt_address( #endif } -struct __attribute__((packed)) block { - char magic_byte; +struct block_wire { + uint8_t magic_byte; uint32_t chain_id; - level_t level; + uint32_t level; uint8_t proto; // ... beyond this we don't care -}; +} __attribute__((packed)); -struct __attribute__((packed)) endorsement { +struct endorsement_wire { uint8_t magic_byte; uint32_t chain_id; uint8_t branch[32]; uint8_t tag; uint32_t level; -}; +} __attribute__((packed)); -bool parse_baking_data(const void *data, size_t length, struct parsed_baking_data *out) { +bool parse_baking_data(parsed_baking_data_t *const out, void const *const data, size_t const length) { switch (get_magic_byte(data, length)) { case MAGIC_BYTE_BAKING_OP: - if (length != sizeof(struct endorsement)) return false; - const struct endorsement *endorsement = data; - // TODO: Check chain ID + if (length != sizeof(struct endorsement_wire)) return false; + struct endorsement_wire const *const endorsement = data; out->is_endorsement = true; - out->level = READ_UNALIGNED_BIG_ENDIAN(level_t, &endorsement->level); + out->chain_id.v = READ_UNALIGNED_BIG_ENDIAN(uint32_t, &endorsement->chain_id); + out->level = READ_UNALIGNED_BIG_ENDIAN(uint32_t, &endorsement->level); return true; case MAGIC_BYTE_BLOCK: - if (length < sizeof(struct block)) return false; - // TODO: Check chain ID + if (length < sizeof(struct block_wire)) return false; + struct block_wire const *const block = data; out->is_endorsement = false; - const struct block *block = data; + out->chain_id.v = READ_UNALIGNED_BIG_ENDIAN(uint32_t, &block->chain_id); out->level = READ_UNALIGNED_BIG_ENDIAN(level_t, &block->level); return true; case MAGIC_BYTE_INVALID: diff --git a/src/baking_auth.h b/src/baking_auth.h index bbbfea59..438567ac 100644 --- a/src/baking_auth.h +++ b/src/baking_auth.h @@ -3,6 +3,7 @@ #include "apdu.h" #include "operations.h" #include "protocol.h" +#include "types.h" #include #include @@ -11,8 +12,6 @@ void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path); void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, bip32_path_t const *const bip32_path); bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path); void update_high_water_mark(void *data, int datalen); -void write_highest_level(level_t level, bool is_endorsement); -bool is_level_authorized(level_t level, bool is_endorsement); bool is_valid_level(level_t level); void update_auth_text(void); @@ -21,9 +20,10 @@ void prompt_address(bool bake, cx_curve_t curve, const cx_ecfp_public_key_t *key, ui_callback_t ok_cb, ui_callback_t cxl_cb) __attribute__((noreturn)); -struct parsed_baking_data { +typedef struct { + chain_id_t chain_id; bool is_endorsement; level_t level; -}; +} parsed_baking_data_t; // Return false if it is invalid -bool parse_baking_data(const void *data, size_t length, struct parsed_baking_data *out); +bool parse_baking_data(parsed_baking_data_t *const out, void const *const data, size_t const length); diff --git a/src/globals.h b/src/globals.h index 77f7e7a7..e2e227d6 100644 --- a/src/globals.h +++ b/src/globals.h @@ -22,6 +22,17 @@ struct priv_generate_key_pair { struct key_pair res; }; +struct apdu_setup_globals { + bip32_path_t bip32_path; + cx_curve_t curve; + cx_ecfp_public_key_t public_key; + chain_id_t main_chain_id; + struct { + level_t main; + level_t test; + } hwm; +}; + typedef struct { void *stack_root; apdu_handler handlers[INS_MAX]; @@ -48,6 +59,8 @@ typedef struct { uint8_t magic_number; bool hash_only; } sign; + + struct apdu_setup_globals setup; } u; struct { @@ -108,6 +121,22 @@ extern WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? #define N_data (*(WIDE nvram_data*)PIC(&N_data_real)) +// Properly updates NVRAM data to prevent any clobbering of data. +// 'out_param' defines the name of a pointer to the nvram_data struct +// that 'body' can change to apply updates. +#define UPDATE_NVRAM(out_name, body) ({ \ + nvram_data *const out_name = &global.baking_auth.new_data; \ + memcpy(&global.baking_auth.new_data, &N_data, sizeof(global.baking_auth.new_data)); \ + body; \ + nvm_write((void*)&N_data, &global.baking_auth.new_data, sizeof(N_data)); \ +}) + +static inline high_watermark_t *select_hwm_by_chain(chain_id_t const chain_id, nvram_data *const ram) { + check_null(ram); + return chain_id.v == ram->main_chain_id.v || ram->main_chain_id.v == 0 + ? &ram->hwm.main + : &ram->hwm.test; +} static inline void throw_stack_size() { uint8_t st; diff --git a/src/main.c b/src/main.c index 73a95d08..1b20ba51 100644 --- a/src/main.c +++ b/src/main.c @@ -17,6 +17,7 @@ #include "apdu_baking.h" #include "apdu_pubkey.h" +#include "apdu_setup.h" #include "apdu_sign.h" #include "apdu.h" #include "globals.h" @@ -31,16 +32,16 @@ void app_main(void) { global.handlers[APDU_INS(INS_VERSION)] = handle_apdu_version; global.handlers[APDU_INS(INS_GET_PUBLIC_KEY)] = handle_apdu_get_public_key; global.handlers[APDU_INS(INS_PROMPT_PUBLIC_KEY)] = handle_apdu_get_public_key; + global.handlers[APDU_INS(INS_SIGN)] = handle_apdu_sign; + global.handlers[APDU_INS(INS_GIT)] = handle_apdu_git; #ifdef BAKING_APP global.handlers[APDU_INS(INS_AUTHORIZE_BAKING)] = handle_apdu_get_public_key; global.handlers[APDU_INS(INS_RESET)] = handle_apdu_reset; global.handlers[APDU_INS(INS_QUERY_AUTH_KEY)] = handle_apdu_query_auth_key; global.handlers[APDU_INS(INS_QUERY_HWM)] = handle_apdu_hwm; -#endif - global.handlers[APDU_INS(INS_SIGN)] = handle_apdu_sign; -#ifndef BAKING_APP + global.handlers[APDU_INS(INS_SETUP)] = handle_apdu_setup; +#else global.handlers[APDU_INS(INS_SIGN_UNSAFE)] = handle_apdu_sign; #endif - global.handlers[APDU_INS(INS_GIT)] = handle_apdu_git; main_loop(global.handlers); } diff --git a/src/to_string.c b/src/to_string.c index 7673657a..f40fb856 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -8,6 +8,8 @@ #define NO_CONTRACT_STRING "None" +#define TEZOS_HASH_CHECKSUM_SIZE 4 + static void pkh_to_string(char *buff, const size_t buff_size, const cx_curve_t curve, const uint8_t hash[HASH_SIZE]); // These functions output terminating null bytes, and return the ending offset. @@ -20,31 +22,35 @@ void parsed_contract_to_string(char *buff, uint32_t buff_size, const struct pars return; } - cx_curve_t curve; - if (contract->originated != 0) { - curve = CX_CURVE_NONE; - } else { - curve = curve_code_to_curve(contract->curve_code); - } + cx_curve_t const curve = contract->originated != 0 + ? CX_CURVE_NONE + : curve_code_to_curve(contract->curve_code); pkh_to_string(buff, buff_size, curve, contract->hash); } void pubkey_to_pkh_string(char *buff, uint32_t buff_size, cx_curve_t curve, - const cx_ecfp_public_key_t *public_key) { + const cx_ecfp_public_key_t *public_key) { uint8_t hash[HASH_SIZE]; public_key_hash(hash, curve, public_key); pkh_to_string(buff, buff_size, curve, hash); } +void compute_hash_checksum(uint8_t out[TEZOS_HASH_CHECKSUM_SIZE], void const *const data, size_t size) { + uint8_t checksum[32]; + cx_hash_sha256(data, size, checksum, sizeof(checksum)); + cx_hash_sha256(checksum, sizeof(checksum), checksum, sizeof(checksum)); + memcpy(out, checksum, TEZOS_HASH_CHECKSUM_SIZE); +} + void pkh_to_string(char *buff, const size_t buff_size, const cx_curve_t curve, const uint8_t hash[HASH_SIZE]) { if (buff_size < PKH_STRING_SIZE) THROW(EXC_WRONG_LENGTH); // Data to encode struct __attribute__((packed)) { - char prefix[3]; + uint8_t prefix[3]; uint8_t hash[HASH_SIZE]; - char checksum[4]; + uint8_t checksum[TEZOS_HASH_CHECKSUM_SIZE]; } data; // prefix @@ -75,12 +81,7 @@ void pkh_to_string(char *buff, const size_t buff_size, const cx_curve_t curve, // hash memcpy(data.hash, hash, sizeof(data.hash)); - - // checksum -- twice because them's the rules - uint8_t checksum[32]; - cx_hash_sha256((void*)&data, sizeof(data) - sizeof(data.checksum), checksum, sizeof(checksum)); - cx_hash_sha256(checksum, sizeof(checksum), checksum, sizeof(checksum)); - memcpy(data.checksum, checksum, sizeof(data.checksum)); + compute_hash_checksum(data.checksum, &data, sizeof(data) - sizeof(data.checksum)); size_t out_size = buff_size; if (!b58enc(buff, &out_size, &data, sizeof(data))) THROW(EXC_WRONG_LENGTH); @@ -91,24 +92,36 @@ void protocol_hash_to_string(char *buff, const size_t buff_size, const uint8_t h // Data to encode struct __attribute__((packed)) { - char prefix[2]; + uint8_t prefix[2]; uint8_t hash[PROTOCOL_HASH_SIZE]; - char checksum[4]; + uint8_t checksum[TEZOS_HASH_CHECKSUM_SIZE]; } data = { .prefix = {2, 170} }; memcpy(data.hash, hash, sizeof(data.hash)); + compute_hash_checksum(data.checksum, &data, sizeof(data) - sizeof(data.checksum)); - // checksum -- twice because them's the rules - // Hash the input (prefix + hash) - // Hash that hash. - // Take the first 4 bytes of that - // Voila: a checksum. - uint8_t checksum[32]; - cx_hash_sha256((void*)&data, sizeof(data) - sizeof(data.checksum), checksum, sizeof(checksum)); - cx_hash_sha256(checksum, sizeof(checksum), checksum, sizeof(checksum)); - memcpy(data.checksum, checksum, sizeof(data.checksum)); + size_t out_size = buff_size; + if (!b58enc(buff, &out_size, &data, sizeof(data))) THROW(EXC_WRONG_LENGTH); +} + +void chain_id_to_string(char *const buff, size_t const buff_size, chain_id_t const chain_id) { + if (buff_size < CHAIN_ID_BASE58_STRING_SIZE) THROW(EXC_WRONG_LENGTH); + + // Data to encode + struct __attribute__((packed)) { + uint8_t prefix[3]; + int32_t chain_id; + uint8_t checksum[TEZOS_HASH_CHECKSUM_SIZE]; + } data = { + .prefix = {87, 82, 0}, + + // Must hash big-endian data so treating little endian as big endian just flips + .chain_id = READ_UNALIGNED_BIG_ENDIAN(uint32_t, &chain_id.v) + }; + + compute_hash_checksum(data.checksum, &data, sizeof(data) - sizeof(data.checksum)); size_t out_size = buff_size; if (!b58enc(buff, &out_size, &data, sizeof(data))) THROW(EXC_WRONG_LENGTH); diff --git a/src/to_string.h b/src/to_string.h index 3eb5516d..58541a09 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -6,12 +6,14 @@ #include "keys.h" #include "operations.h" #include "os_cx.h" +#include "types.h" #include "ui.h" void pubkey_to_pkh_string(char *buff, uint32_t buff_size, cx_curve_t curve, const cx_ecfp_public_key_t *public_key); void protocol_hash_to_string(char *buff, const size_t buff_size, const uint8_t hash[PROTOCOL_HASH_SIZE]); void parsed_contract_to_string(char *buff, uint32_t buff_size, const struct parsed_contract *contract); +void chain_id_to_string(char *buff, size_t const buff_size, chain_id_t const chain_id); #define MAX_INT_DIGITS 20 // dest must be at least MAX_INT_DIGITS diff --git a/src/types.h b/src/types.h index dedb1904..13b22cc2 100644 --- a/src/types.h +++ b/src/types.h @@ -11,6 +11,15 @@ typedef uint32_t (*apdu_handler)(uint8_t instruction); typedef uint32_t level_t; +#define CHAIN_ID_BASE58_STRING_SIZE (15 + 1) // with null termination + +typedef struct { + uint32_t v; +} chain_id_t; + +// Mainnet Chain ID: NetXdQprcVkpaWU +static chain_id_t const mainnet_chain_id = { .v = 0x7A06A770 }; + // UI typedef bool (*ui_callback_t)(void); // return true to go back to idle screen @@ -47,9 +56,17 @@ static inline bool bip32_paths_eq(bip32_path_t const *const a, bip32_path_t cons } typedef struct { - cx_curve_t curve; level_t highest_level; bool had_endorsement; +} high_watermark_t; + +typedef struct { + chain_id_t main_chain_id; + struct { + high_watermark_t main; + high_watermark_t test; + } hwm; + cx_curve_t curve; bip32_path_t bip32_path; } nvram_data; diff --git a/src/ui.c b/src/ui.c index 0326ed4e..bea319f6 100644 --- a/src/ui.c +++ b/src/ui.c @@ -114,7 +114,7 @@ void change_idle_display(uint32_t new) { void ui_initial_screen(void) { #ifdef BAKING_APP - change_idle_display(N_data.highest_level); + change_idle_display(N_data.hwm.main.highest_level); #endif clear_ui_callbacks(); ui_idle(); From 544523e8d8b3f6fd7e02838964ddfeb5e3fe75a8 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 14/25] Use G for globals in apdu_pubkey.c --- src/apdu_pubkey.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index b18eea46..76e01e8a 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -9,13 +9,15 @@ #include +#define G global.u.pubkey + static uint32_t provide_pubkey(void) { uint32_t tx = 0; - G_io_apdu_buffer[tx++] = global.u.pubkey.public_key.W_len; + G_io_apdu_buffer[tx++] = G.public_key.W_len; os_memmove(G_io_apdu_buffer + tx, - global.u.pubkey.public_key.W, - global.u.pubkey.public_key.W_len); - tx += global.u.pubkey.public_key.W_len; + G.public_key.W, + G.public_key.W_len); + tx += G.public_key.W_len; G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x00; return tx; @@ -29,7 +31,7 @@ static bool pubkey_ok(void) { #ifdef BAKING_APP static bool baking_ok(void) { - authorize_baking(global.u.pubkey.curve, &global.u.pubkey.bip32_path); + authorize_baking(G.curve, &G.bip32_path); pubkey_ok(); return true; } @@ -47,24 +49,24 @@ unsigned int handle_apdu_get_public_key(uint8_t instruction) { require_hid(); } - global.u.pubkey.curve = curve_code_to_curve(G_io_apdu_buffer[OFFSET_CURVE]); + G.curve = curve_code_to_curve(G_io_apdu_buffer[OFFSET_CURVE]); #ifdef BAKING_APP if (G_io_apdu_buffer[OFFSET_LC] == 0 && instruction == INS_AUTHORIZE_BAKING) { - global.u.pubkey.curve = N_data.curve; - copy_bip32_path(&global.u.pubkey.bip32_path, &N_data.bip32_path); + G.curve = N_data.curve; + copy_bip32_path(&G.bip32_path, &N_data.bip32_path); } else { #endif - read_bip32_path(&global.u.pubkey.bip32_path, dataBuffer, G_io_apdu_buffer[OFFSET_LC]); + read_bip32_path(&G.bip32_path, dataBuffer, G_io_apdu_buffer[OFFSET_LC]); #ifdef BAKING_APP - if (global.u.pubkey.bip32_path.length == 0) { + if (G.bip32_path.length == 0) { THROW(EXC_WRONG_LENGTH_FOR_INS); } } #endif - struct key_pair *pair = generate_key_pair(global.u.pubkey.curve, &global.u.pubkey.bip32_path); + struct key_pair *pair = generate_key_pair(G.curve, &G.bip32_path); memset(&pair->private_key, 0, sizeof(pair->private_key)); - memcpy(&global.u.pubkey.public_key, &pair->public_key, sizeof(global.u.pubkey.public_key)); + memcpy(&G.public_key, &pair->public_key, sizeof(G.public_key)); if (instruction == INS_GET_PUBLIC_KEY) { return provide_pubkey(); @@ -84,6 +86,6 @@ unsigned int handle_apdu_get_public_key(uint8_t instruction) { #ifdef BAKING_APP } #endif - prompt_address(bake, global.u.pubkey.curve, &global.u.pubkey.public_key, cb, delay_reject); + prompt_address(bake, G.curve, &G.public_key, cb, delay_reject); } } From 516c2a2c785ae79751822cce93f78ea89903c3fd Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 15/25] Use G for globals in apdu_baking.c --- src/apdu_baking.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/apdu_baking.c b/src/apdu_baking.c index c1cb7497..7b55e315 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -10,6 +10,8 @@ #include +#define G global.u.baking + static bool reset_ok(void); unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { @@ -21,9 +23,9 @@ unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { level_t const lvl = READ_UNALIGNED_BIG_ENDIAN(level_t, dataBuffer); if (!is_valid_level(lvl)) THROW(EXC_PARSE_ERROR); - global.u.baking.reset_level = lvl; + G.reset_level = lvl; - register_ui_callback(0, number_to_string_indirect32, &global.u.baking.reset_level); + register_ui_callback(0, number_to_string_indirect32, &G.reset_level); static const char *const reset_prompts[] = { PROMPT("Reset HWM"), @@ -34,9 +36,9 @@ unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { bool reset_ok(void) { UPDATE_NVRAM(ram, { - ram->hwm.main.highest_level = global.u.baking.reset_level; + ram->hwm.main.highest_level = G.reset_level; ram->hwm.main.had_endorsement = false; - ram->hwm.test.highest_level = global.u.baking.reset_level; + ram->hwm.test.highest_level = G.reset_level; ram->hwm.test.had_endorsement = false; }); From 665a3f22bac5945aced40c7fbec8a5d5a5192703 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 16/25] Factor out provide_pubkey --- src/apdu.c | 10 ++++++++++ src/apdu.h | 2 ++ src/apdu_pubkey.c | 17 ++--------------- src/apdu_setup.c | 11 ----------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index 31f3e4d3..1af9a409 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -5,6 +5,16 @@ #include #include +size_t provide_pubkey(uint8_t *const io_buffer, cx_ecfp_public_key_t const *const pubkey) { + size_t tx = 0; + io_buffer[tx++] = pubkey->W_len; + memmove(io_buffer + tx, pubkey->W, pubkey->W_len); + tx += pubkey->W_len; + io_buffer[tx++] = 0x90; + io_buffer[tx++] = 0x00; + return tx; +} + unsigned int handle_apdu_error(uint8_t __attribute__((unused)) instruction) { THROW(EXC_INVALID_INS); } diff --git a/src/apdu.h b/src/apdu.h index bd3f65a5..dc6c859a 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -59,6 +59,8 @@ static inline void require_hid(void) { } } +size_t provide_pubkey(uint8_t *const io_buffer, cx_ecfp_public_key_t const *const pubkey); + uint32_t handle_apdu_error(uint8_t instruction); uint32_t handle_apdu_version(uint8_t instruction); uint32_t handle_apdu_git(uint8_t instruction); diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 76e01e8a..f2bb19fe 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -11,21 +11,8 @@ #define G global.u.pubkey -static uint32_t provide_pubkey(void) { - uint32_t tx = 0; - G_io_apdu_buffer[tx++] = G.public_key.W_len; - os_memmove(G_io_apdu_buffer + tx, - G.public_key.W, - G.public_key.W_len); - tx += G.public_key.W_len; - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; -} - static bool pubkey_ok(void) { - uint32_t const tx = provide_pubkey(); - delayed_send(tx); + delayed_send(provide_pubkey(G_io_apdu_buffer, &G.public_key)); return true; } @@ -69,7 +56,7 @@ unsigned int handle_apdu_get_public_key(uint8_t instruction) { memcpy(&G.public_key, &pair->public_key, sizeof(G.public_key)); if (instruction == INS_GET_PUBLIC_KEY) { - return provide_pubkey(); + return provide_pubkey(G_io_apdu_buffer, &G.public_key); } else { // instruction == INS_PROMPT_PUBLIC_KEY || instruction == INS_AUTHORIZE_BAKING ui_callback_t cb; diff --git a/src/apdu_setup.c b/src/apdu_setup.c index d944dad8..5940edfd 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -21,17 +21,6 @@ struct setup_wire { struct bip32_path_wire bip32_path; } __attribute__((packed)); - -static size_t provide_pubkey(uint8_t *const io_buffer, cx_ecfp_public_key_t const *const pubkey) { - size_t tx = 0; - io_buffer[tx++] = pubkey->W_len; - memmove(io_buffer + tx, pubkey->W, pubkey->W_len); - tx += pubkey->W_len; - io_buffer[tx++] = 0x90; - io_buffer[tx++] = 0x00; - return tx; -} - static bool ok(void) { UPDATE_NVRAM(ram, { ram->curve = G.curve; From e1f875b40e4542af1fd0d59c7a16e56ee7cec597 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 17/25] Use safer abstraction for pubkey generation --- src/apdu_pubkey.c | 26 +++++++++++--------------- src/apdu_setup.c | 5 ++--- src/apdu_sign.c | 1 + src/baking_auth.c | 5 ++--- src/keys.c | 13 +++++++++++-- src/keys.h | 6 ++++-- src/operations.c | 6 +++--- 7 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index f2bb19fe..4109cc21 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -27,33 +27,29 @@ static bool baking_ok(void) { unsigned int handle_apdu_get_public_key(uint8_t instruction) { uint8_t *dataBuffer = G_io_apdu_buffer + OFFSET_CDATA; - if (G_io_apdu_buffer[OFFSET_P1] != 0) { - THROW(EXC_WRONG_PARAM); - } + if (READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_P1]) != 0) THROW(EXC_WRONG_PARAM); // do not expose pks without prompt over U2F (browser support) - if (instruction == INS_GET_PUBLIC_KEY) { - require_hid(); - } + if (instruction == INS_GET_PUBLIC_KEY) require_hid(); - G.curve = curve_code_to_curve(G_io_apdu_buffer[OFFSET_CURVE]); + uint8_t const curve_code = READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_CURVE]); + G.curve = curve_code_to_curve(curve_code); + + size_t const cdata_size = READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_LC]); #ifdef BAKING_APP - if (G_io_apdu_buffer[OFFSET_LC] == 0 && instruction == INS_AUTHORIZE_BAKING) { + if (cdata_size == 0 && instruction == INS_AUTHORIZE_BAKING) { G.curve = N_data.curve; copy_bip32_path(&G.bip32_path, &N_data.bip32_path); } else { #endif - read_bip32_path(&G.bip32_path, dataBuffer, G_io_apdu_buffer[OFFSET_LC]); + read_bip32_path(&G.bip32_path, dataBuffer, cdata_size); #ifdef BAKING_APP - if (G.bip32_path.length == 0) { - THROW(EXC_WRONG_LENGTH_FOR_INS); - } + if (G.bip32_path.length == 0) THROW(EXC_WRONG_LENGTH_FOR_INS); } #endif - struct key_pair *pair = generate_key_pair(G.curve, &G.bip32_path); - memset(&pair->private_key, 0, sizeof(pair->private_key)); - memcpy(&G.public_key, &pair->public_key, sizeof(G.public_key)); + cx_ecfp_public_key_t const *const pubkey = generate_public_key(G.curve, &G.bip32_path); + memcpy(&G.public_key, pubkey, sizeof(G.public_key)); if (instruction == INS_GET_PUBLIC_KEY) { return provide_pubkey(G_io_apdu_buffer, &G.public_key); diff --git a/src/apdu_setup.c b/src/apdu_setup.c index 5940edfd..128b395f 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -92,9 +92,8 @@ __attribute__((noreturn)) unsigned int handle_apdu_setup(__attribute__((unused)) if (consumed != buff_size) THROW(EXC_WRONG_LENGTH); } - struct key_pair *const pair = generate_key_pair(G.curve, &G.bip32_path); - memset(&pair->private_key, 0, sizeof(pair->private_key)); - memcpy(&G.public_key, &pair->public_key, sizeof(G.public_key)); + cx_ecfp_public_key_t const *const pubkey = generate_public_key(G.curve, &G.bip32_path); + memcpy(&G.public_key, pubkey, sizeof(G.public_key)); prompt_setup(ok, delay_reject); } diff --git a/src/apdu_sign.c b/src/apdu_sign.c index f683b679..4805da39 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -147,6 +147,7 @@ const char *const insecure_values[] = { static bool prompt_transaction(const void *data, size_t length, cx_curve_t curve, bip32_path_t const *const bip32_path, ui_callback_t ok, ui_callback_t cxl) { + check_null(data); check_null(bip32_path); struct parsed_operation_group *ops; diff --git a/src/baking_auth.c b/src/baking_auth.c index bac39f22..c7e9061d 100644 --- a/src/baking_auth.c +++ b/src/baking_auth.c @@ -81,11 +81,10 @@ void update_auth_text(void) { if (N_data.bip32_path.length == 0) { strcpy(global.ui.baking_auth_text, "No Key Authorized"); } else { - struct key_pair *pair = generate_key_pair(N_data.curve, &N_data.bip32_path); - memset(&pair->private_key, 0, sizeof(pair->private_key)); + cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); pubkey_to_pkh_string( global.ui.baking_auth_text, sizeof(global.ui.baking_auth_text), - N_data.curve, &pair->public_key); + N_data.curve, pubkey); } } diff --git a/src/keys.c b/src/keys.c index a0b2e387..c7f97da2 100644 --- a/src/keys.c +++ b/src/keys.c @@ -74,8 +74,17 @@ struct key_pair *generate_key_pair(cx_curve_t const curve, bip32_path_t const *c return &priv->res; } -cx_ecfp_public_key_t *public_key_hash(uint8_t output[HASH_SIZE], cx_curve_t curve, - const cx_ecfp_public_key_t *restrict public_key) { +cx_ecfp_public_key_t const *generate_public_key(cx_curve_t const curve, bip32_path_t const *const bip32_path) { + check_null(bip32_path); + struct key_pair *const pair = generate_key_pair(curve, bip32_path); + memset(&pair->private_key, 0, sizeof(pair->private_key)); + return &pair->public_key; +} + +cx_ecfp_public_key_t const *public_key_hash( + uint8_t output[HASH_SIZE], cx_curve_t curve, + cx_ecfp_public_key_t const *const restrict public_key) +{ cx_ecfp_public_key_t *const compressed = &global.priv.public_key_hash.compressed; switch (curve) { case CX_CURVE_Ed25519: diff --git a/src/keys.h b/src/keys.h index 5e3e839a..609c8c60 100644 --- a/src/keys.h +++ b/src/keys.h @@ -17,9 +17,11 @@ struct bip32_path_wire { size_t read_bip32_path(bip32_path_t *const out, uint8_t const *const in, size_t const in_size); struct key_pair *generate_key_pair(cx_curve_t const curve, bip32_path_t const *const bip32_path); +cx_ecfp_public_key_t const *generate_public_key(cx_curve_t const curve, bip32_path_t const *const bip32_path); -cx_ecfp_public_key_t *public_key_hash(uint8_t output[HASH_SIZE], cx_curve_t curve, - const cx_ecfp_public_key_t *restrict public_key); +cx_ecfp_public_key_t const *public_key_hash( + uint8_t output[HASH_SIZE], cx_curve_t curve, + cx_ecfp_public_key_t const *const restrict public_key); enum curve_code { TEZOS_ED, diff --git a/src/operations.c b/src/operations.c index 072a672b..e7feeb7e 100644 --- a/src/operations.c +++ b/src/operations.c @@ -108,9 +108,9 @@ static inline uint64_t parse_z(const void *data, size_t *ix, size_t length, uint static inline void compute_pkh(cx_curve_t curve, bip32_path_t const *const bip32_path, struct parsed_operation_group *const out) { check_null(bip32_path); - memset(&pair->private_key, 0, sizeof(pair->private_key)); - - cx_ecfp_public_key_t *key = public_key_hash(out->signing.hash, curve, &pair->public_key); + check_null(out); + cx_ecfp_public_key_t const *const pubkey = generate_public_key(curve, bip32_path); + cx_ecfp_public_key_t const *const key = public_key_hash(out->signing.hash, curve, pubkey); memcpy(&out->public_key, key, sizeof(out->public_key)); out->signing.curve_code = curve_to_curve_code(curve); out->signing.originated = 0; From f11b103a1fd1712a566fa9eda810fa6a30a7135c Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 18/25] Add new APDU for querying both HWMs and chain ID --- src/apdu.h | 3 ++- src/apdu_baking.c | 16 ++++++++++++---- src/apdu_baking.h | 3 ++- src/main.c | 3 ++- src/types.h | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/apdu.h b/src/apdu.h index dc6c859a..637b45b8 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -30,9 +30,10 @@ #define INS_SIGN_UNSAFE 0x05 // Data that is already hashed. #define INS_RESET 0x06 #define INS_QUERY_AUTH_KEY 0x07 -#define INS_QUERY_HWM 0x08 +#define INS_QUERY_MAIN_HWM 0x08 #define INS_GIT 0x09 #define INS_SETUP 0x0A +#define INS_QUERY_ALL_HWM 0x0B __attribute__((noreturn)) void main_loop(apdu_handler handlers[INS_MAX]); diff --git a/src/apdu_baking.c b/src/apdu_baking.c index 7b55e315..480d0864 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -65,17 +65,25 @@ uint32_t send_word_big_endian(uint32_t tx, uint32_t word) { return tx + i; } -unsigned int handle_apdu_hwm(__attribute__((unused)) uint8_t instruction) { +unsigned int handle_apdu_all_hwm(__attribute__((unused)) uint8_t instruction) { uint32_t tx = 0; + tx = send_word_big_endian(tx, N_data.hwm.main.highest_level); + tx = send_word_big_endian(tx, N_data.hwm.test.highest_level); + tx = send_word_big_endian(tx, N_data.main_chain_id.v); + G_io_apdu_buffer[tx++] = 0x90; + G_io_apdu_buffer[tx++] = 0x00; + return tx; +} - level_t level = N_data.hwm.main.highest_level; - tx = send_word_big_endian(tx, level); - +unsigned int handle_apdu_main_hwm(__attribute__((unused)) uint8_t instruction) { + uint32_t tx = 0; + tx = send_word_big_endian(tx, N_data.hwm.main.highest_level); G_io_apdu_buffer[tx++] = 0x90; G_io_apdu_buffer[tx++] = 0x00; return tx; } + unsigned int handle_apdu_query_auth_key(__attribute__((unused)) uint8_t instruction) { uint8_t const length = N_data.bip32_path.length; diff --git a/src/apdu_baking.h b/src/apdu_baking.h index b32e8fcd..632d8690 100644 --- a/src/apdu_baking.h +++ b/src/apdu_baking.h @@ -4,4 +4,5 @@ unsigned int handle_apdu_reset(uint8_t instruction); unsigned int handle_apdu_query_auth_key(uint8_t instruction); -unsigned int handle_apdu_hwm(uint8_t instruction); +unsigned int handle_apdu_main_hwm(uint8_t instruction); +unsigned int handle_apdu_all_hwm(uint8_t instruction); diff --git a/src/main.c b/src/main.c index 1b20ba51..38d5780f 100644 --- a/src/main.c +++ b/src/main.c @@ -38,8 +38,9 @@ void app_main(void) { global.handlers[APDU_INS(INS_AUTHORIZE_BAKING)] = handle_apdu_get_public_key; global.handlers[APDU_INS(INS_RESET)] = handle_apdu_reset; global.handlers[APDU_INS(INS_QUERY_AUTH_KEY)] = handle_apdu_query_auth_key; - global.handlers[APDU_INS(INS_QUERY_HWM)] = handle_apdu_hwm; + global.handlers[APDU_INS(INS_QUERY_MAIN_HWM)] = handle_apdu_main_hwm; global.handlers[APDU_INS(INS_SETUP)] = handle_apdu_setup; + global.handlers[APDU_INS(INS_QUERY_ALL_HWM)] = handle_apdu_all_hwm; #else global.handlers[APDU_INS(INS_SIGN_UNSAFE)] = handle_apdu_sign; #endif diff --git a/src/types.h b/src/types.h index 13b22cc2..3db418c9 100644 --- a/src/types.h +++ b/src/types.h @@ -159,7 +159,7 @@ struct parsed_operation_group { }; // Maximum number of APDU instructions -#define INS_MAX 0x0B +#define INS_MAX 0x0C #define APDU_INS(x) ({ \ _Static_assert(x <= INS_MAX, "APDU instruction is out of bounds"); \ From ee3639ea68bb418c01780741fe0e5fd45b17fde2 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 19/25] Fix HWM updates on baking idle screens Refactor the idle screen updates to all occur in the same place by the same code. --- src/baking_auth.c | 13 ------------- src/baking_auth.h | 1 - src/ui.c | 24 ++++++++++++++++-------- src/ui.h | 1 - 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/baking_auth.c b/src/baking_auth.c index c7e9061d..02ac20e3 100644 --- a/src/baking_auth.c +++ b/src/baking_auth.c @@ -25,7 +25,6 @@ static void write_high_watermark(parsed_baking_data_t const *const in) { dest->highest_level = in->level; dest->had_endorsement = in->is_endorsement; }); - change_idle_display(N_data.hwm.main.highest_level); } void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path) { @@ -36,7 +35,6 @@ void authorize_baking(cx_curve_t curve, bip32_path_t const *const bip32_path) { ram->curve = curve; copy_bip32_path(&ram->bip32_path, bip32_path); }); - change_idle_display(N_data.hwm.main.highest_level); } static bool is_level_authorized(parsed_baking_data_t const *const baking_info) { @@ -77,17 +75,6 @@ void update_high_water_mark(void *data, int datalen) { write_high_watermark(&baking_info); } -void update_auth_text(void) { - if (N_data.bip32_path.length == 0) { - strcpy(global.ui.baking_auth_text, "No Key Authorized"); - } else { - cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); - pubkey_to_pkh_string( - global.ui.baking_auth_text, sizeof(global.ui.baking_auth_text), - N_data.curve, pubkey); - } -} - static const char *const pubkey_values[] = { "Public Key", global.baking_auth.address_display_data, diff --git a/src/baking_auth.h b/src/baking_auth.h index 438567ac..1a57bb2f 100644 --- a/src/baking_auth.h +++ b/src/baking_auth.h @@ -13,7 +13,6 @@ void guard_baking_authorized(cx_curve_t curve, void *data, int datalen, bip32_pa bool is_path_authorized(cx_curve_t curve, bip32_path_t const *const bip32_path); void update_high_water_mark(void *data, int datalen); bool is_valid_level(level_t level); -void update_auth_text(void); void prompt_contract_for_baking(struct parsed_contract *contract, ui_callback_t ok_cb, ui_callback_t cxl_cb); void prompt_address(bool bake, cx_curve_t curve, diff --git a/src/ui.c b/src/ui.c index bea319f6..dac1a491 100644 --- a/src/ui.c +++ b/src/ui.c @@ -96,9 +96,22 @@ static bool do_nothing(void) { } #endif +static void update_baking_idle_screens(void) { + number_to_string(global.ui.idle_text, N_data.hwm.main.highest_level); + + if (N_data.bip32_path.length == 0) { + strcpy(global.ui.baking_auth_text, "No Key Authorized"); + } else { + cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); + pubkey_to_pkh_string( + global.ui.baking_auth_text, sizeof(global.ui.baking_auth_text), + N_data.curve, pubkey); + } +} + static void ui_idle(void) { #ifdef BAKING_APP - update_auth_text(); + update_baking_idle_screens(); ui_display(ui_idle_screen, NUM_ELEMENTS(ui_idle_screen), do_nothing, exit_app, 2); #else @@ -107,14 +120,9 @@ static void ui_idle(void) { #endif } -void change_idle_display(uint32_t new) { - number_to_string(global.ui.idle_text, new); - update_auth_text(); -} - void ui_initial_screen(void) { #ifdef BAKING_APP - change_idle_display(N_data.hwm.main.highest_level); + update_baking_idle_screens(); #endif clear_ui_callbacks(); ui_idle(); @@ -127,7 +135,7 @@ static bool is_idling(void) { static void timeout(void) { if (is_idling()) { // Idle app timeout - update_auth_text(); + update_baking_idle_screens(); global.ui.timeout_cycle_count = 0; UX_REDISPLAY(); } else { diff --git a/src/ui.h b/src/ui.h index 6cbb9a8d..1bdeb5c5 100644 --- a/src/ui.h +++ b/src/ui.h @@ -18,4 +18,3 @@ void ui_display(const bagl_element_t *elems, size_t sz, ui_callback_t ok_c, ui_c uint32_t step_count); unsigned char io_event(unsigned char channel); void io_seproxyhal_display(const bagl_element_t *element); -void change_idle_display(uint32_t new); From 971970e0d2f3a826b362560ce33544859ab8f1d1 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 20/25] Use G for globals in ui.c --- src/ui.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/ui.c b/src/ui.c index dac1a491..85c118ce 100644 --- a/src/ui.c +++ b/src/ui.c @@ -12,6 +12,8 @@ #include #include +#define G global.ui + static unsigned button_handler(unsigned button_mask, unsigned button_mask_counter); #define PROMPT_CYCLES 3 @@ -62,7 +64,7 @@ static const bagl_element_t ui_idle_screen[] = { {{BAGL_LABELINE, 0x01, 0, 26, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - global.ui.idle_text, + G.idle_text, 0, 0, 0, @@ -82,7 +84,7 @@ static const bagl_element_t ui_idle_screen[] = { {{BAGL_LABELINE, 0x02, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, - global.ui.baking_auth_text, + G.baking_auth_text, 0, 0, 0, @@ -97,14 +99,14 @@ static bool do_nothing(void) { #endif static void update_baking_idle_screens(void) { - number_to_string(global.ui.idle_text, N_data.hwm.main.highest_level); + number_to_string(G.idle_text, N_data.hwm.main.highest_level); if (N_data.bip32_path.length == 0) { - strcpy(global.ui.baking_auth_text, "No Key Authorized"); + strcpy(G.baking_auth_text, "No Key Authorized"); } else { cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); pubkey_to_pkh_string( - global.ui.baking_auth_text, sizeof(global.ui.baking_auth_text), + G.baking_auth_text, sizeof(G.baking_auth_text), N_data.curve, pubkey); } } @@ -115,7 +117,7 @@ static void ui_idle(void) { ui_display(ui_idle_screen, NUM_ELEMENTS(ui_idle_screen), do_nothing, exit_app, 2); #else - global.ui.cxl_callback = exit_app; + G.cxl_callback = exit_app; main_menu(); #endif } @@ -129,14 +131,14 @@ void ui_initial_screen(void) { } static bool is_idling(void) { - return global.ui.cxl_callback == exit_app; + return G.cxl_callback == exit_app; } static void timeout(void) { if (is_idling()) { // Idle app timeout update_baking_idle_screens(); - global.ui.timeout_cycle_count = 0; + G.timeout_cycle_count = 0; UX_REDISPLAY(); } else { // Prompt timeout -- simulate cancel button @@ -148,10 +150,10 @@ static unsigned button_handler(unsigned button_mask, __attribute__((unused)) uns ui_callback_t callback; switch (button_mask) { case BUTTON_EVT_RELEASED | BUTTON_LEFT: - callback = global.ui.cxl_callback; + callback = G.cxl_callback; break; case BUTTON_EVT_RELEASED | BUTTON_RIGHT: - callback = global.ui.ok_callback; + callback = G.ok_callback; break; default: return 0; @@ -174,7 +176,7 @@ const bagl_element_t *prepro(const bagl_element_t *element) { min = 4000; } - if (global.ui.ux_step == element->component.userid - 1 || element->component.userid == BAGL_SCROLLING_ELEMENT) { + if (G.ux_step == element->component.userid - 1 || element->component.userid == BAGL_SCROLLING_ELEMENT) { // timeouts are in millis UX_CALLBACK_SET_INTERVAL(MAX(min, (pause_millis + bagl_label_roundtrip_duration_ms(element, 7)) / div)); @@ -187,11 +189,11 @@ const bagl_element_t *prepro(const bagl_element_t *element) { void ui_display(const bagl_element_t *elems, size_t sz, ui_callback_t ok_c, ui_callback_t cxl_c, uint32_t step_count) { // Adapted from definition of UX_DISPLAY in header file - global.ui.timeout_cycle_count = 0; - global.ui.ux_step = 0; - global.ui.ux_step_count = step_count; - global.ui.ok_callback = ok_c; - global.ui.cxl_callback = cxl_c; + G.timeout_cycle_count = 0; + G.ux_step = 0; + G.ux_step_count = step_count; + G.ok_callback = ok_c; + G.cxl_callback = cxl_c; if (!is_idling()) { switch_screen(0); } @@ -225,15 +227,15 @@ unsigned char io_event(__attribute__((unused)) unsigned char channel) { ux.callback_interval_ms -= MIN(ux.callback_interval_ms, 100); if (ux.callback_interval_ms == 0) { // prepare next screen - global.ui.ux_step = (global.ui.ux_step + 1) % global.ui.ux_step_count; + G.ux_step = (G.ux_step + 1) % G.ux_step_count; if (!is_idling()) { - switch_screen(global.ui.ux_step); + switch_screen(G.ux_step); } // check if we've timed out - if (global.ui.ux_step == 0) { - global.ui.timeout_cycle_count++; - if (global.ui.timeout_cycle_count == PROMPT_CYCLES) { + if (G.ux_step == 0) { + G.timeout_cycle_count++; + if (G.timeout_cycle_count == PROMPT_CYCLES) { timeout(); break; // timeout() will often display a new screen } From 6e90ed491bc1c46555cedbc5314e1a45f183df38 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 21/25] Show chain ID with alias on baking idle screens --- src/globals.h | 3 +++ src/types.h | 5 +++++ src/ui.c | 33 +++++++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/globals.h b/src/globals.h index e2e227d6..ad225eb8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -74,6 +74,9 @@ typedef struct { char idle_text[16]; char baking_auth_text[PKH_STRING_SIZE]; + struct { + char chain[CHAIN_ID_BASE58_STRING_SIZE]; + } baking_idle_screens; struct { string_generation_callback callbacks[MAX_SCREEN_COUNT]; diff --git a/src/types.h b/src/types.h index 3db418c9..5fa48d47 100644 --- a/src/types.h +++ b/src/types.h @@ -165,3 +165,8 @@ struct parsed_operation_group { _Static_assert(x <= INS_MAX, "APDU instruction is out of bounds"); \ x; \ }) + +#define STRCPY(buff, x) ({ \ + _Static_assert(sizeof(buff) >= sizeof(x) && sizeof(*x) == sizeof(char), "String won't fit in buffer"); \ + strcpy(buff, x); \ +}) diff --git a/src/ui.c b/src/ui.c index 85c118ce..79954298 100644 --- a/src/ui.c +++ b/src/ui.c @@ -91,6 +91,27 @@ static const bagl_element_t ui_idle_screen[] = { NULL, NULL, NULL}, + + {{BAGL_LABELINE, 0x03, 0, 12, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, + "Chain", + 0, + 0, + 0, + NULL, + NULL, + NULL}, + + {{BAGL_LABELINE, 0x03, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, + BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, + G.baking_idle_screens.chain, + 0, + 0, + 0, + NULL, + NULL, + NULL}, + }; static bool do_nothing(void) { @@ -102,20 +123,28 @@ static void update_baking_idle_screens(void) { number_to_string(G.idle_text, N_data.hwm.main.highest_level); if (N_data.bip32_path.length == 0) { - strcpy(G.baking_auth_text, "No Key Authorized"); + STRCPY(G.baking_auth_text, "No Key Authorized"); } else { cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); pubkey_to_pkh_string( G.baking_auth_text, sizeof(G.baking_auth_text), N_data.curve, pubkey); } + + if (N_data.main_chain_id.v == 0) { + STRCPY(G.baking_idle_screens.chain, "any"); + } else if (N_data.main_chain_id.v == mainnet_chain_id.v) { + STRCPY(G.baking_idle_screens.chain, "mainnet"); + } else { + chain_id_to_string(G.baking_idle_screens.chain, sizeof(G.baking_idle_screens.chain), N_data.main_chain_id); + } } static void ui_idle(void) { #ifdef BAKING_APP update_baking_idle_screens(); ui_display(ui_idle_screen, NUM_ELEMENTS(ui_idle_screen), - do_nothing, exit_app, 2); + do_nothing, exit_app, 3); #else G.cxl_callback = exit_app; main_menu(); From a1051eb24bd5b9b45131f6c1caf94e767c747d26 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 22/25] Move baking idle screen globals to better place --- src/globals.h | 4 ++-- src/to_string.h | 1 - src/types.h | 2 ++ src/ui.c | 10 +++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/globals.h b/src/globals.h index ad225eb8..b17d9d55 100644 --- a/src/globals.h +++ b/src/globals.h @@ -72,9 +72,9 @@ typedef struct { uint32_t timeout_cycle_count; - char idle_text[16]; - char baking_auth_text[PKH_STRING_SIZE]; struct { + char hwm[MAX_INT_DIGITS + 1]; // with null termination + char pkh[PKH_STRING_SIZE]; char chain[CHAIN_ID_BASE58_STRING_SIZE]; } baking_idle_screens; diff --git a/src/to_string.h b/src/to_string.h index 58541a09..0047a448 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -15,7 +15,6 @@ void protocol_hash_to_string(char *buff, const size_t buff_size, const uint8_t h void parsed_contract_to_string(char *buff, uint32_t buff_size, const struct parsed_contract *contract); void chain_id_to_string(char *buff, size_t const buff_size, chain_id_t const chain_id); -#define MAX_INT_DIGITS 20 // dest must be at least MAX_INT_DIGITS size_t number_to_string(char *dest, uint64_t number); diff --git a/src/types.h b/src/types.h index 5fa48d47..3e316df0 100644 --- a/src/types.h +++ b/src/types.h @@ -13,6 +13,8 @@ typedef uint32_t level_t; #define CHAIN_ID_BASE58_STRING_SIZE (15 + 1) // with null termination +#define MAX_INT_DIGITS 20 + typedef struct { uint32_t v; } chain_id_t; diff --git a/src/ui.c b/src/ui.c index 79954298..5b8c7f8e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -64,7 +64,7 @@ static const bagl_element_t ui_idle_screen[] = { {{BAGL_LABELINE, 0x01, 0, 26, 128, 12, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 0}, - G.idle_text, + G.baking_idle_screens.hwm, 0, 0, 0, @@ -84,7 +84,7 @@ static const bagl_element_t ui_idle_screen[] = { {{BAGL_LABELINE, 0x02, 23, 26, 82, 12, 0x80 | 10, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px | BAGL_FONT_ALIGNMENT_CENTER, 26}, - G.baking_auth_text, + G.baking_idle_screens.pkh, 0, 0, 0, @@ -120,14 +120,14 @@ static bool do_nothing(void) { #endif static void update_baking_idle_screens(void) { - number_to_string(G.idle_text, N_data.hwm.main.highest_level); + number_to_string(G.baking_idle_screens.hwm, N_data.hwm.main.highest_level); if (N_data.bip32_path.length == 0) { - STRCPY(G.baking_auth_text, "No Key Authorized"); + STRCPY(G.baking_idle_screens.pkh, "No Key Authorized"); } else { cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); pubkey_to_pkh_string( - G.baking_auth_text, sizeof(G.baking_auth_text), + G.baking_idle_screens.pkh, sizeof(G.baking_idle_screens.pkh), N_data.curve, pubkey); } From 4a40251bca9e8b4eede12c193c241bf4e4d044b8 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 23/25] Show chain ID aliases in setup prompts --- src/apdu_setup.c | 2 +- src/to_string.c | 16 ++++++++++++++++ src/to_string.h | 1 + src/ui.c | 8 +------- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/apdu_setup.c b/src/apdu_setup.c index 128b395f..b2ce6201 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -64,7 +64,7 @@ __attribute__((noreturn)) static void prompt_setup( SET_STATIC_UI_VALUE(TYPE_INDEX, "Baking?"); register_ui_callback(ADDRESS_INDEX, pubkey_to_string, &G.public_key); - register_ui_callback(CHAIN_INDEX, chain_id_to_string, &G.main_chain_id); + register_ui_callback(CHAIN_INDEX, chain_id_to_string_with_aliases, &G.main_chain_id); register_ui_callback(MAIN_HWM_INDEX, number_to_string_indirect32, &G.hwm.main); register_ui_callback(TEST_HWM_INDEX, number_to_string_indirect32, &G.hwm.test); diff --git a/src/to_string.c b/src/to_string.c index f40fb856..ef57e75f 100644 --- a/src/to_string.c +++ b/src/to_string.c @@ -127,6 +127,22 @@ void chain_id_to_string(char *const buff, size_t const buff_size, chain_id_t con if (!b58enc(buff, &out_size, &data, sizeof(data))) THROW(EXC_WRONG_LENGTH); } +#define STRCPY_OR_THROW(buff, size, x, exc) ({ \ + if (size < sizeof(x)) THROW(exc); \ + strcpy(buff, x); \ +}) + +void chain_id_to_string_with_aliases(char *const out, size_t const out_size, chain_id_t const *const chain_id) { + check_null(chain_id); + if (chain_id->v == 0) { + STRCPY_OR_THROW(out, out_size, "any", EXC_WRONG_LENGTH); + } else if (chain_id->v == mainnet_chain_id.v) { + STRCPY_OR_THROW(out, out_size, "mainnet", EXC_WRONG_LENGTH); + } else { + chain_id_to_string(out, out_size, *chain_id); + } +} + // These functions do not output terminating null bytes. // This function fills digits, potentially with all leading zeroes, from the end of the buffer backwards diff --git a/src/to_string.h b/src/to_string.h index 0047a448..8c214b61 100644 --- a/src/to_string.h +++ b/src/to_string.h @@ -14,6 +14,7 @@ void pubkey_to_pkh_string(char *buff, uint32_t buff_size, cx_curve_t curve, void protocol_hash_to_string(char *buff, const size_t buff_size, const uint8_t hash[PROTOCOL_HASH_SIZE]); void parsed_contract_to_string(char *buff, uint32_t buff_size, const struct parsed_contract *contract); void chain_id_to_string(char *buff, size_t const buff_size, chain_id_t const chain_id); +void chain_id_to_string_with_aliases(char *const out, size_t const out_size, chain_id_t const *const chain_id); // dest must be at least MAX_INT_DIGITS size_t number_to_string(char *dest, uint64_t number); diff --git a/src/ui.c b/src/ui.c index 5b8c7f8e..c10ae64a 100644 --- a/src/ui.c +++ b/src/ui.c @@ -131,13 +131,7 @@ static void update_baking_idle_screens(void) { N_data.curve, pubkey); } - if (N_data.main_chain_id.v == 0) { - STRCPY(G.baking_idle_screens.chain, "any"); - } else if (N_data.main_chain_id.v == mainnet_chain_id.v) { - STRCPY(G.baking_idle_screens.chain, "mainnet"); - } else { - chain_id_to_string(G.baking_idle_screens.chain, sizeof(G.baking_idle_screens.chain), N_data.main_chain_id); - } + chain_id_to_string_with_aliases(G.baking_idle_screens.chain, sizeof(G.baking_idle_screens.chain), &N_data.main_chain_id); } static void ui_idle(void) { From 9d53371fface6da5db55117867b42e6699ac33c3 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 10:38:46 -0500 Subject: [PATCH 24/25] Add clarifications to some string size constants --- src/types.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/types.h b/src/types.h index 3e316df0..29803bd1 100644 --- a/src/types.h +++ b/src/types.h @@ -11,7 +11,7 @@ typedef uint32_t (*apdu_handler)(uint8_t instruction); typedef uint32_t level_t; -#define CHAIN_ID_BASE58_STRING_SIZE (15 + 1) // with null termination +#define CHAIN_ID_BASE58_STRING_SIZE sizeof("NetXdQprcVkpaWU") #define MAX_INT_DIGITS 20 @@ -73,25 +73,23 @@ typedef struct { } nvram_data; -#define PKH_STRING_SIZE 40 -#define PROTOCOL_HASH_BASE58_STRING_SIZE 52 // e.g. "ProtoBetaBetaBetaBetaBetaBetaBetaBetaBet11111a5ug96" plus null byte +#define PKH_STRING_SIZE 40 // includes null byte // TODO: use sizeof for this. +#define PROTOCOL_HASH_BASE58_STRING_SIZE sizeof("ProtoBetaBetaBetaBetaBetaBetaBetaBetaBet11111a5ug96") #define MAX_SCREEN_COUNT 7 // Current maximum usage #define PROMPT_WIDTH 16 #define VALUE_WIDTH PROTOCOL_HASH_BASE58_STRING_SIZE // Macros to wrap a static prompt and value strings and ensure they aren't too long. -#define PROMPT(str) \ - ({ \ +#define PROMPT(str) ({ \ _Static_assert(sizeof(str) <= PROMPT_WIDTH + 1/*null byte*/ , str " won't fit in the UI prompt."); \ str; \ - }) +}) -#define STATIC_UI_VALUE(str) \ - ({ \ +#define STATIC_UI_VALUE(str) ({ \ _Static_assert(sizeof(str) <= VALUE_WIDTH + 1/*null byte*/, str " won't fit in the UI.".); \ str; \ - }) +}) // Operations From cc7e7893f4bb323c41d9ec37ecdc66c42d2a21bb Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Fri, 1 Feb 2019 13:46:51 -0500 Subject: [PATCH 25/25] Update baking idle screens any time NVRAM changes --- src/globals.c | 36 ++++++++++++++++++++++++++++++++---- src/globals.h | 27 +++++++++++++-------------- src/ui.c | 15 --------------- 3 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/globals.c b/src/globals.c index 6cd6da16..4c7a97bf 100644 --- a/src/globals.c +++ b/src/globals.c @@ -1,7 +1,11 @@ #include "globals.h" +#include "exception.h" +#include "to_string.h" + #include + // WARNING: *************************************************** // Non-const globals MUST NOT HAVE AN INITIALIZER. // @@ -16,12 +20,36 @@ globals_t global; ux_state_t ux; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -// DO NOT TRY TO INIT THIS. This can only be written via an system call. -// The "N_" is *significant*. It tells the linker to put this in NVRAM. -WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? - void init_globals(void) { memset(&global, 0, sizeof(global)); memset(&ux, 0, sizeof(ux)); memset(G_io_seproxyhal_spi_buffer, 0, sizeof(G_io_seproxyhal_spi_buffer)); } + +// #ifdef BAKING_APP +// DO NOT TRY TO INIT THIS. This can only be written via an system call. +// The "N_" is *significant*. It tells the linker to put this in NVRAM. +WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? + +high_watermark_t *select_hwm_by_chain(chain_id_t const chain_id, nvram_data *const ram) { + check_null(ram); + return chain_id.v == ram->main_chain_id.v || ram->main_chain_id.v == 0 + ? &ram->hwm.main + : &ram->hwm.test; +} + +void update_baking_idle_screens(void) { + number_to_string(global.ui.baking_idle_screens.hwm, N_data.hwm.main.highest_level); + + if (N_data.bip32_path.length == 0) { + STRCPY(global.ui.baking_idle_screens.pkh, "No Key Authorized"); + } else { + cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); + pubkey_to_pkh_string( + global.ui.baking_idle_screens.pkh, sizeof(global.ui.baking_idle_screens.pkh), + N_data.curve, pubkey); + } + + chain_id_to_string_with_aliases(global.ui.baking_idle_screens.chain, sizeof(global.ui.baking_idle_screens.chain), &N_data.main_chain_id); +} +//#endif diff --git a/src/globals.h b/src/globals.h index b17d9d55..0ec31575 100644 --- a/src/globals.h +++ b/src/globals.h @@ -120,10 +120,21 @@ extern unsigned int app_stack_canary; // From SDK extern ux_state_t ux; extern unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +static inline void throw_stack_size() { + uint8_t st; + // uint32_t tmp1 = (uint32_t)&st - (uint32_t)&app_stack_canary; + uint32_t tmp2 = (uint32_t)global.stack_root - (uint32_t)&st; + THROW(0x9000 + tmp2); +} + +// #ifdef BAKING_APP extern WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? #define N_data (*(WIDE nvram_data*)PIC(&N_data_real)) +void update_baking_idle_screens(void); +high_watermark_t *select_hwm_by_chain(chain_id_t const chain_id, nvram_data *const ram); + // Properly updates NVRAM data to prevent any clobbering of data. // 'out_param' defines the name of a pointer to the nvram_data struct // that 'body' can change to apply updates. @@ -132,18 +143,6 @@ extern WIDE nvram_data N_data_real; // TODO: What does WIDE actually mean? memcpy(&global.baking_auth.new_data, &N_data, sizeof(global.baking_auth.new_data)); \ body; \ nvm_write((void*)&N_data, &global.baking_auth.new_data, sizeof(N_data)); \ + update_baking_idle_screens(); \ }) - -static inline high_watermark_t *select_hwm_by_chain(chain_id_t const chain_id, nvram_data *const ram) { - check_null(ram); - return chain_id.v == ram->main_chain_id.v || ram->main_chain_id.v == 0 - ? &ram->hwm.main - : &ram->hwm.test; -} - -static inline void throw_stack_size() { - uint8_t st; - // uint32_t tmp1 = (uint32_t)&st - (uint32_t)&app_stack_canary; - uint32_t tmp2 = (uint32_t)global.stack_root - (uint32_t)&st; - THROW(0x9000 + tmp2); -} +//#endif diff --git a/src/ui.c b/src/ui.c index c10ae64a..69076574 100644 --- a/src/ui.c +++ b/src/ui.c @@ -119,21 +119,6 @@ static bool do_nothing(void) { } #endif -static void update_baking_idle_screens(void) { - number_to_string(G.baking_idle_screens.hwm, N_data.hwm.main.highest_level); - - if (N_data.bip32_path.length == 0) { - STRCPY(G.baking_idle_screens.pkh, "No Key Authorized"); - } else { - cx_ecfp_public_key_t const *const pubkey = generate_public_key(N_data.curve, &N_data.bip32_path); - pubkey_to_pkh_string( - G.baking_idle_screens.pkh, sizeof(G.baking_idle_screens.pkh), - N_data.curve, pubkey); - } - - chain_id_to_string_with_aliases(G.baking_idle_screens.chain, sizeof(G.baking_idle_screens.chain), &N_data.main_chain_id); -} - static void ui_idle(void) { #ifdef BAKING_APP update_baking_idle_screens();