mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
feat(tests): Test SegWit cross-coin attack.
This commit is contained in:
parent
9052133fca
commit
de6fab3c1e
@ -18,10 +18,12 @@ import pytest
|
||||
|
||||
from trezorlib import btc, device, messages as proto
|
||||
from trezorlib.exceptions import TrezorFailure
|
||||
from trezorlib.tools import parse_path
|
||||
from trezorlib.tools import H_, parse_path
|
||||
|
||||
from ..tx_cache import TxCache
|
||||
from .signtx import request_finished, request_input, request_meta, request_output
|
||||
|
||||
B = proto.ButtonRequestType
|
||||
TX_CACHE_MAINNET = TxCache("Bitcoin")
|
||||
TX_CACHE_BCASH = TxCache("Bcash")
|
||||
|
||||
@ -31,6 +33,12 @@ TXHASH_8cc1f4 = bytes.fromhex(
|
||||
TXHASH_d5f65e = bytes.fromhex(
|
||||
"d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882"
|
||||
)
|
||||
TXHASH_fa80a9 = bytes.fromhex(
|
||||
"fa80a9949f1094119195064462f54d0e0eabd3139becd4514ae635b8c7fe3a46"
|
||||
)
|
||||
TXHASH_5dfd1b = bytes.fromhex(
|
||||
"5dfd1b037633adc7f84a17b2df31c9994fe50b3ab3e246c44c4ceff3d326f62e"
|
||||
)
|
||||
|
||||
|
||||
class TestMsgSigntxInvalidPath:
|
||||
@ -117,3 +125,94 @@ class TestMsgSigntxInvalidPath:
|
||||
)
|
||||
|
||||
btc.sign_tx(client, "Bcash", [inp1], [out1], prev_txes=TX_CACHE_BCASH)
|
||||
|
||||
def test_attack_path_segwit(self, client):
|
||||
# Scenario: The attacker falsely claims that the transaction uses Testnet paths to
|
||||
# avoid the path warning dialog, but in step6_sign_segwit_inputs() uses Bitcoin paths
|
||||
# to get a valid signature.
|
||||
|
||||
device.apply_settings(
|
||||
client, safety_checks=proto.SafetyCheckLevel.PromptTemporarily
|
||||
)
|
||||
|
||||
inp1 = proto.TxInputType(
|
||||
# The actual input that the attcker wants to get signed.
|
||||
address_n=parse_path("84'/0'/0'/0/0"),
|
||||
amount=9426,
|
||||
prev_hash=TXHASH_fa80a9,
|
||||
prev_index=0,
|
||||
script_type=proto.InputScriptType.SPENDWITNESS,
|
||||
)
|
||||
inp2 = proto.TxInputType(
|
||||
# The actual input that the attcker wants to get signed.
|
||||
# We need this one to be from a different account, so that the match checker
|
||||
# allows the transaction to pass.
|
||||
address_n=parse_path("84'/0'/1'/0/1"),
|
||||
amount=7086,
|
||||
prev_hash=TXHASH_5dfd1b,
|
||||
prev_index=0,
|
||||
script_type=proto.InputScriptType.SPENDWITNESS,
|
||||
)
|
||||
|
||||
out1 = proto.TxOutputType(
|
||||
# Attacker's Mainnet address encoded as Testnet.
|
||||
address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu",
|
||||
script_type=proto.OutputScriptType.PAYTOADDRESS,
|
||||
amount=9426 + 7086 - 500,
|
||||
)
|
||||
|
||||
attack_count = 6
|
||||
|
||||
def attack_processor(msg):
|
||||
nonlocal attack_count
|
||||
# Make the inputs look like they are coming from Testnet paths until we reach the
|
||||
# signing phase.
|
||||
if attack_count > 0 and msg.tx.inputs and msg.tx.inputs[0] in (inp1, inp2):
|
||||
attack_count -= 1
|
||||
msg.tx.inputs[0].address_n[1] = H_(1)
|
||||
|
||||
return msg
|
||||
|
||||
with client:
|
||||
client.set_filter(proto.TxAck, attack_processor)
|
||||
client.set_expected_responses(
|
||||
[
|
||||
# Step: process inputs
|
||||
request_input(0),
|
||||
# Attacker bypasses warning about non-standard path.
|
||||
request_input(1),
|
||||
# Attacker bypasses warning about non-standard path.
|
||||
# Step: approve outputs
|
||||
request_output(0),
|
||||
proto.ButtonRequest(code=B.ConfirmOutput),
|
||||
proto.ButtonRequest(code=B.SignTx),
|
||||
# Step: verify inputs
|
||||
request_input(0),
|
||||
request_meta(TXHASH_fa80a9),
|
||||
request_input(0, TXHASH_fa80a9),
|
||||
request_output(0, TXHASH_fa80a9),
|
||||
request_output(1, TXHASH_fa80a9),
|
||||
request_input(1),
|
||||
request_meta(TXHASH_5dfd1b),
|
||||
request_input(0, TXHASH_5dfd1b),
|
||||
request_output(0, TXHASH_5dfd1b),
|
||||
request_output(1, TXHASH_5dfd1b),
|
||||
# Step: serialize inputs
|
||||
request_input(0),
|
||||
request_input(1),
|
||||
# Step: serialize outputs
|
||||
request_output(0),
|
||||
# Step: sign segwit inputs
|
||||
request_input(0),
|
||||
# Trezor must warn about non-standard path before signing.
|
||||
proto.ButtonRequest(code=B.UnknownDerivationPath),
|
||||
request_input(1),
|
||||
# Trezor must warn about non-standard path before signing.
|
||||
proto.ButtonRequest(code=B.UnknownDerivationPath),
|
||||
request_finished(),
|
||||
]
|
||||
)
|
||||
|
||||
btc.sign_tx(
|
||||
client, "Testnet", [inp1, inp2], [out1], prev_txes=TX_CACHE_MAINNET
|
||||
)
|
||||
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"bin_outputs": [
|
||||
{
|
||||
"amount": 7086,
|
||||
"script_pubkey": "0014f6740e521befc61400662d9489a5f744883ca681"
|
||||
},
|
||||
{
|
||||
"amount": 20120,
|
||||
"script_pubkey": "001404278d66e85ad1073d6f7a8eeee8b96ca633e6e8"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"prev_hash": "939cda2b4b609be5f5772dea5885431e18a61834bcbe5e0f895d6dfa05d2cc70",
|
||||
"prev_index": 0,
|
||||
"script_sig": "",
|
||||
"sequence": 4294967293
|
||||
}
|
||||
],
|
||||
"lock_time": 0,
|
||||
"version": 1
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"bin_outputs": [
|
||||
{
|
||||
"amount": 9426,
|
||||
"script_pubkey": "0014ece6935b2a5a5b5ff997c87370b16fa10f164410"
|
||||
},
|
||||
{
|
||||
"amount": 309896,
|
||||
"script_pubkey": "a914dfe58cc93d35fb99e15436f47d3bbfce8203280687"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"prev_hash": "86a6e02943dcd057cfbe349f2c2274478a3a1be908eb788606a6950e727a0d36",
|
||||
"prev_index": 0,
|
||||
"script_sig": "16001495f41f5c0e0ec2c7fe27f0ac4bd59a5632a40b5f",
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"lock_time": 0,
|
||||
"version": 1
|
||||
}
|
@ -661,6 +661,7 @@
|
||||
"test_msg_signtx_grs.py-test_send_segwit_native_change": "fd8b04e26d71fad1c59f5e548c35f22f2031cfb99f9077824242e264fcbedfe6",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_p2sh": "e59018de5c49f902c6880c2347283b6c1830fcb19e8eab9686938a08abd930b3",
|
||||
"test_msg_signtx_grs.py-test_send_segwit_p2sh_change": "08251e3b7e509264dbd89a5ded2deba51544d0fcfce1dc7466b553b73298d423",
|
||||
"test_msg_signtx_invalid_path.py-test_attack_path_segwit": "3feaa01d47aa9757e9d74f668927fd1445493c367adff94215405eb8e0a2749b",
|
||||
"test_msg_signtx_invalid_path.py-test_invalid_path_fail": "1c100ce4b7c1e47e72428f390de0846c1ff933e9f07894872644a369a9422738",
|
||||
"test_msg_signtx_invalid_path.py-test_invalid_path_pass_forkid": "ef98eb752ec5fa948c952def7599f57a2bc5240b2d6b1eec0e02cc9be5c3040f",
|
||||
"test_msg_signtx_invalid_path.py-test_invalid_path_prompt": "12e137210397357ed754af0f4618ef03312b3e884930f55727d1b034f969bfd5",
|
||||
|
Loading…
Reference in New Issue
Block a user