mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-05-29 04:08:46 +00:00
feat(legacy): Check script type match for change-outputs in Bitcoin signing.
This commit is contained in:
parent
2a3cc688a1
commit
f2a73637fe
@ -818,6 +818,7 @@ bool is_segwit_output_script_type(OutputScriptType script_type) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool change_output_to_input_script_type(OutputScriptType output_script_type,
|
bool change_output_to_input_script_type(OutputScriptType output_script_type,
|
||||||
InputScriptType *input_script_type) {
|
InputScriptType *input_script_type) {
|
||||||
switch (output_script_type) {
|
switch (output_script_type) {
|
||||||
|
@ -112,6 +112,12 @@ static const char *progress_label;
|
|||||||
static uint32_t tx_weight, tx_base_weight, our_weight, our_inputs_len;
|
static uint32_t tx_weight, tx_base_weight, our_weight, our_inputs_len;
|
||||||
PathSchema unlocked_schema;
|
PathSchema unlocked_schema;
|
||||||
|
|
||||||
|
typedef enum _MatchState {
|
||||||
|
MatchState_UNDEFINED = 0,
|
||||||
|
MatchState_MATCH = 1,
|
||||||
|
MatchState_MISMATCH = 2,
|
||||||
|
} MatchState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t inputs_count;
|
uint32_t inputs_count;
|
||||||
uint32_t outputs_count;
|
uint32_t outputs_count;
|
||||||
@ -123,6 +129,8 @@ typedef struct {
|
|||||||
uint8_t multisig_fp[32];
|
uint8_t multisig_fp[32];
|
||||||
uint32_t in_address_n[8];
|
uint32_t in_address_n[8];
|
||||||
size_t in_address_n_count;
|
size_t in_address_n_count;
|
||||||
|
InputScriptType in_script_type;
|
||||||
|
MatchState in_script_type_state;
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t lock_time;
|
uint32_t lock_time;
|
||||||
uint32_t expiry;
|
uint32_t expiry;
|
||||||
@ -982,6 +990,47 @@ bool check_change_multisig_fp(const TxInfo *tx_info,
|
|||||||
memcmp(tx_info->multisig_fp, h, 32) == 0;
|
memcmp(tx_info->multisig_fp, h, 32) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static InputScriptType simple_script_type(InputScriptType script_type) {
|
||||||
|
// SPENDMULTISIG is used only for non-SegWit and is effectively the same as
|
||||||
|
// SPENDADDRESS. For SegWit inputs and outputs multisig is indicated by the
|
||||||
|
// presence of the multisig structure. for both SegWit and non-SegWit we can
|
||||||
|
// rely on multisig_fp to check the multisig structure.
|
||||||
|
if (script_type == InputScriptType_SPENDMULTISIG) {
|
||||||
|
script_type = InputScriptType_SPENDADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return script_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void extract_input_script_type(TxInfo *tx_info, const TxInputType *tinput) {
|
||||||
|
switch (tx_info->in_script_type_state) {
|
||||||
|
case MatchState_UNDEFINED:
|
||||||
|
// initialize in_script_type on first input seen
|
||||||
|
tx_info->in_script_type = simple_script_type(tinput->script_type);
|
||||||
|
tx_info->in_script_type_state = MatchState_MATCH;
|
||||||
|
break;
|
||||||
|
case MatchState_MATCH:
|
||||||
|
// check that all input script types are the same
|
||||||
|
if (tx_info->in_script_type != simple_script_type(tinput->script_type)) {
|
||||||
|
tx_info->in_script_type_state = MatchState_MISMATCH;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_change_script_type(const TxInfo *tx_info,
|
||||||
|
const TxOutputType *toutput) {
|
||||||
|
InputScriptType input_script_type = 0;
|
||||||
|
if (!change_output_to_input_script_type(toutput->script_type,
|
||||||
|
&input_script_type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return tx_info->in_script_type_state == MatchState_MATCH &&
|
||||||
|
tx_info->in_script_type == simple_script_type(input_script_type);
|
||||||
|
}
|
||||||
|
|
||||||
void extract_input_bip32_path(TxInfo *tx_info, const TxInputType *tinput) {
|
void extract_input_bip32_path(TxInfo *tx_info, const TxInputType *tinput) {
|
||||||
if (tx_info->in_address_n_count == BIP32_NOCHANGEALLOWED) {
|
if (tx_info->in_address_n_count == BIP32_NOCHANGEALLOWED) {
|
||||||
return;
|
return;
|
||||||
@ -1201,6 +1250,8 @@ static bool tx_info_init(TxInfo *tx_info, uint32_t inputs_count,
|
|||||||
tx_info->multisig_fp_set = false;
|
tx_info->multisig_fp_set = false;
|
||||||
tx_info->multisig_fp_mismatch = false;
|
tx_info->multisig_fp_mismatch = false;
|
||||||
tx_info->in_address_n_count = 0;
|
tx_info->in_address_n_count = 0;
|
||||||
|
tx_info->in_script_type = 0;
|
||||||
|
tx_info->in_script_type_state = MatchState_UNDEFINED;
|
||||||
tx_info->version = version;
|
tx_info->version = version;
|
||||||
tx_info->lock_time = lock_time;
|
tx_info->lock_time = lock_time;
|
||||||
|
|
||||||
@ -1683,6 +1734,10 @@ static bool tx_info_add_input(TxInfo *tx_info, const TxInputType *txinput) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember the input's script type. Change-outputs must use the same script
|
||||||
|
// type as all inputs.
|
||||||
|
extract_input_script_type(tx_info, txinput);
|
||||||
|
|
||||||
// Remember the input's BIP-32 path. Change-outputs must use the same path
|
// Remember the input's BIP-32 path. Change-outputs must use the same path
|
||||||
// as all inputs.
|
// as all inputs.
|
||||||
extract_input_bip32_path(tx_info, txinput);
|
extract_input_bip32_path(tx_info, txinput);
|
||||||
@ -1708,31 +1763,41 @@ static bool tx_info_add_input(TxInfo *tx_info, const TxInputType *txinput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool tx_info_check_input(TxInfo *tx_info, TxInputType *tinput) {
|
static bool tx_info_check_input(TxInfo *tx_info, TxInputType *tinput) {
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
if (!tx_info->multisig_fp_mismatch) {
|
if (!tx_info->multisig_fp_mismatch) {
|
||||||
// check that this is still multisig
|
// check that this is still multisig
|
||||||
uint8_t h[32] = {0};
|
uint8_t h[32] = {0};
|
||||||
if (!tinput->has_multisig ||
|
if (!tinput->has_multisig ||
|
||||||
cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 ||
|
cryptoMultisigFingerprint(&(tinput->multisig), h) == 0 ||
|
||||||
memcmp(tx_info->multisig_fp, h, 32) != 0) {
|
memcmp(tx_info->multisig_fp, h, 32) != 0) {
|
||||||
fsm_sendFailure(FailureType_Failure_ProcessError,
|
result = false;
|
||||||
_("Transaction has changed during signing"));
|
|
||||||
signing_abort();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tx_info->in_script_type_state == MatchState_MATCH) {
|
||||||
|
// check that input script type didn't change
|
||||||
|
if (simple_script_type(tinput->script_type) != tx_info->in_script_type) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tx_info->in_address_n_count != BIP32_NOCHANGEALLOWED) {
|
if (tx_info->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 < 2 || count != tx_info->in_address_n_count ||
|
if (count < 2 || count != tx_info->in_address_n_count ||
|
||||||
0 != memcmp(tx_info->in_address_n, tinput->address_n,
|
0 != memcmp(tx_info->in_address_n, tinput->address_n,
|
||||||
(count - 2) * sizeof(uint32_t))) {
|
(count - 2) * sizeof(uint32_t))) {
|
||||||
fsm_sendFailure(FailureType_Failure_ProcessError,
|
result = false;
|
||||||
_("Transaction has changed during signing"));
|
|
||||||
signing_abort();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
if (result == false) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ProcessError,
|
||||||
|
_("Transaction has changed during signing"));
|
||||||
|
signing_abort();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tx_info_add_output(TxInfo *tx_info,
|
static bool tx_info_add_output(TxInfo *tx_info,
|
||||||
@ -2068,6 +2133,10 @@ static bool is_change_output(const TxInfo *tx_info,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_change_script_type(tx_info, txoutput)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return check_change_bip32_path(tx_info, txoutput);
|
return check_change_bip32_path(tx_info, txoutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user