electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 61a9deaa610fecbacd3b37501faba59a7e60d163
parent 7797af6ffa1f584377bbc16e1aee4736f610508a
Author: ghost43 <somber.night@protonmail.com>
Date:   Wed, 20 Jun 2018 18:09:38 +0200

Check SPV proof inner nodes not to be valid transactions. (#4436)


Diffstat:
Mlib/verifier.py | 28++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/lib/verifier.py b/lib/verifier.py @@ -20,8 +20,12 @@ # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .util import ThreadJob +from .util import ThreadJob, bh2u from .bitcoin import Hash, hash_decode, hash_encode +from .transaction import Transaction + + +class InnerNodeOfSpvProofIsValidTx(Exception): pass class SPV(ThreadJob): @@ -79,7 +83,12 @@ class SPV(ThreadJob): tx_hash = params[0] tx_height = merkle.get('block_height') pos = merkle.get('pos') - merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos) + try: + merkle_root = self.hash_merkle_root(merkle['merkle'], tx_hash, pos) + except InnerNodeOfSpvProofIsValidTx: + self.print_error("merkle verification failed for {} (inner node looks like tx)" + .format(tx_hash)) + return header = self.network.blockchain().read_header(tx_height) # FIXME: if verification fails below, # we should make a fresh connection to a server to @@ -112,8 +121,23 @@ class SPV(ThreadJob): for i in range(len(merkle_s)): item = merkle_s[i] h = Hash(hash_decode(item) + h) if ((pos >> i) & 1) else Hash(h + hash_decode(item)) + cls._raise_if_valid_tx(bh2u(h)) return hash_encode(h) + @classmethod + def _raise_if_valid_tx(cls, raw_tx: str): + # If an inner node of the merkle proof is also a valid tx, chances are, this is an attack. + # https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-June/016105.html + # https://lists.linuxfoundation.org/pipermail/bitcoin-dev/attachments/20180609/9f4f5b1f/attachment-0001.pdf + # https://bitcoin.stackexchange.com/questions/76121/how-is-the-leaf-node-weakness-in-merkle-trees-exploitable/76122#76122 + tx = Transaction(raw_tx) + try: + tx.deserialize() + except: + pass + else: + raise InnerNodeOfSpvProofIsValidTx() + def undo_verifications(self): height = self.blockchain.get_checkpoint() tx_hashes = self.wallet.undo_verifications(self.blockchain, height)