From 05a73593f68e8424640b6c5fb9a4920d54cd0544 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Fri, 19 Aug 2016 22:25:01 +0200 Subject: [PATCH] No special case encoding for '\x0', cleanups The encoding for data '\x00' was tested here: http://testnet.etherscan.io/tx/0x05d6f97de3ecd33ad4059fa9bd342a10ef99d580a2d881b0c5a0c9e8c55ff975 --- firmware/ethereum.c | 59 +++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 857f2f9..358ccfc 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -3,6 +3,7 @@ * * Copyright (C) 2016 Alex Beregszaszi * Copyright (C) 2016 Pavol Rusnak + * Copyright (C) 2016 Jochen Hoenicke * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -30,7 +31,7 @@ #include "sha3.h" #include "util.h" -static bool signing = false; +static bool ethereum_signing = false; static uint32_t data_total, data_left; static EthereumTxRequest resp; static uint8_t hash[32], sig[64], privkey[32]; @@ -47,11 +48,7 @@ static inline void hash_data(const uint8_t *buf, size_t size) static void hash_rlp_length(uint32_t length, uint8_t firstbyte) { uint8_t buf[4]; - if (length == 1 && firstbyte == 0x00) { - // special case: null is encoded differently - buf[0] = 0x80; - hash_data(buf, 1); - } else if (length == 1 && firstbyte <= 0x7f) { + if (length == 1 && firstbyte <= 0x7f) { buf[0] = firstbyte; hash_data(buf, 1); } else if (length <= 55) { @@ -307,7 +304,7 @@ static bool ethereum_signing_check(EthereumSignTx *msg) void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) { - signing = true; + ethereum_signing = true; sha3_256_Init(&keccak_ctx); memset(&resp, 0, sizeof(EthereumTxRequest)); @@ -323,8 +320,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) ethereum_signing_abort(); return; } - if (msg->data_initial_chunk.size > msg->data_length) { - fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + /* Our encoding only supports transactions up to 2^24 bytes. To + * prevent exceeding the limit we use a stricter limit on data length. + */ + if (msg->data_length > 16000000) { + fsm_sendFailure(FailureType_Failure_Other, "Data length exceeds limit"); ethereum_signing_abort(); return; } @@ -332,6 +332,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) } else { data_total = 0; } + if (msg->data_initial_chunk.size > data_total) { + fsm_sendFailure(FailureType_Failure_Other, "Invalid size of initial chunk"); + ethereum_signing_abort(); + return; + } // safety checks if (!ethereum_signing_check(msg)) { @@ -357,7 +362,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += msg->has_gas_limit ? rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]) : 1; rlp_length += msg->has_to ? rlp_calculate_length(msg->to.size, msg->to.bytes[0]) : 1; rlp_length += msg->has_value ? rlp_calculate_length(msg->value.size, msg->value.bytes[0]) : 1; - rlp_length += (msg->has_data_length && msg->has_data_initial_chunk) ? rlp_calculate_length(msg->data_length, msg->data_initial_chunk.bytes[0]) : 1; + rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); /* Stage 2: Store header fields */ hash_rlp_list_length(rlp_length); @@ -367,47 +372,43 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) if (msg->has_nonce) { hash_rlp_field(msg->nonce.bytes, msg->nonce.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_gas_price) { hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_gas_limit) { hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_to) { hash_rlp_field(msg->to.bytes, msg->to.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } if (msg->has_value) { hash_rlp_field(msg->value.bytes, msg->value.size); } else { - hash_rlp_length(1, 0); + hash_rlp_length(0, 0); } - if (msg->has_data_length && msg->has_data_initial_chunk) { - hash_rlp_length(msg->data_length, msg->data_initial_chunk.bytes[0]); + hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); + if (data_total > 1 || msg->data_initial_chunk.bytes[0] >= 0x80) { hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); - } else { - hash_rlp_length(1, 0); } - - layoutProgress("Signing", 200); + data_left = data_total - msg->data_initial_chunk.size; /* FIXME: probably this shouldn't be done here, but at a later stage */ memcpy(privkey, node->private_key, 32); - if (msg->has_data_length && msg->data_length > msg->data_initial_chunk.size) { - data_left = msg->data_length - msg->data_initial_chunk.size; + if (data_left > 0) { send_request_chunk(); } else { send_signature(); @@ -416,12 +417,18 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_txack(EthereumTxAck *tx) { - if (!signing) { + if (!ethereum_signing) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Not in Signing mode"); layoutHome(); return; } + if (tx->data_chunk.size > data_left) { + fsm_sendFailure(FailureType_Failure_Other, "Too much data"); + ethereum_signing_abort(); + return; + } + if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { fsm_sendFailure(FailureType_Failure_Other, "Empty data chunk received"); ethereum_signing_abort(); @@ -441,9 +448,9 @@ void ethereum_signing_txack(EthereumTxAck *tx) void ethereum_signing_abort(void) { - if (signing) { + if (ethereum_signing) { memset(privkey, 0, sizeof(privkey)); layoutHome(); - signing = false; + ethereum_signing = false; } }