What changed, and why it matters
This commit is a routine cleanup after merging (rebasing) other Cardano code changes. It updates the Cardano message-signing flow to use newer internal APIs (sessions instead of raw clients, and a separate SLIP-21 keychain argument) and refreshes automated test snapshots. There is no indication it fixes or introduces a security vulnerability.
No security action required; treat as normal maintenance. Reviewers may verify the new session-based call wrappers preserve prior behavior and that the added slip21_keychain argument is correctly wired in the calling code path.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is a refactor of Cardano sign_message plumbing: core/src/apps/cardano/sign_message.py adds a slip21_keychain parameter and type alias; python/src/trezorlib/cardano.py switches from client.call to session.call with explicit expect= message types; python/src/trezorlib/cli/cardano.py uses @with_session(derive_cardano=True) instead of @with_client plus client.init_device; tests are updated to use SessionDebugWrapper and new UI fixtures are added. No cryptographic, validation, or authorization logic changes are visible.
Changed components
core/src/apps/cardano/sign_message.pypython/src/trezorlib/cardano.pypython/src/trezorlib/cli/cardano.pytests/device_tests/cardano/test_sign_message.pytests/ui_tests/fixtures.jsonInspect captured patch +41 / −37
diff --git a/core/src/apps/cardano/sign_message.py b/core/src/apps/cardano/sign_message.py
index edf01fb8..98579c97 100644
--- a/core/src/apps/cardano/sign_message.py
+++ b/core/src/apps/cardano/sign_message.py
@@ -20,6 +20,7 @@ if TYPE_CHECKING:
from apps.common.cbor import CborSequence
Headers = dict[str | int, Any]
+ from apps.common.keychain import Keychain as Slip21Keychain
_COSE_HEADER_ADDRESS_KEY = "address"
_COSE_HEADER_ALGORITHM_KEY = const(1)
@@ -152,7 +153,9 @@ def _sign_sig_structure(
@seed.with_keychain
async def sign_message(
- msg: CardanoSignMessageInit, keychain: seed.Keychain
+ msg: CardanoSignMessageInit,
+ keychain: seed.Keychain,
+ slip21_keychain: "Slip21Keychain",
) -> CardanoSignMessageFinished:
from trezor.messages import CardanoSignMessageFinished
diff --git a/python/src/trezorlib/cardano.py b/python/src/trezorlib/cardano.py
index 900a94a3..31f5ca5e 100644
--- a/python/src/trezorlib/cardano.py
+++ b/python/src/trezorlib/cardano.py
@@ -330,7 +330,7 @@ def _parse_address_parameters(
def parse_optional_address_parameters(
address_parameters: Optional[dict],
-) -> Optional[messages.CardanoAddressParametersType]:
+) -> Optional[m.CardanoAddressParametersType]:
if address_parameters is None:
return None
@@ -1021,22 +1021,21 @@ def sign_tx(
def sign_message(
- client: "TrezorClient",
+ session: "Session",
signing_path: Path,
payload: bytes,
hash_payload: bool,
prefer_hex_display: bool,
- address_parameters: Optional[messages.CardanoAddressParametersType] = None,
- derivation_type: messages.CardanoDerivationType = messages.CardanoDerivationType.ICARUS,
+ address_parameters: Optional[m.CardanoAddressParametersType] = None,
+ derivation_type: m.CardanoDerivationType = m.CardanoDerivationType.ICARUS,
protocol_magic: Optional[int] = None,
network_id: Optional[int] = None,
-) -> messages.CardanoSignMessageFinished:
- UNEXPECTED_RESPONSE_ERROR = exceptions.TrezorException("Unexpected response")
+) -> m.CardanoSignMessageFinished:
- size, chunks = _parse_chunkable_data(payload, messages.CardanoMessagePayloadChunk)
+ size, chunks = _parse_chunkable_data(payload, m.CardanoMessagePayloadChunk)
- response = client.call(
- messages.CardanoSignMessageInit(
+ response = session.call(
+ m.CardanoSignMessageInit(
signing_path=signing_path,
payload_size=size,
hash_payload=hash_payload,
@@ -1045,20 +1044,13 @@ def sign_message(
protocol_magic=protocol_magic,
network_id=network_id,
derivation_type=derivation_type,
- )
+ ),
+ expect=m.CardanoMessageItemAck,
)
- if not isinstance(response, messages.CardanoMessageItemAck):
- raise UNEXPECTED_RESPONSE_ERROR
-
for chunk in chunks:
- chunk_response = client.call(chunk)
- if not isinstance(chunk_response, messages.CardanoMessageItemAck):
- raise UNEXPECTED_RESPONSE_ERROR
-
- final_response = client.call(messages.CardanoMessageItemHostAck())
-
- if not isinstance(final_response, messages.CardanoSignMessageFinished):
- raise UNEXPECTED_RESPONSE_ERROR
+ session.call(chunk, expect=m.CardanoMessageItemAck)
- return final_response
+ return session.call(
+ m.CardanoMessageItemHostAck(), expect=m.CardanoSignMessageFinished
+ )
diff --git a/python/src/trezorlib/cli/cardano.py b/python/src/trezorlib/cli/cardano.py
index cd207aa6..6208e7c6 100644
--- a/python/src/trezorlib/cli/cardano.py
+++ b/python/src/trezorlib/cli/cardano.py
@@ -333,18 +333,17 @@ def get_native_script_hash(
type=ChoiceType({m.name: m for m in messages.CardanoDerivationType}),
default=messages.CardanoDerivationType.ICARUS,
)
-@with_client
+@with_session(derive_cardano=True)
def sign_message(
- client: "TrezorClient",
+ session: "Session",
file: TextIO,
derivation_type: messages.CardanoDerivationType,
) -> messages.CardanoSignMessageFinished:
"""Sign Cardano message containing arbitrary data."""
request: dict[Any, Any] = json.load(file)
- client.init_device(derive_cardano=True)
return cardano.sign_message(
- client,
+ session,
payload=bytes.fromhex(request["payload"]),
hash_payload=request["hash_payload"],
prefer_hex_display=request["prefer_hex_display"],
diff --git a/tests/device_tests/cardano/test_sign_message.py b/tests/device_tests/cardano/test_sign_message.py
index 86a643b7..0188f880 100644
--- a/tests/device_tests/cardano/test_sign_message.py
+++ b/tests/device_tests/cardano/test_sign_message.py
@@ -1,7 +1,7 @@
import pytest
from trezorlib import cardano, messages, tools
-from trezorlib.debuglink import TrezorClientDebugLink as Client
+from trezorlib.debuglink import SessionDebugWrapper as Session
from trezorlib.exceptions import TrezorFailure
from ...common import parametrize_using_common_fixtures
@@ -14,26 +14,24 @@ pytestmark = [
@parametrize_using_common_fixtures("cardano/sign_message.json")
-def test_cardano_sign_message(client: Client, parameters, result):
- response = call_sign_message(client, parameters)
+def test_cardano_sign_message(session: Session, parameters, result):
+ response = call_sign_message(session, parameters)
assert response == _transform_expected_result(result)
@parametrize_using_common_fixtures("cardano/sign_message.failed.json")
-def test_cardano_sign_message_failed(client: Client, parameters, result):
+def test_cardano_sign_message_failed(session: Session, parameters, result):
with pytest.raises(TrezorFailure, match=result["error_message"]):
- call_sign_message(client, parameters)
+ call_sign_message(session, parameters)
def call_sign_message(
- client: Client,
+ session: Session,
parameters,
) -> messages.CardanoSignMessageFinished:
- client.init_device(new_session=True, derive_cardano=True)
-
- with client:
+ with session.client:
return cardano.sign_message(
- client,
+ session=session,
payload=bytes.fromhex(parameters["payload"]),
hash_payload=parameters["hash_payload"],
prefer_hex_display=parameters["prefer_hex_display"],
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index ef9ddac8..189ade1e 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -4775,6 +4775,18 @@
"T2T1_en_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[nested_script_w-789238e6": "3b24b2bd4189f9bf9bac54636aa1326ff888de9eec3ce0bd47b8b9bfa6c9a4cb",
"T2T1_en_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script]": "85ddca2717fb3723e1389b8f8d6d23378aa276e4dfd4df937eb4d20541c1ce56",
"T2T1_en_cardano-test_get_native_script_hash.py::test_cardano_get_native_script_hash[pub_key_script_-1579fe2a": "86267107419ea723cb89eeb09afecef96bdb8682175a24445d14dc0224dbb7fb",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[ambiguous_ascii_payload_falls_back_to_hex]": "70e89a43a3db6f42cce715a7e63ba70e1114dbe531400936c5441e04e0787a8e",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[non-ascii_payload_falls_back_to_hex]": "2d4712e66b63f90c5dda380cfbb6b82b824bdc4e22713c84d1e0f22164b33819",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_empty_payload]": "2de9116c5979a808e3f1507bdbc037155a6fe0be41be9dea74fbe40a3749be3d",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_empty_payload_hash]": "f719612b4903f74aeeef1cf8ecad21cf744a919bae21c25667915708e85fd931",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_long_ascii_payload_hash]": "396b51143a83cedd45e359410d2a445205588825c9a7b6cbd41e9cc0c75d4efb",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_ascii_payload]": "cb81e264c7add093d24743a769621b235f923f7a20afa122f8786086df415919",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_ascii_payload_rendered_as_hex]": "d64a7592306207a6778c45eaeec8cef08cdc30f5d0d8b09834b73421734d9bd8",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_non-ascii_payload]": "8698f74946e7fba97a9c6a427d8b0aefeac65291d3cbcb6095a08c0b32fab72b",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_non-ascii_payload_hash]": "61818bbd8095343382190f7b983cf7eaca996999681f68cd4b4b85f18f9a7949",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_non-ascii_payload_with_a-1f337ea4": "070c21dbcde8e14ae33a5de627ea205485b18455d23ecbfa67cc4eaf0e3d4936",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[missing_network_id_and_proto-21ec11cf": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[unhashed_payload_too_long]": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_cardano-test_sign_tx.py::test_cardano_sign_tx[byron_to_shelley_transfer]": "2ebaaf8458ac58fe0a9237238299dae01927bce1a29b5695510d039034134602",
"T2T1_en_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "7a20525b47412bf3835dd4fc5374166342dba4492a35d40761291d9c8089a617",
"T2T1_en_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change1]": "d2d450949f9d79cfe08c6878207fbabe8383d271a2f28459bc38c19ecc251d22",
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.