-
Notifications
You must be signed in to change notification settings - Fork 5
/
test_sign_personal_message_cmd.py
187 lines (154 loc) · 9.45 KB
/
test_sign_personal_message_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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from application_client.kaspa_command_sender import KaspaCommandSender, Errors, InsType, P1, P2
from application_client.kaspa_message import PersonalMessage
from application_client.kaspa_response_unpacker import unpack_get_public_key_response, unpack_sign_message_response
from ragger.backend import RaisePolicy
from ragger.navigator import NavInsID
from utils import ROOT_SCREENSHOT_PATH, check_signature_validity
# In this tests we check the behavior of the device when asked to sign a transaction
# In this test se send to the device a transaction to sign and validate it on screen
# We will ensure that the displayed information is correct by using screenshots comparison
def test_sign_message_simple(firmware, backend, navigator, test_name):
# Use the app interface instead of raw interface
client = KaspaCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/111111'/0'/1/5"
# 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)
address_type = 1
address_index = 5
message = "Hello Kaspa!"
message_data = PersonalMessage(message, address_type, address_index)
# 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_message(message_data=message_data):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Approve",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _, message_hash = unpack_sign_message_response(response)
assert message_hash == message_data.to_hash()
assert check_signature_validity(public_key, der_sig, message_hash)
def test_sign_message_simple_different_account(firmware, backend, navigator, test_name):
# Use the app interface instead of raw interface
client = KaspaCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/111111'/1'/1/5"
# 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)
address_type = 1
address_index = 5
account = 0x80000001 # This is account 1'
message = "Hello Kaspa!"
message_data = PersonalMessage(message, address_type, address_index, account)
# 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_message(message_data=message_data):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Approve",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _, message_hash = unpack_sign_message_response(response)
assert message_hash == message_data.to_hash()
assert check_signature_validity(public_key, der_sig, message_hash)
def test_sign_message_kanji(firmware, backend, navigator, test_name):
# Use the app interface instead of raw interface
client = KaspaCommandSender(backend)
# The path used for this entire test
path: str = "m/44'/111111'/0'/1/3"
# 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)
address_type = 1
address_index = 3
message = "こんにちは世界"
message_data = PersonalMessage(message, address_type, address_index)
# 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_message(message_data=message_data):
# Validate the on-screen request by performing the navigation appropriate for this device
if firmware.device.startswith("nano"):
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Approve",
ROOT_SCREENSHOT_PATH,
test_name)
else:
navigator.navigate_until_text_and_compare(NavInsID.USE_CASE_REVIEW_TAP,
[NavInsID.USE_CASE_REVIEW_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS],
"Hold to sign",
ROOT_SCREENSHOT_PATH,
test_name)
# The device as yielded the result, parse it and ensure that the signature is correct
response = client.get_async_response().data
_, der_sig, _, message_hash = unpack_sign_message_response(response)
assert message_hash == message_data.to_hash()
assert check_signature_validity(public_key, der_sig, message_hash)
def test_sign_message_too_long(firmware, backend, navigator, test_name):
backend.raise_policy = RaisePolicy.RAISE_NOTHING
# Use the app interface instead of raw interface
client = KaspaCommandSender(backend)
address_type = 1
address_index = 4
message = '''Lorem ipsum dolor sit amet. Aut omnis amet id voluptatem eligendi sit accusantium dolorem 33 corrupti necessitatibus hic consequatur quod et maiores alias non molestias suscipit? Est voluptatem magni qui odit eius est eveniet cupiditate id eius'''
message_data = PersonalMessage(message, address_type, address_index)
last_response = client.send_raw_apdu(InsType.SIGN_MESSAGE, p1=P1.P1_INPUTS, p2=P2.P2_LAST, data=message_data.serialize())
assert last_response.status == Errors.SW_MESSAGE_TOO_LONG
def test_sign_message_refused(firmware, backend, navigator, test_name):
# Use the app interface instead of raw interface
client = KaspaCommandSender(backend)
address_type = 1
address_index = 6
message = "Hello Kaspa!"
message_data = PersonalMessage(message, address_type, address_index)
if firmware.device.startswith("nano"):
with client.sign_message(message_data=message_data):
# Disable raising when trying to unpack an error APDU
backend.raise_policy = RaisePolicy.RAISE_NOTHING
navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK,
[NavInsID.BOTH_CLICK],
"Reject",
ROOT_SCREENSHOT_PATH,
test_name)
assert client.get_async_response().status == Errors.SW_DENY
else:
for i in range(3):
instructions = [NavInsID.USE_CASE_REVIEW_TAP] * i
instructions += [NavInsID.USE_CASE_REVIEW_REJECT,
NavInsID.USE_CASE_CHOICE_CONFIRM,
NavInsID.USE_CASE_STATUS_DISMISS]
with client.sign_message(message_data=message_data):
backend.raise_policy = RaisePolicy.RAISE_NOTHING
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH,
test_name + f"/part{i}",
instructions)
assert client.get_async_response().status == Errors.SW_DENY