Skip to content

Commit

Permalink
Merge pull request #80 from LedgerHQ/fbe/cherry-pick_exchange_features
Browse files Browse the repository at this point in the history
Fbe/cherry pick exchange features
  • Loading branch information
fbeutin-ledger authored Jan 3, 2024
2 parents a920c9f + 958b2b8 commit b7b8683
Show file tree
Hide file tree
Showing 15 changed files with 464 additions and 422 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ include $(BOLOS_SDK)/Makefile.defines
APPNAME = Stellar
APPVERSION_M=4
APPVERSION_N=0
APPVERSION_P=1
APPVERSION_P=3
APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)

ifeq ($(TARGET_NAME), TARGET_NANOS)
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {

set_state_data(true);
while (formatter_stack[formatter_index] != NULL) {
printf("%s: %s\n", G_ui_detail_caption, G_ui_detail_value);
printf("%s: %s\n", G.ui.detail_caption, G.ui.detail_value);
formatter_index++;

if (formatter_stack[formatter_index] != NULL) {
Expand Down
9 changes: 2 additions & 7 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ io_state_e G_io_state;
uint32_t G_output_len;

global_ctx_t G_context;
swap_values_t G_swap_values;

bool G_called_from_swap;

// We define these variables as global variables to reduce memory usage.
char G_ui_detail_caption[DETAIL_CAPTION_MAX_LENGTH];
char G_ui_detail_value[DETAIL_VALUE_MAX_LENGTH];
volatile uint8_t G_ui_current_state;
uint8_t G_ui_current_data_index;
ui_action_validate_cb G_ui_validate_callback;
swap_or_ui_t G;
43 changes: 29 additions & 14 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,43 @@ extern io_state_e G_io_state;
*/
extern global_ctx_t G_context;

/**
* Global context for swap requests.
*/
extern swap_values_t G_swap_values;

/**
* Is it called through the exchange app
*/
extern bool G_called_from_swap;

/**
* Global variable with the caption of the current UI detail.
* Use an union to avoid the UI variable footprints for the swap flow and vice versa
*/
extern char G_ui_detail_caption[DETAIL_CAPTION_MAX_LENGTH];
typedef union swap_or_ui_u {
struct {
/**
* The response to the swap is ready
*/
bool response_ready;

/**
* Global variable with the value of the current UI detail.
*/
extern char G_ui_detail_value[DETAIL_VALUE_MAX_LENGTH];
/**
* Global context for swap requests.
*/
swap_values_t values;
} swap;

struct {
/**
* Global variable with the caption of the current UI detail.
*/
char detail_caption[DETAIL_CAPTION_MAX_LENGTH];
/**
* Global variable with the value of the current UI detail.
*/
char detail_value[DETAIL_VALUE_MAX_LENGTH];

uint8_t current_state;

extern volatile uint8_t G_ui_current_state;
uint8_t current_data_index;

extern uint8_t G_ui_current_data_index;
ui_action_validate_cb validate_callback;
} ui;
} swap_or_ui_t;

extern ui_action_validate_cb G_ui_validate_callback;
extern swap_or_ui_t G;
64 changes: 43 additions & 21 deletions src/handler/sign_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,36 @@ int handler_sign_tx(buffer_t *cdata, bool is_first_chunk, bool more) {
return io_send_sw(SW_OK);
}

if (cx_hash_sha256(G_context.tx_info.raw,
G_context.tx_info.raw_size,
G_context.hash,
HASH_SIZE) != HASH_SIZE) {
THROW(SW_TX_HASH_FAIL);
}

if (!parse_tx_xdr(G_context.tx_info.raw, G_context.tx_info.raw_size, &G_context.tx_info)) {
THROW(SW_TX_PARSING_FAIL);
}

G_context.state = STATE_PARSED;
PRINTF("tx parsed.\n");

// We have been called from the Exchange app that has already vaidated the TX in the UI
if (G_called_from_swap) {
if (G.swap.response_ready) {
// Safety against trying to make the app sign multiple TX
// This panic quit is a failsafe that should never trigger, as the app is supposed to
// exit after the first send when started in swap mode
os_sched_exit(-1);
} else {
// We will quit the app after this transaction, whether it succeeds or fails
G.swap.response_ready = true;
}
if (!swap_check()) {
return io_send_sw(SW_SWAP_CHECKING_FAIL);
}
uint8_t signature[SIGNATURE_SIZE];

if (cx_hash_sha256(G_context.tx_info.raw,
G_context.tx_info.raw_size,
G_context.hash,
HASH_SIZE) != HASH_SIZE) {
THROW(SW_TX_HASH_FAIL);
}

if (crypto_sign_message(G_context.hash,
sizeof(G_context.hash),
signature,
Expand All @@ -89,21 +100,32 @@ int handler_sign_tx(buffer_t *cdata, bool is_first_chunk, bool more) {
} else {
return send_response_sig(signature, SIGNATURE_SIZE);
}
}

cx_ecfp_private_key_t private_key = {0};
cx_ecfp_public_key_t public_key = {0};
} else {
// Normal (not-swap) mode, derive the public_key and display the validation UI

// derive private key according to BIP32 path
int error =
crypto_derive_private_key(&private_key, G_context.bip32_path, G_context.bip32_path_len);
if (error != 0) {
return io_send_sw(error);
}
// generate corresponding public key
crypto_init_public_key(&private_key, &public_key, G_context.raw_public_key);
// reset private key
explicit_bzero(&private_key, sizeof(private_key));
cx_ecfp_private_key_t private_key = {0};
cx_ecfp_public_key_t public_key = {0};

// derive private key according to BIP32 path
int error =
crypto_derive_private_key(&private_key, G_context.bip32_path, G_context.bip32_path_len);
if (error != 0) {
explicit_bzero(&private_key, sizeof(private_key));
return io_send_sw(error);
}
// generate corresponding public key
crypto_init_public_key(&private_key, &public_key, G_context.raw_public_key);
// reset private key
explicit_bzero(&private_key, sizeof(private_key));

return ui_approve_tx_init();
if (cx_hash_sha256(G_context.tx_info.raw,
G_context.tx_info.raw_size,
G_context.hash,
HASH_SIZE) != HASH_SIZE) {
THROW(SW_TX_HASH_FAIL);
}

return ui_approve_tx_init();
}
};
9 changes: 8 additions & 1 deletion src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,14 @@ int io_recv_command() {
switch (G_io_state) {
case READY:
G_io_state = RECEIVED;
ret = io_exchange(CHANNEL_APDU, G_output_len);
// If we are in swap mode and have validated a TX, we send it and immediatly quit
if (G_called_from_swap && G.swap.response_ready) {
ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len);
PRINTF("Swap answer is processed and sent. The app will quit\n");
os_sched_exit(0);
} else {
ret = io_exchange(CHANNEL_APDU, G_output_len);
}
break;
case RECEIVED:
G_io_state = WAITING;
Expand Down
3 changes: 2 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ static void library_main_helper(struct libargs_s *args) {
case SIGN_TRANSACTION:
if (copy_transaction_parameters(args->create_transaction)) {
// never returns
G_called_from_swap = true;
G.swap.response_ready = false;
handle_swap_sign_transaction();
}
break;
Expand Down Expand Up @@ -213,7 +215,6 @@ __attribute__((section(".boot"))) int main(int arg0) {
// Called as library from another app
libargs_t *args = (libargs_t *) arg0;
if (args->id == 0x100) {
G_called_from_swap = true;
library_main(args);
} else {
app_exit();
Expand Down
10 changes: 6 additions & 4 deletions src/swap/handle_swap_sign_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "./swap_lib_calls.h"
#include "../globals.h"
#include "os.h"
#include "../types.h"

bool copy_transaction_parameters(const create_transaction_parameters_t* params) {
Expand Down Expand Up @@ -33,7 +34,8 @@ bool copy_transaction_parameters(const create_transaction_parameters_t* params)
return false;
}

memcpy(&G_swap_values, &stack_data, sizeof(stack_data));
os_explicit_zero_BSS_segment();
memcpy(&G.swap.values, &stack_data, sizeof(stack_data));
return true;
}

Expand All @@ -43,13 +45,13 @@ void handle_swap_sign_transaction(void) {
USB_power(0);
USB_power(1);
PRINTF("USB power ON/OFF\n");
#ifdef TARGET_NANOX
#ifdef HAVE_BLE
// grab the current plane mode setting
G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0);
#endif // TARGET_NANOX
#endif // HAVE_BLE
#ifdef HAVE_BLE
BLE_power(0, NULL);
BLE_power(1, "Nano X");
BLE_power(1, NULL);
#endif // HAVE_BLE
app_main();
}
28 changes: 14 additions & 14 deletions src/swap/swap_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,56 @@

bool swap_check() {
PRINTF("swap_check invoked.\n");
char *tmp_buf = G_ui_detail_value;

tx_ctx_t *tx_ctx = &G_context.tx_info;
char tmp_buf[sizeof(G.ui.detail_value)];

// tx type
if (tx_ctx->envelope_type != ENVELOPE_TYPE_TX) {
if (G_context.tx_info.envelope_type != ENVELOPE_TYPE_TX) {
return false;
}

// A XLM swap consist of only one "send" operation
if (tx_ctx->tx_details.operations_count != 1) {
if (G_context.tx_info.tx_details.operations_count != 1) {
return false;
}

// op type
if (tx_ctx->tx_details.op_details.type != OPERATION_TYPE_PAYMENT) {
if (G_context.tx_info.tx_details.op_details.type != OPERATION_TYPE_PAYMENT) {
return false;
}

// amount
if (tx_ctx->tx_details.op_details.payment_op.asset.type != ASSET_TYPE_NATIVE ||
tx_ctx->tx_details.op_details.payment_op.amount != (int64_t) G_swap_values.amount) {
if (G_context.tx_info.tx_details.op_details.payment_op.asset.type != ASSET_TYPE_NATIVE ||
G_context.tx_info.tx_details.op_details.payment_op.amount !=
(int64_t) G.swap.values.amount) {
return false;
}

// destination addr
if (!print_muxed_account(&tx_ctx->tx_details.op_details.payment_op.destination,
if (!print_muxed_account(&G_context.tx_info.tx_details.op_details.payment_op.destination,
tmp_buf,
DETAIL_VALUE_MAX_LENGTH,
0,
0)) {
return false;
};

if (strcmp(tmp_buf, G_swap_values.destination) != 0) {
if (strcmp(tmp_buf, G.swap.values.destination) != 0) {
return false;
}

if (tx_ctx->tx_details.op_details.source_account_present) {
if (G_context.tx_info.tx_details.op_details.source_account_present) {
return false;
}

// memo
if (tx_ctx->tx_details.memo.type != MEMO_TEXT ||
strcmp((char *) tx_ctx->tx_details.memo.text.text, G_swap_values.memo) != 0) {
if (G_context.tx_info.tx_details.memo.type != MEMO_TEXT ||
strcmp((char *) G_context.tx_info.tx_details.memo.text.text, G.swap.values.memo) != 0) {
return false;
}

// fees
if (tx_ctx->network != NETWORK_TYPE_PUBLIC || tx_ctx->tx_details.fee != G_swap_values.fees) {
if (G_context.tx_info.network != NETWORK_TYPE_PUBLIC ||
G_context.tx_info.tx_details.fee != G.swap.values.fees) {
return false;
}

Expand Down
Loading

0 comments on commit b7b8683

Please sign in to comment.