Skip to content

Commit

Permalink
Blind signing: Implement the ability to sign transactions that cannot…
Browse files Browse the repository at this point in the history
… be decoded
  • Loading branch information
vldmkr committed Apr 23, 2024
1 parent d9b724c commit 58a4e3e
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 31 deletions.
18 changes: 10 additions & 8 deletions src/handler/sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more) {
G_context.req_type = REQUEST_UNDEFINED;
return io_send_sw(SW_BAD_STATE);
}
if (G_context.state == STATE_PARSED || G_context.state == STATE_APPROVED) {
if (G_context.state == STATE_PARSED || G_context.state == STATE_APPROVED ||
G_context.state == STATE_CONTINUE_UNPARSED) {
// should not get here, double check, context should already be reset
return io_send_sw(SW_BAD_STATE);
}
Expand Down Expand Up @@ -96,15 +97,16 @@ int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more) {

parser_status_e status = transaction_deserialize(&buf, &G_context.tx_info.transaction);
PRINTF("Parsing status: %d.\n", status);
if (status != PARSING_OK) {
// reset the context to prevent sending the "last" chunk multiple times
G_context.req_type = REQUEST_UNDEFINED;
return io_send_sw(SW_TX_PARSING_FAIL);
}

G_context.state = STATE_PARSED;
int ui_status = 0;
if (status == PARSING_OK) {
G_context.state = STATE_PARSED;
ui_status = ui_display_transaction();
} else {
G_context.state = STATE_CONTINUE_UNPARSED;
ui_status = ui_display_unparsed_transaction();
}

int ui_status = ui_display_transaction();
G_context.req_type = REQUEST_UNDEFINED; // all the work is done, reset the context
return ui_status;
}
Expand Down
7 changes: 4 additions & 3 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ typedef enum {
* Enumeration with parsing state.
*/
typedef enum {
STATE_NONE, /// No state
STATE_PARSED, /// Transaction data parsed
STATE_APPROVED /// Transaction data approved
STATE_NONE, /// No state
STATE_PARSED, /// Transaction data parsed
STATE_CONTINUE_UNPARSED, /// Transaction data parsed
STATE_APPROVED /// Transaction data approved
} state_e;

/**
Expand Down
5 changes: 5 additions & 0 deletions src/ui/action/validate.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ void validate_transaction(bool choice) {
io_send_sw(SW_DENY);
}
}

void reject_unparsed_transaction(void) {
G_context.state = STATE_NONE;
io_send_sw(SW_TX_PARSING_FAIL);
}
2 changes: 2 additions & 0 deletions src/ui/action/validate.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ void validate_pubkey(bool choice);
*
*/
void validate_transaction(bool choice);

void reject_unparsed_transaction(void);
72 changes: 72 additions & 0 deletions src/ui/bagl_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ UX_STEP_NOCB(ux_display_blind_sign_banner_step,
"enabled in Settings",
});
#endif
// Step with continue button
UX_STEP_CB(ux_display_continue_step,
pb,
(*g_validate_callback)(true),
{
&C_icon_validate_14,
"Continue",
});
// Step with approve button
UX_STEP_CB(ux_display_approve_step,
pb,
Expand Down Expand Up @@ -170,6 +178,29 @@ int ui_display_address() {
return ret;
}

#ifdef TARGET_NANOS
UX_STEP_NOCB(ux_display_decode_fail_step,
bnnn_paging,
{
.title = "Info",
.text = "Unable to display transaction data",
});
#else
UX_STEP_NOCB(ux_display_decode_fail_step,
pnn,
{
&C_icon_warning,
"Unable to display",
"transaction data",
});
#endif
UX_STEP_NOCB(ux_display_details_step,
pnn,
{
&C_icon_eye,
"Details",
"Unavailable",
});
// Step with icon and text
UX_STEP_NOCB(ux_display_blind_warn_step,
pnn,
Expand Down Expand Up @@ -258,6 +289,26 @@ UX_STEP_NOCB(ux_display_gas_fee_step,
.text = g_gas_fee,
});

// FLOW to display uparsed transaction information:
// #1 screen : "Unable to display transaction data"
// #2 screen : continue button
// #3 screen : reject button
UX_FLOW(ux_display_warn_uparsed_tx_flow,
&ux_display_decode_fail_step,
&ux_display_continue_step,
&ux_display_reject_step);

// FLOW to display message that transaction details are unavailable:
// #1 screen : warning icon + "Blind Signing"
// #2 screen : eye icon + "Details Unavailable"
// #3 screen : approve button
// #4 screen : reject button
UX_FLOW(ux_display_uparsed_tx_flow,
&ux_display_blind_warn_step,
&ux_display_details_step,
&ux_display_approve_step,
&ux_display_reject_step);

// FLOW to display default transaction information:
// #1 screen : warning icon + "Blind Signing"
// #2 screen : eye icon + "Review Transaction"
Expand Down Expand Up @@ -366,6 +417,27 @@ UX_FLOW(ux_display_tx_coin_transfer_flow,
&ux_display_approve_step,
&ux_display_reject_step);

static void ui_action_continue_unparsed_transaction(bool choice) {
if (choice) {
g_validate_callback = &ui_action_validate_transaction;
ui_flow_verified_display(ux_display_uparsed_tx_flow);
} else {
reject_unparsed_transaction();
ui_menu_main();
}
}

int ui_display_unparsed_transaction() {
const int ret = ui_prepare_unparsed_transaction();
if (ret == UI_PREPARED) {
g_validate_callback = &ui_action_continue_unparsed_transaction;
ui_flow_display(ux_display_warn_uparsed_tx_flow);
return 0;
}

return ret;
}

int ui_display_transaction() {
g_validate_callback = &ui_action_validate_transaction;

Expand Down
9 changes: 9 additions & 0 deletions src/ui/common_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ int ui_prepare_transaction() {
return UI_PREPARED;
}

int ui_prepare_unparsed_transaction() {
if (G_context.req_type != CONFIRM_TRANSACTION || G_context.state != STATE_CONTINUE_UNPARSED) {
G_context.state = STATE_NONE;
return io_send_sw(SW_BAD_STATE);
}

return UI_PREPARED;
}

int ui_prepare_entry_function() {
entry_function_payload_t *function = &G_context.tx_info.transaction.payload.entry_function;
char function_module_id_address_hex[67] = {0};
Expand Down
3 changes: 3 additions & 0 deletions src/ui/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ int ui_prepare_address(void);
int ui_display_transaction(void);
int ui_prepare_transaction(void);

int ui_display_unparsed_transaction(void);
int ui_prepare_unparsed_transaction(void);

int ui_display_message(void);
int ui_display_raw_message(void);

Expand Down
72 changes: 56 additions & 16 deletions src/ui/nbgl_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,29 @@ nbgl_layoutTagValueList_t pairList;
nbgl_pageInfoLongPress_t infoLongPress;

static void blind_sign_continue() {
nbgl_useCaseReviewStart(blind_sign_ctx.icon,
blind_sign_ctx.review_title,
blind_sign_ctx.review_sub_title,
blind_sign_ctx.reject_text,
blind_sign_ctx.continue_callback,
blind_sign_ctx.reject_callback);
if (blind_sign_ctx.continue_callback) {
nbgl_useCaseReviewStart(blind_sign_ctx.icon,
blind_sign_ctx.review_title,
blind_sign_ctx.review_sub_title,
blind_sign_ctx.reject_text,
blind_sign_ctx.continue_callback,
blind_sign_ctx.reject_callback);
} else if (blind_sign_ctx.choice_callback) {
pairList.nbMaxLinesForValue = 0;
pairList.nbPairs = 0;
pairList.pairs = pairs;

infoLongPress.icon = &C_aptos_logo_64px;
infoLongPress.text = blind_sign_ctx.long_press_title;
infoLongPress.longPressText = blind_sign_ctx.long_press_button_text;

nbgl_useCaseStaticReview(&pairList,
&infoLongPress,
blind_sign_ctx.reject_text,
blind_sign_ctx.choice_callback);
} else {
PRINTF("Invalid blind signing context\n");
}
}

static void blind_sign_info() {
Expand All @@ -65,6 +82,19 @@ static void blind_sign_choice(bool enable) {
}
}

static void blind_sign_init_choice() {
if (N_storage.settings.allow_blind_signing) {
blind_sign_info();
} else {
nbgl_useCaseChoice(&C_round_warning_64px,
"Enable blind signing to\nauthorize this\noperation",
NULL,
"Enable blind signing",
blind_sign_ctx.reject_text,
blind_sign_choice);
}
}

void nbgl_useCaseReviewVerify(const nbgl_icon_details_t *icon,
const char *review_title,
const char *review_sub_title,
Expand All @@ -77,16 +107,26 @@ void nbgl_useCaseReviewVerify(const nbgl_icon_details_t *icon,
blind_sign_ctx.reject_text = reject_text;
blind_sign_ctx.continue_callback = continue_callback;
blind_sign_ctx.reject_callback = reject_callback;
if (N_storage.settings.allow_blind_signing) {
blind_sign_info();
} else {
nbgl_useCaseChoice(&C_round_warning_64px,
"Enable blind signing to\nauthorize this\noperation",
NULL,
"Enable blind signing",
reject_text,
blind_sign_choice);
}
blind_sign_ctx.choice_callback = NULL;

blind_sign_init_choice();
}

void nbgl_useCaseStaticReviewVerify(const nbgl_icon_details_t *icon,
const char *long_press_title,
const char *long_press_button_text,
const char *reject_text,
nbgl_choiceCallback_t choice_callback,
nbgl_callback_t reject_callback) {
blind_sign_ctx.icon = icon;
blind_sign_ctx.long_press_title = long_press_title;
blind_sign_ctx.long_press_button_text = long_press_button_text;
blind_sign_ctx.reject_text = reject_text;
blind_sign_ctx.continue_callback = NULL;
blind_sign_ctx.reject_callback = reject_callback;
blind_sign_ctx.choice_callback = choice_callback;

blind_sign_init_choice();
}

#endif
18 changes: 16 additions & 2 deletions src/ui/nbgl_display.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@ extern nbgl_pageInfoLongPress_t infoLongPress;

typedef struct use_case_review_ctx_s {
const nbgl_icon_details_t *icon;
const char *review_title;
const char *review_sub_title;
union {
const char *review_title;
const char *long_press_title;
};
union {
const char *review_sub_title;
const char *long_press_button_text;
};
const char *reject_text;
nbgl_callback_t continue_callback;
nbgl_callback_t reject_callback;
nbgl_choiceCallback_t choice_callback;
} use_case_review_ctx_t;

void nbgl_useCaseReviewVerify(const nbgl_icon_details_t *icon,
Expand All @@ -21,3 +28,10 @@ void nbgl_useCaseReviewVerify(const nbgl_icon_details_t *icon,
const char *reject_text,
nbgl_callback_t continue_callback,
nbgl_callback_t reject_callback);

void nbgl_useCaseStaticReviewVerify(const nbgl_icon_details_t *icon,
const char *long_press_title,
const char *long_press_button_text,
const char *reject_text,
nbgl_choiceCallback_t choice_callback,
nbgl_callback_t reject_callback);
45 changes: 43 additions & 2 deletions src/ui/nbgl_display_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,25 @@ static void confirm_transaction_rejection(void) {
nbgl_useCaseStatus("Transaction rejected", false, ui_menu_main);
}

static void ask_transaction_rejection_confirmation(void) {
static void confirm_unparsed_transaction_rejection(void) {
reject_unparsed_transaction();
nbgl_useCaseStatus("Transaction rejected", false, ui_menu_main);
}

static void ask_transaction_rejection(nbgl_callback_t callback) {
nbgl_useCaseConfirm("Reject transaction?",
NULL,
"Yes, Reject",
"Go back to transaction",
confirm_transaction_rejection);
callback);
}

static void ask_transaction_rejection_confirmation(void) {
ask_transaction_rejection(confirm_transaction_rejection);
}

static void ask_unparsed_transaction_rejection_confirmation(void) {
ask_transaction_rejection(confirm_unparsed_transaction_rejection);
}

static void review_choice(bool confirm) {
Expand All @@ -53,6 +66,19 @@ static void review_choice(bool confirm) {
}
}

static void review_unparsed_choice(bool confirm) {
if (confirm) {
nbgl_useCaseStaticReviewVerify(&C_aptos_logo_64px,
"Sign transaction",
"Hold to sign",
"Reject transaction",
review_choice,
ask_transaction_rejection_confirmation);
} else {
ask_unparsed_transaction_rejection_confirmation();
}
}

static void review_default_continue(void) {
pairs[0].item = "Transaction Type";
pairs[0].value = g_tx_type;
Expand Down Expand Up @@ -197,4 +223,19 @@ int ui_display_tx_coin_transfer() {
return ret;
}

int ui_display_unparsed_transaction() {
const int ret = ui_prepare_unparsed_transaction();
if (ret == UI_PREPARED) {
nbgl_useCaseChoice(&C_warning64px,
"Transaction\ndetails unavailable",
"Acknowledge the risks\nand proceed with caution.",
"Continue",
"Reject transaction",
review_unparsed_choice);
return 0;
}

return ret;
}

#endif

0 comments on commit 58a4e3e

Please sign in to comment.