예제 #1
0
def test_cardano_sign_tx_failed(client: Client, parameters, result):
    client.init_device(new_session=True, derive_cardano=True)

    signing_mode = messages.CardanoTxSigningMode.__members__[
        parameters["signing_mode"]]
    inputs = [cardano.parse_input(i) for i in parameters["inputs"]]
    outputs = [cardano.parse_output(o) for o in parameters["outputs"]]
    certificates = [
        cardano.parse_certificate(c) for c in parameters["certificates"]
    ]
    withdrawals = [
        cardano.parse_withdrawal(w) for w in parameters["withdrawals"]
    ]
    auxiliary_data = cardano.parse_auxiliary_data(parameters["auxiliary_data"])
    mint = cardano.parse_mint(parameters["mint"])
    script_data_hash = cardano.parse_script_data_hash(
        parameters["script_data_hash"])
    collateral_inputs = [
        cardano.parse_collateral_input(i)
        for i in parameters["collateral_inputs"]
    ]
    required_signers = [
        cardano.parse_required_signer(s)
        for s in parameters["required_signers"]
    ]
    additional_witness_requests = [
        cardano.parse_additional_witness_request(p)
        for p in parameters["additional_witness_requests"]
    ]

    if parameters.get("security_checks") == "prompt":
        device.apply_settings(
            client, safety_checks=messages.SafetyCheckLevel.PromptTemporarily)
    else:
        device.apply_settings(client,
                              safety_checks=messages.SafetyCheckLevel.Strict)

    with client:
        with pytest.raises(TrezorFailure, match=result["error_message"]):
            cardano.sign_tx(
                client=client,
                signing_mode=signing_mode,
                inputs=inputs,
                outputs=outputs,
                fee=parameters["fee"],
                ttl=parameters.get("ttl"),
                validity_interval_start=parameters.get(
                    "validity_interval_start"),
                certificates=certificates,
                withdrawals=withdrawals,
                protocol_magic=parameters["protocol_magic"],
                network_id=parameters["network_id"],
                auxiliary_data=auxiliary_data,
                mint=mint,
                script_data_hash=script_data_hash,
                collateral_inputs=collateral_inputs,
                required_signers=required_signers,
                additional_witness_requests=additional_witness_requests,
                include_network_id=parameters["include_network_id"],
            )
def test_change_invalid_current(client: Client):
    assert client.features.pin_protection is True

    # Check current PIN value
    _check_pin(client, PIN4)

    # Let's set new PIN
    def input_flow():
        yield  # do you want to change pin?
        client.debug.press_yes()
        yield  # enter wrong current pin
        client.debug.input(PIN60)
        yield
        client.debug.press_no()

    with client, pytest.raises(TrezorFailure):
        client.set_expected_responses([messages.ButtonRequest] * 3 +
                                      [messages.Failure])
        client.set_input_flow(input_flow)

        device.change_pin(client)

    # Check that there's still old PIN protection
    client.init_device()
    assert client.features.pin_protection is True
    _check_pin(client, PIN4)
예제 #3
0
def test_end_session(client: Client):
    # client instance starts out not initialized
    # XXX do we want to change this?
    assert client.session_id is not None

    # get_address will succeed
    with client:
        client.set_expected_responses([messages.Address])
        get_test_address(client)

    client.end_session()
    assert client.session_id is None
    with pytest.raises(TrezorFailure) as exc:
        get_test_address(client)
    assert exc.value.code == messages.FailureType.InvalidSession
    assert exc.value.message.endswith("Invalid session")

    client.init_device()
    assert client.session_id is not None
    with client:
        client.set_expected_responses([messages.Address])
        get_test_address(client)

    with client:
        # end_session should succeed on empty session too
        client.set_expected_responses([messages.Success] * 2)
        client.end_session()
        client.end_session()
예제 #4
0
def test_derivation_irrelevant_on_slip39(client: Client, derivation_type):
    client.init_device(new_session=True, derive_cardano=False)
    pubkey = get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS)
    test_pubkey = get_public_key(client,
                                 ADDRESS_N,
                                 derivation_type=derivation_type)
    assert pubkey == test_pubkey
def test_set_failed(client: Client):
    assert client.features.pin_protection is False

    # Check that there's no PIN protection
    _check_no_pin(client)

    # Let's set new PIN
    def input_flow():
        yield  # do you want to set pin?
        client.debug.press_yes()
        yield  # enter new pin
        client.debug.input(PIN4)
        yield  # enter new pin again (but different)
        client.debug.input(PIN60)

        # failed retry
        yield  # enter new pin
        client.cancel()

    with client, pytest.raises(Cancelled):
        client.set_expected_responses([messages.ButtonRequest] * 4 +
                                      [messages.Failure])
        client.set_input_flow(input_flow)

        device.change_pin(client)

    # Check that there's still no PIN protection now
    client.init_device()
    assert client.features.pin_protection is False
    _check_no_pin(client)
def test_change_failed(client: Client):
    assert client.features.pin_protection is True

    # Check current PIN value
    _check_pin(client, PIN4)

    # Let's set new PIN
    def input_flow():
        yield  # do you want to change pin?
        client.debug.press_yes()
        yield  # enter current pin
        client.debug.input(PIN4)
        yield  # enter new pin
        client.debug.input("457891")
        yield  # enter new pin again (but different)
        client.debug.input("381847")

        # failed retry
        yield  # enter current pin again
        client.cancel()

    with client, pytest.raises(Cancelled):
        client.set_expected_responses([messages.ButtonRequest] * 5 +
                                      [messages.Failure])
        client.set_input_flow(input_flow)

        device.change_pin(client)

    # Check that there's still old PIN protection
    client.init_device()
    assert client.features.pin_protection is True
    _check_pin(client, PIN4)
예제 #7
0
def test_skip_backup_msg(client: Client, backup_type, backup_flow):

    os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
    with mock.patch("os.urandom", os_urandom), client:
        device.reset(
            client,
            skip_backup=True,
            passphrase_protection=False,
            pin_protection=False,
            backup_type=backup_type,
        )

    assert client.features.initialized is True
    assert client.features.needs_backup is True
    assert client.features.unfinished_backup is False
    assert client.features.no_backup is False
    assert client.features.backup_type is backup_type

    secret = backup_flow(client)

    client.init_device()
    assert client.features.initialized is True
    assert client.features.needs_backup is False
    assert client.features.unfinished_backup is False
    assert client.features.backup_type is backup_type

    assert secret is not None
    state = client.debug.state()
    assert state.mnemonic_type is backup_type
    assert state.mnemonic_secret == secret
def test_backup_bip39(client: Client):
    assert client.features.needs_backup is True
    mnemonic = None

    def input_flow():
        nonlocal mnemonic
        yield  # Confirm Backup
        client.debug.press_yes()
        # Mnemonic phrases
        mnemonic = yield from read_and_confirm_mnemonic(client.debug)
        yield  # Confirm success
        client.debug.press_yes()
        yield  # Backup is done
        client.debug.press_yes()

    with client:
        client.set_input_flow(input_flow)
        client.set_expected_responses([
            messages.ButtonRequest(code=B.ResetDevice),
            messages.ButtonRequest(code=B.ResetDevice),
            messages.ButtonRequest(code=B.Success),
            messages.ButtonRequest(code=B.Success),
            messages.Success,
            messages.Features,
        ])
        device.backup(client)

    assert mnemonic == MNEMONIC12
    client.init_device()
    assert client.features.initialized is True
    assert client.features.needs_backup is False
    assert client.features.unfinished_backup is False
    assert client.features.no_backup is False
    assert client.features.backup_type is messages.BackupType.Bip39
def test_backup_slip39_basic(client: Client, click_info: bool):
    assert client.features.needs_backup is True
    mnemonics = []

    def input_flow():
        yield  # Checklist
        client.debug.press_yes()
        if click_info:
            yield from click_info_button(client.debug)
        yield  # Number of shares (5)
        client.debug.press_yes()
        yield  # Checklist
        client.debug.press_yes()
        if click_info:
            yield from click_info_button(client.debug)
        yield  # Threshold (3)
        client.debug.press_yes()
        yield  # Checklist
        client.debug.press_yes()
        yield  # Confirm show seeds
        client.debug.press_yes()

        # Mnemonic phrases
        for _ in range(5):
            # Phrase screen
            mnemonic = yield from read_and_confirm_mnemonic(client.debug)
            mnemonics.append(mnemonic)
            yield  # Confirm continue to next
            client.debug.press_yes()

        yield  # Confirm backup
        client.debug.press_yes()

    with client:
        client.set_input_flow(input_flow)
        client.set_expected_responses(
            [messages.ButtonRequest(code=B.ResetDevice)] *
            (8 if click_info else 6)  # intro screens (and optional info)
            + [
                messages.ButtonRequest(code=B.ResetDevice),
                messages.ButtonRequest(code=B.Success),
            ] * 5  # individual shares
            + [
                messages.ButtonRequest(code=B.Success),
                messages.Success,
                messages.Features,
            ])
        device.backup(client)

    client.init_device()
    assert client.features.initialized is True
    assert client.features.needs_backup is False
    assert client.features.unfinished_backup is False
    assert client.features.no_backup is False
    assert client.features.backup_type is messages.BackupType.Slip39_Basic

    expected_ms = shamir.combine_mnemonics(MNEMONIC_SLIP39_BASIC_20_3of6)
    actual_ms = shamir.combine_mnemonics(mnemonics[:3])
    assert expected_ms == actual_ms
예제 #10
0
def test_pin_passphrase(client: Client):
    mnemonic = MNEMONIC12.split(" ")
    ret = client.call_raw(
        messages.RecoveryDevice(
            word_count=12,
            passphrase_protection=True,
            pin_protection=True,
            label="label",
            language="en-US",
            enforce_wordlist=True,
        )
    )

    # click through confirmation
    assert isinstance(ret, messages.ButtonRequest)
    client.debug.press_yes()
    ret = client.call_raw(messages.ButtonAck())

    assert isinstance(ret, messages.PinMatrixRequest)

    # Enter PIN for first time
    pin_encoded = client.debug.encode_pin(PIN6)
    ret = client.call_raw(messages.PinMatrixAck(pin=pin_encoded))
    assert isinstance(ret, messages.PinMatrixRequest)

    # Enter PIN for second time
    pin_encoded = client.debug.encode_pin(PIN6)
    ret = client.call_raw(messages.PinMatrixAck(pin=pin_encoded))

    fakes = 0
    for _ in range(int(12 * 2)):
        assert isinstance(ret, messages.WordRequest)
        (word, pos) = client.debug.read_recovery_word()

        if pos != 0:
            ret = client.call_raw(messages.WordAck(word=mnemonic[pos - 1]))
            mnemonic[pos - 1] = None
        else:
            ret = client.call_raw(messages.WordAck(word=word))
            fakes += 1

    # Workflow succesfully ended
    assert isinstance(ret, messages.Success)

    # 12 expected fake words and all words of mnemonic are used
    assert fakes == 12
    assert mnemonic == [None] * 12

    # Mnemonic is the same
    client.init_device()
    assert client.debug.state().mnemonic_secret == MNEMONIC12.encode()

    assert client.features.pin_protection is True
    assert client.features.passphrase_protection is True

    # Do passphrase-protected action, PassphraseRequest should be raised
    resp = client.call_raw(messages.GetAddress(address_n=parse_path("m/44'/0'/0'/0/0")))
    assert isinstance(resp, messages.PassphraseRequest)
    client.call_raw(messages.Cancel())
예제 #11
0
def test_bad_session(client: Client):
    client.init_device(new_session=True)
    with pytest.raises(TrezorFailure, match="not enabled"):
        get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS)

    client.init_device(new_session=True, derive_cardano=False)
    with pytest.raises(TrezorFailure, match="not enabled"):
        get_public_key(client, ADDRESS_N, derivation_type=D.ICARUS)
예제 #12
0
def test_device_id_same(client: Client):
    id1 = client.get_device_id()
    client.init_device()
    id2 = client.get_device_id()

    # ID must be at least 12 characters
    assert len(id1) >= 12

    # Every resulf of UUID must be the same
    assert id1 == id2
예제 #13
0
def _check_wipe_code(client: Client, pin, wipe_code):
    client.init_device()
    assert client.features.wipe_code_protection is True

    # Try to change the PIN to the current wipe code value. The operation should fail.
    with client, pytest.raises(TrezorFailure):
        client.use_pin_sequence([pin, wipe_code, wipe_code])
        client.set_expected_responses(
            [messages.ButtonRequest()] * 5 +
            [messages.Failure(code=messages.FailureType.PinInvalid)])
        device.change_pin(client)
예제 #14
0
def test_cardano_get_public_key(client: Client, parameters, result):
    client.init_device(new_session=True, derive_cardano=True)

    derivation_type = CardanoDerivationType.__members__[
        parameters.get("derivation_type", "ICARUS_TREZOR")
    ]
    key = get_public_key(client, parse_path(parameters["path"]), derivation_type)

    assert key.node.public_key.hex() == result["public_key"]
    assert key.node.chain_code.hex() == result["chain_code"]
    assert key.xpub == result["public_key"] + result["chain_code"]
def test_cardano_get_native_script_hash(client: Client, parameters, result):
    client.init_device(new_session=True, derive_cardano=True)

    native_script_hash = get_native_script_hash(
        client,
        native_script=parse_native_script(parameters["native_script"]),
        display_format=messages.CardanoNativeScriptHashDisplayFormat.
        __members__[parameters["display_format"]],
    ).script_hash

    assert native_script_hash.hex() == result["expected_hash"]
예제 #16
0
def test_set_wipe_code_to_pin(client: Client):
    _ensure_unlocked(client, PIN4)

    with client:
        client.set_expected_responses([messages.ButtonRequest()] * 6 +
                                      [messages.Success, messages.Features])
        client.use_pin_sequence([PIN4, PIN4, WIPE_CODE4, WIPE_CODE4])
        device.change_wipe_code(client)

    client.init_device()
    assert client.features.wipe_code_protection is True
    _check_wipe_code(client, PIN4, WIPE_CODE4)
예제 #17
0
def test_cannot_resume_ended_session(client: Client):
    session_id = client.session_id
    with client:
        client.set_expected_responses([messages.Features])
        client.init_device(session_id=session_id)

    assert session_id == client.session_id

    client.end_session()
    with client:
        client.set_expected_responses([messages.Features])
        client.init_device(session_id=session_id)

    assert session_id != client.session_id
예제 #18
0
def test_unlocked(client: Client):
    assert client.features.unlocked is False

    _assert_protection(client, passphrase=False)
    with client:
        client.use_pin_sequence([PIN4])
        client.set_expected_responses([_pin_request(client), messages.Address])
        get_test_address(client)

    client.init_device()
    assert client.features.unlocked is True
    with client:
        client.set_expected_responses([messages.Address])
        get_test_address(client)
def test_set_pin(client: Client):
    assert client.features.pin_protection is False

    # Check that there's no PIN protection
    _check_no_pin(client)

    # Let's set new PIN
    with client:
        client.use_pin_sequence([PIN_MAX, PIN_MAX])
        client.set_expected_responses([messages.ButtonRequest] * 4 +
                                      [messages.Success, messages.Features])
        device.change_pin(client)

    client.init_device()
    assert client.features.pin_protection is True
    _check_pin(client, PIN_MAX)
예제 #20
0
def test_skip_backup_manual(client: Client, backup_type, backup_flow):
    def reset_skip_input_flow():
        yield  # Confirm Recovery
        client.debug.press_yes()

        yield  # Skip Backup
        client.debug.press_no()

        yield  # Confirm skip backup
        client.debug.press_no()

    os_urandom = mock.Mock(return_value=EXTERNAL_ENTROPY)
    with mock.patch("os.urandom", os_urandom), client:
        client.set_input_flow(reset_skip_input_flow)
        client.set_expected_responses([
            messages.ButtonRequest(code=B.ResetDevice),
            messages.EntropyRequest(),
            messages.ButtonRequest(code=B.ResetDevice),
            messages.ButtonRequest(code=B.ResetDevice),
            messages.Success,
            messages.Features,
        ])
        device.reset(
            client,
            pin_protection=False,
            passphrase_protection=False,
            backup_type=backup_type,
        )

    assert client.features.initialized is True
    assert client.features.needs_backup is True
    assert client.features.unfinished_backup is False
    assert client.features.no_backup is False
    assert client.features.backup_type is backup_type

    secret = backup_flow(client)

    client.init_device()
    assert client.features.initialized is True
    assert client.features.needs_backup is False
    assert client.features.unfinished_backup is False
    assert client.features.backup_type is backup_type

    assert secret is not None
    state = client.debug.state()
    assert state.mnemonic_type is backup_type
    assert state.mnemonic_secret == secret
예제 #21
0
def screen_recording(
        client: Client,
        request: pytest.FixtureRequest) -> Generator[None, None, None]:
    test_ui = request.config.getoption("ui")
    test_name = get_test_name(request.node.nodeid)

    # Differentiating test names between T1 and TT
    # Making the model global for other functions
    global MODEL
    MODEL = f"T{client.features.model}"
    if os.getenv("UI2") == "1":
        MODEL += "ui2"

    test_name = f"{MODEL}_{test_name}"

    screens_test_path = SCREENS_DIR / test_name

    if test_ui == "record":
        screen_path = screens_test_path / "recorded"
    else:
        screen_path = screens_test_path / "actual"

    if not screens_test_path.exists():
        screens_test_path.mkdir()
    # remove previous files
    shutil.rmtree(screen_path, ignore_errors=True)
    screen_path.mkdir()

    try:
        client.debug.start_recording(str(screen_path))
        yield
    finally:
        # Wait for response to Initialize, which gives the emulator time to catch up
        # and redraw the homescreen. Otherwise there's a race condition between that
        # and stopping recording.
        client.init_device()
        client.debug.stop_recording()

    if test_ui:
        PROCESSED.add(test_name)
        if get_last_call_test_result(request) is False:
            FAILED_TESTS.add(test_name)

        if test_ui == "record":
            _process_recorded(screen_path, test_name)
        else:
            _process_tested(screens_test_path, test_name)
def test_remove_pin(client: Client):
    assert client.features.pin_protection is True

    # Check current PIN value
    _check_pin(client, PIN4)

    # Let's remove PIN
    with client:
        client.use_pin_sequence([PIN4])
        client.set_expected_responses([messages.ButtonRequest] * 3 +
                                      [messages.Success, messages.Features])
        device.change_pin(client, remove=True)

    # Check that there's no PIN protection now
    client.init_device()
    assert client.features.pin_protection is False
    _check_no_pin(client)
예제 #23
0
def test_abort(client: Client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - abort process
        debug.press_no()
        yield  # Homescreen - confirm abort
        debug.press_yes()

    with client:
        client.set_input_flow(input_flow)
        with pytest.raises(exceptions.Cancelled):
            device.recover(client, pin_protection=False, label="label")
        client.init_device()
        assert client.features.initialized is False
예제 #24
0
def test_noabort(client: Client):
    debug = client.debug

    def input_flow():
        yield  # Confirm Recovery
        debug.press_yes()
        yield  # Homescreen - abort process
        debug.press_no()
        yield  # Homescreen - go back to process
        debug.press_no()
        yield from recovery_enter_shares(debug, MNEMONIC_SLIP39_BASIC_20_3of6)

    with client:
        client.set_input_flow(input_flow)
        device.recover(client, pin_protection=False, label="label")
        client.init_device()
        assert client.features.initialized is True
def test_change_pin(client: Client):
    assert client.features.pin_protection is True

    # Check current PIN value
    _check_pin(client, PIN4)

    # Let's change PIN
    with client:
        client.use_pin_sequence([PIN4, PIN_MAX, PIN_MAX])
        client.set_expected_responses([messages.ButtonRequest] * 5 +
                                      [messages.Success, messages.Features])
        device.change_pin(client)

    # Check that there's still PIN protection now
    client.init_device()
    assert client.features.pin_protection is True
    # Check that the PIN is correct
    _check_pin(client, PIN_MAX)
def test_set_wipe_code_to_pin(client: Client):
    # Check that wipe code protection status is not revealed in locked state.
    assert client.features.wipe_code_protection is None

    # Let's try setting the wipe code to the curent PIN value.
    with client:
        client.use_pin_sequence([PIN4, PIN4])
        client.set_expected_responses([
            messages.ButtonRequest(),
            messages.PinMatrixRequest(type=PinType.Current),
            messages.PinMatrixRequest(type=PinType.WipeCodeFirst),
            messages.Failure(code=messages.FailureType.ProcessError),
        ])
        with pytest.raises(exceptions.TrezorFailure):
            device.change_wipe_code(client)

    # Check that there is no wipe code protection.
    client.init_device()
    assert client.features.wipe_code_protection is False
def test_set_wipe_code_mismatch(client: Client):
    # Check that there is no wipe code protection.
    client.ensure_unlocked()
    assert client.features.wipe_code_protection is False

    # Let's set a new wipe code.
    with client:
        client.use_pin_sequence([WIPE_CODE4, WIPE_CODE6])
        client.set_expected_responses([
            messages.ButtonRequest(),
            messages.PinMatrixRequest(type=PinType.WipeCodeFirst),
            messages.PinMatrixRequest(type=PinType.WipeCodeSecond),
            messages.Failure(code=messages.FailureType.WipeCodeMismatch),
        ])
        with pytest.raises(exceptions.TrezorFailure):
            device.change_wipe_code(client)

    # Check that there is no wipe code protection.
    client.init_device()
    assert client.features.wipe_code_protection is False
예제 #28
0
def test_change_mismatch(client: Client):
    assert client.features.pin_protection is True

    # Let's set new PIN
    with pytest.raises(TrezorFailure, match="PIN mismatch"), client:
        client.use_pin_sequence([PIN4, PIN6, PIN6 + "3"])
        client.set_expected_responses([
            messages.ButtonRequest(
                code=messages.ButtonRequestType.ProtectCall),
            messages.PinMatrixRequest,
            messages.PinMatrixRequest,
            messages.PinMatrixRequest,
            messages.Failure,
        ])
        device.change_pin(client)

    # Check that there's still old PIN protection
    client.init_device()
    assert client.features.pin_protection is True
    _check_pin(client, PIN4)
def test_set_wipe_code_invalid(client: Client, invalid_wipe_code):
    # Let's set the wipe code
    ret = client.call_raw(messages.ChangeWipeCode())
    assert isinstance(ret, messages.ButtonRequest)

    # Confirm
    client.debug.press_yes()
    ret = client.call_raw(messages.ButtonAck())

    # Enter a wipe code containing an invalid digit
    assert isinstance(ret, messages.PinMatrixRequest)
    assert ret.type == PinType.WipeCodeFirst
    ret = client.call_raw(messages.PinMatrixAck(pin=invalid_wipe_code))

    # Ensure the invalid wipe code is detected
    assert isinstance(ret, messages.Failure)

    # Check that there's still no wipe code protection.
    client.init_device()
    client.ensure_unlocked()
    assert client.features.wipe_code_protection is False
def test_set_pin_to_wipe_code(client: Client):
    # Set wipe code.
    _set_wipe_code(client, None, WIPE_CODE4)

    # Try to set the PIN to the current wipe code value.
    with client:
        client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4])
        client.set_expected_responses([
            messages.ButtonRequest(),
            messages.PinMatrixRequest(type=PinType.NewFirst),
            messages.PinMatrixRequest(type=PinType.NewSecond),
            messages.Failure(code=messages.FailureType.ProcessError),
        ])
        with pytest.raises(exceptions.TrezorFailure):
            device.change_pin(client)

    # Check that there is no PIN protection.
    client.init_device()
    assert client.features.pin_protection is False
    resp = client.call_raw(messages.GetAddress())
    assert isinstance(resp, messages.Address)