1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-06-28 02:42:34 +00:00

Fix checking change address

There was a signed/unsigned problem: size_t is unsigned, but we use
-1 to indicate mismatch.  The problem was that when checking the input
address path, it still did this unintentionally when a mismatch was
detected, forbidding to sign with mismatched inputs, even when there
is no change address.

We now use 1 for mismatch.  Also we don't allow change address anymore
if the inputs have a path of length 1.  This simplifies the code a bit.
This commit is contained in:
Jochen Hoenicke 2017-10-10 16:05:42 +02:00 committed by Pavol Rusnak
parent 5e98b0ffd6
commit 4805f27e8c

View File

@ -68,6 +68,12 @@ static uint8_t multisig_fp[32];
static uint32_t in_address_n[8]; static uint32_t in_address_n[8];
static size_t in_address_n_count; static size_t in_address_n_count;
/* marker for in_address_n_count to indicate a mismatch in bip32 paths in
input */
#define BIP32_NOCHANGEALLOWED 1
/* maximum allowed change index */
#define MAX_BIP32_LAST_ELEMENT 1000000
enum { enum {
SIGHASH_ALL = 1, SIGHASH_ALL = 1,
SIGHASH_FORKID = 0x40, SIGHASH_FORKID = 0x40,
@ -328,61 +334,45 @@ void phase2_request_next_input(void)
void extract_input_bip32_path(const TxInputType *tinput) void extract_input_bip32_path(const TxInputType *tinput)
{ {
if (in_address_n_count == (size_t) -1) { if (in_address_n_count == BIP32_NOCHANGEALLOWED) {
return; return;
} }
size_t count = tinput->address_n_count; size_t count = tinput->address_n_count;
if (count < 1) { if (count < 2) {
// no change address allowed // no change address allowed
in_address_n_count = (size_t) -1; in_address_n_count = BIP32_NOCHANGEALLOWED;
return; return;
} }
if (in_address_n_count == 0) { if (in_address_n_count == 0) {
// initialize in_address_n on first input seen // initialize in_address_n on first input seen
in_address_n_count = count; in_address_n_count = count;
if (count > 2) { // if longer than 2 elements, store first N - 2 // store first N - 2
memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)); memcpy(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t));
}
return; return;
} }
// check whether they are same length // check whether they are same length
if (in_address_n_count != count) { if (in_address_n_count != count) {
in_address_n_count = (size_t) -1; in_address_n_count = BIP32_NOCHANGEALLOWED;
return; return;
} }
if (count > 2 && memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) { if (memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t)) != 0) {
// mismatch -> no change address allowed // mismatch -> no change address allowed
in_address_n_count = (size_t) -1; in_address_n_count = BIP32_NOCHANGEALLOWED;
return; return;
} }
} }
#define MAX_BIP32_LAST_ELEMENT 1000000
bool check_change_bip32_path(const TxOutputType *toutput) bool check_change_bip32_path(const TxOutputType *toutput)
{ {
size_t count = toutput->address_n_count; size_t count = toutput->address_n_count;
if (count < 1 || in_address_n_count < 1) { // Note: count >= 2 and count == in_address_n_count
return 0; // imply that in_address_n_count != BIP32_NOCHANGEALLOWED
} return (count >= 2
&& count == in_address_n_count
if (count != in_address_n_count) { && 0 == memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t))
return 0; && toutput->address_n[count - 2] == 1
} && toutput->address_n[count - 1] <= MAX_BIP32_LAST_ELEMENT);
if (toutput->address_n[count - 1] > MAX_BIP32_LAST_ELEMENT) {
return 0;
}
if (count >= 2) {
if (0 != memcmp(in_address_n, toutput->address_n, (count - 2) * sizeof(uint32_t)) ||
toutput->address_n[count - 2] != 1) {
return 0;
}
}
return 1;
} }
bool compile_input_script_sig(TxInputType *tinput) bool compile_input_script_sig(TxInputType *tinput)
@ -397,14 +387,12 @@ bool compile_input_script_sig(TxInputType *tinput)
return false; return false;
} }
} }
if (in_address_n_count >= 1) { if (in_address_n_count != BIP32_NOCHANGEALLOWED) {
// check that input address didn't change // check that input address didn't change
size_t count = tinput->address_n_count; size_t count = tinput->address_n_count;
if (count != in_address_n_count) { if (count < 2
return false; || count != in_address_n_count
} || 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) {
if (count >= 2
&& 0 != memcmp(in_address_n, tinput->address_n, (count - 2) * sizeof(uint32_t))) {
return false; return false;
} }
} }