Exemple #1
0
    def test_end_session(self):
        session_id = cache.start_session()
        self.assertTrue(cache.is_session_started())
        cache.set(KEY, b"A")
        cache.end_current_session()
        self.assertFalse(cache.is_session_started())
        self.assertRaises(cache.InvalidSessionError, cache.get, KEY)

        # ending an ended session should be a no-op
        cache.end_current_session()
        self.assertFalse(cache.is_session_started())

        session_id_a = cache.start_session(session_id)
        # original session no longer exists
        self.assertNotEqual(session_id_a, session_id)
        # original session data no longer exists
        self.assertIsNone(cache.get(KEY))

        # create a new session
        session_id_b = cache.start_session()
        # switch back to original session
        session_id = cache.start_session(session_id_a)
        self.assertEqual(session_id, session_id_a)
        # end original session
        cache.end_current_session()
        # switch back to B
        session_id = cache.start_session(session_id_b)
        self.assertEqual(session_id, session_id_b)
Exemple #2
0
    def test_Initialize(self):
        def call_Initialize(**kwargs):
            msg = Initialize(**kwargs)
            return await_result(handle_Initialize(DUMMY_CONTEXT, msg))

        # calling Initialize without an ID allocates a new one
        session_id = cache.start_session()
        features = call_Initialize()
        self.assertNotEqual(session_id, features.session_id)

        # calling Initialize with the current ID does not allocate a new one
        features = call_Initialize(session_id=session_id)
        self.assertEqual(session_id, features.session_id)

        # store "hello"
        cache.set(KEY, b"hello")
        # check that it is cleared
        features = call_Initialize()
        session_id = features.session_id
        self.assertIsNone(cache.get(KEY))
        # store "hello" again
        cache.set(KEY, b"hello")
        self.assertEqual(cache.get(KEY), b"hello")

        # supplying a different session ID starts a new cache
        call_Initialize(session_id=b"A" * cache._SESSION_ID_LENGTH)
        self.assertIsNone(cache.get(KEY))

        # but resuming a session loads the previous one
        call_Initialize(session_id=session_id)
        self.assertEqual(cache.get(KEY), b"hello")
Exemple #3
0
 def test_session_queue(self):
     session_id = cache.start_session()
     self.assertEqual(cache.start_session(session_id), session_id)
     cache.set(KEY, b"A")
     for i in range(cache._MAX_SESSIONS_COUNT):
         cache.start_session()
     self.assertNotEqual(cache.start_session(session_id), session_id)
     self.assertIsNone(cache.get(KEY))
Exemple #4
0
def derive_slip21_node_without_passphrase(path: list) -> Slip21Node:
    if not storage.is_initialized():
        raise Exception("Device is not initialized")
    seed = cache.get(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE)
    if seed is None:
        seed = mnemonic.get_seed(progress_bar=False)
        cache.set(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE, seed)
    node = Slip21Node(seed)
    node.derive_path(path)
    return node
Exemple #5
0
async def get_keychain(ctx: wire.Context, namespaces: list) -> Keychain:
    if not storage.is_initialized():
        raise wire.NotInitialized("Device is not initialized")
    seed = cache.get(cache.APP_COMMON_SEED)
    if seed is None:
        passphrase = await get_passphrase(ctx)
        seed = mnemonic.get_seed(passphrase)
        cache.set(cache.APP_COMMON_SEED, seed)
    keychain = Keychain(seed, namespaces)
    return keychain
Exemple #6
0
    def test_start_session(self):
        session_id_a = cache.start_session()
        self.assertIsNotNone(session_id_a)
        session_id_b = cache.start_session()
        self.assertNotEqual(session_id_a, session_id_b)

        cache.clear_all()
        with self.assertRaises(cache.InvalidSessionError):
            cache.set(KEY, "something")
        with self.assertRaises(cache.InvalidSessionError):
            cache.get(KEY)
Exemple #7
0
def derive_node_without_passphrase(
    path: list, curve_name: str = "secp256k1"
) -> bip32.HDNode:
    if not storage.is_initialized():
        raise Exception("Device is not initialized")
    seed = cache.get(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE)
    if seed is None:
        seed = mnemonic.get_seed(progress_bar=False)
        cache.set(cache.APP_COMMON_SEED_WITHOUT_PASSPHRASE, seed)
    node = bip32.from_seed(seed, curve_name)
    node.derive_path(path)
    return node
    def test_get_keychain(self):
        seed = bip39.seed(' '.join(['all'] * 12), '')
        cache.start_session()
        cache.set(cache.APP_COMMON_SEED, seed)

        namespaces = [("secp256k1", [44 | HARDENED])]
        keychain = await_result(get_keychain(wire.DUMMY_CONTEXT, namespaces))

        # valid path:
        self.assertIsNotNone(keychain.derive([44 | HARDENED, 1 | HARDENED]))

        # invalid path:
        with self.assertRaises(wire.DataError):
            keychain.derive([44])
    def test_get_keychain(self):
        seed = bip39.seed(" ".join(["all"] * 12), "")
        cache.set(cache.APP_COMMON_SEED, seed)

        schema = PathSchema("m/44'/1'", 0)
        keychain = await_result(
            get_keychain(wire.DUMMY_CONTEXT, "secp256k1", [schema]))

        # valid path:
        self.assertIsNotNone(keychain.derive([H_(44), H_(1)]))

        # invalid path:
        with self.assertRaises(wire.DataError):
            keychain.derive([44])
Exemple #10
0
    def test_get_set(self):
        session_id1 = cache.start_session()
        cache.set(KEY, b"hello")
        self.assertEqual(cache.get(KEY), b"hello")

        session_id2 = cache.start_session()
        cache.set(KEY, b"world")
        self.assertEqual(cache.get(KEY), b"world")

        cache.start_session(session_id2)
        self.assertEqual(cache.get(KEY), b"world")
        cache.start_session(session_id1)
        self.assertEqual(cache.get(KEY), b"hello")

        cache.clear_all()
        with self.assertRaises(cache.InvalidSessionError):
            cache.get(KEY)
    def test_with_slip44(self):
        seed = bip39.seed(' '.join(['all'] * 12), '')
        cache.start_session()
        cache.set(cache.APP_COMMON_SEED, seed)

        slip44_id = 42
        valid_path = [44 | HARDENED, slip44_id | HARDENED]
        invalid_path = [44 | HARDENED, 99 | HARDENED]
        testnet_path = [44 | HARDENED, 1 | HARDENED]

        def check_valid_paths(keychain, *paths):
            for path in paths:
                self.assertIsNotNone(keychain.derive(path))

        def check_invalid_paths(keychain, *paths):
            for path in paths:
                self.assertRaises(wire.DataError, keychain.derive, path)

        @with_slip44_keychain(slip44_id)
        async def func_id_only(ctx, msg, keychain):
            check_valid_paths(keychain, valid_path)
            check_invalid_paths(keychain, testnet_path, invalid_path)

        @with_slip44_keychain(slip44_id, allow_testnet=True)
        async def func_allow_testnet(ctx, msg, keychain):
            check_valid_paths(keychain, valid_path, testnet_path)
            check_invalid_paths(keychain, invalid_path)

        @with_slip44_keychain(slip44_id, curve="ed25519")
        async def func_with_curve(ctx, msg, keychain):
            check_valid_paths(keychain, valid_path)
            check_invalid_paths(keychain, testnet_path, invalid_path)

            i, _ = keychain.match_path(valid_path)
            ns_curve, ns = keychain.namespaces[i]
            self.assertEqual(ns_curve, "ed25519")

        await_result(func_id_only(wire.DUMMY_CONTEXT, None))
        await_result(func_allow_testnet(wire.DUMMY_CONTEXT, None))
        await_result(func_with_curve(wire.DUMMY_CONTEXT, None))
    def test_with_slip44(self):
        seed = bip39.seed(" ".join(["all"] * 12), "")
        cache.set(cache.APP_COMMON_SEED, seed)

        slip44_id = 42
        valid_path = [H_(44), H_(slip44_id), H_(0)]
        invalid_path = [H_(44), H_(99), H_(0)]
        testnet_path = [H_(44), H_(1), H_(0)]

        def check_valid_paths(keychain, *paths):
            for path in paths:
                self.assertIsNotNone(keychain.derive(path))

        def check_invalid_paths(keychain, *paths):
            for path in paths:
                self.assertRaises(wire.DataError, keychain.derive, path)

        @with_slip44_keychain(PATTERN_SEP5, slip44_id=slip44_id)
        async def func_id_only(ctx, msg, keychain):
            check_valid_paths(keychain, valid_path, testnet_path)
            check_invalid_paths(keychain, invalid_path)

        @with_slip44_keychain(PATTERN_SEP5,
                              slip44_id=slip44_id,
                              allow_testnet=False)
        async def func_disallow_testnet(ctx, msg, keychain):
            check_valid_paths(keychain, valid_path)
            check_invalid_paths(keychain, testnet_path, invalid_path)

        @with_slip44_keychain(PATTERN_SEP5,
                              slip44_id=slip44_id,
                              curve="ed25519")
        async def func_with_curve(ctx, msg, keychain):
            self.assertEqual(keychain.curve, "ed25519")
            check_valid_paths(keychain, valid_path, testnet_path)
            check_invalid_paths(keychain, invalid_path)

        await_result(func_id_only(wire.DUMMY_CONTEXT, None))
        await_result(func_disallow_testnet(wire.DUMMY_CONTEXT, None))
        await_result(func_with_curve(wire.DUMMY_CONTEXT, None))
Exemple #13
0
    def test_empty_value(self):
        cache.start_session()

        self.assertIsNone(cache.get(KEY))
        cache.set(KEY, b"")
        self.assertEqual(cache.get(KEY), b"")

        cache.delete(KEY)
        run_count = 0

        @cache.stored(KEY)
        def func():
            nonlocal run_count
            run_count += 1
            return b""

        self.assertEqual(func(), b"")
        # function gets called once
        self.assertEqual(run_count, 1)
        self.assertEqual(func(), b"")
        # function is not called for a second time
        self.assertEqual(run_count, 1)
Exemple #14
0
    async def derive_and_store_roots(ctx: wire.Context) -> None:
        if not device.is_initialized():
            raise wire.NotInitialized("Device is not initialized")

        need_seed = not cache.is_set(cache.APP_COMMON_SEED)
        need_cardano_secret = cache.get(
            cache.APP_COMMON_DERIVE_CARDANO
        ) and not cache.is_set(cache.APP_CARDANO_ICARUS_SECRET)

        if not need_seed and not need_cardano_secret:
            return

        passphrase = await get_passphrase(ctx)

        if need_seed:
            common_seed = mnemonic.get_seed(passphrase)
            cache.set(cache.APP_COMMON_SEED, common_seed)

        if need_cardano_secret:
            from apps.cardano.seed import derive_and_store_secrets

            derive_and_store_secrets(passphrase)
Exemple #15
0
def derive_and_store_secrets(passphrase: str) -> None:
    assert device.is_initialized()
    assert cache.get(cache.APP_COMMON_DERIVE_CARDANO)

    if not mnemonic.is_bip39():
        # nothing to do for SLIP-39, where we can derive the root from the main seed
        return

    icarus_secret = mnemonic.derive_cardano_icarus(passphrase,
                                                   trezor_derivation=False)

    words = mnemonic.get_secret()
    assert words is not None, "Mnemonic is not set"
    # count ASCII spaces, add 1 to get number of words
    words_count = sum(c == 0x20 for c in words) + 1

    if words_count == 24:
        icarus_trezor_secret = mnemonic.derive_cardano_icarus(
            passphrase, trezor_derivation=True)
    else:
        icarus_trezor_secret = icarus_secret

    cache.set(cache.APP_CARDANO_ICARUS_SECRET, icarus_secret)
    cache.set(cache.APP_CARDANO_ICARUS_TREZOR_SECRET, icarus_trezor_secret)
Exemple #16
0
    def test_delete(self):
        session_id1 = cache.start_session()
        self.assertIsNone(cache.get(KEY))
        cache.set(KEY, b"hello")
        self.assertEqual(cache.get(KEY), b"hello")
        cache.delete(KEY)
        self.assertIsNone(cache.get(KEY))

        cache.set(KEY, b"hello")
        session_id2 = cache.start_session()
        self.assertIsNone(cache.get(KEY))
        cache.set(KEY, b"hello")
        self.assertEqual(cache.get(KEY), b"hello")
        cache.delete(KEY)
        self.assertIsNone(cache.get(KEY))

        cache.start_session(session_id1)
        self.assertEqual(cache.get(KEY), b"hello")
 def setUp(self):
     cache.start_session()
     seed = bip39.seed(" ".join(["all"] * 12), "")
     cache.set(cache.APP_COMMON_SEED, seed)
Exemple #18
0
async def get_nonce(ctx: wire.Context, msg: GetNonce) -> Nonce:
    nonce = random.bytes(32)
    cache.set(cache.APP_COMMON_NONCE, nonce)
    return Nonce(nonce=nonce)