diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile new file mode 100644 index 000000000..32efe99a5 --- /dev/null +++ b/.clusterfuzzlite/Dockerfile @@ -0,0 +1,17 @@ +FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER + +# Base image with clang toolchain +FROM gcr.io/oss-fuzz-base/base-builder:v1 + +# Copy the project's source code. +COPY . $SRC/app-ethereum +COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-ethereum/BOLOS_SDK + +# Add the ethereum-plugin-sdk submodule +RUN git clone https://github.com/LedgerHQ/ethereum-plugin-sdk.git $SRC/app-ethereum/ethereum-plugin-sdk + +# Working directory for build.sh +WORKDIR $SRC/app-ethereum + +# Copy build.sh into $SRC dir. +COPY ./.clusterfuzzlite/build.sh $SRC/ diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh new file mode 100644 index 000000000..6fc75a929 --- /dev/null +++ b/.clusterfuzzlite/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +# build fuzzers + +pushd tests/fuzzing +cmake -DBOLOS_SDK=$(pwd)/../../BOLOS_SDK -B build -S . +cmake --build build +mv ./build/fuzzer "${OUT}" +popd diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml new file mode 100644 index 000000000..b455aa397 --- /dev/null +++ b/.clusterfuzzlite/project.yaml @@ -0,0 +1 @@ +language: c diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml new file mode 100644 index 000000000..440a752f5 --- /dev/null +++ b/.github/workflows/cflite_cron.yml @@ -0,0 +1,40 @@ +name: ClusterFuzzLite cron tasks +on: + workflow_dispatch: + push: + branches: + - main # Use your actual default branch here. + schedule: + - cron: '0 13 * * 6' # At 01:00 PM, only on Saturday +permissions: read-all +jobs: + Fuzzing: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - mode: batch + sanitizer: address + - mode: batch + sanitizer: memory + - mode: prune + sanitizer: address + - mode: coverage + sanitizer: coverage + steps: + - name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + language: c # Change this to the language you are fuzzing. + sanitizer: ${{ matrix.sanitizer }} + - name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: ${{ matrix.mode }} + sanitizer: ${{ matrix.sanitizer }} diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml new file mode 100644 index 000000000..09f91dafe --- /dev/null +++ b/.github/workflows/cflite_pr.yml @@ -0,0 +1,43 @@ +name: ClusterFuzzLite PR fuzzing +on: + pull_request: + paths: + - '**' +permissions: read-all +jobs: + PR: + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + sanitizer: [address, undefined, memory] # Override this with the sanitizers you want. + steps: + - name: Build Fuzzers (${{ matrix.sanitizer }}) + id: build + uses: google/clusterfuzzlite/actions/build_fuzzers@v1 + with: + language: c # Change this to the language you are fuzzing. + github-token: ${{ secrets.GITHUB_TOKEN }} + sanitizer: ${{ matrix.sanitizer }} + # Optional but recommended: used to only run fuzzers that are affected + # by the PR. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". + - name: Run Fuzzers (${{ matrix.sanitizer }}) + id: run + uses: google/clusterfuzzlite/actions/run_fuzzers@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + fuzz-seconds: 300 # 5 minutes + mode: 'code-change' + sanitizer: ${{ matrix.sanitizer }} + output-sarif: true + # Optional but recommended: used to download the corpus produced by + # batch fuzzing. + # storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git + # storage-repo-branch: main # Optional. Defaults to "main" + # storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages". diff --git a/.gitignore b/.gitignore index 20f25ff19..ed206c628 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,12 @@ __version__.py .vscode .idea + +# Fuzzing +tests/fuzzing/corpus/ +tests/fuzzing/out/ +default.profraw +default.profdata +fuzz-*.log +crash-* +report.html diff --git a/CHANGELOG.md b/CHANGELOG.md index fff895cff..f3ec327cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,35 @@ 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.14.0](https://github.com/ledgerhq/app-ethereum/compare/1.13.0...1.14.0) - 2024-12-19 +## [1.15.0](../../compare/1.14.0...1.15.0) - 2025-01-30 + +### Added + +- (clone) Harmony +- (network) Sonic +- (network) Soneium +- (network) Swellchain +- (network) Swellchain Testnet +- (network) Soneium Testnet Minato +- (network) Bahamut +- (network) Odyssey Chain +- (network) Lumia +- (network) Harmony ONE S0 +- (network) Harmony ONE S1 + +### Removed + +- (clone) ARTIS tau1 +- (clone) TecraTestnet +- (clone) Volta +- Dynamic networks support from LNS + +### Changed + +- (network) Klaytn Cypress renamed to Kaia Mainnet +- Switched to production PKI key usages + +## [1.14.0](../../compare/1.13.0...1.14.0) - 2024-12-19 ### Added @@ -24,7 +52,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Key ID & public key used for trusted names coming from CAL - PKI key usage in trusted name feature -## [1.13.0](https://github.com/ledgerhq/app-ethereum/compare/1.12.2...1.13.0) - 2024-11-26 +## [1.13.0](../../compare/1.12.2...1.13.0) - 2024-11-26 ### Added @@ -49,20 +77,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Potential overflow on the UI buffer used for amounts - RLP parsing issue with legacy transactions -## [1.12.2](https://github.com/ledgerhq/app-ethereum/compare/1.12.1...1.12.2) - 2024-10-24 +## [1.12.2](../../compare/1.12.1...1.12.2) - 2024-10-24 ### Fixed - Token swap with calldata -## [1.12.1](https://github.com/ledgerhq/app-ethereum/compare/1.12.0...1.12.1) - 2024-10-02 +## [1.12.1](../../compare/1.12.0...1.12.1) - 2024-10-02 ### Fixed - Review of EIP-191 messages getting stuck and not responding to APDUs - (clone) Ethereum Classic, gave it back the Ethereum derivation path -## [1.12.0](https://github.com/ledgerhq/app-ethereum/compare/1.11.3...1.12.0) - 2024-09-27 +## [1.12.0](../../compare/1.11.3...1.12.0) - 2024-09-27 ### Added @@ -114,13 +142,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added blind-signing friction to EIP-712 v0 & unfiltered flows - EIP-712 unfiltered flow now defaults to raw/verbose mode on Stax & Flex, but adds a skip button -## [1.11.3](https://github.com/ledgerhq/app-ethereum/compare/1.11.2...1.11.3) - 2024-09-04 +## [1.11.3](../../compare/1.11.2...1.11.3) - 2024-09-04 ### Changed - Replaced MATIC by POL ticker for Polygon network -## [1.11.2](https://github.com/ledgerhq/app-ethereum/compare/1.11.1...1.11.2) - 2024-08-13 +## [1.11.2](../../compare/1.11.1...1.11.2) - 2024-08-13 ### Added @@ -131,14 +159,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Simplified blind-signing warnings on Flex & Stax - Restored blind-signing warning screen from < 1.11.0 on Nano devices -## [1.11.1](https://github.com/ledgerhq/app-ethereum/compare/1.11.0...1.11.1) - 2024-07-26 +## [1.11.1](../../compare/1.11.0...1.11.1) - 2024-07-26 ### Fixed - (network/clone) Wanchain - Refusal of EIP-712 messages after another transaction or message -## [1.11.0](https://github.com/ledgerhq/app-ethereum/compare/1.10.4...1.11.0) - 2024-07-24 +## [1.11.0](../../compare/1.10.4...1.11.0) - 2024-07-24 ### Added @@ -184,7 +212,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Handling of EIP-712 empty arrays within nested structs -## [1.10.4](https://github.com/ledgerhq/app-ethereum/compare/1.10.3...1.10.4) - 2024-03-08 +## [1.10.4](../../compare/1.10.3...1.10.4) - 2024-03-08 ### Added @@ -217,7 +245,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - (network) Wanchain chain ID - (network) Sepolia chain ID -## [1.10.3](https://github.com/ledgerhq/app-ethereum/compare/1.10.2...1.10.3) - 2023-07-27 +## [1.10.3](../../compare/1.10.2...1.10.3) - 2023-07-27 ### Added @@ -244,7 +272,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Miscellaneous swap issues - Improper EIP-712 array handling -## [1.10.2](https://github.com/ledgerhq/app-ethereum/compare/1.10.1...1.10.2) - 2023-04-24 +## [1.10.2](../../compare/1.10.1...1.10.2) - 2023-04-24 ### Added @@ -277,19 +305,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - 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 +## [1.10.1](../../compare/1.10.0...1.10.1) - 2022-11-09 ### Fixed - App/device crash with fast button clicks on slow APDU transport on the new EIP-712 signature UI -## [1.10.0](https://github.com/ledgerhq/app-ethereum/compare/1.9.20...1.10.0) - 2022-10-26 +## [1.10.0](../../compare/1.9.20...1.10.0) - 2022-10-26 ### Changed - EIP-712 signatures are now computed on-device and display their content (clear-signing) (LNX & LNS+) -## [1.9.20](https://github.com/ledgerhq/app-ethereum/compare/1.9.19...1.9.20) - 2022-10-10 +## [1.9.20](../../compare/1.9.19...1.9.20) - 2022-10-10 ### Added @@ -312,7 +340,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Compound support (will become its own plugin) -## [1.9.19](https://github.com/ledgerhq/app-ethereum/compare/1.9.18...1.9.19) - 2022-06-15 +## [1.9.19](../../compare/1.9.18...1.9.19) - 2022-06-15 ### Added @@ -330,7 +358,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Bug with huge swap amounts -## [1.9.18](https://github.com/ledgerhq/app-ethereum/compare/1.9.17...1.9.18) - 2022-04-25 +## [1.9.18](../../compare/1.9.17...1.9.18) - 2022-04-25 ### Added @@ -352,19 +380,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - App crashing when trying to approve an NFT transaction without having received the NFT information beforehand - App refusing to approve an NFT transaction with a long collection name -## [1.9.17](https://github.com/ledgerhq/app-ethereum/compare/1.9.16...1.9.17) - 2022-01-14 +## [1.9.17](../../compare/1.9.16...1.9.17) - 2022-01-14 ### Added - Support for Non-Fungible Tokens (ERC-721 & ERC-1155) -## [1.9.16](https://github.com/ledgerhq/app-ethereum/compare/1.9.14...1.9.16) - 2022-01-13 +## [1.9.16](../../compare/1.9.14...1.9.16) - 2022-01-13 ### Added - Shyft variant -## [1.9.14](https://github.com/ledgerhq/app-ethereum/compare/1.9.13...1.9.14) - 2021-11-30 +## [1.9.14](../../compare/1.9.13...1.9.14) - 2021-11-30 ### Added @@ -374,38 +402,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed stark order signature on LNS -## [1.9.13](https://github.com/ledgerhq/app-ethereum/compare/1.9.12...1.9.13) - 2021-11-17 +## [1.9.13](../../compare/1.9.12...1.9.13) - 2021-11-17 ### Changed - Small improvement in app size -## [1.9.12](https://github.com/ledgerhq/app-ethereum/compare/1.9.11...1.9.12) - 2021-11-12 +## [1.9.12](../../compare/1.9.11...1.9.12) - 2021-11-12 ### Fixed - Fixed stark order signature on LNX -## [1.9.11](https://github.com/ledgerhq/app-ethereum/compare/1.9.10...1.9.11) - 2021-10-12 +## [1.9.11](../../compare/1.9.10...1.9.11) - 2021-10-12 ### Added - Provide network ticker to plugins (especially helpful for Paraswap plugin) - Polygon variant -## [1.9.10](https://github.com/ledgerhq/app-ethereum/compare/1.9.9...1.9.10) - 2021-10-08 +## [1.9.10](../../compare/1.9.9...1.9.10) - 2021-10-08 ### Added - Add new app: Moonriver -## [1.9.9](https://github.com/ledgerhq/app-ethereum/compare/1.9.8...1.9.9) - 2021-10-08 +## [1.9.9](../../compare/1.9.8...1.9.9) - 2021-10-08 ### Changed - Rollback the revert in wording change of "Contract data" in "Blind signing" that was introduced in v1.9.8 -## [1.9.8](https://github.com/ledgerhq/app-ethereum/compare/1.9.7...1.9.8) - 2021-10-06 +## [1.9.8](../../compare/1.9.7...1.9.8) - 2021-10-06 ### Changed @@ -415,19 +443,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Goerli now has its own standalone app, with hardcoded deversifi tokens -## [1.9.7](https://github.com/ledgerhq/app-ethereum/compare/1.9.6...1.9.7) - 2021-9-30 +## [1.9.7](../../compare/1.9.6...1.9.7) - 2021-9-30 ### Fixed - Fixed a bug where amounts displayed where wrong when the amount was huge (>=2^87) -## [1.9.6](https://github.com/ledgerhq/app-ethereum/compare/1.9.5...1.9.6) - 2021-9-29 +## [1.9.6](../../compare/1.9.5...1.9.6) - 2021-9-29 ### Fixed - Fixed a bug where fees displayed were wrong on Starkware transactions -## [1.9.5](https://github.com/ledgerhq/app-ethereum/compare/1.9.4...1.9.5) - 2021-9-27 +## [1.9.5](../../compare/1.9.4...1.9.5) - 2021-9-27 ### Changed @@ -438,13 +466,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - When blind signing is disabled in settings, and a transaction with smart conract interactions is sent to the app, a new warning screen pops to let the user know that the setting must be enabled to sign this kind of transactions. -## [1.9.4](https://github.com/ledgerhq/app-ethereum/compare/1.9.3...1.9.4) - 2021-9-14 +## [1.9.4](../../compare/1.9.3...1.9.4) - 2021-9-14 ### Added - Added Arbitrum network -## [1.9.3](https://github.com/ledgerhq/app-ethereum/compare/1.9.2...1.9.3) - 2021-9-03 +## [1.9.3](../../compare/1.9.2...1.9.3) - 2021-9-03 ### Added @@ -459,7 +487,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Increased plugin interface to version 2 - Remove support for Theta and Flare -## [1.9.2](https://github.com/ledgerhq/app-ethereum/compare/1.9.0...1.9.2) - 2021-8-11 +## [1.9.2](../../compare/1.9.0...1.9.2) - 2021-8-11 ### Added @@ -470,20 +498,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed BSC icon colors. - Fixed theta tokens. -## [1.9.0](https://github.com/ledgerhq/app-ethereum/compare/1.8.8...1.9.0) - 2021-8-05 +## [1.9.0](../../compare/1.8.8...1.9.0) - 2021-8-05 ### Added - Added support for EIP-1559 and EIP-2930 style transactions. -## [1.8.8](https://github.com/ledgerhq/app-ethereum/compare/1.8.7...1.8.8) - 2021-7-21 +## [1.8.8](../../compare/1.8.7...1.8.8) - 2021-7-21 ### Added - Added support for BSC. - Add support for Lido plugin -## [1.8.7](https://github.com/ledgerhq/app-ethereum/compare/1.8.6...1.8.7) - 2021-7-9 +## [1.8.7](../../compare/1.8.6...1.8.7) - 2021-7-9 ### Added @@ -494,7 +522,7 @@ Remove `m/44'/60'` derivation path authorisation for Theta app. `additional_screens` was introduced previously but wasn't properly initialized in some cases. -## [1.8.6](https://github.com/ledgerhq/app-ethereum/compare/1.8.5...1.8.6) - 2021-7-5 +## [1.8.6](../../compare/1.8.5...1.8.6) - 2021-7-5 ### Added @@ -505,63 +533,63 @@ When the network is known, amounts and fees are displayed in the network unit in Fix some compilation warning -## [1.8.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.9...1.8.5) - 2021-6-8 +## [1.8.5](../../compare/1.7.9...1.8.5) - 2021-6-8 ### Added - Added support for external plugins. -## [1.7.9](https://github.com/ledgerhq/app-ethereum/compare/1.7.8...1.7.9) - 2021-6-2 +## [1.7.9](../../compare/1.7.8...1.7.9) - 2021-6-2 ### Added - Added support for Flare Network and Theta Chain. -## [1.7.8](https://github.com/ledgerhq/app-ethereum/compare/1.7.7...1.7.8) - 2021-5-20 +## [1.7.8](../../compare/1.7.7...1.7.8) - 2021-5-20 ### Fixed - Fixed a bug where transaction would sometimes not get properly signed. -## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19 +## [1.7.7](../../compare/1.7.6...1.7.7) - 2021-5-19 ### Special - Version bump needed for deployment reasons, nothing changed. -## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.5...1.7.6) - 2021-5-14 +## [1.7.6](../../compare/1.7.5...1.7.6) - 2021-5-14 ### Special - Version bump needed for deployment reasons, nothing changed. -## [1.7.7](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.7) - 2021-5-19 +## [1.7.7](../../compare/1.7.6...1.7.7) - 2021-5-19 - N/A -## [1.7.6](https://github.com/ledgerhq/app-ethereum/compare/1.7.6...1.7.6) - 2021-5-14 +## [1.7.6](../../compare/1.7.6...1.7.6) - 2021-5-14 - N/A -## [1.7.5](https://github.com/ledgerhq/app-ethereum/compare/1.7.4...1.7.5) - 2021-5-10 +## [1.7.5](../../compare/1.7.4...1.7.5) - 2021-5-10 ### Fixed - Fixed a bug with cx_ecfp_scalar_mult -## [1.7.4](https://github.com/ledgerhq/app-ethereum/compare/1.7.3...1.7.4) - 2021-5-6 +## [1.7.4](../../compare/1.7.3...1.7.4) - 2021-5-6 ### Fixed - Fixed a bug that prevented using Ethereum sidechains -## [1.7.3](https://github.com/ledgerhq/app-ethereum/compare/1.7.2...1.7.3) - 2021-5-5 +## [1.7.3](../../compare/1.7.2...1.7.3) - 2021-5-5 ### Added - Enable Ethereum 2 deposit on Nano S 2.0.0 -## [1.7.2](https://github.com/ledgerhq/app-ethereum/compare/1.7.1...1.7.2) - 2021-5-5 +## [1.7.2](../../compare/1.7.1...1.7.2) - 2021-5-5 ### Added @@ -570,38 +598,38 @@ Fix some compilation warning - Abort signing when the account index of the withdrawal key is higher than INDEX_MAX. - Check that the destination field of the transaction is Ethereum 2 deposit contract. -## [1.7.1](https://github.com/ledgerhq/app-ethereum/compare/1.7.0...1.7.1) - 2021-5-5 +## [1.7.1](../../compare/1.7.0...1.7.1) - 2021-5-5 ### Added - Support for Berlin hard fork: EIP2718 (transaction types) and EIP2930 (access list transactions) - Display ChainID when transacting on chains which are not ethereum (BSC, Polygon, etc) -## [1.7.0](https://github.com/ledgerhq/app-ethereum/compare/1.6.6...1.7.0) - 2021-4-30 +## [1.7.0](../../compare/1.6.6...1.7.0) - 2021-4-30 ### Added - Wallet ID feature now available on Nano X -## [1.6.6](https://github.com/ledgerhq/app-ethereum/compare/1.6.5...1.6.6) - 2021-4-16 +## [1.6.6](../../compare/1.6.5...1.6.6) - 2021-4-16 ### Added - Improved Starkware support -## [1.6.5](https://github.com/ledgerhq/app-ethereum/compare/1.6.4...1.6.5) - 2021-2-12 +## [1.6.5](../../compare/1.6.4...1.6.5) - 2021-2-12 ### Added - Add a setting to enable nonce display when approving transactions -## [1.6.4](https://github.com/ledgerhq/app-ethereum/compare/1.6.3...1.6.4) - 2021-1-12 +## [1.6.4](../../compare/1.6.3...1.6.4) - 2021-1-12 ### Fixed - "warning" icon wasn't correctly displayed -## [1.6.3](https://github.com/ledgerhq/app-ethereum/compare/1.6.2...1.6.3) - 2020-12-10 +## [1.6.3](../../compare/1.6.2...1.6.3) - 2020-12-10 ### Added diff --git a/Makefile b/Makefile index 2928b10f6..5fb269659 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ endif include ./makefile_conf/chain/$(CHAIN).mk APPVERSION_M = 1 -APPVERSION_N = 14 +APPVERSION_N = 15 APPVERSION_P = 0 APPVERSION = $(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) diff --git a/README.md b/README.md index f356b91d9..14d991c11 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ ## About the project -Ethereum wallet application framework for Nano S, Nano S Plus and Nano X. +Ethereum wallet application framework for Ledger Nano S, Ledger Nano S Plus, Ledger Nano X, Ledger Flex and Ledger Stax. Ledger Blue is not maintained anymore, but the app can still be compiled for this target using the branch [`blue-final-release`](https://github.com/LedgerHQ/app-ethereum/tree/blue-final-release). ## Documentation diff --git a/client/src/ledger_app_clients/ethereum/client.py b/client/src/ledger_app_clients/ethereum/client.py index a26404d74..4a4801597 100644 --- a/client/src/ledger_app_clients/ethereum/client.py +++ b/client/src/ledger_app_clients/ethereum/client.py @@ -75,6 +75,8 @@ class PKIPubKeyUsage(IntEnum): PUBKEY_USAGE_PLUGIN_METADATA = 0x07 PUBKEY_USAGE_COIN_META = 0x08 PUBKEY_USAGE_SEED_ID_AUTH = 0x09 + PUBKEY_USAGE_CALLDATA = 0x0b + PUBKEY_USAGE_NETWORK = 0x0c class SignMode(IntEnum): @@ -272,28 +274,39 @@ def perform_privacy_operation(self, pubkey)) def _provide_trusted_name_common(self, payload: bytes, name_source: TrustedNameSource) -> RAPDU: - if self._pki_client is None: - print(f"Ledger-PKI Not supported on '{self._firmware.name}'") - else: - # pylint: disable=line-too-long - if self._firmware == Firmware.NANOSP: - cert_apdu = "01010102010210040102000011040000000212010013020002140101160400000000200b446f6d61696e5f4e616d6530020007310108320121332102b91fbec173e3ba4a714e014ebc827b6f899a9fa7f4ac769cde284317a00f4f653401013501031546304402201b5188f5af5cd4d40d2e5eee85609323ee129b789082d079644c89c0df9b6ce0022076c5d26bb5c8db8ab02771ecd577f63f68eaf1c90523173f161f9c12f6e978bd" # noqa: E501 - elif self._firmware == Firmware.NANOX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F653401013501021546304402202CD052029B756890F0C56713409C58C24785FEFFD1A997E9C840A7BDB176B512022059A30E04E491CD27BD1DA1B5CB810CF8E4EAE67F6406F054FDFC371F7EB9F2C4" # noqa: E501 - elif self._firmware == Firmware.STAX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350104154630440220741DB4E738749D4188436419B20B9AEF8F07581312A9B3C9BAA3F3E879690F6002204C4A3510569247777BC43DB830D129ACA8985B88552E2E234E14D8AA2863026B" # noqa: E501 - elif self._firmware == Firmware.FLEX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B446F6D61696E5F4E616D6530020007310108320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350105154730450221008B6BBCE1716C0A06F110C77FE181F8395D1692441459A106411463F01A45D4A7022044AB69037E6FA9D1D1A409E00B202C2D4451D464C8E5D4962D509FE63153FE93" # noqa: E501 - # pylint: enable=line-too-long - - self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu)) payload += format_tlv(FieldTag.STRUCT_TYPE, 3) # TrustedName if name_source == TrustedNameSource.CAL: + if self._pki_client is not None: + # pylint: disable=line-too-long + if self._firmware == Firmware.NANOSP: + cert_apdu = "010101020102110400000002120100130200021401011604000000002010547275737465645F4E616D655F43414C300200093101043201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501031546304402202397E6D4F5A9C13532810619EB766CB41919F7A814935CA207429966E41CE80202202E43159A04BB0596A6B1F0DDE1A12931EA56156751586BEE8FDCAB54EEE36883" # noqa: E501 + elif self._firmware == Firmware.NANOX: + cert_apdu = "010101020102110400000002120100130200021401011604000000002010547275737465645F4E616D655F43414C300200093101043201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100BCAED6896A3413657F7F936F53FFF5BD7E30498B1109EAB878135F6DD4AAE555022056913EF42F166BEFEEDDB06C1F7AEEDE8712828F37B916E3E6DA7AE0809558E4" # noqa: E501 + elif self._firmware == Firmware.STAX: + cert_apdu = "010101020102110400000002120100130200021401011604000000002010547275737465645F4E616D655F43414C300200093101043201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010415473045022100ABA9D58446EE81EB073DA91941989DD7E133556D58DE2BCBA59E46253DB448B102201DF8AE930A9E318B50576D8922503A5D3EC84C00C332A7C8FF7CD48708751840" # noqa: E501 + elif self._firmware == Firmware.FLEX: + cert_apdu = "010101020102110400000002120100130200021401011604000000002010547275737465645F4E616D655F43414C300200093101043201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501051546304402206DC9F82C53F3B13400D3E343E3C8C81868E8C73B1EF2655D07891064B7AC3166022069A36E4059D75C93E488A5D58C02BCA9C80C081F77B31C5EDCF07F1A500C565A" # noqa: E501 + # pylint: enable=line-too-long key_id = 6 key = Key.CAL else: + if self._pki_client is not None: + # pylint: disable=line-too-long + if self._firmware == Firmware.NANOSP: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020007310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010315473045022100F394484C045418507E0F76A3231F233B920C733D3E5BB68AFBAA80A55195F70D022012BC1FD796CD2081D8355DEEFA051FBB9329E34826FF3125098F4C6A0C29992A" # noqa: E501 + elif self._firmware == Firmware.NANOX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020007310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F65340101350102154730450221009D97646C49EE771BE56C321AB59C732E10D5D363EBB9944BF284A3A04EC5A14102200633518E851984A7EA00C5F81EDA9DAA58B4A6C98E57DA1FBB9074AEFF0FE49F" # noqa: E501 + elif self._firmware == Firmware.STAX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020007310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010415473045022100A57DC7AB3F0E38A8D10783C7449024D929C60843BB75E5FF7B8088CB71CB130C022045A03E6F501F3702871466473BA08CE1F111357ED9EF395959733477165924C4" # noqa: E501 + elif self._firmware == Firmware.FLEX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200C547275737465645F4E616D6530020007310104320121332102B91FBEC173E3BA4A714E014EBC827B6F899A9FA7F4AC769CDE284317A00F4F6534010135010515473045022100D5BB77756C3D7C1B4254EA8D5351B94A89B13BA69C3631A523F293A10B7144B302201519B29A882BB22DCDDF6BE79A9CBA76566717FA877B7CA4B9CC40361A2D579E" # noqa: E501 + # pylint: enable=line-too-long key_id = 3 key = Key.TRUSTED_NAME + + if self._pki_client is not None: + self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_TRUSTED_NAME, bytes.fromhex(cert_apdu)) + payload += format_tlv(FieldTag.SIGNER_KEY_ID, key_id) # test key payload += format_tlv(FieldTag.SIGNER_ALGO, 1) # secp256k1 payload += format_tlv(FieldTag.DER_SIGNATURE, @@ -513,7 +526,7 @@ def _prepare_network_info(self, payload += format_tlv(FieldTag.NETWORK_ICON_HASH, sha256(icon).digest()) # Append the data Signature payload += format_tlv(FieldTag.DER_SIGNATURE, - sign_data(Key.CAL, payload)) + sign_data(Key.NETWORK, payload)) return payload def provide_network_information(self, @@ -527,16 +540,16 @@ def provide_network_information(self, else: # pylint: disable=line-too-long if self._firmware == Firmware.NANOSP: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010310040102000015473045022100C15795C2AE41E6FAE6B1362EE1AE216428507D7C1D6939B928559CC7A1F6425C02206139CF2E133DD62F3E00F183E42109C9853AC62B6B70C5079B9A80DBB9D54AB5" # noqa: E501 + cert_apdu = "0101010201021104000000021201001302000214010116040000000020076E6574776F726B3002000A31010C32012133210304AF5CF32094F855E93235E9EB43F48E9B436C2E1DFAEA58ECAFA68AAFB1D27C3401013501031546304402207BDE0D30C0A573ECF2F8377F30D9A064CFDD8C85E3B328E4C0867A5C7E95EC7E02204B3546342571AE54E7524DD66D4F801E3E4F4F2EA9008F943661F62E48053E92" # noqa: E501 elif self._firmware == Firmware.NANOX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010215473045022100E3B956F93FBFF0D41908483888F0F75D4714662A692F7A38DC6C41A13294F9370220471991BECB3CA4F43413CADC8FF738A8CC03568BFA832B4DCFE8C469080984E5" # noqa: E501 + cert_apdu = "0101010201021104000000021201001302000214010116040000000020076E6574776F726B3002000A31010C32012133210304AF5CF32094F855E93235E9EB43F48E9B436C2E1DFAEA58ECAFA68AAFB1D27C34010135010215473045022100E1CE7DAC7A23B9422B0764F8FE80246B2CF0780227289FBFB203985DA6326A9502205F90B43600407A094DD6DEBCEB92F34DA3EDA9EB5463568440BDC21635FF2044" # noqa: E501 elif self._firmware == Firmware.STAX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C6405618873401013501041546304402206731FCD3E2432C5CA162381392FD17AD3A41EEF852E1D706F21A656AB165263602204B89FAE8DBAF191E2D79FB00EBA80D613CB7EDF0BE960CB6F6B29D96E1437F5F" # noqa: E501 + cert_apdu = "0101010201021104000000021201001302000214010116040000000020076E6574776F726B3002000A31010C32012133210304AF5CF32094F855E93235E9EB43F48E9B436C2E1DFAEA58ECAFA68AAFB1D27C34010135010415463044022044C595C3E98100D4ECA75A73BF294090FF94948E80EE1430624C886B15BE862302200994E1D98CA72B78D57808B5FD236F439376AFC7C651B55D4AFBFB5AF4C15E00" # noqa: E501 elif self._firmware == Firmware.FLEX: - cert_apdu = "01010102010211040000000212010013020002140101160400000000200B45524332305F546F6B656E300200063101083201213321024CCA8FAD496AA5040A00A7EB2F5CC3B85376D88BA147A7D7054A99C64056188734010135010515473045022100B59EA8B958AA40578A6FBE9BBFB761020ACD5DBD8AA863C11DA17F42B2AFDE790220186316059EFA58811337D47C7F815F772EA42BBBCEA4AE123D1118C80588F5CB" # noqa: E501 + cert_apdu = "0101010201021104000000021201001302000214010116040000000020076E6574776F726B3002000A31010C32012133210304AF5CF32094F855E93235E9EB43F48E9B436C2E1DFAEA58ECAFA68AAFB1D27C34010135010515463044022008D276684F1A1CC3A89DB0B15120860414FF6A60E227FCAA29ED8F2096C982460220343FE956D443CEA33A2F8BD9DD1EAD783ACFF86088CF01BCE63C224DC815D7F0" # noqa: E501 # pylint: enable=line-too-long - self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_COIN_META, bytes.fromhex(cert_apdu)) + self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_NETWORK, bytes.fromhex(cert_apdu)) # Add the network info payload = self._prepare_network_info(name, ticker, chain_id, icon) @@ -554,6 +567,21 @@ def provide_enum_value(self, payload: bytes) -> RAPDU: return self._exchange(chunks[-1]) def provide_transaction_info(self, payload: bytes) -> RAPDU: + if self._pki_client is None: + print(f"Ledger-PKI Not supported on '{self._firmware.name}'") + else: + # pylint: disable=line-too-long + if self._firmware == Firmware.NANOSP: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200863616C6C646174613002000831010B32012133210381C0821E2A14AC2546FB0B9852F37CA2789D7D76483D79217FB36F51DCE1E7B434010135010315463044022076DD2EAB72E69D440D6ED8290C8C37E39F54294C23FF0F8520F836E7BE07455C02201D9A8A75223C1ADA1D9D00966A12EBB919D0BBF2E66F144C83FADCAA23672566" # noqa: E501 + elif self._firmware == Firmware.NANOX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200863616C6C646174613002000831010B32012133210381C0821E2A14AC2546FB0B9852F37CA2789D7D76483D79217FB36F51DCE1E7B434010135010215463044022077FF9625006CB8A4AD41A4B04FF2112E92A732BD263CCE9B97D8E7D2536D04300220445B8EE3616FB907AA5E68359275E94D0A099C3E32A4FC8B3669C34083671F2F" # noqa: E501 + elif self._firmware == Firmware.STAX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200863616C6C646174613002000831010B32012133210381C0821E2A14AC2546FB0B9852F37CA2789D7D76483D79217FB36F51DCE1E7B434010135010415473045022100A88646AD72CA012D5FDAF8F6AE0B7EBEF079212768D57323CB5B57CADD9EB20D022005872F8EA06092C9783F01AF02C5510588FB60CBF4BA51FB382B39C1E060BB6B" # noqa: E501 + elif self._firmware == Firmware.FLEX: + cert_apdu = "01010102010211040000000212010013020002140101160400000000200863616C6C646174613002000831010B32012133210381C0821E2A14AC2546FB0B9852F37CA2789D7D76483D79217FB36F51DCE1E7B43401013501051546304402205305BDDDAD0284A2EAC2A9BE4CEF6604AE9415C5F46883448F5F6325026234A3022001ED743BCF33CCEB070FDD73C3D3FCC2CEE5AB30A5C3EB7D2A8D21C6F58D493F" # noqa: E501 + # pylint: enable=line-too-long + + self._pki_client.send_certificate(PKIPubKeyUsage.PUBKEY_USAGE_CALLDATA, bytes.fromhex(cert_apdu)) chunks = self._cmd_builder.provide_transaction_info(payload) for chunk in chunks[:-1]: self._exchange(chunk) diff --git a/client/src/ledger_app_clients/ethereum/gcs.py b/client/src/ledger_app_clients/ethereum/gcs.py index b48fc6f43..3913b2223 100644 --- a/client/src/ledger_app_clients/ethereum/gcs.py +++ b/client/src/ledger_app_clients/ethereum/gcs.py @@ -67,7 +67,7 @@ def serialize(self) -> bytes: payload += format_tlv(0x0a, self.deploy_date) signature = self.signature if signature is None: - signature = sign_data(Key.CAL, payload) + signature = sign_data(Key.CALLDATA, payload) payload += format_tlv(0xff, signature) return payload diff --git a/client/src/ledger_app_clients/ethereum/keychain.py b/client/src/ledger_app_clients/ethereum/keychain.py index 4eb638573..b913c867a 100644 --- a/client/src/ledger_app_clients/ethereum/keychain.py +++ b/client/src/ledger_app_clients/ethereum/keychain.py @@ -12,6 +12,8 @@ class Key(Enum): TRUSTED_NAME = auto() SET_PLUGIN = auto() NFT = auto() + CALLDATA = auto() + NETWORK = auto() _keys: dict[Key, SigningKey] = dict() diff --git a/client/src/ledger_app_clients/ethereum/keychain/calldata.pem b/client/src/ledger_app_clients/ethereum/keychain/calldata.pem new file mode 100644 index 000000000..f97d7bf16 --- /dev/null +++ b/client/src/ledger_app_clients/ethereum/keychain/calldata.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIHZBTCI/Q1M5E9r4P4VWDLOewcY+2BmgULfSvzYynWkqoAcGBSuBBAAK +oUQDQgAEgcCCHioUrCVG+wuYUvN8onidfXZIPXkhf7NvUdzh57QGca5YJUtFU1DS +ys87vfMyysGQtD1aymex2r+OcAa2RQ== +-----END EC PRIVATE KEY----- diff --git a/client/src/ledger_app_clients/ethereum/keychain/network.pem b/client/src/ledger_app_clients/ethereum/keychain/network.pem new file mode 100644 index 000000000..160a4aedb --- /dev/null +++ b/client/src/ledger_app_clients/ethereum/keychain/network.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQACg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHQCAQEEIBWMfLNb5rHjqi1tyaZ0toOPu9U0gUSSXOeNQ9k1C4jaoAcGBSuBBAAK +oUQDQgAEBK9c8yCU+FXpMjXp60P0jptDbC4d+upY7K+miq+x0nyHMUmG/f/vNNKW +0vGHFHx8FKpAaFSMAsUh92NlAg8ZJQ== +-----END EC PRIVATE KEY----- diff --git a/glyphs/chain_146_64px.gif b/glyphs/chain_146_64px.gif new file mode 100644 index 000000000..f77a2e966 Binary files /dev/null and b/glyphs/chain_146_64px.gif differ diff --git a/glyphs/chain_153153_64px.gif b/glyphs/chain_153153_64px.gif new file mode 100644 index 000000000..d6ee05c64 Binary files /dev/null and b/glyphs/chain_153153_64px.gif differ diff --git a/glyphs/chain_1666600000_64px.gif b/glyphs/chain_1666600000_64px.gif new file mode 100644 index 000000000..ebe181085 Binary files /dev/null and b/glyphs/chain_1666600000_64px.gif differ diff --git a/glyphs/chain_1666600001_64px.gif b/glyphs/chain_1666600001_64px.gif new file mode 120000 index 000000000..96de1d4cd --- /dev/null +++ b/glyphs/chain_1666600001_64px.gif @@ -0,0 +1 @@ +chain_1666600000_64px.gif \ No newline at end of file diff --git a/glyphs/chain_1868_64px.gif b/glyphs/chain_1868_64px.gif new file mode 100644 index 000000000..b5cabbf72 Binary files /dev/null and b/glyphs/chain_1868_64px.gif differ diff --git a/glyphs/chain_1923_64px.gif b/glyphs/chain_1923_64px.gif new file mode 100644 index 000000000..5e6cd050e Binary files /dev/null and b/glyphs/chain_1923_64px.gif differ diff --git a/glyphs/chain_1924_64px.gif b/glyphs/chain_1924_64px.gif new file mode 120000 index 000000000..f94eb26ee --- /dev/null +++ b/glyphs/chain_1924_64px.gif @@ -0,0 +1 @@ +chain_1923_64px.gif \ No newline at end of file diff --git a/glyphs/chain_1946_64px.gif b/glyphs/chain_1946_64px.gif new file mode 120000 index 000000000..23552aca5 --- /dev/null +++ b/glyphs/chain_1946_64px.gif @@ -0,0 +1 @@ +chain_1868_64px.gif \ No newline at end of file diff --git a/glyphs/chain_246785_64px.gif b/glyphs/chain_246785_64px.gif deleted file mode 100644 index 87b527dae..000000000 Binary files a/glyphs/chain_246785_64px.gif and /dev/null differ diff --git a/glyphs/chain_5165_64px.gif b/glyphs/chain_5165_64px.gif new file mode 100644 index 000000000..03839c7b8 Binary files /dev/null and b/glyphs/chain_5165_64px.gif differ diff --git a/glyphs/chain_8217_64px.gif b/glyphs/chain_8217_64px.gif index 787694c23..d6db41dcb 100644 Binary files a/glyphs/chain_8217_64px.gif and b/glyphs/chain_8217_64px.gif differ diff --git a/glyphs/chain_994873017_64px.gif b/glyphs/chain_994873017_64px.gif new file mode 100644 index 000000000..b4ab07b6b Binary files /dev/null and b/glyphs/chain_994873017_64px.gif differ diff --git a/icons/flex_app_chain_1666600000.gif b/icons/flex_app_chain_1666600000.gif new file mode 100644 index 000000000..6575822e6 Binary files /dev/null and b/icons/flex_app_chain_1666600000.gif differ diff --git a/icons/flex_app_chain_20531811.gif b/icons/flex_app_chain_20531811.gif deleted file mode 100644 index 8c09a8df3..000000000 Binary files a/icons/flex_app_chain_20531811.gif and /dev/null differ diff --git a/icons/flex_app_chain_246785.gif b/icons/flex_app_chain_246785.gif deleted file mode 100644 index 18860a44c..000000000 Binary files a/icons/flex_app_chain_246785.gif and /dev/null differ diff --git a/icons/flex_app_chain_73799.gif b/icons/flex_app_chain_73799.gif deleted file mode 100644 index 78e1fb5f3..000000000 Binary files a/icons/flex_app_chain_73799.gif and /dev/null differ diff --git a/icons/nanos_app_chain_1666600000.gif b/icons/nanos_app_chain_1666600000.gif new file mode 100644 index 000000000..6e4e96d16 Binary files /dev/null and b/icons/nanos_app_chain_1666600000.gif differ diff --git a/icons/nanos_app_chain_20531811.gif b/icons/nanos_app_chain_20531811.gif deleted file mode 100644 index 8f94d1db8..000000000 Binary files a/icons/nanos_app_chain_20531811.gif and /dev/null differ diff --git a/icons/nanos_app_chain_246785.gif b/icons/nanos_app_chain_246785.gif deleted file mode 100644 index e9525ae91..000000000 Binary files a/icons/nanos_app_chain_246785.gif and /dev/null differ diff --git a/icons/nanos_app_chain_73799.gif b/icons/nanos_app_chain_73799.gif deleted file mode 100644 index d15c9370d..000000000 Binary files a/icons/nanos_app_chain_73799.gif and /dev/null differ diff --git a/icons/nanox_app_chain_1666600000.gif b/icons/nanox_app_chain_1666600000.gif new file mode 100644 index 000000000..874e47094 Binary files /dev/null and b/icons/nanox_app_chain_1666600000.gif differ diff --git a/icons/nanox_app_chain_20531811.gif b/icons/nanox_app_chain_20531811.gif deleted file mode 100644 index 36a8eb705..000000000 Binary files a/icons/nanox_app_chain_20531811.gif and /dev/null differ diff --git a/icons/nanox_app_chain_246785.gif b/icons/nanox_app_chain_246785.gif deleted file mode 100644 index 47ceeb506..000000000 Binary files a/icons/nanox_app_chain_246785.gif and /dev/null differ diff --git a/icons/nanox_app_chain_73799.gif b/icons/nanox_app_chain_73799.gif deleted file mode 100644 index b0e43f0f8..000000000 Binary files a/icons/nanox_app_chain_73799.gif and /dev/null differ diff --git a/icons/stax_app_chain_1666600000.gif b/icons/stax_app_chain_1666600000.gif new file mode 100644 index 000000000..a7ab29206 Binary files /dev/null and b/icons/stax_app_chain_1666600000.gif differ diff --git a/icons/stax_app_chain_20531811.gif b/icons/stax_app_chain_20531811.gif deleted file mode 100644 index a1ccb2d47..000000000 Binary files a/icons/stax_app_chain_20531811.gif and /dev/null differ diff --git a/icons/stax_app_chain_246785.gif b/icons/stax_app_chain_246785.gif deleted file mode 100644 index 555be4a6d..000000000 Binary files a/icons/stax_app_chain_246785.gif and /dev/null differ diff --git a/icons/stax_app_chain_73799.gif b/icons/stax_app_chain_73799.gif deleted file mode 100644 index ea4c02447..000000000 Binary files a/icons/stax_app_chain_73799.gif and /dev/null differ diff --git a/makefile_conf/chain/artis_tau1.mk b/makefile_conf/chain/artis_tau1.mk deleted file mode 100644 index 6aacfccbd..000000000 --- a/makefile_conf/chain/artis_tau1.mk +++ /dev/null @@ -1,4 +0,0 @@ -PATH_APP_LOAD_PARAMS += "44'/246785'" -TICKER = "ATS" -CHAIN_ID = 246785 -APPNAME = "ARTIS tau1" diff --git a/makefile_conf/chain/harmony.mk b/makefile_conf/chain/harmony.mk new file mode 100644 index 000000000..de4b8adbb --- /dev/null +++ b/makefile_conf/chain/harmony.mk @@ -0,0 +1,4 @@ +PATH_APP_LOAD_PARAMS += "44'/1023'" +TICKER = "ONE" +CHAIN_ID = 1666600000 +APPNAME = "Harmony" \ No newline at end of file diff --git a/makefile_conf/chain/tecratestnet.mk b/makefile_conf/chain/tecratestnet.mk deleted file mode 100644 index 8135f4265..000000000 --- a/makefile_conf/chain/tecratestnet.mk +++ /dev/null @@ -1,4 +0,0 @@ -PATH_APP_LOAD_PARAMS += "44'/554'" -TICKER = "TCR" -CHAIN_ID = 20531811 -APPNAME = "TecraTestnet" diff --git a/makefile_conf/chain/volta.mk b/makefile_conf/chain/volta.mk deleted file mode 100644 index 136c5de02..000000000 --- a/makefile_conf/chain/volta.mk +++ /dev/null @@ -1,4 +0,0 @@ -PATH_APP_LOAD_PARAMS += "44'/73799'" -TICKER = "VOLTA" -CHAIN_ID = 73799 -APPNAME = "Volta" diff --git a/makefile_conf/features.mk b/makefile_conf/features.mk index b56dc9fee..615b8b2f7 100644 --- a/makefile_conf/features.mk +++ b/makefile_conf/features.mk @@ -62,6 +62,12 @@ ifneq ($(TARGET_NAME),TARGET_NANOS) endif endif +# Dynamic networks +ifneq ($(TARGET_NAME),TARGET_NANOS) + DEFINES += HAVE_DYNAMIC_NETWORKS +endif + + # Check features incompatibilities # -------------------------------- # NFTs diff --git a/src/main.c b/src/main.c index 3e4890801..3a0625f8f 100644 --- a/src/main.c +++ b/src/main.c @@ -147,9 +147,6 @@ static uint16_t handleApdu(command_t *cmd, uint32_t *flags, uint32_t *tx) { } switch (cmd->ins) { - case INS_PROVIDE_NETWORK_CONFIGURATION: - sw = handleNetworkConfiguration(cmd->p1, cmd->p2, cmd->data, cmd->lc, tx); - break; case INS_GET_PUBLIC_KEY: forget_known_assets(); sw = handleGetPublicKey(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags, tx); @@ -207,7 +204,6 @@ static uint16_t handleApdu(command_t *cmd, uint32_t *flags, uint32_t *tx) { break; #ifdef HAVE_ETH2 - case INS_GET_ETH2_PUBLIC_KEY: forget_known_assets(); sw = handleGetEth2PublicKey(cmd->p1, cmd->p2, cmd->data, cmd->lc, flags, tx); @@ -216,8 +212,7 @@ static uint16_t handleApdu(command_t *cmd, uint32_t *flags, uint32_t *tx) { case INS_SET_ETH2_WITHDRAWAL_INDEX: sw = handleSetEth2WithdrawalIndex(cmd->p1, cmd->p2, cmd->data, cmd->lc); break; - -#endif +#endif // HAVE_ETH2 #ifdef HAVE_EIP712_FULL_SUPPORT case INS_EIP712_STRUCT_DEF: @@ -259,6 +254,12 @@ static uint16_t handleApdu(command_t *cmd, uint32_t *flags, uint32_t *tx) { break; #endif // HAVE_GENERIC_TX_PARSER +#ifdef HAVE_DYNAMIC_NETWORKS + case INS_PROVIDE_NETWORK_CONFIGURATION: + sw = handleNetworkConfiguration(cmd->p1, cmd->p2, cmd->data, cmd->lc, tx); + break; +#endif // HAVE_DYNAMIC_NETWORKS + default: sw = APDU_RESPONSE_INVALID_INS; break; diff --git a/src/network.c b/src/network.c index 906e7e3d0..70ffef78f 100644 --- a/src/network.c +++ b/src/network.c @@ -35,6 +35,7 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 106, .name = "Velas EVM", .ticker = "VLX"}, {.chain_id = 137, .name = "Polygon", .ticker = "POL"}, {.chain_id = 138, .name = "Defi Oracle Meta", .ticker = "ETH"}, + {.chain_id = 146, .name = "Sonic", .ticker = "S"}, {.chain_id = 196, .name = "OKBChain Mainnet", .ticker = "OKB"}, {.chain_id = 199, .name = "BTTC", .ticker = "BTT"}, {.chain_id = 246, .name = "EnergyWebChain", .ticker = "EWT"}, @@ -57,7 +58,11 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 1284, .name = "Moonbeam", .ticker = "GLMR"}, {.chain_id = 1285, .name = "Moonriver", .ticker = "MOVR"}, {.chain_id = 1818, .name = "Cube", .ticker = "CUBE"}, + {.chain_id = 1868, .name = "Soneium", .ticker = "ETH"}, {.chain_id = 1907, .name = "Bitcichain", .ticker = "BITCI"}, + {.chain_id = 1923, .name = "Swellchain", .ticker = "ETH"}, + {.chain_id = 1924, .name = "Swellchain Testnet", .ticker = "ETH"}, + {.chain_id = 1946, .name = "Soneium Testnet Minato", .ticker = "ETH"}, {.chain_id = 2222, .name = "Kava EVM", .ticker = "KAVA"}, {.chain_id = 3776, .name = "Astar zkEVM", .ticker = "ETH"}, {.chain_id = 4201, .name = "LUKSO Testnet", .ticker = "LYXt"}, @@ -67,10 +72,11 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 4919, .name = "Venidium", .ticker = "XVM"}, {.chain_id = 5000, .name = "Mantle", .ticker = "MNT"}, {.chain_id = 5003, .name = "Mantle Sepolia", .ticker = "MNT"}, + {.chain_id = 5165, .name = "Bahamut", .ticker = "FTN"}, {.chain_id = 7000, .name = "ZetaChain", .ticker = "ZETA"}, {.chain_id = 7171, .name = "Bitrock Mainnet", .ticker = "BROCK"}, {.chain_id = 7341, .name = "Shyft", .ticker = "SHFT"}, - {.chain_id = 8217, .name = "Klaytn Cypress", .ticker = "KLAY"}, + {.chain_id = 8217, .name = "Kaia Mainnet", .ticker = "KAIA"}, {.chain_id = 8453, .name = "Base", .ticker = "ETH"}, {.chain_id = 9001, .name = "Evmos", .ticker = "EVMOS"}, {.chain_id = 10200, .name = "Chiado", .ticker = "xDAI"}, @@ -92,6 +98,7 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 73799, .name = "Volta", .ticker = "VOLTA"}, {.chain_id = 81457, .name = "Blast", .ticker = "ETH"}, {.chain_id = 84532, .name = "Base Sepolia", .ticker = "ETH"}, + {.chain_id = 153153, .name = "Odyssey Chain", .ticker = "DIONE"}, {.chain_id = 200810, .name = "Bitlayer Testnet", .ticker = "BTC"}, {.chain_id = 200901, .name = "Bitlayer", .ticker = "BTC"}, {.chain_id = 421614, .name = "Arbitrum Sepolia", .ticker = "ETH"}, @@ -108,11 +115,15 @@ static const network_info_t NETWORK_MAPPING[] = { {.chain_id = 168587773, .name = "Blast Sepolia", .ticker = "ETH"}, {.chain_id = 245022926, .name = "Neon EVM Devnet", .ticker = "NEON"}, {.chain_id = 245022934, .name = "Neon EVM Mainnet", .ticker = "NEON"}, + {.chain_id = 994873017, .name = "Lumia", .ticker = "LUMIA"}, + {.chain_id = 1666600000, .name = "Harmony ONE S0", .ticker = "ONE"}, + {.chain_id = 1666600001, .name = "Harmony ONE S1", .ticker = "ONE"}, {.chain_id = 11297108109, .name = "Palm Network", .ticker = "PALM"}, }; static const network_info_t *get_network_from_chain_id(const uint64_t *chain_id) { if (*chain_id != 0) { +#ifdef HAVE_DYNAMIC_NETWORKS // Look if the network is available for (size_t i = 0; i < MAX_DYNAMIC_NETWORKS; i++) { if (DYNAMIC_NETWORK_INFO[i].chain_id == *chain_id) { @@ -120,6 +131,8 @@ static const network_info_t *get_network_from_chain_id(const uint64_t *chain_id) return (const network_info_t *) &DYNAMIC_NETWORK_INFO[i]; } } +#endif // HAVE_DYNAMIC_NETWORKS + // Fallback to hardcoded table for (size_t i = 0; i < ARRAYLEN(NETWORK_MAPPING); i++) { if (NETWORK_MAPPING[i].chain_id == *chain_id) { diff --git a/src/shared_context.h b/src/shared_context.h index eaac84fb0..d329d043f 100644 --- a/src/shared_context.h +++ b/src/shared_context.h @@ -16,7 +16,7 @@ #include "nbgl_types.h" #endif -extern void app_exit(); +extern void app_exit(void); extern void common_app_init(void); #define SELECTOR_LENGTH 4 diff --git a/src_features/generic_tx_parser/cmd_tx_info.h b/src_features/generic_tx_parser/cmd_tx_info.h index a093669b4..d8c13442c 100644 --- a/src_features/generic_tx_parser/cmd_tx_info.h +++ b/src_features/generic_tx_parser/cmd_tx_info.h @@ -2,6 +2,7 @@ #define CMD_TX_INFO_H_ #include +#include "gtp_tx_info.h" uint16_t handle_tx_info(uint8_t p1, uint8_t p2, uint8_t lc, const uint8_t *payload); void gcs_cleanup(void); diff --git a/src_features/generic_tx_parser/gtp_param_datetime.c b/src_features/generic_tx_parser/gtp_param_datetime.c index ca3fdade0..2242aded1 100644 --- a/src_features/generic_tx_parser/gtp_param_datetime.c +++ b/src_features/generic_tx_parser/gtp_param_datetime.c @@ -68,7 +68,7 @@ bool format_param_datetime(const s_param_datetime *param, const char *name) { s_parsed_value_collection collec; char *buf = strings.tmp.tmp; size_t buf_size = sizeof(strings.tmp.tmp); - uint8_t time_buf[sizeof(uint32_t)]; + uint8_t time_buf[sizeof(uint32_t)] = {0}; time_t timestamp; uint256_t block_height; diff --git a/src_features/generic_tx_parser/gtp_param_duration.c b/src_features/generic_tx_parser/gtp_param_duration.c index d55a94e58..01eae53a5 100644 --- a/src_features/generic_tx_parser/gtp_param_duration.c +++ b/src_features/generic_tx_parser/gtp_param_duration.c @@ -60,7 +60,7 @@ bool format_param_duration(const s_param_duration *param, const char *name) { uint8_t minutes; uint8_t seconds; uint64_t remaining; - uint8_t raw_buf[sizeof(remaining)]; + uint8_t raw_buf[sizeof(remaining)] = {0}; int off; if (!value_get(¶m->value, &collec)) { diff --git a/src_features/generic_tx_parser/gtp_param_trusted_name.c b/src_features/generic_tx_parser/gtp_param_trusted_name.c index 5fffb9fe2..4c6c27989 100644 --- a/src_features/generic_tx_parser/gtp_param_trusted_name.c +++ b/src_features/generic_tx_parser/gtp_param_trusted_name.c @@ -78,7 +78,7 @@ bool format_param_trusted_name(const s_param_trusted_name *param, const char *na char *buf = strings.tmp.tmp; size_t buf_size = sizeof(strings.tmp.tmp); uint64_t chain_id; - uint8_t addr[ADDRESS_LENGTH]; + uint8_t addr[ADDRESS_LENGTH] = {0}; const char *tname; e_param_type param_type; diff --git a/src_features/generic_tx_parser/gtp_tx_info.c b/src_features/generic_tx_parser/gtp_tx_info.c index 7913ab08d..39ed016ca 100644 --- a/src_features/generic_tx_parser/gtp_tx_info.c +++ b/src_features/generic_tx_parser/gtp_tx_info.c @@ -55,7 +55,7 @@ static bool handle_version(const s_tlv_data *data, s_tx_info_ctx *context) { static bool handle_chain_id(const s_tlv_data *data, s_tx_info_ctx *context) { uint64_t chain_id; - uint8_t buf[sizeof(chain_id)]; + uint8_t buf[sizeof(chain_id)] = {0}; if (data->length > sizeof(buf)) { return false; @@ -72,7 +72,7 @@ static bool handle_chain_id(const s_tlv_data *data, s_tx_info_ctx *context) { } static bool handle_contract_addr(const s_tlv_data *data, s_tx_info_ctx *context) { - uint8_t buf[ADDRESS_LENGTH]; + uint8_t buf[ADDRESS_LENGTH] = {0}; if (data->length > sizeof(buf)) { return false; @@ -165,7 +165,7 @@ static bool handle_contract_name(const s_tlv_data *data, s_tx_info_ctx *context) } static bool handle_deploy_date(const s_tlv_data *data, s_tx_info_ctx *context) { - uint8_t buf[sizeof(uint32_t)]; + uint8_t buf[sizeof(uint32_t)] = {0}; time_t timestamp; if (data->length > sizeof(buf)) { @@ -281,14 +281,14 @@ bool verify_tx_info_struct(const s_tx_info_ctx *context) { return false; } - // TODO: change to LEDGER_CALLDATA_DESCRIPTOR key once available if (check_signature_with_pubkey("TX info", hash, sizeof(hash), - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), + NULL, + 0, #ifdef HAVE_LEDGER_PKI - CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, + // TODO: change once SDK has the enum value for this + 0x0b, #endif (uint8_t *) context->tx_info->signature, context->tx_info->signature_len) != CX_OK) { diff --git a/src_features/provideDynamicNetwork/network_dynamic.c b/src_features/provideDynamicNetwork/network_dynamic.c index 3ff7d7c09..32a9db20a 100644 --- a/src_features/provideDynamicNetwork/network_dynamic.c +++ b/src_features/provideDynamicNetwork/network_dynamic.c @@ -1,3 +1,5 @@ +#ifdef HAVE_DYNAMIC_NETWORKS + #include #include #include "os_utils.h" @@ -288,6 +290,7 @@ static uint16_t parse_icon_buffer(void) { uint8_t digest[CX_SHA256_SIZE]; const uint8_t *data = g_network_icon[g_current_slot].bitmap; const uint16_t field_len = g_icon_payload.received_size; + cx_err_t error = CX_INTERNAL_ERROR; // Check the icon header sw = check_icon_header(data, field_len, &img_len); @@ -298,7 +301,7 @@ static uint16_t parse_icon_buffer(void) { CHECK_FIELD_OVERFLOW("NETWORK_ICON", g_network_icon[g_current_slot].bitmap); // Check icon hash - cx_sha256_hash(data, field_len, digest); + CX_CHECK(cx_sha256_hash(data, field_len, digest)); if (memcmp(digest, g_network_icon[g_current_slot].hash, CX_SHA256_SIZE) != 0) { PRINTF("NETWORK_ICON hash mismatch!\n"); return APDU_RESPONSE_INVALID_DATA; @@ -313,7 +316,9 @@ static uint16_t parse_icon_buffer(void) { DYNAMIC_NETWORK_INFO[g_current_slot].icon.isFile = true; COPY_FIELD(DYNAMIC_NETWORK_INFO[g_current_slot].icon.bitmap); print_icon_info(); - return APDU_RESPONSE_OK; + error = APDU_RESPONSE_OK; +end: + return error; } /** @@ -376,6 +381,12 @@ static uint16_t handle_next_icon_chunk(const uint8_t *data, uint8_t length) { */ static uint16_t handle_icon_chunks(uint8_t p1, const uint8_t *data, uint8_t length) { uint16_t sw = APDU_RESPONSE_UNKNOWN; + uint8_t hash[CX_SHA256_SIZE] = {0}; + + if (memcmp(g_network_icon[g_current_slot].hash, hash, CX_SHA256_SIZE) == 0) { + PRINTF("Error: Icon hash not set!\n"); + return APDU_RESPONSE_INVALID_DATA; + } // Check the received chunk index if (p1 == P1_FIRST_CHUNK) { @@ -426,26 +437,26 @@ static uint16_t parse_signature(const uint8_t *data, uint16_t field_len, s_sig_c */ static bool verify_signature(s_sig_ctx *sig_ctx) { uint8_t hash[INT256_LENGTH]; - cx_err_t error = CX_INTERNAL_ERROR; - bool ret_code = false; - CX_CHECK( - cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); + if (cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH) != + CX_OK) { + return false; + } - CX_CHECK(check_signature_with_pubkey("Dynamic Network", - hash, - sizeof(hash), - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), + if (check_signature_with_pubkey("Dynamic Network", + hash, + sizeof(hash), + NULL, + 0, #ifdef HAVE_LEDGER_PKI - CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, + // TODO: change once SDK has the enum value for this + 0x0c, #endif - (uint8_t *) (sig_ctx->sig), - sig_ctx->sig_size)); - - ret_code = true; -end: - return ret_code; + (uint8_t *) (sig_ctx->sig), + sig_ctx->sig_size) != CX_OK) { + return false; + } + return true; } /** @@ -647,3 +658,5 @@ uint16_t handleNetworkConfiguration(uint8_t p1, return sw; } + +#endif // HAVE_DYNAMIC_NETWORKS diff --git a/src_features/provideTrustedName/cmd_provide_trusted_name.c b/src_features/provideTrustedName/cmd_provide_trusted_name.c index a540c2369..ffb98e671 100644 --- a/src_features/provideTrustedName/cmd_provide_trusted_name.c +++ b/src_features/provideTrustedName/cmd_provide_trusted_name.c @@ -613,7 +613,7 @@ static bool verify_signature(const s_sig_ctx *sig_ctx) { CX_CHECK( cx_hash_no_throw((cx_hash_t *) &sig_ctx->hash_ctx, CX_LAST, NULL, 0, hash, INT256_LENGTH)); - CX_CHECK(check_signature_with_pubkey("Domain Name", + CX_CHECK(check_signature_with_pubkey("Trusted Name", hash, sizeof(hash), pk, @@ -822,7 +822,7 @@ static bool parse_tlv(const s_tlv_payload *payload, {.tag = NFT_ID, .func = &handle_nft_id}, }; e_tlv_step step = TLV_TAG; - s_tlv_data data; + s_tlv_data data = {0}; size_t offset = 0; size_t tag_start_off; diff --git a/src_features/provide_enum_value/enum_value.c b/src_features/provide_enum_value/enum_value.c index 64cf2fc30..84c34d40e 100644 --- a/src_features/provide_enum_value/enum_value.c +++ b/src_features/provide_enum_value/enum_value.c @@ -28,7 +28,7 @@ static bool handle_version(const s_tlv_data *data, s_enum_value_ctx *context) { } static bool handle_chain_id(const s_tlv_data *data, s_enum_value_ctx *context) { - uint8_t buf[sizeof(context->enum_value.entry.chain_id)]; + uint8_t buf[sizeof(context->enum_value.entry.chain_id)] = {0}; if (data->length > sizeof(buf)) { return false; @@ -150,14 +150,14 @@ bool verify_enum_value_struct(const s_enum_value_ctx *context) { PRINTF("Could not finalize struct hash!\n"); return false; } - // TODO: change to LEDGER_CALLDATA_DESCRIPTOR key once available if (check_signature_with_pubkey("enum value", hash, sizeof(hash), - LEDGER_SIGNATURE_PUBLIC_KEY, - sizeof(LEDGER_SIGNATURE_PUBLIC_KEY), + NULL, + 0, #ifdef HAVE_LEDGER_PKI - CERTIFICATE_PUBLIC_KEY_USAGE_COIN_META, + // TODO: change once SDK has the enum value for this + 0x0b, #endif (uint8_t *) context->enum_value.signature, context->enum_value.signature_length) != CX_OK) { diff --git a/src_features/signTx/logic_signTx.c b/src_features/signTx/logic_signTx.c index 1f9085346..6d3c304ca 100644 --- a/src_features/signTx/logic_signTx.c +++ b/src_features/signTx/logic_signTx.c @@ -343,7 +343,7 @@ __attribute__((noreturn)) void send_swap_error(uint8_t error_code, const char *str1, const char *str2) { uint32_t tx = 0; - uint len = 0; + size_t len = 0; PRINTF("APDU_RESPONSE_MODE_CHECK_FAILED: 0x%x\n", error_code); // Set RAPDU error codes G_io_apdu_buffer[tx++] = error_code; diff --git a/src_plugins/erc20/erc20_plugin.c b/src_plugins/erc20/erc20_plugin.c index c7a5af884..b15268c33 100644 --- a/src_plugins/erc20/erc20_plugin.c +++ b/src_plugins/erc20/erc20_plugin.c @@ -7,8 +7,6 @@ typedef enum { ERC20_TRANSFER = 0, ERC20_APPROVE } erc20Selector_t; -typedef enum { TARGET_ADDRESS = 0, TARGET_CONTRACT } targetType_t; - #define MAX_CONTRACT_NAME_LEN 15 typedef struct erc20_parameters_t { @@ -17,61 +15,9 @@ typedef struct erc20_parameters_t { uint8_t amount[INT256_LENGTH]; char ticker[MAX_TICKER_LEN]; uint8_t decimals; - uint8_t target; char contract_name[MAX_CONTRACT_NAME_LEN]; } erc20_parameters_t; -typedef struct contract_t { - char name[MAX_CONTRACT_NAME_LEN]; - uint8_t address[ADDRESS_LENGTH]; -} contract_t; - -#define NUM_CONTRACTS 13 -const contract_t CONTRACTS[NUM_CONTRACTS] = { - // Compound - {"Compound DAI", {0x5d, 0x3a, 0x53, 0x6e, 0x4d, 0x6d, 0xbd, 0x61, 0x14, 0xcc, - 0x1e, 0xad, 0x35, 0x77, 0x7b, 0xab, 0x94, 0x8e, 0x36, 0x43}}, - {"Compound ETH", {0x4d, 0xdc, 0x2d, 0x19, 0x39, 0x48, 0x92, 0x6d, 0x02, 0xf9, - 0xb1, 0xfe, 0x9e, 0x1d, 0xaa, 0x07, 0x18, 0x27, 0x0e, 0xd5}}, - {"Compound USDC", {0x39, 0xaa, 0x39, 0xc0, 0x21, 0xdf, 0xba, 0xe8, 0xfa, 0xc5, - 0x45, 0x93, 0x66, 0x93, 0xac, 0x91, 0x7d, 0x5e, 0x75, 0x63}}, - {"Compound ZRX", {0xb3, 0x31, 0x9f, 0x5d, 0x18, 0xbc, 0x0d, 0x84, 0xdd, 0x1b, - 0x48, 0x25, 0xdc, 0xde, 0x5d, 0x5f, 0x72, 0x66, 0xd4, 0x07}}, - {"Compound USDT", {0xf6, 0x50, 0xc3, 0xd8, 0x8d, 0x12, 0xdb, 0x85, 0x5b, 0x8b, - 0xf7, 0xd1, 0x1b, 0xe6, 0xc5, 0x5a, 0x4e, 0x07, 0xdc, 0xc9}}, - {"Compound WBTC", {0xc1, 0x1b, 0x12, 0x68, 0xc1, 0xa3, 0x84, 0xe5, 0x5c, 0x48, - 0xc2, 0x39, 0x1d, 0x8d, 0x48, 0x02, 0x64, 0xa3, 0xa7, 0xf4}}, - {"Compound BAT", {0x6c, 0x8c, 0x6b, 0x02, 0xe7, 0xb2, 0xbe, 0x14, 0xd4, 0xfa, - 0x60, 0x22, 0xdf, 0xd6, 0xd7, 0x59, 0x21, 0xd9, 0x0e, 0x4e}}, - {"Compound REP", {0x15, 0x80, 0x79, 0xee, 0x67, 0xfc, 0xe2, 0xf5, 0x84, 0x72, - 0xa9, 0x65, 0x84, 0xa7, 0x3c, 0x7a, 0xb9, 0xac, 0x95, 0xc1}}, - {"Compound SAI", {0xf5, 0xdc, 0xe5, 0x72, 0x82, 0xa5, 0x84, 0xd2, 0x74, 0x6f, - 0xaf, 0x15, 0x93, 0xd3, 0x12, 0x1f, 0xca, 0xc4, 0x44, 0xdc}}, - {"Compound UNI", {0x35, 0xa1, 0x80, 0x00, 0x23, 0x0d, 0xa7, 0x75, 0xca, 0xc2, - 0x48, 0x73, 0xd0, 0x0f, 0xf8, 0x5b, 0xcc, 0xde, 0xd5, 0x50}}, - // Paraswap - {"Paraswap", {0x1b, 0xd4, 0x35, 0xf3, 0xc0, 0x54, 0xb6, 0xe9, 0x01, 0xb7, - 0xb1, 0x08, 0xa0, 0xab, 0x76, 0x17, 0xc8, 0x08, 0x67, 0x7b}}, - - // stETH - {"Lido", {0x7f, 0x39, 0xc5, 0x81, 0xf5, 0x95, 0xb5, 0x3c, 0x5c, 0xb1, - 0x9b, 0xd0, 0xb3, 0xf8, 0xda, 0x6c, 0x93, 0x5e, 0x2c, 0xa0}}, - - // wstETH - {"Wrapped stETH", {0xae, 0x7a, 0xb9, 0x65, 0x20, 0xde, 0x3a, 0x18, 0xe5, 0xe1, - 0x11, 0xb5, 0xea, 0xab, 0x09, 0x53, 0x12, 0xd7, 0xfe, 0x84}}}; - -bool check_contract(erc20_parameters_t *context) { - for (size_t i = 0; i < NUM_CONTRACTS; i++) { - const contract_t *contract = (const contract_t *) PIC(&CONTRACTS[i]); - if (memcmp(contract->address, context->destinationAddress, ADDRESS_LENGTH) == 0) { - strlcpy(context->contract_name, contract->name, sizeof(context->contract_name)); - return true; - } - } - return false; -} - void erc20_plugin_call(int message, void *parameters) { switch (message) { case ETH_PLUGIN_INIT_CONTRACT: { @@ -148,14 +94,8 @@ void erc20_plugin_call(int message, void *parameters) { (msg->item1 != NULL), (msg->item2 != NULL)); if (msg->item1 != NULL) { - context->target = TARGET_ADDRESS; strlcpy(context->ticker, msg->item1->token.ticker, MAX_TICKER_LEN); context->decimals = msg->item1->token.decimals; - if (context->selectorIndex == ERC20_APPROVE) { - if (check_contract(context)) { - context->target = TARGET_CONTRACT; - } - } msg->result = ETH_PLUGIN_RESULT_OK; } else { msg->result = ETH_PLUGIN_RESULT_FALLBACK; @@ -196,19 +136,13 @@ void erc20_plugin_call(int message, void *parameters) { msg->result = ETH_PLUGIN_RESULT_OK; break; case 1: - if (context->target >= TARGET_CONTRACT) { - strlcpy(msg->title, "Contract", msg->titleLength); - strlcpy(msg->msg, context->contract_name, msg->msgLength); - } else { - strlcpy(msg->title, "Approve to", msg->titleLength); - if (!getEthDisplayableAddress(context->destinationAddress, - msg->msg, - msg->msgLength, - chainConfig->chainId)) { - msg->result = ETH_PLUGIN_RESULT_ERROR; - } + strlcpy(msg->title, "Approve to", msg->titleLength); + if (!getEthDisplayableAddress(context->destinationAddress, + msg->msg, + msg->msgLength, + chainConfig->chainId)) { + msg->result = ETH_PLUGIN_RESULT_ERROR; } - msg->result = ETH_PLUGIN_RESULT_OK; break; default: diff --git a/tests/fuzzing/CMakeLists.txt b/tests/fuzzing/CMakeLists.txt new file mode 100644 index 000000000..8ef8e5081 --- /dev/null +++ b/tests/fuzzing/CMakeLists.txt @@ -0,0 +1,220 @@ +cmake_minimum_required(VERSION 3.14) + +# project information +project(EthereumAppFuzzer + VERSION 1.0 + DESCRIPTION "Eth Fuzzer" + LANGUAGES C) + +if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "Fuzzer needs to be built with Clang") +endif() + +# guard against bad build-type strings +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") +endif() + +# default fuzz device target +if (NOT TARGET_DEVICE) + set(TARGET_DEVICE "flex") +endif() + +if (NOT DEFINED BOLOS_SDK) + set(BOLOS_SDK /opt/${TARGET_DEVICE}-secure-sdk) +endif() + +# compatible with ClusterFuzzLite +if (NOT DEFINED ENV{LIB_FUZZING_ENGINE}) + set(COMPILATION_FLAGS -g -O0 -Wall -Wextra -fprofile-instr-generate -fcoverage-mapping) + if (SANITIZER MATCHES "address") + set(COMPILATION_FLAGS ${COMPILATION_FLAGS} -fsanitize=fuzzer,address,undefined) + elseif (SANITIZER MATCHES "memory") + set(COMPILATION_FLAGS ${COMPILATION_FLAGS} -fsanitize=fuzzer,memory,undefined -fsanitize-memory-track-origins -fsanitize=fuzzer-no-link) + else() + message(FATAL_ERROR "Unkown sanitizer type. It must be set to `address` or `memory`.") + endif() +else() + set(COMPILATION_FLAGS "$ENV{LIB_FUZZING_ENGINE} $ENV{CFLAGS}") + separate_arguments(COMPILATION_FLAGS) +endif() + +# guard against in-source builds +if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) + message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") +endif() + +set(DEFINES + gcc + APPNAME=\"Fuzzing\" + API_LEVEL=21 + TARGET=\"flex\" + TARGET_NAME=\"TARGET_FUZZ\" + APPVERSION=\"1.1.0\" + SDK_NAME=\"ledger-secure-sdk\" + SDK_VERSION=\"v21.3.3\" + SDK_HASH=\"d88d4db3c93665f52b5b1f45099d9d36dfaa06ba\" + gcc + __IO=volatile + NDEBUG + HAVE_BAGL_FONT_INTER_REGULAR_28PX + HAVE_BAGL_FONT_INTER_SEMIBOLD_28PX + HAVE_BAGL_FONT_INTER_MEDIUM_36PX + HAVE_INAPP_BLE_PAIRING + HAVE_NBGL + HAVE_PIEZO_SOUND + HAVE_SE_TOUCH + HAVE_SE_EINK_DISPLAY + NBGL_PAGE + NBGL_USE_CASE + SCREEN_SIZE_WALLET + HAVE_FAST_HOLD_TO_APPROVE + HAVE_LEDGER_PKI + HAVE_NES_CRYPT + HAVE_ST_AES + NATIVE_LITTLE_ENDIAN + HAVE_CRC + HAVE_HASH + HAVE_RIPEMD160 + HAVE_SHA224 + HAVE_SHA256 + HAVE_SHA3 + HAVE_SHA384 + HAVE_SHA512 + HAVE_SHA512_WITH_BLOCK_ALT_METHOD + HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 + HAVE_BLAKE2 + HAVE_HMAC + HAVE_PBKDF2 + HAVE_AES + HAVE_MATH + HAVE_RNG + HAVE_RNG_RFC6979 + HAVE_RNG_SP800_90A + HAVE_ECC + HAVE_ECC_WEIERSTRASS + HAVE_ECC_TWISTED_EDWARDS + HAVE_ECC_MONTGOMERY + HAVE_SECP256K1_CURVE + HAVE_SECP256R1_CURVE + HAVE_SECP384R1_CURVE + HAVE_SECP521R1_CURVE + HAVE_FR256V1_CURVE + HAVE_STARK256_CURVE + HAVE_BRAINPOOL_P256R1_CURVE + HAVE_BRAINPOOL_P256T1_CURVE + HAVE_BRAINPOOL_P320R1_CURVE + HAVE_BRAINPOOL_P320T1_CURVE + HAVE_BRAINPOOL_P384R1_CURVE + HAVE_BRAINPOOL_P384T1_CURVE + HAVE_BRAINPOOL_P512R1_CURVE + HAVE_BRAINPOOL_P512T1_CURVE + HAVE_BLS12_381_G1_CURVE + HAVE_CV25519_CURVE + HAVE_CV448_CURVE + HAVE_ED25519_CURVE + HAVE_ED448_CURVE + HAVE_ECDH + HAVE_ECDSA + HAVE_EDDSA + HAVE_ECSCHNORR + HAVE_X25519 + HAVE_X448 + HAVE_AES_GCM + HAVE_CMAC + HAVE_AES_SIV + COIN_VARIANT=1 + HAVE_BOLOS_APP_STACK_CANARY + IO_SEPROXYHAL_BUFFER_SIZE_B=300 + HAVE_BLE + BLE_COMMAND_TIMEOUT_MS=2000 + HAVE_BLE_APDU + BLE_SEGMENT_SIZE=32 + HAVE_DEBUG_THROWS + NBGL_QRCODE + MAJOR_VERSION=1 + MINOR_VERSION=1 + PATCH_VERSION=0 + IO_HID_EP_LENGTH=64 + HAVE_SPRINTF + HAVE_SNPRINTF_FORMAT_U + HAVE_IO_USB + HAVE_L4_USBLIB + IO_USB_MAX_ENDPOINTS=4 + HAVE_USB_APDU + USB_SEGMENT_SIZE=64 + HAVE_WEBUSB + WEBUSB_URL_SIZE_B=0 + WEBUSB_URL= + OS_IO_SEPROXYHAL + STANDARD_APP_SYNC_RAPDU + HAVE_GENERIC_TX_PARSER + HAVE_TRUSTED_NAME + HAVE_DYN_MEM_ALLOC + HAVE_SWAP + HAVE_ENUM_VALUE + HAVE_NFT_SUPPORT + HAVE_DYNAMIC_NETWORKS + explicit_bzero=bzero # Fix for https://github.com/google/sanitizers/issues/1507 +) + +add_compile_definitions(${DEFINES}) + +FILE( + GLOB_RECURSE SDK_STD_SOURCES + ${BOLOS_SDK}/lib_standard_app/*.c + ${CMAKE_SOURCE_DIR}/../../ethereum-plugin-sdk/src/*.c + ./src/mock.c +) +list( + REMOVE_ITEM SDK_STD_SOURCES + ${BOLOS_SDK}/lib_standard_app/io.c + ${CMAKE_SOURCE_DIR}/../../ethereum-plugin-sdk/src/main.c + ${BOLOS_SDK}/lib_standard_app/main.c + ${BOLOS_SDK}/lib_standard_app/crypto_helpers.c +) + +include_directories( + ${CMAKE_SOURCE_DIR}/../../ethereum-plugin-sdk/src/ + ${CMAKE_SOURCE_DIR}/../../src + ${CMAKE_SOURCE_DIR}/../../src_features/generic_tx_parser/ + ${CMAKE_SOURCE_DIR}/../../src_features/provide_enum_value/ + ${CMAKE_SOURCE_DIR}/../../src_features/provideDynamicNetwork/ + ${CMAKE_SOURCE_DIR}/../../src_features/signTx/ + ${CMAKE_SOURCE_DIR}/../../src_features/provideTrustedName/ + ${CMAKE_SOURCE_DIR}/../../src_features/getChallenge/ + ${CMAKE_SOURCE_DIR}/../../src_features/signMessageEIP712/ + ${BOLOS_SDK}/include + ${BOLOS_SDK}/target/${TARGET_DEVICE}/include + ${BOLOS_SDK}/lib_cxng/include + ${BOLOS_SDK}/lib_cxng/src + ${BOLOS_SDK}/lib_ux_nbgl + ${BOLOS_SDK}/lib_nbgl/include + ${BOLOS_SDK}/lib_standard_app/ + ${CMAKE_SOURCE_DIR}/src/ +) + +FILE(GLOB_RECURSE SOURCES + ${CMAKE_SOURCE_DIR}/../../src_features/generic_tx_parser/*.c + ${CMAKE_SOURCE_DIR}/../../src_features/provideTrustedName/*.c + ${CMAKE_SOURCE_DIR}/../../src_features/getChallenge/*.c + ${CMAKE_SOURCE_DIR}/../../src_features/provide_enum_value/*.c + ${CMAKE_SOURCE_DIR}/../../src_features/provideDynamicNetwork/*.c + ${CMAKE_SOURCE_DIR}/../../src_features/provideNFTInformation/*.c + ${CMAKE_SOURCE_DIR}/../../src/mem.c + ${CMAKE_SOURCE_DIR}/../../src/mem_utils.c + ${CMAKE_SOURCE_DIR}/../../src/network.c + ${CMAKE_SOURCE_DIR}/../../src/tlv.c + ${CMAKE_SOURCE_DIR}/../../src/tlv_apdu.c + ${CMAKE_SOURCE_DIR}/../../src/uint128.c + ${CMAKE_SOURCE_DIR}/../../src/uint256.c + ${CMAKE_SOURCE_DIR}/../../src/time_format.c + ${CMAKE_SOURCE_DIR}/../../src/uint_common.c + ${CMAKE_SOURCE_DIR}/../../src/utils.c + ${CMAKE_SOURCE_DIR}/../../src/manage_asset_info.c + ${CMAKE_SOURCE_DIR}/../../src/hash_bytes.c +) + +add_executable(fuzzer src/fuzzer.c ${SDK_STD_SOURCES} ${SOURCES}) +target_compile_options(fuzzer PRIVATE ${COMPILATION_FLAGS}) +target_link_options(fuzzer PRIVATE ${COMPILATION_FLAGS}) diff --git a/tests/fuzzing/README.md b/tests/fuzzing/README.md new file mode 100644 index 000000000..89db1e283 --- /dev/null +++ b/tests/fuzzing/README.md @@ -0,0 +1,84 @@ +# Fuzzing Tests + +## Fuzzing + +Fuzzing allows us to test how a program behaves when provided with invalid, unexpected, or random data as input. + +Our fuzz target needs to implement `int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)`, +which provides an array of random bytes that can be used to simulate a serialized buffer. +If the application crashes, or a [sanitizer](https://github.com/google/sanitizers) detects +any kind of access violation, the fuzzing process is stopped, a report regarding the vulnerability is shown, +and the input that triggered the bug is written to disk under the name `crash-*`. +The vulnerable input file created can be passed as an argument to the fuzzer to triage the issue. + + +## Manual usage based on Ledger container + +### Preparation + +The fuzzer can run from the docker `ledger-app-builder-legacy`. You can download it from the `ghcr.io` docker repository: + +```console +sudo docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest +``` + +You can then enter this development environment by executing the following command from the repository root directory: + +```console +sudo docker run --rm -ti --user "$(id -u):$(id -g)" -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest +``` + +### Compilation + +Once in the container, go into the `tests/fuzzing` folder to compile the fuzzer: + +```console +cd tests/fuzzing + +# cmake initialization +cmake -DBOLOS_SDK=/opt/ledger-secure-sdk -DCMAKE_C_COMPILER=/usr/bin/clang -DSANITIZER=[address|memory] -B build -S . + +# Fuzzer compilation +cmake --build build +``` + +### Run + +```console +./build/fuzzer -max_len=8192 +``` + +If you want to do a fuzzing campain on more than one core and compute the coverage results, you can use the `local_run.sh` script within the container (it'll only run the address and UB sanitizers). + +## Full usage based on `clusterfuzzlite` container + +Exactly the same context as the CI, directly using the `clusterfuzzlite` environment. + +More info can be found here: + + +### Preparation + +The principle is to build the container, and run it to perform the fuzzing. + +> **Note**: The container contains a copy of the sources (they are not cloned), +> which means the `docker build` command must be re-executed after each code modification. + +```console +# Prepare directory tree +mkdir tests/fuzzing/{corpus,out} +# Container generation +docker build -t app-ethereum --file .clusterfuzzlite/Dockerfile . +``` + +### Compilation + +```console +docker run --rm --privileged -e FUZZING_LANGUAGE=c -v "$(realpath .)/tests/fuzzing/out:/out" -ti app-ethereum +``` + +### Run + +```console +docker run --rm --privileged -e FUZZING_ENGINE=libfuzzer -e RUN_FUZZER_MODE=interactive -v "$(realpath .)/tests/fuzzing/corpus:/tmp/fuzz_corpus" -v "$(realpath .)/tests/fuzzing/out:/out" -ti gcr.io/oss-fuzz-base/base-runner run_fuzzer fuzzer +``` diff --git a/tests/fuzzing/local_run.sh b/tests/fuzzing/local_run.sh new file mode 100755 index 000000000..cbc179247 --- /dev/null +++ b/tests/fuzzing/local_run.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Clean +rm -rf build + +# Build the fuzzer +cmake -B build -S . -DCMAKE_C_COMPILER=/usr/bin/clang -DSANITIZER=address +cmake --build build + +# Create the corpus directory if it doesn't exist +if ! [ -d ./corpus ]; then + mkdir corpus +fi + +# Run the fuzzer on half CPU cores +ncpus=$(nproc) +jobs=$(($ncpus/2)) +echo "The fuzzer will start very soon, press Ctrl-C when you want to stop it and compute the coverage" +./build/fuzzer -max_len=8192 -jobs="$jobs" ./corpus + + +read -p "Would you like to compute coverage (y/n)? " -n 1 -r +echo +if [[ $REPLY =~ ^[Nn]$ ]] +then + exit 0 +fi + +# Remove previous artifcats +rm default.profdata default.profraw + +# Run profiling on the corpus +./build/fuzzer -max_len=8192 -runs=0 ./corpus + +# Compute coverage +llvm-profdata merge -sparse *.profraw -o default.profdata +llvm-cov show build/fuzzer -instr-profile=default.profdata -format=html -ignore-filename-regex='ethereum-plugin-sdk\/|secure-sdk\/' > report.html +llvm-cov report build/fuzzer -instr-profile=default.profdata -ignore-filename-regex='ethereum-plugin-sdk\/|secure-sdk\/' diff --git a/tests/fuzzing/src/fuzzer.c b/tests/fuzzing/src/fuzzer.c new file mode 100644 index 000000000..3b024c80b --- /dev/null +++ b/tests/fuzzing/src/fuzzer.c @@ -0,0 +1,140 @@ +#include +#include + +#include "network_dynamic.h" + +#include "cmd_field.h" +#include "cmd_tx_info.h" +#include "cmd_enum_value.h" + +#include "gtp_field.h" +#include "gtp_tx_info.h" +#include "enum_value.h" + +#include "shared_context.h" +#include "tlv.h" +#include "apdu_constants.h" + +// Fuzzing harness interface +typedef int (*harness)(const uint8_t *data, size_t size); + +// Global state required by the app features +cx_sha3_t sha3; +unsigned char G_io_apdu_buffer[260]; +tmpContent_t tmpContent; +txContext_t txContext; +txContent_t txContent; +chain_config_t config = { + .coinName = "FUZZ", + .chainId = 0x42, +}; +const chain_config_t *chainConfig = &config; +uint8_t appState; +tmpCtx_t tmpCtx; +strings_t strings; + +int fuzzGenericParserFieldCmd(const uint8_t *data, size_t size) { + s_field field = {0}; + s_field_ctx ctx = {0}; + ctx.field = &field; + + if (!tlv_parse(data, size, (f_tlv_data_handler) &handle_field_struct, &ctx)) return 1; + + if (!verify_field_struct(&ctx)) return 1; + + return format_field(&field); +} + +int fuzzGenericParserTxInfoCmd(const uint8_t *data, size_t size) { + s_tx_info tx_info = {0}; + s_tx_info_ctx ctx = {0}; + ctx.tx_info = &tx_info; + + if (!tlv_parse(data, size, (f_tlv_data_handler) &handle_tx_info_struct, &ctx)) return 1; + + return verify_tx_info_struct(&ctx); +} + +int fuzzGenericParserEnumCmd(const uint8_t *data, size_t size) { + s_enum_value_ctx ctx = {0}; + + if (!tlv_parse(data, size, (f_tlv_data_handler) &handle_enum_value_struct, &ctx)) return 1; + + return verify_enum_value_struct(&ctx); +} + +int fuzzDynamicNetworks(const uint8_t *data, size_t size) { + size_t offset = 0; + size_t len = 0; + uint8_t p1; + uint8_t p2; + unsigned int tx; + + while (size - offset > 4) { + if (data[offset++] == 0) break; + p1 = data[offset++]; + p2 = data[offset++]; + len = data[offset++]; + if (size - offset < len) return 0; + if (handleNetworkConfiguration(p1, p2, data + offset, len, &tx) != APDU_RESPONSE_OK) + return 1; + offset += len; + } + return 0; +} + +int fuzzTrustedNames(const uint8_t *data, size_t size) { + size_t offset = 0; + size_t len = 0; + uint8_t p1; + + while (size - offset > 3) { + if (data[offset++] == 0) break; + p1 = data[offset++]; + len = data[offset++]; + if (size - offset < len) return 0; + if (handle_provide_trusted_name(p1, data + offset, len) != APDU_RESPONSE_OK) return 1; + offset += len; + } + return 0; +} + +int fuzzNFTInfo(const uint8_t *data, size_t size) { + unsigned int tx; + return handleProvideNFTInformation(data, size, &tx) != APDU_RESPONSE_OK; +} + +// Array of fuzzing harness functions +harness harnesses[] = { + fuzzGenericParserFieldCmd, + fuzzGenericParserTxInfoCmd, + fuzzGenericParserEnumCmd, + fuzzDynamicNetworks, + fuzzTrustedNames, + fuzzNFTInfo, +}; + +/* Main fuzzing handler called by libfuzzer */ +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // Clear global structures to ensure a clean state for each fuzzing iteration + explicit_bzero(&tmpContent, sizeof(tmpContent_t)); + explicit_bzero(&txContext, sizeof(txContext_t)); + explicit_bzero(&txContent, sizeof(txContent_t)); + explicit_bzero(&tmpCtx, sizeof(tmpCtx_t)); + explicit_bzero(&strings, sizeof(strings_t)); + explicit_bzero(&G_io_apdu_buffer, 260); + explicit_bzero(&sha3, sizeof(sha3)); + + uint8_t target; + + txContext.content = &txContent; + txContext.sha3 = &sha3; + + // Determine which harness function to call based on the first byte of data + if (size < 1) return 0; + target = data[0]; + if (target >= sizeof(harnesses) / sizeof(harnesses[0])) return 0; + + // Call the selected harness function with the remaining data (which can be of size 0) + return harnesses[target](++data, --size); +} diff --git a/tests/fuzzing/src/glyphs.h b/tests/fuzzing/src/glyphs.h new file mode 100644 index 000000000..e69de29bb diff --git a/tests/fuzzing/src/mock.c b/tests/fuzzing/src/mock.c new file mode 100644 index 000000000..cfcd65c83 --- /dev/null +++ b/tests/fuzzing/src/mock.c @@ -0,0 +1,169 @@ +#include +#include + +#include "cx_errors.h" +#include "cx_sha256.h" +#include "cx_sha3.h" + +/** MemorySanitizer does not wrap explicit_bzero https://github.com/google/sanitizers/issues/1507 + * which results in false positives when running MemorySanitizer. + */ +void memset_s(void *buffer, char c, size_t n) { + if (buffer == NULL) return; + + volatile char *ptr = buffer; + while (n--) *ptr++ = c; +} + +size_t strlcpy(char *dst, const char *src, size_t size) { + const char *s = src; + size_t n = size; + + if (n != 0) { + while (--n != 0) { + if ((*dst++ = *s++) == '\0') { + break; + } + } + } + + if (n == 0) { + if (size != 0) { + *dst = '\0'; + } + while (*s++) + ; + } + + return (s - src - 1); +} + +size_t strlcat(char *dst, const char *src, size_t size) { + char *d = dst; + const char *s = src; + size_t n = size; + size_t dsize; + + while (n-- != 0 && *d != '\0') { + d++; + } + dsize = d - dst; + n = size - dsize; + + if (n == 0) { + return (dsize + strlen(s)); + } + + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return (dsize + (s - src)); +} + +cx_err_t cx_sha256_init_no_throw(cx_sha256_t *hash) { + memset_s(hash, 0, sizeof(cx_sha256_t)); + return CX_OK; +} + +cx_err_t cx_sha3_init_no_throw(cx_sha3_t *hash PLENGTH(sizeof(cx_sha3_t)), size_t size) { + UNUSED(size); + memset_s(hash, 0, sizeof(cx_sha3_t)); + return CX_OK; +} + +cx_err_t cx_hash_no_throw(cx_hash_t *hash, + uint32_t mode, + const uint8_t *in, + size_t len, + uint8_t *out, + size_t out_len) { + UNUSED(hash); + UNUSED(mode); + memset_s(out, 0, out_len); // let's initialize the buffer + // if arrays are not empty, read the last element of in and write it in the last element of out + if (len > 0 && out_len > 0) out[out_len - 1] = in[len - 1]; + return CX_OK; +} + +void assert_exit(bool confirm) { + UNUSED(confirm); + exit(1); +} + +cx_err_t cx_keccak_256_hash_iovec(const cx_iovec_t *iovec, + size_t iovec_len, + uint8_t digest[static CX_KECCAK_256_SIZE]) { + UNUSED(iovec); + UNUSED(iovec_len); + memset_s(digest, 0, CX_SHA256_SIZE); + return CX_OK; +} + +cx_err_t cx_sha256_hash_iovec(const cx_iovec_t *iovec, + size_t iovec_len, + uint8_t digest[static CX_SHA256_SIZE]) { + UNUSED(iovec); + UNUSED(iovec_len); + memset_s(digest, 0, CX_SHA256_SIZE); + return CX_OK; +} + +int check_signature_with_pubkey(const char *tag, + uint8_t *buffer, + const uint8_t bufLen, + const uint8_t *PubKey, + const uint8_t keyLen, +#ifdef HAVE_LEDGER_PKI + const uint8_t keyUsageExp, +#endif + uint8_t *signature, + const uint8_t sigLen) { + UNUSED(tag); + UNUSED(buffer); + UNUSED(bufLen); + UNUSED(PubKey); +#ifdef HAVE_LEDGER_PKI + UNUSED(keyUsageExp); +#endif + UNUSED(keyLen); + UNUSED(signature); + UNUSED(sigLen); + return CX_OK; +} + +void *pic(void *addr) { + return addr; +} + +cx_err_t cx_math_mult_no_throw(uint8_t *r, const uint8_t *a, const uint8_t *b, size_t len) { + UNUSED(r); + UNUSED(a); + UNUSED(b); + UNUSED(len); + return CX_OK; +} + +void cx_rng_no_throw(uint8_t *buffer, size_t len) { + memset_s(buffer, 0, len); +} + +uint16_t get_public_key(uint8_t *out, uint8_t outLength) { + memset_s(out, 0, outLength); + return 0; +} + +void ui_gcs_cleanup(void) { +} + +size_t cx_hash_sha256(const uint8_t *in, size_t in_len, uint8_t *out, size_t out_len) { + memset_s(out, 0, out_len); // let's initialize the buffer + // if arrays are not empty, read the last element of in and write it in the last element of out + if (in_len > 0 && out_len > 0) out[out_len - 1] = in[in_len - 1]; + return CX_OK; +} diff --git a/tests/ragger/snapshots/flex/test_blind_sign/00000.png b/tests/ragger/snapshots/flex/test_blind_sign/00000.png index acbb161df..039eff047 100644 Binary files a/tests/ragger/snapshots/flex/test_blind_sign/00000.png and b/tests/ragger/snapshots/flex/test_blind_sign/00000.png differ diff --git a/tests/ragger/snapshots/flex/test_blind_sign_nonzero/00000.png b/tests/ragger/snapshots/flex/test_blind_sign_nonzero/00000.png index acbb161df..039eff047 100644 Binary files a/tests/ragger/snapshots/flex/test_blind_sign_nonzero/00000.png and b/tests/ragger/snapshots/flex/test_blind_sign_nonzero/00000.png differ diff --git a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png index acbb161df..039eff047 100644 Binary files a/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png and b/tests/ragger/snapshots/flex/test_blind_sign_rejected/00000.png differ diff --git a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png index acbb161df..039eff047 100644 Binary files a/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png and b/tests/ragger/snapshots/flex/test_sign_parameter_selector/00006.png differ diff --git a/tests/ragger/snapshots/stax/test_blind_sign/00000.png b/tests/ragger/snapshots/stax/test_blind_sign/00000.png index 9696ae123..0463721b1 100644 Binary files a/tests/ragger/snapshots/stax/test_blind_sign/00000.png and b/tests/ragger/snapshots/stax/test_blind_sign/00000.png differ diff --git a/tests/ragger/snapshots/stax/test_blind_sign_nonzero/00000.png b/tests/ragger/snapshots/stax/test_blind_sign_nonzero/00000.png index 9696ae123..0463721b1 100644 Binary files a/tests/ragger/snapshots/stax/test_blind_sign_nonzero/00000.png and b/tests/ragger/snapshots/stax/test_blind_sign_nonzero/00000.png differ diff --git a/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png b/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png index 9696ae123..0463721b1 100644 Binary files a/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png and b/tests/ragger/snapshots/stax/test_blind_sign_rejected/00000.png differ diff --git a/tests/ragger/snapshots/stax/test_sign_parameter_selector/00006.png b/tests/ragger/snapshots/stax/test_sign_parameter_selector/00006.png index 9696ae123..0463721b1 100644 Binary files a/tests/ragger/snapshots/stax/test_sign_parameter_selector/00006.png and b/tests/ragger/snapshots/stax/test_sign_parameter_selector/00006.png differ diff --git a/tests/ragger/test_get_address.py b/tests/ragger/test_get_address.py index 39e0ab16a..e670295a2 100644 --- a/tests/ragger/test_get_address.py +++ b/tests/ragger/test_get_address.py @@ -67,7 +67,7 @@ def test_get_pk(backend: BackendInterface, else: name = "" - if name: + if (app_client._firmware != Firmware.NANOS) and name: app_client.provide_network_information(name, ticker, chain, bytes.fromhex(icon)) with app_client.get_public_addr(chaincode=with_chaincode, chain_id=chain): diff --git a/tests/ragger/test_sign.py b/tests/ragger/test_sign.py index 499ed651c..3ac93064d 100644 --- a/tests/ragger/test_sign.py +++ b/tests/ragger/test_sign.py @@ -56,7 +56,7 @@ def common(firmware: Firmware, else: name = "" - if name: + if (app_client._firmware != Firmware.NANOS) and name: app_client.provide_network_information(name, ticker, tx_params["chainId"], bytes.fromhex(icon)) with app_client.get_public_addr(bip32_path=path, display=False):