Skip to content

Commit

Permalink
Merge pull request #30 from steel97/audit-fixes
Browse files Browse the repository at this point in the history
Improvements
  • Loading branch information
arobsn authored Jan 24, 2025
2 parents 9c6f777 + 6fd6057 commit d779206
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 57 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/codeql-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: "CodeQL"
on:
push:
branches: ["main", "master", "develop"]
pull_request:
branches: ["main", "master", "develop"]
# Excluded path: add the paths you want to ignore instead of deleting the workflow
paths-ignore:
- '.github/workflows/*.yml'
- 'tests/*'
jobs:
analyse:
name: Analyse
strategy:
matrix:
sdk: [ "$NANOX_SDK", "$NANOSP_SDK", "$STAX_SDK", "$FLEX_SDK" ]
#'cpp' covers C and C++
language: [ 'cpp' ]
runs-on: ubuntu-latest
container:
image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest
steps:
- name: Clone
uses: actions/checkout@v3
with:
submodules: recursive
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-and-quality
# CodeQL will create the database during the compilation
- name: Build
run: |
make BOLOS_SDK=${{ matrix.sdk }}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
6 changes: 3 additions & 3 deletions doc/INS-20-ATTEST-BOX.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ To avoid any confusion, Authorization Token and Session ID are two different val
| Transaction ID | 32 | ID of the Transaction containing this Box |
| Box Index | 2 | Box index in the Transaction. Big-endian |
| Value | 8 | Box value. Big-endian. |
| Ergo Tree Size | 4 | Size in bytes of serialized Ergo Tree data. Big-endian. |
| Ergo Tree Size | 4 | Size in bytes of serialized Ergo Tree data. Big-endian. Limited to 32768 bytes |
| Creation Height | 4 | Big-endian |
| Tokens Count | 1 | Tokens count inside the Box |
| Additional Registers Size | 4 | Size in bytes of serialized Additional Registers data. Big-endian |
| Additional Registers Size | 4 | Size in bytes of serialized Additional Registers data. Big-endian. Limited to 32768 bytes |
| [Optional] Auth Token | 4 | Big-endian. Randomly generated value. Becomes an ID for the session for future use, i.e. once transaction signing is requested. If present, **P2** should be set to 0x02 |

### Response
Expand Down Expand Up @@ -82,7 +82,7 @@ If Box is finished then 1 byte of the data (amount of frames) or empty if more d

## 0x04 - Add Registers chunk

Add Registers data chunk to the current Box. Can be used only when Box has additional registers size > 0.
Add Registers data chunk to the current Box. Can be used only when Box has additional registers size > 0 and after tokens have been added.

### Request
| INS | P1 | P2 | Lc | Data |
Expand Down
5 changes: 4 additions & 1 deletion src/commands/attestinput/ainpt_response.c
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ int send_response_attested_input_frame(attest_input_ctx_t *ctx,
CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, tokens_count));

uint8_t offset = index * FRAME_MAX_TOKENS_COUNT;
for (uint8_t i = offset; i < offset + tokens_count; i++) {
if (offset + tokens_count > 255) {
return send_error(SW_TOO_MUCH_DATA);
}
for (uint8_t i = offset; i < (uint8_t) (offset + tokens_count); i++) {
CHECK_WRITE_PARAM(rw_buffer_write_bytes(&output, ctx->tokens_table.tokens[i], ERGO_ID_LEN));
CHECK_WRITE_PARAM(rw_buffer_write_u64(&output, ctx->token_amounts[i], BE));
}
Expand Down
7 changes: 7 additions & 0 deletions src/commands/deriveaddress/da_ui_nbgl.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void ui_address_flow_end(void) {
set_flow_response(true);
}

// Display
int ui_display_address(derive_address_ctx_t* ctx,
bool send,
uint32_t app_access_token,
Expand All @@ -45,6 +46,7 @@ int ui_display_address(derive_address_ctx_t* ctx,
return send_error(SW_BIP32_BAD_PATH);
}

// Set required context fields
ctx->app_token_value = app_access_token;
ctx->send = send;

Expand All @@ -69,10 +71,12 @@ int ui_display_address(derive_address_ctx_t* ctx,

int n_pairs = 0;

// Prepare derivation path display pair
pairs_global[n_pairs].item = "Derivation path";
pairs_global[n_pairs].value = ctx->bip32_path;
n_pairs++;

// Add application id display pair if app_access_token is not equal to zero
if (app_access_token != 0) {
pairs_global[n_pairs++] = ui_application_id_screen(app_access_token, app_id_buf);
}
Expand All @@ -81,6 +85,7 @@ int ui_display_address(derive_address_ctx_t* ctx,
strncpy(addr_buf, ctx->address, MEMBER_SIZE(derive_address_ctx_t, address));
}

// Prepare pair_list before showing review screen
pair_list.nbMaxLinesForValue = 0;
pair_list.nbPairs = n_pairs;
pair_list.pairs = pairs_global;
Expand Down Expand Up @@ -117,6 +122,7 @@ int ui_display_address(derive_address_ctx_t* ctx,
res_ok();
}

// Show result screen
if (send) {
nbgl_useCaseStatus("Address exported", true, ui_address_flow_end);
} else {
Expand All @@ -126,6 +132,7 @@ int ui_display_address(derive_address_ctx_t* ctx,
app_set_current_command(CMD_NONE);
res_deny();

// Show result screen
if (send) {
nbgl_useCaseStatus("Address export\ncancelled", false, ui_address_flow_end);
} else {
Expand Down
2 changes: 0 additions & 2 deletions src/commands/signtx/stx_ui_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,9 @@ static NOINLINE bool ui_stx_operation_output_confirm_action(bool approved, void*
&ctx->output->bip32_path,
sizeof(sign_transaction_bip32_path_t));
}
// res_ok();
return true;
} else {
app_set_current_command(CMD_NONE);
// res_deny();
}

ui_menu_main();
Expand Down
66 changes: 28 additions & 38 deletions src/commands/signtx/stx_ui_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,48 +66,38 @@ uint16_t ui_stx_display_tx_state(uint8_t screen, char* title, char* text, void*
return ctx->op_screen_cb(screen, title, title_len, text, text_len, ctx->op_cb_context);
}
screen -= ctx->op_screen_count;
switch (screen) {
/*case 0: { // TX Value
strncpy(title, "Transaction Amount", title_len);
if (!format_erg_amount(ctx->amounts->value, text, text_len)) {
return SW_BUFFER_ERROR;
}
break;
}*/
case 0: { // TX Fee
strncpy(title, "Fee", title_len);
if (!format_erg_amount(ctx->amounts->fee, text, text_len)) {
return SW_BUFFER_ERROR;
}
break;
if (screen == 0) {
strncpy(title, "Fee", title_len);
if (!format_erg_amount(ctx->amounts->fee, text, text_len)) {
return SW_BUFFER_ERROR;
}
default: { // Tokens
screen -= 1; // Decrease index for info screens
uint8_t token_idx = stx_amounts_non_zero_token_index(ctx->amounts, screen / 2);
if (!IS_ELEMENT_FOUND(token_idx)) { // error. bad index state
return SW_BAD_TOKEN_INDEX;
} else {
// Tokens
screen -= 1; // Decrease index for info screens
uint8_t token_idx = stx_amounts_non_zero_token_index(ctx->amounts, screen / 2);
if (!IS_ELEMENT_FOUND(token_idx)) { // error. bad index state
return SW_BAD_TOKEN_INDEX;
}
if (screen % 2 == 0) { // Token ID
snprintf(title, title_len, "Token [%d]", (int) (screen / 2) + 1);
if (!format_hex_id(ctx->amounts->tokens_table.tokens[token_idx],
ERGO_ID_LEN,
text,
text_len)) {
return SW_ADDRESS_FORMATTING_FAILED;
}
if (screen % 2 == 0) { // Token ID
snprintf(title, title_len, "Token [%d]", (int) (screen / 2) + 1);
if (!format_hex_id(ctx->amounts->tokens_table.tokens[token_idx],
ERGO_ID_LEN,
text,
text_len)) {
return SW_ADDRESS_FORMATTING_FAILED;
}
} else { // Token Value
snprintf(title, title_len, "Token [%d] Raw Value", (int) (screen / 2) + 1);
int64_t value = ctx->amounts->tokens[token_idx];
if (value < 0) { // output > inputs
STRING_ADD_STATIC_TEXT(text, text_len, "Minting: ");
format_u64(text, text_len, -value);
} else { // inputs > outputs
STRING_ADD_STATIC_TEXT(text, text_len, "Burning: ");
format_u64(text, text_len, value);
}
} else { // Token Value
snprintf(title, title_len, "Token [%d] Raw Value", (int) (screen / 2) + 1);
int64_t value = ctx->amounts->tokens[token_idx];
if (value < 0) { // output > inputs
STRING_ADD_STATIC_TEXT(text, text_len, "Minting: ");
format_u64(text, text_len, -value);
} else { // inputs > outputs
STRING_ADD_STATIC_TEXT(text, text_len, "Burning: ");
format_u64(text, text_len, value);
}
break;
}
}

return SW_OK;
}
3 changes: 0 additions & 3 deletions src/common/bip32_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@ bool bip32_path_validate(const uint32_t *bip32_path,
case BIP32_PATH_VALIDATE_ACCOUNT_E3:
return bip32_path_len == 3 && bip32_path[2] >= BIP32_HARDENED_CONSTANT;
case BIP32_PATH_VALIDATE_ACCOUNT_GE3:
if (bip32_path_len < 3) {
return false;
}
for (uint8_t i = 2; i < bip32_path_len; i++) {
if (bip32_path[i] < BIP32_HARDENED_CONSTANT) {
return false;
Expand Down
7 changes: 1 addition & 6 deletions src/ergo/ergo_tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,7 @@ bool ergo_tree_parse_p2sh(const uint8_t tree[ERGO_TREE_P2SH_LEN],
}

void ergo_tree_miners_fee_tree(bool is_mainnet, const uint8_t** tree, size_t* size) {
// if (is_mainnet) {
UNUSED(is_mainnet);
*size = sizeof(C_ERGO_TREE_MINERS_HASH_FEE_MAINNET);
*tree = PIC(C_ERGO_TREE_MINERS_HASH_FEE_MAINNET);
// } else {
// *size = sizeof(C_ERGO_TREE_MINERS_HASH_FEE_TESTNET);
// *tree = PIC(C_ERGO_TREE_MINERS_HASH_FEE_TESTNET);
// }
}
}
2 changes: 1 addition & 1 deletion src/ergo/schnorr.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ bool ergo_secp256k1_schnorr_p2pk_sign_init(cx_blake2b_t* hash,
// check private key has a proper value
if (cx_math_is_zero(secret, PRIVATE_KEY_LEN)) break;
if (cx_math_cmp_no_throw(secret, PIC(SECP256K1_N), PRIVATE_KEY_LEN, &cmp_diff) != 0 ||
cmp_diff > 0)
cmp_diff >= 0)
break;

// pk = G * secret (pub key)
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/sw_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ static inline uint16_t sw_from_tx_full_result(ergo_tx_serializer_full_result_e r
case ERGO_TX_SERIALIZER_FULL_RES_ERR_SMALL_CHUNK:
return SW_SMALL_CHUNK;
}

return SW_BAD_STATE;
}

static inline uint16_t sw_from_tx_box_result(ergo_tx_serializer_box_result_e res) {
Expand Down Expand Up @@ -80,4 +82,6 @@ static inline uint16_t sw_from_tx_box_result(ergo_tx_serializer_box_result_e res
case ERGO_TX_SERIALIZER_BOX_RES_ERR_SMALL_CHUNK:
return SW_SMALL_CHUNK;
}

return SW_BAD_STATE;
}
9 changes: 6 additions & 3 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ npm install
First start your application with Speculos

```
./path/to/speculos.py /path/to/bin/app.elf --apdu-port 9999 --api-port 40000
export SEED=`cat '/path/to/tests/seed.txt'`
./path/to/speculos.py /path/to/bin/app.elf --apdu-port 9999 --seed "$SEED"
```

then run

```
npm run test
npm run test --model=<model>
```

### Launch with your Nano S+/X

Be sure to have you device connected through USB (without any other software interacting with it) and run

```
LEDGER_LIVE_HARDWARE=1 npm run test
LEDGER_LIVE_HARDWARE=1 npm run test --model=<model>
```

`<model>` can be either `nanox` or `nanosp`

0 comments on commit d779206

Please sign in to comment.