1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-30 17:21:21 +00:00

feat(core, python): implement nfc pairing for tests, add device test

[no changelog]
This commit is contained in:
M1nd3r 2025-01-30 13:10:13 +01:00
parent 7bdaa2dfad
commit 76e3ce611e
2 changed files with 77 additions and 7 deletions

View File

@ -221,10 +221,6 @@ async def _handle_code_entry_is_selected_first_time(ctx: PairingContext) -> None
@check_state_and_log(ChannelState.TP1)
async def _handle_nfc_is_selected(ctx: PairingContext) -> None:
ctx.nfc_secret = random.bytes(16)
sha_ctx = sha256(ctx.channel_ctx.get_handshake_hash())
sha_ctx.update(ctx.nfc_secret)
sha_ctx.update(bytes("PairingMethod_NfcUnidirectional", "utf-8"))
ctx.display_data.code_nfc = sha_ctx.digest()[:16]
await ctx.write_force(ThpPairingPreparationsFinished())
@ -327,9 +323,13 @@ async def _handle_nfc_tag(
) -> protobuf.MessageType:
if TYPE_CHECKING:
assert isinstance(message, ThpNfcTagHost)
assert ctx.nfc_secret is not None
assert ctx.handshake_hash_host is not None
assert ctx.nfc_secret_host is not None
sha_ctx = sha256(ThpPairingMethod.NFC.to_bytes(1, "big"))
sha_ctx.update(ctx.channel_ctx.get_handshake_hash())
assert ctx.nfc_secret is not None
sha_ctx.update(ctx.nfc_secret)
expected_tag = sha_ctx.digest()
if expected_tag != message.tag:
@ -338,10 +338,12 @@ async def _handle_nfc_tag(
) # TODO remove after testing
raise ThpError("Unexpected NFC Unidirectional Tag")
if ctx.handshake_hash_host[:16] != ctx.channel_ctx.get_handshake_hash()[:16]:
raise ThpError("Handshake hash mismatch")
sha_ctx = sha256(ThpPairingMethod.NFC.to_bytes(1, "big"))
sha_ctx.update(ctx.channel_ctx.get_handshake_hash())
# TODO add Host's secret from NFC message transferred over NFC
# sha_ctx.update(host's secret)
sha_ctx.update(ctx.nfc_secret_host)
trezor_tag = sha_ctx.digest()
return await _handle_secret_reveal(
ctx,

View File

@ -18,6 +18,8 @@ from trezorlib.messages import (
ThpCodeEntrySecret,
ThpEndRequest,
ThpEndResponse,
ThpNfcTagHost,
ThpNfcTagTrezor,
ThpPairingMethod,
ThpPairingPreparationsFinished,
ThpPairingRequest,
@ -252,3 +254,69 @@ def test_pairing_code_entry(client: Client) -> None:
_read_message(ThpEndResponse)
protocol._has_valid_channel = True
def test_pairing_nfc(client: Client) -> None:
global protocol
_prepare_protocol(client)
# Generate ephemeral keys
host_ephemeral_privkey = curve25519.get_private_key(os.urandom(32))
host_ephemeral_pubkey = curve25519.get_public_key(host_ephemeral_privkey)
protocol._do_channel_allocation()
protocol._do_handshake(host_ephemeral_privkey, host_ephemeral_pubkey)
_send_message(ThpPairingRequest())
_read_message(ButtonRequest)
_send_message(ButtonAck())
client.debug.press_yes()
_read_message(ThpPairingRequestApproved)
_send_message(ThpSelectMethod(selected_pairing_method=ThpPairingMethod.NFC))
_read_message(ThpPairingPreparationsFinished)
# NFC screen shown
_read_message(ButtonRequest)
_send_message(ButtonAck())
nfc_secret_host = b"\x02\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF" # TODO generate randomly
# Read `nfc_secret` and `handshake_hash` from Trezor using debuglink
pairing_info = client.debug.pairing_info(
thp_channel_id=protocol.channel_id.to_bytes(2, "big"),
handshake_hash=protocol.handshake_hash,
nfc_secret_host=nfc_secret_host,
)
handshake_hash_trezor = pairing_info.handshake_hash
nfc_secret_trezor = pairing_info.nfc_secret_trezor
assert handshake_hash_trezor[:16] == protocol.handshake_hash[:16]
# Compute tag for response
sha_ctx = hashlib.sha256(ThpPairingMethod.NFC.to_bytes(1, "big"))
sha_ctx.update(protocol.handshake_hash)
sha_ctx.update(nfc_secret_trezor)
tag_host = sha_ctx.digest()
_send_message(ThpNfcTagHost(tag=tag_host))
tag_trezor_msg = _read_message(ThpNfcTagTrezor)
# Check that the `code` was derived from the revealed secret
sha_ctx = hashlib.sha256(ThpPairingMethod.NFC.to_bytes(1, "big"))
sha_ctx.update(protocol.handshake_hash)
sha_ctx.update(nfc_secret_host)
computed_tag = sha_ctx.digest()
assert tag_trezor_msg.tag == computed_tag
_send_message(ThpEndRequest())
_read_message(ThpEndResponse)
protocol._has_valid_channel = True