From 020a47d67c06e6bf64f4be0f2abb7b3476b41479 Mon Sep 17 00:00:00 2001 From: Elliot Cameron Date: Wed, 20 Feb 2019 11:12:11 -0500 Subject: [PATCH] Factor out common APDU code and normalize --- src/apdu.c | 32 ++++++++++++-------------------- src/apdu.h | 23 +++++++++++++++-------- src/apdu_baking.c | 41 ++++++++++++++--------------------------- src/apdu_baking.h | 11 ++++++----- src/apdu_pubkey.c | 2 +- src/apdu_pubkey.h | 2 +- src/apdu_setup.c | 2 +- src/apdu_setup.h | 3 ++- src/apdu_sign.c | 22 +++++++--------------- src/apdu_sign.h | 2 +- src/main.c | 2 +- src/types.h | 2 +- 12 files changed, 62 insertions(+), 82 deletions(-) diff --git a/src/apdu.c b/src/apdu.c index 1af9a409..dcd65282 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -10,38 +10,30 @@ size_t provide_pubkey(uint8_t *const io_buffer, cx_ecfp_public_key_t const *cons 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; + return finalize_successful_send(tx); } -unsigned int handle_apdu_error(uint8_t __attribute__((unused)) instruction) { +size_t handle_apdu_error(uint8_t __attribute__((unused)) instruction) { THROW(EXC_INVALID_INS); } -unsigned int handle_apdu_version(uint8_t __attribute__((unused)) instruction) { - int tx = 0; +size_t handle_apdu_version(uint8_t __attribute__((unused)) instruction) { memcpy(G_io_apdu_buffer, &version, sizeof(version_t)); - tx += sizeof(version_t); - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; + size_t tx = sizeof(version_t); + return finalize_successful_send(tx); } -unsigned int handle_apdu_git(uint8_t __attribute__((unused)) instruction) { +size_t handle_apdu_git(uint8_t __attribute__((unused)) instruction) { static const char commit[] = COMMIT; memcpy(G_io_apdu_buffer, commit, sizeof(commit)); - - uint32_t tx = sizeof(commit); - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; + size_t tx = sizeof(commit); + return finalize_successful_send(tx); } #define CLA 0x80 __attribute__((noreturn)) -void main_loop(apdu_handler handlers[INS_MAX]) { +void main_loop(apdu_handler const *const handlers, size_t const handlers_size) { volatile uint32_t rx = io_exchange(CHANNEL_APDU, 0); while (true) { BEGIN_TRY { @@ -65,12 +57,12 @@ void main_loop(apdu_handler handlers[INS_MAX]) { THROW(EXC_WRONG_LENGTH); } - const uint8_t instruction = G_io_apdu_buffer[OFFSET_INS]; - const apdu_handler cb = (instruction >= INS_MAX) + uint8_t const instruction = G_io_apdu_buffer[OFFSET_INS]; + apdu_handler const cb = instruction >= handlers_size ? handle_apdu_error : handlers[instruction]; - const uint32_t tx = cb(instruction); + size_t const tx = cb(instruction); rx = io_exchange(CHANNEL_APDU, tx); } CATCH(ASYNC_EXCEPTION) { diff --git a/src/apdu.h b/src/apdu.h index 297fc7b1..d3074def 100644 --- a/src/apdu.h +++ b/src/apdu.h @@ -37,21 +37,28 @@ #define INS_DEAUTHORIZE 0x0C __attribute__((noreturn)) -void main_loop(apdu_handler handlers[INS_MAX]); +void main_loop(apdu_handler const *const handlers, size_t const handlers_size); static inline void return_ok(void) { THROW(EXC_NO_ERROR); } +static inline size_t finalize_successful_send(size_t tx) { + G_io_apdu_buffer[tx++] = 0x90; + G_io_apdu_buffer[tx++] = 0x00; + return tx; +} + // Send back response; do not restart the event loop -static inline void delayed_send(uint32_t tx) { +static inline void delayed_send(size_t tx) { io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); } static inline bool delay_reject(void) { - G_io_apdu_buffer[0] = EXC_REJECT >> 8; - G_io_apdu_buffer[1] = EXC_REJECT & 0xFF; - delayed_send(2); + size_t tx = 0; + G_io_apdu_buffer[tx++] = EXC_REJECT >> 8; + G_io_apdu_buffer[tx++] = EXC_REJECT & 0xFF; + delayed_send(tx); return true; } @@ -63,6 +70,6 @@ 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); +size_t handle_apdu_error(uint8_t instruction); +size_t handle_apdu_version(uint8_t instruction); +size_t handle_apdu_git(uint8_t instruction); diff --git a/src/apdu_baking.c b/src/apdu_baking.c index d601c5d2..7cfe99de 100644 --- a/src/apdu_baking.c +++ b/src/apdu_baking.c @@ -14,7 +14,7 @@ static bool reset_ok(void); -unsigned int handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { +size_t handle_apdu_reset(__attribute__((unused)) uint8_t instruction) { uint8_t *dataBuffer = G_io_apdu_buffer + OFFSET_CDATA; uint32_t dataLength = G_io_apdu_buffer[OFFSET_LC]; if (dataLength != sizeof(int)) { @@ -42,16 +42,12 @@ bool reset_ok(void) { ram->hwm.test.had_endorsement = false; }); - uint32_t tx = 0; - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - // Send back the response, do not restart the event loop - delayed_send(tx); + delayed_send(finalize_successful_send(0)); return true; } -uint32_t send_word_big_endian(uint32_t tx, uint32_t word) { +size_t send_word_big_endian(size_t tx, uint32_t word) { char word_bytes[sizeof(word)]; memcpy(word_bytes, &word, sizeof(word)); @@ -65,49 +61,40 @@ uint32_t send_word_big_endian(uint32_t tx, uint32_t word) { return tx + i; } -unsigned int handle_apdu_all_hwm(__attribute__((unused)) uint8_t instruction) { - uint32_t tx = 0; +size_t handle_apdu_all_hwm(__attribute__((unused)) uint8_t instruction) { + size_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; + return finalize_successful_send(tx); } -unsigned int handle_apdu_main_hwm(__attribute__((unused)) uint8_t instruction) { - uint32_t tx = 0; +size_t handle_apdu_main_hwm(__attribute__((unused)) uint8_t instruction) { + size_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; + return finalize_successful_send(tx); } -unsigned int handle_apdu_query_auth_key(__attribute__((unused)) uint8_t instruction) { +size_t handle_apdu_query_auth_key(__attribute__((unused)) uint8_t instruction) { uint8_t const length = N_data.baking_key.bip32_path.length; - uint32_t tx = 0; + size_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.baking_key.bip32_path.components[i]); } - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; + return finalize_successful_send(tx); } -unsigned int handle_apdu_deauthorize(__attribute__((unused)) uint8_t instruction) { +size_t handle_apdu_deauthorize(__attribute__((unused)) uint8_t instruction) { if (READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_P1]) != 0) THROW(EXC_WRONG_PARAM); if (READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_LC]) != 0) THROW(EXC_PARSE_ERROR); UPDATE_NVRAM(ram, { memset(&ram->baking_key, 0, sizeof(ram->baking_key)); }); - unsigned int tx = 0; - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; + return finalize_successful_send(0); } diff --git a/src/apdu_baking.h b/src/apdu_baking.h index 75bc954c..4234184e 100644 --- a/src/apdu_baking.h +++ b/src/apdu_baking.h @@ -1,9 +1,10 @@ #pragma once +#include #include -unsigned int handle_apdu_reset(uint8_t instruction); -unsigned int handle_apdu_query_auth_key(uint8_t instruction); -unsigned int handle_apdu_main_hwm(uint8_t instruction); -unsigned int handle_apdu_all_hwm(uint8_t instruction); -unsigned int handle_apdu_deauthorize(uint8_t instruction); +size_t handle_apdu_reset(uint8_t instruction); +size_t handle_apdu_query_auth_key(uint8_t instruction); +size_t handle_apdu_main_hwm(uint8_t instruction); +size_t handle_apdu_all_hwm(uint8_t instruction); +size_t handle_apdu_deauthorize(uint8_t instruction); diff --git a/src/apdu_pubkey.c b/src/apdu_pubkey.c index 677c6d20..3105fbe1 100644 --- a/src/apdu_pubkey.c +++ b/src/apdu_pubkey.c @@ -24,7 +24,7 @@ static bool baking_ok(void) { } #endif -unsigned int handle_apdu_get_public_key(uint8_t instruction) { +size_t handle_apdu_get_public_key(uint8_t instruction) { uint8_t *dataBuffer = G_io_apdu_buffer + OFFSET_CDATA; if (READ_UNALIGNED_BIG_ENDIAN(uint8_t, &G_io_apdu_buffer[OFFSET_P1]) != 0) THROW(EXC_WRONG_PARAM); diff --git a/src/apdu_pubkey.h b/src/apdu_pubkey.h index 460ca218..ac58d796 100644 --- a/src/apdu_pubkey.h +++ b/src/apdu_pubkey.h @@ -2,4 +2,4 @@ #include "apdu.h" -unsigned int handle_apdu_get_public_key(uint8_t instruction); +size_t handle_apdu_get_public_key(uint8_t instruction); diff --git a/src/apdu_setup.c b/src/apdu_setup.c index 9d0f3153..bcc9ac30 100644 --- a/src/apdu_setup.c +++ b/src/apdu_setup.c @@ -64,7 +64,7 @@ __attribute__((noreturn)) static void prompt_setup( ui_prompt(prompts, NULL, ok_cb, cxl_cb); } -__attribute__((noreturn)) unsigned int handle_apdu_setup(__attribute__((unused)) uint8_t instruction) { +__attribute__((noreturn)) size_t 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]); diff --git a/src/apdu_setup.h b/src/apdu_setup.h index a61beb1b..fd2d2d0a 100644 --- a/src/apdu_setup.h +++ b/src/apdu_setup.h @@ -1,5 +1,6 @@ #pragma once +#include #include -unsigned int handle_apdu_setup(uint8_t instruction); +size_t handle_apdu_setup(uint8_t instruction); diff --git a/src/apdu_sign.c b/src/apdu_sign.c index fd6a6b9e..a6c24e82 100644 --- a/src/apdu_sign.c +++ b/src/apdu_sign.c @@ -53,15 +53,13 @@ static void finish_hashing(uint8_t *hash, size_t hash_size) { static int perform_signature(bool hash_first); static bool sign_ok(void) { - int tx = perform_signature(true); - delayed_send(tx); + delayed_send(perform_signature(true)); return true; } #ifndef BAKING_APP static bool sign_unsafe_ok(void) { - int tx = perform_signature(false); - delayed_send(tx); + delayed_send(perform_signature(false)); return true; } #endif @@ -477,7 +475,7 @@ uint32_t wallet_sign_complete(uint8_t instruction) { #define P1_HASH_ONLY_NEXT 0x03 // You only need it once #define P1_LAST_MARKER 0x80 -unsigned int handle_apdu_sign(uint8_t instruction) { +size_t handle_apdu_sign(uint8_t instruction) { uint8_t p1 = G_io_apdu_buffer[OFFSET_P1]; uint8_t *dataBuffer = G_io_apdu_buffer + OFFSET_CDATA; uint32_t dataLength = G_io_apdu_buffer[OFFSET_LC]; @@ -552,18 +550,15 @@ static int perform_signature(bool hash_first) { #ifndef BAKING_APP if (G.hash_only) { memcpy(G_io_apdu_buffer, data, datalen); - uint32_t tx = datalen; - - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - return tx; + size_t tx = datalen; + return finalize_successful_send(tx); } #endif } struct key_pair *const pair = generate_key_pair(G.key.curve, &G.key.bip32_path); - uint32_t tx; + size_t tx = 0; switch (G.key.curve) { case CX_CURVE_Ed25519: { tx = cx_eddsa_sign(&pair->private_key, @@ -601,10 +596,7 @@ static int perform_signature(bool hash_first) { memset(&pair->private_key, 0, sizeof(pair->private_key)); - G_io_apdu_buffer[tx++] = 0x90; - G_io_apdu_buffer[tx++] = 0x00; - clear_data(); - return tx; + return finalize_successful_send(tx); } diff --git a/src/apdu_sign.h b/src/apdu_sign.h index 0e5ad17c..8c3b8583 100644 --- a/src/apdu_sign.h +++ b/src/apdu_sign.h @@ -2,4 +2,4 @@ #include "apdu.h" -unsigned int handle_apdu_sign(uint8_t instruction); +size_t handle_apdu_sign(uint8_t instruction); diff --git a/src/main.c b/src/main.c index 78d28d9d..c2a40862 100644 --- a/src/main.c +++ b/src/main.c @@ -45,5 +45,5 @@ void app_main(void) { #else global.handlers[APDU_INS(INS_SIGN_UNSAFE)] = handle_apdu_sign; #endif - main_loop(global.handlers); + main_loop(global.handlers, sizeof(global.handlers)); } diff --git a/src/types.h b/src/types.h index 6a37ad28..96326cf3 100644 --- a/src/types.h +++ b/src/types.h @@ -8,7 +8,7 @@ #include // Return number of bytes to transmit (tx) -typedef uint32_t (*apdu_handler)(uint8_t instruction); +typedef size_t (*apdu_handler)(uint8_t instruction); typedef uint32_t level_t;