From ead85a0aaa45755e2068b1ea33363a517020c345 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Wed, 2 Nov 2022 13:34:26 +0100 Subject: [PATCH 01/79] Add funcs to avoid tricking user when using plugin Usually the length of an array is sent in a parameter. Most of the times the developer simply uses U2BE/U4BE to get this length. It is possible to forge a tx with a `length > sizeof(uint16_t/uint32_t)` and trick the user into signing something different from what is shown. For instance consider the following parameter: 00 ... 01 00 00 00 01 if the developer uses U2BE/U4BE, it is possible that this length is shown to the user and if it is, the user will see the length as 1. --- doc/ethapp_plugins.adoc | 11 +++++++++++ src/eth_plugin_internal.c | 19 +++++++++++++++++++ src/eth_plugin_internal.h | 4 ++++ tools/build_sdk.py | 2 +- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/doc/ethapp_plugins.adoc b/doc/ethapp_plugins.adoc index af89087..61f6e0d 100644 --- a/doc/ethapp_plugins.adoc +++ b/doc/ethapp_plugins.adoc @@ -134,6 +134,17 @@ The following return codes are expected, any other will abort the signing proces * ETH_PLUGIN_RESULT_OK : if the plugin can be successfully initialized * ETH_PLUGIN_RESULT_FALLBACK : if the signing logic should fallback to the generic one +There are already defined functions to extract data from a parameter: +[source,C] +---- +void copy_address(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); +void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); + +// Get the value from the beginning of the parameter (right to left) and check if the rest of it is zero +bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value); +bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value); +---- + ### ETH_PLUGIN_FINALIZE [source,C] diff --git a/src/eth_plugin_internal.c b/src/eth_plugin_internal.c index b266969..b608177 100644 --- a/src/eth_plugin_internal.c +++ b/src/eth_plugin_internal.c @@ -1,5 +1,6 @@ #include #include "eth_plugin_internal.h" +#include "ethUtils.h" // allzeroes bool erc20_plugin_available_check(void); @@ -15,6 +16,24 @@ void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size) { memmove(dst, parameter, copy_size); } +bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value) { + if (allzeroes(parameter, PARAMETER_LENGTH - sizeof(uint16_t))) { + *value = U2BE(parameter, PARAMETER_LENGTH - sizeof(uint16_t)); + return true; + } + + return false; +} + +bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value) { + if (allzeroes(parameter, PARAMETER_LENGTH - sizeof(uint32_t))) { + *value = U4BE(parameter, PARAMETER_LENGTH - sizeof(uint32_t)); + return true; + } + + return false; +} + #ifdef HAVE_STARKWARE void starkware_plugin_call(int message, void* parameters); #endif diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h index 1ad8382..3d7ee55 100644 --- a/src/eth_plugin_internal.h +++ b/src/eth_plugin_internal.h @@ -16,6 +16,10 @@ void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); void erc721_plugin_call(int message, void* parameters); void erc1155_plugin_call(int message, void* parameters); +// Get the value from the beginning of the parameter (right to left) and check if the rest of it is zero +bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value); +bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value); + typedef bool (*PluginAvailableCheck)(void); typedef struct internalEthPlugin_t { diff --git a/tools/build_sdk.py b/tools/build_sdk.py index aab3a6e..b68b368 100755 --- a/tools/build_sdk.py +++ b/tools/build_sdk.py @@ -164,7 +164,7 @@ if __name__ == "__main__": "typedef union": ["extraInfo_t"], "__attribute__((no_instrument_function)) inline": ["int allzeroes"], "const": ["HEXDIGITS"], - "fn": ["void getEthAddressStringFromBinary", "void getEthAddressFromKey", "void getEthDisplayableAddress", "bool adjustDecimals", "bool uint256_to_decimal", "void amountToString", "void u64_to_string", "void copy_address", "void copy_parameter"] + "fn": ["void getEthAddressStringFromBinary", "void getEthAddressFromKey", "void getEthDisplayableAddress", "bool adjustDecimals", "bool uint256_to_decimal", "void amountToString", "void u64_to_string", "void copy_address", "void copy_parameter", "bool U2BE_from_parameter", "U4BE_from_parameter"] } merge_headers(headers_to_merge, nodes_to_extract) From b120fc6565e4e7263db6e47fcf98c94bda8eb2bd Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Tue, 8 Nov 2022 09:56:00 +0100 Subject: [PATCH 02/79] fix code style --- src/eth_plugin_internal.c | 2 +- src/eth_plugin_internal.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/eth_plugin_internal.c b/src/eth_plugin_internal.c index b608177..40a6f70 100644 --- a/src/eth_plugin_internal.c +++ b/src/eth_plugin_internal.c @@ -1,6 +1,6 @@ #include #include "eth_plugin_internal.h" -#include "ethUtils.h" // allzeroes +#include "ethUtils.h" // allzeroes bool erc20_plugin_available_check(void); diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h index 3d7ee55..cb5521f 100644 --- a/src/eth_plugin_internal.h +++ b/src/eth_plugin_internal.h @@ -16,7 +16,8 @@ void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); void erc721_plugin_call(int message, void* parameters); void erc1155_plugin_call(int message, void* parameters); -// Get the value from the beginning of the parameter (right to left) and check if the rest of it is zero +// Get the value from the beginning of the parameter (right to left) and check if the rest of it is +// zero bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value); bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value); From 51db776de6c3f8611c6b17152497e9ad4b6e8087 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Tue, 8 Nov 2022 09:57:24 +0100 Subject: [PATCH 03/79] add const to parameters --- src/eth_plugin_internal.c | 4 ++-- src/eth_plugin_internal.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eth_plugin_internal.c b/src/eth_plugin_internal.c index 40a6f70..075f2ec 100644 --- a/src/eth_plugin_internal.c +++ b/src/eth_plugin_internal.c @@ -16,7 +16,7 @@ void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size) { memmove(dst, parameter, copy_size); } -bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value) { +bool U2BE_from_parameter(const uint8_t* parameter, uint16_t* value) { if (allzeroes(parameter, PARAMETER_LENGTH - sizeof(uint16_t))) { *value = U2BE(parameter, PARAMETER_LENGTH - sizeof(uint16_t)); return true; @@ -25,7 +25,7 @@ bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value) { return false; } -bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value) { +bool U4BE_from_parameter(const uint8_t* parameter, uint32_t* value) { if (allzeroes(parameter, PARAMETER_LENGTH - sizeof(uint32_t))) { *value = U4BE(parameter, PARAMETER_LENGTH - sizeof(uint32_t)); return true; diff --git a/src/eth_plugin_internal.h b/src/eth_plugin_internal.h index cb5521f..692c9b6 100644 --- a/src/eth_plugin_internal.h +++ b/src/eth_plugin_internal.h @@ -18,8 +18,8 @@ void erc1155_plugin_call(int message, void* parameters); // Get the value from the beginning of the parameter (right to left) and check if the rest of it is // zero -bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value); -bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value); +bool U2BE_from_parameter(const uint8_t* parameter, uint16_t* value); +bool U4BE_from_parameter(const uint8_t* parameter, uint32_t* value); typedef bool (*PluginAvailableCheck)(void); From 65d2c88f2da174935c4ac1333fe395ee969d78d7 Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Tue, 8 Nov 2022 10:22:26 +0100 Subject: [PATCH 04/79] update docs --- doc/ethapp_plugins.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ethapp_plugins.adoc b/doc/ethapp_plugins.adoc index 61f6e0d..a3bdbbe 100644 --- a/doc/ethapp_plugins.adoc +++ b/doc/ethapp_plugins.adoc @@ -141,8 +141,8 @@ void copy_address(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); void copy_parameter(uint8_t* dst, const uint8_t* parameter, uint8_t dst_size); // Get the value from the beginning of the parameter (right to left) and check if the rest of it is zero -bool U2BE_from_parameter(uint8_t* parameter, uint16_t* value); -bool U4BE_from_parameter(uint8_t* parameter, uint32_t* value); +bool U2BE_from_parameter(const uint8_t* parameter, uint16_t* value); +bool U4BE_from_parameter(const uint8_t* parameter, uint32_t* value); ---- ### ETH_PLUGIN_FINALIZE From a49752fe9b76fba51f75afd937d08d6963a3988d Mon Sep 17 00:00:00 2001 From: Jorge Martins Date: Tue, 8 Nov 2022 11:23:14 +0100 Subject: [PATCH 05/79] allzeroes const void* buf --- src_common/ethUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_common/ethUtils.h b/src_common/ethUtils.h index 0755b13..9722e2c 100644 --- a/src_common/ethUtils.h +++ b/src_common/ethUtils.h @@ -66,7 +66,7 @@ bool adjustDecimals(const char *src, size_t targetLength, uint8_t decimals); -static __attribute__((no_instrument_function)) inline int allzeroes(void *buf, size_t n) { +static __attribute__((no_instrument_function)) inline int allzeroes(const void *buf, size_t n) { uint8_t *p = (uint8_t *) buf; for (size_t i = 0; i < n; ++i) { if (p[i]) { From 800116ee9d6b34deaad0445bd4fa6603e4dadbaa Mon Sep 17 00:00:00 2001 From: Clement Bouvet Date: Thu, 10 Nov 2022 13:32:20 +0100 Subject: [PATCH 06/79] cmd_signMessage712.c: use common ui --- src_features/signMessageEIP712_v0/cmd_signMessage712.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_features/signMessageEIP712_v0/cmd_signMessage712.c b/src_features/signMessageEIP712_v0/cmd_signMessage712.c index 539e8f0..deaab84 100644 --- a/src_features/signMessageEIP712_v0/cmd_signMessage712.c +++ b/src_features/signMessageEIP712_v0/cmd_signMessage712.c @@ -1,7 +1,7 @@ #include "shared_context.h" #include "apdu_constants.h" #include "utils.h" -#include "ui_flow.h" +#include "common_ui.h" #include "common_712.h" #include "ethUtils.h" @@ -33,7 +33,7 @@ void handleSignEIP712Message_v0(uint8_t p1, #ifdef NO_CONSENT io_seproxyhal_touch_signMessage_ok(NULL); #else // NO_CONSENT - ux_flow_init(0, ux_sign_712_v0_flow, NULL); + ui_sign_712_v0(); #endif // NO_CONSENT *flags |= IO_ASYNCH_REPLY; From f26f5e21852d44a5653baa7cf57f952dc9fe1b61 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 10 Nov 2022 16:43:47 +0100 Subject: [PATCH 07/79] Version bump to 1.10.2-dev --- CHANGELOG.md | 2 ++ Makefile | 4 ++-- tests/speculos/test_configuration_cmd.py | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ebd76b..7846305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-XX-XX + ## [1.10.1](https://github.com/ledgerhq/app-ethereum/compare/1.10.0...1.10.1) - 2022-11-09 ### Fixed diff --git a/Makefile b/Makefile index 0adefe5..b0dfbb5 100644 --- a/Makefile +++ b/Makefile @@ -34,8 +34,8 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" APPVERSION_M=1 APPVERSION_N=10 -APPVERSION_P=1 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) +APPVERSION_P=2 +APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION) ########################### diff --git a/tests/speculos/test_configuration_cmd.py b/tests/speculos/test_configuration_cmd.py index 55c99ac..1d84839 100644 --- a/tests/speculos/test_configuration_cmd.py +++ b/tests/speculos/test_configuration_cmd.py @@ -1,10 +1,10 @@ def test_configuration(cmd): if cmd.model == "nanos": - assert cmd.get_configuration() == (14, 1, 10, 1) + assert cmd.get_configuration() == (14, 1, 10, 2) if cmd.model == "nanox": - assert cmd.get_configuration() == (14, 1, 10, 1) + assert cmd.get_configuration() == (14, 1, 10, 2) if cmd.model == "nanosp": - assert cmd.get_configuration() == (14, 1, 10, 1) + assert cmd.get_configuration() == (14, 1, 10, 2) From fcc9f7ab8487878d02a1a477d13e41b696ffcc85 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 15 Nov 2022 16:38:23 +0100 Subject: [PATCH 08/79] Update actions to fix deprecation warnings --- .github/workflows/auto-author-assign.yml | 2 +- .github/workflows/build-workflow.yml | 2 +- .github/workflows/ci-workflow.yml | 32 ++++++++++++------------ .github/workflows/lint-workflow.yml | 2 +- .github/workflows/sdk-generation.yml | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/auto-author-assign.yml b/.github/workflows/auto-author-assign.yml index acd55ab..373f8bc 100644 --- a/.github/workflows/auto-author-assign.yml +++ b/.github/workflows/auto-author-assign.yml @@ -11,4 +11,4 @@ jobs: assign-author: runs-on: ubuntu-latest steps: - - uses: toshimaru/auto-author-assign@v1.4.0 + - uses: toshimaru/auto-author-assign@v1 diff --git a/.github/workflows/build-workflow.yml b/.github/workflows/build-workflow.yml index 46f714b..1eb105d 100644 --- a/.github/workflows/build-workflow.yml +++ b/.github/workflows/build-workflow.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build Ethereum run: | diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index e5357df..490928d 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -18,14 +18,14 @@ jobs: image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build with Clang Static Analyzer run: | make clean scan-build --use-cc=clang -analyze-headers -enable-checker security -enable-checker unix -enable-checker valist -o scan-build --status-bugs make default - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: failure() with: name: scan-build @@ -42,7 +42,7 @@ jobs: image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build testing binaries run: | @@ -50,7 +50,7 @@ jobs: cd tests/zemu/ && ./build_local_test_elfs.sh - name: Upload app binaries - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: e2e_zemu_elfs path: ./tests/zemu/elfs/ @@ -68,12 +68,12 @@ jobs: echo $DISPLAY - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev - name: Install node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: "14.4.0" @@ -87,7 +87,7 @@ jobs: run: mkdir tests/zemu/elfs - name: Download app binaries - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: path: tmp/ @@ -109,7 +109,7 @@ jobs: image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build testing binaries run: | @@ -119,7 +119,7 @@ jobs: make clean && make -j DEBUG=1 NFT_TESTING_KEY=1 BOLOS_SDK=$NANOSP_SDK && mv bin/app.elf tests/speculos/elfs/nanosp.elf - name: Upload app binaries - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: e2e_speculos_elfs path: ./tests/speculos/elfs @@ -136,13 +136,13 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Create tmp folder for artifacts run: mkdir tests/speculos/elfs - name: Download app binaries - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: path: tmp/ @@ -173,7 +173,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Build test binaries run: | @@ -187,7 +187,7 @@ jobs: mv bin/app.elf app-nanosp.elf - name: Upload app binaries - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ragger_elfs path: ./app-*.elf @@ -198,7 +198,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: APT update run: | @@ -243,10 +243,10 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Download previously built artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: ragger_elfs path: tmp/ diff --git a/.github/workflows/lint-workflow.yml b/.github/workflows/lint-workflow.yml index f74416d..7b98075 100644 --- a/.github/workflows/lint-workflow.yml +++ b/.github/workflows/lint-workflow.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Lint uses: DoozyX/clang-format-lint-action@v0.14 diff --git a/.github/workflows/sdk-generation.yml b/.github/workflows/sdk-generation.yml index 4593b41..00cdbb0 100644 --- a/.github/workflows/sdk-generation.yml +++ b/.github/workflows/sdk-generation.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # by default the action uses fetch-depth = 1, which creates # shallow repositories from which we can't push From 60fc9c141784976a8f935da4071562f1943ae3ab Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 15 Nov 2022 18:11:03 +0100 Subject: [PATCH 09/79] Add missing function return type to SDK generation script for consistency --- tools/build_sdk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/build_sdk.py b/tools/build_sdk.py index b68b368..a808e4a 100755 --- a/tools/build_sdk.py +++ b/tools/build_sdk.py @@ -164,7 +164,7 @@ if __name__ == "__main__": "typedef union": ["extraInfo_t"], "__attribute__((no_instrument_function)) inline": ["int allzeroes"], "const": ["HEXDIGITS"], - "fn": ["void getEthAddressStringFromBinary", "void getEthAddressFromKey", "void getEthDisplayableAddress", "bool adjustDecimals", "bool uint256_to_decimal", "void amountToString", "void u64_to_string", "void copy_address", "void copy_parameter", "bool U2BE_from_parameter", "U4BE_from_parameter"] + "fn": ["void getEthAddressStringFromBinary", "void getEthAddressFromKey", "void getEthDisplayableAddress", "bool adjustDecimals", "bool uint256_to_decimal", "void amountToString", "void u64_to_string", "void copy_address", "void copy_parameter", "bool U2BE_from_parameter", "bool U4BE_from_parameter"] } merge_headers(headers_to_merge, nodes_to_extract) From 55a4b48f18c6222c7cc99824fc9f092e59e25151 Mon Sep 17 00:00:00 2001 From: Lucas PASCAL Date: Wed, 16 Nov 2022 12:14:57 +0100 Subject: [PATCH 10/79] [fix] 'github-push-action' does not seem to cope with src:dst git push syntax --- .github/actions/commit-changes/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/commit-changes/action.yml b/.github/actions/commit-changes/action.yml index 0099ad6..f572b32 100644 --- a/.github/actions/commit-changes/action.yml +++ b/.github/actions/commit-changes/action.yml @@ -114,6 +114,6 @@ runs: uses: ad-m/github-push-action@master with: github_token: ${{ inputs.secret }} - branch: ${{ steps.commit.outputs.src_branch }}:${{ steps.commit.outputs.dst_branch }} + branch: ${{ steps.commit.outputs.dst_branch }} directory: ${{ inputs.directory }} repository: ${{ inputs.repository }} From 3e455250d2579790d1456371cef42a540a57539f Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 13:52:49 +0100 Subject: [PATCH 11/79] Explicit github action version, v1 tag does not exist --- .github/workflows/auto-author-assign.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-author-assign.yml b/.github/workflows/auto-author-assign.yml index 373f8bc..a6255c9 100644 --- a/.github/workflows/auto-author-assign.yml +++ b/.github/workflows/auto-author-assign.yml @@ -11,4 +11,4 @@ jobs: assign-author: runs-on: ubuntu-latest steps: - - uses: toshimaru/auto-author-assign@v1 + - uses: toshimaru/auto-author-assign@v1.6.1 From 309c09b599ca479d959b955c3ab24bc13924d09a Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 13:50:17 +0100 Subject: [PATCH 12/79] Added new public CAL testing key in app --- Makefile | 12 ++++++++---- src/tokens.h | 26 ++++++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index b0dfbb5..81da667 100644 --- a/Makefile +++ b/Makefile @@ -147,10 +147,14 @@ ifneq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_EIP712_FULL_SUPPORT endif -# CryptoAssetsList testing key -CAL_TESTING_KEY:=0 -ifneq ($(CAL_TESTING_KEY),0) -DEFINES += HAVE_CAL_TESTING_KEY +# CryptoAssetsList key +CAL_TEST_KEY:=0 +CAL_CI_KEY:=0 +ifneq ($(CAL_TEST_KEY),0) +DEFINES += HAVE_CAL_TEST_KEY +endif +ifneq ($(CAL_CI_KEY),0) +DEFINES += HAVE_CAL_CI_KEY endif # Enabling debug PRINTF diff --git a/src/tokens.h b/src/tokens.h index 7aa38f6..0a10125 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -43,21 +43,31 @@ extern tokenDefinition_t const TOKENS_EXTRA[NUM_TOKENS_EXTRA]; #ifndef HAVE_TOKENS_LIST +#if defined(HAVE_CAL_TEST_KEY) && defined(HAVE_CAL_CI_KEY) +#error "CAL key contradiction, two alternative keys selected at once" +#endif + static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { -#ifndef HAVE_CAL_TESTING_KEY - // production key 2019-01-11 03:07PM (erc20signer) - 0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, - 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30, - 0xfe, 0x4e, 0x8c, 0xc7, 0x6b, 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44, - 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce, - 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83 -#else +#if defined(HAVE_CAL_TEST_KEY) // test key 2019-01-11 03:07PM (erc20signer) 0x04, 0x20, 0xda, 0x62, 0x00, 0x3c, 0x0c, 0xe0, 0x97, 0xe3, 0x36, 0x44, 0xa1, 0x0f, 0xe4, 0xc3, 0x04, 0x54, 0x06, 0x9a, 0x44, 0x54, 0xf0, 0xfa, 0x9d, 0x4e, 0x84, 0xf4, 0x50, 0x91, 0x42, 0x9b, 0x52, 0x20, 0xaf, 0x9e, 0x35, 0xc0, 0xb2, 0xd9, 0x28, 0x93, 0x80, 0x13, 0x73, 0x07, 0xde, 0x4d, 0xd1, 0xd4, 0x18, 0x42, 0x8c, 0xf2, 0x1a, 0x93, 0xb3, 0x35, 0x61, 0xbb, 0x09, 0xd8, 0x8f, 0xe5, 0x79 +#elif defined(HAVE_CAL_CI_KEY) + 0x04, 0x4c, 0xca, 0x8f, 0xad, 0x49, 0x6a, 0xa5, 0x04, 0x0a, 0x00, 0xa7, 0xeb, 0x2f, + 0x5c, 0xc3, 0xb8, 0x53, 0x76, 0xd8, 0x8b, 0xa1, 0x47, 0xa7, 0xd7, 0x05, 0x4a, 0x99, + 0xc6, 0x40, 0x56, 0x18, 0x87, 0xfe, 0x17, 0xa0, 0x96, 0xe3, 0x6c, 0x3b, 0x52, 0x3b, + 0x24, 0x4f, 0x3e, 0x2f, 0xf7, 0xf8, 0x40, 0xae, 0x26, 0xc4, 0xe7, 0x7a, 0xd3, 0xbc, + 0x73, 0x9a, 0xf5, 0xde, 0x6f, 0x2d, 0x77, 0xa7, 0xb6 +#else + // production key 2019-01-11 03:07PM (erc20signer) + 0x04, 0x5e, 0x6c, 0x10, 0x20, 0xc1, 0x4d, 0xc4, 0x64, 0x42, 0xfe, 0x89, 0xf9, 0x7c, + 0x0b, 0x68, 0xcd, 0xb1, 0x59, 0x76, 0xdc, 0x24, 0xf2, 0x4c, 0x31, 0x6e, 0x7b, 0x30, + 0xfe, 0x4e, 0x8c, 0xc7, 0x6b, 0x14, 0x89, 0x15, 0x0c, 0x21, 0x51, 0x4e, 0xbf, 0x44, + 0x0f, 0xf5, 0xde, 0xa5, 0x39, 0x3d, 0x83, 0xde, 0x53, 0x58, 0xcd, 0x09, 0x8f, 0xce, + 0x8f, 0xd0, 0xf8, 0x1d, 0xaa, 0x94, 0x97, 0x91, 0x83 #endif }; From b1d6e9851d14da68c35b78661144a780a28151cb Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 14:20:13 +0100 Subject: [PATCH 13/79] Now compiles the app with the new CAL key for Ragger tests --- .github/workflows/ci-workflow.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 490928d..ff7c218 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -177,13 +177,13 @@ jobs: - name: Build test binaries run: | - make -j BOLOS_SDK=$NANOS_SDK CAL_TESTING_KEY=1 + make -j BOLOS_SDK=$NANOS_SDK CAL_CI_KEY=1 mv bin/app.elf app-nanos.elf make clean - make -j BOLOS_SDK=$NANOX_SDK CAL_TESTING_KEY=1 + make -j BOLOS_SDK=$NANOX_SDK CAL_CI_KEY=1 mv bin/app.elf app-nanox.elf make clean - make -j BOLOS_SDK=$NANOSP_SDK CAL_TESTING_KEY=1 + make -j BOLOS_SDK=$NANOSP_SDK CAL_CI_KEY=1 mv bin/app.elf app-nanosp.elf - name: Upload app binaries From bbe1723b25b25607a7b35ed24428ce048a8110b2 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 15:08:06 +0100 Subject: [PATCH 14/79] Added new private CAL key file for CI --- tests/ragger/cal/key.pem | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/ragger/cal/key.pem diff --git a/tests/ragger/cal/key.pem b/tests/ragger/cal/key.pem new file mode 100644 index 0000000..338e49f --- /dev/null +++ b/tests/ragger/cal/key.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIHoMkoRaNq0neb1TxRBor4WouV8PQqJf02sg4eh768LpoAcGBSuBBAAK +oUQDQgAETMqPrUlqpQQKAKfrL1zDuFN22IuhR6fXBUqZxkBWGIf+F6CW42w7Ujsk +Tz4v9/hAribE53rTvHOa9d5vLXentg== +-----END EC PRIVATE KEY----- From 2300bb9d008dc241f70b04d9cc62dc46d08ab4f7 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 15:16:44 +0100 Subject: [PATCH 15/79] Updated Ragger tests to use the new private CAL key --- .github/workflows/ci-workflow.yml | 2 -- tests/ragger/cal/cal.py | 18 ++++++++++++++++++ tests/ragger/eip712/InputData.py | 12 +++--------- 3 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 tests/ragger/cal/cal.py diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index ff7c218..b846efa 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -270,8 +270,6 @@ jobs: sudo apt install -y qemu-user-static - name: Run tests - env: - CAL_SIGNATURE_TEST_KEY: ${{ secrets.CAL_SIGNATURE_TEST_KEY }} run: | cd tests/ragger . ./venv/bin/activate diff --git a/tests/ragger/cal/cal.py b/tests/ragger/cal/cal.py new file mode 100644 index 0000000..e75fcab --- /dev/null +++ b/tests/ragger/cal/cal.py @@ -0,0 +1,18 @@ +import os +import hashlib +from ecdsa.util import sigencode_der +from ecdsa import SigningKey + +_key: SigningKey = None + +def _init_key(): + global _key + with open(os.path.dirname(__file__) + "/key.pem") as pem_file: + _key = SigningKey.from_pem(pem_file.read(), hashlib.sha256) + assert _key != None + +def sign(data: bytes) -> bytes: + global _key + if not _key: + _init_key() + return _key.sign_deterministic(data, sigencode=sigencode_der) diff --git a/tests/ragger/eip712/InputData.py b/tests/ragger/eip712/InputData.py index 89e877c..01e0c6e 100644 --- a/tests/ragger/eip712/InputData.py +++ b/tests/ragger/eip712/InputData.py @@ -1,14 +1,11 @@ #!/usr/bin/env python3 -import os import json import sys import re import hashlib -from ecdsa import SigningKey -from ecdsa.util import sigencode_der from ethereum_client.client import EthereumClient, EIP712FieldType -import base64 +from cal import cal # global variables app_client: EthereumClient = None @@ -254,7 +251,7 @@ def send_filtering_message_info(display_name: str, filters_count: int): for char in display_name: to_sign.append(ord(char)) - sig = sig_ctx["key"].sign_deterministic(to_sign, sigencode=sigencode_der) + sig = cal.sign(to_sign) app_client.eip712_filtering_message_info(display_name, filters_count, sig) # ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures @@ -272,7 +269,7 @@ def send_filtering_show_field(display_name): to_sign.append(ord(char)) for char in display_name: to_sign.append(ord(char)) - sig = sig_ctx["key"].sign_deterministic(to_sign, sigencode=sigencode_der) + sig = cal.sign(to_sign) app_client.eip712_filtering_show_field(display_name, sig) def read_filtering_file(domain, message, filtering_file_path): @@ -299,9 +296,6 @@ def init_signature_context(types, domain): global sig_ctx handle_optional_domain_values(domain) - env_key = os.environ["CAL_SIGNATURE_TEST_KEY"] - key = base64.b64decode(env_key).decode() # base 64 string -> decode bytes -> string - sig_ctx["key"] = SigningKey.from_pem(key, hashlib.sha256) caddr = domain["verifyingContract"] if caddr.startswith("0x"): caddr = caddr[2:] From 32161b94325f18c5c56c1048c842b750bf47c9c8 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 16 Nov 2022 15:30:12 +0100 Subject: [PATCH 16/79] Shorter Python tracebacks for Ragger tests --- .github/workflows/ci-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index b846efa..23b1679 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -273,4 +273,4 @@ jobs: run: | cd tests/ragger . ./venv/bin/activate - pytest --path ./elfs --model ${{ matrix.model }} -s -v + pytest --path ./elfs --model ${{ matrix.model }} -s -v --tb=short From 5cf1e1e8e21c97f94365f08a514c2c6f2c994e07 Mon Sep 17 00:00:00 2001 From: tjulien-ledger Date: Tue, 15 Nov 2022 11:59:18 +0100 Subject: [PATCH 17/79] adding eth path to xdc --- makefile_conf/chain/xdcnetwork.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile_conf/chain/xdcnetwork.mk b/makefile_conf/chain/xdcnetwork.mk index 0bea527..4be443a 100644 --- a/makefile_conf/chain/xdcnetwork.mk +++ b/makefile_conf/chain/xdcnetwork.mk @@ -1,3 +1,3 @@ -APP_LOAD_PARAMS += --path "44'/550'" +APP_LOAD_PARAMS += --path "44'/60'" --path "44'/550'" DEFINES += CHAINID_UPCASE=\"XDCNETWORK\" CHAINID_COINNAME=\"XDC\" CHAIN_KIND=CHAIN_KIND_XDCNETWORK CHAIN_ID=50 -APPNAME = "XDC Network" \ No newline at end of file +APPNAME = "XDC Network" From 795140015de540b62adb84372a3cfbca99fbfe54 Mon Sep 17 00:00:00 2001 From: tjulien-ledger Date: Tue, 15 Nov 2022 12:19:00 +0100 Subject: [PATCH 18/79] adding id4good --- icons/nanos_app_id4good.gif | Bin 0 -> 81 bytes icons/nanox_app_id4good.gif | Bin 0 -> 78 bytes makefile_conf/chain/id4good.mk | 3 +++ src/chainConfig.h | 3 ++- src/main.c | 6 ++++++ 5 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 icons/nanos_app_id4good.gif create mode 100644 icons/nanox_app_id4good.gif create mode 100644 makefile_conf/chain/id4good.mk diff --git a/icons/nanos_app_id4good.gif b/icons/nanos_app_id4good.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad64f0f50f151428b950257b19746def01abf092 GIT binary patch literal 81 zcmZ?wbhEHb6krfwn8?8J|Nnmm7^(P^g_VJUi9rV_0+ba1vXxr;SDt>$@6@qL&$HK8 c;`K@2II&63E;c@Q&+~{{dBNwpKO=)R0Mh{)^#A|> literal 0 HcmV?d00001 diff --git a/icons/nanox_app_id4good.gif b/icons/nanox_app_id4good.gif new file mode 100644 index 0000000000000000000000000000000000000000..d36d2097c77db45dc19807a5d9ffd5f00be87159 GIT binary patch literal 78 zcmZ?wbhEHbkind) { @@ -447,6 +450,9 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_APOTHEMNETWORK: currentToken = (tokenDefinition_t *) PIC(&TOKENS_APOTHEMNETWORK[i]); break; + case CHAIN_KIND_ID4GOOD: + currentToken = (tokenDefinition_t *) PIC(&TOKENS_ID4GOOD[i]); + break; } if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) { return currentToken; From 0976df5077296e769ca62eb2d8dbb308d389b372 Mon Sep 17 00:00:00 2001 From: tjulien-ledger Date: Tue, 15 Nov 2022 12:29:52 +0100 Subject: [PATCH 19/79] fix path id4good --- makefile_conf/chain/id4good.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile_conf/chain/id4good.mk b/makefile_conf/chain/id4good.mk index 187250c..57a50cb 100644 --- a/makefile_conf/chain/id4good.mk +++ b/makefile_conf/chain/id4good.mk @@ -1,3 +1,3 @@ -APP_LOAD_PARAMS += "44'/161803'" +APP_LOAD_PARAMS += --path "44'/161803'" DEFINES += CHAINID_UPCASE=\"ID4GOOD\" CHAINID_COINNAME=\"A4G\" CHAIN_KIND=CHAIN_KIND_ID4GOOD CHAIN_ID=846000 APPNAME = "ID4Good" From 96690ac96944cc636d5c23e459e5fb2f57e11cf3 Mon Sep 17 00:00:00 2001 From: BTChip github Date: Mon, 29 Nov 2021 10:12:22 +0100 Subject: [PATCH 20/79] Review Starknet blind signing wording --- src_bagl/ui_flow_stark_unsafe_sign.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_bagl/ui_flow_stark_unsafe_sign.c b/src_bagl/ui_flow_stark_unsafe_sign.c index 6bb8764..7f8fbbb 100644 --- a/src_bagl/ui_flow_stark_unsafe_sign.c +++ b/src_bagl/ui_flow_stark_unsafe_sign.c @@ -18,8 +18,8 @@ UX_STEP_NOCB(ux_stark_unsafe_sign_1_step, pnn, { &C_icon_warning, - "Unsafe", - "Stark Sign", + "StarkNet", + "Blind Sign", }); UX_STEP_NOCB_INIT( From ec5b1769c44c6b3dabd0725ff2cbadf82c93c454 Mon Sep 17 00:00:00 2001 From: BTChip github Date: Mon, 29 Nov 2021 10:14:24 +0100 Subject: [PATCH 21/79] Review Starknet blind signing wording --- src_bagl/ui_flow_stark_unsafe_sign.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_bagl/ui_flow_stark_unsafe_sign.c b/src_bagl/ui_flow_stark_unsafe_sign.c index 7f8fbbb..1c08058 100644 --- a/src_bagl/ui_flow_stark_unsafe_sign.c +++ b/src_bagl/ui_flow_stark_unsafe_sign.c @@ -36,7 +36,7 @@ UX_STEP_NOCB_INIT( bnnn_paging, stark_unsafe_sign_display_hash(), { - .title = "Hash", + .title = "Tx Hash", .text = strings.tmp.tmp }); From 78ddfa3f73f9483129bd084b4dae250e8e090771 Mon Sep 17 00:00:00 2001 From: Lucas PASCAL Date: Thu, 17 Nov 2022 10:38:47 +0100 Subject: [PATCH 22/79] [fix] Replace manual commit & push on protected branch with automatic PR with SDK submodule update --- .github/workflows/sdk-generation.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/sdk-generation.yml b/.github/workflows/sdk-generation.yml index 00cdbb0..9d26eb3 100644 --- a/.github/workflows/sdk-generation.yml +++ b/.github/workflows/sdk-generation.yml @@ -42,11 +42,10 @@ jobs: secret: ${{ secrets.CI_BOT_TOKEN }} repository: LedgerHQ/ethereum-plugin-sdk - - name: Update the SDK submodule in the Ethereum app - uses: ./.github/actions/commit-changes + - name: Create SDK update pull request + uses: peter-evans/create-pull-request@v4 with: - name: 'ldg-github-ci' - files: ethereum-plugin-sdk - message: "[update][SDK] Branch ${{ steps.extract_branch.outputs.branch }} | Commit ${GITHUB_SHA}" - secret: ${{ secrets.CI_BOT_TOKEN }} - repository: LedgerHQ/app-ethereum + branch: sdk/update-submodule + delete-branch: true + title: Update the SDK submodule + reviewers: apailler-ledger From cf1d937ed7d955ea2326050c88164e339c387c5c Mon Sep 17 00:00:00 2001 From: apaillier-ledger Date: Thu, 17 Nov 2022 11:06:01 +0000 Subject: [PATCH 23/79] Plugin SDK submodule update --- ethereum-plugin-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum-plugin-sdk b/ethereum-plugin-sdk index 0de74c6..81eb658 160000 --- a/ethereum-plugin-sdk +++ b/ethereum-plugin-sdk @@ -1 +1 @@ -Subproject commit 0de74c6382f876f89f82ef0eef90408fd94888a3 +Subproject commit 81eb658b138f8201c666351315e79d04400219aa From b135e55b06255d35fad04c42ecaadf9eee9c8a8b Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Thu, 17 Nov 2022 09:10:56 -0600 Subject: [PATCH 24/79] fix: add comment above 1559 txn test (#273) --- examples/signTx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/signTx.py b/examples/signTx.py index 527c0ce..af97925 100755 --- a/examples/signTx.py +++ b/examples/signTx.py @@ -96,6 +96,8 @@ tx = UnsignedTransaction( ) encodedTx = encode(tx, UnsignedTransaction) + +# To test an EIP-1559 transaction, uncomment this line # encodedTx = bytearray.fromhex( # "02ef0306843b9aca008504a817c80082520894b2bb2b958afa2e96dab3f3ce7162b87daea39017872386f26fc1000080c0") From fb1e1b2f7861ab9b3ac763b1a31ef7ba324803ab Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 18 Nov 2022 11:26:06 +0100 Subject: [PATCH 25/79] EIP712 verbose mode "Struct review" visual glitch fix --- src_bagl/ui_flow_signMessage712.c | 32 ++++++++++++++--------- src_features/signMessageEIP712/ui_logic.c | 16 +++++++----- src_features/signMessageEIP712/ui_logic.h | 7 ++++- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src_bagl/ui_flow_signMessage712.c b/src_bagl/ui_flow_signMessage712.c index 9769bb2..d21d047 100644 --- a/src_bagl/ui_flow_signMessage712.c +++ b/src_bagl/ui_flow_signMessage712.c @@ -7,19 +7,25 @@ enum { UI_712_POS_REVIEW, UI_712_POS_END }; static uint8_t ui_pos; static void dummy_cb(void) { - if (!ui_712_next_field()) { - if (ui_pos == UI_712_POS_REVIEW) { - ux_flow_next(); - ui_pos = UI_712_POS_END; - } else // UI_712_POS_END - { - ux_flow_prev(); - ui_pos = UI_712_POS_REVIEW; - } - } else { - // temporarily disable button clicks, they will be re-enabled as soon as new data - // is received and the page is redrawn with ux_flow_init() - G_ux.stack[0].button_push_callback = NULL; + switch (ui_712_next_field()) { + case EIP712_NO_MORE_FIELD: + if (ui_pos == UI_712_POS_REVIEW) { + ux_flow_next(); + ui_pos = UI_712_POS_END; + } else // UI_712_POS_END + { + ux_flow_prev(); + ui_pos = UI_712_POS_REVIEW; + } + break; + case EIP712_FIELD_INCOMING: + // temporarily disable button clicks, they will be re-enabled as soon as new data + // is received and the page is redrawn with ux_flow_init() + G_ux.stack[0].button_push_callback = NULL; + break; + case EIP712_FIELD_LATER: + default: + break; } } diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c index 698e5e1..e6f7b6a 100644 --- a/src_features/signMessageEIP712/ui_logic.c +++ b/src_features/signMessageEIP712/ui_logic.c @@ -115,10 +115,12 @@ void ui_712_redraw_generic_step(void) { /** * Called to fetch the next field if they have not all been processed yet * - * @return whether there will be a next field + * Also handles the special "Review struct" screen of the verbose mode + * + * @return the next field state */ -bool ui_712_next_field(void) { - bool next = false; +e_eip712_nfs ui_712_next_field(void) { + e_eip712_nfs state = EIP712_NO_MORE_FIELD; if (ui_ctx == NULL) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; @@ -126,13 +128,13 @@ bool ui_712_next_field(void) { if (ui_ctx->structs_to_review > 0) { ui_712_review_struct(path_get_nth_field_to_last(ui_ctx->structs_to_review)); ui_ctx->structs_to_review -= 1; - } - if (!ui_ctx->end_reached) { + state = EIP712_FIELD_LATER; + } else if (!ui_ctx->end_reached) { handle_eip712_return_code(true); - next = true; + state = EIP712_FIELD_INCOMING; } } - return next; + return state; } /** diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h index 7ebb4b6..0b651e6 100644 --- a/src_features/signMessageEIP712/ui_logic.h +++ b/src_features/signMessageEIP712/ui_logic.h @@ -10,6 +10,11 @@ #define UI_712_FIELD_NAME_PROVIDED (1 << 1) typedef enum { EIP712_FILTERING_BASIC, EIP712_FILTERING_FULL } e_eip712_filtering_mode; +typedef enum { + EIP712_FIELD_LATER, + EIP712_FIELD_INCOMING, + EIP712_NO_MORE_FIELD +} e_eip712_nfs; // next field state typedef struct { bool shown; @@ -22,7 +27,7 @@ typedef struct { bool ui_712_init(void); void ui_712_deinit(void); -bool ui_712_next_field(void); +e_eip712_nfs ui_712_next_field(void); void ui_712_review_struct(const void *const struct_ptr); bool ui_712_new_field(const void *const field_ptr, const uint8_t *const data, uint8_t length); void ui_712_end_sign(void); From 648fa3b66a63e1d83403cf9f1daa21706d372457 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 18 Nov 2022 11:53:56 +0100 Subject: [PATCH 26/79] Ragger Python regex warnings fix --- tests/ragger/eip712/InputData.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ragger/eip712/InputData.py b/tests/ragger/eip712/InputData.py index 01e0c6e..38ca8c0 100644 --- a/tests/ragger/eip712/InputData.py +++ b/tests/ragger/eip712/InputData.py @@ -21,7 +21,7 @@ sig_ctx = {} # Output = ('uint8', [2, None, 4]) | ('bool', []) def get_array_levels(typename): array_lvls = list() - regex = re.compile("(.*)\[([0-9]*)\]$") + regex = re.compile(r"(.*)\[([0-9]*)\]$") while True: result = regex.search(typename) @@ -42,7 +42,7 @@ def get_array_levels(typename): # Input = "uint64" | "string" # Output = ('uint', 64) | ('string', None) def get_typesize(typename): - regex = re.compile("^(\w+?)(\d*)$") + regex = re.compile(r"^(\w+?)(\d*)$") result = regex.search(typename) typename = result.group(1) typesize = result.group(2) From 529a67b9dd8d330f0001afe2a9d9cdda6aa0c1a5 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 18 Nov 2022 17:57:01 +0100 Subject: [PATCH 27/79] Fix uninitialized verbose EIP712 setting --- src/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.c b/src/main.c index 4a22c0d..5ca0a34 100644 --- a/src/main.c +++ b/src/main.c @@ -955,6 +955,9 @@ void coin_main(chain_config_t *coin_config) { #endif storage.contractDetails = 0x00; storage.displayNonce = 0x00; +#ifdef HAVE_EIP712_FULL_SUPPORT + storage.verbose_eip712 = 0x00; +#endif storage.initialized = 0x01; nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t)); } From 685df6b89c36e0e67d2a52cd8e69110f898d0710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Wed, 23 Nov 2022 09:41:51 +0100 Subject: [PATCH 28/79] add Scroll networks (#372) --- src_common/network.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src_common/network.c b/src_common/network.c index 5bd29f7..e745acd 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -48,7 +48,10 @@ const network_info_t NETWORK_MAPPING[] = { {.chain_id = 7341, .name = "Shyft", .ticker = "SHFT "}, {.chain_id = 19, .name = "Songbird", .ticker = "SGB "}, {.chain_id = 73799, .name = "Volta", .ticker = "VOLTA "}, - {.chain_id = 25, .name = "Cronos", .ticker = "CRO "}}; + {.chain_id = 25, .name = "Cronos", .ticker = "CRO "}, + {.chain_id = 534354, .name = "Scroll (Pre-Alpha)", .ticker = "SCR "}, + {.chain_id = 534353, .name = "Scroll (Goerli)", .ticker = "SCR "}, + {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; From 071c96ea1309fc765b656eff1eab281dff87678d Mon Sep 17 00:00:00 2001 From: Benjyskan Date: Wed, 23 Nov 2022 14:25:49 +0100 Subject: [PATCH 29/79] change dataContext.tokenContext.fieldIndex to uint16_t to avoid plugin's 'context->parameterOffset' overflow on large tx (#228) --- src/shared_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared_context.h b/src/shared_context.h index 3b3b98b..54c7566 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -53,7 +53,7 @@ typedef struct tokenContext_t { uint8_t pluginStatus; uint8_t data[INT256_LENGTH]; - uint8_t fieldIndex; + uint16_t fieldIndex; uint8_t fieldOffset; uint8_t pluginUiMaxItems; From 9e2b67552e6719d61b9788a1b7577011100f36e0 Mon Sep 17 00:00:00 2001 From: Leandre Date: Fri, 25 Nov 2022 16:31:00 +0800 Subject: [PATCH 30/79] Add KCC Chain with ChainID = 321 as ETH clones (#379) * Add KCC Chain with ChainID = 321 as ETH clones * Update network.c * Update network.c * Update network.c * Update network.c * Update network.c --- src_common/network.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src_common/network.c b/src_common/network.c index e745acd..215537c 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -51,7 +51,8 @@ const network_info_t NETWORK_MAPPING[] = { {.chain_id = 25, .name = "Cronos", .ticker = "CRO "}, {.chain_id = 534354, .name = "Scroll (Pre-Alpha)", .ticker = "SCR "}, {.chain_id = 534353, .name = "Scroll (Goerli)", .ticker = "SCR "}, - {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}}; + {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}, + {.chain_id = 321, .name = "KCC", .ticker = "KCS "}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; From 3e750e8419ff2ad1a7eb46d6d7a2a2b88d2d7be4 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 1 Dec 2022 14:22:23 +0100 Subject: [PATCH 31/79] Fix device crash caused by improper memory alignment of the plugin context buffer --- src/shared_context.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shared_context.h b/src/shared_context.h index 54c7566..414586c 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -65,7 +65,9 @@ typedef struct tokenContext_t { uint8_t contractAddress[ADDRESS_LENGTH]; uint8_t methodSelector[SELECTOR_LENGTH]; }; - uint8_t pluginContext[5 * INT256_LENGTH]; + // This needs to be strictly 4 bytes aligned since pointers to it will be casted as + // plugin context struct pointers (structs that contain up to 4 bytes wide elements) + uint8_t pluginContext[5 * INT256_LENGTH] __attribute__((aligned(4))); }; #ifdef HAVE_STARKWARE @@ -77,6 +79,8 @@ typedef struct tokenContext_t { } tokenContext_t; +_Static_assert((offsetof(tokenContext_t, pluginContext) % 4) == 0, "Plugin context not aligned"); + typedef struct publicKeyContext_t { cx_ecfp_public_key_t publicKey; char address[41]; From 0d09d31dba737bf90bee00ae8e47d4e7f2169d6a Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 1 Dec 2022 15:07:37 +0100 Subject: [PATCH 32/79] Small reordering to save 4 bytes on tokenContext_t struct padding --- src/shared_context.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared_context.h b/src/shared_context.h index 414586c..7d3d86b 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -50,7 +50,6 @@ typedef enum starkQuantumType_e { typedef struct tokenContext_t { char pluginName[PLUGIN_ID_LENGTH]; - uint8_t pluginStatus; uint8_t data[INT256_LENGTH]; uint16_t fieldIndex; @@ -70,6 +69,8 @@ typedef struct tokenContext_t { uint8_t pluginContext[5 * INT256_LENGTH] __attribute__((aligned(4))); }; + uint8_t pluginStatus; + #ifdef HAVE_STARKWARE uint8_t quantum[32]; uint8_t mintingBlob[32]; From 782ea07925e69b200f014a707db0c667320a5125 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Fri, 16 Dec 2022 15:02:08 +0100 Subject: [PATCH 33/79] Use proper ragger import --- tests/ragger/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ragger/conftest.py b/tests/ragger/conftest.py index de165db..e527350 100644 --- a/tests/ragger/conftest.py +++ b/tests/ragger/conftest.py @@ -1,6 +1,6 @@ import pytest from pathlib import Path -from ragger import Firmware +from ragger.firmware import Firmware from ragger.backend import SpeculosBackend, LedgerCommBackend, LedgerWalletBackend, BackendInterface from ethereum_client.client import EthereumClient From 6571550b46ddb82a1afcd0e8d5730d235488d847 Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Mon, 9 Jan 2023 17:00:37 +0100 Subject: [PATCH 34/79] adding many networks (#391) --- src_common/network.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src_common/network.c b/src_common/network.c index 215537c..f3ab574 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -52,7 +52,48 @@ const network_info_t NETWORK_MAPPING[] = { {.chain_id = 534354, .name = "Scroll (Pre-Alpha)", .ticker = "SCR "}, {.chain_id = 534353, .name = "Scroll (Goerli)", .ticker = "SCR "}, {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}, - {.chain_id = 321, .name = "KCC", .ticker = "KCS "}}; + {.chain_id = 321, .name = "KCC", .ticker = "KCS "}, + {.chain_id = 30, .name = "Rootstock", .ticker = "RBTC "}, + {.chain_id = 122, .name = "Fuse", .ticker = "FUSE "}, + {.chain_id = 1666600000, .name = "Harmony shard0", .ticker = "ONE "}, + {.chain_id = 128, .name = "Huobi ECO Chain", .ticker = "HT "}, + {.chain_id = 1313161554, .name = "Aurora", .ticker = "ETH "}, + {.chain_id = 53935, .name = "DFK Chain", .ticker = "JEWEL "}, + {.chain_id = 9001, .name = "Evmos", .ticker = "EVMOS "}, + {.chain_id = 4689, .name = "IoTeX Network", .ticker = "IOTX "}, + {.chain_id = 1088, .name = "Metis Andromeda", .ticker = "METIS "}, + {.chain_id = 40, .name = "Telos EVM", .ticker = "TLOS "}, + {.chain_id = 2222, .name = "Kava EVM", .ticker = "KAVA "}, + {.chain_id = 10000, .name = "Smart Bitcoin Cash", .ticker = "BCH "}, + {.chain_id = 8217, .name = "Klaytn Cypress", .ticker = "KLAY "}, + {.chain_id = 245022934, .name = "Neon EVM", .ticker = "NEON "}, + {.chain_id = 57, .name = "Syscoin", .ticker = "SYS "}, + {.chain_id = 32520, .name = "Bitgert", .ticker = "BRISE "}, + {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX "}, + {.chain_id = 288, .name = "Boba Network", .ticker = "ETH "}, + {.chain_id = 7700, .name = "Canto", .ticker = "CANTO "}, + {.chain_id = 108, .name = "ThunderCore", .ticker = "TT "}, + {.chain_id = 88, .name = "TomoChain", .ticker = "TOMO "}, + {.chain_id = 1024, .name = "CLV Parachain", .ticker = "CLV "}, + {.chain_id = 32659, .name = "Fusion", .ticker = "FSN "}, + {.chain_id = 20, .name = "Elastos Smart Chain", .ticker = "ELA "}, + {.chain_id = 39797, .name = "Energi", .ticker = "NRG "}, + {.chain_id = 820, .name = "Callisto", .ticker = "CLO "}, + {.chain_id = 60, .name = "GoChain", .ticker = "GO "}, + {.chain_id = 2152, .name = "Findora", .ticker = "FRA "}, + {.chain_id = 8, .name = "Ubiq", .ticker = "UBQ "}, + {.chain_id = 269, .name = "High Performance Blockchain", .ticker = "HPB "}, + {.chain_id = 1234, .name = "Step Network", .ticker = "FITFI "}, + {.chain_id = 333999, .name = "Polis Network", .ticker = "POLIS "}, + {.chain_id = 2000, .name = "DogeChain", .ticker = "DOGE "}, + {.chain_id = 416, .name = "SX Network", .ticker = "SX "}, + {.chain_id = 1231, .name = "Ultron", .ticker = "ULX "}, + {.chain_id = 6969, .name = "Tomb Chain", .ticker = "TOMB "}, + {.chain_id = 420420, .name = "KekChain", .ticker = "KEK "}, + {.chain_id = 5551, .name = "Nahmii", .ticker = "ETH "}, + {.chain_id = 55, .name = "Zyx", .ticker = "ZYX "}, + {.chain_id = 877, .name = "Dexit Network", .ticker = "DXT "}, + {.chain_id = 26863, .name = "Oasis Chain", .ticker = "OAC "}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; From 41c5d3e011b143b7862892009588adee49481654 Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Tue, 10 Jan 2023 14:10:08 +0100 Subject: [PATCH 35/79] removing networks to reduce size (#394) --- src_common/network.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/src_common/network.c b/src_common/network.c index f3ab574..a412774 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -54,46 +54,14 @@ const network_info_t NETWORK_MAPPING[] = { {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}, {.chain_id = 321, .name = "KCC", .ticker = "KCS "}, {.chain_id = 30, .name = "Rootstock", .ticker = "RBTC "}, - {.chain_id = 122, .name = "Fuse", .ticker = "FUSE "}, - {.chain_id = 1666600000, .name = "Harmony shard0", .ticker = "ONE "}, - {.chain_id = 128, .name = "Huobi ECO Chain", .ticker = "HT "}, - {.chain_id = 1313161554, .name = "Aurora", .ticker = "ETH "}, - {.chain_id = 53935, .name = "DFK Chain", .ticker = "JEWEL "}, {.chain_id = 9001, .name = "Evmos", .ticker = "EVMOS "}, - {.chain_id = 4689, .name = "IoTeX Network", .ticker = "IOTX "}, {.chain_id = 1088, .name = "Metis Andromeda", .ticker = "METIS "}, - {.chain_id = 40, .name = "Telos EVM", .ticker = "TLOS "}, {.chain_id = 2222, .name = "Kava EVM", .ticker = "KAVA "}, - {.chain_id = 10000, .name = "Smart Bitcoin Cash", .ticker = "BCH "}, {.chain_id = 8217, .name = "Klaytn Cypress", .ticker = "KLAY "}, - {.chain_id = 245022934, .name = "Neon EVM", .ticker = "NEON "}, {.chain_id = 57, .name = "Syscoin", .ticker = "SYS "}, - {.chain_id = 32520, .name = "Bitgert", .ticker = "BRISE "}, {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX "}, {.chain_id = 288, .name = "Boba Network", .ticker = "ETH "}, - {.chain_id = 7700, .name = "Canto", .ticker = "CANTO "}, - {.chain_id = 108, .name = "ThunderCore", .ticker = "TT "}, - {.chain_id = 88, .name = "TomoChain", .ticker = "TOMO "}, - {.chain_id = 1024, .name = "CLV Parachain", .ticker = "CLV "}, - {.chain_id = 32659, .name = "Fusion", .ticker = "FSN "}, - {.chain_id = 20, .name = "Elastos Smart Chain", .ticker = "ELA "}, - {.chain_id = 39797, .name = "Energi", .ticker = "NRG "}, - {.chain_id = 820, .name = "Callisto", .ticker = "CLO "}, - {.chain_id = 60, .name = "GoChain", .ticker = "GO "}, - {.chain_id = 2152, .name = "Findora", .ticker = "FRA "}, - {.chain_id = 8, .name = "Ubiq", .ticker = "UBQ "}, - {.chain_id = 269, .name = "High Performance Blockchain", .ticker = "HPB "}, - {.chain_id = 1234, .name = "Step Network", .ticker = "FITFI "}, - {.chain_id = 333999, .name = "Polis Network", .ticker = "POLIS "}, - {.chain_id = 2000, .name = "DogeChain", .ticker = "DOGE "}, - {.chain_id = 416, .name = "SX Network", .ticker = "SX "}, - {.chain_id = 1231, .name = "Ultron", .ticker = "ULX "}, - {.chain_id = 6969, .name = "Tomb Chain", .ticker = "TOMB "}, - {.chain_id = 420420, .name = "KekChain", .ticker = "KEK "}, - {.chain_id = 5551, .name = "Nahmii", .ticker = "ETH "}, - {.chain_id = 55, .name = "Zyx", .ticker = "ZYX "}, - {.chain_id = 877, .name = "Dexit Network", .ticker = "DXT "}, - {.chain_id = 26863, .name = "Oasis Chain", .ticker = "OAC "}}; + {.chain_id = 39797, .name = "Energi", .ticker = "NRG "}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; From 74f880dce99a117df0d4f528d8fcf91e7f82f0b1 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 10 Jan 2023 14:12:39 +0100 Subject: [PATCH 36/79] Removes useless space at the end of tickers --- src/eth_plugin_handler.c | 6 +- src/handle_get_printable_amount.c | 3 +- src/main.c | 2 +- src/tokens.h | 2 +- src/utils.c | 6 +- src_common/network.c | 108 +++++++++--------- src_common/network.h | 2 - .../cmd_provideTokenInfo.c | 6 +- src_features/signTx/logic_signTx.c | 1 + src_plugins/starkware/starkware_plugin.c | 5 +- 10 files changed, 68 insertions(+), 73 deletions(-) diff --git a/src/eth_plugin_handler.c b/src/eth_plugin_handler.c index 22ffbe8..3aa6883 100644 --- a/src/eth_plugin_handler.c +++ b/src/eth_plugin_handler.c @@ -63,12 +63,8 @@ void eth_plugin_prepare_query_contract_UI(ethQueryContractUI_t *queryContractUI, queryContractUI->item2 = &tmpCtx.transactionContext.extraInfo[0]; } - strlcpy(queryContractUI->network_ticker, get_network_ticker(), MAX_TICKER_LEN); - queryContractUI->screenIndex = screenIndex; - strlcpy(queryContractUI->network_ticker, - get_network_ticker(), - sizeof(queryContractUI->network_ticker)); + strlcpy(queryContractUI->network_ticker, get_network_ticker(), MAX_TICKER_LEN); queryContractUI->title = title; queryContractUI->titleLength = titleLength; queryContractUI->msg = msg; diff --git a/src/handle_get_printable_amount.c b/src/handle_get_printable_amount.c index 13acc28..715c85d 100644 --- a/src/handle_get_printable_amount.c +++ b/src/handle_get_printable_amount.c @@ -20,8 +20,7 @@ int handle_get_printable_amount(get_printable_amount_parameters_t* params, chain if (params->is_fee) { uint8_t ticker_len = strnlen(config->coinName, sizeof(config->coinName)); memcpy(ticker, config->coinName, ticker_len); - ticker[ticker_len] = ' '; - ticker[ticker_len + 1] = '\0'; + ticker[ticker_len] = '\0'; decimals = WEI_TO_ETHER; } else { // If the amount is *not* a fee, decimals and ticker are built from the given config diff --git a/src/main.c b/src/main.c index 5ca0a34..261ff18 100644 --- a/src/main.c +++ b/src/main.c @@ -918,7 +918,7 @@ void app_exit() { void init_coin_config(chain_config_t *coin_config) { memset(coin_config, 0, sizeof(chain_config_t)); - strcpy(coin_config->coinName, CHAINID_COINNAME " "); + strcpy(coin_config->coinName, CHAINID_COINNAME); coin_config->chainId = CHAIN_ID; coin_config->kind = CHAIN_KIND; } diff --git a/src/tokens.h b/src/tokens.h index 0a10125..e4e096c 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -21,7 +21,7 @@ #include #include "ethUstream.h" -#define MAX_TICKER_LEN 12 // 10 characters + ' ' + '\0' +#define MAX_TICKER_LEN 11 // 10 characters + '\0' #define MAX_ITEMS 2 typedef struct tokenDefinition_t { diff --git a/src/utils.c b/src/utils.c index be03f10..2c553b4 100644 --- a/src/utils.c +++ b/src/utils.c @@ -132,6 +132,9 @@ void amountToString(const uint8_t *amount, uint8_t ticker_len = strnlen(ticker, MAX_TICKER_LEN); memcpy(out_buffer, ticker, MIN(out_buffer_size, ticker_len)); + if (ticker_len > 0) { + out_buffer[ticker_len++] = ' '; + } if (adjustDecimals(tmp_buffer, amount_len, @@ -155,8 +158,7 @@ bool parse_swap_config(const uint8_t *config, uint8_t config_len, char *ticker, } memcpy(ticker, config + offset, ticker_len); offset += ticker_len; - ticker[ticker_len] = ' '; - ticker[ticker_len + 1] = '\0'; + ticker[ticker_len] = '\0'; if (config_len - offset < 1) { return false; diff --git a/src_common/network.c b/src_common/network.c index a412774..9d55ec2 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -8,60 +8,60 @@ #include "utils.h" // Mappping of chain ids to networks. -const network_info_t NETWORK_MAPPING[] = { - {.chain_id = 1, .name = "Ethereum", .ticker = "ETH "}, - {.chain_id = 3, .name = "Ropsten", .ticker = "ETH "}, - {.chain_id = 4, .name = "Rinkeby", .ticker = "ETH "}, - {.chain_id = 5, .name = "Goerli", .ticker = "ETH "}, - {.chain_id = 10, .name = "Optimism", .ticker = "ETH "}, - {.chain_id = 42, .name = "Kovan", .ticker = "ETH "}, - {.chain_id = 56, .name = "BSC", .ticker = "BNB "}, - {.chain_id = 100, .name = "xDai", .ticker = "xDAI "}, - {.chain_id = 137, .name = "Polygon", .ticker = "MATIC "}, - {.chain_id = 250, .name = "Fantom", .ticker = "FTM "}, - {.chain_id = 42161, .name = "Arbitrum", .ticker = "AETH "}, - {.chain_id = 42220, .name = "Celo", .ticker = "CELO "}, - {.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX "}, - {.chain_id = 44787, .name = "Celo Alfajores", .ticker = "aCELO "}, - {.chain_id = 62320, .name = "Celo Baklava", .ticker = "bCELO "}, - {.chain_id = 11297108109, .name = "Palm Network", .ticker = "PALM "}, - {.chain_id = 1818, .name = "Cube", .ticker = "CUBE "}, - {.chain_id = 336, .name = "Shiden", .ticker = "SDN "}, - {.chain_id = 592, .name = "Astar", .ticker = "ASTR "}, - {.chain_id = 50, .name = "XDC", .ticker = "XDC "}, - {.chain_id = 82, .name = "Meter", .ticker = "MTR "}, - {.chain_id = 62621, .name = "Multivac", .ticker = "MTV "}, - {.chain_id = 20531812, .name = "Tecra", .ticker = "TCR "}, - {.chain_id = 20531811, .name = "TecraTestnet", .ticker = "TCR "}, - {.chain_id = 51, .name = "Apothemnetwork", .ticker = "XDC "}, - {.chain_id = 199, .name = "BTTC", .ticker = "BTT "}, - {.chain_id = 1030, .name = "Conflux", .ticker = "CFX "}, - {.chain_id = 61, .name = "Ethereum Classic", .ticker = "ETC "}, - {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWC "}, - {.chain_id = 14, .name = "Flare", .ticker = "FLR "}, - {.chain_id = 16, .name = "Flare Coston", .ticker = "FLR "}, - {.chain_id = 24, .name = "KardiaChain", .ticker = "KAI "}, - {.chain_id = 1284, .name = "Moonbeam", .ticker = "GLMR "}, - {.chain_id = 1285, .name = "Moonriver", .ticker = "MOVR "}, - {.chain_id = 66, .name = "OKXChain", .ticker = "OKT "}, - {.chain_id = 99, .name = "POA", .ticker = "POA "}, - {.chain_id = 7341, .name = "Shyft", .ticker = "SHFT "}, - {.chain_id = 19, .name = "Songbird", .ticker = "SGB "}, - {.chain_id = 73799, .name = "Volta", .ticker = "VOLTA "}, - {.chain_id = 25, .name = "Cronos", .ticker = "CRO "}, - {.chain_id = 534354, .name = "Scroll (Pre-Alpha)", .ticker = "SCR "}, - {.chain_id = 534353, .name = "Scroll (Goerli)", .ticker = "SCR "}, - {.chain_id = 534352, .name = "Scroll", .ticker = "SCR "}, - {.chain_id = 321, .name = "KCC", .ticker = "KCS "}, - {.chain_id = 30, .name = "Rootstock", .ticker = "RBTC "}, - {.chain_id = 9001, .name = "Evmos", .ticker = "EVMOS "}, - {.chain_id = 1088, .name = "Metis Andromeda", .ticker = "METIS "}, - {.chain_id = 2222, .name = "Kava EVM", .ticker = "KAVA "}, - {.chain_id = 8217, .name = "Klaytn Cypress", .ticker = "KLAY "}, - {.chain_id = 57, .name = "Syscoin", .ticker = "SYS "}, - {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX "}, - {.chain_id = 288, .name = "Boba Network", .ticker = "ETH "}, - {.chain_id = 39797, .name = "Energi", .ticker = "NRG "}}; +static const network_info_t NETWORK_MAPPING[] = { + {.chain_id = 1, .name = "Ethereum", .ticker = "ETH"}, + {.chain_id = 3, .name = "Ropsten", .ticker = "ETH"}, + {.chain_id = 4, .name = "Rinkeby", .ticker = "ETH"}, + {.chain_id = 5, .name = "Goerli", .ticker = "ETH"}, + {.chain_id = 10, .name = "Optimism", .ticker = "ETH"}, + {.chain_id = 42, .name = "Kovan", .ticker = "ETH"}, + {.chain_id = 56, .name = "BSC", .ticker = "BNB"}, + {.chain_id = 100, .name = "xDai", .ticker = "xDAI"}, + {.chain_id = 137, .name = "Polygon", .ticker = "MATIC"}, + {.chain_id = 250, .name = "Fantom", .ticker = "FTM"}, + {.chain_id = 42161, .name = "Arbitrum", .ticker = "AETH"}, + {.chain_id = 42220, .name = "Celo", .ticker = "CELO"}, + {.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX"}, + {.chain_id = 44787, .name = "Celo Alfajores", .ticker = "aCELO"}, + {.chain_id = 62320, .name = "Celo Baklava", .ticker = "bCELO"}, + {.chain_id = 11297108109, .name = "Palm Network", .ticker = "PALM"}, + {.chain_id = 1818, .name = "Cube", .ticker = "CUBE"}, + {.chain_id = 336, .name = "Shiden", .ticker = "SDN"}, + {.chain_id = 592, .name = "Astar", .ticker = "ASTR"}, + {.chain_id = 50, .name = "XDC", .ticker = "XDC"}, + {.chain_id = 82, .name = "Meter", .ticker = "MTR"}, + {.chain_id = 62621, .name = "Multivac", .ticker = "MTV"}, + {.chain_id = 20531812, .name = "Tecra", .ticker = "TCR"}, + {.chain_id = 20531811, .name = "TecraTestnet", .ticker = "TCR"}, + {.chain_id = 51, .name = "Apothemnetwork", .ticker = "XDC"}, + {.chain_id = 199, .name = "BTTC", .ticker = "BTT"}, + {.chain_id = 1030, .name = "Conflux", .ticker = "CFX"}, + {.chain_id = 61, .name = "Ethereum Classic", .ticker = "ETC"}, + {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWC"}, + {.chain_id = 14, .name = "Flare", .ticker = "FLR"}, + {.chain_id = 16, .name = "Flare Coston", .ticker = "FLR"}, + {.chain_id = 24, .name = "KardiaChain", .ticker = "KAI"}, + {.chain_id = 1284, .name = "Moonbeam", .ticker = "GLMR"}, + {.chain_id = 1285, .name = "Moonriver", .ticker = "MOVR"}, + {.chain_id = 66, .name = "OKXChain", .ticker = "OKT"}, + {.chain_id = 99, .name = "POA", .ticker = "POA"}, + {.chain_id = 7341, .name = "Shyft", .ticker = "SHFT"}, + {.chain_id = 19, .name = "Songbird", .ticker = "SGB"}, + {.chain_id = 73799, .name = "Volta", .ticker = "VOLTA"}, + {.chain_id = 25, .name = "Cronos", .ticker = "CRO"}, + {.chain_id = 534354, .name = "Scroll (Pre-Alpha)", .ticker = "SCR"}, + {.chain_id = 534353, .name = "Scroll (Goerli)", .ticker = "SCR"}, + {.chain_id = 534352, .name = "Scroll", .ticker = "SCR"}, + {.chain_id = 321, .name = "KCC", .ticker = "KCS"}, + {.chain_id = 30, .name = "Rootstock", .ticker = "RBTC"}, + {.chain_id = 9001, .name = "Evmos", .ticker = "EVMOS"}, + {.chain_id = 1088, .name = "Metis Andromeda", .ticker = "METIS"}, + {.chain_id = 2222, .name = "Kava EVM", .ticker = "KAVA"}, + {.chain_id = 8217, .name = "Klaytn Cypress", .ticker = "KLAY"}, + {.chain_id = 57, .name = "Syscoin", .ticker = "SYS"}, + {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"}, + {.chain_id = 288, .name = "Boba Network", .ticker = "ETH"}, + {.chain_id = 39797, .name = "Energi", .ticker = "NRG"}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; diff --git a/src_common/network.h b/src_common/network.h index ade3152..b9ce7f3 100644 --- a/src_common/network.h +++ b/src_common/network.h @@ -5,8 +5,6 @@ #include "tokens.h" #include "shared_context.h" -#define MAX_NETWORK_TICKER_LEN 8 - typedef struct network_info_s { const char *name; const char *ticker; diff --git a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c index 1340966..496c54a 100644 --- a/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c +++ b/src_features/provideErc20TokenInformation/cmd_provideTokenInfo.c @@ -42,8 +42,7 @@ void handleProvideErc20TokenInformation(uint8_t p1, } cx_hash((cx_hash_t *) &sha256, 0, workBuffer + offset, tickerLength, NULL, 0); memmove(token->ticker, workBuffer + offset, tickerLength); - token->ticker[tickerLength] = ' '; - token->ticker[tickerLength + 1] = '\0'; + token->ticker[tickerLength] = '\0'; offset += tickerLength; dataLength -= tickerLength; @@ -136,8 +135,7 @@ void handleProvideErc20TokenInformation(uint8_t p1, } cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32); memmove(token->ticker, workBuffer + offset, tickerLength); - token->ticker[tickerLength] = ' '; - token->ticker[tickerLength + 1] = '\0'; + token->ticker[tickerLength] = '\0'; offset += tickerLength; dataLength -= tickerLength; memmove(token->address, workBuffer + offset, 20); diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 1c41646..c22214c 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -240,6 +240,7 @@ static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displa displayBuffer[tickerOffset] = feeTicker[tickerOffset]; tickerOffset++; } + if ((uint32_t) tickerOffset < displayBufferSize) displayBuffer[tickerOffset++] = ' '; while (G_io_apdu_buffer[i]) { if ((uint32_t) (tickerOffset) + i >= displayBufferSize) { break; diff --git a/src_plugins/starkware/starkware_plugin.c b/src_plugins/starkware/starkware_plugin.c index 3937ada..634ea4e 100644 --- a/src_plugins/starkware/starkware_plugin.c +++ b/src_plugins/starkware/starkware_plugin.c @@ -326,10 +326,11 @@ void starkware_print_amount(uint8_t *amountData, } tostring256(&amount, 10, (char *) (G_io_apdu_buffer + 100), 100); strlcpy(destination, ticker, destinationLength); + strlcat(destination, " ", destinationLength); adjustDecimals((char *) (G_io_apdu_buffer + 100), strlen((char *) (G_io_apdu_buffer + 100)), - destination + strlen(ticker), - destinationLength - strlen(ticker), + destination + strlen(ticker) + 1, + destinationLength - strlen(ticker) - 1, decimals); } From 098f328b99f84b3ff67415cccc7cfa704d68858c Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 6 Jan 2023 11:29:49 +0100 Subject: [PATCH 37/79] Plugin interface version bump --- src/eth_plugin_interface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/eth_plugin_interface.h b/src/eth_plugin_interface.h index 48c6e67..5bf5499 100644 --- a/src/eth_plugin_interface.h +++ b/src/eth_plugin_interface.h @@ -13,7 +13,8 @@ typedef enum { ETH_PLUGIN_INTERFACE_VERSION_2 = 2, ETH_PLUGIN_INTERFACE_VERSION_3 = 3, ETH_PLUGIN_INTERFACE_VERSION_4 = 4, - ETH_PLUGIN_INTERFACE_VERSION_LATEST = 5, + ETH_PLUGIN_INTERFACE_VERSION_5 = 5, + ETH_PLUGIN_INTERFACE_VERSION_LATEST = 6 } eth_plugin_interface_version_t; typedef enum { From c93b7dfabce4e4fbbe0e42678b889d68cab77686 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 6 Jan 2023 10:35:20 +0100 Subject: [PATCH 38/79] Fix Zemu tests Before the centered string was "Unlimited DAI " and now is "Unlimited DAI", so the centering changed by a few pixels. --- .../nanos_approve_dai_tokens/00002.png | Bin 346 -> 345 bytes .../nanox_approve_dai_tokens/00002.png | Bin 416 -> 416 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/zemu/snapshots/nanos_approve_dai_tokens/00002.png b/tests/zemu/snapshots/nanos_approve_dai_tokens/00002.png index d514de0dd5eca7cc46a85bcf2cb57ff1e802c61b..8afcc011563071f2d0ec1127c9e7a6f10c98c802 100644 GIT binary patch delta 318 zcmV-E0m1&-0@(tPB!3`DL_t(|ob8#x5`!QNL}RD^{|9@}gHwx1#Db7y%D(A=YNX5t zlVM8)0002^vo78%7@1vtvmAs;_S<^_*Q6Rv^Y`mC^MLe<9J6`ooa`fhbmSYLj^*I_ zMOR+l3m~Fox28LN48oM4!E`?elK@%S#~?rg(#}brDskMAT)N9q#r@K=f=Gb_v+ zQ%x~Hh)Hjf-Bm42cIMi{q^X&4Orzp)5?0;gU&5H0?942~*xiuCa6?<6R`ZHU46WG! zUQk0?89Ror%Qt@|pcRINt6Kut``gcSJesiV)weZ7{kO8hngsv=0001mZ0{k)-yXzj Q&j0`b07*qoM6N<$g5{l>0{{R3 delta 319 zcmV-F0l@y*0@?zQB!3}EL_t(|ob8#>4udcVMRA$`|G_@!gPE&*DRf$n4QK%R!iAzr7u}CXLZFe}7IhH%RZuF`I|Z$v*5yNA3W1EC=^* zy7KaNfQXXSny&OQ2vdRvi~B*C1jx!h1_2U~c24?Kp<-`T+kZ0EvFpC_8r%y(GqVZlmC7>6!h3lCFu>Jd-;&?P+*{h2+ME$F>L6-#p00000^=vDT#@|3b Rng9R*002ovPDHLkV1h8Sn7RM} diff --git a/tests/zemu/snapshots/nanox_approve_dai_tokens/00002.png b/tests/zemu/snapshots/nanox_approve_dai_tokens/00002.png index f42c8d1588974bd65168d8123f4caf4828147bcb..1bf7f2e0b70cc533b0d9d23ac6b6f02e1dca3070 100644 GIT binary patch delta 367 zcmV-#0g(Qn1E2$tI)A=P7f8s$giL@*`rj&T$xyqP#0>!e008(~A|fK*SK;8}eE}ha zkV8K$2kYef>wN*6L?p(T!jw1Cb{kyvcb6=+bP9`xZM_+)wVRkD*e-rz- zq`Pl=Skd^@4bEy;?)XEsJBMD7j!xr|)ebA7nR3t=R(#s?JM^1gt*1oSeqaFq!-(n>s{n7`xN#d#67YxQmou~%sSJL?sYe8$$%mR+gd zWHZP_f0|0DiT-5dz!O!-(@v1d!BB)30000000000000000000O<_C&~7|`Vja$5iZ N002ovPDHLkV1l03u66(b delta 367 zcmV-#0g(Qn1E2$tI)B`y3nXM2LMFgY`rj&T$xyqP#0>!e008(~DW#N>^;H=7SYJR0 zA(YTB%YmPKf2}WIQ%Whun8Q>y@^%@}d`Ir3j-w7Ghgq?o0qU11U*_1!4K=KMx_b(_ zd)baL+D1QkNI-Tf7Inm()RPOml%VHE@FwFKAWL&y+_%(o#eck#T;`$#$)bE}m*y&3 zFBqNO|90j9006vDr@PP@eDIF&!i{6|$yw@;f8MR?wFKNe%c+t522}H%NtU)Ed4d$76}B%{-LUag0zXyzPrhN(|Seutr4v?7KW(pM;HlQVBB zFWu1lM)l(sPiU9-Bw&=qg-a*kNGoxdn!odU#bpt$*XrFGQeR>H$Jvl*sFU^%=y|bv zjm;nv{bd@VCi;t!14~pPOFKa(2U8JV0000000000000000001BnjcCW7|=eK+h7 From dbeba1e226725152dafca9741b43d92e013d5829 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 11:26:24 +0100 Subject: [PATCH 39/79] [create-pull-request] automated change (#395) Co-authored-by: apaillier-ledger --- ethereum-plugin-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum-plugin-sdk b/ethereum-plugin-sdk index 81eb658..a4b971f 160000 --- a/ethereum-plugin-sdk +++ b/ethereum-plugin-sdk @@ -1 +1 @@ -Subproject commit 81eb658b138f8201c666351315e79d04400219aa +Subproject commit a4b971f67980694d8c3862e793859209bc525545 From f5b32109bedbd52167cd424a3a0d99fb34294729 Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Thu, 2 Feb 2023 15:53:45 +0100 Subject: [PATCH 40/79] correcting ticker (#396) --- src_common/network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_common/network.c b/src_common/network.c index 9d55ec2..1102a0f 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -37,7 +37,7 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 199, .name = "BTTC", .ticker = "BTT"}, {.chain_id = 1030, .name = "Conflux", .ticker = "CFX"}, {.chain_id = 61, .name = "Ethereum Classic", .ticker = "ETC"}, - {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWC"}, + {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWT"}, {.chain_id = 14, .name = "Flare", .ticker = "FLR"}, {.chain_id = 16, .name = "Flare Coston", .ticker = "FLR"}, {.chain_id = 24, .name = "KardiaChain", .ticker = "KAI"}, From 160fed73483413b28b27391fd47c66cc1de5ef8a Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Fri, 3 Feb 2023 15:54:07 +0100 Subject: [PATCH 41/79] renaming EWC to EWT (#397) * correcting ticker * modifying conf file * updating main.c * updating chainConfig.h * Removed last bits of EWC --------- Co-authored-by: Alexandre Paillier --- makefile_conf/chain/energywebchain.mk | 3 +++ makefile_conf/chain/ewc.mk | 3 --- src/chainConfig.h | 2 +- src/main.c | 8 ++++---- src/tokens.c | 2 +- src/tokens.h | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 makefile_conf/chain/energywebchain.mk delete mode 100644 makefile_conf/chain/ewc.mk diff --git a/makefile_conf/chain/energywebchain.mk b/makefile_conf/chain/energywebchain.mk new file mode 100644 index 0000000..1024857 --- /dev/null +++ b/makefile_conf/chain/energywebchain.mk @@ -0,0 +1,3 @@ +APP_LOAD_PARAMS += --path "44'/246'" --path "44'/60'" +DEFINES += CHAINID_UPCASE=\"ENERGYWEBCHAIN\" CHAINID_COINNAME=\"EWT\" CHAIN_KIND=CHAIN_KIND_ENERGYWEBCHAIN CHAIN_ID=246 +APPNAME = "EnergyWebChain" diff --git a/makefile_conf/chain/ewc.mk b/makefile_conf/chain/ewc.mk deleted file mode 100644 index 816a5fb..0000000 --- a/makefile_conf/chain/ewc.mk +++ /dev/null @@ -1,3 +0,0 @@ -APP_LOAD_PARAMS += --path "44'/246'" --path "44'/60'" -DEFINES += CHAINID_UPCASE=\"EWC\" CHAINID_COINNAME=\"EWC\" CHAIN_KIND=CHAIN_KIND_EWC CHAIN_ID=246 -APPNAME = "EnergyWebChain" \ No newline at end of file diff --git a/src/chainConfig.h b/src/chainConfig.h index ba846c8..fd09ed2 100644 --- a/src/chainConfig.h +++ b/src/chainConfig.h @@ -49,7 +49,7 @@ typedef enum chain_kind_e { CHAIN_KIND_TOBALABA, CHAIN_KIND_DEXON, CHAIN_KIND_VOLTA, - CHAIN_KIND_EWC, + CHAIN_KIND_ENERGYWEBCHAIN, CHAIN_KIND_ARTIS_SIGMA1, CHAIN_KIND_ARTIS_TAU1, CHAIN_KIND_WEBCHAIN, diff --git a/src/main.c b/src/main.c index 261ff18..be755e5 100644 --- a/src/main.c +++ b/src/main.c @@ -228,8 +228,8 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_VOLTA: numTokens = NUM_TOKENS_VOLTA; break; - case CHAIN_KIND_EWC: - numTokens = NUM_TOKENS_EWC; + case CHAIN_KIND_ENERGYWEBCHAIN: + numTokens = NUM_TOKENS_ENERGYWEBCHAIN; break; case CHAIN_KIND_WEBCHAIN: numTokens = NUM_TOKENS_WEBCHAIN; @@ -384,8 +384,8 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_VOLTA: currentToken = (tokenDefinition_t *) PIC(&TOKENS_VOLTA[i]); break; - case CHAIN_KIND_EWC: - currentToken = (tokenDefinition_t *) PIC(&TOKENS_EWC[i]); + case CHAIN_KIND_ENERGYWEBCHAIN: + currentToken = (tokenDefinition_t *) PIC(&TOKENS_ENERGYWEBCHAIN[i]); break; case CHAIN_KIND_WEBCHAIN: currentToken = (tokenDefinition_t *) PIC(&TOKENS_WEBCHAIN[i]); diff --git a/src/tokens.c b/src/tokens.c index 20ae6f8..8916c0e 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -172,7 +172,7 @@ const tokenDefinition_t const TOKENS_DEXON[NUM_TOKENS_DEXON] = {}; const tokenDefinition_t const TOKENS_VOLTA[NUM_TOKENS_VOLTA] = {}; -const tokenDefinition_t const TOKENS_EWC[NUM_TOKENS_EWC] = {}; +const tokenDefinition_t const TOKENS_ENERGYWEBCHAIN[NUM_TOKENS_ENERGYWEBCHAIN] = {}; const tokenDefinition_t const TOKENS_ARTIS_SIGMA1[NUM_TOKENS_ARTIS_SIGMA1] = {}; diff --git a/src/tokens.h b/src/tokens.h index e4e096c..7eecde1 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -100,7 +100,7 @@ static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { #define NUM_TOKENS_TOBALABA 0 #define NUM_TOKENS_DEXON 0 #define NUM_TOKENS_VOLTA 0 -#define NUM_TOKENS_EWC 0 +#define NUM_TOKENS_ENERGYWEBCHAIN 0 #define NUM_TOKENS_ARTIS_SIGMA1 0 #define NUM_TOKENS_ARTIS_TAU1 0 #define NUM_TOKENS_WEBCHAIN 0 @@ -151,7 +151,7 @@ extern tokenDefinition_t const TOKENS_TOMOCHAIN[NUM_TOKENS_TOMOCHAIN]; extern tokenDefinition_t const TOKENS_TOBALABA[NUM_TOKENS_TOBALABA]; extern tokenDefinition_t const TOKENS_DEXON[NUM_TOKENS_DEXON]; extern tokenDefinition_t const TOKENS_VOLTA[NUM_TOKENS_VOLTA]; -extern tokenDefinition_t const TOKENS_EWC[NUM_TOKENS_EWC]; +extern tokenDefinition_t const TOKENS_ENERGYWEBCHAIN[NUM_TOKENS_ENERGYWEBCHAIN]; extern tokenDefinition_t const TOKENS_ARTIS_SIGMA1[NUM_TOKENS_ARTIS_SIGMA1]; extern tokenDefinition_t const TOKENS_ARTIS_TAU1[NUM_TOKENS_ARTIS_TAU1]; extern tokenDefinition_t const TOKENS_WEBCHAIN[NUM_TOKENS_WEBCHAIN]; From 1bf18f8ecfcab8b0aff96588f263999a5781c754 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 3 Feb 2023 14:53:01 +0100 Subject: [PATCH 42/79] 1.10.2 changelog --- CHANGELOG.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7846305..c5ec16a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-XX-XX +## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-02-03 + +### Added + +- (clone) ID4Good +- (network) Cronos +- (network) Scroll +- (network) KCC +- (network) Rootstock +- (network) Evmos +- (network) Metis Andromeda +- (network) Kava EVM +- (network) Klaytn Cypress +- (network) Syscoin +- (network) Velas EVM +- (network) Boba Network +- (network) Energi + +### Changed + +- Starknet blind signing wording + +### Fixed + +- Missing 44'/60' derivation path for XDC Network +- Small visual glitch with EIP-712 verbose mode with the "Review struct" page +- Possible overflow with very large transactions +- EnergyWebChain ticker ## [1.10.1](https://github.com/ledgerhq/app-ethereum/compare/1.10.0...1.10.1) - 2022-11-09 From 7d3bbc703b4595988a24374195df192fdb5b9090 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 3 Feb 2023 16:14:10 +0100 Subject: [PATCH 43/79] Removed version -dev suffix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 81da667..7020d17 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" APPVERSION_M=1 APPVERSION_N=10 APPVERSION_P=2 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev +APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION) ########################### From e70e3180b561ced3de39374c750995cd201d4d30 Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Mon, 6 Feb 2023 14:23:50 +0100 Subject: [PATCH 44/79] ticker correction (#399) * correcting ticker * modifying conf file * updating main.c * updating chainConfig.h * Removed last bits of EWC * correcting arbitrum --------- Co-authored-by: Alexandre Paillier --- src_common/network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_common/network.c b/src_common/network.c index 1102a0f..84e08dd 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -19,7 +19,7 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 100, .name = "xDai", .ticker = "xDAI"}, {.chain_id = 137, .name = "Polygon", .ticker = "MATIC"}, {.chain_id = 250, .name = "Fantom", .ticker = "FTM"}, - {.chain_id = 42161, .name = "Arbitrum", .ticker = "AETH"}, + {.chain_id = 42161, .name = "Arbitrum", .ticker = "ETH"}, {.chain_id = 42220, .name = "Celo", .ticker = "CELO"}, {.chain_id = 43114, .name = "Avalanche", .ticker = "AVAX"}, {.chain_id = 44787, .name = "Celo Alfajores", .ticker = "aCELO"}, From 8a3cf49eced47ca55af7f4cd0c91b3a609089627 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 6 Feb 2023 14:30:17 +0100 Subject: [PATCH 45/79] Updated changelog for latest changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ec16a..7c22116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Small visual glitch with EIP-712 verbose mode with the "Review struct" page - Possible overflow with very large transactions - EnergyWebChain ticker +- Arbitrum ticker ## [1.10.1](https://github.com/ledgerhq/app-ethereum/compare/1.10.0...1.10.1) - 2022-11-09 From 87f23349add57f55f44afd6ff20a99a732a01ad7 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 9 Feb 2023 11:30:42 +0100 Subject: [PATCH 46/79] Fix freeze on slow/unresponsive APDU transport --- src_bagl/ui_flow_signMessage.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src_bagl/ui_flow_signMessage.c b/src_bagl/ui_flow_signMessage.c index 9b97d57..e1eed03 100644 --- a/src_bagl/ui_flow_signMessage.c +++ b/src_bagl/ui_flow_signMessage.c @@ -19,6 +19,9 @@ static void dummy_pre_cb(void) { static void dummy_post_cb(void) { if (ui_pos == UI_191_POS_QUESTION) { continue_displaying_message(); + // temporarily disable button clicks, they will be re-enabled as soon as new data + // is received and the page is redrawn with ux_flow_init() + G_ux.stack[0].button_push_callback = NULL; } else // UI_191_END { ui_191_switch_to_message_end(); @@ -55,6 +58,7 @@ UX_STEP_CB( #else nnn, #endif + G_ux.stack[0].button_push_callback = NULL; // disable button clicks skip_rest_of_message(), { #ifndef TARGET_NANOS From 27392c20de4d405c312fd8a8d1a367f580aeb821 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 9 Feb 2023 11:44:21 +0100 Subject: [PATCH 47/79] Better context checks when processing EIP-191 APDUs --- src/main.c | 10 ++++++---- src_features/signMessage/cmd_signMessage.c | 23 ++++++++++++++-------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main.c b/src/main.c index be755e5..56a7f6b 100644 --- a/src/main.c +++ b/src/main.c @@ -673,10 +673,12 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { case INS_SIGN_PERSONAL_MESSAGE: memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS); *flags |= IO_ASYNCH_REPLY; - handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC]); + if (!handleSignPersonalMessage(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC])) { + reset_app_context(); + } break; case INS_SIGN_EIP_712_MESSAGE: diff --git a/src_features/signMessage/cmd_signMessage.c b/src_features/signMessage/cmd_signMessage.c index 1779142..6280ca0 100644 --- a/src_features/signMessage/cmd_signMessage.c +++ b/src_features/signMessage/cmd_signMessage.c @@ -21,6 +21,9 @@ static const char SIGN_MAGIC[] = * @param[in] sw status word */ static void apdu_reply(uint16_t sw) { + if ((sw != APDU_RESPONSE_OK) && states.ui_started) { + ui_idle(); + } G_io_apdu_buffer[0] = (sw >> 8) & 0xff; G_io_apdu_buffer[1] = sw & 0xff; io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); @@ -90,18 +93,18 @@ static void reset_ui_buffer(void) { */ static const uint8_t *first_apdu_data(const uint8_t *data, uint8_t *length) { if (appState != APP_STATE_IDLE) { - reset_app_context(); + apdu_reply(APDU_RESPONSE_CONDITION_NOT_SATISFIED); } appState = APP_STATE_SIGNING_MESSAGE; data = parseBip32(data, length, &tmpCtx.messageSigningContext.bip32); if (data == NULL) { - apdu_reply(0x6a80); + apdu_reply(APDU_RESPONSE_INVALID_DATA); return NULL; } if (*length < sizeof(uint32_t)) { PRINTF("Invalid data\n"); - apdu_reply(0x6a80); + apdu_reply(APDU_RESPONSE_INVALID_DATA); return NULL; } @@ -140,7 +143,7 @@ static bool feed_hash(const uint8_t *const data, const uint8_t length) { PRINTF("Error: Length mismatch ! (%u > %u)!\n", length, tmpCtx.messageSigningContext.remainingLength); - apdu_reply(0x6a80); + apdu_reply(APDU_RESPONSE_INVALID_DATA); return false; } cx_hash((cx_hash_t *) &global_sha3, 0, data, length, NULL, 0); @@ -194,7 +197,7 @@ static void feed_display(void) { } if ((unprocessed_length() == 0) && (tmpCtx.messageSigningContext.remainingLength > 0)) { - apdu_reply(0x9000); + apdu_reply(APDU_RESPONSE_OK); } } @@ -222,7 +225,11 @@ bool handleSignPersonalMessage(uint8_t p1, processed_size = data - payload; } else if (p1 != P1_MORE) { PRINTF("Error: Unexpected P1 (%u)!\n", p1); - apdu_reply(0x6B00); + apdu_reply(APDU_RESPONSE_INVALID_P1_P2); + return false; + } else if (appState != APP_STATE_SIGNING_MESSAGE) { + PRINTF("Error: App not already in signing state!\n"); + apdu_reply(APDU_RESPONSE_INVALID_DATA); return false; } @@ -241,7 +248,7 @@ bool handleSignPersonalMessage(uint8_t p1, ui_191_switch_to_sign(); #endif } else { - apdu_reply(0x9000); + apdu_reply(APDU_RESPONSE_OK); } } return true; @@ -266,7 +273,7 @@ void question_switcher(void) { void skip_rest_of_message(void) { states.sign_state = STATE_191_HASH_ONLY; if (tmpCtx.messageSigningContext.remainingLength > 0) { - apdu_reply(0x9000); + apdu_reply(APDU_RESPONSE_OK); } else { ui_191_switch_to_sign(); } From cf1d21edf96eb18fd57ac57574188da6753c1f3e Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 9 Feb 2023 11:46:40 +0100 Subject: [PATCH 48/79] Updated the changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c22116..950ee93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-02-03 +## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-02-09 ### Added @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Possible overflow with very large transactions - EnergyWebChain ticker - Arbitrum ticker +- Better error handling on EIP-191 APDUs ## [1.10.1](https://github.com/ledgerhq/app-ethereum/compare/1.10.0...1.10.1) - 2022-11-09 From 32bff3e0d02f38379e39a5fdd30933ed6b8548f9 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 20 Feb 2023 16:37:22 +0100 Subject: [PATCH 49/79] Disable button clicks before getting the new EIP-191 data, not after --- src_bagl/ui_flow_signMessage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_bagl/ui_flow_signMessage.c b/src_bagl/ui_flow_signMessage.c index e1eed03..3c2a75a 100644 --- a/src_bagl/ui_flow_signMessage.c +++ b/src_bagl/ui_flow_signMessage.c @@ -18,10 +18,10 @@ static void dummy_pre_cb(void) { static void dummy_post_cb(void) { if (ui_pos == UI_191_POS_QUESTION) { - continue_displaying_message(); // temporarily disable button clicks, they will be re-enabled as soon as new data // is received and the page is redrawn with ux_flow_init() G_ux.stack[0].button_push_callback = NULL; + continue_displaying_message(); } else // UI_191_END { ui_191_switch_to_message_end(); From 1cf39711b8ec6996deaa450e39f4980a18e87827 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 20 Feb 2023 16:49:02 +0100 Subject: [PATCH 50/79] Fix Speculos tests --- .github/workflows/ci-workflow.yml | 4 ++-- tests/speculos/conftest.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 23b1679..b66a5fa 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -72,10 +72,10 @@ jobs: - run: sudo apt-get update -y && sudo apt-get install -y libusb-1.0.0 libudev-dev - - name: Install node + - name: Install NodeJS uses: actions/setup-node@v3 with: - node-version: "14.4.0" + node-version: "16" - name: Install yarn run: npm install -g yarn diff --git a/tests/speculos/conftest.py b/tests/speculos/conftest.py index b10f7a6..4d68fc6 100644 --- a/tests/speculos/conftest.py +++ b/tests/speculos/conftest.py @@ -9,8 +9,6 @@ from ethereum_client.ethereum_cmd import EthereumCommand SCRIPT_DIR = Path(__file__).absolute().parent API_URL = "http://127.0.0.1:5000" -VERSION = {"nanos": "2.1", "nanox": "2.0.2", "nanosp": "1.0.3"} - def pytest_addoption(parser): # nanos, nanox, nanosp @@ -27,7 +25,7 @@ def client(pytestconfig): file_path = pytestconfig.getoption("path") model = pytestconfig.getoption("model") - args = ['--log-level', 'speculos:DEBUG','--model', model, '--display', pytestconfig.getoption("display"), '--sdk', VERSION[model]] + args = ['--log-level', 'speculos:DEBUG','--model', model, '--display', pytestconfig.getoption("display")] with SpeculosClient(app=str(file_path), args=args) as client: yield client From 45c049fd04688f038279a3cbe27507e1155211d6 Mon Sep 17 00:00:00 2001 From: tjulien-ledger <84443769+tjulien-ledger@users.noreply.github.com> Date: Fri, 10 Mar 2023 18:41:35 +0100 Subject: [PATCH 51/79] Oasys (#413) * correcting ticker * modifying conf file * updating main.c * updating chainConfig.h * Removed last bits of EWC * correcting arbitrum * adding oasys conf file * adding oasys icons * remaining changes for oasys * removing trailing space --------- Co-authored-by: Alexandre Paillier --- icons/nanos_app_oasys.gif | Bin 0 -> 107 bytes icons/nanox_app_oasys.gif | Bin 0 -> 104 bytes makefile_conf/chain/oasys.mk | 3 +++ src/chainConfig.h | 3 ++- src/main.c | 6 ++++++ src/tokens.c | 2 ++ src/tokens.h | 2 ++ src_common/network.c | 3 ++- 8 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 icons/nanos_app_oasys.gif create mode 100644 icons/nanox_app_oasys.gif create mode 100644 makefile_conf/chain/oasys.mk diff --git a/icons/nanos_app_oasys.gif b/icons/nanos_app_oasys.gif new file mode 100644 index 0000000000000000000000000000000000000000..e43f39477a163958026a4fd073bf3981d429fd74 GIT binary patch literal 107 zcmZ?wbhEHb6krfw_`t{j1poj4SNzEWVlgQG=l0A^Oi%SqOwUZt=1Wh^%}um5&@(Xw zK?WU=5|BOyCY7H4m8ah_#B>Op6HPajEIq9`rCjxK;UuXW3w^q`J=pE}tyi9v!5RQ* CA0hPs literal 0 HcmV?d00001 diff --git a/icons/nanox_app_oasys.gif b/icons/nanox_app_oasys.gif new file mode 100644 index 0000000000000000000000000000000000000000..cfb4ea46048024d31bfddca79204121bb0a482a8 GIT binary patch literal 104 zcmZ?wbhEHbB&gM%`%*{=-HPACL z1wjTKkP?tS1}4Rx{*|j4Wabqc?zK33wf$3EW3;K)3Dbq@#!2b7Q!n^Pvocr%00&(k AiU0rr literal 0 HcmV?d00001 diff --git a/makefile_conf/chain/oasys.mk b/makefile_conf/chain/oasys.mk new file mode 100644 index 0000000..0e2dc18 --- /dev/null +++ b/makefile_conf/chain/oasys.mk @@ -0,0 +1,3 @@ +APP_LOAD_PARAMS += --path "44'/685'" --path "44'/60'" +DEFINES += CHAINID_UPCASE=\"OASYS\" CHAINID_COINNAME=\"OAS\" CHAIN_KIND=CHAIN_KIND_OASYS CHAIN_ID=248 +APPNAME = "Oasys" diff --git a/src/chainConfig.h b/src/chainConfig.h index fd09ed2..070de49 100644 --- a/src/chainConfig.h +++ b/src/chainConfig.h @@ -73,7 +73,8 @@ typedef enum chain_kind_e { CHAIN_KIND_MULTIVAC, CHAIN_KIND_TECRA, CHAIN_KIND_APOTHEMNETWORK, - CHAIN_KIND_ID4GOOD + CHAIN_KIND_ID4GOOD, + CHAIN_KIND_OASYS } chain_kind_t; typedef struct chain_config_s { diff --git a/src/main.c b/src/main.c index 56a7f6b..3ba8bd6 100644 --- a/src/main.c +++ b/src/main.c @@ -297,6 +297,9 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_ID4GOOD: numTokens = NUM_TOKENS_ID4GOOD; break; + case CHAIN_KIND_OASYS: + numTokens = NUM_TOKENS_OASYS; + break; } for (i = 0; i < numTokens; i++) { switch (chainConfig->kind) { @@ -453,6 +456,9 @@ extraInfo_t *getKnownToken(uint8_t *contractAddress) { case CHAIN_KIND_ID4GOOD: currentToken = (tokenDefinition_t *) PIC(&TOKENS_ID4GOOD[i]); break; + case CHAIN_KIND_OASYS: + currentToken = (tokenDefinition_t *) PIC(&TOKENS_OASYS[i]); + break; } if (memcmp(currentToken->address, tmpContent.txContent.destination, ADDRESS_LENGTH) == 0) { return currentToken; diff --git a/src/tokens.c b/src/tokens.c index 8916c0e..e17e482 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -222,4 +222,6 @@ const tokenDefinition_t const TOKENS_TECRA[NUM_TOKENS_TECRA] = {}; const tokenDefinition_t const TOKENS_APOTHEMNETWORK[NUM_TOKENS_APOTHEMNETWORK] = {}; +const tokenDefinition_t const TOKENS_OASYS[NUM_TOKENS_OASYS] = {}; + #endif diff --git a/src/tokens.h b/src/tokens.h index 7eecde1..1a261c3 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -125,6 +125,7 @@ static const uint8_t LEDGER_SIGNATURE_PUBLIC_KEY[] = { #define NUM_TOKENS_MULTIVAC 0 #define NUM_TOKENS_TECRA 0 #define NUM_TOKENS_APOTHEMNETWORK 0 +#define NUM_TOKENS_OASYS 0 extern tokenDefinition_t const TOKENS_AKROMA[NUM_TOKENS_AKROMA]; extern tokenDefinition_t const TOKENS_ELLAISM[NUM_TOKENS_ELLAISM]; @@ -175,6 +176,7 @@ extern tokenDefinition_t const TOKENS_METER[NUM_TOKENS_METER]; extern tokenDefinition_t const TOKENS_MULTIVAC[NUM_TOKENS_MULTIVAC]; extern tokenDefinition_t const TOKENS_TECRA[NUM_TOKENS_TECRA]; extern tokenDefinition_t const TOKENS_APOTHEMNETWORK[NUM_TOKENS_APOTHEMNETWORK]; +extern tokenDefinition_t const TOKENS_OASYS[NUM_TOKENS_OASYS]; #endif /* HAVE_TOKENS_LIST */ diff --git a/src_common/network.c b/src_common/network.c index 84e08dd..f0dc4d1 100644 --- a/src_common/network.c +++ b/src_common/network.c @@ -61,7 +61,8 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 57, .name = "Syscoin", .ticker = "SYS"}, {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"}, {.chain_id = 288, .name = "Boba Network", .ticker = "ETH"}, - {.chain_id = 39797, .name = "Energi", .ticker = "NRG"}}; + {.chain_id = 39797, .name = "Energi", .ticker = "NRG"}, + {.chain_id = 248, .name = "Oasys", .ticker = "OAS"}}; uint64_t get_chain_id(void) { uint64_t chain_id = 0; From 48461b004abe099d85677ff10b3ed643cbfca379 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 27 Feb 2023 11:12:39 +0100 Subject: [PATCH 52/79] Add -dev version suffix again --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7020d17..81da667 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" APPVERSION_M=1 APPVERSION_N=10 APPVERSION_P=2 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) +APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION) ########################### From c00fab2f6acddffe543e12074edf2f7d0a3b63c7 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 25 Nov 2022 18:11:27 +0100 Subject: [PATCH 53/79] GET_CHALLENGE & PROVIDE_DOMAIN_NAME APDU documentation --- doc/ethapp.adoc | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/doc/ethapp.adoc b/doc/ethapp.adoc index bc57b3b..6997b9b 100644 --- a/doc/ethapp.adoc +++ b/doc/ethapp.adoc @@ -38,6 +38,9 @@ Application version 1.9.19 - 2022-05-17 - Add EIP712 STRUCT DEFINITION & EIP712 STRUCT IMPLEMENTATION - Update to SIGN ETH EIP712 +### 1.10.2 + - Add domain names support + ## About This application describes the APDU messages interface to communicate with the Ethereum application. @@ -881,6 +884,82 @@ _Output data_ None +### GET CHALLENGE + +#### Description + +Sends a random 32-bit long value. Can prevent replay of signed payloads when the challenge +is included in said payload. + +#### Coding + +_Command_ + +[width="80%"] +|============================================================= +| *CLA* | *INS* | *P1* | *P2* | *LC* +| E0 | 20 | 00 | 00 | 00 +|============================================================= + +_Input data_ + +None + +_Output data_ + +[width="80%"] +|=========================================== +| *Description* | *Length* +| Challenge value (BE) | 4 +|=========================================== + + +### PROVIDE DOMAIN NAME + +#### Description + +This command provides a domain name (like ENS) to be displayed during transactions in place of the address it is associated to. +It shall be run just before a transaction involving the associated address that would be displayed on the device. + +The signature is computed on the TLV payload (minus the signature obviously). + +#### Coding + +_Command_ + +[width="80%"] +|============================================================== +| *CLA* | *INS* | *P1* | *P2* | *LC* +| E0 | 22 | 01 : first chunk + + 00 : following chunk + | 00 | 00 +|============================================================== + +_Input data_ + +##### If P1 == first chunk + +[width="80%"] +|========================================== +| *Description* | *Length (byte)* +| Payload length | 2 +| TLV payload | variable +|========================================== + +##### If P1 == following chunk + +[width="80%"] +|========================================== +| *Description* | *Length (byte)* +| TLV payload | variable +|========================================== + +_Output data_ + +None + + ## Transport protocol ### General transport description From f17104312bce34c03d3a4a8df53a50dbf6b9fd57 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 25 Nov 2022 18:13:07 +0100 Subject: [PATCH 54/79] Challenge implementation --- Makefile | 5 +++ src/apdu_constants.h | 2 + src/main.c | 12 ++++++ src_features/getChallenge/challenge.h | 14 +++++++ src_features/getChallenge/cmd_get_challenge.c | 38 +++++++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 src_features/getChallenge/challenge.h create mode 100644 src_features/getChallenge/cmd_get_challenge.c diff --git a/Makefile b/Makefile index 81da667..fa0c9e0 100644 --- a/Makefile +++ b/Makefile @@ -157,6 +157,11 @@ ifneq ($(CAL_CI_KEY),0) DEFINES += HAVE_CAL_CI_KEY endif +# ENS +ifneq ($(TARGET_NAME),TARGET_NANOS) +DEFINES += HAVE_DOMAIN_NAME +endif + # Enabling debug PRINTF DEBUG:=0 ifneq ($(DEBUG),0) diff --git a/src/apdu_constants.h b/src/apdu_constants.h index cab0688..7911d6b 100644 --- a/src/apdu_constants.h +++ b/src/apdu_constants.h @@ -24,6 +24,8 @@ #define INS_EIP712_STRUCT_DEF 0x1A #define INS_EIP712_STRUCT_IMPL 0x1C #define INS_EIP712_FILTERING 0x1E +#define INS_ENS_GET_CHALLENGE 0x20 +#define INS_ENS_PROVIDE_INFO 0x22 #define P1_CONFIRM 0x01 #define P1_NON_CONFIRM 0x00 #define P2_NO_CHAINCODE 0x00 diff --git a/src/main.c b/src/main.c index 3ba8bd6..ea024ab 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ #include "handle_get_printable_amount.h" #include "handle_check_address.h" #include "commands_712.h" +#include "challenge.h" #ifdef HAVE_STARKWARE #include "stark_crypto.h" @@ -749,6 +750,12 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { break; #endif // HAVE_EIP712_FULL_SUPPORT +#ifdef HAVE_DOMAIN_NAME + case INS_ENS_GET_CHALLENGE: + handle_get_challenge(); + break; +#endif // HAVE_DOMAIN_NAME + #if 0 case 0xFF: // return to dashboard goto return_to_dashboard; @@ -980,6 +987,11 @@ void coin_main(chain_config_t *coin_config) { BLE_power(1, "Nano X"); #endif // HAVE_BLE +#ifdef HAVE_DOMAIN_NAME + // to prevent it from having a fixed value at boot + roll_challenge(); +#endif // HAVE_DOMAIN_NAME + app_main(); } CATCH(EXCEPTION_IO_RESET) { diff --git a/src_features/getChallenge/challenge.h b/src_features/getChallenge/challenge.h new file mode 100644 index 0000000..9fdb01d --- /dev/null +++ b/src_features/getChallenge/challenge.h @@ -0,0 +1,14 @@ +#ifdef HAVE_DOMAIN_NAME + +#ifndef CHALLENGE_H_ +#define CHALLENGE_H_ + +#include + +void roll_challenge(void); +uint32_t get_challenge(void); +void handle_get_challenge(void); + +#endif // CHALLENGE_H_ + +#endif // HAVE_DOMAIN_NAME diff --git a/src_features/getChallenge/cmd_get_challenge.c b/src_features/getChallenge/cmd_get_challenge.c new file mode 100644 index 0000000..93e52d9 --- /dev/null +++ b/src_features/getChallenge/cmd_get_challenge.c @@ -0,0 +1,38 @@ +#ifdef HAVE_DOMAIN_NAME + +#include +#include +#include +#include "apdu_constants.h" +#include "challenge.h" + +static uint32_t challenge; + +/** + * Generate a new challenge from the Random Number Generator + */ +void roll_challenge(void) { + challenge = cx_rng_u32(); +} + +/** + * Get the current challenge + * + * @return challenge + */ +uint32_t get_challenge(void) { + return challenge; +} + +/** + * Send back the current challenge + */ +void handle_get_challenge(void) { + PRINTF("New challenge -> %u\n", get_challenge()); + U4BE_ENCODE(G_io_apdu_buffer, 0, get_challenge()); + U2BE_ENCODE(G_io_apdu_buffer, 4, APDU_RESPONSE_OK); + + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 6); +} + +#endif // HAVE_DOMAIN_NAME From e15899c92e9ed82b2880d7c1d079bf395027f4b5 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 25 Nov 2022 16:40:15 +0100 Subject: [PATCH 55/79] Moved hash_byte & hash_nbytes functions to common Also fixed possible overflow on large payload hashing --- .../signMessageEIP712 => src_common}/hash_bytes.c | 8 ++------ src_common/hash_bytes.h | 10 ++++++++++ src_features/signMessageEIP712/hash_bytes.h | 13 ------------- 3 files changed, 12 insertions(+), 19 deletions(-) rename {src_features/signMessageEIP712 => src_common}/hash_bytes.c (67%) create mode 100644 src_common/hash_bytes.h delete mode 100644 src_features/signMessageEIP712/hash_bytes.h diff --git a/src_features/signMessageEIP712/hash_bytes.c b/src_common/hash_bytes.c similarity index 67% rename from src_features/signMessageEIP712/hash_bytes.c rename to src_common/hash_bytes.c index 6f702a4..e6b6437 100644 --- a/src_features/signMessageEIP712/hash_bytes.c +++ b/src_common/hash_bytes.c @@ -1,5 +1,3 @@ -#ifdef HAVE_EIP712_FULL_SUPPORT - #include "hash_bytes.h" /** @@ -9,7 +7,7 @@ * @param[in] n number of bytes to hash * @param[in] hash_ctx pointer to the hashing context */ -void hash_nbytes(const uint8_t *const bytes_ptr, uint8_t n, cx_hash_t *const hash_ctx) { +void hash_nbytes(const uint8_t *bytes_ptr, size_t n, cx_hash_t *hash_ctx) { cx_hash(hash_ctx, 0, bytes_ptr, n, NULL, 0); } @@ -19,8 +17,6 @@ void hash_nbytes(const uint8_t *const bytes_ptr, uint8_t n, cx_hash_t *const has * @param[in] byte byte to hash * @param[in] hash_ctx pointer to the hashing context */ -void hash_byte(uint8_t byte, cx_hash_t *const hash_ctx) { +void hash_byte(uint8_t byte, cx_hash_t *hash_ctx) { hash_nbytes(&byte, 1, hash_ctx); } - -#endif // HAVE_EIP712_FULL_SUPPORT diff --git a/src_common/hash_bytes.h b/src_common/hash_bytes.h new file mode 100644 index 0000000..2928fab --- /dev/null +++ b/src_common/hash_bytes.h @@ -0,0 +1,10 @@ +#ifndef HASH_BYTES_H_ +#define HASH_BYTES_H_ + +#include +#include "cx.h" + +void hash_nbytes(const uint8_t *const bytes_ptr, size_t n, cx_hash_t *hash_ctx); +void hash_byte(uint8_t byte, cx_hash_t *hash_ctx); + +#endif // HASH_BYTES_H_ diff --git a/src_features/signMessageEIP712/hash_bytes.h b/src_features/signMessageEIP712/hash_bytes.h deleted file mode 100644 index 6c1d329..0000000 --- a/src_features/signMessageEIP712/hash_bytes.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef HASH_BYTES_H_ -#define HASH_BYTES_H_ - -#ifdef HAVE_EIP712_FULL_SUPPORT - -#include "cx.h" - -void hash_nbytes(const uint8_t *const bytes_ptr, uint8_t n, cx_hash_t *hash_ctx); -void hash_byte(uint8_t byte, cx_hash_t *hash_ctx); - -#endif // HAVE_EIP712_FULL_SUPPORT - -#endif // HASH_BYTES_H_ From ceacee00a71fb1b3a71f47d04a689a54bbf5df7a Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 2 Mar 2023 15:06:11 +0100 Subject: [PATCH 56/79] Provide domain name APDU implementation --- .github/workflows/ci-workflow.yml | 6 +- Makefile | 4 + src/main.c | 25 +- src/shared_context.h | 11 +- .../cmd_provide_domain_name.c | 670 ++++++++++++++++++ src_features/provideDomainName/domain_name.h | 18 + 6 files changed, 720 insertions(+), 14 deletions(-) create mode 100644 src_features/provideDomainName/cmd_provide_domain_name.c create mode 100644 src_features/provideDomainName/domain_name.h diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index b66a5fa..7c52cb7 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -177,13 +177,13 @@ jobs: - name: Build test binaries run: | - make -j BOLOS_SDK=$NANOS_SDK CAL_CI_KEY=1 + make -j BOLOS_SDK=$NANOS_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 mv bin/app.elf app-nanos.elf make clean - make -j BOLOS_SDK=$NANOX_SDK CAL_CI_KEY=1 + make -j BOLOS_SDK=$NANOX_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 mv bin/app.elf app-nanox.elf make clean - make -j BOLOS_SDK=$NANOSP_SDK CAL_CI_KEY=1 + make -j BOLOS_SDK=$NANOSP_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 mv bin/app.elf app-nanosp.elf - name: Upload app binaries diff --git a/Makefile b/Makefile index fa0c9e0..95afe9b 100644 --- a/Makefile +++ b/Makefile @@ -160,6 +160,10 @@ endif # ENS ifneq ($(TARGET_NAME),TARGET_NANOS) DEFINES += HAVE_DOMAIN_NAME +DOMAIN_NAME_TEST_KEY:=0 +ifneq ($(DOMAIN_NAME_TEST_KEY),0) +DEFINES += HAVE_DOMAIN_NAME_TEST_KEY +endif endif # Enabling debug PRINTF diff --git a/src/main.c b/src/main.c index ea024ab..a483bf4 100644 --- a/src/main.c +++ b/src/main.c @@ -30,6 +30,7 @@ #include "handle_check_address.h" #include "commands_712.h" #include "challenge.h" +#include "domain_name.h" #ifdef HAVE_STARKWARE #include "stark_crypto.h" @@ -754,6 +755,13 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { case INS_ENS_GET_CHALLENGE: handle_get_challenge(); break; + + case INS_ENS_PROVIDE_INFO: + handle_provide_domain_name(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC]); + break; #endif // HAVE_DOMAIN_NAME #if 0 @@ -961,19 +969,22 @@ void coin_main(chain_config_t *coin_config) { G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); #endif // TARGET_NANOX - if (N_storage.initialized != 0x01) { + if (!N_storage.initialized) { internalStorage_t storage; #ifdef HAVE_ALLOW_DATA - storage.dataAllowed = 0x01; + storage.dataAllowed = true; #else - storage.dataAllowed = 0x00; + storage.dataAllowed = false; #endif - storage.contractDetails = 0x00; - storage.displayNonce = 0x00; + storage.contractDetails = false; + storage.displayNonce = false; #ifdef HAVE_EIP712_FULL_SUPPORT - storage.verbose_eip712 = 0x00; + storage.verbose_eip712 = false; #endif - storage.initialized = 0x01; +#ifdef HAVE_DOMAIN_NAME + storage.verbose_domain_name = false; +#endif + storage.initialized = true; nvm_write((void *) &N_storage, (void *) &storage, sizeof(internalStorage_t)); } diff --git a/src/shared_context.h b/src/shared_context.h index 7d3d86b..0480a59 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -24,13 +24,16 @@ typedef struct bip32_path_t { } bip32_path_t; typedef struct internalStorage_t { - unsigned char dataAllowed; - unsigned char contractDetails; - unsigned char displayNonce; + bool dataAllowed; + bool contractDetails; + bool displayNonce; #ifdef HAVE_EIP712_FULL_SUPPORT bool verbose_eip712; #endif // HAVE_EIP712_FULL_SUPPORT - uint8_t initialized; +#ifdef HAVE_DOMAIN_NAME + bool verbose_domain_name; +#endif // HAVE_DOMAIN_NAME + bool initialized; } internalStorage_t; #ifdef HAVE_STARKWARE diff --git a/src_features/provideDomainName/cmd_provide_domain_name.c b/src_features/provideDomainName/cmd_provide_domain_name.c new file mode 100644 index 0000000..aa7e547 --- /dev/null +++ b/src_features/provideDomainName/cmd_provide_domain_name.c @@ -0,0 +1,670 @@ +#ifdef HAVE_DOMAIN_NAME + +#include +#include +#include +#include "utils.h" // ARRAY_SIZE +#include "apdu_constants.h" +#include "domain_name.h" +#include "challenge.h" +#include "mem.h" +#include "hash_bytes.h" + +static const uint8_t DOMAIN_NAME_PUB_KEY[] = { +#ifdef HAVE_DOMAIN_NAME_TEST_KEY + 0x04, 0xb9, 0x1f, 0xbe, 0xc1, 0x73, 0xe3, 0xba, 0x4a, 0x71, 0x4e, 0x01, 0x4e, 0xbc, + 0x82, 0x7b, 0x6f, 0x89, 0x9a, 0x9f, 0xa7, 0xf4, 0xac, 0x76, 0x9c, 0xde, 0x28, 0x43, + 0x17, 0xa0, 0x0f, 0x4f, 0x65, 0x0f, 0x09, 0xf0, 0x9a, 0xa4, 0xff, 0x5a, 0x31, 0x76, + 0x02, 0x55, 0xfe, 0x5d, 0xfc, 0x81, 0x13, 0x29, 0xb3, 0xb5, 0x0b, 0xe9, 0x91, 0x94, + 0xfc, 0xa1, 0x16, 0x19, 0xe6, 0x5f, 0x2e, 0xdf, 0xea +#else + 0x04, 0x6a, 0x94, 0xe7, 0xa4, 0x2c, 0xd0, 0xc3, 0x3f, 0xdf, 0x44, 0x0c, 0x8e, 0x2a, + 0xb2, 0x54, 0x2c, 0xef, 0xbe, 0x5d, 0xb7, 0xaa, 0x0b, 0x93, 0xa9, 0xfc, 0x81, 0x4b, + 0x9a, 0xcf, 0xa7, 0x5e, 0xb4, 0xe5, 0x3d, 0x6f, 0x00, 0x25, 0x94, 0xbd, 0xb6, 0x05, + 0xd9, 0xb5, 0xbd, 0xa9, 0xfa, 0x4b, 0x4b, 0xf3, 0xa5, 0x49, 0x6f, 0xd3, 0x16, 0x4b, + 0xae, 0xf5, 0xaf, 0xcf, 0x90, 0xe8, 0x40, 0x88, 0x71 +#endif +}; + +#define P1_FIRST_CHUNK 0x01 +#define P1_FOLLOWING_CHUNK 0x00 + +#define ALGO_SECP256K1 1 + +#define SLIP_44_ETHEREUM 60 + +#define DER_LONG_FORM_FLAG 0x80 // 8th bit set +#define DER_FIRST_BYTE_VALUE_MASK 0x7f + +typedef enum { TLV_TAG, TLV_LENGTH, TLV_VALUE } e_tlv_step; + +typedef enum { + STRUCTURE_TYPE = 0x01, + STRUCTURE_VERSION = 0x02, + CHALLENGE = 0x12, + SIGNER_KEY_ID = 0x13, + SIGNER_ALGO = 0x14, + SIGNATURE = 0x15, + DOMAIN_NAME = 0x20, + COIN_TYPE = 0x21, + ADDRESS = 0x22 +} e_tlv_tag; + +typedef enum { KEY_ID_TEST = 0x00, KEY_ID_PROD = 0x03 } e_key_id; + +typedef struct { + uint8_t *buf; + uint16_t size; + uint16_t expected_size; +} s_tlv_payload; + +typedef struct { + e_tlv_tag tag; + uint8_t length; + const uint8_t *value; +} s_tlv_data; + +typedef struct { + bool valid; + char *name; + uint8_t addr[ADDRESS_LENGTH]; +} s_domain_name_info; + +typedef struct { + e_key_id key_id; + uint8_t input_sig_size; + const uint8_t *input_sig; + cx_sha256_t hash_ctx; +} s_sig_ctx; + +typedef bool(t_tlv_handler)(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx); + +typedef struct { + uint8_t tag; + t_tlv_handler *func; + uint8_t found; +} s_tlv_handler; + +static s_tlv_payload g_tlv_payload = {0}; +static s_domain_name_info g_domain_name_info; +char g_domain_name[DOMAIN_NAME_MAX_LENGTH + 1]; + +/** + * Send a response APDU + * + * @param[in] success whether it should use \ref APDU_RESPONSE_OK + * @param[in] off payload offset (0 if no data other than status word) + */ +static void response_to_domain_name(bool success, uint8_t off) { + uint16_t sw; + + if (success) { + sw = APDU_RESPONSE_OK; + } else { + sw = apdu_response_code; + } + U2BE_ENCODE(G_io_apdu_buffer, off, sw); + + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, off + 2); +} + +/** + * Checks if a domain name for the given chain ID and address is known + * + * @param[in] chain_id given chain ID + * @param[in] addr given address + * @return whether there is or not + */ +bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr) { + bool ret = false; + + if (g_domain_name_info.valid) { + if ((*chain_id == ETHEREUM_MAINNET_CHAINID) && + (memcmp(addr, g_domain_name_info.addr, ADDRESS_LENGTH) == 0)) { + ret = true; + } + memset(&g_domain_name_info, 0, sizeof(g_domain_name_info)); + } + return ret; +} + +/** + * Get uint from tlv data + * + * Get an unsigned integer from variable length tlv data (up to 4 bytes) + * + * @param[in] data tlv data + * @param[out] value the returned value + * @return whether it was successful + */ +static bool get_uint_from_data(const s_tlv_data *data, uint32_t *value) { + uint8_t size_diff; + uint8_t buffer[sizeof(uint32_t)]; + + if (data->length > sizeof(buffer)) { + PRINTF("Unexpectedly long value (%u bytes) for tag 0x%x\n", data->length, data->tag); + return false; + } + size_diff = sizeof(buffer) - data->length; + memset(buffer, 0, size_diff); + memcpy(buffer + size_diff, data->value, data->length); + *value = U4BE(buffer, 0); + return true; +} + +/** + * Handler for tag \ref STRUCTURE_TYPE + * + * @param[] data the tlv data + * @param[] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_structure_type(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + (void) data; + (void) domain_name_info; + (void) sig_ctx; + return true; // unhandled for now +} + +/** + * Handler for tag \ref STRUCTURE_VERSION + * + * @param[] data the tlv data + * @param[] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_structure_version(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + (void) data; + (void) domain_name_info; + (void) sig_ctx; + return true; // unhandled for now +} + +/** + * Handler for tag \ref CHALLENGE + * + * @param[in] data the tlv data + * @param[] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_challenge(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) domain_name_info; + (void) sig_ctx; + return get_uint_from_data(data, &value) && (value == get_challenge()); +} + +/** + * Handler for tag \ref SIGNER_KEY_ID + * + * @param[in] data the tlv data + * @param[] domain_name_info the domain name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_sign_key_id(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) domain_name_info; + if (!get_uint_from_data(data, &value) || (value > UINT8_MAX)) { + return false; + } + sig_ctx->key_id = value; + return true; +} + +/** + * Handler for tag \ref SIGNER_ALGO + * + * @param[in] data the tlv data + * @param[] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_sign_algo(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) domain_name_info; + (void) sig_ctx; + return get_uint_from_data(data, &value) && (value == ALGO_SECP256K1); +} + +/** + * Handler for tag \ref SIGNATURE + * + * @param[in] data the tlv data + * @param[] domain_name_info the domain name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_signature(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + (void) domain_name_info; + sig_ctx->input_sig_size = data->length; + sig_ctx->input_sig = data->value; + return true; +} + +/** + * Handler for tag \ref DOMAIN_NAME + * + * @param[in] data the tlv data + * @param[out] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_domain_name(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + if (data->length > DOMAIN_NAME_MAX_LENGTH) { + return false; + } + strncpy(domain_name_info->name, (const char *) data->value, data->length); + domain_name_info->name[data->length] = '\0'; + return true; +} + +/** + * Handler for tag \ref COIN_TYPE + * + * @param[in] data the tlv data + * @param[] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_coin_type(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + uint32_t value; + + (void) domain_name_info; + (void) sig_ctx; + return get_uint_from_data(data, &value) && (value == SLIP_44_ETHEREUM); +} + +/** + * Handler for tag \ref ADDRESS + * + * @param[in] data the tlv data + * @param[out] domain_name_info the domain name information + * @param[] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_address(const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + (void) sig_ctx; + if (data->length != ADDRESS_LENGTH) { + return false; + } + memcpy(domain_name_info->addr, data->value, ADDRESS_LENGTH); + return true; +} + +/** + * Verify the signature context + * + * Verify the SHA-256 hash of the payload against the public key + * + * @param[in] sig_ctx the signature context + * @return whether it was successful + */ +static bool verify_signature(const s_sig_ctx *sig_ctx) { + uint8_t hash[INT256_LENGTH]; + cx_ecfp_public_key_t verif_key; + + cx_hash((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH); + switch (sig_ctx->key_id) { +#ifdef HAVE_DOMAIN_NAME_TEST_KEY + case KEY_ID_TEST: +#else + case KEY_ID_PROD: +#endif + cx_ecfp_init_public_key(CX_CURVE_256K1, + DOMAIN_NAME_PUB_KEY, + sizeof(DOMAIN_NAME_PUB_KEY), + &verif_key); + break; + default: + PRINTF("Error: Unknown metadata key ID %u\n", sig_ctx->key_id); + return false; + } + if (!cx_ecdsa_verify(&verif_key, + CX_LAST, + CX_SHA256, + hash, + sizeof(hash), + sig_ctx->input_sig, + sig_ctx->input_sig_size)) { + PRINTF("Domain name signature verification failed!\n"); +#ifndef HAVE_BYPASS_SIGNATURES + return false; +#endif + } + return true; +} + +/** + * Calls the proper handler for the given TLV data + * + * Checks if there is a proper handler function for the given TLV tag and then calls it + * + * @param[in] handlers list of tag / handler function pairs + * @param[in] handler_count number of handlers + * @param[in] data the TLV data + * @param[out] domain_name_info the domain name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool handle_tlv_data(s_tlv_handler *handlers, + int handler_count, + const s_tlv_data *data, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + t_tlv_handler *fptr; + + // check if a handler exists for this tag + for (int idx = 0; idx < handler_count; ++idx) { + if (handlers[idx].tag == data->tag) { + handlers[idx].found += 1; + fptr = PIC(handlers[idx].func); + if (!(*fptr)(data, domain_name_info, sig_ctx)) { + PRINTF("Error while handling tag 0x%x\n", handlers[idx].tag); + return false; + } + break; + } + } + return true; +} + +/** + * Checks if all the TLV tags were found during parsing + * + * @param[in,out] handlers list of tag / handler function pairs + * @param[in] handler_count number of handlers + * @return whether all tags were found + */ +static bool check_found_tlv_tags(s_tlv_handler *handlers, int handler_count) { + // prevent missing or duplicated tags + for (int idx = 0; idx < handler_count; ++idx) { + if (handlers[idx].found != 1) { + PRINTF("Found %u occurence(s) of tag 0x%x in TLV!\n", + handlers[idx].found, + handlers[idx].tag); + return false; + } + } + return true; +} + +/** Parse DER-encoded value + * + * Parses a DER-encoded value (up to 4 bytes long) + * https://en.wikipedia.org/wiki/X.690 + * + * @param[in] payload the TLV payload + * @param[in,out] offset the payload offset + * @param[out] value the parsed value + * @return whether it was successful + */ +static bool parse_der_value(const s_tlv_payload *payload, size_t *offset, uint32_t *value) { + bool ret = false; + uint8_t byte_length; + uint8_t buf[sizeof(*value)]; + + if (value != NULL) { + if (payload->buf[*offset] & DER_LONG_FORM_FLAG) { // long form + byte_length = payload->buf[*offset] & DER_FIRST_BYTE_VALUE_MASK; + *offset += 1; + if ((*offset + byte_length) > payload->size) { + PRINTF("TLV payload too small for DER encoded value\n"); + } else { + if (byte_length > sizeof(buf)) { + PRINTF("Unexpectedly long DER-encoded value (%u bytes)\n", byte_length); + } else { + memset(buf, 0, (sizeof(buf) - byte_length)); + memcpy(buf + (sizeof(buf) - byte_length), &payload->buf[*offset], byte_length); + *value = U4BE(buf, 0); + *offset += byte_length; + ret = true; + } + } + } else { // short form + *value = payload->buf[*offset]; + *offset += 1; + ret = true; + } + } + return ret; +} + +/** + * Get DER-encoded value as an uint8 + * + * Parses the value and checks if it fits in the given \ref uint8_t value + * + * @param[in] payload the TLV payload + * @param[in,out] offset + * @param[out] value the parsed value + * @return whether it was successful + */ +static bool get_der_value_as_uint8(const s_tlv_payload *payload, size_t *offset, uint8_t *value) { + bool ret = false; + uint32_t tmp_value; + + if (value != NULL) { + if (!parse_der_value(payload, offset, &tmp_value)) { + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + } else { + if (tmp_value <= UINT8_MAX) { + *value = tmp_value; + ret = true; + } else { + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + PRINTF("TLV DER-encoded value larger than 8 bits\n"); + } + } + } + return ret; +} + +/** + * Parse the TLV payload + * + * Does the TLV parsing but also the SHA-256 hash of the payload. + * + * @param[in] payload the raw TLV payload + * @param[out] domain_name_info the domain name information + * @param[out] sig_ctx the signature context + * @return whether it was successful + */ +static bool parse_tlv(const s_tlv_payload *payload, + s_domain_name_info *domain_name_info, + s_sig_ctx *sig_ctx) { + s_tlv_handler handlers[] = { + {.tag = STRUCTURE_TYPE, .func = &handle_structure_type, .found = 0}, + {.tag = STRUCTURE_VERSION, .func = &handle_structure_version, .found = 0}, + {.tag = CHALLENGE, .func = &handle_challenge, .found = 0}, + {.tag = SIGNER_KEY_ID, .func = &handle_sign_key_id, .found = 0}, + {.tag = SIGNER_ALGO, .func = &handle_sign_algo, .found = 0}, + {.tag = SIGNATURE, .func = &handle_signature, .found = 0}, + {.tag = DOMAIN_NAME, .func = &handle_domain_name, .found = 0}, + {.tag = COIN_TYPE, .func = &handle_coin_type, .found = 0}, + {.tag = ADDRESS, .func = &handle_address, .found = 0}}; + e_tlv_step step = TLV_TAG; + s_tlv_data data; + size_t offset = 0; + size_t tag_start_off; + + cx_sha256_init(&sig_ctx->hash_ctx); + // handle TLV payload + while (offset < payload->size) { + switch (step) { + case TLV_TAG: + tag_start_off = offset; + if (!get_der_value_as_uint8(payload, &offset, &data.tag)) { + return false; + } + step = TLV_LENGTH; + break; + + case TLV_LENGTH: + if (!get_der_value_as_uint8(payload, &offset, &data.length)) { + return false; + } + step = TLV_VALUE; + break; + + case TLV_VALUE: + if (offset >= payload->size) { + return false; + } + data.value = &payload->buf[offset]; + if (!handle_tlv_data(handlers, + ARRAY_SIZE(handlers), + &data, + domain_name_info, + sig_ctx)) { + return false; + } + offset += data.length; + if (data.tag != SIGNATURE) { // the signature wasn't computed on itself + hash_nbytes(&payload->buf[tag_start_off], + (offset - tag_start_off), + (cx_hash_t *) &sig_ctx->hash_ctx); + } + step = TLV_TAG; + break; + + default: + return false; + } + } + return check_found_tlv_tags(handlers, ARRAY_SIZE(handlers)); +} + +/** + * Allocate and assign TLV payload + * + * @param[in] payload payload structure + * @param[in] size size of the payload + * @return whether it was successful + */ +static bool alloc_payload(s_tlv_payload *payload, uint16_t size) { + if ((payload->buf = mem_alloc(size)) == NULL) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; + } + payload->expected_size = size; + return true; +} + +/** + * Deallocate and unassign TLV payload + * + * @param[in] payload payload structure + */ +static void free_payload(s_tlv_payload *payload) { + mem_dealloc(payload->expected_size); + memset(payload, 0, sizeof(*payload)); +} + +static bool handle_first_chunk(const uint8_t **data, uint8_t *length, s_tlv_payload *payload) { + // check if no payload is already in memory + if (payload->buf != NULL) { + free_payload(payload); + apdu_response_code = APDU_RESPONSE_INVALID_P1_P2; + return false; + } + + // check if we at least get the size + if (*length < sizeof(payload->expected_size)) { + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + return false; + } + if (!alloc_payload(payload, U2BE(*data, 0))) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; + } + + // skip the size so we can process it like a following chunk + *data += sizeof(payload->expected_size); + *length -= sizeof(payload->expected_size); + return true; +} + +/** + * Handle domain name APDU + * + * @param[in] p1 first APDU instruction parameter + * @param[in] p2 second APDU instruction parameter + * @param[in] data APDU payload + * @param[in] length payload size + */ +void handle_provide_domain_name(uint8_t p1, uint8_t p2, const uint8_t *data, uint8_t length) { + s_sig_ctx sig_ctx; + + (void) p2; + if (p1 == P1_FIRST_CHUNK) { + if (!handle_first_chunk(&data, &length, &g_tlv_payload)) { + return response_to_domain_name(false, 0); + } + } else { + // check if a payload is already in memory + if (g_tlv_payload.buf == NULL) { + apdu_response_code = APDU_RESPONSE_INVALID_P1_P2; + return response_to_domain_name(false, 0); + } + } + + if ((g_tlv_payload.size + length) > g_tlv_payload.expected_size) { + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + free_payload(&g_tlv_payload); + PRINTF("TLV payload size mismatch!\n"); + return response_to_domain_name(false, 0); + } + // feed into tlv payload + memcpy(g_tlv_payload.buf + g_tlv_payload.size, data, length); + g_tlv_payload.size += length; + + // everything has been received + if (g_tlv_payload.size == g_tlv_payload.expected_size) { + g_domain_name_info.name = g_domain_name; + if (!parse_tlv(&g_tlv_payload, &g_domain_name_info, &sig_ctx) || + !verify_signature(&sig_ctx)) { + free_payload(&g_tlv_payload); + roll_challenge(); // prevent brute-force guesses + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + return response_to_domain_name(false, 0); + } + g_domain_name_info.valid = true; + PRINTF("Registered : %s => %.*h\n", + g_domain_name_info.name, + ADDRESS_LENGTH, + g_domain_name_info.addr); + free_payload(&g_tlv_payload); + roll_challenge(); // prevent replays + } + return response_to_domain_name(true, 0); +} + +#endif // HAVE_DOMAIN_NAME diff --git a/src_features/provideDomainName/domain_name.h b/src_features/provideDomainName/domain_name.h new file mode 100644 index 0000000..b8f22de --- /dev/null +++ b/src_features/provideDomainName/domain_name.h @@ -0,0 +1,18 @@ +#ifdef HAVE_DOMAIN_NAME + +#ifndef DOMAIN_NAME_H_ +#define DOMAIN_NAME_H_ + +#include +#include + +#define DOMAIN_NAME_MAX_LENGTH 255 + +bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr); +void handle_provide_domain_name(uint8_t p1, uint8_t p2, const uint8_t *data, uint8_t length); + +extern char g_domain_name[DOMAIN_NAME_MAX_LENGTH + 1]; + +#endif // DOMAIN_NAME_H_ + +#endif // HAVE_DOMAIN_NAME From dbad8d1ba16914a5e564fa8500508cd1d1a53646 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 17 Feb 2023 16:56:12 +0100 Subject: [PATCH 57/79] Domain name UI implementation --- src_bagl/ui_domain_name.c | 17 ++++++ src_bagl/ui_domain_name.h | 12 +++++ src_bagl/ui_flow.c | 111 ++++++++++++++++++++++++-------------- src_bagl/ui_flow_signTx.c | 18 ++++++- 4 files changed, 117 insertions(+), 41 deletions(-) create mode 100644 src_bagl/ui_domain_name.c create mode 100644 src_bagl/ui_domain_name.h diff --git a/src_bagl/ui_domain_name.c b/src_bagl/ui_domain_name.c new file mode 100644 index 0000000..599133d --- /dev/null +++ b/src_bagl/ui_domain_name.c @@ -0,0 +1,17 @@ +#ifdef HAVE_DOMAIN_NAME + +#include "ux.h" +#include "domain_name.h" + +////////////////////////////////////////////////////////////////////// +// clang-format off +UX_STEP_NOCB( + ux_domain_name_step, + bnnn_paging, + { + .title = "Domain", + .text = g_domain_name + }); +// clang-format on + +#endif // HAVE_DOMAIN_NAME diff --git a/src_bagl/ui_domain_name.h b/src_bagl/ui_domain_name.h new file mode 100644 index 0000000..bcfa8b0 --- /dev/null +++ b/src_bagl/ui_domain_name.h @@ -0,0 +1,12 @@ +#ifdef HAVE_DOMAIN_NAME + +#ifndef UI_DOMAIN_NAME_H_ +#define UI_DOMAIN_NAME_H_ + +#include "ux.h" + +extern const ux_flow_step_t ux_domain_name_step; + +#endif // UI_DOMAIN_NAME_H_ + +#endif // HAVE_DOMAIN_NAME diff --git a/src_bagl/ui_flow.c b/src_bagl/ui_flow.c index 7cac427..a98ce6b 100644 --- a/src_bagl/ui_flow.c +++ b/src_bagl/ui_flow.c @@ -7,13 +7,26 @@ #define DISABLED_STR "Disabled" #define BUF_INCREMENT (MAX(strlen(ENABLED_STR), strlen(DISABLED_STR)) + 1) -void display_settings(const ux_flow_step_t* const start_step); -void switch_settings_blind_signing(void); -void switch_settings_display_data(void); -void switch_settings_display_nonce(void); +// Reuse the strings.common.fullAmount buffer for settings displaying. +// No risk of collision as this buffer is unused in the settings menu +#define SETTING_BLIND_SIGNING_STATE (strings.common.fullAmount) +#define SETTING_DISPLAY_DATA_STATE (strings.common.fullAmount + (BUF_INCREMENT * 1)) +#define SETTING_DISPLAY_NONCE_STATE (strings.common.fullAmount + (BUF_INCREMENT * 2)) +#define SETTING_VERBOSE_EIP712_STATE (strings.common.fullAmount + (BUF_INCREMENT * 3)) +#define SETTING_VERBOSE_DOMAIN_NAME_STATE (strings.common.fullAmount + (BUF_INCREMENT * 4)) + +#define BOOL_TO_STATE_STR(b) (b ? ENABLED_STR : DISABLED_STR) + +static void display_settings(const ux_flow_step_t* const start_step); +static void switch_settings_blind_signing(void); +static void switch_settings_display_data(void); +static void switch_settings_display_nonce(void); #ifdef HAVE_EIP712_FULL_SUPPORT -void switch_settings_verbose_eip712(void); +static void switch_settings_verbose_eip712(void); #endif // HAVE_EIP712_FULL_SUPPORT +#ifdef HAVE_DOMAIN_NAME +static void switch_settings_verbose_domain_name(void); +#endif // HAVE_DOMAIN_NAME ////////////////////////////////////////////////////////////////////// // clang-format off @@ -75,7 +88,7 @@ UX_STEP_CB( "Transaction", "blind signing", #endif - strings.common.fullAddress + SETTING_BLIND_SIGNING_STATE }); UX_STEP_CB( @@ -95,7 +108,7 @@ UX_STEP_CB( "Show contract data", "details", #endif - strings.common.fullAddress + BUF_INCREMENT + SETTING_DISPLAY_DATA_STATE }); UX_STEP_CB( @@ -115,7 +128,7 @@ UX_STEP_CB( "Show account nonce", "in transactions", #endif - strings.common.fullAddress + (BUF_INCREMENT * 2) + SETTING_DISPLAY_NONCE_STATE }); #ifdef HAVE_EIP712_FULL_SUPPORT @@ -127,10 +140,23 @@ UX_STEP_CB( "Verbose EIP-712", "Ignore filtering &", "display raw content", - strings.common.fullAddress + (BUF_INCREMENT * 3) + SETTING_VERBOSE_EIP712_STATE }); #endif // HAVE_EIP712_FULL_SUPPORT +#ifdef HAVE_DOMAIN_NAME +UX_STEP_CB( + ux_settings_flow_verbose_domain_name_step, + bnnn, + switch_settings_verbose_domain_name(), + { + "Verbose domains", + "Show", + "resolved address", + SETTING_VERBOSE_DOMAIN_NAME_STATE + }); +#endif // HAVE_DOMAIN_NAME + UX_STEP_CB( ux_settings_flow_back_step, @@ -149,54 +175,61 @@ UX_FLOW(ux_settings_flow, #ifdef HAVE_EIP712_FULL_SUPPORT &ux_settings_flow_verbose_eip712_step, #endif // HAVE_EIP712_FULL_SUPPORT +#ifdef HAVE_DOMAIN_NAME + &ux_settings_flow_verbose_domain_name_step, +#endif // HAVE_DOMAIN_NAME &ux_settings_flow_back_step); -void display_settings(const ux_flow_step_t* const start_step) { - bool settings[] = {N_storage.dataAllowed, - N_storage.contractDetails, - N_storage.displayNonce, +static void display_settings(const ux_flow_step_t* const start_step) { + strlcpy(SETTING_BLIND_SIGNING_STATE, BOOL_TO_STATE_STR(N_storage.dataAllowed), BUF_INCREMENT); + strlcpy(SETTING_DISPLAY_DATA_STATE, + BOOL_TO_STATE_STR(N_storage.contractDetails), + BUF_INCREMENT); + strlcpy(SETTING_DISPLAY_NONCE_STATE, BOOL_TO_STATE_STR(N_storage.displayNonce), BUF_INCREMENT); #ifdef HAVE_EIP712_FULL_SUPPORT - N_storage.verbose_eip712 + strlcpy(SETTING_VERBOSE_EIP712_STATE, + BOOL_TO_STATE_STR(N_storage.verbose_eip712), + BUF_INCREMENT); #endif // HAVE_EIP712_FULL_SUPPORT - }; - uint8_t offset = 0; - - for (unsigned int i = 0; i < ARRAY_SIZE(settings); ++i) { - strlcpy(strings.common.fullAddress + offset, - (settings[i] ? ENABLED_STR : DISABLED_STR), - sizeof(strings.common.fullAddress) - offset); - offset += BUF_INCREMENT; - } +#ifdef HAVE_DOMAIN_NAME + strlcpy(SETTING_VERBOSE_DOMAIN_NAME_STATE, + BOOL_TO_STATE_STR(N_storage.verbose_domain_name), + BUF_INCREMENT); +#endif // HAVE_DOMAIN_NAME ux_flow_init(0, ux_settings_flow, start_step); } -void switch_settings_blind_signing(void) { - uint8_t value = (N_storage.dataAllowed ? 0 : 1); - nvm_write((void*) &N_storage.dataAllowed, (void*) &value, sizeof(uint8_t)); - display_settings(&ux_settings_flow_blind_signing_step); +static void toggle_setting(volatile bool* setting, const ux_flow_step_t* ui_step) { + bool value = !*setting; + nvm_write((void*) setting, (void*) &value, sizeof(value)); + display_settings(ui_step); } -void switch_settings_display_data(void) { - uint8_t value = (N_storage.contractDetails ? 0 : 1); - nvm_write((void*) &N_storage.contractDetails, (void*) &value, sizeof(uint8_t)); - display_settings(&ux_settings_flow_display_data_step); +static void switch_settings_blind_signing(void) { + toggle_setting(&N_storage.dataAllowed, &ux_settings_flow_blind_signing_step); } -void switch_settings_display_nonce(void) { - uint8_t value = (N_storage.displayNonce ? 0 : 1); - nvm_write((void*) &N_storage.displayNonce, (void*) &value, sizeof(uint8_t)); - display_settings(&ux_settings_flow_display_nonce_step); +static void switch_settings_display_data(void) { + toggle_setting(&N_storage.contractDetails, &ux_settings_flow_display_data_step); +} + +static void switch_settings_display_nonce(void) { + toggle_setting(&N_storage.displayNonce, &ux_settings_flow_display_nonce_step); } #ifdef HAVE_EIP712_FULL_SUPPORT -void switch_settings_verbose_eip712(void) { - bool value = !N_storage.verbose_eip712; - nvm_write((void*) &N_storage.verbose_eip712, (void*) &value, sizeof(value)); - display_settings(&ux_settings_flow_verbose_eip712_step); +static void switch_settings_verbose_eip712(void) { + toggle_setting(&N_storage.verbose_eip712, &ux_settings_flow_verbose_eip712_step); } #endif // HAVE_EIP712_FULL_SUPPORT +#ifdef HAVE_DOMAIN_NAME +static void switch_settings_verbose_domain_name(void) { + toggle_setting(&N_storage.verbose_domain_name, &ux_settings_flow_verbose_domain_name_step); +} +#endif // HAVE_DOMAIN_NAME + ////////////////////////////////////////////////////////////////////// // clang-format off #ifdef TARGET_NANOS diff --git a/src_bagl/ui_flow_signTx.c b/src_bagl/ui_flow_signTx.c index 574dd9c..2b55922 100644 --- a/src_bagl/ui_flow_signTx.c +++ b/src_bagl/ui_flow_signTx.c @@ -8,6 +8,8 @@ #include "ui_plugin.h" #include "common_ui.h" #include "plugins.h" +#include "domain_name.h" +#include "ui_domain_name.h" // clang-format off UX_STEP_NOCB( @@ -217,7 +219,19 @@ void ux_approve_tx(bool fromPlugin) { } else { // We're in a regular transaction, just show the amount and the address ux_approval_tx_flow[step++] = &ux_approval_amount_step; - ux_approval_tx_flow[step++] = &ux_approval_address_step; +#ifdef HAVE_DOMAIN_NAME + uint64_t chain_id = get_chain_id(); + if (has_domain_name(&chain_id, tmpContent.txContent.destination)) { + ux_approval_tx_flow[step++] = &ux_domain_name_step; + if (N_storage.verbose_domain_name) { + ux_approval_tx_flow[step++] = &ux_approval_address_step; + } + } else { +#endif // HAVE_DOMAIN_NAME + ux_approval_tx_flow[step++] = &ux_approval_address_step; +#ifdef HAVE_DOMAIN_NAME + } +#endif // HAVE_DOMAIN_NAME } if (N_storage.displayNonce) { @@ -235,4 +249,4 @@ void ux_approve_tx(bool fromPlugin) { ux_approval_tx_flow[step++] = FLOW_END_STEP; ux_flow_init(0, ux_approval_tx_flow, NULL); -} \ No newline at end of file +} From fbe062a861a5e4f7b2f1815f04e78345d8724365 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 7 Apr 2023 17:39:19 +0200 Subject: [PATCH 58/79] Extra security checks on domain name when parsing it --- .../cmd_provide_domain_name.c | 44 ++++++++++++++++++- src_features/provideDomainName/domain_name.h | 2 +- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src_features/provideDomainName/cmd_provide_domain_name.c b/src_features/provideDomainName/cmd_provide_domain_name.c index aa7e547..0d0849f 100644 --- a/src_features/provideDomainName/cmd_provide_domain_name.c +++ b/src_features/provideDomainName/cmd_provide_domain_name.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "utils.h" // ARRAY_SIZE #include "apdu_constants.h" #include "domain_name.h" @@ -113,6 +114,8 @@ static void response_to_domain_name(bool success, uint8_t off) { /** * Checks if a domain name for the given chain ID and address is known * + * Always wipes the content of \ref g_domain_name_info + * * @param[in] chain_id given chain ID * @param[in] addr given address * @return whether there is or not @@ -121,12 +124,13 @@ bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr) { bool ret = false; if (g_domain_name_info.valid) { + // TODO: Remove once other domain name providers are supported if ((*chain_id == ETHEREUM_MAINNET_CHAINID) && (memcmp(addr, g_domain_name_info.addr, ADDRESS_LENGTH) == 0)) { ret = true; } - memset(&g_domain_name_info, 0, sizeof(g_domain_name_info)); } + memset(&g_domain_name_info, 0, sizeof(g_domain_name_info)); return ret; } @@ -262,6 +266,30 @@ static bool handle_signature(const s_tlv_data *data, return true; } +/** + * Tests if the given domain name character is valid (in our subset of allowed characters) + * + * @param[in] c given character + * @return whether the character is valid + */ +static bool is_valid_domain_character(char c) { + if (isalpha((int) c)) { + if (!islower((int) c)) { + return false; + } + } else if (!isdigit((int) c)) { + switch (c) { + case '.': + case '-': + case '_': + break; + default: + return false; + } + } + return true; +} + /** * Handler for tag \ref DOMAIN_NAME * @@ -275,9 +303,21 @@ static bool handle_domain_name(const s_tlv_data *data, s_sig_ctx *sig_ctx) { (void) sig_ctx; if (data->length > DOMAIN_NAME_MAX_LENGTH) { + PRINTF("Domain name too long! (%u)\n", data->length); return false; } - strncpy(domain_name_info->name, (const char *) data->value, data->length); + // TODO: Remove once other domain name providers are supported + if ((data->length < 5) || (strncmp(".eth", (char *) &data->value[data->length - 4], 4) != 0)) { + PRINTF("Unexpected TLD!\n"); + return false; + } + for (int idx = 0; idx < data->length; ++idx) { + if (!is_valid_domain_character(data->value[idx])) { + PRINTF("Domain name contains non-allowed character! (0x%x)\n", data->value[idx]); + return false; + } + domain_name_info->name[idx] = data->value[idx]; + } domain_name_info->name[data->length] = '\0'; return true; } diff --git a/src_features/provideDomainName/domain_name.h b/src_features/provideDomainName/domain_name.h index b8f22de..502254f 100644 --- a/src_features/provideDomainName/domain_name.h +++ b/src_features/provideDomainName/domain_name.h @@ -6,7 +6,7 @@ #include #include -#define DOMAIN_NAME_MAX_LENGTH 255 +#define DOMAIN_NAME_MAX_LENGTH 30 bool has_domain_name(const uint64_t *chain_id, const uint8_t *addr); void handle_provide_domain_name(uint8_t p1, uint8_t p2, const uint8_t *data, uint8_t length); From 50d14f5686b5f718fa1bd7f1426e13db73387f1c Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 28 Nov 2022 17:19:40 +0100 Subject: [PATCH 59/79] Removed unused Python empty init files --- tests/ragger/eip712/__init__.py | 0 tests/ragger/ethereum_client/__init__.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/ragger/eip712/__init__.py delete mode 100644 tests/ragger/ethereum_client/__init__.py diff --git a/tests/ragger/eip712/__init__.py b/tests/ragger/eip712/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/ragger/ethereum_client/__init__.py b/tests/ragger/ethereum_client/__init__.py deleted file mode 100644 index e69de29..0000000 From e99cb5f46975788d160478d1872074351f74d182 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 27 Feb 2023 17:52:54 +0100 Subject: [PATCH 60/79] Upgraded Ragger version + simplified PIP requirements file --- tests/ragger/requirements.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/ragger/requirements.txt b/tests/ragger/requirements.txt index 8836582..b2c4a7b 100644 --- a/tests/ragger/requirements.txt +++ b/tests/ragger/requirements.txt @@ -1,6 +1,3 @@ -requests>=2.28,<3.0 -click>=8.0,<9.0 # needed by the CI as it installs an older version and breaks dependencies -protobuf==3.20.1 # To fix the protobuf dependency bug -ragger[speculos] +ragger[speculos]>=1.6.0,<1.7.0 pytest ecdsa From faed963e3a350205ce6b949472d86fe65ed8e193 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 2 Mar 2023 15:12:18 +0100 Subject: [PATCH 61/79] Now uses the reusable conftest from Ragger --- .github/workflows/ci-workflow.yml | 31 +++++++------- tests/ragger/conftest.py | 70 ++++--------------------------- 2 files changed, 22 insertions(+), 79 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 7c52cb7..d487776 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -167,6 +167,16 @@ jobs: build_ragger_elfs: name: Building binaries for Ragger tests + strategy: + matrix: + include: + - sdk: "$NANOS_SDK" + name: "nanos" + - sdk: "$NANOX_SDK" + name: "nanox" + - sdk: "$NANOSP_SDK" + name: "nanosp" + runs-on: ubuntu-latest container: image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest @@ -177,20 +187,14 @@ jobs: - name: Build test binaries run: | - make -j BOLOS_SDK=$NANOS_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 - mv bin/app.elf app-nanos.elf - make clean - make -j BOLOS_SDK=$NANOX_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 - mv bin/app.elf app-nanox.elf - make clean - make -j BOLOS_SDK=$NANOSP_SDK CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 - mv bin/app.elf app-nanosp.elf + make -j BOLOS_SDK=${{ matrix.sdk }} CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 + mv bin/app.elf app-${{ matrix.name }}.elf - name: Upload app binaries uses: actions/upload-artifact@v3 with: name: ragger_elfs - path: ./app-*.elf + path: app-${{ matrix.name }}.elf create_ragger_env: name: Cache Ragger environment @@ -249,12 +253,7 @@ jobs: uses: actions/download-artifact@v3 with: name: ragger_elfs - path: tmp/ - - - name: Put them where they belong - run: | - mkdir -p tests/ragger/elfs - find tmp/ -type f -name '*.elf' -exec cp {} tests/ragger/elfs/ \; + path: tests/ragger/elfs/ - name: Get cached environment uses: actions/cache@v3 @@ -273,4 +272,4 @@ jobs: run: | cd tests/ragger . ./venv/bin/activate - pytest --path ./elfs --model ${{ matrix.model }} -s -v --tb=short + pytest --device ${{ matrix.model }} -s -v --tb=short diff --git a/tests/ragger/conftest.py b/tests/ragger/conftest.py index e527350..60fb393 100644 --- a/tests/ragger/conftest.py +++ b/tests/ragger/conftest.py @@ -1,68 +1,12 @@ import pytest -from pathlib import Path -from ragger.firmware import Firmware -from ragger.backend import SpeculosBackend, LedgerCommBackend, LedgerWalletBackend, BackendInterface +from ragger.conftest import configuration +from ragger.backend import BackendInterface from ethereum_client.client import EthereumClient -FWS = [ - Firmware("nanos", "2.1"), - Firmware("nanox", "2.0.2"), - Firmware("nanosp", "1.0.3") -] - -def pytest_addoption(parser): - parser.addoption("--backend", action="store", default="speculos") - parser.addoption("--path", action="store", default="./elfs") - parser.addoption("--model", action="store", required=True) - -# accessing the value of the "--backend" option as a fixture -@pytest.fixture -def arg_backend(pytestconfig) -> str: - return pytestconfig.getoption("backend") - -@pytest.fixture -def arg_path(pytestconfig) -> str: - return pytestconfig.getoption("path") - -@pytest.fixture -def arg_model(pytestconfig) -> str: - return pytestconfig.getoption("model") - -# Providing the firmware as a fixture -@pytest.fixture -def firmware(arg_model: str) -> Firmware: - for fw in FWS: - if fw.device == arg_model: - return fw - raise ValueError("Unknown device model \"%s\"" % (arg_model)) - -def get_elf_path(arg_path: str, firmware: Firmware) -> Path: - elf_dir = Path(arg_path).resolve() - assert elf_dir.is_dir(), ("%s is not a directory" % (arg_path)) - app = elf_dir / ("app-%s.elf" % firmware.device) - assert app.is_file(), ("Firmware %s does not exist !" % (app)) - return app - -# Depending on the "--backend" option value, a different backend is -# instantiated, and the tests will either run on Speculos or on a physical -# device depending on the backend -def create_backend(backend: str, arg_path: str, firmware: Firmware) -> BackendInterface: - if backend.lower() == "ledgercomm": - return LedgerCommBackend(firmware, interface="hid") - elif backend.lower() == "ledgerwallet": - return LedgerWalletBackend(firmware) - elif backend.lower() == "speculos": - return SpeculosBackend(get_elf_path(arg_path, firmware), firmware) - else: - raise ValueError(f"Backend '{backend}' is unknown. Valid backends are: {BACKENDS}") - -# This fixture will create and return the backend client -@pytest.fixture -def backend_client(arg_backend: str, arg_path: str, firmware: Firmware) -> BackendInterface: - with create_backend(arg_backend, arg_path, firmware) as b: - yield b - # This final fixture will return the properly configured app client, to be used in tests @pytest.fixture -def app_client(backend_client: BackendInterface) -> EthereumClient: - return EthereumClient(backend_client) +def app_client(backend: BackendInterface) -> EthereumClient: + return EthereumClient(backend) + +# Pull all features from the base ragger conftest using the overridden configuration +pytest_plugins = ("ragger.conftest.base_conftest", ) From be3aa9f1ba6052b80bdb5332cdf2e1411040826d Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 2 Mar 2023 15:14:16 +0100 Subject: [PATCH 62/79] Now uses the reusable Ragger tests workflows --- .github/workflows/ci-workflow.yml | 118 ++++-------------------------- tests/ragger/test_eip712.py | 2 +- 2 files changed, 14 insertions(+), 106 deletions(-) diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index d487776..3e15b79 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -166,110 +166,18 @@ jobs: # ===================================================== build_ragger_elfs: - name: Building binaries for Ragger tests - strategy: - matrix: - include: - - sdk: "$NANOS_SDK" - name: "nanos" - - sdk: "$NANOX_SDK" - name: "nanox" - - sdk: "$NANOSP_SDK" - name: "nanosp" - - runs-on: ubuntu-latest - container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest - - steps: - - name: Clone - uses: actions/checkout@v3 - - - name: Build test binaries - run: | - make -j BOLOS_SDK=${{ matrix.sdk }} CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1 - mv bin/app.elf app-${{ matrix.name }}.elf - - - name: Upload app binaries - uses: actions/upload-artifact@v3 - with: - name: ragger_elfs - path: app-${{ matrix.name }}.elf - - create_ragger_env: - name: Cache Ragger environment - runs-on: ubuntu-latest - - steps: - - name: Clone - uses: actions/checkout@v3 - - - name: APT update - run: | - sudo apt update - - - name: Create virtual env with dependencies - run: | - cd tests/ragger - python3 -m venv ./venv - . ./venv/bin/activate - pip3 install --extra-index-url https://test.pypi.org/simple/ -r requirements.txt - # Used for the cache key - echo "py_deps=$(pip freeze | md5sum | cut -d' ' -f1)" >> $GITHUB_ENV - - - name: Download QEMU - run: | - sudo apt install --download-only -y qemu-user-static - mkdir -p tests/ragger/packages - cp /var/cache/apt/archives/*.deb tests/ragger/packages/ - # Used for the cache key - echo "deb_deps=$(find /var/cache/apt/archives/ -maxdepth 0 -type f -name '*.deb' | md5sum | cut -d' ' -f 1)" >> $GITHUB_ENV - - - name: Set up cache - uses: actions/cache@v3 - with: - key: ${{ runner.os }}-raggenv-${{ env.py_deps }}-${{ env.deb_deps }} - path: | - tests/ragger/venv/ - tests/ragger/packages/ - outputs: - py_deps: ${{ env.py_deps }} - deb_deps: ${{ env.deb_deps }} - + name: Build app for Ragger tests + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1 + with: + upload_app_binaries_artifact: "ragger_elfs" + flags: "DEBUG=1 CAL_CI_KEY=1 DOMAIN_NAME_TEST_KEY=1" + run_for_devices: '["nanos", "nanox", "nanosp"]' jobs-ragger-tests: - name: Ragger tests - strategy: - matrix: - model: ["nanos", "nanox", "nanosp"] - needs: [build_ragger_elfs, create_ragger_env] - runs-on: ubuntu-latest - - steps: - - name: Clone - uses: actions/checkout@v3 - - - name: Download previously built artifacts - uses: actions/download-artifact@v3 - with: - name: ragger_elfs - path: tests/ragger/elfs/ - - - name: Get cached environment - uses: actions/cache@v3 - with: - key: ${{ runner.os }}-raggenv-${{ needs.create_ragger_env.outputs.py_deps }}-${{ needs.create_ragger_env.outputs.deb_deps }} - path: | - tests/ragger/venv/ - tests/ragger/packages/ - - - name: Install QEMU - run: | - sudo mv tests/ragger/packages/*.deb /var/cache/apt/archives/ - sudo apt install -y qemu-user-static - - - name: Run tests - run: | - cd tests/ragger - . ./venv/bin/activate - pytest --device ${{ matrix.model }} -s -v --tb=short + name: Run Ragger tests + needs: build_ragger_elfs + uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1 + with: + download_app_binaries_artifact: "ragger_elfs" + test_dir: tests/ragger + run_for_devices: '["nanos", "nanox", "nanosp"]' diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py index bb53ba8..8dfa442 100644 --- a/tests/ragger/test_eip712.py +++ b/tests/ragger/test_eip712.py @@ -18,7 +18,7 @@ bip32 = [ def input_files() -> List[str]: files = [] - for file in os.scandir("./eip712/input_files"): + for file in os.scandir("%s/eip712/input_files" % (os.path.dirname(__file__))): if fnmatch.fnmatch(file, "*-data.json"): files.append(file.path) return sorted(files) From 25b57bb830f51dc8a2616043316e0f123b7bc343 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 27 Feb 2023 18:15:41 +0100 Subject: [PATCH 63/79] Small refactoring : renamed the Ragger client --- .../ragger/{ethereum_client => app}/client.py | 26 +++++++------- .../command_builder.py | 36 ++++++++++--------- .../ragger/{ethereum_client => app}/eip712.py | 2 +- .../response_parser.py | 2 +- .../{ethereum_client => app}/setting.py | 4 +-- tests/ragger/conftest.py | 2 +- tests/ragger/eip712/InputData.py | 2 +- tests/ragger/test_eip712.py | 26 +++++++------- 8 files changed, 50 insertions(+), 50 deletions(-) rename tests/ragger/{ethereum_client => app}/client.py (91%) rename tests/ragger/{ethereum_client => app}/command_builder.py (89%) rename tests/ragger/{ethereum_client => app}/eip712.py (84%) rename tests/ragger/{ethereum_client => app}/response_parser.py (89%) rename tests/ragger/{ethereum_client => app}/setting.py (83%) diff --git a/tests/ragger/ethereum_client/client.py b/tests/ragger/app/client.py similarity index 91% rename from tests/ragger/ethereum_client/client.py rename to tests/ragger/app/client.py index 9622a05..7e25093 100644 --- a/tests/ragger/ethereum_client/client.py +++ b/tests/ragger/app/client.py @@ -1,17 +1,17 @@ from enum import IntEnum, auto -from typing import Iterator, Dict, List +from typing import Optional from ragger.backend import BackendInterface from ragger.utils import RAPDU -from ethereum_client.command_builder import EthereumCmdBuilder -from ethereum_client.setting import SettingType, SettingImpl -from ethereum_client.eip712 import EIP712FieldType -from ethereum_client.response_parser import EthereumRespParser +from .command_builder import EthereumCmdBuilder +from .setting import SettingType, SettingImpl +from .eip712 import EIP712FieldType +from .response_parser import EthereumRespParser import signal import time -class EthereumClient: - _settings: Dict[SettingType, SettingImpl] = { +class EthereumClient: + _settings: dict[SettingType, SettingImpl] = { SettingType.BLIND_SIGNING: SettingImpl( [ "nanos", "nanox", "nanosp" ] ), @@ -65,11 +65,11 @@ class EthereumClient: array_levels: [], key_name: str): with self._send(self._cmd_builder.eip712_send_struct_def_struct_field( - field_type, - type_name, - type_size, - array_levels, - key_name)): + field_type, + type_name, + type_size, + array_levels, + key_name)): pass return self._recv() @@ -125,7 +125,7 @@ class EthereumClient: assert resp.status == 0x9000 return self._resp_parser.sign(resp.data) - def settings_set(self, new_values: Dict[SettingType, bool]): + def settings_set(self, new_values: dict[SettingType, bool]): # Go to settings for _ in range(2): self._client.right_click() diff --git a/tests/ragger/ethereum_client/command_builder.py b/tests/ragger/app/command_builder.py similarity index 89% rename from tests/ragger/ethereum_client/command_builder.py rename to tests/ragger/app/command_builder.py index 134405f..04fdc20 100644 --- a/tests/ragger/ethereum_client/command_builder.py +++ b/tests/ragger/app/command_builder.py @@ -1,18 +1,19 @@ from enum import IntEnum, auto -from typing import Iterator -from ethereum_client.eip712 import EIP712FieldType +from typing import Iterator, Optional +from .eip712 import EIP712FieldType +import struct -class InsType(IntEnum): +class InsType(IntEnum): EIP712_SEND_STRUCT_DEF = 0x1a EIP712_SEND_STRUCT_IMPL = 0x1c EIP712_SEND_FILTERING = 0x1e EIP712_SIGN = 0x0c -class P1Type(IntEnum): +class P1Type(IntEnum): COMPLETE_SEND = 0x00 PARTIAL_SEND = 0x01 -class P2Type(IntEnum): +class P2Type(IntEnum): STRUCT_NAME = 0x00 STRUCT_FIELD = 0xff ARRAY = 0x0f @@ -22,7 +23,7 @@ class P2Type(IntEnum): FILTERING_CONTRACT_NAME = 0x0f FILTERING_FIELD_NAME = 0xff -class EthereumCmdBuilder: +class EthereumCmdBuilder: _CLA: int = 0xE0 def _serialize(self, @@ -109,27 +110,28 @@ class EthereumCmdBuilder: data_w_length[:0xff]) data_w_length = data_w_length[0xff:] - def _format_bip32(self, bip32, data: bytearray) -> bytearray: - data.append(len(bip32)) - for idx in bip32: - data.append((idx & 0xff000000) >> 24) - data.append((idx & 0x00ff0000) >> 16) - data.append((idx & 0x0000ff00) >> 8) - data.append((idx & 0x000000ff)) + def _format_bip32(self, path: list[Optional[int]], data: bytearray) -> bytearray: + data.append(len(path)) + for p in path: + if p == None: + val = 0 + else: + val = (0x8 << 28) | p + data += struct.pack(">I", val) return data - def eip712_sign_new(self, bip32) -> bytes: - data = self._format_bip32(bip32, bytearray()) + def eip712_sign_new(self, bip32_path: list[Optional[int]]) -> bytes: + data = self._format_bip32(bip32_path, bytearray()) return self._serialize(InsType.EIP712_SIGN, P1Type.COMPLETE_SEND, P2Type.NEW_IMPLEM, data) def eip712_sign_legacy(self, - bip32, + bip32_path: list[Optional[int]], domain_hash: bytes, message_hash: bytes) -> bytes: - data = self._format_bip32(bip32, bytearray()) + data = self._format_bip32(bip32_path, bytearray()) data += domain_hash data += message_hash return self._serialize(InsType.EIP712_SIGN, diff --git a/tests/ragger/ethereum_client/eip712.py b/tests/ragger/app/eip712.py similarity index 84% rename from tests/ragger/ethereum_client/eip712.py rename to tests/ragger/app/eip712.py index 3438a1c..f719c6e 100644 --- a/tests/ragger/ethereum_client/eip712.py +++ b/tests/ragger/app/eip712.py @@ -1,6 +1,6 @@ from enum import IntEnum, auto -class EIP712FieldType(IntEnum): +class EIP712FieldType(IntEnum): CUSTOM = 0, INT = auto() UINT = auto() diff --git a/tests/ragger/ethereum_client/response_parser.py b/tests/ragger/app/response_parser.py similarity index 89% rename from tests/ragger/ethereum_client/response_parser.py rename to tests/ragger/app/response_parser.py index 681c18d..9d1c9bd 100644 --- a/tests/ragger/ethereum_client/response_parser.py +++ b/tests/ragger/app/response_parser.py @@ -1,4 +1,4 @@ -class EthereumRespParser: +class EthereumRespParser: def sign(self, data: bytes): assert len(data) == (1 + 32 + 32) diff --git a/tests/ragger/ethereum_client/setting.py b/tests/ragger/app/setting.py similarity index 83% rename from tests/ragger/ethereum_client/setting.py rename to tests/ragger/app/setting.py index a965fe3..a51f988 100644 --- a/tests/ragger/ethereum_client/setting.py +++ b/tests/ragger/app/setting.py @@ -1,13 +1,13 @@ from enum import IntEnum, auto from typing import List -class SettingType(IntEnum): +class SettingType(IntEnum): BLIND_SIGNING = 0, DEBUG_DATA = auto() NONCE = auto() VERBOSE_EIP712 = auto() -class SettingImpl: +class SettingImpl: devices: List[str] value: bool diff --git a/tests/ragger/conftest.py b/tests/ragger/conftest.py index 60fb393..35e3fd3 100644 --- a/tests/ragger/conftest.py +++ b/tests/ragger/conftest.py @@ -1,7 +1,7 @@ import pytest from ragger.conftest import configuration from ragger.backend import BackendInterface -from ethereum_client.client import EthereumClient +from app.client import EthereumClient # This final fixture will return the properly configured app client, to be used in tests @pytest.fixture diff --git a/tests/ragger/eip712/InputData.py b/tests/ragger/eip712/InputData.py index 38ca8c0..40a3882 100644 --- a/tests/ragger/eip712/InputData.py +++ b/tests/ragger/eip712/InputData.py @@ -4,7 +4,7 @@ import json import sys import re import hashlib -from ethereum_client.client import EthereumClient, EIP712FieldType +from app.client import EthereumClient, EIP712FieldType from cal import cal # global variables diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py index 8dfa442..51cc773 100644 --- a/tests/ragger/test_eip712.py +++ b/tests/ragger/test_eip712.py @@ -2,17 +2,17 @@ import pytest import os import fnmatch from typing import List -from ethereum_client.client import EthereumClient, SettingType +from app.client import EthereumClient, SettingType from eip712 import InputData from pathlib import Path from configparser import ConfigParser -bip32 = [ - 0x8000002c, - 0x8000003c, - 0x80000000, +bip32_path = [ + 44, + 60, 0, - 0 + None, + None ] @@ -38,7 +38,7 @@ def filtering(request) -> bool: def test_eip712_legacy(app_client: EthereumClient): v, r, s = app_client.eip712_sign_legacy( - bip32, + bip32_path, bytes.fromhex('6137beb405d9ff777172aa879e33edb34a1460e701802746c5ef96e741710e59'), bytes.fromhex('eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8') ) @@ -47,10 +47,10 @@ def test_eip712_legacy(app_client: EthereumClient): assert r == bytes.fromhex("ea66f747173762715751c889fea8722acac3fc35db2c226d37a2e58815398f64") assert s == bytes.fromhex("52d8ba9153de9255da220ffd36762c0b027701a3b5110f0a765f94b16a9dfb55") - def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool, filtering: bool): - print("=====> %s" % (input_file)) - if app_client._client.firmware.device != "nanos": + if app_client._client.firmware.device == "nanos": + pytest.skip("Not supported on LNS") + else: test_path = "%s/%s" % (input_file.parent, "-".join(input_file.stem.split("-")[:-1])) conf_file = "%s.ini" % (test_path) filter_file = None @@ -74,7 +74,7 @@ def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool, }) assert InputData.process_file(app_client, input_file, filter_file) == True - v, r, s = app_client.eip712_sign_new(bip32) + v, r, s = app_client.eip712_sign_new(bip32_path) #print("[signature]") #print("v = %s" % (v.hex())) #print("r = %s" % (r.hex())) @@ -84,6 +84,4 @@ def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool, assert r == bytes.fromhex(config["signature"]["r"]) assert s == bytes.fromhex(config["signature"]["s"]) else: - print("No filter file found, skipping...") - else: - print("Not supported by LNS, skipping...") + pytest.skip("No filter file found") From 51a3fa0f805b334c151298faa30e0adb894122c0 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 9 Mar 2023 16:01:38 +0100 Subject: [PATCH 64/79] Ragger tests can now handle multiple signing keys --- tests/ragger/cal/cal.py | 18 ------------- tests/ragger/eip712/InputData.py | 6 ++--- tests/ragger/keychain.py | 26 +++++++++++++++++++ .../ragger/{cal/key.pem => keychain/cal.pem} | 0 4 files changed, 29 insertions(+), 21 deletions(-) delete mode 100644 tests/ragger/cal/cal.py create mode 100644 tests/ragger/keychain.py rename tests/ragger/{cal/key.pem => keychain/cal.pem} (100%) diff --git a/tests/ragger/cal/cal.py b/tests/ragger/cal/cal.py deleted file mode 100644 index e75fcab..0000000 --- a/tests/ragger/cal/cal.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -import hashlib -from ecdsa.util import sigencode_der -from ecdsa import SigningKey - -_key: SigningKey = None - -def _init_key(): - global _key - with open(os.path.dirname(__file__) + "/key.pem") as pem_file: - _key = SigningKey.from_pem(pem_file.read(), hashlib.sha256) - assert _key != None - -def sign(data: bytes) -> bytes: - global _key - if not _key: - _init_key() - return _key.sign_deterministic(data, sigencode=sigencode_der) diff --git a/tests/ragger/eip712/InputData.py b/tests/ragger/eip712/InputData.py index 40a3882..02a96eb 100644 --- a/tests/ragger/eip712/InputData.py +++ b/tests/ragger/eip712/InputData.py @@ -5,7 +5,7 @@ import sys import re import hashlib from app.client import EthereumClient, EIP712FieldType -from cal import cal +import keychain # global variables app_client: EthereumClient = None @@ -251,7 +251,7 @@ def send_filtering_message_info(display_name: str, filters_count: int): for char in display_name: to_sign.append(ord(char)) - sig = cal.sign(to_sign) + sig = keychain.sign_data(keychain.Key.CAL, to_sign) app_client.eip712_filtering_message_info(display_name, filters_count, sig) # ledgerjs doesn't actually sign anything, and instead uses already pre-computed signatures @@ -269,7 +269,7 @@ def send_filtering_show_field(display_name): to_sign.append(ord(char)) for char in display_name: to_sign.append(ord(char)) - sig = cal.sign(to_sign) + sig = keychain.sign_data(keychain.Key.CAL, to_sign) app_client.eip712_filtering_show_field(display_name, sig) def read_filtering_file(domain, message, filtering_file_path): diff --git a/tests/ragger/keychain.py b/tests/ragger/keychain.py new file mode 100644 index 0000000..194bf49 --- /dev/null +++ b/tests/ragger/keychain.py @@ -0,0 +1,26 @@ +import os +import hashlib +from ecdsa.util import sigencode_der +from ecdsa import SigningKey +from enum import Enum, auto + +# Private key PEM files have to be named the same (lowercase) as their corresponding enum entries +# Example: for an entry in the Enum named DEV, its PEM file must be at keychain/dev.pem +class Key(Enum): + CAL = auto() + +_keys: dict[Key, SigningKey] = dict() + +# Open the corresponding PEM file and load its key in the global dict +def _init_key(key: Key): + global _keys + with open("%s/keychain/%s.pem" % (os.path.dirname(__file__), key.name.lower())) as pem_file: + _keys[key] = SigningKey.from_pem(pem_file.read(), hashlib.sha256) + assert (key in _keys) and (_keys[key] != None) + +# Generate a SECP256K1 signature of the given data with the given key +def sign_data(key: Key, data: bytes) -> bytes: + global _keys + if key not in _keys: + _init_key(key) + return _keys[key].sign_deterministic(data, sigencode=sigencode_der) diff --git a/tests/ragger/cal/key.pem b/tests/ragger/keychain/cal.pem similarity index 100% rename from tests/ragger/cal/key.pem rename to tests/ragger/keychain/cal.pem From e3a6db7c93875435feaa2d76678225c1959befdc Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 9 Mar 2023 16:01:53 +0100 Subject: [PATCH 65/79] Now uses Ragger's bip-32 packing function --- tests/ragger/app/client.py | 8 ++++---- tests/ragger/app/command_builder.py | 19 +++++-------------- tests/ragger/test_eip712.py | 12 +++--------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/tests/ragger/app/client.py b/tests/ragger/app/client.py index 7e25093..6904c87 100644 --- a/tests/ragger/app/client.py +++ b/tests/ragger/app/client.py @@ -91,8 +91,8 @@ class EthereumClient: self._disable_click_until_response() assert self._recv().status == 0x9000 - def eip712_sign_new(self, bip32): - with self._send(self._cmd_builder.eip712_sign_new(bip32)): + def eip712_sign_new(self, bip32_path: str): + with self._send(self._cmd_builder.eip712_sign_new(bip32_path)): time.sleep(0.5) # tight on timing, needed by the CI otherwise might fail sometimes if not self._settings[SettingType.VERBOSE_EIP712].value and \ not self._eip712_filtering: # need to skip the message hash @@ -104,10 +104,10 @@ class EthereumClient: return self._resp_parser.sign(resp.data) def eip712_sign_legacy(self, - bip32, + bip32_path: str, domain_hash: bytes, message_hash: bytes): - with self._send(self._cmd_builder.eip712_sign_legacy(bip32, + with self._send(self._cmd_builder.eip712_sign_legacy(bip32_path, domain_hash, message_hash)): self._client.right_click() # sign typed message screen diff --git a/tests/ragger/app/command_builder.py b/tests/ragger/app/command_builder.py index 04fdc20..9dea245 100644 --- a/tests/ragger/app/command_builder.py +++ b/tests/ragger/app/command_builder.py @@ -1,6 +1,7 @@ from enum import IntEnum, auto from typing import Iterator, Optional from .eip712 import EIP712FieldType +from ragger.bip import pack_derivation_path import struct class InsType(IntEnum): @@ -110,28 +111,18 @@ class EthereumCmdBuilder: data_w_length[:0xff]) data_w_length = data_w_length[0xff:] - def _format_bip32(self, path: list[Optional[int]], data: bytearray) -> bytearray: - data.append(len(path)) - for p in path: - if p == None: - val = 0 - else: - val = (0x8 << 28) | p - data += struct.pack(">I", val) - return data - - def eip712_sign_new(self, bip32_path: list[Optional[int]]) -> bytes: - data = self._format_bip32(bip32_path, bytearray()) + def eip712_sign_new(self, bip32_path: str) -> bytes: + data = pack_derivation_path(bip32_path) return self._serialize(InsType.EIP712_SIGN, P1Type.COMPLETE_SEND, P2Type.NEW_IMPLEM, data) def eip712_sign_legacy(self, - bip32_path: list[Optional[int]], + bip32_path: str, domain_hash: bytes, message_hash: bytes) -> bytes: - data = self._format_bip32(bip32_path, bytearray()) + data = pack_derivation_path(bip32_path) data += domain_hash data += message_hash return self._serialize(InsType.EIP712_SIGN, diff --git a/tests/ragger/test_eip712.py b/tests/ragger/test_eip712.py index 51cc773..29cb843 100644 --- a/tests/ragger/test_eip712.py +++ b/tests/ragger/test_eip712.py @@ -7,13 +7,7 @@ from eip712 import InputData from pathlib import Path from configparser import ConfigParser -bip32_path = [ - 44, - 60, - 0, - None, - None -] +BIP32_PATH = "m/44'/60'/0'/0/0" def input_files() -> List[str]: @@ -38,7 +32,7 @@ def filtering(request) -> bool: def test_eip712_legacy(app_client: EthereumClient): v, r, s = app_client.eip712_sign_legacy( - bip32_path, + BIP32_PATH, bytes.fromhex('6137beb405d9ff777172aa879e33edb34a1460e701802746c5ef96e741710e59'), bytes.fromhex('eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8') ) @@ -74,7 +68,7 @@ def test_eip712_new(app_client: EthereumClient, input_file: Path, verbose: bool, }) assert InputData.process_file(app_client, input_file, filter_file) == True - v, r, s = app_client.eip712_sign_new(bip32_path) + v, r, s = app_client.eip712_sign_new(BIP32_PATH) #print("[signature]") #print("v = %s" % (v.hex())) #print("r = %s" % (r.hex())) From 0336f3fcf03f7d95ca975f19367b5a9d3ed1417a Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 28 Feb 2023 14:30:39 +0100 Subject: [PATCH 66/79] Added new test signature key for domain names --- tests/ragger/keychain.py | 1 + tests/ragger/keychain/domain_name.pem | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 tests/ragger/keychain/domain_name.pem diff --git a/tests/ragger/keychain.py b/tests/ragger/keychain.py index 194bf49..31914a4 100644 --- a/tests/ragger/keychain.py +++ b/tests/ragger/keychain.py @@ -8,6 +8,7 @@ from enum import Enum, auto # Example: for an entry in the Enum named DEV, its PEM file must be at keychain/dev.pem class Key(Enum): CAL = auto() + DOMAIN_NAME = auto() _keys: dict[Key, SigningKey] = dict() diff --git a/tests/ragger/keychain/domain_name.pem b/tests/ragger/keychain/domain_name.pem new file mode 100644 index 0000000..726204e --- /dev/null +++ b/tests/ragger/keychain/domain_name.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIHfwyko1dEHTTQ7es7EUy2ajZo1IRRcEC8/9b+MDOzUaoAcGBSuBBAAK +oUQDQgAEuR++wXPjukpxTgFOvIJ7b4man6f0rHac3ihDF6APT2UPCfCapP9aMXYC +Vf5d/IETKbO1C+mRlPyhFhnmXy7f6g== +-----END EC PRIVATE KEY----- From c2eae8a7a22f30d96c98ae6b6cc4a91363771705 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 10 Mar 2023 16:40:34 +0100 Subject: [PATCH 67/79] Updated Ragger app client for domain names & sign APDUs --- tests/ragger/.gitignore | 2 + tests/ragger/app/client.py | 86 ++++++++++++++++++++++++++++- tests/ragger/app/command_builder.py | 34 +++++++++++- tests/ragger/app/response_parser.py | 4 ++ tests/ragger/app/setting.py | 1 + tests/ragger/app/tlv.py | 25 +++++++++ tests/ragger/conftest.py | 4 +- tests/ragger/requirements.txt | 1 + 8 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 tests/ragger/app/tlv.py diff --git a/tests/ragger/.gitignore b/tests/ragger/.gitignore index 93526df..a3fe09d 100644 --- a/tests/ragger/.gitignore +++ b/tests/ragger/.gitignore @@ -1,2 +1,4 @@ venv/ __pycache__/ +snapshots-tmp/ +elfs/ diff --git a/tests/ragger/app/client.py b/tests/ragger/app/client.py index 6904c87..dad04f6 100644 --- a/tests/ragger/app/client.py +++ b/tests/ragger/app/client.py @@ -2,12 +2,33 @@ from enum import IntEnum, auto from typing import Optional from ragger.backend import BackendInterface from ragger.utils import RAPDU +from ragger.navigator import NavInsID, NavIns, NanoNavigator from .command_builder import EthereumCmdBuilder from .setting import SettingType, SettingImpl from .eip712 import EIP712FieldType from .response_parser import EthereumRespParser +from .tlv import format_tlv import signal import time +from pathlib import Path +import keychain +import rlp + + +ROOT_SCREENSHOT_PATH = Path(__file__).parent.parent +WEI_IN_ETH = 1e+18 + + +class DOMAIN_NAME_TAG(IntEnum): + STRUCTURE_TYPE = 0x01 + STRUCTURE_VERSION = 0x02 + CHALLENGE = 0x12 + SIGNER_KEY_ID = 0x13 + SIGNER_ALGO = 0x14 + SIGNATURE = 0x15 + DOMAIN_NAME = 0x20 + COIN_TYPE = 0x21 + ADDRESS = 0x22 class EthereumClient: @@ -23,15 +44,20 @@ class EthereumClient: ), SettingType.VERBOSE_EIP712: SettingImpl( [ "nanox", "nanosp" ] + ), + SettingType.VERBOSE_ENS: SettingImpl( + [ "nanox", "nanosp" ] ) } _click_delay = 1/4 _eip712_filtering = False - def __init__(self, client: BackendInterface): + def __init__(self, client: BackendInterface, golden_run: bool): self._client = client + self._chain_id = 1 self._cmd_builder = EthereumCmdBuilder() self._resp_parser = EthereumRespParser() + self._nav = NanoNavigator(client, client.firmware, golden_run) signal.signal(signal.SIGALRM, self._click_signal_timeout) for setting in self._settings.values(): setting.value = False @@ -156,3 +182,61 @@ class EthereumClient: with self._send(self._cmd_builder.eip712_filtering_show_field(name, sig)): pass assert self._recv().status == 0x9000 + + def send_fund(self, + bip32_path: str, + nonce: int, + gas_price: int, + gas_limit: int, + to: bytes, + amount: float, + chain_id: int, + screenshot_collection: str = None): + data = list() + data.append(nonce) + data.append(gas_price) + data.append(gas_limit) + data.append(to) + data.append(int(amount * WEI_IN_ETH)) + data.append(bytes()) + data.append(chain_id) + data.append(bytes()) + data.append(bytes()) + + for chunk in self._cmd_builder.sign(bip32_path, rlp.encode(data)): + with self._send(chunk): + nav_ins = NavIns(NavInsID.RIGHT_CLICK) + final_ins = [ NavIns(NavInsID.BOTH_CLICK) ] + target_text = "and send" + if screenshot_collection: + self._nav.navigate_until_text_and_compare(nav_ins, + final_ins, + target_text, + ROOT_SCREENSHOT_PATH, + screenshot_collection) + else: + self._nav.navigate_until_text(nav_ins, + final_ins, + target_text) + + def get_challenge(self) -> int: + with self._send(self._cmd_builder.get_challenge()): + pass + resp = self._recv() + return self._resp_parser.challenge(resp.data) + + def provide_domain_name(self, challenge: int, name: str, addr: bytes): + payload = format_tlv(DOMAIN_NAME_TAG.STRUCTURE_TYPE, 3) # TrustedDomainName + payload += format_tlv(DOMAIN_NAME_TAG.STRUCTURE_VERSION, 1) + payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_KEY_ID, 0) # test key + payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_ALGO, 1) # secp256k1 + payload += format_tlv(DOMAIN_NAME_TAG.CHALLENGE, challenge) + payload += format_tlv(DOMAIN_NAME_TAG.COIN_TYPE, 0x3c) # ETH in slip-44 + payload += format_tlv(DOMAIN_NAME_TAG.DOMAIN_NAME, name) + payload += format_tlv(DOMAIN_NAME_TAG.ADDRESS, addr) + payload += format_tlv(DOMAIN_NAME_TAG.SIGNATURE, + keychain.sign_data(keychain.Key.DOMAIN_NAME, payload)) + + for chunk in self._cmd_builder.provide_domain_name(payload): + with self._send(chunk): + pass diff --git a/tests/ragger/app/command_builder.py b/tests/ragger/app/command_builder.py index 9dea245..aac10d0 100644 --- a/tests/ragger/app/command_builder.py +++ b/tests/ragger/app/command_builder.py @@ -5,14 +5,19 @@ from ragger.bip import pack_derivation_path import struct class InsType(IntEnum): + SIGN = 0x04 EIP712_SEND_STRUCT_DEF = 0x1a EIP712_SEND_STRUCT_IMPL = 0x1c EIP712_SEND_FILTERING = 0x1e EIP712_SIGN = 0x0c + GET_CHALLENGE = 0x20 + PROVIDE_DOMAIN_NAME = 0x22 class P1Type(IntEnum): COMPLETE_SEND = 0x00 PARTIAL_SEND = 0x01 + SIGN_FIRST_CHUNK = 0x00 + SIGN_SUBSQT_CHUNK = 0x80 class P2Type(IntEnum): STRUCT_NAME = 0x00 @@ -31,7 +36,7 @@ class EthereumCmdBuilder: ins: InsType, p1: int, p2: int, - cdata: bytearray = bytearray()) -> bytes: + cdata: bytearray = bytes()) -> bytes: header = bytearray() header.append(self._CLA) @@ -161,3 +166,30 @@ class EthereumCmdBuilder: P1Type.COMPLETE_SEND, P2Type.FILTERING_FIELD_NAME, self._eip712_filtering_send_name(name, sig)) + + def sign(self, bip32_path: str, rlp_data: bytes) -> Iterator[bytes]: + payload = pack_derivation_path(bip32_path) + payload += rlp_data + p1 = P1Type.SIGN_FIRST_CHUNK + while len(payload) > 0: + yield self._serialize(InsType.SIGN, + p1, + 0x00, + payload[:0xff]) + payload = payload[0xff:] + p1 = P1Type.SIGN_SUBSQT_CHUNK + + def get_challenge(self) -> bytes: + return self._serialize(InsType.GET_CHALLENGE, 0x00, 0x00) + + def provide_domain_name(self, tlv_payload: bytes) -> bytes: + payload = struct.pack(">H", len(tlv_payload)) + payload += tlv_payload + p1 = 1 + while len(payload) > 0: + yield self._serialize(InsType.PROVIDE_DOMAIN_NAME, + p1, + 0x00, + payload[:0xff]) + payload = payload[0xff:] + p1 = 0 diff --git a/tests/ragger/app/response_parser.py b/tests/ragger/app/response_parser.py index 9d1c9bd..242f4cf 100644 --- a/tests/ragger/app/response_parser.py +++ b/tests/ragger/app/response_parser.py @@ -12,3 +12,7 @@ class EthereumRespParser: data = data[32:] return v, r, s + + def challenge(self, data: bytes) -> int: + assert len(data) == 4 + return int.from_bytes(data, "big") diff --git a/tests/ragger/app/setting.py b/tests/ragger/app/setting.py index a51f988..7e79da7 100644 --- a/tests/ragger/app/setting.py +++ b/tests/ragger/app/setting.py @@ -6,6 +6,7 @@ class SettingType(IntEnum): DEBUG_DATA = auto() NONCE = auto() VERBOSE_EIP712 = auto() + VERBOSE_ENS = auto() class SettingImpl: devices: List[str] diff --git a/tests/ragger/app/tlv.py b/tests/ragger/app/tlv.py new file mode 100644 index 0000000..2ff4cef --- /dev/null +++ b/tests/ragger/app/tlv.py @@ -0,0 +1,25 @@ +from typing import Any + +def der_encode(value: int) -> bytes: + # max() to have minimum length of 1 + value_bytes = value.to_bytes(max(1, (value.bit_length() + 7) // 8), 'big') + if value >= 0x80: + value_bytes = (0x80 | len(value_bytes)).to_bytes(1, 'big') + value_bytes + return value_bytes + +def format_tlv(tag: int, value: Any) -> bytes: + if isinstance(value, int): + # max() to have minimum length of 1 + value = value.to_bytes(max(1, (value.bit_length() + 7) // 8), 'big') + elif isinstance(value, str): + value = value.encode() + + if not isinstance(value, bytes): + print("Unhandled TLV formatting for type : %s" % (type(value))) + return None + + tlv = bytearray() + tlv += der_encode(tag) + tlv += der_encode(len(value)) + tlv += value + return tlv diff --git a/tests/ragger/conftest.py b/tests/ragger/conftest.py index 35e3fd3..68799b2 100644 --- a/tests/ragger/conftest.py +++ b/tests/ragger/conftest.py @@ -5,8 +5,8 @@ from app.client import EthereumClient # This final fixture will return the properly configured app client, to be used in tests @pytest.fixture -def app_client(backend: BackendInterface) -> EthereumClient: - return EthereumClient(backend) +def app_client(backend: BackendInterface, golden_run: bool) -> EthereumClient: + return EthereumClient(backend, golden_run) # Pull all features from the base ragger conftest using the overridden configuration pytest_plugins = ("ragger.conftest.base_conftest", ) diff --git a/tests/ragger/requirements.txt b/tests/ragger/requirements.txt index b2c4a7b..e408ead 100644 --- a/tests/ragger/requirements.txt +++ b/tests/ragger/requirements.txt @@ -1,3 +1,4 @@ ragger[speculos]>=1.6.0,<1.7.0 pytest ecdsa +simple-rlp From f3d05f839b6e795d77a1caf1c2c518f714da0cc2 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 3 Mar 2023 15:00:52 +0100 Subject: [PATCH 68/79] Ragger domain names tests --- tests/ragger/app/client.py | 10 ++ tests/ragger/snapshots/nanosp | 1 + .../nanox/domain_name_non_mainnet/00000.png | Bin 0 -> 414 bytes .../nanox/domain_name_non_mainnet/00001.png | Bin 0 -> 368 bytes .../nanox/domain_name_non_mainnet/00002.png | Bin 0 -> 585 bytes .../nanox/domain_name_non_mainnet/00003.png | Bin 0 -> 383 bytes .../nanox/domain_name_non_mainnet/00004.png | Bin 0 -> 436 bytes .../nanox/domain_name_non_mainnet/00005.png | Bin 0 -> 472 bytes .../nanox/domain_name_non_mainnet/00006.png | Bin 0 -> 382 bytes .../nanox/domain_name_verbose_False/00000.png | Bin 0 -> 414 bytes .../nanox/domain_name_verbose_False/00001.png | Bin 0 -> 368 bytes .../nanox/domain_name_verbose_False/00002.png | Bin 0 -> 394 bytes .../nanox/domain_name_verbose_False/00003.png | Bin 0 -> 436 bytes .../nanox/domain_name_verbose_False/00004.png | Bin 0 -> 472 bytes .../nanox/domain_name_verbose_False/00005.png | Bin 0 -> 382 bytes .../nanox/domain_name_verbose_True/00000.png | Bin 0 -> 414 bytes .../nanox/domain_name_verbose_True/00001.png | Bin 0 -> 368 bytes .../nanox/domain_name_verbose_True/00002.png | Bin 0 -> 394 bytes .../nanox/domain_name_verbose_True/00003.png | Bin 0 -> 585 bytes .../nanox/domain_name_verbose_True/00004.png | Bin 0 -> 436 bytes .../nanox/domain_name_verbose_True/00005.png | Bin 0 -> 472 bytes .../nanox/domain_name_verbose_True/00006.png | Bin 0 -> 382 bytes .../nanox/domain_name_wrong_addr/00000.png | Bin 0 -> 414 bytes .../nanox/domain_name_wrong_addr/00001.png | Bin 0 -> 368 bytes .../nanox/domain_name_wrong_addr/00002.png | Bin 0 -> 588 bytes .../nanox/domain_name_wrong_addr/00003.png | Bin 0 -> 436 bytes .../nanox/domain_name_wrong_addr/00004.png | Bin 0 -> 472 bytes .../nanox/domain_name_wrong_addr/00005.png | Bin 0 -> 382 bytes tests/ragger/test_domain_name.py | 128 ++++++++++++++++++ 29 files changed, 139 insertions(+) create mode 120000 tests/ragger/snapshots/nanosp create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00000.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00001.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00003.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00005.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_non_mainnet/00006.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00000.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00001.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00002.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00003.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00004.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_False/00005.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00000.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00001.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00002.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00003.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00005.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_verbose_True/00006.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00000.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00001.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00002.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00003.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00004.png create mode 100644 tests/ragger/snapshots/nanox/domain_name_wrong_addr/00005.png create mode 100644 tests/ragger/test_domain_name.py diff --git a/tests/ragger/app/client.py b/tests/ragger/app/client.py index dad04f6..9732c81 100644 --- a/tests/ragger/app/client.py +++ b/tests/ragger/app/client.py @@ -19,6 +19,16 @@ ROOT_SCREENSHOT_PATH = Path(__file__).parent.parent WEI_IN_ETH = 1e+18 +class StatusWord(IntEnum): + OK = 0x9000 + ERROR_NO_INFO = 0x6a00 + INVALID_DATA = 0x6a80 + INSUFFICIENT_MEMORY = 0x6a84 + INVALID_INS = 0x6d00 + INVALID_P1_P2 = 0x6b00 + CONDITION_NOT_SATISFIED = 0x6985 + REF_DATA_NOT_FOUND = 0x6a88 + class DOMAIN_NAME_TAG(IntEnum): STRUCTURE_TYPE = 0x01 STRUCTURE_VERSION = 0x02 diff --git a/tests/ragger/snapshots/nanosp b/tests/ragger/snapshots/nanosp new file mode 120000 index 0000000..da13a6a --- /dev/null +++ b/tests/ragger/snapshots/nanosp @@ -0,0 +1 @@ +nanox/ \ No newline at end of file diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00000.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..487ea10fcfeb2f3e6b79239459672251d49addd7 GIT binary patch literal 414 zcmV;P0b%}$P)vpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*fn&`6tH9gqo;^MN#J@G-NZG(W*iG}t#e1Fb- zKV8KTt0a`{lX$B4$~o~B?x*6e)~<@4Iz4h@Jmb~b5&vc;g`2H9{psfXevRGF%X%)F z{W^G1#bn40-weR!F*3L+ubT($m0wc}!uNKw0-sV5H z;CF7g9MJJ=+rKjGEBl+3>A2QyMfKUZ+;mUbm;0)$KRWh$yq((D^ZhGdwuD|?hi~Df z@|&)@8Hr8?_0j7y!?>j6!~H8~TztJ`f#FwsF1bzDbkz>zesQ*DR9hWnx9on|hmN^& zyJ|dM`zN>MP3ZiWI3+;%Z?hr$v=dI#e(*&r?E!in863#FcU<{Z?XiYs!60EzS3j3^ HP6 literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..6a5a9d64a202a062cb8bb576a84ba653e232345c GIT binary patch literal 585 zcmV-P0=E5$P)Fdu z__dw@MOS{tr(OJ6PoPLP9@*UxLb&ZA1lC4xvBG!qQ&wg@Ymi`OA5aK9q=YC=*Fi;`yDjPzxkl=%^cJKW8Rm7R%x^V000000G!J| X8HZ1szRqx300000NkvXXu0mjfUbPWB literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00003.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..93112b3ab44e4f2fda4db252509cc196086ddfe4 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|@9fba4!+nDh2#BHtkep0-4j zdo91^SC)S~p49BHJ!?zqFT4F}f!k|X&9XH?T6cI~>vT=AUa|Gn>9-c2n3T?2l%BQS zJHI32Y~4xS-%MQ{J(o9}-F0o1{_c;TY$hImeCf=`w=R#5oR8(wUdQ0;viM5LE9Xi* zx5AL5KPO65B8nKxj6S`wygYT|{7u*L_w1ovS;^lz1}|X7OvSf z+x3+G0T1WQ@`Ys={_`GvYk(e{b*WT#)t^JoP z;)!4C*^OBcSXHTQ3DBky85}Sb4q9e0CCc*{Qv*} literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..70c1b9a68f5fb1ee090966199cb58a891b0a5ad4 GIT binary patch literal 436 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_8Fba4!+nDh2V;G|{+o`%F- zmuDCJS1z1hTaXeVq>#&b2QSTI5qI}IeE+uQ$d($HH~rmjmfzpG^!&>@vHo;H|A#$&J>60(rv&w- z{Y$*re=CCT)rWkxbu*ft7z>`O-oI7u=d4xjo3yuXwAx+AyG_?&s?U?T(oz$vN~hG^ zITd^LMfdfDVy;c?KbE!zHs9!cv+j?u-i)SGA(L0?zp6X2s;;m5>ao50i9jz_e_Gr2 zjaxr8`Rh@Y?ag!bLo2gxTv~bJ)XKV#_qKdJdgcDJ@>9jrf~PT`jyPOzcvQ5zaQmZw zsyQ_iV&5BC&*W(?<|>M3c>Lz-s+s2Awug&us=u4vloD}$y3^rY@dWQRp`~22>^5u8 z-Wjt=zq~iKakEWo=0=}0$4N$E@I8h8IZK)78&qol`;+03*-H(EtDd literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00005.png b/tests/ragger/snapshots/nanox/domain_name_non_mainnet/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*fn&`6tH9gqo;^MN#J@G-NZG(W*iG}t#e1Fb- zKV8KTt0a`{lX$B4$~o~B?x*6e)~<@4Iz4h@Jmb~b5&vc;g`2H9{psfXevRGF%X%)F z{W^G1#bn40-weR!F*3L+ubT($m0wc}!uNKw0-sV5H z;CF7g9MJJ=+rKjGEBl+3>A2QyMfKUZ+;mUbm;0)$KRWh$yq((D^ZhGdwuD|?hi~Df z@|&)@8Hr8?_0j7y!?>j6!~H8~TztJ`f#FwsF1bzDbkz>zesQ*DR9hWnx9on|hmN^& zyJ|dM`zN>MP3ZiWI3+;%Z?hr$v=dI#e(*&r?E!in863#FcU<{Z?XiYs!60EzS3j3^ HP6 literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00002.png b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..6af0ec54b2a0718d258e534bf29b059567fc8a37 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|OeC49QR=-2B7dxJ{W zgs*+Kp>I)S?nComvp*b*(d&*o`esS|_Wz0OWf4q4#T*CSRgb;eS9841(&A*@>I#&b2QSTI5qI}IeE+uQ$d($HH~rmjmfzpG^!&>@vHo;H|A#$&J>60(rv&w- z{Y$*re=CCT)rWkxbu*ft7z>`O-oI7u=d4xjo3yuXwAx+AyG_?&s?U?T(oz$vN~hG^ zITd^LMfdfDVy;c?KbE!zHs9!cv+j?u-i)SGA(L0?zp6X2s;;m5>ao50i9jz_e_Gr2 zjaxr8`Rh@Y?ag!bLo2gxTv~bJ)XKV#_qKdJdgcDJ@>9jrf~PT`jyPOzcvQ5zaQmZw zsyQ_iV&5BC&*W(?<|>M3c>Lz-s+s2Awug&us=u4vloD}$y3^rY@dWQRp`~22>^5u8 z-Wjt=zq~iKakEWo=0=}0$4N$E@I8h8IZK)78&qol`;+03*-H(EtDd literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_False/00004.png b/tests/ragger/snapshots/nanox/domain_name_verbose_False/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*fn&`6tH9gqo;^MN#J@G-NZG(W*iG}t#e1Fb- zKV8KTt0a`{lX$B4$~o~B?x*6e)~<@4Iz4h@Jmb~b5&vc;g`2H9{psfXevRGF%X%)F z{W^G1#bn40-weR!F*3L+ubT($m0wc}!uNKw0-sV5H z;CF7g9MJJ=+rKjGEBl+3>A2QyMfKUZ+;mUbm;0)$KRWh$yq((D^ZhGdwuD|?hi~Df z@|&)@8Hr8?_0j7y!?>j6!~H8~TztJ`f#FwsF1bzDbkz>zesQ*DR9hWnx9on|hmN^& zyJ|dM`zN>MP3ZiWI3+;%Z?hr$v=dI#e(*&r?E!in863#FcU<{Z?XiYs!60EzS3j3^ HP6 literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00002.png b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..6af0ec54b2a0718d258e534bf29b059567fc8a37 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|OeC49QR=-2B7dxJ{W zgs*+Kp>I)S?nComvp*b*(d&*o`esS|_Wz0OWf4q4#T*CSRgb;eS9841(&A*@>IFdu z__dw@MOS{tr(OJ6PoPLP9@*UxLb&ZA1lC4xvBG!qQ&wg@Ymi`OA5aK9q=YC=*Fi;`yDjPzxkl=%^cJKW8Rm7R%x^V000000G!J| X8HZ1szRqx300000NkvXXu0mjfUbPWB literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..70c1b9a68f5fb1ee090966199cb58a891b0a5ad4 GIT binary patch literal 436 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!2~2@x4h6`U|_8Fba4!+nDh2V;G|{+o`%F- zmuDCJS1z1hTaXeVq>#&b2QSTI5qI}IeE+uQ$d($HH~rmjmfzpG^!&>@vHo;H|A#$&J>60(rv&w- z{Y$*re=CCT)rWkxbu*ft7z>`O-oI7u=d4xjo3yuXwAx+AyG_?&s?U?T(oz$vN~hG^ zITd^LMfdfDVy;c?KbE!zHs9!cv+j?u-i)SGA(L0?zp6X2s;;m5>ao50i9jz_e_Gr2 zjaxr8`Rh@Y?ag!bLo2gxTv~bJ)XKV#_qKdJdgcDJ@>9jrf~PT`jyPOzcvQ5zaQmZw zsyQ_iV&5BC&*W(?<|>M3c>Lz-s+s2Awug&us=u4vloD}$y3^rY@dWQRp`~22>^5u8 z-Wjt=zq~iKakEWo=0=}0$4N$E@I8h8IZK)78&qol`;+03*-H(EtDd literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_verbose_True/00005.png b/tests/ragger/snapshots/nanox/domain_name_verbose_True/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~ovpO}&+|8}fC)JNq`>?#dJ%s{^>GN_4usXQirk{^@^BA?p!El9&T9q~zMsh2=YdLB`_ONiP zKy6XlUGFZ>Cn7mP3u*fn&`6tH9gqo;^MN#J@G-NZG(W*iG}t#e1Fb- zKV8KTt0a`{lX$B4$~o~B?x*6e)~<@4Iz4h@Jmb~b5&vc;g`2H9{psfXevRGF%X%)F z{W^G1#bn40-weR!F*3L+ubT($m0wc}!uNKw0-sV5H z;CF7g9MJJ=+rKjGEBl+3>A2QyMfKUZ+;mUbm;0)$KRWh$yq((D^ZhGdwuD|?hi~Df z@|&)@8Hr8?_0j7y!?>j6!~H8~TztJ`f#FwsF1bzDbkz>zesQ*DR9hWnx9on|hmN^& zyJ|dM`zN>MP3ZiWI3+;%Z?hr$v=dI#e(*&r?E!in863#FcU<{Z?XiYs!60EzS3j3^ HP6 literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00002.png b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..639e4214e2503dea60de36382cca415eba0612ef GIT binary patch literal 588 zcmV-S0<-;zP)O0W zchFsT)i}^Q!1`wvO&TVU-WL7u7Lerb2v~T-6W-5}9LuNEJd4tofu>?$4t}ALa z+pgs{)78Thz#Qt%begfRUjy1``q}X~sO`Sn^ZL71NxS8Y)xw+}-aS2NY8me@&zh zE2f7M0L8TSt3&St(g74xiI*wJ8#@%!A`9LJEKw*wqL=~z0001hgyknnlA+h%_bs4G zSMR*9(K^A!XR1TIOrw2X0$zs41RPV`Jm4+?pNc+tOTgEnPY&hiC9>iwZ503j0001h ack&On!Zml6z*33;0000#&b2QSTI5qI}IeE+uQ$d($HH~rmjmfzpG^!&>@vHo;H|A#$&J>60(rv&w- z{Y$*re=CCT)rWkxbu*ft7z>`O-oI7u=d4xjo3yuXwAx+AyG_?&s?U?T(oz$vN~hG^ zITd^LMfdfDVy;c?KbE!zHs9!cv+j?u-i)SGA(L0?zp6X2s;;m5>ao50i9jz_e_Gr2 zjaxr8`Rh@Y?ag!bLo2gxTv~bJ)XKV#_qKdJdgcDJ@>9jrf~PT`jyPOzcvQ5zaQmZw zsyQ_iV&5BC&*W(?<|>M3c>Lz-s+s2Awug&us=u4vloD}$y3^rY@dWQRp`~22>^5u8 z-Wjt=zq~iKakEWo=0=}0$4N$E@I8h8IZK)78&qol`;+03*-H(EtDd literal 0 HcmV?d00001 diff --git a/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00004.png b/tests/ragger/snapshots/nanox/domain_name_wrong_addr/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..570ce28d53e82ac396ba25c370110058f3a638f9 GIT binary patch literal 472 zcmV;}0Vn>6P)Nkl`l1;k+@4An6g^M6kcbtxu@7*hfO000000DuchDWw$aQJnB& zJ%BsK3VrpQ1hnYqoNY&PO0WdV>i`7cs)e_@w@x()p@w=B24`klR6(CLpxqtlZO|2 zIWjpO-F~*EHtLqUMt)Wc_@bMv^h#{CUFW0M(vJ1P=5N1GhWcHM(-Xu*&bc@D4_o$^ z7Y|pL)I@*DzttR=&yLH#^{|TW)8Sp0qphw%epiuSUG#WHS~ht|j~;`U4>BXmdi9@& zuz>%00000G5i7^TsbXePb2LB O0000sAjk5Y(@*V#~rbuHu`7A_H&AxgwHf8y4cdKvg$JbB4n%ez%sZ31aBYd&Oo@(7)_WJ(Znl2o8^PD` zFE`_Y-IS+Kdq0Q2-7r_C=}F(5ev`U`H~)QH|9$1FHE$YjoVax+e0xei%S`SAGlOm! zp7{T3NA-mVOYb&rdU8MdyIHo@@7cE*uj@I+Zu{2i)KMSV-E~o bool: + return request.param + +def common(app_client: EthereumClient) -> int: + if app_client._client.firmware.device == "nanos": + pytest.skip("Not supported on LNS") + return app_client.get_challenge() + + +def test_send_fund(app_client: EthereumClient, verbose: bool): + challenge = common(app_client) + + if verbose: + app_client.settings_set({ + SettingType.VERBOSE_ENS: True + }) + + app_client.provide_domain_name(challenge, NAME, ADDR) + + app_client.send_fund(BIP32_PATH, + NONCE, + GAS_PRICE, + GAS_LIMIT, + ADDR, + AMOUNT, + CHAIN_ID, + "domain_name_verbose_" + str(verbose)) + +def test_send_fund_wrong_challenge(app_client: EthereumClient): + caught = False + challenge = common(app_client) + + try: + app_client.provide_domain_name(~challenge & 0xffffffff, NAME, ADDR) + except ExceptionRAPDU as e: + assert e.status == StatusWord.INVALID_DATA + else: + assert False # An exception should have been raised + +def test_send_fund_wrong_addr(app_client: EthereumClient): + challenge = common(app_client) + + app_client.provide_domain_name(challenge, NAME, ADDR) + + addr = bytearray(ADDR) + addr.reverse() + + app_client.send_fund(BIP32_PATH, + NONCE, + GAS_PRICE, + GAS_LIMIT, + addr, + AMOUNT, + CHAIN_ID, + "domain_name_wrong_addr") + +def test_send_fund_non_mainnet(app_client: EthereumClient): + challenge = common(app_client) + + app_client.provide_domain_name(challenge, NAME, ADDR) + + app_client.send_fund(BIP32_PATH, + NONCE, + GAS_PRICE, + GAS_LIMIT, + ADDR, + AMOUNT, + 5, + "domain_name_non_mainnet") + +def test_send_fund_domain_too_long(app_client: EthereumClient): + challenge = common(app_client) + + try: + app_client.provide_domain_name(challenge, "ledger" + "0"*25 + ".eth", ADDR) + except ExceptionRAPDU as e: + assert e.status == StatusWord.INVALID_DATA + else: + assert False # An exception should have been raised + +def test_send_fund_domain_invalid_character(app_client: EthereumClient): + challenge = common(app_client) + + try: + app_client.provide_domain_name(challenge, "l\xe8dger.eth", ADDR) + except ExceptionRAPDU as e: + assert e.status == StatusWord.INVALID_DATA + else: + assert False # An exception should have been raised + +def test_send_fund_uppercase(app_client: EthereumClient): + challenge = common(app_client) + + try: + app_client.provide_domain_name(challenge, NAME.upper(), ADDR) + except ExceptionRAPDU as e: + assert e.status == StatusWord.INVALID_DATA + else: + assert False # An exception should have been raised + +def test_send_fund_domain_non_ens(app_client: EthereumClient): + challenge = common(app_client) + + try: + app_client.provide_domain_name(challenge, "ledger.hte", ADDR) + except ExceptionRAPDU as e: + assert e.status == StatusWord.INVALID_DATA + else: + assert False # An exception should have been raised From 7545bcdeb6eb7355e4edb65cf7d4d5d876135a52 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 28 Feb 2023 17:56:08 +0100 Subject: [PATCH 69/79] Disabled Zemu LNX tests since the framework broke with the latest SDK --- tests/zemu/src/{erc1155.test.js => erc1155.notest.js} | 0 tests/zemu/src/{erc721.test.js => erc721.notest.js} | 0 tests/zemu/src/test.fixture.js | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/zemu/src/{erc1155.test.js => erc1155.notest.js} (100%) rename tests/zemu/src/{erc721.test.js => erc721.notest.js} (100%) diff --git a/tests/zemu/src/erc1155.test.js b/tests/zemu/src/erc1155.notest.js similarity index 100% rename from tests/zemu/src/erc1155.test.js rename to tests/zemu/src/erc1155.notest.js diff --git a/tests/zemu/src/erc721.test.js b/tests/zemu/src/erc721.notest.js similarity index 100% rename from tests/zemu/src/erc721.test.js rename to tests/zemu/src/erc721.notest.js diff --git a/tests/zemu/src/test.fixture.js b/tests/zemu/src/test.fixture.js index c29dbad..1a2f898 100644 --- a/tests/zemu/src/test.fixture.js +++ b/tests/zemu/src/test.fixture.js @@ -26,8 +26,8 @@ const NANOS_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanos.elf"); const NANOX_CLONE_ELF_PATH = Resolve("elfs/ethereum_classic_nanox.elf"); const nano_models: DeviceModel[] = [ - { name: 'nanos', letter: 'S', path: NANOS_ELF_PATH, clone_path: NANOS_CLONE_ELF_PATH }, - { name: 'nanox', letter: 'X', path: NANOX_ELF_PATH, clone_path: NANOX_CLONE_ELF_PATH } + { name: 'nanos', letter: 'S', path: NANOS_ELF_PATH, clone_path: NANOS_CLONE_ELF_PATH }/*, + { name: 'nanox', letter: 'X', path: NANOX_ELF_PATH, clone_path: NANOX_CLONE_ELF_PATH }*/ ]; const TIMEOUT = 1000000; From 400473c06eb0026b75269700c1351912fee013a4 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 28 Feb 2023 17:50:27 +0100 Subject: [PATCH 70/79] Fix Zemu tests --- .../nanox_enable_blind_signing/00007.png | Bin 758 -> 705 bytes .../nanox_enable_blind_signing/00008.png | Bin 305 -> 758 bytes .../nanox_enable_blind_signing/00009.png | Bin 382 -> 305 bytes tests/zemu/src/blind_compound_deposit.test.js | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/zemu/snapshots/nanox_enable_blind_signing/00007.png b/tests/zemu/snapshots/nanox_enable_blind_signing/00007.png index 5b3eed92be2ac662655d726f7880834b803bd82c..706ef7d8d2ee24a20c477ab5ec56db1ac8e715b7 100644 GIT binary patch delta 681 zcmV;a0#^O@1;GW7B!7rWL_t(|ob8+4a;+c?h3T2TiSPeNzRS6Ax`&1&gqQ%<^<8w7 zjUj|zm$VcB000000H*VmXZk$PQp#~0Fz~XFPhzwvUUIf0002MMw~x~%4`bFn$45`XQtmJD0aidpq7J1>#M_ODcs&%TtXxNXUQlduus`0_PGV71vHLPnc3 z_}C102%ds!c`_VD;&<3-&0ZJn#Hi=L$?Oj@ELXFA>c3rN;*MC8>EsF-VCE5 z>SnBCNnLY`7qOPTbgoj$K8JJl!y1m0BSm=GF-o3_4?~W1&!l`@(rYxY>*zA!s1n)L zAT3Y%d@vduebC6Q5fICe3X;89aM<^$I36`LM3p4M^{B)+VWbaL(=CxMTZE+(pO4-L zJN);I0Dq~BA*ItOF?J=-oB1ss4rShO|3=Y20ltk*-vi!5`tfuY{bd3G0Ki)~e^aO1 zEf^Es+49)pKjqm&Q7>7Xw`c&CR(*7fk-8N6cDg#K6fC#k>YM12*mnffbUzPtACLAZ zj0ZG;bXe0K)}5D=$4C)R7fL0z7y)-ab4qz?gCgYDzuJ}n0000009g4CX+6?ysc4bO P00000NkvXXu0mjfG5|?0 delta 734 zcmV<40wMju1@;AyB!9h0L_t(|ob8)ka>F1DglVTY;r>VRUHagThky{0wNRYw_s~fR z2$1+)J1G%D2qAI8h;?eZs==8<^9%vWhyu@ zd$q#}&46=Im%~-L8gwPlqVHgq~JW~!-ZJ%c)L+wcFshL{m33*Sy;+Ri5(Dx5JCtc z#Khu5Sb6L--hYaFc7ko#<@C9-9m=VHS!3XJ!EVCst*WOS3`I~;YCjVz!ETtLXZ9*P zR9h2HR+)mbAc&gRy+kp^TjPzY7f7u;K9E86aK=h4PP+(5F%BZnLM+7X=zS>{u^`9* zY`s=G8TJJggE{~aqvGaSQEtv+wqXWK8_s7~aXVsJaep(no7M6MCEU239hlvh%HVhT z#XGGb+fp6S|K1CVd%t(;e&CO_x|%Uqz`)6j!Bk-Gy{Abrx-GD`BHoe( zLbvZGEDB`0^qADUOp>lMJ-ww>SdZ7Y=fuygk@jD)!FG97DT2f$9C`&#y9g@gZ~rP5 zP%^EtkAFH~G0qrv)RlWNGirwgKzvAI$$z^dZ^1Y-Hazh2fZOkGUN2gEJ6Y}oK$UnI zjv1gkSJ~D?kE~pUDrM9ql-`h6XKlhR798N-gB>49eiXBQpy6VRIZFs3WIe|#WxCyh zG4Xb`d2F!>i%Q&w?8#dMK*Xi98ZUjlw?99co>x>k)EB*)rJn!4*mnk$9L=xhy~WWj zg7JU=v^uL-5Z!q@d5jbR|Bd`6Y%v3j&o7l#NZEv274uzVNeCf?5JHHRUz4p6rvVzb Q3jhEB07*qoM6N<$g7(2&@c;k- diff --git a/tests/zemu/snapshots/nanox_enable_blind_signing/00008.png b/tests/zemu/snapshots/nanox_enable_blind_signing/00008.png index 61861f2998e3ad1281d45331147c852277579e50..5b3eed92be2ac662655d726f7880834b803bd82c 100644 GIT binary patch delta 735 zcmV<50wDdd0`>)vBYy(DNkla(jLmecY{+pzLmu>neks?ArtbM~_!)3{xqliU!*1wnMdkh0eq|~+ zFnhJb3C)0WP?y72ad+wuoSqX~r|b5I6}4rR88&n}WG9=l1SQ-g?KwSSAJR6|3YqTW!whh3N#S6`V;S88DmSIVU&Do1^mw~bUv|z!i~YzRU|CqoNr@d0gb+dq zA;iSuLs)t2Gk@NSdv=0t*yZ%OvK`8)e_3PTb-`}J?X9Y(91KNJQEEREE5UA*S$nB#arWzsuxJDJ3f#>^>D^YEl#@#NHGo~&q6H3?dW|e7qKA7 z0BpThIvMr_6@xke5u@VfSy67zVzyxhOB>E-SaCaIS$}aex0}`S2PNFNogJ9nm&)LG z`Ncb}A=^?N(Er{GihI9z>VF~&`XV^|(d)*u=(?IQSir!^jKNf3?!Bi;F}f|Vw<6w> z1wyy)CM*hMy7ZXTyG)X`E?5S->>umr`!g3pnj~ z@}#RI%0wNk3rO^NCYV2KiGR|ckn|%-Kb{Wa=^&mC z_%B2M6|vfmrw;zF_l|$Bkl;>u{1C5rL@(g9ep~e29A6){#WW*mn_!>pHsveh>zC4u zpcZI-YcKeCavL`NlA?fK`=*ba=_$zy*mY3GYWEB%K>^!eg6-o#{q^0rNA3Us00000 d0Dwt70pO5tV-R0y=BNMw002ovPDHLkV1oAbg3$l~ diff --git a/tests/zemu/snapshots/nanox_enable_blind_signing/00009.png b/tests/zemu/snapshots/nanox_enable_blind_signing/00009.png index a58590b988714545e7960f7f400f360ffc5de41f..61861f2998e3ad1281d45331147c852277579e50 100644 GIT binary patch delta 279 zcmV+y0qFkz0`E?5S->>umr`!g3pnj~ z@}#RI%0wNk3rO^NCYV2KiGR|ckn|%-Kb{Wa=^&mC z_%B2M6|vfmrw;zF_l|$Bkl;>u{1C5rL@(g9ep~e29A6){#WW*mn_!>pHsveh>zC4u zpcZI-YcKeCavL`NlA?fK`=*ba=_$zy*mY3GYWEB%K>^!eg6-o#{q^0rNA3Us00000 d0Dwt70pO5tV-R0y=BNMw002ovPDHLkV1oQ>g4O^4 delta 356 zcmV-q0h|7@0{#M!BYy!!NklIM-mZ9&c>_-hT!sn4N;8=O_gAL6Mjp zfMU+wSsDO|%usAO&O-Ssu~wLfU%a)of4+npwWjGzuga<{K6K&zQ5~Arn0E_+D~?Wa zz#9g@S&PAL%w?gibS9Y?h_XAqqCK-a>`hn>fc|Z0&_0yq<&E=K?XaC3g5-{zk2HS4 z+5Yjb_o?cv>|KD^$lA { let clicks; - // LNS does not have an EIP712 setting + // LNS does not have EIP712 & ENS settings if (model.letter === 'S') clicks = 3; - else clicks = 4; + else clicks = 5; // Enable blind-signing await sim.navigateAndCompareSnapshots('.', model.name + '_enable_blind_signing', [-2, 0, 0, clicks, 0]); From 8decdc9390d2f0ae9b69db5286f2d557cdf7c19d Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 3 Mar 2023 14:43:47 +0100 Subject: [PATCH 71/79] Updated changelog file --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 950ee93..b95816f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2022-02-09 +## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2023-XX-XX ### Added @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - (network) Velas EVM - (network) Boba Network - (network) Energi +- Domain names support (LNX / LNS+) ### Changed From 504747aba294ed0264f4bbecd4779f90e8ecc3d2 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 21 Apr 2023 14:09:44 +0200 Subject: [PATCH 72/79] Improve finalizeParsing() checking in swap context Simplify code in logic_signTx.c --- src/eth_plugin_handler.h | 2 - src/eth_plugin_ui.c | 11 -- src/shared_context.h | 4 +- src_features/signTx/logic_signTx.c | 194 ++++++++++++++++------------- 4 files changed, 111 insertions(+), 100 deletions(-) delete mode 100644 src/eth_plugin_ui.c diff --git a/src/eth_plugin_handler.h b/src/eth_plugin_handler.h index 28b13fb..acd982d 100644 --- a/src/eth_plugin_handler.h +++ b/src/eth_plugin_handler.h @@ -31,6 +31,4 @@ eth_plugin_result_t eth_plugin_perform_init(uint8_t *contractAddress, // NULL for cached address, or base contract address eth_plugin_result_t eth_plugin_call(int method, void *parameter); -void plugin_ui_start(void); - #endif // _ETH_PLUGIN_HANDLER_H_ diff --git a/src/eth_plugin_ui.c b/src/eth_plugin_ui.c deleted file mode 100644 index d4bdc15..0000000 --- a/src/eth_plugin_ui.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "shared_context.h" -#include "eth_plugin_handler.h" -#include "ux.h" -#include "feature_signTx.h" - -void plugin_ui_start() { - dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; - dataContext.tokenContext.pluginUiCurrentItem = 0; - - ux_approve_tx(true); -} diff --git a/src/shared_context.h b/src/shared_context.h index 0480a59..ce907dd 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -175,7 +175,7 @@ typedef enum { #define NETWORK_STRING_MAX_SIZE 16 -typedef struct txStringProperties_t { +typedef struct txStringProperties_s { char fullAddress[43]; char fullAmount[79]; // 2^256 is 78 digits long char maxFee[50]; @@ -190,7 +190,7 @@ typedef struct txStringProperties_t { #endif #define SHARED_CTX_FIELD_2_SIZE 40 -typedef struct strDataTmp_t { +typedef struct strDataTmp_s { char tmp[SHARED_CTX_FIELD_1_SIZE]; char tmp2[SHARED_CTX_FIELD_2_SIZE]; } strDataTmp_t; diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index c22214c..9530d27 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -170,26 +170,6 @@ customStatus_e customProcessor(txContext_t *context) { return CUSTOM_NOT_HANDLED; } -void to_uppercase(char *str, unsigned char size) { - for (unsigned char i = 0; i < size && str[i] != 0; i++) { - str[i] = str[i] >= 'a' ? str[i] - ('a' - 'A') : str[i]; - } -} - -void compareOrCopy(char *preapproved_string, size_t size, char *parsed_string, bool silent_mode) { - if (silent_mode) { - /* ETH address are not fundamentally case sensitive but might - have some for checksum purpose, so let's get rid of these diffs */ - to_uppercase(preapproved_string, strlen(preapproved_string)); - to_uppercase(parsed_string, strlen(parsed_string)); - if (memcmp(preapproved_string, parsed_string, strlen(preapproved_string))) { - THROW(ERR_SILENT_MODE_CHECK_FAILED); - } - } else { - strlcpy(preapproved_string, parsed_string, size); - } -} - void reportFinalizeError(bool direct) { reset_app_context(); if (direct) { @@ -200,20 +180,20 @@ void reportFinalizeError(bool direct) { } } -// Convert `BEgasPrice` and `BEgasLimit` to Uint256 and then stores the multiplication of both in -// `output`. -static void computeFees(txInt256_t *BEgasPrice, txInt256_t *BEgasLimit, uint256_t *output) { - uint256_t gasPrice = {0}; - uint256_t gasLimit = {0}; - - PRINTF("Gas price %.*H\n", BEgasPrice->length, BEgasPrice->value); - PRINTF("Gas limit %.*H\n", BEgasLimit->length, BEgasLimit->value); - convertUint256BE(BEgasPrice->value, BEgasPrice->length, &gasPrice); - convertUint256BE(BEgasLimit->value, BEgasLimit->length, &gasLimit); - mul256(&gasPrice, &gasLimit, output); +static void address_to_string(uint8_t *in, + size_t in_len, + char *out, + size_t out_len, + cx_sha3_t *sha3, + uint64_t chainId) { + if (in_len != 0) { + getEthDisplayableAddress(in, out, out_len, sha3, chainId); + } else { + strlcpy(out, "Contract", out_len); + } } -static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) { +static void raw_fee_to_string(uint256_t *rawFee, char *displayBuffer, uint32_t displayBufferSize) { const char *feeTicker = get_network_ticker(); uint8_t tickerOffset = 0; uint32_t i; @@ -255,32 +235,40 @@ static void feesToString(uint256_t *rawFee, char *displayBuffer, uint32_t displa } // Compute the fees, transform it to a string, prepend a ticker to it and copy everything to -// `displayBuffer`. -void prepareAndCopyFees(txInt256_t *BEGasPrice, - txInt256_t *BEGasLimit, - char *displayBuffer, - uint32_t displayBufferSize) { +// `displayBuffer` output +static void max_transaction_fee_to_string(const txInt256_t *BEGasPrice, + const txInt256_t *BEGasLimit, + char *displayBuffer, + uint32_t displayBufferSize) { + // Use temporary variables to convert values to uint256_t + uint256_t gasPrice = {0}; + uint256_t gasLimit = {0}; + // Use temporary variable to store the result of the operation in uint256_t uint256_t rawFee = {0}; - computeFees(BEGasPrice, BEGasLimit, &rawFee); - feesToString(&rawFee, displayBuffer, displayBufferSize); + + PRINTF("Gas price %.*H\n", BEGasPrice->length, BEGasPrice->value); + PRINTF("Gas limit %.*H\n", BEGasLimit->length, BEGasLimit->value); + convertUint256BE(BEGasPrice->value, BEGasPrice->length, &gasPrice); + convertUint256BE(BEGasLimit->value, BEGasLimit->length, &gasLimit); + mul256(&gasPrice, &gasLimit, &rawFee); + raw_fee_to_string(&rawFee, displayBuffer, displayBufferSize); } -void prepareFeeDisplay() { - prepareAndCopyFees(&tmpContent.txContent.gasprice, - &tmpContent.txContent.startgas, - strings.common.maxFee, - sizeof(strings.common.maxFee)); +static void nonce_to_string(const txInt256_t *nonce, char *out, size_t out_size) { + uint256_t nonce_uint256; + convertUint256BE(nonce->value, nonce->length, &nonce_uint256); + tostring256(&nonce_uint256, 10, out, out_size); } -void prepareNetworkDisplay() { +static void get_network_as_string(char *out, size_t out_size) { const char *name = get_network_name(); if (name == NULL) { // No network name found so simply copy the chain ID as the network name. uint64_t chain_id = get_chain_id(); - u64_to_string(chain_id, strings.common.network_name, sizeof(strings.common.network_name)); + u64_to_string(chain_id, out, out_size); } else { // Network name found, simply copy it. - strlcpy(strings.common.network_name, name, sizeof(strings.common.network_name)); + strlcpy(out, name, out_size); } } @@ -310,7 +298,7 @@ void finalizeParsing(bool direct) { uint8_t decimals = WEI_TO_ETHER; const char *ticker = get_network_ticker(); ethPluginFinalize_t pluginFinalize; - bool genericUI = true; + bool use_standard_UI = true; // Verify the chain if (chainConfig->chainId != ETHEREUM_MAINNET_CHAINID) { @@ -335,7 +323,6 @@ void finalizeParsing(bool direct) { // Finalize the plugin handling if (dataContext.tokenContext.pluginStatus >= ETH_PLUGIN_RESULT_SUCCESSFUL) { - genericUI = false; eth_plugin_prepare_finalize(&pluginFinalize); uint8_t msg_sender[ADDRESS_LENGTH] = {0}; @@ -381,6 +368,8 @@ void finalizeParsing(bool direct) { // Handle the right interface switch (pluginFinalize.uiType) { case ETH_UI_TYPE_GENERIC: + // Use the dedicated ETH plugin UI + use_standard_UI = false; tmpContent.txContent.dataPresent = false; // Add the number of screens + the number of additional screens to get the total // number of screens needed. @@ -388,7 +377,8 @@ void finalizeParsing(bool direct) { pluginFinalize.numScreens + pluginProvideInfo.additionalScreens; break; case ETH_UI_TYPE_AMOUNT_ADDRESS: - genericUI = true; + // Use the standard ETH UI as this plugin uses the amount/address UI + use_standard_UI = true; tmpContent.txContent.dataPresent = false; if ((pluginFinalize.amount == NULL) || (pluginFinalize.address == NULL)) { PRINTF("Incorrect amount/address set by plugin\n"); @@ -413,11 +403,14 @@ void finalizeParsing(bool direct) { return; } } - } else { - genericUI = true; } } + // User has just validated a swap but ETH received apdus about a non standard plugin / contract + if (called_from_swap && !use_standard_UI) { + THROW(ERR_SILENT_MODE_CHECK_FAILED); + } + if (tmpContent.txContent.dataPresent && !N_storage.dataAllowed) { reportFinalizeError(direct); ui_warning_contract_data(); @@ -426,66 +419,97 @@ void finalizeParsing(bool direct) { } } - // Prepare destination address to display - if (genericUI) { - if (tmpContent.txContent.destinationLength != 0) { - getEthDisplayableAddress(tmpContent.txContent.destination, - displayBuffer, - sizeof(displayBuffer), - &global_sha3, - chainConfig->chainId); - compareOrCopy(strings.common.fullAddress, - sizeof(strings.common.fullAddress), + // Prepare destination address and amount to display + if (use_standard_UI) { + // Format the address in a temporary buffer, if in swap case compare it with validated + // address, else commit it + address_to_string(tmpContent.txContent.destination, + tmpContent.txContent.destinationLength, displayBuffer, - called_from_swap); + sizeof(displayBuffer), + &global_sha3, + chainConfig->chainId); + if (called_from_swap) { + // Ensure the values are the same that the ones that have been previously validated + if (strncasecmp(strings.common.fullAddress, + displayBuffer, + MIN(sizeof(strings.common.fullAddress), sizeof(displayBuffer))) != 0) { + THROW(ERR_SILENT_MODE_CHECK_FAILED); + } } else { - strcpy(strings.common.fullAddress, "Contract"); + strlcpy(strings.common.fullAddress, displayBuffer, sizeof(strings.common.fullAddress)); } - } + PRINTF("Address displayed: %s\n", strings.common.fullAddress); - // Prepare amount to display - if (genericUI) { + // Format the amount in a temporary buffer, if in swap case compare it with validated + // amount, else commit it amountToString(tmpContent.txContent.value.value, tmpContent.txContent.value.length, decimals, ticker, displayBuffer, sizeof(displayBuffer)); - compareOrCopy(strings.common.fullAmount, - sizeof(strings.common.fullAmount), - displayBuffer, - called_from_swap); + if (called_from_swap) { + // Ensure the values are the same that the ones that have been previously validated + if (strncmp(strings.common.fullAmount, + displayBuffer, + MIN(sizeof(strings.common.fullAmount), sizeof(displayBuffer))) != 0) { + THROW(ERR_SILENT_MODE_CHECK_FAILED); + } + } else { + strlcpy(strings.common.fullAmount, displayBuffer, sizeof(strings.common.fullAmount)); + } + PRINTF("Amount displayed: %s\n", strings.common.fullAmount); } - // Prepare nonce to display - uint256_t nonce; - convertUint256BE(tmpContent.txContent.nonce.value, tmpContent.txContent.nonce.length, &nonce); - tostring256(&nonce, 10, displayBuffer, sizeof(displayBuffer)); - strlcpy(strings.common.nonce, displayBuffer, sizeof(strings.common.nonce)); + // Compute the max fee in a temporary buffer, if in swap case compare it with validated max fee, + // else commit it + max_transaction_fee_to_string(&tmpContent.txContent.gasprice, + &tmpContent.txContent.startgas, + displayBuffer, + sizeof(displayBuffer)); + if (called_from_swap) { + // Ensure the values are the same that the ones that have been previously validated + if (strncmp(strings.common.maxFee, + displayBuffer, + MIN(sizeof(strings.common.maxFee), sizeof(displayBuffer))) != 0) { + THROW(ERR_SILENT_MODE_CHECK_FAILED); + } + } else { + strlcpy(strings.common.maxFee, displayBuffer, sizeof(strings.common.maxFee)); + } - // Compute maximum fee - prepareFeeDisplay(); PRINTF("Fees displayed: %s\n", strings.common.maxFee); + // Prepare nonce to display + nonce_to_string(&tmpContent.txContent.nonce, + strings.common.nonce, + sizeof(strings.common.nonce)); + PRINTF("Nonce: %s\n", strings.common.nonce); + // Prepare chainID field - prepareNetworkDisplay(); + get_network_as_string(strings.common.network_name, sizeof(strings.common.network_name)); PRINTF("Network: %s\n", strings.common.network_name); - bool no_consent; + bool no_consent_check; - no_consent = called_from_swap; + // If called from swap, the user as already validated a standard transaction + // We have already checked the fields of this transaction above + no_consent_check = called_from_swap && use_standard_UI; #ifdef NO_CONSENT - no_consent = true; + no_consent_check = true; #endif // NO_CONSENT - if (no_consent) { + if (no_consent_check) { io_seproxyhal_touch_tx_ok(NULL); } else { - if (genericUI) { + if (use_standard_UI) { ux_approve_tx(false); } else { - plugin_ui_start(); + dataContext.tokenContext.pluginUiState = PLUGIN_UI_OUTSIDE; + dataContext.tokenContext.pluginUiCurrentItem = 0; + ux_approve_tx(true); } } } From d128b0c9cbbb1de2460572e8829b6c9f6bb838a5 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 24 Apr 2023 11:28:42 +0200 Subject: [PATCH 73/79] Workaround strncasecmp segfault --- src_features/signTx/logic_signTx.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 9530d27..997bba7 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -9,6 +9,7 @@ #include "ethUtils.h" #include "common_ui.h" #include "ui_callbacks.h" +#include #define ERR_SILENT_MODE_CHECK_FAILED 0x6001 @@ -293,6 +294,18 @@ static void get_public_key(uint8_t *out, uint8_t outLength) { getEthAddressFromKey(&publicKey, out, &global_sha3); } +static int strncasecmp_workaround(const char *str1, const char *str2, size_t n) { + unsigned char c1, c2; + for (; n != 0; --n) { + c1 = *str1++; + c2 = *str2++; + if (toupper(c1) != toupper(c2)) { + return toupper(c1) - toupper(c2); + } + }; + return 0; +} + void finalizeParsing(bool direct) { char displayBuffer[50]; uint8_t decimals = WEI_TO_ETHER; @@ -431,9 +444,10 @@ void finalizeParsing(bool direct) { chainConfig->chainId); if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated - if (strncasecmp(strings.common.fullAddress, - displayBuffer, - MIN(sizeof(strings.common.fullAddress), sizeof(displayBuffer))) != 0) { + if (strncasecmp_workaround( + strings.common.fullAddress, + displayBuffer, + MIN(sizeof(strings.common.fullAddress), sizeof(displayBuffer))) != 0) { THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { From 1edd8c528a7196ad8c2a4bb1198aaf984932003f Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 24 Apr 2023 11:30:04 +0200 Subject: [PATCH 74/79] Review --- src_features/signTx/logic_signTx.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 997bba7..7e44dfa 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -294,15 +294,18 @@ static void get_public_key(uint8_t *out, uint8_t outLength) { getEthAddressFromKey(&publicKey, out, &global_sha3); } -static int strncasecmp_workaround(const char *str1, const char *str2, size_t n) { +/* Local implmentation of strncasecmp, workaround of the segfaulting base implem + * Remove once strncasecmp is fixed + */ +static int strcasecmp_workaround(const char *str1, const char *str2) { unsigned char c1, c2; - for (; n != 0; --n) { + do { c1 = *str1++; c2 = *str2++; if (toupper(c1) != toupper(c2)) { return toupper(c1) - toupper(c2); } - }; + } while (c1 != '\0'); return 0; } @@ -444,10 +447,7 @@ void finalizeParsing(bool direct) { chainConfig->chainId); if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated - if (strncasecmp_workaround( - strings.common.fullAddress, - displayBuffer, - MIN(sizeof(strings.common.fullAddress), sizeof(displayBuffer))) != 0) { + if (strcasecmp_workaround(strings.common.fullAddress, displayBuffer) != 0) { THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { @@ -465,9 +465,7 @@ void finalizeParsing(bool direct) { sizeof(displayBuffer)); if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated - if (strncmp(strings.common.fullAmount, - displayBuffer, - MIN(sizeof(strings.common.fullAmount), sizeof(displayBuffer))) != 0) { + if (strcmp(strings.common.fullAmount, displayBuffer) != 0) { THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { @@ -484,9 +482,7 @@ void finalizeParsing(bool direct) { sizeof(displayBuffer)); if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated - if (strncmp(strings.common.maxFee, - displayBuffer, - MIN(sizeof(strings.common.maxFee), sizeof(displayBuffer))) != 0) { + if (strcmp(strings.common.maxFee, displayBuffer) != 0) { THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { From 3fa410fb241426cc850166282116123086e62451 Mon Sep 17 00:00:00 2001 From: Francois Beutin Date: Fri, 8 Jul 2022 12:22:36 +0200 Subject: [PATCH 75/79] Add log for exception --- src_features/signTx/logic_signTx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 7e44dfa..199ccbb 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -424,6 +424,7 @@ void finalizeParsing(bool direct) { // User has just validated a swap but ETH received apdus about a non standard plugin / contract if (called_from_swap && !use_standard_UI) { + PRINTF("ERR_SILENT_MODE_CHECK_FAILED, called_from_swap\n"); THROW(ERR_SILENT_MODE_CHECK_FAILED); } @@ -448,6 +449,7 @@ void finalizeParsing(bool direct) { if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated if (strcasecmp_workaround(strings.common.fullAddress, displayBuffer) != 0) { + PRINTF("ERR_SILENT_MODE_CHECK_FAILED, address check failed\n"); THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { @@ -466,6 +468,7 @@ void finalizeParsing(bool direct) { if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated if (strcmp(strings.common.fullAmount, displayBuffer) != 0) { + PRINTF("ERR_SILENT_MODE_CHECK_FAILED, amount check failed\n"); THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { @@ -483,6 +486,7 @@ void finalizeParsing(bool direct) { if (called_from_swap) { // Ensure the values are the same that the ones that have been previously validated if (strcmp(strings.common.maxFee, displayBuffer) != 0) { + PRINTF("ERR_SILENT_MODE_CHECK_FAILED, fees check failed\n"); THROW(ERR_SILENT_MODE_CHECK_FAILED); } } else { From 9735116f508f302e0f81a7b1b39358b242aec7b0 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Fri, 21 Apr 2023 18:15:23 +0200 Subject: [PATCH 76/79] Nonce handling fixes One test had a nonce way too big that was causing issue with the recent refactoring --- src_common/uint256.c | 14 ++++++++------ tests/speculos/test_sign_cmd.py | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src_common/uint256.c b/src_common/uint256.c index 9da483d..b3f4b2a 100644 --- a/src_common/uint256.c +++ b/src_common/uint256.c @@ -230,18 +230,20 @@ bool tostring256(const uint256_t *const number, UPPER(LOWER(base)) = 0; LOWER(LOWER(base)) = baseParam; uint32_t offset = 0; - if ((baseParam < 2) || (baseParam > 16)) { + if ((outLength == 0) || (baseParam < 2) || (baseParam > 16)) { return false; } do { - if (offset > (outLength - 1)) { - return false; - } divmod256(&rDiv, &base, &rDiv, &rMod); out[offset++] = HEXDIGITS[(uint8_t) LOWER(LOWER(rMod))]; - } while (!zero256(&rDiv)); + } while (!zero256(&rDiv) && (offset < outLength)); - if (offset > (outLength - 1)) { + if (offset == outLength) { // destination buffer too small + if (outLength > 3) { + strcpy(out, "..."); + } else { + out[0] = '\0'; + } return false; } diff --git a/tests/speculos/test_sign_cmd.py b/tests/speculos/test_sign_cmd.py index 0e0207a..588e7aa 100644 --- a/tests/speculos/test_sign_cmd.py +++ b/tests/speculos/test_sign_cmd.py @@ -619,7 +619,7 @@ def test_sign_blind_and_nonce_display(cmd): transaction = Transaction( txType=0xEB, - nonce=2**64-1, + nonce=1844674, gasPrice=0x0306dc4200, gasLimit=0x5208, to="0x5a321744667052affa8386ed49e00ef223cbffc3", @@ -699,6 +699,6 @@ def test_sign_blind_and_nonce_display(cmd): v, r, s = result - assert v == 0x25 # 37 - assert r.hex() == "737c07042022d37286216312d62163c4238536d82c5b45937ce9fbf259d11b7d" - assert s.hex() == "5604485e0cf37e465a84290eb26a18e40a430f1b0fda184c56b2c3a51ada2e6c" + assert v == 0x26 # 38 + assert r.hex() == "c8d7cd5c1711ea1af7da048d15d1a95fc9347d4622afa11f32320d73384984d1" + assert s.hex() == "3165ca0a27f565e1a87560ed3d3a144c4ac9732370428da5e6952e93659f6ac2" From cc283f271c398088f990c24601dcdaac060eb30b Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 24 Apr 2023 14:28:08 +0200 Subject: [PATCH 77/79] Changed strcpy to strlcpy for the static analysis --- src_common/uint256.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_common/uint256.c b/src_common/uint256.c index b3f4b2a..7851124 100644 --- a/src_common/uint256.c +++ b/src_common/uint256.c @@ -240,7 +240,7 @@ bool tostring256(const uint256_t *const number, if (offset == outLength) { // destination buffer too small if (outLength > 3) { - strcpy(out, "..."); + strlcpy(out, "...", outLength); } else { out[0] = '\0'; } From bb811f9e559ff7fc6ab7aa40a256f91982845b03 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 24 Apr 2023 13:59:10 +0200 Subject: [PATCH 78/79] Removed -dev version suffix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 95afe9b..b7704d7 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ APP_LOAD_PARAMS += --path "1517992542'/1101353413'" APPVERSION_M=1 APPVERSION_N=10 APPVERSION_P=2 -APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)-dev +APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) APP_LOAD_FLAGS= --appFlags 0xa40 --dep Ethereum:$(APPVERSION) ########################### From 01997ba34baf6241beb25ad4b76079eb08839f67 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 24 Apr 2023 13:59:23 +0200 Subject: [PATCH 79/79] Updated changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b95816f..50c74f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2023-XX-XX +## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2023-04-24 ### Added @@ -35,7 +35,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Possible overflow with very large transactions - EnergyWebChain ticker - Arbitrum ticker -- Better error handling on EIP-191 APDUs +- Error handling on EIP-191 APDUs +- Swap transactions handling ## [1.10.1](https://github.com/ledgerhq/app-ethereum/compare/1.10.0...1.10.1) - 2022-11-09