Skip to content

Commit 658c3a3

Browse files
Merge pull request #127 from LedgerHQ/tdj/add_blindsign_flow_example
Add an example of Blind-sign flow for Stax/Flex
2 parents 5d88a46 + f0a6eb0 commit 658c3a3

File tree

18 files changed

+95
-11
lines changed

18 files changed

+95
-11
lines changed

src/handler/sign_tx.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,17 @@ int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more) {
8989

9090
PRINTF("Hash: %.*H\n", sizeof(G_context.tx_info.m_hash), G_context.tx_info.m_hash);
9191

92-
return ui_display_transaction();
92+
// Example to trig a blind-sign flow
93+
if (strcmp((char *) G_context.tx_info.transaction.memo, "Blind-sign") == 0) {
94+
// to remove when Nbgl will be available for Nanos
95+
#ifdef HAVE_NBGL
96+
return ui_display_blind_signed_transaction();
97+
#else
98+
return ui_display_transaction();
99+
#endif
100+
} else {
101+
return ui_display_transaction();
102+
}
93103
}
94104
}
95105

src/ui/display.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ int ui_display_address(void);
2222
*
2323
*/
2424
int ui_display_transaction(void);
25+
26+
/**
27+
* Display blind-sign transaction information on the device and ask confirmation to sign.
28+
*
29+
* @return 0 if success, negative integer otherwise.
30+
*
31+
*/
32+
int ui_display_blind_signed_transaction(void);

src/ui/nbgl_display_transaction.c

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ static void review_choice(bool confirm) {
6060
// - Check if the app is in the right state for transaction review
6161
// - Format the amount and address strings in g_amount and g_address buffers
6262
// - Display the first screen of the transaction review
63-
int ui_display_transaction() {
63+
// - Display a warning if the transaction is blind-signed
64+
int ui_display_transaction_bs_choice(bool is_blind_signed) {
6465
if (G_context.req_type != CONFIRM_TRANSACTION || G_context.state != STATE_PARSED) {
6566
G_context.state = STATE_NONE;
6667
return io_send_sw(SW_BAD_STATE);
@@ -94,15 +95,38 @@ int ui_display_transaction() {
9495
pairList.nbPairs = 2;
9596
pairList.pairs = pairs;
9697

97-
// Start review
98-
nbgl_useCaseReview(TYPE_TRANSACTION,
99-
&pairList,
100-
&C_app_boilerplate_64px,
101-
"Review transaction\nto send BOL",
102-
NULL,
103-
"Sign transaction\nto send BOL",
104-
review_choice);
98+
if (is_blind_signed) {
99+
// Start blind-signing review flow
100+
nbgl_useCaseReviewBlindSigning(TYPE_TRANSACTION,
101+
&pairList,
102+
&C_app_boilerplate_64px,
103+
"Review transaction\nto send BOL",
104+
NULL,
105+
"Sign transaction\nto send BOL",
106+
NULL,
107+
review_choice);
108+
} else {
109+
// Start review flow
110+
nbgl_useCaseReview(TYPE_TRANSACTION,
111+
&pairList,
112+
&C_app_boilerplate_64px,
113+
"Review transaction\nto send BOL",
114+
NULL,
115+
"Sign transaction\nto send BOL",
116+
review_choice);
117+
}
118+
105119
return 0;
106120
}
107121

122+
// Flow used to display a blind-signed transaction
123+
int ui_display_blind_signed_transaction(void) {
124+
return ui_display_transaction_bs_choice(true);
125+
}
126+
127+
// Flow used to display a clear-signed transaction
128+
int ui_display_transaction() {
129+
return ui_display_transaction_bs_choice(false);
130+
}
131+
108132
#endif
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

tests/test_sign_cmd.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors
55
from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response
66
from ragger.error import ExceptionRAPDU
7+
from ragger.navigator import NavInsID
78
from utils import check_signature_validity
89

910
# In this tests we check the behavior of the device when asked to sign a transaction
1011

1112

12-
# In this test se send to the device a transaction to sign and validate it on screen
13+
# In this test we send to the device a transaction to sign and validate it on screen
1314
# The transaction is short and will be sent in one chunk
1415
# We will ensure that the displayed information is correct by using screenshots comparison
1516
def test_sign_tx_short_tx(backend, scenario_navigator):
@@ -43,6 +44,47 @@ def test_sign_tx_short_tx(backend, scenario_navigator):
4344
assert check_signature_validity(public_key, der_sig, transaction)
4445

4546

47+
# In this test we send to the device a transaction to trig a blind-signing flow
48+
# The transaction is short and will be sent in one chunk
49+
# We will ensure that the displayed information is correct by using screenshots comparison
50+
def test_sign_tx_short_tx_blind_sign(firmware, navigator, backend, scenario_navigator, test_name, default_screenshot_path):
51+
if firmware.is_nano:
52+
pytest.skip("Not supported on Nano devices")
53+
54+
# Use the app interface instead of raw interface
55+
client = BoilerplateCommandSender(backend)
56+
# The path used for this entire test
57+
path: str = "m/44'/1'/0'/0/0"
58+
59+
# First we need to get the public key of the device in order to build the transaction
60+
rapdu = client.get_public_key(path=path)
61+
_, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
62+
63+
# Create the transaction that will be sent to the device for signing
64+
transaction = Transaction(
65+
nonce=1,
66+
to="0x0000000000000000000000000000000000000000",
67+
value=0,
68+
memo="Blind-sign"
69+
).serialize()
70+
71+
# Send the sign device instruction.
72+
# As it requires on-screen validation, the function is asynchronous.
73+
# It will yield the result when the navigation is done
74+
with client.sign_tx(path=path, transaction=transaction):
75+
navigator.navigate_and_compare(default_screenshot_path,
76+
test_name+"/part1",
77+
[NavInsID.USE_CASE_CHOICE_REJECT],
78+
screen_change_after_last_instruction=False)
79+
80+
# Validate the on-screen request by performing the navigation appropriate for this device
81+
scenario_navigator.review_approve()
82+
83+
# The device as yielded the result, parse it and ensure that the signature is correct
84+
response = client.get_async_response().data
85+
_, der_sig, _ = unpack_sign_tx_response(response)
86+
assert check_signature_validity(public_key, der_sig, transaction)
87+
4688
# In this test se send to the device a transaction to sign and validate it on screen
4789
# This test is mostly the same as the previous one but with different values.
4890
# In particular the long memo will force the transaction to be sent in multiple chunks

0 commit comments

Comments
 (0)