"""SIGN_MESSAGE, which had no functional coverage at all before.""" import pytest from ecdsa import SECP256k1, VerifyingKey from ecdsa.util import sigdecode_string from ragger.error import ExceptionRAPDU from application_client.handshake_command_sender import Errors, HandshakeCommandSender from application_client.handshake_response_unpacker import ( unpack_get_public_key_response, unpack_sign_message_response, ) from application_client.handshake_sighash import blake2b_256 from .review_nav import approve_review PATH = "m/44'/5353'/0'/0/0" #: The device prepends this before hashing, matching shd's `verifymessage`. MESSAGE_PREFIX = b"handshake signed message:\n" def test_sign_message_accepted(backend, device, navigator, default_screenshot_path, test_name): client = HandshakeCommandSender(backend) pubkey, _, _ = unpack_get_public_key_response(client.get_public_key(path=PATH).data) message = b"hello handshake" with client.sign_message(path=PATH, message=message): approve_review(device, navigator, default_screenshot_path, test_name) _, signature, returned_pubkey = unpack_sign_message_response( client.get_async_response().data) assert returned_pubkey == pubkey digest = blake2b_256(MESSAGE_PREFIX + message) vk = VerifyingKey.from_string(pubkey, curve=SECP256k1) assert vk.verify_digest(signature, digest, sigdecode=sigdecode_string) def test_sign_message_refused(backend, scenario_navigator): client = HandshakeCommandSender(backend) with pytest.raises(ExceptionRAPDU) as e: with client.sign_message(path=PATH, message=b"hello handshake"): scenario_navigator.review_reject() assert e.value.status == Errors.SW_DENY def test_sign_message_rejects_out_of_policy_path(backend): client = HandshakeCommandSender(backend) with pytest.raises(ExceptionRAPDU) as e: with client.sign_message(path="m/44'/1'/0'/0/0", message=b"hi"): pass assert e.value.status == Errors.SW_BAD_DERIVATION_PATH def test_sign_message_rejects_truncated_payload(backend): """A declared message length longer than the bytes that follow. `MAX_MESSAGE_LEN` is 512, but a single APDU carries at most 255 data bytes, so the length cap is unreachable and the bounds check in the reader is what actually protects here. """ from application_client.handshake_command_sender import CLA, InsType from ragger.bip import pack_derivation_path payload = pack_derivation_path(PATH) + (200).to_bytes(2, "little") + b"A" * 10 with pytest.raises(ExceptionRAPDU) as e: backend.exchange(cla=CLA, ins=InsType.SIGN_MESSAGE, p1=0, p2=0, data=payload) assert e.value.status == Errors.SW_TX_WRONG_LENGTH