Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ to quickly **build** your apps, **test** them on **Speculos** and **load** them
- On Windows, install and launch [VcXsrv](https://sourceforge.net/projects/vcxsrv/)
(make sure to configure it to disable access control).
- Install [VScode](https://code.visualstudio.com/download) and add [Ledger's extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools).
- Restart VSCode after installing the extension.
- Open a terminal and clone `app-ethereum` with `git clone git@github.com:LedgerHQ/app-ethereum.git`.
- Open the `app-ethereum` folder with VSCode.
- Use Ledger extension's sidebar menu or open the tasks menu with `ctrl + shift + b`
Expand Down
2 changes: 1 addition & 1 deletion src/features/sign_message_eip712/ui_logic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1335,7 +1335,7 @@ void ui_712_push_pairs(void) {
// Initialize the pairs list
nbPairs = flist_size((flist_node_t **) &ui_ctx->ui_pairs);
if (N_storage.displayHash) {
nbPairs += 2;
nbPairs += 3;
}

ui_pairs_init(nbPairs);
Expand Down
35 changes: 33 additions & 2 deletions src/features/sign_message_eip712_common/common_712.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,52 @@ static char *format_hash(const uint8_t *hash, char *buffer, size_t buffer_size,
return buffer + offset;
}

static void compute_eip712_digest(void) {
CX_ASSERT(cx_keccak_init_no_throw(&global_sha3, 256));
CX_ASSERT(cx_hash_no_throw((cx_hash_t *) &global_sha3,
0,
(uint8_t *) EIP_712_MAGIC,
sizeof(EIP_712_MAGIC),
NULL,
0));
CX_ASSERT(cx_hash_no_throw((cx_hash_t *) &global_sha3,
0,
tmpCtx.messageSigningContext712.domainHash,
sizeof(tmpCtx.messageSigningContext712.domainHash),
NULL,
0));
CX_ASSERT(cx_hash_no_throw((cx_hash_t *) &global_sha3,
CX_LAST,
tmpCtx.messageSigningContext712.messageHash,
sizeof(tmpCtx.messageSigningContext712.messageHash),
tmpCtx.messageSigningContext712.eip712Digest,
sizeof(tmpCtx.messageSigningContext712.eip712Digest)));
}

void eip712_format_hash(uint8_t index) {
if ((g_pairs == NULL) || (g_pairsList == NULL) || (index >= g_pairsList->nbPairs)) {
return;
}

compute_eip712_digest();

g_pairs[index].item = "EIP-712 Digest";
g_pairs[index].value = format_hash(tmpCtx.messageSigningContext712.eip712Digest,
strings.tmp.tmp,
sizeof(strings.tmp.tmp),
0);
index++;
g_pairs[index].item = "Domain hash";
g_pairs[index].value = format_hash(tmpCtx.messageSigningContext712.domainHash,
strings.tmp.tmp,
sizeof(strings.tmp.tmp),
0);
70);
index++;
g_pairs[index].item = "Message hash";
g_pairs[index].value = format_hash(tmpCtx.messageSigningContext712.messageHash,
strings.tmp.tmp,
sizeof(strings.tmp.tmp),
70);
140);
}

/**
Expand Down
25 changes: 25 additions & 0 deletions src/features/sign_tx/eth_ustream.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "shared_context.h" // tmpContent
#include "read.h" // read_u64_be
#include "network.h" // get_tx_chain_id
#include "app_mem_utils.h" // APP_MEM_FREE_AND_NULL

static bool check_fields(txContext_t *context, const char *name, uint32_t length) {
UNUSED(name); // Just for the case where DEBUG is not enabled
Expand Down Expand Up @@ -109,6 +110,17 @@ bool copy_tx_data(txContext_t *context, uint8_t *out, uint32_t length) {
return false;
}
}
// Feed calldata bytes into the calldata digest hash (includes single-byte fields)
if (context->calldata_sha3 != NULL) {
if (cx_hash_no_throw((cx_hash_t *) context->calldata_sha3,
0,
context->workBuffer,
length,
NULL,
0) != CX_OK) {
return false;
}
}
context->workBuffer += length;
context->commandLength -= length;
if (context->processingField) {
Expand Down Expand Up @@ -350,6 +362,19 @@ static bool process_data(txContext_t *context) {
}
if (context->currentFieldPos == context->currentFieldLength) {
PRINTF("incrementing field\n");
// Finalize calldata digest if we were hashing
if (context->calldata_sha3 != NULL) {
if (cx_hash_no_throw((cx_hash_t *) context->calldata_sha3,
CX_LAST,
NULL,
0,
context->calldataDigest,
sizeof(context->calldataDigest)) != CX_OK) {
return false;
}
context->calldataDigestValid = context->content->dataPresent;
APP_MEM_FREE_AND_NULL((void **) &context->calldata_sha3);
}
context->currentField++;
context->processingField = false;
}
Expand Down
3 changes: 3 additions & 0 deletions src/features/sign_tx/eth_ustream.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ typedef struct txContext_t {
uint8_t batch_nb_tx;
uint8_t current_batch_size;
uint8_t selector_bytes[CALLDATA_SELECTOR_SIZE];
cx_sha3_t *calldata_sha3;
uint8_t calldataDigest[INT256_LENGTH];
bool calldataDigestValid;
} txContext_t;

bool init_tx(txContext_t *context, cx_sha3_t *sha3, txContent_t *content, bool store_calldata);
Expand Down
48 changes: 48 additions & 0 deletions src/features/sign_tx/logic_sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,47 @@ static uint32_t split_binary_parameter_part(char *result, size_t result_size, ui
}
}

static bool init_calldata_digest(txContext_t *context) {
uint8_t len_buf[INT256_LENGTH];

if (APP_MEM_CALLOC((void **) &context->calldata_sha3, sizeof(cx_sha3_t)) == false) {
return false;
}
if (cx_keccak_init_no_throw(context->calldata_sha3, 256) != CX_OK) {
APP_MEM_FREE_AND_NULL((void **) &context->calldata_sha3);
return false;
}
// Hash uint256(len(calldata)) as big-endian length prefix
explicit_bzero(len_buf, sizeof(len_buf));
len_buf[28] = (context->currentFieldLength >> 24) & 0xFF;
len_buf[29] = (context->currentFieldLength >> 16) & 0xFF;
len_buf[30] = (context->currentFieldLength >> 8) & 0xFF;
len_buf[31] = context->currentFieldLength & 0xFF;
if (cx_hash_no_throw((cx_hash_t *) context->calldata_sha3,
0,
len_buf,
sizeof(len_buf),
NULL,
0) != CX_OK) {
APP_MEM_FREE_AND_NULL((void **) &context->calldata_sha3);
return false;
}
return true;
}

customStatus_e custom_processor(txContext_t *context) {
if (((context->txType == LEGACY && context->currentField == LEGACY_RLP_DATA) ||
(context->txType == EIP2930 && context->currentField == EIP2930_RLP_DATA) ||
(context->txType == EIP1559 && context->currentField == EIP1559_RLP_DATA) ||
(context->txType == EIP7702 && context->currentField == EIP7702_RLP_DATA)) &&
(context->currentFieldLength != 0)) {
context->content->dataPresent = true;
// Initialize calldata digest hashing at the start of the DATA field
if (context->currentFieldPos == 0 && context->calldata_sha3 == NULL) {
if (!init_calldata_digest(context)) {
return CUSTOM_FAULT;
}
}
// If handling a new contract rather than a function call, abort immediately
if (tmpContent.txContent.destinationLength == 0) {
return CUSTOM_NOT_HANDLED;
Expand Down Expand Up @@ -134,6 +168,19 @@ customStatus_e custom_processor(txContext_t *context) {

if (context->currentFieldPos == context->currentFieldLength) {
PRINTF("\n\nIncrementing one\n");
// Finalize calldata digest if we were hashing
if (context->calldata_sha3 != NULL) {
if (cx_hash_no_throw((cx_hash_t *) context->calldata_sha3,
CX_LAST,
NULL,
0,
context->calldataDigest,
sizeof(context->calldataDigest)) != CX_OK) {
return CUSTOM_FAULT;
}
context->calldataDigestValid = context->content->dataPresent;
APP_MEM_FREE_AND_NULL((void **) &context->calldata_sha3);
}
context->currentField++;
context->processingField = false;
}
Expand Down Expand Up @@ -505,6 +552,7 @@ __attribute__((noinline)) static uint16_t finalize_parsing_helper(const txContex
}
end:
APP_MEM_FREE_AND_NULL((void **) &g_tx_hash_ctx);
APP_MEM_FREE_AND_NULL((void **) &txContext.calldata_sha3);
return error;
}

Expand Down
18 changes: 18 additions & 0 deletions src/nbgl/ui_approve_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ static bool setTagValuePairs(bool displayNetwork, bool fromPlugin) {
nbPairs++;
}
}

// Display the Calldata Digest
// ----------------------------
if (txContext.calldataDigestValid) {
strlcpy(strings.common.calldata_digest, "0x", 3);
if (bytes_to_lowercase_hex(strings.common.calldata_digest + 2,
sizeof(strings.common.calldata_digest) - 2,
txContext.calldataDigest,
INT256_LENGTH) >= 0) {
g_pairs[nbPairs].item = "Calldata Digest";
g_pairs[nbPairs].value = strings.common.calldata_digest;
nbPairs++;
}
}
}
return true;
}
Expand Down Expand Up @@ -290,6 +304,10 @@ static uint8_t getNbPairs(bool displayNetwork, bool fromPlugin) {
if ((N_storage.displayHash) || (tmpContent.txContent.dataPresent)) {
nbPairs++;
}
// Count the Calldata Digest
if (txContext.calldataDigestValid) {
nbPairs++;
}
}
return nbPairs;
}
Expand Down
4 changes: 2 additions & 2 deletions src/nbgl/ui_sign_712.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ uint16_t ui_sign_712_v0(void) {
return sw;
}

// Initialize the buffers
if (!ui_pairs_init(2)) {
// Initialize the buffers (3 pairs: EIP-712 Digest, Domain Hash, Message Hash)
if (!ui_pairs_init(3)) {
// Initialization failed, cleanup and return
return SWO_INSUFFICIENT_MEMORY;
}
Expand Down
2 changes: 2 additions & 0 deletions src/shared_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ typedef struct messageSigningContext712_t {
bip32_path_t bip32;
uint8_t domainHash[INT256_LENGTH];
uint8_t messageHash[INT256_LENGTH];
uint8_t eip712Digest[INT256_LENGTH];
} messageSigningContext712_t;

typedef struct authSigningContext7702_t {
Expand Down Expand Up @@ -145,6 +146,7 @@ typedef struct txStringProperties_s {
char nonce[8]; // 10M tx per account ought to be enough for everybody
char network_name[NETWORK_STRING_MAX_SIZE + 1];
char tx_hash[2 + (INT256_LENGTH * 2) + 1];
char calldata_digest[2 + (INT256_LENGTH * 2) + 1];
} txStringProperties_t;

#define SHARED_CTX_FIELD_1_SIZE 380
Expand Down