def test_safety_checks(self, client): BAD_ADDRESS = parse_path("m/0") with pytest.raises(exceptions.TrezorFailure, match="Forbidden key path"), client: client.set_expected_responses([messages.Failure()]) btc.get_address(client, "Bitcoin", BAD_ADDRESS) with client: client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.Prompt) with client: client.set_expected_responses( [messages.ButtonRequest(), messages.Address()]) btc.get_address(client, "Bitcoin", BAD_ADDRESS) with client: client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.Strict) with pytest.raises(exceptions.TrezorFailure, match="Forbidden key path"), client: client.set_expected_responses([messages.Failure()]) btc.get_address(client, "Bitcoin", BAD_ADDRESS)
def test_safety_checks(self, client): def get_bad_address(): btc.get_address(client, "Bitcoin", parse_path("m/0")) assert client.features.safety_checks == messages.SafetyCheckLevel.Strict with pytest.raises( exceptions.TrezorFailure, match="Forbidden key path" ), client: client.set_expected_responses([messages.Failure()]) get_bad_address() with client: client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.PromptAlways ) assert client.features.safety_checks == messages.SafetyCheckLevel.PromptAlways with client: client.set_expected_responses( [messages.ButtonRequest(), messages.Address()] ) get_bad_address() with client: client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.Strict ) assert client.features.safety_checks == messages.SafetyCheckLevel.Strict with pytest.raises( exceptions.TrezorFailure, match="Forbidden key path" ), client: client.set_expected_responses([messages.Failure()]) get_bad_address() with client: client.set_expected_responses(EXPECTED_RESPONSES_NOPIN) device.apply_settings( client, safety_checks=messages.SafetyCheckLevel.PromptTemporarily ) assert ( client.features.safety_checks == messages.SafetyCheckLevel.PromptTemporarily ) with client: client.set_expected_responses( [messages.ButtonRequest(), messages.Address()] ) get_bad_address()
def test_nonzero_opreturn(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/0'/10'/0/5"), amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( op_return_data=b"test of the op_return data", amount=10000, script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with client: client.set_expected_responses( [request_input(0), request_output(0), proto.Failure()]) with pytest.raises(TrezorFailure, match="OP_RETURN output with non-zero amount"): btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=TX_API)
def test_attack_amount(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinCash) inp1 = proto.TxInputType( address_n=self.client.expand_path("44'/145'/0'/1/0"), # 1HADRPJpgqBzThepERpVXNi6qRgiLQRNoE amount=1896050 - 1, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) inp2 = proto.TxInputType( address_n=self.client.expand_path("44'/145'/0'/0/1"), # 1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3 amount=73452, prev_hash=unhexlify('502e8577b237b0152843a416f8f1ab0c63321b1be7a8cad7bf5c5c216fcf062c'), prev_index=1, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address='15pnEDZJo3ycPUamqP3tEDnEju1oW5fBCz', amount=1934960, script_type=proto.OutputScriptType.PAYTOADDRESS, ) global run_attack run_attack = True def attack_processor(req, msg): import sys global run_attack if req.details.tx_hash is not None: return msg if req.request_type != proto.RequestType.TXINPUT: return msg if req.details.request_index != 0: return msg if not run_attack: return msg msg.inputs[0].amount = 1896050 run_attack = False return msg with self.client: self.client.set_expected_responses([ proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(CallException): self.client.sign_tx('Bcash', [inp1, inp2], [out1], debug_processor=attack_processor)
def test_change_failed(client): assert client.features.pin_protection is True # Check current PIN value _check_pin(client, PIN4) # Let's set new PIN def input_flow(): yield # do you want to change pin? client.debug.press_yes() yield # enter current pin client.debug.input(PIN4) yield # enter new pin client.debug.input("457891") yield # enter new pin again (but different) client.debug.input("381847") # failed retry yield # enter current pin again client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses([messages.ButtonRequest()] * 5 + [messages.Failure()]) client.set_input_flow(input_flow) device.change_pin(client) # Check that there's still old PIN protection client.init_device() assert client.features.pin_protection is True _check_pin(client, PIN4)
def test_invalid_path_fail_asap(client): inp1 = messages.TxInputType( address_n=parse_path("0"), amount=4977040, prev_hash=TXHASH_a5cd2a, prev_index=0, script_type=messages.InputScriptType.SPENDWITNESS, sequence=4294967293, ) out1 = messages.TxOutputType( address_n=parse_path("84h/0h/0h/1/0"), amount=4977040, script_type=messages.OutputScriptType.PAYTOWITNESS, ) with client: client.set_expected_responses([ request_input(0), messages.Failure(code=messages.FailureType.DataError) ]) try: btc.sign_tx(client, "Testnet", [inp1], [out1], prev_txes=TX_CACHE_TESTNET) except TrezorFailure: pass
def test_set_wipe_code_mismatch(client): # Let's set a wipe code. def input_flow(): yield # do you want to set the wipe code? client.debug.press_yes() yield # enter new wipe code client.debug.input(WIPE_CODE4) yield # enter new wipe code again (but different) client.debug.input(WIPE_CODE6) # failed retry yield # enter new wipe code client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses( [messages.ButtonRequest()] * 4 + [messages.Failure()] ) client.set_input_flow(input_flow) device.change_wipe_code(client) # Check that there's still no wipe code protection now client.init_device() assert client.features.wipe_code_protection is False
def test_opreturn_address(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/0'/0'/0/2"), amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( address_n=parse_path("44'/0'/0'/1/2"), amount=0, op_return_data=b"OMNI TRANSACTION GOES HERE", script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with client: client.set_expected_responses( [request_input(0), request_output(0), proto.Failure()] ) with pytest.raises( TrezorFailure, match="Output's address_n provided but not expected." ): _, serialized_tx = btc.sign_tx( client, "Bitcoin", [inp1], [out1], prev_txes=TX_API )
def test_not_enough_funds(self, client): # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882 # input 0: 0.0039 BTC inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e # amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", amount=400000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) trezor_core = client.features.model != "1" with client: client.set_expected_responses([ request_input(0), (trezor_core, proto.ButtonRequest(code=B.UnknownDerivationPath)), request_meta(TXHASH_d5f65e), request_input(0, TXHASH_d5f65e), request_input(1, TXHASH_d5f65e), request_output(0, TXHASH_d5f65e), request_output(0), proto.ButtonRequest(code=B.ConfirmOutput), proto.Failure(code=proto.FailureType.NotEnoughFunds), ]) with pytest.raises(TrezorFailure, match="NotEnoughFunds"): btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=TX_CACHE_MAINNET)
def test_not_enough_funds(self, client): # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882 # input 0: 0.0039 BTC inp1 = messages.TxInputType( address_n=parse_path("44h/0h/0h/0/0"), # amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = messages.TxOutputType( address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1", amount=400000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) with client: client.set_expected_responses([ request_input(0), request_meta(TXHASH_d5f65e), request_input(0, TXHASH_d5f65e), request_input(1, TXHASH_d5f65e), request_output(0, TXHASH_d5f65e), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), messages.Failure(code=messages.FailureType.NotEnoughFunds), ]) with pytest.raises(TrezorFailure, match="NotEnoughFunds"): btc.sign_tx(client, "Bitcoin", [inp1], [out1], prev_txes=TX_CACHE_MAINNET)
def test_invalid_path_fail_asap(client: Client): inp1 = messages.TxInputType( address_n=parse_path("m/0"), amount=1_000_000, prev_hash=b"\x42" * 32, prev_index=0, script_type=messages.InputScriptType.SPENDWITNESS, sequence=4_294_967_293, ) out1 = messages.TxOutputType( address_n=parse_path("m/84h/0h/0h/1/0"), amount=1_000_000, script_type=messages.OutputScriptType.PAYTOWITNESS, ) with client: client.set_expected_responses([ request_input(0), messages.Failure(code=messages.FailureType.DataError), ]) try: btc.sign_tx(client, "Testnet", [inp1], [out1]) except TrezorFailure: pass
def test_set_failed(client): assert client.features.pin_protection is False # Check that there's no PIN protection _check_no_pin(client) # Let's set new PIN def input_flow(): yield # do you want to set pin? client.debug.press_yes() yield # enter new pin client.debug.input(PIN4) yield # enter new pin again (but different) client.debug.input(PIN6) # failed retry yield # enter new pin client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses([messages.ButtonRequest()] * 4 + [messages.Failure()]) client.set_input_flow(input_flow) device.change_pin(client) # Check that there's still no PIN protection now client.init_device() assert client.features.pin_protection is False _check_no_pin(client)
def test_cardano_sign_tx_failed(client, parameters, result): inputs = [cardano.create_input(i) for i in parameters["inputs"]] outputs = [cardano.create_output(o) for o in parameters["outputs"]] certificates = [ cardano.create_certificate(c) for c in parameters["certificates"] ] withdrawals = [ cardano.create_withdrawal(w) for w in parameters["withdrawals"] ] expected_responses = [messages.PassphraseRequest(), messages.Failure()] with client: client.set_expected_responses(expected_responses) with pytest.raises(TrezorFailure, match=result["error_message"]): cardano.sign_tx( client=client, inputs=inputs, outputs=outputs, fee=parameters["fee"], ttl=parameters["ttl"], certificates=certificates, withdrawals=withdrawals, metadata=bytes.fromhex(parameters["metadata"]), protocol_magic=parameters["protocol_magic"], network_id=parameters["network_id"], )
def test_p2wpkh_with_false_proof(client: Client): inp1 = messages.TxInputType( # tb1qkvwu9g3k2pdxewfqr7syz89r3gj557l3uuf9r9 address_n=parse_path("m/84h/1h/0h/0/0"), prev_hash=TXHASH_70f987, prev_index=0, amount=100_000, script_type=messages.InputScriptType.SPENDWITNESS, ) inp2 = messages.TxInputType( # tb1qldlynaqp0hy4zc2aag3pkenzvxy65saesxw3wd # address_n=parse_path("m/84h/1h/0h/0/1"), prev_hash=TXHASH_65b768, prev_index=0, amount=10_000, script_type=messages.InputScriptType.EXTERNAL, script_pubkey=bytes.fromhex("0014fb7e49f4017dc951615dea221b66626189aa43b9"), ownership_proof=bytes.fromhex( "534c00190001b0b66657a824e41c063299fb4435dc70a6fd2e9db4c87e3c26a7ab7c0283547b000247304402206e285291aa955cb60b16acd69332eaada67ec5192d361fe4e2b384553e7e80c6022023470cfcb9c3251a136c26eb1637142206785a3d91b98583e5a1d6ab64fa91ed012103dcf3bc936ecb2ec57b8f468050abce8c8756e75fd74273c9977744b1a0be7d03" ), ) out1 = messages.TxOutputType( address="tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2", amount=50_000, script_type=messages.OutputScriptType.PAYTOWITNESS, ) with client: client.set_expected_responses( [ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_70f987), request_input(0, TXHASH_70f987), request_output(0, TXHASH_70f987), request_output(1, TXHASH_70f987), request_input(1), request_meta(TXHASH_65b768), request_input(0, TXHASH_65b768), request_output(0, TXHASH_65b768), request_output(1, TXHASH_65b768), messages.Failure(code=messages.FailureType.DataError), ] ) with pytest.raises(TrezorFailure, match="Invalid external input"): btc.sign_tx( client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_CACHE_TESTNET, )
def test_nonzero_opreturn(self): self.setup_mnemonic_allallall() inp1 = proto.TxInputType( address_n=parse_path("44'/0'/10'/0/5"), prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( op_return_data=b"test of the op_return data", amount=10000, script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=1, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0, tx_hash=TXHASH_d5f65e), ), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0), ), proto.Failure(), ]) with pytest.raises(CallException) as exc: btc.sign_tx(self.client, "Bitcoin", [inp1], [out1], prev_txes=TX_API) if TREZOR_VERSION == 1: assert exc.value.args[0] == proto.FailureType.ProcessError assert exc.value.args[1].endswith("Failed to compile output") else: assert exc.value.args[0] == proto.FailureType.DataError assert exc.value.args[1].endswith( "OP_RETURN output with non-zero amount")
def test_p2wpkh_with_false_proof(client): inp1 = messages.TxInputType( # tb1qkvwu9g3k2pdxewfqr7syz89r3gj557l3uuf9r9 address_n=parse_path("m/84h/1h/0h/0/0"), prev_hash=TXHASH_70f987, prev_index=0, amount=100000, script_type=messages.InputScriptType.SPENDWITNESS, ) inp2 = messages.TxInputType( # tb1qldlynaqp0hy4zc2aag3pkenzvxy65saesxw3wd # address_n=parse_path("m/84h/1h/0h/0/1"), prev_hash=TXHASH_65b768, prev_index=0, amount=10000, script_type=messages.InputScriptType.EXTERNAL, script_pubkey=bytes.fromhex( "0014fb7e49f4017dc951615dea221b66626189aa43b9"), ownership_proof=bytes.fromhex( "534c00190001b0b66657a824e41c063299fb4435dc70a6fd2e9db4c87e3c26a7ab7c0283547b0002473044022060bf60380142ed54fa907c82cb5ab438bfec22ebf8b5a92971fe104b7e3dd41002206f3fc4ac2f9c1a4a12255b5f678b6e57a088816051faea5a65a66951b394c150012103dcf3bc936ecb2ec57b8f468050abce8c8756e75fd74273c9977744b1a0be7d03" ), ) out1 = messages.TxOutputType( address="tb1qnspxpr2xj9s2jt6qlhuvdnxw6q55jvygcf89r2", amount=50000, script_type=messages.OutputScriptType.PAYTOWITNESS, ) with client: client.set_expected_responses([ request_input(0), request_input(1), request_output(0), messages.ButtonRequest(code=B.ConfirmOutput), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_70f987), request_input(0, TXHASH_70f987), request_output(0, TXHASH_70f987), request_output(1, TXHASH_70f987), request_input(1), request_meta(TXHASH_65b768), request_input(0, TXHASH_65b768), request_output(0, TXHASH_65b768), request_output(1, TXHASH_65b768), messages.Failure(code=messages.FailureType.DataError), ]) with pytest.raises(TrezorFailure, match="Invalid external input"): btc.sign_tx( client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_CACHE_TESTNET, )
def test_cancel_message_via_cancel(client, message): def input_flow(): yield client.cancel() with client, pytest.raises(Cancelled): client.set_expected_responses([m.ButtonRequest(), m.Failure()]) client.set_input_flow(input_flow) client.call(message)
def _check_wipe_code(client, pin, wipe_code): client.init_device() assert client.features.wipe_code_protection is True # Try to change the PIN to the current wipe code value. The operation should fail. with client, pytest.raises(TrezorFailure): client.use_pin_sequence([pin, wipe_code, wipe_code]) client.set_expected_responses( [messages.ButtonRequest()] * 5 + [messages.Failure(code=messages.FailureType.PinInvalid)]) device.change_pin(client)
def test_attack_change_input(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinGold) inp1 = proto.TxInputType( address_n=self.client.expand_path("44'/156'/1000'/0/0"), # 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q amount=1995344, prev_hash=unhexlify('25526bf06c76ad3082bba930cf627cdd5f1b3cd0b9907dd7ff1a07e14addc985'), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=self.client.expand_path("44'/156'/1000'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address='GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe', amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) global attack_ctr attack_ctr = 0 def attack_processor(req, msg): import sys global attack_ctr if req.details.tx_hash is not None: return msg if req.request_type != proto.RequestType.TXINPUT: return msg attack_ctr += 1 if attack_ctr <= 1: return msg msg.inputs[0].address_n[2] = 1 + 0x80000000 return msg with self.client: self.client.set_expected_responses([ proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1)), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(CallException): self.client.sign_tx('Bitcoin Gold', [inp1], [out1, out2], debug_processor=attack_processor)
def test_attack_change_input(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBitcoinCash) inp1 = proto.TxInputType( address_n=self.client.expand_path("44'/145'/1000'/0/0"), # 1MH9KKcvdCTY44xVDC2k3fjBbX5Cz29N1q amount=1995344, prev_hash=unhexlify('bc37c28dfb467d2ecb50261387bf752a3977d7e5337915071bb4151e6b711a78'), prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=self.client.expand_path("44'/145'/1000'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address='1LRspCZNFJcbuNKQkXgHMDucctFRQya5a3', amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) global attack_ctr attack_ctr = 0 def attack_processor(req, msg): import sys global attack_ctr if req.details.tx_hash is not None: return msg if req.request_type != proto.RequestType.TXINPUT: return msg attack_ctr += 1 if attack_ctr <= 1: return msg msg.inputs[0].address_n[2] = 1 + 0x80000000 return msg with self.client: self.client.set_expected_responses([ proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=1)), proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput), proto.ButtonRequest(code=proto.ButtonRequestType.SignTx), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(CallException): self.client.sign_tx('Bcash', [inp1], [out1, out2], debug_processor=attack_processor)
def test_attack_change_input(client: Client): # NOTE: fake input tx used inp1 = messages.TxInputType( address_n=parse_path("m/44h/156h/0h/0/0"), amount=1_252_382_934, prev_hash=FAKE_TXHASH_6f0398, prev_index=0, script_type=messages.InputScriptType.SPENDADDRESS, ) out1 = messages.TxOutputType( address_n=parse_path("m/44h/156h/0h/1/0"), amount=1_896_050, script_type=messages.OutputScriptType.PAYTOADDRESS, ) out2 = messages.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1_252_382_934 - 1_896_050 - 1_000, script_type=messages.OutputScriptType.PAYTOADDRESS, ) attack_count = 2 def attack_processor(msg): nonlocal attack_count if msg.tx.inputs and msg.tx.inputs[0] == inp1: if attack_count > 0: attack_count -= 1 else: msg.tx.inputs[0].address_n[2] = H_(1) return msg with client: client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses([ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_6f0398), request_input(0, FAKE_TXHASH_6f0398), request_output(0, FAKE_TXHASH_6f0398), request_output(1, FAKE_TXHASH_6f0398), request_input(0), messages.Failure(code=messages.FailureType.ProcessError), ]) with pytest.raises(TrezorFailure): btc.sign_tx(client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API)
def test_apply_auto_lock_delay_out_of_range(client, seconds): with client: client.use_pin_sequence([PIN4]) client.set_expected_responses([ pin_request(client), messages.Failure(code=messages.FailureType.ProcessError), ]) delay = seconds * 1000 with pytest.raises(TrezorFailure): device.apply_settings(client, auto_lock_delay_ms=delay)
def test_attack_change_input(client: Client): # NOTE: fake input tx used inp1 = messages.TxInputType( address_n=parse_path("m/44h/145h/10h/0/0"), amount=1_995_344, prev_hash=FAKE_TXHASH_bd32ff, prev_index=0, script_type=messages.InputScriptType.SPENDADDRESS, ) out1 = messages.TxOutputType( address_n=parse_path("m/44h/145h/10h/1/0"), amount=1_896_050, script_type=messages.OutputScriptType.PAYTOADDRESS, ) out2 = messages.TxOutputType( address="bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4", amount=73_452, script_type=messages.OutputScriptType.PAYTOADDRESS, ) attack_count = 2 def attack_processor(msg): nonlocal attack_count if msg.tx.inputs and msg.tx.inputs[0] == inp1: if attack_count > 0: attack_count -= 1 else: msg.tx.inputs[0].address_n[2] = H_(1) return msg with client: client.set_filter(messages.TxAck, attack_processor) client.set_expected_responses([ request_input(0), request_output(0), request_output(1), messages.ButtonRequest(code=B.ConfirmOutput), messages.ButtonRequest(code=B.SignTx), request_input(0), request_meta(FAKE_TXHASH_bd32ff), request_input(0, FAKE_TXHASH_bd32ff), request_output(0, FAKE_TXHASH_bd32ff), request_input(0), messages.Failure(code=messages.FailureType.ProcessError), ]) with pytest.raises(TrezorFailure): btc.sign_tx(client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API)
def _check_wipe_code(client, pin, wipe_code): client.clear_session() assert client.features.wipe_code_protection is True # Try to change the PIN to the current wipe code value. The operation should fail. with client, pytest.raises(TrezorFailure): client.set_expected_responses( [messages.ButtonRequest()] * 5 + [messages.Failure(code=messages.FailureType.PinInvalid)] ) client.set_input_flow(_input_flow_change_pin(client.debug, pin, wipe_code)) device.change_pin(client)
def test_attack_change_input(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/156'/11'/0/0"), amount=1252382934, prev_hash=TXHASH_25526b, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/156'/11'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe", amount=1252382934 - 1896050 - 1000, script_type=proto.OutputScriptType.PAYTOADDRESS, ) attack_count = 2 def attack_processor(msg): nonlocal attack_count if msg.tx.inputs and msg.tx.inputs[0] == inp1: if attack_count > 0: attack_count -= 1 else: msg.tx.inputs[0].address_n[2] = H_(1) return msg client.set_filter(proto.TxAck, attack_processor) with client: client.set_expected_responses([ request_input(0), request_output(0), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_25526b), request_input(0, TXHASH_25526b), request_output(0, TXHASH_25526b), request_output(1, TXHASH_25526b), request_input(0), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(TrezorFailure): btc.sign_tx(client, "Bgold", [inp1], [out1, out2], prev_txes=TX_API)
def test_attack_change_input(self, client): inp1 = proto.TxInputType( address_n=parse_path("44'/145'/10'/0/0"), amount=1995344, prev_hash=TXHASH_bc37c2, prev_index=0, script_type=proto.InputScriptType.SPENDADDRESS, ) out1 = proto.TxOutputType( address_n=parse_path("44'/145'/10'/1/0"), amount=1896050, script_type=proto.OutputScriptType.PAYTOADDRESS, ) out2 = proto.TxOutputType( address="bitcoincash:qr23ajjfd9wd73l87j642puf8cad20lfmqdgwvpat4", amount=73452, script_type=proto.OutputScriptType.PAYTOADDRESS, ) attack_count = 2 def attack_processor(msg): nonlocal attack_count if msg.tx.inputs and msg.tx.inputs[0] == inp1: if attack_count > 0: attack_count -= 1 else: msg.tx.inputs[0].address_n[2] = H_(1) return msg client.set_filter(proto.TxAck, attack_processor) with client: client.set_expected_responses([ request_input(0), request_output(0), request_output(1), proto.ButtonRequest(code=B.ConfirmOutput), proto.ButtonRequest(code=B.SignTx), request_input(0), request_meta(TXHASH_bc37c2), request_input(0, TXHASH_bc37c2), request_output(0, TXHASH_bc37c2), request_input(0), proto.Failure(code=proto.FailureType.ProcessError), ]) with pytest.raises(TrezorFailure): btc.sign_tx(client, "Bcash", [inp1], [out1, out2], prev_txes=TX_API)
def test_nonzero_opreturn(self): self.setup_mnemonic_nopin_nopassphrase() # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882 # input 0: 0.0039 BTC inp1 = proto.TxInputType( address_n=[0], # 14LmW5k4ssUrtbAB4255zdqv3b4w1TuX9e # amount=390000, prev_hash=TXHASH_d5f65e, prev_index=0, ) out1 = proto.TxOutputType( op_return_data=b'test of the op_return data', amount=10000, script_type=proto.OutputScriptType.PAYTOOPRETURN, ) with self.client: self.client.set_expected_responses([ proto.TxRequest( request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.TxRequest( request_type=proto.RequestType.TXMETA, details=proto.TxRequestDetailsType(tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXINPUT, details=proto.TxRequestDetailsType( request_index=1, tx_hash=TXHASH_d5f65e)), proto.TxRequest(request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType( request_index=0, tx_hash=TXHASH_d5f65e)), proto.TxRequest( request_type=proto.RequestType.TXOUTPUT, details=proto.TxRequestDetailsType(request_index=0)), proto.Failure() ]) with pytest.raises(CallException) as exc: self.client.sign_tx('Bitcoin', [inp1], [out1]) if TREZOR_VERSION == 1: assert exc.value.args[0] == proto.FailureType.ProcessError assert exc.value.args[1].endswith("Failed to compile output") else: assert exc.value.args[0] == proto.FailureType.DataError assert exc.value.args[1].endswith( 'OP_RETURN output with non-zero amount')
def test_set_pin_to_wipe_code(client): # Set wipe code. with client: client.set_expected_responses([messages.ButtonRequest()] * 4 + [messages.Success, messages.Features]) client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4]) device.change_wipe_code(client) # Try to set the PIN to the current wipe code value. with client, pytest.raises(TrezorFailure): client.set_expected_responses( [messages.ButtonRequest()] * 4 + [messages.Failure(code=messages.FailureType.PinInvalid)]) client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4]) device.change_pin(client)
def test_cardano_sign_tx_validation(client, protocol_magic, inputs, outputs, transactions, expected_error_message): inputs = [cardano.create_input(i) for i in inputs] outputs = [cardano.create_output(o) for o in outputs] expected_responses = [ messages.CardanoTxRequest(tx_index=i) for i in range(len(transactions)) ] expected_responses += [messages.Failure()] with client: client.set_expected_responses(expected_responses) with pytest.raises(TrezorFailure, match=expected_error_message): cardano.sign_tx(client, inputs, outputs, transactions, protocol_magic)
def test_set_pin_to_wipe_code(client): # Set wipe code. with client: client.set_expected_responses( [messages.ButtonRequest()] * 4 + [messages.Success(), messages.Features()] ) client.set_input_flow(_input_flow_set_wipe_code(client.debug, None, WIPE_CODE4)) device.change_wipe_code(client) # Try to set the PIN to the current wipe code value. with client, pytest.raises(TrezorFailure): client.set_expected_responses( [messages.ButtonRequest()] * 4 + [messages.Failure(code=messages.FailureType.PinInvalid)] ) client.set_input_flow(_input_flow_set_pin(client.debug, WIPE_CODE4)) device.change_pin(client)