def test_nopin_nopassphrase(self):
        mnemonic = self.mnemonic12
        ret = self.client.call_raw(
            proto.RecoveryDevice(word_count=12,
                                 passphrase_protection=False,
                                 pin_protection=False,
                                 label='label',
                                 language='english',
                                 enforce_wordlist=True,
                                 use_character_cipher=True))

        # Reminder UI
        assert isinstance(ret, proto.ButtonRequest)
        self.client.debug.press_yes()
        ret = self.client.call_raw(proto.ButtonAck())

        mnemonic_words = mnemonic.split(' ')

        for index, word in enumerate(mnemonic_words):
            for character in word:
                self.assertIsInstance(ret, proto.CharacterRequest)
                cipher = self.client.debug.read_recovery_cipher()

                encoded_character = cipher[ord(character) - 97]
                ret = self.client.call_raw(
                    proto.CharacterAck(character=encoded_character))

                auto_completed = self.client.debug.read_recovery_auto_completed_word(
                )

                if word == auto_completed:
                    if len(mnemonic_words) != index + 1:
                        ret = self.client.call_raw(
                            proto.CharacterAck(character=' '))
                    break

        # Send final ack
        self.assertIsInstance(ret, proto.CharacterRequest)
        ret = self.client.call_raw(proto.CharacterAck(done=True))

        # Workflow succesfully ended
        self.assertIsInstance(ret, proto.Success)

        # Mnemonic is the same
        self.client.init_device()
        self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12)

        self.assertFalse(self.client.features.pin_protection)
        self.assertFalse(self.client.features.passphrase_protection)

        # Do passphrase-protected action, PassphraseRequest should NOT be raised
        resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
        self.assertIsInstance(resp, proto.Success)

        # Do PIN-protected action, PinRequest should NOT be raised
        resp = self.client.call_raw(proto.Ping(pin_protection=True))
        self.assertIsInstance(resp, proto.Success)
Ejemplo n.º 2
0
        def check_n_words(n):
            ret = self.client.call_raw(
                proto.RecoveryDevice(word_count=12,
                                     passphrase_protection=False,
                                     pin_protection=False,
                                     label='label',
                                     language='english',
                                     enforce_wordlist=True,
                                     use_character_cipher=True))

            # Reminder UI
            assert isinstance(ret, proto.ButtonRequest)
            self.client.debug.press_yes()
            ret = self.client.call_raw(proto.ButtonAck())

            mnemonic_words = ['all'] * n

            for index, word in enumerate(mnemonic_words):
                if index >= 12:
                    self.assertIsInstance(ret, proto.Success)
                    self.assertEndsWith(ret.message, "Device recovered")
                    return

                for character in word:
                    self.assertIsInstance(ret, proto.CharacterRequest)
                    cipher = self.client.debug.read_recovery_cipher()

                    encoded_character = cipher[ord(character) - 97]
                    ret = self.client.call_raw(
                        proto.CharacterAck(character=encoded_character))

                    auto_completed = self.client.debug.read_recovery_auto_completed_word(
                    )

                    if word == auto_completed:
                        if len(mnemonic_words) != index + 1:
                            ret = self.client.call_raw(
                                proto.CharacterAck(character=' '))
                        break

            # Send final ack
            self.assertIsInstance(ret, proto.CharacterRequest)
            ret = self.client.call_raw(proto.CharacterAck(done=True))

            if n == 12:
                self.assertIsInstance(ret, proto.Success)
                self.assertEndsWith(ret.message, "Device recovered")
            else:
                self.assertIsInstance(ret, proto.Failure)
                self.assertEndsWith(ret.message, "words entered")
    def test_vuln1971(self):
        self.setup_mnemonic_allallall()

        self.assertEquals(
            self.client.get_address("Testnet",
                                    parse_path("49'/1'/0'/1/0"),
                                    True,
                                    None,
                                    script_type=proto_types.SPENDP2SHWITNESS),
            '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX')

        # Previously, there weren't good checks on the expected state of the
        # recovery cipher state machine, which led to this case triggering an
        # out of bounds memory access, as well as setting the device's mnemonic
        # to "".
        self.client.call_raw(proto.CharacterAck(done=True))

        # The emulator, with ASan enabled, crashes on the out of bounds
        # memory access before even getting to the part where the empty
        # mnemonic is pushed into storage, but for posterity, let's make sure
        # we still get the correct address afterward:
        self.assertEquals(
            self.client.get_address("Testnet",
                                    parse_path("49'/1'/0'/1/0"),
                                    True,
                                    None,
                                    script_type=proto_types.SPENDP2SHWITNESS),
            '2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX')
    def test_too_many_characters(self):
        ret = self.client.call_raw(
            proto.RecoveryDevice(word_count=12,
                                 passphrase_protection=False,
                                 pin_protection=False,
                                 label='label',
                                 language='english',
                                 enforce_wordlist=True,
                                 use_character_cipher=True))

        # Reminder UI
        assert isinstance(ret, proto.ButtonRequest)
        self.client.debug.press_yes()
        ret = self.client.call_raw(proto.ButtonAck())

        mnemonic_words = ['all'] * 100

        for index, word in enumerate(mnemonic_words):
            for character in word:
                if isinstance(ret, proto.Failure):
                    self.assertEndsWith(ret.message, "Too many words entered")
                    return

                self.assertIsInstance(ret, proto.CharacterRequest)
                cipher = self.client.debug.read_recovery_cipher()

                encoded_character = cipher[ord(character) - 97]
                ret = self.client.call_raw(
                    proto.CharacterAck(character=encoded_character))

                auto_completed = self.client.debug.read_recovery_auto_completed_word(
                )

                if word == auto_completed:
                    if len(mnemonic_words) != index + 1:
                        ret = self.client.call_raw(
                            proto.CharacterAck(character=' '))
                    break

        # Shouldn't ever get here, assuming the test worked
        self.assertEquals(True, False)
Ejemplo n.º 5
0
    def test_character_fail(self):
        ret = self.client.call_raw(proto.RecoveryDevice(word_count=12,
                                   passphrase_protection=False,
                                   pin_protection=False,
                                   label='label',
                                   language='english',
                                   enforce_wordlist=True,
                                   use_character_cipher=True))

        self.assertIsInstance(ret, proto.CharacterRequest)
        ret = self.client.call_raw(proto.CharacterAck(character='1'))
        self.assertIsInstance(ret, proto.Failure)
    def recovery_loop(self, mnemonic, result):
        ret = self.client.call_raw(
            proto.RecoveryDevice(
                word_count=12,
                passphrase_protection=False,
                pin_protection=False,
                label="label",
                language="english",
                enforce_wordlist=True,
                dry_run=True,
                use_character_cipher=True,
            )
        )

        for index, word in enumerate(mnemonic):
            for character in word:
                self.assertIsInstance(ret, proto.CharacterRequest)
                cipher = self.client.debug.read_recovery_cipher()

                encoded_character = cipher[ord(character) - 97]
                ret = self.client.call_raw(proto.CharacterAck(character=encoded_character))

                auto_completed = self.client.debug.read_recovery_auto_completed_word()

                if word == auto_completed:
                    if len(mnemonic) != index + 1:
                        ret = self.client.call_raw(proto.CharacterAck(character=' '))
                    break

        self.assertIsInstance(ret, proto.CharacterRequest)
        ret = self.client.call_raw(proto.CharacterAck(done=True))

        assert isinstance(ret, proto.ButtonRequest)
        self.client.debug.press_yes()

        ret = self.client.call_raw(proto.ButtonAck())
        assert isinstance(ret, result)
Ejemplo n.º 7
0
    def callback_CharacterRequest(self, msg):
        from keepkeylib import messages_pb2 as proto
        if self.character_request_first_pass:
            self.character_request_first_pass = False

        # format mnemonic for console
        input_label = f'WORD {msg.word_pos + 1}:'

        while True:
            cur_str = msg.character_pos * '*'
            character_ascii = self.request_character(cur_str, input_label)

            # capture escape
            if character_ascii in (3, 4):
                return proto.Cancel()

            if 65 <= character_ascii <= 90:
                character_ascii = ord(chr(character_ascii).lower())

            if 97 <= character_ascii <= 122 and msg.character_pos != 4:
                # capture characters a-z
                character = chr(character_ascii).lower()
                return proto.CharacterAck(character=character)

            elif character_ascii == 32 and msg.word_pos < 23 and msg.character_pos >= 3:
                # capture spaces
                return proto.CharacterAck(character=' ')

            elif character_ascii == 8 or character_ascii == 127 \
            and (msg.word_pos > 0 or msg.character_pos > 0):
                # capture backspaces
                return proto.CharacterAck(delete=True)

            elif character_ascii == 13 and msg.word_pos in (11, 17, 23):
                # capture returns
                return proto.CharacterAck(done=True)
Ejemplo n.º 8
0
    def test_pin_passphrase(self):
        mnemonic = self.mnemonic12
        ret = self.client.call_raw(proto.RecoveryDevice(word_count=12,
                                   passphrase_protection=True,
                                   pin_protection=True,
                                   label='label',
                                   language='english',
                                   enforce_wordlist=True,
                                   use_character_cipher=True))

        self.assertIsInstance(ret, proto.PinMatrixRequest)

        # Enter PIN for first time
        pin_encoded = self.client.debug.encode_pin(self.pin6)
        ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))
        self.assertIsInstance(ret, proto.PinMatrixRequest)

        # Enter PIN for second time
        pin_encoded = self.client.debug.encode_pin(self.pin6)
        ret = self.client.call_raw(proto.PinMatrixAck(pin=pin_encoded))

        mnemonic_words = mnemonic.split(' ')

        for index, word in enumerate(mnemonic_words):
            for character in word:
                self.assertIsInstance(ret, proto.CharacterRequest)
                cipher = self.client.debug.read_recovery_cipher()

                encoded_character = cipher[ord(character) - 97]
                ret = self.client.call_raw(proto.CharacterAck(character=encoded_character))
                
                auto_completed = self.client.debug.read_recovery_auto_completed_word()       

                if word == auto_completed:
                    if len(mnemonic_words) != index + 1:
                        ret = self.client.call_raw(proto.CharacterAck(character=' '))
                    break

        # Send final ack
        self.assertIsInstance(ret, proto.CharacterRequest)
        ret = self.client.call_raw(proto.CharacterAck(done=True))

        # Workflow succesfully ended
        self.assertIsInstance(ret, proto.Success)

        # Mnemonic is the same
        self.client.init_device()
        self.assertEqual(self.client.debug.read_mnemonic(), self.mnemonic12)

        self.assertTrue(self.client.features.pin_protection)
        self.assertTrue(self.client.features.passphrase_protection)
        
        # Do passphrase-protected action, PassphraseRequest should be raised
        resp = self.client.call_raw(proto.Ping(passphrase_protection=True))
        self.assertIsInstance(resp, proto.PassphraseRequest)
        self.client.call_raw(proto.Cancel())

        self.client.clear_session()

        # Do PIN-protected action, PinRequest should be raised
        resp = self.client.call_raw(proto.Ping(pin_protection=True))
        self.assertIsInstance(resp, proto.PinMatrixRequest)
        self.client.call_raw(proto.Cancel())
Ejemplo n.º 9
0
    def test_reset_and_recover(self):
        for strength in (128, 192, 256):
            external_entropy = self.client._get_local_entropy()

            ret = self.client.call_raw(proto.ResetDevice(display_random=False,
                                                strength=strength,
                                                passphrase_protection=False,
                                                pin_protection=False,
                                                language='english',
                                                label='test'))

            # Provide entropy
            self.assertIsInstance(ret, proto.EntropyRequest)
            resp = self.client.call_raw(proto.EntropyAck(entropy=external_entropy))

            mnemonic = []
            while isinstance(resp, proto.ButtonRequest):
                mnemonic.append(self.client.debug.read_reset_word())
                self.client.debug.press_yes()
                resp = self.client.call_raw(proto.ButtonAck())

            mnemonic = ' '.join(mnemonic)
            
            # wipe device
            ret = self.client.call_raw(proto.WipeDevice())
            self.client.debug.press_yes()
            ret = self.client.call_raw(proto.ButtonAck())

            # recover devce
            ret = self.client.call_raw(proto.RecoveryDevice(word_count=(strength/32*3),
                                   passphrase_protection=False,
                                   pin_protection=False,
                                   label='label',
                                   language='english',
                                   enforce_wordlist=True,
                                   use_character_cipher=True))

            mnemonic_words = mnemonic.split(' ')

            for index, word in enumerate(mnemonic_words):
                for character in word:
                    self.assertIsInstance(ret, proto.CharacterRequest)
                    cipher = self.client.debug.read_recovery_cipher()

                    encoded_character = cipher[ord(character) - 97]
                    ret = self.client.call_raw(proto.CharacterAck(character=encoded_character))
                
                    auto_completed = self.client.debug.read_recovery_auto_completed_word()       

                    if word == auto_completed:
                        if len(mnemonic_words) != index + 1:
                            ret = self.client.call_raw(proto.CharacterAck(character=' '))
                        break

            # Send final ack
            self.assertIsInstance(ret, proto.CharacterRequest)
            ret = self.client.call_raw(proto.CharacterAck(done=True))

            # Workflow succesfully ended
            self.assertIsInstance(ret, proto.Success)
           
            self.client.init_device()
            self.assertEqual(self.client.debug.read_mnemonic(), mnemonic) 
            
            # wipe device
            ret = self.client.call_raw(proto.WipeDevice())
            self.client.debug.press_yes()
            ret = self.client.call_raw(proto.ButtonAck())