diff --git a/legacy/firmware/layout2.c b/legacy/firmware/layout2.c index 3c75f9784..ff1d68d50 100644 --- a/legacy/firmware/layout2.c +++ b/legacy/firmware/layout2.c @@ -598,6 +598,13 @@ void layoutChangeCountOverThreshold(uint32_t change_count) { _("Continue?"), NULL); } +void layoutConfirmUnverifiedExternalInputs(void) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Warning!"), _("The transaction"), + _("contains unverified"), _("external inputs."), + _("Continue?"), NULL); +} + void layoutConfirmNondefaultLockTime(uint32_t lock_time, bool lock_time_disabled) { if (lock_time_disabled) { diff --git a/legacy/firmware/layout2.h b/legacy/firmware/layout2.h index 428d72562..ede148617 100644 --- a/legacy/firmware/layout2.h +++ b/legacy/firmware/layout2.h @@ -68,6 +68,7 @@ void layoutConfirmModifyFee(const CoinInfo *coin, AmountUnit amount_unit, void layoutFeeOverThreshold(const CoinInfo *coin, AmountUnit amount_unit, uint64_t fee); void layoutChangeCountOverThreshold(uint32_t change_count); +void layoutConfirmUnverifiedExternalInputs(void); void layoutConfirmNondefaultLockTime(uint32_t lock_time, bool lock_time_disabled); void layoutVerifyAddress(const CoinInfo *coin, const char *address); diff --git a/legacy/firmware/signing.c b/legacy/firmware/signing.c index 817a9fbd6..c68bb2faf 100644 --- a/legacy/firmware/signing.c +++ b/legacy/firmware/signing.c @@ -341,6 +341,14 @@ static bool is_external_input(uint32_t i) { return external_inputs[i / 32] & (1 << (i % 32)); } +static bool has_external_input(void) { + uint32_t sum = 0; + for (size_t i = 0; i < sizeof(external_inputs) / sizeof(uint32_t); ++i) { + sum |= external_inputs[i]; + } + return sum != 0; +} + void send_req_1_input(void) { signing_stage = STAGE_REQUEST_1_INPUT; resp.has_request_type = true; @@ -1803,6 +1811,15 @@ static bool signing_add_orig_output(TxOutputType *orig_output) { } static bool signing_confirm_tx(void) { + if (has_external_input()) { + layoutConfirmUnverifiedExternalInputs(); + if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + signing_abort(); + return false; + } + } + if (coin->negative_fee) { // bypass check for negative fee coins, required for reward TX } else { diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index e06b72b3e..14d664012 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -249,8 +249,8 @@ "T1_bitcoin-test_signtx_amount_unit.py::test_signtx[AmountUnit.MILLIBITCOIN]": "8081910bd937c704fb65226dc85e8fc58a7331102aa036a5a97652638a0bde20", "T1_bitcoin-test_signtx_amount_unit.py::test_signtx[AmountUnit.SATOSHI]": "a565b50e63776aad284c42c71bf53e5844dff12f159cbd00679b97d2fb74fd20", "T1_bitcoin-test_signtx_amount_unit.py::test_signtx[None]": "367fd3c75f30f7224435e3309562d210d9ac6809ce2fae392f7fe75070fda094", -"T1_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "9640b4d0bdcde8fec8a4c077e1d12da211d02989458ad34115731237b3dad4f9", -"T1_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "c478ef5c111b38c0fee1f79df1e0d00ecd5c0e81913e59051047cb0db65ece69", +"T1_bitcoin-test_signtx_external.py::test_p2tr_external_unverified": "e09b404a39a4594f1b7bdc146bc6b8783f62f6c4568785f1ee8e1eae2d902c65", +"T1_bitcoin-test_signtx_external.py::test_p2wpkh_external_unverified": "3502ca6c3112b694161713d573a5547d3801894a990c108096900b95f689a734", "T1_bitcoin-test_signtx_invalid_path.py::test_attack_path_segwit": "473636ae4c43d8a349db09187b74eb4c1aa2b7fe02742d5fa928cdbc2a9e4cfd", "T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1_bitcoin-test_signtx_invalid_path.py::test_invalid_path_fail_asap": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",