URI: 
       tCheck SPV proof inner nodes not to be valid transactions. (#4436) - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 61a9deaa610fecbacd3b37501faba59a7e60d163
   DIR parent 7797af6ffa1f584377bbc16e1aee4736f610508a
  HTML 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:
         M lib/verifier.py                     |      28 ++++++++++++++++++++++++++--
       
       1 file changed, 26 insertions(+), 2 deletions(-)
       ---
   DIR diff --git a/lib/verifier.py b/lib/verifier.py
       t@@ -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):
       t@@ -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
       t@@ -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)