Skip to content

Commit 980875b

Browse files
authored
Merge pull request #19 from blooo-io/fix/app-update-audit-fix
fix: app update audit fix
2 parents 402feb3 + 4758913 commit 980875b

File tree

8 files changed

+89
-32
lines changed

8 files changed

+89
-32
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ PATH_APP_LOAD_PARAMS = "44'/0'" "44'/1'" "48'/0'" "48'/1'" "49'/0'" "49'/1'" "84
4545
# Application version
4646
APPVERSION_M = 1
4747
APPVERSION_N = 1
48-
APPVERSION_P = 0
48+
APPVERSION_P = 1
4949
APPVERSION_SUFFIX = # if not empty, appended at the end. Do not add a dash.
5050

5151
ifeq ($(APPVERSION_SUFFIX),)

src/handler/sign_erc4361_message.c

+52-24
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,35 @@ typedef struct {
3333
size_t max_length;
3434
} ERC4361Field;
3535

36-
static size_t parse_field(const uint8_t *buffer,
37-
size_t buffer_len,
38-
char *output,
39-
size_t max_length) {
36+
static int parse_field(const uint8_t *buffer, size_t buffer_len, char *output, size_t max_length) {
37+
// Add NULL check
38+
if (buffer == NULL || output == NULL) {
39+
return -1;
40+
}
41+
42+
// Check buffer_len to prevent buffer overflow
43+
if (buffer_len == 0 || max_length == 0) {
44+
return -1;
45+
}
46+
4047
size_t field_length = 0;
41-
while (field_length < buffer_len && field_length < max_length - 1) {
48+
// Ensure we don't exceed buffer_len or max_length-1 (for null terminator)
49+
const size_t max_field_length = (buffer_len < max_length - 1) ? buffer_len : max_length - 1;
50+
51+
while (field_length < max_field_length) {
52+
// Safe to dereference buffer here as we've checked both pointer and bounds
4253
if (buffer[field_length] == '\n' || buffer[field_length] == '\0' ||
4354
buffer[field_length] == ' ') {
4455
break;
4556
}
4657
field_length++;
4758
}
4859

60+
// Safe to use memcpy as we've validated both source and destination
4961
memcpy(output, buffer, field_length);
5062
output[field_length] = '\0';
5163

52-
return field_length;
64+
return (int) field_length; // Safe cast as field_length is bounded by max_field_length
5365
}
5466

5567
static bool has_newline(const char *buffer, size_t length) {
@@ -62,6 +74,12 @@ static bool has_newline(const char *buffer, size_t length) {
6274
}
6375

6476
void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_version) {
77+
// Add NULL check with status word
78+
if (dc == NULL) {
79+
SAFE_SEND_SW(dc, SW_BAD_STATE);
80+
return;
81+
}
82+
6583
(void) protocol_version;
6684

6785
uint8_t bip32_path_len;
@@ -172,15 +190,23 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
172190
}
173191

174192
if (current_line == 0) {
175-
size_t domain_length =
193+
int domain_length =
176194
parse_field(parsing_buffer, parsing_buffer_len, domain, MAX_DOMAIN_LENGTH);
195+
if (domain_length < 0) {
196+
SAFE_SEND_SW(dc, SW_BAD_STATE);
197+
return;
198+
}
177199
total_bytes_read += domain_length;
178200
PRINTF("Domain: %s\n", domain);
179201
}
180202

181203
if (current_line == 1) {
182-
size_t address_length =
204+
int address_length =
183205
parse_field(parsing_buffer, parsing_buffer_len, address, MAX_ADDRESS_LENGTH_STR);
206+
if (address_length < 0) {
207+
SAFE_SEND_SW(dc, SW_BAD_STATE);
208+
return;
209+
}
184210
total_bytes_read += address_length;
185211
PRINTF("Address: %s\n", address);
186212
}
@@ -191,10 +217,14 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
191217
ERC4361Field *field = &fields[i];
192218
if (parsing_buffer_len >= field->name_length &&
193219
memcmp(parsing_buffer, field->name, field->name_length) == 0) {
194-
size_t field_length = parse_field(parsing_buffer + field->name_length,
195-
parsing_buffer_len - field->name_length,
196-
field->output,
197-
field->max_length);
220+
int field_length = parse_field(parsing_buffer + field->name_length,
221+
parsing_buffer_len - field->name_length,
222+
field->output,
223+
field->max_length);
224+
if (field_length < 0) {
225+
SAFE_SEND_SW(dc, SW_BAD_STATE);
226+
return;
227+
}
198228
total_bytes_read += field_length + field->name_length;
199229
PRINTF("%s%s\n", field->name, field->output);
200230
break;
@@ -247,9 +277,7 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
247277
issued_at,
248278
expiration_time)) {
249279
SAFE_SEND_SW(dc, SW_DENY);
250-
if (!ui_post_processing_confirm_message(dc, false)) {
251-
PRINTF("Error in ui_post_processing_confirm_message");
252-
}
280+
ui_post_processing_confirm_message(dc, false);
253281
return;
254282
}
255283
#endif
@@ -265,9 +293,7 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
265293
if (sig_len < 0) {
266294
// unexpected error when signing
267295
SAFE_SEND_SW(dc, SW_BAD_STATE);
268-
if (!ui_post_processing_confirm_message(dc, false)) {
269-
PRINTF("Error in ui_post_processing_confirm_message");
270-
}
296+
ui_post_processing_confirm_message(dc, false);
271297
return;
272298
}
273299

@@ -277,15 +303,19 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
277303
uint8_t result[65];
278304
memset(result, 0, sizeof(result));
279305

306+
// Verify r_length won't cause buffer overflow
307+
if (sig[3] > MAX_DER_SIG_LEN - 5) { // -5 accounts for DER header and s_length byte
308+
SAFE_SEND_SW(dc, SW_BAD_STATE);
309+
ui_post_processing_confirm_message(dc, false);
310+
return;
311+
}
280312
// # Format signature into standard bitcoin format
281313
int r_length = sig[3];
282314
int s_length = sig[4 + r_length + 1];
283315

284316
if (r_length > 33 || s_length > 33) {
285317
SAFE_SEND_SW(dc, SW_BAD_STATE); // can never happen
286-
if (!ui_post_processing_confirm_message(dc, false)) {
287-
PRINTF("Error in ui_post_processing_confirm_message");
288-
}
318+
ui_post_processing_confirm_message(dc, false);
289319
return;
290320
}
291321

@@ -301,9 +331,7 @@ void handler_sign_erc4361_message(dispatcher_context_t *dc, uint8_t protocol_ver
301331
result[0] = 27 + 4 + ((info & CX_ECCINFO_PARITY_ODD) ? 1 : 0);
302332

303333
SEND_RESPONSE(dc, result, sizeof(result), SW_OK);
304-
if (!ui_post_processing_confirm_message(dc, true)) {
305-
PRINTF("Error in ui_post_processing_confirm_message");
306-
}
334+
ui_post_processing_confirm_message(dc, true);
307335
return;
308336
}
309337
}

src/handler/withdraw.c

+30-7
Original file line numberDiff line numberDiff line change
@@ -437,12 +437,28 @@ void fetch_and_hash_tx_data(dispatcher_context_t* dc,
437437
* @param n_chunks Number of chunks in the Merkle tree.
438438
* @param keccak_of_tx_data Pointer to the Keccak hash of the transaction data.
439439
* @param output_buffer Pointer to the buffer where the encoded transaction fields will be stored.
440+
* @param output_buffer_size Size of the output buffer (must be at least FIELD_SIZE * 11 bytes).
441+
*
442+
* @return true if successful, false if buffer size is insufficient
440443
*/
441-
void fetch_and_abi_encode_tx_fields(dispatcher_context_t* dc,
444+
bool fetch_and_abi_encode_tx_fields(dispatcher_context_t* dc,
442445
uint8_t* data_merkle_root,
443446
size_t n_chunks,
444447
uint8_t* keccak_of_tx_data,
445-
uint8_t* output_buffer) {
448+
uint8_t* output_buffer,
449+
size_t output_buffer_size) {
450+
if (dc == NULL || data_merkle_root == NULL || output_buffer == NULL) {
451+
SAFE_SEND_SW(dc, SW_BAD_STATE);
452+
return false;
453+
}
454+
455+
// Check if output buffer is large enough
456+
const size_t required_size = FIELD_SIZE * 11;
457+
if (output_buffer_size < required_size) {
458+
SAFE_SEND_SW(dc, SW_WRONG_DATA_LENGTH);
459+
return false;
460+
}
461+
446462
size_t offset = 0;
447463

448464
// Copy 'SafeTxTypeHash' field into output_buffer
@@ -484,6 +500,8 @@ void fetch_and_abi_encode_tx_fields(dispatcher_context_t* dc,
484500
offset += FIELD_SIZE;
485501
// Fetch '_nonce' field, add leading zeroes and add to output_buffer
486502
fetch_and_add_chunk_to_buffer(dc, data_merkle_root, n_chunks, 3, 0, 32, output_buffer, offset);
503+
504+
return true;
487505
}
488506

489507
/**
@@ -513,13 +531,18 @@ void compute_tx_hash(dispatcher_context_t* dc,
513531
u_int8_t keccak_of_tx_data[KECCAK_256_HASH_SIZE];
514532
// Compute keccak256 hash of the tx_data_data
515533
fetch_and_hash_tx_data(dc, data_merkle_root, n_chunks, &hash_context, keccak_of_tx_data);
534+
516535
// Fetch and ABI-encode the tx fields
517536
u_int8_t abi_encoded_tx_fields[FIELD_SIZE * 11];
518-
fetch_and_abi_encode_tx_fields(dc,
519-
data_merkle_root,
520-
n_chunks,
521-
keccak_of_tx_data,
522-
abi_encoded_tx_fields);
537+
if (!fetch_and_abi_encode_tx_fields(dc,
538+
data_merkle_root,
539+
n_chunks,
540+
keccak_of_tx_data,
541+
abi_encoded_tx_fields,
542+
sizeof(abi_encoded_tx_fields))) {
543+
return; // Error already handled in the function
544+
}
545+
523546
// Hash the abi_encoded_tx_fields
524547
u_int8_t keccak_of_abi_encoded_tx_fields[KECCAK_256_HASH_SIZE];
525548
CX_THROW(cx_keccak_init_no_throw(&hash_context, 256));

src/ui/display.c

+6
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,12 @@ bool ui_validate_erc4361_data_and_confirm(dispatcher_context_t *context,
184184
return true;
185185
#endif
186186

187+
// Add NULL checks for context and required fields
188+
if (context == NULL || domain == NULL || address == NULL || uri == NULL || version == NULL ||
189+
nonce == NULL || issued_at == NULL || expiration_time == NULL) {
190+
return false;
191+
}
192+
187193
ui_validate_erc4361_state_t *state = (ui_validate_erc4361_state_t *) &g_ui_state;
188194
// copy the erc4361 data to the state
189195
strncpy(state->domain, domain, sizeof(state->domain));
-320 Bytes
Loading
-10 Bytes
Loading
-10 Bytes
Loading
-246 Bytes
Loading

0 commit comments

Comments
 (0)