1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 20:38:10 +00:00

fix(core): Stricter Bitcoin transaction checks.

This commit is contained in:
Andrew Kozlik 2022-03-11 12:26:05 +01:00 committed by Martin Milata
parent 181fd1c601
commit b1c6b42201
4 changed files with 19 additions and 9 deletions

View File

@ -0,0 +1 @@
Fix a coin loss vulnerability related to replacement transactions with multisig inputs and unverified external inputs.

View File

@ -153,8 +153,11 @@ class OriginalTxInfo(TxInfoBase):
super().add_input(txi, script_pubkey) super().add_input(txi, script_pubkey)
writers.write_tx_input(self.h_tx, txi, txi.script_sig or bytes()) writers.write_tx_input(self.h_tx, txi, txi.script_sig or bytes())
# For verification use the first original input that specifies address_n. # For verification use the first original non-multisig input that specifies address_n.
if not self.verification_input and txi.address_n: # NOTE: Supporting replacement transactions where all internal inputs are multisig would
# require checking the signatures of all of the original internal inputs or not allowing
# unverified external inputs in transactions where multisig inputs are present.
if not self.verification_input and txi.address_n and not txi.multisig:
self.verification_input = txi self.verification_input = txi
self.verification_index = self.index self.verification_index = self.index

View File

@ -15,8 +15,6 @@ from apps.common.writers import ( # noqa: F401
write_uint64_le, write_uint64_le,
) )
from .common import input_is_external_unverified
if TYPE_CHECKING: if TYPE_CHECKING:
from trezor.messages import ( from trezor.messages import (
PrevInput, PrevInput,
@ -48,15 +46,23 @@ def write_tx_input(w: Writer, i: TxInput | PrevInput, script: bytes) -> None:
def write_tx_input_check(w: Writer, i: TxInput) -> None: def write_tx_input_check(w: Writer, i: TxInput) -> None:
write_bytes_fixed(w, i.prev_hash, TX_HASH_SIZE) from .multisig import multisig_fingerprint
write_uint32(w, i.prev_index)
write_uint32(w, i.script_type)
write_uint8(w, input_is_external_unverified(i))
write_uint32(w, len(i.address_n)) write_uint32(w, len(i.address_n))
for n in i.address_n: for n in i.address_n:
write_uint32(w, n) write_uint32(w, n)
write_bytes_fixed(w, i.prev_hash, TX_HASH_SIZE)
write_uint32(w, i.prev_index)
write_bytes_prefixed(w, i.script_sig or b"")
write_uint32(w, i.sequence) write_uint32(w, i.sequence)
write_uint32(w, i.script_type)
multisig_fp = multisig_fingerprint(i.multisig) if i.multisig else b""
write_bytes_prefixed(w, multisig_fp)
write_uint64(w, i.amount or 0) write_uint64(w, i.amount or 0)
write_bytes_prefixed(w, i.witness or b"")
write_bytes_prefixed(w, i.ownership_proof or b"")
write_bytes_prefixed(w, i.orig_hash or b"")
write_uint32(w, i.orig_index or 0)
write_bytes_prefixed(w, i.script_pubkey or b"") write_bytes_prefixed(w, i.script_pubkey or b"")

View File

@ -43,7 +43,7 @@ class TestWriters(unittest.TestCase):
b = bytearray() b = bytearray()
writers.write_tx_input_check(b, inp) writers.write_tx_input_check(b, inp)
self.assertEqual(len(b), 32 + 4 + 4 + 1 + 4 + 4 + 4 + 8 + 26) self.assertEqual(len(b), 4 + 4 + 32 + 4 + 11 + 4 + 4 + 1 + 8 + 1 + 1 + 1 + 4 + 26)
for bad_prevhash in (b"", b"x", b"hello", b"x" * 33): for bad_prevhash in (b"", b"x", b"hello", b"x" * 33):
inp.prev_hash = bad_prevhash inp.prev_hash = bad_prevhash