diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 686ee4bb..1d5def00 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -60,7 +60,7 @@ jobs: path: scan-build python_tests_nano: - name: NanoS Ragger tests + name: Ragger tests needs: build_application runs-on: ubuntu-latest steps: diff --git a/.github/workflows/lint-workflow.yml b/.github/workflows/lint-workflow.yml index 6c1efb98..20715e25 100644 --- a/.github/workflows/lint-workflow.yml +++ b/.github/workflows/lint-workflow.yml @@ -45,4 +45,4 @@ jobs: # Use Config file when the github action supports it builtin: clear,rare check_filenames: true - skip: ./libsol,./tests + skip: ./libsol/printer_test.c,./tests/Cargo.lock diff --git a/Makefile b/Makefile index 0656ba2a..67fd68e7 100644 --- a/Makefile +++ b/Makefile @@ -28,11 +28,11 @@ endif include $(BOLOS_SDK)/Makefile.defines -APP_LOAD_PARAMS = --curve ed25519 -ifeq ($(TARGET_NAME), TARGET_NANOX) - APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS +APP_LOAD_PARAMS = --curve ed25519 +ifeq ($(TARGET_NAME), TARGET_NANOS) +APP_LOAD_PARAMS += --appFlags 0x800 # APPLICATION_FLAG_LIBRARY else - APP_LOAD_PARAMS += --appFlags 0x000 +APP_LOAD_PARAMS += --appFlags 0xa00 # APPLICATION_FLAG_LIBRARY + APPLICATION_FLAG_BOLOS_SETTINGS endif APP_LOAD_PARAMS += --path "44'/501'" APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) diff --git a/doc/api.md b/doc/api.md index 98a1392d..66acb019 100644 --- a/doc/api.md +++ b/doc/api.md @@ -3,6 +3,7 @@ ## 1.3.0 - Add SIGN SOLANA OFF-CHAIN MESSAGE +- Add compatibility with the Exchange Application to SWAP, FUND, or SELL SOL tokens ## About diff --git a/libsol/message_test.c b/libsol/message_test.c index 25a0b65d..1d78d9b8 100644 --- a/libsol/message_test.c +++ b/libsol/message_test.c @@ -6,7 +6,7 @@ #include #include -// Disable clang format for this file to keep clear buffer formating +// Disable clang format for this file to keep clear buffer formatting /* clang-format off */ void test_process_message_body_ok() { diff --git a/src/apdu.c b/src/apdu.c index 5ed1c88f..3432b357 100644 --- a/src/apdu.c +++ b/src/apdu.c @@ -193,4 +193,4 @@ int apdu_handle_message(const uint8_t* apdu_message, apdu_command->state = ApduStatePayloadComplete; return 0; -} \ No newline at end of file +} diff --git a/src/getPubkey.c b/src/getPubkey.c index 5cb6bb2c..e7de168b 100644 --- a/src/getPubkey.c +++ b/src/getPubkey.c @@ -28,14 +28,14 @@ UX_STEP_NOCB(ux_display_public_flow_5_step, }); UX_STEP_CB(ux_display_public_flow_6_step, pb, - sendResponse(set_result_get_pubkey(), true), + sendResponse(set_result_get_pubkey(), true, true), { &C_icon_validate_14, "Approve", }); UX_STEP_CB(ux_display_public_flow_7_step, pb, - sendResponse(0, false), + sendResponse(0, false, true), { &C_icon_crossmark, "Reject", diff --git a/src/globals.h b/src/globals.h index 727505ba..ee138595 100644 --- a/src/globals.h +++ b/src/globals.h @@ -52,6 +52,9 @@ typedef enum InstructionCode { InsSignOffchainMessage = 0x07 } InstructionCode; +extern volatile bool G_called_from_swap; +extern volatile bool G_swap_response_ready; + // display stepped screens extern unsigned int ux_step; extern unsigned int ux_step_count; @@ -84,4 +87,4 @@ typedef struct internalStorage_t { extern const internalStorage_t N_storage_real; #define N_storage (*(volatile internalStorage_t*) PIC(&N_storage_real)) -#endif \ No newline at end of file +#endif diff --git a/src/main.c b/src/main.c index 60c00aed..82341491 100644 --- a/src/main.c +++ b/src/main.c @@ -22,8 +22,16 @@ #include "apdu.h" #include "menu.h" +// Swap feature +#include "swap_lib_calls.h" +#include "handle_swap_sign_transaction.h" +#include "handle_get_printable_amount.h" +#include "handle_check_address.h" + ApduCommand G_command; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +volatile bool G_called_from_swap; +volatile bool G_swap_response_ready; static void reset_main_globals(void) { MEMCLEAR(G_command); @@ -41,8 +49,10 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) const int ret = apdu_handle_message(G_io_apdu_buffer, rx, &G_command); if (ret != 0) { + MEMCLEAR(G_command); THROW(ret); } + if (G_command.state == ApduStatePayloadInProgress) { THROW(ApduReplySuccess); } @@ -96,7 +106,6 @@ void app_main(void) { // APDU injection faults. for (;;) { volatile unsigned short sw = 0; - BEGIN_TRY { TRY { rx = tx; @@ -105,6 +114,12 @@ void app_main(void) { rx = io_exchange(CHANNEL_APDU | flags, rx); flags = 0; + if (G_called_from_swap && G_swap_response_ready) { + PRINTF("Quitting app started in swap mode\n"); + // Quit app, we are in limited mode and our work is done + os_sched_exit(0); + } + // no apdu received, well, reset the session, and reset the // bootloader configuration if (rx == 0) { @@ -260,13 +275,8 @@ void nv_app_state_init() { } } -__attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); - - // ensure exception will work as planned - os_boot(); - +void coin_main(void) { + G_called_from_swap = false; for (;;) { UX_INIT(); @@ -307,5 +317,88 @@ __attribute__((section(".boot"))) int main(void) { END_TRY; } app_exit(); +} + +static void start_app_from_lib(void) { + G_called_from_swap = true; + G_swap_response_ready = false; + UX_INIT(); + io_seproxyhal_init(); + nv_app_state_init(); + USB_power(0); + USB_power(1); +#ifdef HAVE_BLE + // Erase globals that may inherit values from exchange + MEMCLEAR(G_io_asynch_ux_callback); + // grab the current plane mode setting + G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); + BLE_power(0, NULL); + BLE_power(1, "Nano X"); +#endif // HAVE_BLE + app_main(); +} + +static void library_main_helper(libargs_t *args) { + check_api_level(CX_COMPAT_APILEVEL); + switch (args->command) { + case CHECK_ADDRESS: + // ensure result is zero if an exception is thrown + args->check_address->result = 0; + args->check_address->result = handle_check_address(args->check_address); + break; + case SIGN_TRANSACTION: + if (copy_transaction_parameters(args->create_transaction)) { + // never returns + start_app_from_lib(); + } + break; + case GET_PRINTABLE_AMOUNT: + handle_get_printable_amount(args->get_printable_amount); + break; + default: + break; + } +} + +static void library_main(libargs_t *args) { + volatile bool end = false; + /* This loop ensures that library_main_helper and os_lib_end are called + * within a try context, even if an exception is thrown */ + while (1) { + BEGIN_TRY { + TRY { + if (!end) { + library_main_helper(args); + } + os_lib_end(); + } + FINALLY { + end = true; + } + } + END_TRY; + } +} + +__attribute__((section(".boot"))) int main(int arg0) { + // exit critical section + __asm volatile("cpsie i"); + + // ensure exception will work as planned + os_boot(); + + if (arg0 == 0) { + // called from dashboard as standalone app + coin_main(); + } else { + // Called as library from another app + libargs_t *args = (libargs_t *) arg0; + if (args->id == 0x100) { + library_main(args); + } else { + app_exit(); + } + } + return 0; } diff --git a/src/signMessage.c b/src/signMessage.c index caa44224..32c83591 100644 --- a/src/signMessage.c +++ b/src/signMessage.c @@ -12,6 +12,8 @@ #include "globals.h" #include "apdu.h" +#include "handle_swap_sign_transaction.h" + static uint8_t set_result_sign_message() { uint8_t signature[SIGNATURE_LENGTH]; cx_ecfp_private_key_t privateKey; @@ -43,22 +45,18 @@ static uint8_t set_result_sign_message() { return SIGNATURE_LENGTH; } -static void send_result_sign_message(void) { - sendResponse(set_result_sign_message(), true); -} - ////////////////////////////////////////////////////////////////////// UX_STEP_CB(ux_approve_step, pb, - send_result_sign_message(), + sendResponse(set_result_sign_message(), true, true), { &C_icon_validate_14, "Approve", }); UX_STEP_CB(ux_reject_step, pb, - sendResponse(0, false), + sendResponse(0, false, true), { &C_icon_crossmark, "Reject", @@ -167,22 +165,73 @@ void handle_sign_message_parse_message(volatile unsigned int *tx) { } } +static bool check_swap_validity(const SummaryItemKind_t kinds[MAX_TRANSACTION_SUMMARY_ITEMS], + size_t num_summary_steps) { + bool amount_ok = false; + bool recipient_ok = false; + if (num_summary_steps != 2) { + PRINTF("2 steps expected for transaction in swap context, not %u\n", num_summary_steps); + return false; + } + for (size_t i = 0; i < num_summary_steps; ++i) { + transaction_summary_display_item(i, DisplayFlagNone | DisplayFlagLongPubkeys); + switch (kinds[i]) { + case SummaryItemAmount: + amount_ok = + check_swap_amount(G_transaction_summary_title, G_transaction_summary_text); + break; + case SummaryItemPubkey: + recipient_ok = + check_swap_recipient(G_transaction_summary_title, G_transaction_summary_text); + break; + default: + PRINTF("Refused kind '%u'\n", kinds[i]); + return false; + } + } + return amount_ok && recipient_ok; +} + void handle_sign_message_ui(volatile unsigned int *flags) { // Display the transaction summary SummaryItemKind_t summary_step_kinds[MAX_TRANSACTION_SUMMARY_ITEMS]; size_t num_summary_steps = 0; if (transaction_summary_finalize(summary_step_kinds, &num_summary_steps) == 0) { - size_t num_flow_steps = 0; + // If we are in swap context, do not redisplay the message data + // Instead, ensure they are identitical with what was previously displayed + if (G_called_from_swap) { + if (G_swap_response_ready) { + // Safety against trying to make the app sign multiple TX + // This code should never be triggered as the app is supposed to exit after + // sending the signed transaction + PRINTF("Safety against double signing triggered\n"); + os_sched_exit(-1); + } else { + // We will quit the app after this transaction, whether it succeeds or fails + PRINTF("Swap response is ready, the app will quit after the next send\n"); + G_swap_response_ready = true; + } + if (check_swap_validity(summary_step_kinds, num_summary_steps)) { + PRINTF("Valid swap transaction signed\n"); + sendResponse(set_result_sign_message(), true, false); + } else { + PRINTF("Refused signing incorrect Swap transaction\n"); + THROW(ApduReplySolanaSummaryFinalizeFailed); + } + } else { + MEMCLEAR(flow_steps); + size_t num_flow_steps = 0; - for (size_t i = 0; i < num_summary_steps; i++) { - flow_steps[num_flow_steps++] = &ux_summary_step; - } + for (size_t i = 0; i < num_summary_steps; i++) { + flow_steps[num_flow_steps++] = &ux_summary_step; + } - flow_steps[num_flow_steps++] = &ux_approve_step; - flow_steps[num_flow_steps++] = &ux_reject_step; - flow_steps[num_flow_steps++] = FLOW_END_STEP; + flow_steps[num_flow_steps++] = &ux_approve_step; + flow_steps[num_flow_steps++] = &ux_reject_step; + flow_steps[num_flow_steps++] = FLOW_END_STEP; - ux_flow_init(0, flow_steps, NULL); + ux_flow_init(0, flow_steps, NULL); + } } else { THROW(ApduReplySolanaSummaryFinalizeFailed); } diff --git a/src/signOffchainMessage.c b/src/signOffchainMessage.c index 38aaf995..1ed86aa8 100644 --- a/src/signOffchainMessage.c +++ b/src/signOffchainMessage.c @@ -117,14 +117,14 @@ UX_STEP_NOCB(ux_sign_msg_text_step, }); UX_STEP_CB(ux_sign_msg_approve_step, pb, - sendResponse(set_result_sign_message(), true), + sendResponse(set_result_sign_message(), true, true), { &C_icon_validate_14, "Approve", }); UX_STEP_CB(ux_sign_msg_reject_step, pb, - sendResponse(0, false), + sendResponse(0, false, true), { &C_icon_crossmark, "Reject", diff --git a/src/swap/handle_check_address.c b/src/swap/handle_check_address.c new file mode 100644 index 00000000..c777dcd1 --- /dev/null +++ b/src/swap/handle_check_address.c @@ -0,0 +1,73 @@ +#include + +#include "handle_check_address.h" +#include "os.h" +#include "utils.h" +#include "sol/printer.h" + +static int derive_public_key(const uint8_t *buffer, + uint16_t buffer_length, + uint8_t public_key[PUBKEY_LENGTH], + char public_key_str[BASE58_PUBKEY_LENGTH]) { + uint32_t derivation_path[MAX_BIP32_PATH_LENGTH]; + uint32_t path_length; + int ret; + + ret = read_derivation_path(buffer, buffer_length, derivation_path, &path_length) != 0; + if (ret != 0) { + return ret; + } + + get_public_key(public_key, derivation_path, path_length); + + return encode_base58(public_key, PUBKEY_LENGTH, public_key_str, BASE58_PUBKEY_LENGTH); +} + +int handle_check_address(const check_address_parameters_t *params) { + PRINTF("Inside Solana handle_check_address\n"); + PRINTF("Params on the address %d\n", (unsigned int) params); + + if (params->coin_configuration != NULL || params->coin_configuration_length != 0) { + PRINTF("No coin_configuration expected\n"); + return 0; + } + + if (params->address_parameters == NULL) { + PRINTF("derivation path expected\n"); + return 0; + } + + if (params->address_to_check == NULL) { + PRINTF("Address to check expected\n"); + return 0; + } + PRINTF("Address to check %s\n", params->address_to_check); + + if (params->extra_id_to_check == NULL) { + PRINTF("extra_id_to_check expected\n"); + return 0; + } else if (params->extra_id_to_check[0] != '\0') { + PRINTF("extra_id_to_check expected empty, not '%s'\n", params->extra_id_to_check); + return 0; + } + + uint8_t public_key[PUBKEY_LENGTH]; + char public_key_str[BASE58_PUBKEY_LENGTH]; + if (derive_public_key(params->address_parameters, + params->address_parameters_length, + public_key, + public_key_str) != 0) { + PRINTF("Failed to derive public key\n"); + return 0; + } + // Only public_key_str is useful in this context + UNUSED(public_key); + + if (strcmp(params->address_to_check, public_key_str) != 0) { + PRINTF("Address %s != %s\n", params->address_to_check, public_key_str); + return 0; + } + + PRINTF("Addresses match\n"); + return 1; +} diff --git a/src/swap/handle_check_address.h b/src/swap/handle_check_address.h new file mode 100644 index 00000000..5d148e63 --- /dev/null +++ b/src/swap/handle_check_address.h @@ -0,0 +1,5 @@ +#pragma once + +#include "swap_lib_calls.h" + +int handle_check_address(const check_address_parameters_t* params); diff --git a/src/swap/handle_get_printable_amount.c b/src/swap/handle_get_printable_amount.c new file mode 100644 index 00000000..7cf1a9ff --- /dev/null +++ b/src/swap/handle_get_printable_amount.c @@ -0,0 +1,33 @@ +#include "handle_get_printable_amount.h" +#include "swap_lib_calls.h" +#include "utils.h" +#include "sol/printer.h" + +/* return 0 on error, 1 otherwise */ +int handle_get_printable_amount(get_printable_amount_parameters_t* params) { + PRINTF("Inside Solana handle_get_printable_amount\n"); + MEMCLEAR(params->printable_amount); + + // Fees are displayed normally + // params->is_fee + + if (params->coin_configuration != NULL || params->coin_configuration_length != 0) { + PRINTF("No coin_configuration expected\n"); + return 0; + } + + uint64_t amount; + if (!swap_str_to_u64(params->amount, params->amount_length, &amount)) { + PRINTF("Amount is too big"); + return 0; + } + + if (print_amount(amount, params->printable_amount, sizeof(params->printable_amount)) != 0) { + PRINTF("print_amount failed"); + return 0; + } + + PRINTF("Amount %s\n", params->printable_amount); + + return 1; +} diff --git a/src/swap/handle_get_printable_amount.h b/src/swap/handle_get_printable_amount.h new file mode 100644 index 00000000..36481fdd --- /dev/null +++ b/src/swap/handle_get_printable_amount.h @@ -0,0 +1,5 @@ +#pragma once + +#include "swap_lib_calls.h" + +int handle_get_printable_amount(get_printable_amount_parameters_t* params); diff --git a/src/swap/handle_swap_sign_transaction.c b/src/swap/handle_swap_sign_transaction.c new file mode 100644 index 00000000..d26ae2fb --- /dev/null +++ b/src/swap/handle_swap_sign_transaction.c @@ -0,0 +1,102 @@ +#include "handle_swap_sign_transaction.h" +#include "utils.h" +#include "swap_lib_calls.h" +#include "sol/printer.h" + +typedef struct swap_validated_s { + bool initialized; + uint64_t amount; + char recipient[BASE58_PUBKEY_LENGTH]; +} swap_validated_t; + +static swap_validated_t G_swap_validated; + +// Save the data validated during the Exchange app flow +bool copy_transaction_parameters(const create_transaction_parameters_t *params) { + // Ensure no subcoin configuration + if (params->coin_configuration != NULL || params->coin_configuration_length != 0) { + PRINTF("No coin_configuration expected\n"); + return false; + } + + // Ensure no extraid + if (params->destination_address_extra_id == NULL) { + PRINTF("destination_address_extra_id expected\n"); + return false; + } else if (params->destination_address_extra_id[0] != '\0') { + PRINTF("destination_address_extra_id expected empty, not '%s'\n", + params->destination_address_extra_id); + return false; + } + + // first copy parameters to stack, and then to global data. + // We need this "trick" as the input data position can overlap with app globals + swap_validated_t swap_validated; + memset(&swap_validated, 0, sizeof(swap_validated)); + + // Save recipient + strlcpy(swap_validated.recipient, + params->destination_address, + sizeof(swap_validated.recipient)); + if (swap_validated.recipient[sizeof(swap_validated.recipient) - 1] != '\0') { + PRINTF("Address copy error\n"); + return false; + } + + // Save amount + if (!swap_str_to_u64(params->amount, params->amount_length, &swap_validated.amount)) { + return false; + } + + swap_validated.initialized = true; + + // Commit from stack to global data, params becomes tainted but we won't access it anymore + memcpy(&G_swap_validated, &swap_validated, sizeof(swap_validated)); + return true; +} + +// Check that the amount in parameter is the same as the previously saved amount +bool check_swap_amount(const char *title, const char *text) { + if (!G_swap_validated.initialized) { + return false; + } + + if (strcmp(title, "Transfer") != 0) { + PRINTF("Refused field '%s', expecting 'Transfer'\n", title); + return false; + } + + char validated_amount[MAX_PRINTABLE_AMOUNT_SIZE]; + if (print_amount(G_swap_validated.amount, validated_amount, sizeof(validated_amount)) != 0) { + PRINTF("Conversion failed\n"); + return false; + } + + if (strcmp(text, validated_amount) == 0) { + return true; + } else { + PRINTF("Amount requested in this transaction = %s\n", text); + PRINTF("Amount validated in swap = %s\n", validated_amount); + return false; + } +} + +// Check that the recipient in parameter is the same as the previously saved recipient +bool check_swap_recipient(const char *title, const char *text) { + if (!G_swap_validated.initialized) { + return false; + } + + if (strcmp(title, "Recipient") != 0) { + PRINTF("Refused field '%s', expecting 'Recipient'\n", title); + return false; + } + + if (strcmp(G_swap_validated.recipient, text) == 0) { + return true; + } else { + PRINTF("Recipient requested in this transaction = %s\n", text); + PRINTF("Recipient validated in swap = %s\n", G_swap_validated.recipient); + return false; + } +} diff --git a/src/swap/handle_swap_sign_transaction.h b/src/swap/handle_swap_sign_transaction.h new file mode 100644 index 00000000..60358c0f --- /dev/null +++ b/src/swap/handle_swap_sign_transaction.h @@ -0,0 +1,8 @@ +#pragma once + +#include "swap_lib_calls.h" + +bool copy_transaction_parameters(const create_transaction_parameters_t *sign_transaction_params); + +bool check_swap_amount(const char *title, const char *text); +bool check_swap_recipient(const char *title, const char *text); diff --git a/src/swap/swap_lib_calls.c b/src/swap/swap_lib_calls.c new file mode 100644 index 00000000..009a9bc5 --- /dev/null +++ b/src/swap/swap_lib_calls.c @@ -0,0 +1,16 @@ +#include + +#include "swap_lib_calls.h" + +bool swap_str_to_u64(const uint8_t* src, size_t length, uint64_t* result) { + if (length > sizeof(uint64_t)) { + return false; + } + uint64_t value = 0; + for (size_t i = 0; i < length; i++) { + value <<= 8; + value |= src[i]; + } + *result = value; + return true; +} diff --git a/src/swap/swap_lib_calls.h b/src/swap/swap_lib_calls.h new file mode 100644 index 00000000..27a4436a --- /dev/null +++ b/src/swap/swap_lib_calls.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include + +#define RUN_APPLICATION 1 + +#define SIGN_TRANSACTION 2 + +#define CHECK_ADDRESS 3 + +#define GET_PRINTABLE_AMOUNT 4 + +/* + * Amounts are stored as bytes, with a max size of 16 (see protobuf + * specifications). Max 16B integer is 340282366920938463463374607431768211455 + * in decimal, which is a 32-long char string. + * The printable amount also contains spaces, the ticker symbol (with variable + * size, up to 12 in Ethereum for instance) and a terminating null byte, so 50 + * bytes total should be a fair maximum. + */ +#define MAX_PRINTABLE_AMOUNT_SIZE 50 + +// structure that should be send to specific coin application to get address +typedef struct check_address_parameters_s { + // IN + unsigned char *coin_configuration; + unsigned char coin_configuration_length; + // serialized path, segwit, version prefix, hash used, dictionary etc. + // fields and serialization format depends on specific coin app + unsigned char *address_parameters; + unsigned char address_parameters_length; + char *address_to_check; + char *extra_id_to_check; + // OUT + int result; +} check_address_parameters_t; + +// structure that should be send to specific coin application to get printable amount +typedef struct get_printable_amount_parameters_s { + // IN + unsigned char *coin_configuration; + unsigned char coin_configuration_length; + unsigned char *amount; + unsigned char amount_length; + bool is_fee; + // OUT + char printable_amount[MAX_PRINTABLE_AMOUNT_SIZE]; +} get_printable_amount_parameters_t; + +typedef struct create_transaction_parameters_s { + unsigned char *coin_configuration; + unsigned char coin_configuration_length; + unsigned char *amount; + unsigned char amount_length; + unsigned char *fee_amount; + unsigned char fee_amount_length; + char *destination_address; + char *destination_address_extra_id; +} create_transaction_parameters_t; + +bool swap_str_to_u64(const uint8_t *src, size_t length, uint64_t *result); + +typedef struct libargs_s { + unsigned int id; + unsigned int command; + unsigned int unused; + union { + check_address_parameters_t *check_address; + create_transaction_parameters_t *create_transaction; + get_printable_amount_parameters_t *get_printable_amount; + }; +} libargs_t; diff --git a/src/utils.c b/src/utils.c index 258a1fcc..6a4e0b30 100644 --- a/src/utils.c +++ b/src/utils.c @@ -123,13 +123,15 @@ int read_derivation_path(const uint8_t *data_buffer, return 0; } -void sendResponse(uint8_t tx, bool approve) { +void sendResponse(uint8_t tx, bool approve, bool display_menu) { G_io_apdu_buffer[tx++] = approve ? 0x90 : 0x69; G_io_apdu_buffer[tx++] = approve ? 0x00 : 0x85; // Send back the response, do not restart the event loop io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); - // Display back the original UX - ui_idle(); + if (display_menu) { + // Display back the original UX + ui_idle(); + } } unsigned int ui_prepro(const bagl_element_t *element) { diff --git a/src/utils.h b/src/utils.h index af8f2889..a5c2ce56 100644 --- a/src/utils.h +++ b/src/utils.h @@ -53,7 +53,7 @@ int read_derivation_path(const uint8_t *data_buffer, uint32_t *derivation_path, uint32_t *derivation_path_length); -void sendResponse(uint8_t tx, bool approve); +void sendResponse(uint8_t tx, bool approve, bool display_menu); // type userid x y w h str rad fill fg bg fid iid txt // touchparams... ] diff --git a/tests/python/apps/solana.py b/tests/python/apps/solana.py index ca06561f..69bd96bc 100644 --- a/tests/python/apps/solana.py +++ b/tests/python/apps/solana.py @@ -2,8 +2,7 @@ from enum import IntEnum from contextlib import contextmanager -from ragger.backend import BackendInterface -from ragger.utils import RAPDU +from ragger.backend.interface import BackendInterface, RAPDU class INS(IntEnum): @@ -74,7 +73,7 @@ def _extend_and_serialize_multiple_derivations_paths(derivations_paths: List[byt class SolanaClient: client: BackendInterface - def __init__(self, client): + def __init__(self, client: BackendInterface): self._client = client @@ -126,21 +125,3 @@ def send_async_sign_message(self, def get_async_response(self) -> RAPDU: return self._client.last_async_response - - - def send_blind_sign_message(self, derivation_path : bytes, message: bytes) -> RAPDU: - message_splited_prefixed = self.split_and_prefix_message(derivation_path, message) - - # Send all chunks with P2_MORE except for the last chunk - # Send all chunks with P2_EXTEND except for the first chunk - if len(message_splited_prefixed) > 1: - final_p2 |= P2_EXTEND - self.send_first_message_batch(message_splited_prefixed[:-1], P1_NON_CONFIRM) - else: - final_p2 = 0 - - return self._client.exchange(CLA, - INS.INS_SIGN_MESSAGE, - P1_NON_CONFIRM, - final_p2, - message_splited_prefixed[-1]) diff --git a/tests/python/apps/solana_utils.py b/tests/python/apps/solana_utils.py index f18e624e..ec7be1e0 100644 --- a/tests/python/apps/solana_utils.py +++ b/tests/python/apps/solana_utils.py @@ -1,7 +1,7 @@ import base58 -from ragger.bip import pack_derivation_path from ragger.utils import create_currency_config +from ragger.bip import pack_derivation_path ### Some utilities functions for amounts conversions ### diff --git a/tests/python/test_solana.py b/tests/python/test_solana.py index e647e8eb..501f8684 100644 --- a/tests/python/test_solana.py +++ b/tests/python/test_solana.py @@ -65,16 +65,3 @@ def test_solana_simple_transfer_refused(backend, navigator, test_name): rapdu: RAPDU = sol.get_async_response() assert rapdu.status == ErrorType.USER_CANCEL - - -def test_solana_blind_sign_refused(backend): - sol = SolanaClient(backend) - from_public_key = sol.get_public_key(SOL_PACKED_DERIVATION_PATH) - - instruction: SystemInstructionTransfer = SystemInstructionTransfer(from_public_key, FOREIGN_PUBLIC_KEY, AMOUNT) - message: bytes = Message([instruction]).serialize() - - backend.raise_policy = RaisePolicy.RAISE_NOTHING - rapdu: RAPDU = sol.send_blind_sign_message(SOL_PACKED_DERIVATION_PATH, message) - assert rapdu.status == ErrorType.SDK_NOT_SUPPORTED -