Version 0.9.4a - security release
TX hexdata switch attack protection:
- Protect against an exotic but theoretically possible attack where a
malicious, compromised or malfunctioning coin daemon could alter hex
transaction data. An integrity check is performed during both signing and
sending. Needless to say, a user should always view a transaction and
double-check its outputs before broadcasting.
This commit is contained in:
parent
6a06b54ffe
commit
b4d75b09f2
2 changed files with 37 additions and 1 deletions
|
|
@ -38,7 +38,7 @@ class g(object):
|
|||
sys.exit(ev)
|
||||
# Variables - these might be altered at runtime:
|
||||
|
||||
version = '0.9.399'
|
||||
version = '0.9.4a'
|
||||
release_date = 'October 2017'
|
||||
|
||||
proj_name = 'MMGen'
|
||||
|
|
|
|||
36
mmgen/tx.py
36
mmgen/tx.py
|
|
@ -48,6 +48,12 @@ def bytes2int(hex_bytes):
|
|||
def bytes2btc(hex_bytes):
|
||||
return bytes2int(hex_bytes) * g.satoshi
|
||||
|
||||
def scriptPubKey2addr(s):
|
||||
if len(s) == 50 and s[:6] == '76a914' and s[-4:] == '88ac': addr_hex,p2sh = s[6:-4],False
|
||||
elif len(s) == 46 and s[:4] == 'a914' and s[-2:] == '87': addr_hex,p2sh = s[4:-2],True
|
||||
else: raise NotImplementedError,'Unknown scriptPubKey'
|
||||
return g.proto.hexaddr2addr(addr_hex,p2sh)
|
||||
|
||||
from collections import OrderedDict
|
||||
class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
||||
def __init__(self,txhex):
|
||||
|
|
@ -91,6 +97,9 @@ class DeserializedTX(OrderedDict,MMGenObject): # need to add MMGen types
|
|||
('scriptPubKey', hshift(tx,readVInt(tx)))
|
||||
)) for i in range(d['num_txouts'])])
|
||||
|
||||
for o in d['txouts']:
|
||||
o['address'] = scriptPubKey2addr(o['scriptPubKey'])
|
||||
|
||||
d['witness_size'] = 0
|
||||
if has_witness:
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
|
||||
|
|
@ -475,6 +484,7 @@ class MMGenTX(MMGenObject):
|
|||
self.hex = ret['hex']
|
||||
vmsg('Signed transaction size: {}'.format(len(self.hex)/2))
|
||||
dt = DeserializedTX(self.hex)
|
||||
self.check_hex_tx_matches_mmgen_tx(dt)
|
||||
txid = dt['txid']
|
||||
self.check_sigs(dt)
|
||||
assert txid == c.decoderawtransaction(self.hex)['txid'], 'txid mismatch (after signing)'
|
||||
|
|
@ -498,6 +508,30 @@ class MMGenTX(MMGenObject):
|
|||
ret = self.desc == 'signed transaction'
|
||||
return (red,green)[ret](str(ret)) if color else ret
|
||||
|
||||
# protect against an attack where a malicious, compromised or malfunctioning daemon could switch
|
||||
# hex transaction data.
|
||||
def check_hex_tx_matches_mmgen_tx(self,deserial_tx):
|
||||
m = 'Fatal error: a malicious or malfunctioning coin daemon or other program has altered your data!'
|
||||
|
||||
if deserial_tx['lock_time'] != 0:
|
||||
rdie(3,'\nLock time is not zero!\n' + m)
|
||||
|
||||
def do_io_err(desc,mmio,hexio):
|
||||
msg('\nMMGen {}:\n{}'.format(desc,pformat(mmio)))
|
||||
msg('Hex {}:\n{}'.format(desc,pformat(hexio)))
|
||||
m2 = '{} in hex transaction data from coin daemon do not match those in MMGen transaction!\n' + m
|
||||
rdie(3,m2.format(desc.capitalize()))
|
||||
|
||||
i_hex = sorted((i['txid'],i['vout']) for i in deserial_tx['txins'])
|
||||
i_mmgen = sorted((i.txid,i.vout) for i in self.inputs)
|
||||
if i_hex != i_mmgen:
|
||||
do_io_err('inputs',i_hex,i_mmgen)
|
||||
|
||||
o_hex = sorted((o['address'],BTCAmt(o['amount'])) for o in deserial_tx['txouts'])
|
||||
o_mmgen = sorted((o.addr,o.amt) for o in self.outputs)
|
||||
if o_hex != o_mmgen:
|
||||
do_io_err('outputs',o_hex,o_mmgen)
|
||||
|
||||
def check_sigs(self,deserial_tx=None): # return False if no sigs, die on error
|
||||
txins = (deserial_tx or DeserializedTX(self.hex))['txins']
|
||||
has_ss = any(ti['scriptSig'] for ti in txins)
|
||||
|
|
@ -557,6 +591,8 @@ class MMGenTX(MMGenObject):
|
|||
|
||||
self.die_if_incorrect_chain()
|
||||
|
||||
self.check_hex_tx_matches_mmgen_tx(DeserializedTX(self.hex))
|
||||
|
||||
bogus_send = os.getenv('MMGEN_BOGUS_SEND')
|
||||
|
||||
if self.has_segwit_outputs() and not segwit_is_active() and not bogus_send:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue