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:
parent
181fd1c601
commit
b1c6b42201
1
core/.changelog.d/noissue.security
Normal file
1
core/.changelog.d/noissue.security
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fix a coin loss vulnerability related to replacement transactions with multisig inputs and unverified external inputs.
|
@ -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
|
||||||
|
|
||||||
|
@ -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"")
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user