-
Notifications
You must be signed in to change notification settings - Fork 236
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6b0e56e
commit 51b3e91
Showing
2 changed files
with
161 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
#include "swap_error_code_helpers.h" | ||
#include "swap_utils.h" | ||
|
||
__attribute__((noreturn)) void send_swap_error(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code) { | ||
send_swap_error_with_buffers(status_word, | ||
common_error_code, | ||
application_specific_error_code, | ||
NULL, | ||
0); | ||
} | ||
|
||
__attribute__((noreturn)) void send_swap_error_with_buffer(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code, | ||
const buffer_t buffer_data) { | ||
send_swap_error_with_buffers(status_word, | ||
common_error_code, | ||
application_specific_error_code, | ||
&buffer_data, | ||
1); | ||
} | ||
|
||
__attribute__((noreturn)) void send_swap_error_with_buffers(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code, | ||
const buffer_t *buffer_data, | ||
size_t count) { | ||
if (!G_called_from_swap) { | ||
PRINTF("Fatal error, send_swap_error_with_buffers called outside of swap context\n"); | ||
// Don't try to recover, the caller logic has a huge issue | ||
os_sched_exit(0); | ||
} | ||
// Force G_swap_response_ready to true | ||
G_swap_response_ready = true; | ||
|
||
// Simply prepend a constructed buffer with the error code to the buffer list and use standard | ||
// io function to send | ||
uint8_t swap_error_code[2]; | ||
swap_error_code[0] = common_error_code; | ||
swap_error_code[1] = application_specific_error_code; | ||
buffer_t response[1 + SWAP_ERROR_HELPER_MAX_BUFFER_COUNT] = {0}; | ||
response[0].ptr = (uint8_t *) &swap_error_code; | ||
response[0].size = sizeof(swap_error_code); | ||
response[0].offset = 0; | ||
|
||
// Not really an error, let's just truncate without raising | ||
if (count > SWAP_ERROR_HELPER_MAX_BUFFER_COUNT) { | ||
PRINTF("send_swap_error_with_buffers truncated from %d to %d\n", | ||
count, | ||
SWAP_ERROR_HELPER_MAX_BUFFER_COUNT); | ||
count = SWAP_ERROR_HELPER_MAX_BUFFER_COUNT; | ||
} | ||
for (uint8_t i = 0; i < count; i++) { | ||
// We are only copying the buffer_t structure, not the content | ||
memcpy(&(response[i + 1]), buffer_data, sizeof(buffer_t)); | ||
} | ||
|
||
// io_send_response_buffers will use the correct flag IO_RETURN_AFTER_TX | ||
io_send_response_buffers((buffer_t *) &response, count + 1, status_word); | ||
|
||
// unreachable | ||
os_sched_exit(0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#pragma once | ||
|
||
#include "io.h" | ||
#include "buffer.h" | ||
|
||
// clang-format off | ||
/* | ||
# Error response for applications started by Exchange in SWAP context | ||
## RAPDU status word | ||
Each application must define a unique status word for every Exchange-related error. | ||
## RAPDU data | ||
The first 2 bytes of the RAPDU data represent the error code. Format is 16 bits integer in big endian. | ||
The upper byte is common between all applications. It must be one of the following value: | ||
| Name | Value | Description | | ||
| ----------------------------- | ------ | ------------------------------------ | | ||
| ERROR_INTERNAL | 0x00 | Internal application error, forward to the firmware team for analysis. | | ||
| ERROR_WRONG_AMOUNT | 0x01 | The amount does not match the one validated in Exchange. | | ||
| ERROR_WRONG_DESTINATION | 0x02 | The destination address does not match the one validated in Exchange. | | ||
| ERROR_WRONG_FEES | 0x03 | The fees are different from what was validated in Exchange. | | ||
| ERROR_WRONG_METHOD | 0x04 | The method used is invalid in Exchange context. | | ||
| ERROR_CROSSCHAIN_WRONG_MODE | 0x05 | The mode used for the cross-chain hash validation is not supported. | | ||
| ERROR_CROSSCHAIN_WRONG_METHOD | 0x06 | The method used is invalid in cross-chain Exchange context. | | ||
| ERROR_CROSSCHAIN_WRONG_HASH | 0x07 | The hash for the cross-chain transaction does not match the validated value. | | ||
| ERROR_GENERIC | 0xFF | A generic or unspecified error not covered by the specific error codes above. Refer to the remaining bytes for further details on the error. | | ||
The lower byte can be set by the application to refine the error code returned | ||
So the error code for ERROR_WRONG_METHOD would be 0x04XX with XX being application specific (can be 00 if there is nothing to refine) | ||
The remaining bytes of the data are application-specific and can include, but are not limited to: | ||
- Debugging information (e.g., error logs or internal state). | ||
- Field values (e.g., expected vs actual amounts, destination, fees). | ||
- More specific error codes tailored to the application's context. | ||
*/ | ||
// clang-format on | ||
|
||
typedef enum swap_error_common_code_e { | ||
ERROR_INTERNAL = 0x00, | ||
ERROR_WRONG_AMOUNT = 0x01, | ||
ERROR_WRONG_DESTINATION = 0x02, | ||
ERROR_WRONG_FEES = 0x03, | ||
ERROR_WRONG_METHOD = 0x04, | ||
ERROR_CROSSCHAIN_WRONG_MODE = 0x05, | ||
ERROR_CROSSCHAIN_WRONG_METHOD = 0x06, | ||
ERROR_CROSSCHAIN_WRONG_HASH = 0x07, | ||
ERROR_GENERIC = 0xFF, | ||
} swap_error_common_code_t; | ||
|
||
__attribute__((noreturn)) void send_swap_error(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code); | ||
|
||
__attribute__((noreturn)) void send_swap_error_with_buffer(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code, | ||
const buffer_t buffer_data); | ||
|
||
#define SWAP_ERROR_HELPER_MAX_BUFFER_COUNT 8 | ||
__attribute__((noreturn)) void send_swap_error_with_buffers(uint16_t status_word, | ||
uint8_t common_error_code, | ||
uint8_t application_specific_error_code, | ||
const buffer_t *buffer_data, | ||
size_t count); | ||
|
||
// Immediately call snprintf here (no function wrapping it cleanly in a .c file). | ||
// This is because we don't have a vsnprintf implementation which would be needed if | ||
// we were to pass the va_args to an intermediate function. | ||
// See https://stackoverflow.com/a/150578 | ||
#define send_swap_error_with_string(status_word, \ | ||
common_error_code, \ | ||
application_specific_error_code, \ | ||
format, \ | ||
...) \ | ||
do { \ | ||
/* Up to a full data apdu minus the status word and the swap error code */ \ | ||
char format_buffer[sizeof(G_io_apdu_buffer) - sizeof(status_word) - 2] = {0}; \ | ||
/* snprintf always returns 0 on our platform, don't check the return value */ \ | ||
/* See https://github.com/LedgerHQ/ledger-secure-sdk/issues/236 */ \ | ||
snprintf(format_buffer, sizeof(format_buffer), format, ##__VA_ARGS__); \ | ||
PRINTF("send_swap_error_with_string %s\n", format_buffer); \ | ||
buffer_t string_buffer; \ | ||
string_buffer.ptr = (uint8_t *) &format_buffer; \ | ||
string_buffer.size = strnlen(format_buffer, sizeof(format_buffer)); \ | ||
string_buffer.offset = 0; \ | ||
send_swap_error_with_buffers(status_word, \ | ||
common_error_code, \ | ||
application_specific_error_code, \ | ||
&string_buffer, \ | ||
1); \ | ||
} while (0) |