From 21ba7dcd8596fcc2488e17229330fcd5853a049d Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 20 Sep 2026 17:20:23 -0500 Subject: [PATCH 1/3] test(eos): require corrected 7.15 updateauth digest --- tests/test_msg_eos_signtx.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_msg_eos_signtx.py b/tests/test_msg_eos_signtx.py index f04c990d..6c3bbff0 100644 --- a/tests/test_msg_eos_signtx.py +++ b/tests/test_msg_eos_signtx.py @@ -568,7 +568,9 @@ def test_updateauth(self): num_actions=1), [self.action_updateauth(True)]) - self.assertEqual(binascii.hexlify(res.hash), "fb936ef1be4bda680d93bd10b6d062357d8dd7272038a706dc0d61a91f39c5ee") + # Firmware 7.15 serializes waits_count here. The historical golden + # hashed a phantom zero wait by iterating accounts_count instead. + self.assertEqual(binascii.hexlify(res.hash), "5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1") def test_deleteauth(self): self.requires_fullFeature() From 223bae604266d328bd81a99ca5e3051eb62edf24 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 20 Sep 2026 17:28:38 -0500 Subject: [PATCH 2/3] test(solana): align 7.15 plain-text policy --- tests/test_msg_solana_signtx.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/test_msg_solana_signtx.py b/tests/test_msg_solana_signtx.py index 1c4a8cda..ff45bd09 100644 --- a/tests/test_msg_solana_signtx.py +++ b/tests/test_msg_solana_signtx.py @@ -73,6 +73,7 @@ def setUp(self): def setup_mnemonic_allallall(self): policy_negative = self._testMethodName in { "test_solana_sign_message_blocked_without_advanced_mode", + "test_solana_sign_plain_text_message_without_advanced_mode", "test_solana_sign_malformed_bad_account_count", "test_solana_sign_versioned_v0_opaque", } @@ -153,9 +154,11 @@ def test_solana_sign_message(self): self.client.apply_policy('AdvancedMode', False) def test_solana_sign_message_blocked_without_advanced_mode(self): - """Solana message signing BLOCKED without AdvancedMode. + """Non-text Solana message signing BLOCKED without AdvancedMode. Without domain separation, a signed message is indistinguishable from - a signed transaction. Device refuses to sign without explicit opt-in.""" + a signed transaction. Device refuses to sign without explicit opt-in. + The payload is binary so this remains true when bounded plain text is + allowed.""" self.requires_firmware("7.14.0") self.requires_fullFeature() self.requires_message("SolanaSignMessage") @@ -165,10 +168,27 @@ def test_solana_sign_message_blocked_without_advanced_mode(self): with pytest.raises(CallException) as exc: self.client.call(messages.SolanaSignMessage( address_n=parse_path("m/44'/501'/0'/0'"), - message=b"Hello Solana!", + message=b"\x01\x00\x01\x02" + b"\x00" * 64, )) self.assertIn("disabled by policy", str(exc.value)) + def test_solana_sign_plain_text_message_without_advanced_mode(self): + """Bounded printable login text signs without AdvancedMode.""" + self.requires_firmware("7.15.0") + self.requires_fullFeature() + self.requires_message("SolanaSignMessage") + self.setup_mnemonic_allallall() + self.client.apply_policy('AdvancedMode', False) + + text = (b"example.com wants you to sign in with your Solana account:\n" + b"Sign in to Example.\n\nNonce: 9d9972a1f2ed0aaa") + resp = self.client.call(messages.SolanaSignMessage( + address_n=parse_path("m/44'/501'/0'/0'"), + message=text, + )) + self.assertEqual(len(resp.signature), 64) + self.assertEqual(len(resp.public_key), 32) + def test_solana_sign_empty_rejected(self): """Test that empty raw_tx is rejected.""" self.requires_fullFeature() From 7b26468b165a04f4ebdafe9ee7ebd2a0023e0155 Mon Sep 17 00:00:00 2001 From: highlander Date: Sun, 20 Sep 2026 17:36:27 -0500 Subject: [PATCH 3/3] test(7.15): gate release-only signing policies --- tests/test_msg_eos_signtx.py | 12 +++++++++--- tests/test_msg_ethereum_erc20_approve.py | 1 + tests/test_msg_ethereum_erc20_uniswap_liquidity.py | 2 +- tests/test_msg_signtx_ethereum_erc20.py | 1 + 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/test_msg_eos_signtx.py b/tests/test_msg_eos_signtx.py index 6c3bbff0..1b9610ab 100644 --- a/tests/test_msg_eos_signtx.py +++ b/tests/test_msg_eos_signtx.py @@ -568,9 +568,15 @@ def test_updateauth(self): num_actions=1), [self.action_updateauth(True)]) - # Firmware 7.15 serializes waits_count here. The historical golden - # hashed a phantom zero wait by iterating accounts_count instead. - self.assertEqual(binascii.hexlify(res.hash), "5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1") + # Firmware 7.15 serializes waits_count here. Older firmware hashed a + # phantom zero wait by iterating accounts_count instead. + version = (self.client.features.major_version, + self.client.features.minor_version, + self.client.features.patch_version) + expected = ("5938294e65cf9e8b5dd5f2b204503b4825f277e6f4a2d5ab7a55a31065a23af1" + if version >= (7, 15, 0) + else "fb936ef1be4bda680d93bd10b6d062357d8dd7272038a706dc0d61a91f39c5ee") + self.assertEqual(binascii.hexlify(res.hash), expected) def test_deleteauth(self): self.requires_fullFeature() diff --git a/tests/test_msg_ethereum_erc20_approve.py b/tests/test_msg_ethereum_erc20_approve.py index 9fdba114..e69fdec5 100644 --- a/tests/test_msg_ethereum_erc20_approve.py +++ b/tests/test_msg_ethereum_erc20_approve.py @@ -69,6 +69,7 @@ def test_approve_cvc_0(self): def test_approve_cvc_all(self): self.requires_fullFeature() + self.requires_firmware("7.15.0") self.setup_mnemonic_nopin_nopassphrase() with self.assertRaises(CallException) as caught: diff --git a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py index bb2c1049..ab4d9cd6 100644 --- a/tests/test_msg_ethereum_erc20_uniswap_liquidity.py +++ b/tests/test_msg_ethereum_erc20_uniswap_liquidity.py @@ -29,7 +29,7 @@ class TestMsgEthereumUniswaptxERC20(common.KeepKeyTest): def test_sign_uni_approve_liquidity_ETH(self): self.requires_fullFeature() - self.requires_firmware("7.1.0") + self.requires_firmware("7.15.0") self.setup_mnemonic_nopin_nopassphrase() self.client.apply_policy("AdvancedMode", 1) diff --git a/tests/test_msg_signtx_ethereum_erc20.py b/tests/test_msg_signtx_ethereum_erc20.py index 73a671af..79ce8b2c 100644 --- a/tests/test_msg_signtx_ethereum_erc20.py +++ b/tests/test_msg_signtx_ethereum_erc20.py @@ -69,6 +69,7 @@ def test_approve_some(self): def test_approve_all(self): self.requires_fullFeature() + self.requires_firmware("7.15.0") self.setup_mnemonic_nopin_nopassphrase() with self.assertRaises(CallException) as caught: