mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-30 19:38:15 +00:00
feat(legacy): forbid multisig to singlesig change outputs
This commit is contained in:
parent
93e3fd925b
commit
f3c85e7ec7
@ -124,6 +124,9 @@ typedef struct {
|
|||||||
bool multisig_fp_set;
|
bool multisig_fp_set;
|
||||||
bool multisig_fp_mismatch;
|
bool multisig_fp_mismatch;
|
||||||
uint8_t multisig_fp[32];
|
uint8_t multisig_fp[32];
|
||||||
|
bool multisig;
|
||||||
|
bool multisig_set;
|
||||||
|
bool multisig_mismatch;
|
||||||
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;
|
InputScriptType in_script_type;
|
||||||
@ -978,6 +981,22 @@ static bool extract_input_multisig_fp(TxInfo *tx_info,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void extract_multisig(TxInfo *tx_info, const TxInputType *txinput) {
|
||||||
|
if (tx_info->multisig_mismatch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tx_info->multisig_set) {
|
||||||
|
tx_info->multisig = txinput->has_multisig;
|
||||||
|
tx_info->multisig_set = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txinput->has_multisig != tx_info->multisig) {
|
||||||
|
tx_info->multisig_mismatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool check_change_multisig_fp(const TxInfo *tx_info,
|
bool check_change_multisig_fp(const TxInfo *tx_info,
|
||||||
const TxOutputType *txoutput) {
|
const TxOutputType *txoutput) {
|
||||||
uint8_t h[32] = {0};
|
uint8_t h[32] = {0};
|
||||||
@ -986,6 +1005,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_change_multisig(const TxInfo *tx_info,
|
||||||
|
const TxOutputType *txoutput) {
|
||||||
|
return tx_info->multisig_set && !tx_info->multisig_mismatch &&
|
||||||
|
txoutput->has_multisig == tx_info->multisig;
|
||||||
|
}
|
||||||
|
|
||||||
static InputScriptType simple_script_type(InputScriptType script_type) {
|
static InputScriptType simple_script_type(InputScriptType script_type) {
|
||||||
// SPENDMULTISIG is used only for non-SegWit and is effectively the same as
|
// SPENDMULTISIG is used only for non-SegWit and is effectively the same as
|
||||||
// SPENDADDRESS. For SegWit inputs and outputs multisig is indicated by the
|
// SPENDADDRESS. For SegWit inputs and outputs multisig is indicated by the
|
||||||
@ -1245,6 +1270,8 @@ static bool tx_info_init(TxInfo *tx_info, uint32_t inputs_count,
|
|||||||
tx_info->min_sequence = SEQUENCE_FINAL;
|
tx_info->min_sequence = SEQUENCE_FINAL;
|
||||||
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->multisig_set = false;
|
||||||
|
tx_info->multisig_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 = 0;
|
||||||
tx_info->in_script_type_state = MatchState_UNDEFINED;
|
tx_info->in_script_type_state = MatchState_UNDEFINED;
|
||||||
@ -1711,6 +1738,10 @@ static bool tx_info_add_input(TxInfo *tx_info, const TxInputType *txinput) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remember whether all inputs are singlesig or all inputs are multisig.
|
||||||
|
// Change-outputs must be of the same type.
|
||||||
|
extract_multisig(tx_info, txinput);
|
||||||
|
|
||||||
// Remember the input's script type. Change-outputs must use the same script
|
// Remember the input's script type. Change-outputs must use the same script
|
||||||
// type as all inputs.
|
// type as all inputs.
|
||||||
extract_input_script_type(tx_info, txinput);
|
extract_input_script_type(tx_info, txinput);
|
||||||
@ -2069,18 +2100,14 @@ static bool is_change_output(const TxInfo *tx_info,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check the multisig fingerprint only for multisig outputs. This means that
|
|
||||||
* a transfer from a multisig account to a singlesig account is treated as a
|
|
||||||
* change-output as long as all other change-output conditions are satisfied.
|
|
||||||
* This goes a bit against the concept of a multisig account, but the other
|
|
||||||
* cosigners will notice that they are relinquishing control of the funds, so
|
|
||||||
* there is no security risk.
|
|
||||||
*/
|
|
||||||
if (txoutput->has_multisig && !check_change_multisig_fp(tx_info, txoutput)) {
|
if (txoutput->has_multisig && !check_change_multisig_fp(tx_info, txoutput)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_change_multisig(tx_info, txoutput)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!check_change_script_type(tx_info, txoutput)) {
|
if (!check_change_script_type(tx_info, txoutput)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,7 @@ def test_external_internal(client: Client):
|
|||||||
client,
|
client,
|
||||||
INP1,
|
INP1,
|
||||||
INP2,
|
INP2,
|
||||||
change_indices=[] if is_core(client) else [2],
|
change_indices=[],
|
||||||
foreign_indices=[2],
|
foreign_indices=[2],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -262,7 +262,7 @@ def test_internal_external(client: Client):
|
|||||||
client,
|
client,
|
||||||
INP1,
|
INP1,
|
||||||
INP2,
|
INP2,
|
||||||
change_indices=[] if is_core(client) else [1],
|
change_indices=[],
|
||||||
foreign_indices=[1],
|
foreign_indices=[1],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user