-
Notifications
You must be signed in to change notification settings - Fork 32
/
test_sign_cmd.py
161 lines (133 loc) · 7.4 KB
/
test_sign_cmd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import pytest
from application_client.boilerplate_transaction import Transaction
from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors
from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response
from ragger.error import ExceptionRAPDU
from ragger.navigator import NavIns, NavInsID
from utils import ROOT_SCREENSHOT_PATH, check_signature_validity
# In these tests we check the behavior of the device when asked to sign a transaction
# In this test a transaction is sent to the device to be signed and validated on screen.
# The transaction is short and will be sent in one chunk.
# We will ensure that the displayed information is correct by using screenshots comparison.
def test_sign_tx_short_tx(backend, scenario_navigator, firmware, navigator):
# Use the app interface instead of raw interface
client = BoilerplateCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/1'/0'/0/0"
# First we need to get the public key of the device in order to build the transaction
rapdu = client.get_public_key(path=path)
_, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
# Create the transaction that will be sent to the device for signing
transaction = Transaction(
nonce=1,
coin="CRAB",
value=777,
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo="For u EthDev"
).serialize()
# Enable display of transaction memo (NBGL devices only)
if not firmware.device.startswith("nano"):
navigator.navigate([NavInsID.USE_CASE_HOME_SETTINGS,
NavIns(NavInsID.TOUCH, (200, 113)),
NavInsID.USE_CASE_SUB_SETTINGS_EXIT],
screen_change_before_first_instruction=False,
screen_change_after_last_instruction=False)
# Send the sign device instruction.
# As it requires on-screen validation, the function is asynchronous.
# It will yield the result when the navigation is done
with client.sign_tx(path=path, transaction=transaction):
# Validate the on-screen request by performing the navigation appropriate for this device
scenario_navigator.review_approve()
# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _ = unpack_sign_tx_response(response)
assert check_signature_validity(public_key, der_sig, transaction)
# In this test a transaction is sent to the device to be signed and validated on screen.
# The transaction is short and will be sent in one chunk
# We will ensure that the displayed information is correct by using screenshots comparison
# The transaction memo should not be displayed as we have not enabled it in the app settings.
def test_sign_tx_short_tx_no_memo(backend, scenario_navigator, firmware):
if firmware.device.startswith("nano"):
pytest.skip("Skipping this test for Nano devices")
# Use the app interface instead of raw interface
client = BoilerplateCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/1'/0'/0/0"
# First we need to get the public key of the device in order to build the transaction
rapdu = client.get_public_key(path=path)
_, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
# Create the transaction that will be sent to the device for signing
transaction = Transaction(
nonce=1,
coin="CRAB",
value=777,
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo="For u EthDev"
).serialize()
# Send the sign device instruction.
# As it requires on-screen validation, the function is asynchronous.
# It will yield the result when the navigation is done
with client.sign_tx(path=path, transaction=transaction):
# Validate the on-screen request by performing the navigation appropriate for this device
scenario_navigator.review_approve()
# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _ = unpack_sign_tx_response(response)
assert check_signature_validity(public_key, der_sig, transaction)
# In this test a transaction is sent to the device to be signed and validated on screen.
# This test is mostly the same as the previous one but with different values.
# In particular the long memo will force the transaction to be sent in multiple chunks
# def test_sign_tx_long_tx(firmware, backend, navigator, test_name):
def test_sign_tx_long_tx(backend, scenario_navigator, firmware, navigator):
# Use the app interface instead of raw interface
client = BoilerplateCommandSender(backend)
path: str = "m/44'/1'/0'/0/0"
rapdu = client.get_public_key(path=path)
_, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
transaction = Transaction(
nonce=1,
coin="CRAB",
value=666,
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo=("This is a very long memo. "
"It will force the app client to send the serialized transaction to be sent in chunk. "
"As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. "
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.")
).serialize()
# Enable display of transaction memo (NBGL devices only)
if not firmware.device.startswith("nano"):
navigator.navigate([NavInsID.USE_CASE_HOME_SETTINGS,
NavIns(NavInsID.TOUCH, (200, 113)),
NavInsID.USE_CASE_SUB_SETTINGS_EXIT],
screen_change_before_first_instruction=False,
screen_change_after_last_instruction=False)
# Send the sign device instruction.
# As it requires on-screen validation, the function is asynchronous.
# It will yield the result when the navigation is done
with client.sign_tx(path=path, transaction=transaction):
# Validate the on-screen request by performing the navigation appropriate for this device
scenario_navigator.review_approve()
response = client.get_async_response().data
_, der_sig, _ = unpack_sign_tx_response(response)
assert check_signature_validity(public_key, der_sig, transaction)
# Transaction signature refused test
# The test will ask for a transaction signature that will be refused on screen
def test_sign_tx_refused(backend, scenario_navigator):
# Use the app interface instead of raw interface
client = BoilerplateCommandSender(backend)
path: str = "m/44'/1'/0'/0/0"
rapdu = client.get_public_key(path=path)
_, pub_key, _, _ = unpack_get_public_key_response(rapdu.data)
transaction = Transaction(
nonce=1,
coin="CRAB",
value=666,
to="de0b295669a9fd93d5f28d9ec85e40f4cb697bae",
memo="This transaction will be refused by the user"
).serialize()
with pytest.raises(ExceptionRAPDU) as e:
with client.sign_tx(path=path, transaction=transaction):
scenario_navigator.review_reject()
# Assert that we have received a refusal
assert e.value.status == Errors.SW_DENY
assert len(e.value.data) == 0