From 1134dcf1ee2d641be6705998caf33cea8b4c8007 Mon Sep 17 00:00:00 2001 From: neithanmo Date: Wed, 13 Nov 2024 12:09:35 +0100 Subject: [PATCH 1/5] Fix post conditions checks after parsing --- app/rust/src/parser/post_conditions.rs | 25 +++++---- app/rust/src/parser/tx_post_conditions.rs | 68 ++++++++++++++++++----- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/app/rust/src/parser/post_conditions.rs b/app/rust/src/parser/post_conditions.rs index 2f108237..fb3df585 100644 --- a/app/rust/src/parser/post_conditions.rs +++ b/app/rust/src/parser/post_conditions.rs @@ -83,26 +83,31 @@ impl<'a> TransactionPostCondition<'a> { } pub fn read_as_bytes(bytes: &'a [u8]) -> nom::IResult<&[u8], &[u8], ParserError> { - let cond_type = le_u8(bytes)?; - let (raw, _) = PostConditionPrincipal::read_as_bytes(cond_type.0)?; - let mut len = bytes.len() - raw.len(); - len += match PostConditionType::try_from(cond_type.1)? { + let rem = bytes; + let (rem, cond_type) = le_u8(rem)?; + let (mut rem, _) = PostConditionPrincipal::read_as_bytes(rem)?; + + match PostConditionType::try_from(cond_type)? { PostConditionType::Stx => { // We take 9-bytes which comprises the 8-byte amount + 1-byte fungible code - 9usize + let (raw, _) = take(9usize)(rem)?; + rem = raw; } PostConditionType::FungibleToken => { - let (_, asset) = AssetInfo::read_as_bytes(raw)?; + let (raw, _) = AssetInfo::read_as_bytes(rem)?; // We take 9-bytes which containf the 8-byte amount + 1-byte fungible code - asset.len() + 9 + let (raw, _) = take(9usize)(raw)?; + rem = raw; } PostConditionType::NonFungibleToken => { - let (asset_raw, asset) = AssetInfo::read_as_bytes(raw)?; - let value_len = Value::value_len::(asset_raw)?; - asset.len() + value_len + 1 + let (asset_raw, _) = AssetInfo::read_as_bytes(rem)?; + let (raw, _) = Value::from_bytes::(asset_raw)?; + let (raw, _) = take(1usize)(raw)?; + rem = raw; } }; crate::check_canary!(); + let len = bytes.len() - rem.len(); take(len)(bytes) } diff --git a/app/rust/src/parser/tx_post_conditions.rs b/app/rust/src/parser/tx_post_conditions.rs index f1cd8c8c..28b828ad 100644 --- a/app/rust/src/parser/tx_post_conditions.rs +++ b/app/rust/src/parser/tx_post_conditions.rs @@ -1,8 +1,5 @@ use arrayvec::ArrayVec; -use nom::{ - combinator::iterator, - number::complete::{be_u32, le_u8}, -}; +use nom::number::complete::{be_u32, le_u8}; use crate::{bolos::c_zemu_log_stack, check_canary, parser::TransactionPostCondition}; @@ -51,28 +48,73 @@ impl<'a> PostConditions<'a> { #[inline(never)] pub fn from_bytes(bytes: &'a [u8]) -> nom::IResult<&[u8], Self, ParserError> { let (raw, len) = be_u32::<_, ParserError>(bytes)?; + let conditions_len = len as usize; - if len > NUM_SUPPORTED_POST_CONDITIONS as u32 { + // Validate length + if conditions_len > NUM_SUPPORTED_POST_CONDITIONS { return Err(nom::Err::Error(ParserError::ValueOutOfRange)); } + let mut conditions: ArrayVec<[&'a [u8]; NUM_SUPPORTED_POST_CONDITIONS]> = ArrayVec::new(); - let mut iter = iterator(raw, TransactionPostCondition::read_as_bytes); - iter.take(len as _).enumerate().for_each(|i| { - conditions.push(i.1); - }); - let res = iter.finish()?; - let num_items = Self::get_num_items(&conditions[..len as usize]); + let mut current_input = raw; + + // Safely iterate exactly len times + for _ in 0..conditions_len { + match TransactionPostCondition::read_as_bytes(current_input) { + Ok((remaining, item)) => { + current_input = remaining; + // Safe push with error handling + if conditions.try_push(item).is_err() { + return Err(nom::Err::Error(ParserError::ValueOutOfRange)); + } + } + Err(e) => return Err(e), + } + } + + if conditions.len() != conditions_len { + return Err(nom::Err::Error(ParserError::ValueOutOfRange)); + } + + let num_items = Self::get_num_items(&conditions); check_canary!(); + + let num_conditions = conditions.len(); + Ok(( - res.0, + current_input, Self { conditions, num_items, current_idx: 0, - num_conditions: len as usize, + num_conditions, }, )) } + // pub fn from_bytes(bytes: &'a [u8]) -> nom::IResult<&[u8], Self, ParserError> { + // let (raw, len) = be_u32::<_, ParserError>(bytes)?; + // + // if len > NUM_SUPPORTED_POST_CONDITIONS as u32 { + // return Err(nom::Err::Error(ParserError::ValueOutOfRange)); + // } + // let mut conditions: ArrayVec<[&'a [u8]; NUM_SUPPORTED_POST_CONDITIONS]> = ArrayVec::new(); + // let mut iter = iterator(raw, TransactionPostCondition::read_as_bytes); + // iter.take(len as _).enumerate().for_each(|i| { + // conditions.push(i.1); + // }); + // let res = iter.finish()?; + // let num_items = Self::get_num_items(&conditions[..len as usize]); + // check_canary!(); + // Ok(( + // res.0, + // Self { + // conditions, + // num_items, + // current_idx: 0, + // num_conditions: len as usize, + // }, + // )) + // } pub fn get_num_items(conditions: &[&[u8]]) -> u8 { conditions From 890dffe8e51d8f715e1e45d33b3bc5003ef34159 Mon Sep 17 00:00:00 2001 From: neithanmo Date: Wed, 13 Nov 2024 12:10:53 +0100 Subject: [PATCH 2/5] Add corpus generator that we can use later to update corpus data Add lexical core to fuzzer deps Update lock Increate max number of arguments Update instruction son fuzzing Minor updates Remove fuzzing artifact from this as it is handle in a different Cargo.toml Cargo fmt Use nom::sequence::tuple instead of permutation to ensure fields ordering Use fuzzing in CI with some time configuration Update lint ci job Apply linter for formatting remove unused import Add clang settings Fix some lint errors Use honggfuzz built-in timing configs Use our runners for fuzzing fix linter Fix running time for fuzzer Use timeout and preserve status to control fuzzer execution --- .clang-format | 10 + .clang-tidy | 23 +++ .github/workflows/lint.yml | 21 +- .github/workflows/main.yml | 81 ++++++++ .gitignore | 1 + Makefile | 3 +- app/FUZZING.md | 9 +- app/hfuzz-parser/Cargo.lock | 33 +++ app/hfuzz-parser/corpus/Cargo.lock | 16 ++ app/hfuzz-parser/corpus/Cargo.toml | 7 + app/hfuzz-parser/corpus/src/main.rs | 46 +++++ app/rust/Cargo.toml | 9 - app/rust/native/Cargo.toml | 5 +- app/rust/src/parser/transaction.rs | 4 +- .../parser/transaction_payload/arguments.rs | 2 +- app/src/addr.c | 43 ++-- app/src/addr.h | 34 ++-- app/src/apdu_handler.c | 109 +++++----- app/src/c_api/rust.c | 6 +- app/src/coin.h | 28 +-- app/src/coin_standard.h | 72 +++---- app/src/common/actions.c | 30 +-- app/src/common/actions.h | 190 +++++++++--------- app/src/common/main.c | 51 +++-- app/src/common/tx.c | 139 +++++-------- app/src/common/tx.h | 38 ++-- app/src/crypto.c | 138 ++++++------- app/src/crypto.h | 40 ++-- app/src/parser.c | 68 +++---- app/src/parser.h | 46 ++--- app/src/parser_common.h | 47 ++--- app/src/parser_txdef.h | 30 +-- 32 files changed, 760 insertions(+), 619 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 app/hfuzz-parser/corpus/Cargo.lock create mode 100644 app/hfuzz-parser/corpus/Cargo.toml create mode 100644 app/hfuzz-parser/corpus/src/main.rs diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..949c869c --- /dev/null +++ b/.clang-format @@ -0,0 +1,10 @@ +BasedOnStyle: Google +IndentWidth: 4 +ColumnLimit: 125 +DerivePointerAlignment: false +PointerAlignment: Right +AllowShortFunctionsOnASingleLine: None +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..75f10ca4 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,23 @@ +Checks: "-*, + clang-diagnostic-*, + clang-analyzer-*, + cppcoreguidelines-init-variables, + google-runtime-int, + google-readability-avoid-underscore-in-googletest-name, + misc-*, + performance-*, + portability-*, + readability-*, + -misc-no-recursion, + -readability-function-cognitive-complexity + -readability-magic-numbers" +WarningsAsErrors: "*" +CheckOptions: + - key: readability-identifier-length.MinimumVariableNameLength + value: 2 + - key: readability-identifier-length.MinimumParameterNameLength + value: 2 + - key: readability-identifier-length.MinimumLoopCounterNameLength + value: 1 + - key: readability-magic-numbers.IgnorePowersOf2IntegerValues + value: true diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 166b5f30..a3765510 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,27 +2,34 @@ name: Lint and format 💅 on: workflow_dispatch: - # push: - # pull_request: - # branches: - # - main - # - develop + push: + pull_request: + branches: + - main + - develop + - master # for safety reasons + - dev # for safety reasons jobs: lint: - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'zondax' && 'zondax-runners' || 'ubuntu-latest' }} container: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Add missing deps + env: + DEBIAN_FRONTEND: noninteractive run: | - DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y bear sudo - name: Generate compilation database run: bear -- make -j BOLOS_SDK="$NANOSP_SDK" + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: "3.11" - name: Lint and format 💅 uses: cpp-linter/cpp-linter-action@v2 id: linter diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2df9ea0b..88118764 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -264,3 +264,84 @@ jobs: tag_name: ${{ steps.flex.outputs.tag_name }} draft: false prerelease: false + + fuzzing: + name: fuzzing + runs-on: ${{ github.repository_owner == 'zondax' && 'zondax-runners' || 'ubuntu-latest' }} + container: + image: rust:latest + steps: + - uses: actions/checkout@v3 + + # Install only the additional dependencies needed for honggfuzz + - name: Install system dependencies + run: | + apt-get update && apt-get install -y \ + binutils-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + + - name: Install honggfuzz + run: cargo install honggfuzz + + - name: Generate corpus + run: | + cd app/hfuzz-parser/corpus + cargo run + + # Different fuzzing durations based on trigger + - name: Quick fuzz (PR) + if: github.event_name == 'push' + run: | + cd app/hfuzz-parser + timeout --preserve-status 5m cargo hfuzz run transaction ../hfuzz_corpus/ + + - name: Medium fuzz (main) + if: github.event_name == 'pull_request' + run: | + cd app/hfuzz-parser + timeout --preserve-status 15m cargo hfuzz run transaction ../hfuzz_corpus/ + + - name: Extended fuzz (weekly) + if: github.event_name == 'schedule' + run: | + cd app/hfuzz-parser + timeout --preserve-status 30m cargo hfuzz run transaction ../hfuzz_corpus/ + + - name: Check for crashes + run: | + if ls app/hfuzz-parser/hfuzz_workspace/transaction/SIGABRT.PC.* 1> /dev/null 2>&1; then + echo "::error::Crashes found during fuzzing!" + exit 1 + fi + + - name: Upload crash artifacts + if: failure() + uses: actions/upload-artifact@v3 + with: + name: crash-reports + path: | + app/hfuzz-parser/hfuzz_workspace/transaction/SIGABRT.PC.* + app/hfuzz-parser/hfuzz_workspace/transaction/HONGGFUZZ.REPORT.TXT + app/hfuzz-parser/hfuzz_workspace/transaction/input/ + + - name: Cache corpus + uses: actions/cache@v3 + with: + path: app/hfuzz_corpus + key: ${{ runner.os }}-fuzz-corpus-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-fuzz-corpus- + + - name: Notify on failure + if: failure() + uses: actions/github-script@v6 + with: + script: | + github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: 'Fuzzing found crashes', + body: 'Fuzzing job failed. Check the artifacts in the workflow run.' + }) diff --git a/.gitignore b/.gitignore index fa117508..925727ff 100644 --- a/.gitignore +++ b/.gitignore @@ -90,5 +90,6 @@ app/output/*.sha256 app/pkg/* app/rust/.cargo/.package-cache-mutate +app/hfuzz_corpus diff --git a/Makefile b/Makefile index b4767ca6..cdfa1480 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,8 @@ prod: make PRODUCTION_BUILD=1 rust_fuzz: - cd app/hfuzz-parser/ && cargo hfuzz run transaction + cd app/hfuzz-parser/corpus/ && cargo run + cd app/hfuzz-parser/ && cargo hfuzz run transaction app/hfuzz_corpus diff --git a/app/FUZZING.md b/app/FUZZING.md index 44323d37..5f2d097d 100644 --- a/app/FUZZING.md +++ b/app/FUZZING.md @@ -35,6 +35,13 @@ cargo hfuzz run-debug transaction hfuzz_workspace/*/*.fuzz ``` -This will deploy a gdb console with a backtrace with the first crash +To opt to use _gdb_ instead of `lldb`, you can configure it before running the debugger with: + +```bash +export HFUZZ_DEBUGGER="rust-gdb" + +``` + +This will deploy a **gdb** console with a backtrace with the first crash _note_: There could be more than one _.fuzz_ file. diff --git a/app/hfuzz-parser/Cargo.lock b/app/hfuzz-parser/Cargo.lock index 349e182f..23bb266a 100644 --- a/app/hfuzz-parser/Cargo.lock +++ b/app/hfuzz-parser/Cargo.lock @@ -41,6 +41,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "block-buffer" version = "0.9.0" @@ -150,12 +156,32 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "libm", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.157" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86" +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "lock_api" version = "0.4.12" @@ -241,6 +267,7 @@ dependencies = [ "arrayvec", "base64", "hex", + "lexical-core", "no-std-compat", "nom", "numtoa", @@ -335,6 +362,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "2.0.75" diff --git a/app/hfuzz-parser/corpus/Cargo.lock b/app/hfuzz-parser/corpus/Cargo.lock new file mode 100644 index 00000000..a3eb7a5b --- /dev/null +++ b/app/hfuzz-parser/corpus/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "corpus-generator" +version = "0.1.0" +dependencies = [ + "hex", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" diff --git a/app/hfuzz-parser/corpus/Cargo.toml b/app/hfuzz-parser/corpus/Cargo.toml new file mode 100644 index 00000000..2970ea09 --- /dev/null +++ b/app/hfuzz-parser/corpus/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "corpus-generator" +version = "0.1.0" +edition = "2021" + +[dependencies] +hex = "0.4.3" diff --git a/app/hfuzz-parser/corpus/src/main.rs b/app/hfuzz-parser/corpus/src/main.rs new file mode 100644 index 00000000..4c3c208e --- /dev/null +++ b/app/hfuzz-parser/corpus/src/main.rs @@ -0,0 +1,46 @@ +use hex::decode; +use std::fs; + +fn generate_corpus() -> Result<(), std::io::Error> { + let corpus_dir = "../../hfuzz_corpus"; + fs::create_dir_all(corpus_dir)?; + + // Contract call with 20 args + let contract_call = "0000000001040097432af9a5c04675136b8c2badfbfe9bf17fa804000000000000003500000000000003e800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020000000300021697432af9a5c04675136b8c2badfbfe9bf17fa8040100000000000000640003167c5f674a8fd08efa61dd9b11121e046dd2c892730a756e6976322d636f72650500000000000000010103167c5f674a8fd08efa61dd9b11121e046dd2c892730a756e6976322d636f7265167c5f674a8fd08efa61dd9b11121e046dd2c892730b76656c61722d746f6b656e0576656c6172030000000000000b3f02167c5f674a8fd08efa61dd9b11121e046dd2c8927311706174682d6170706c795f76315f325f30056170706c79000000180b000000010c0000000601610d0000000175016206167c5f674a8fd08efa61dd9b11121e046dd2c892730976656c61722d73747801630100000000000000000000000000000015016406167c5f674a8fd08efa61dd9b11121e046dd2c892730477737478016506167c5f674a8fd08efa61dd9b11121e046dd2c892730b76656c61722d746f6b656e01660401000000000000000000000000000000640a06167c5f674a8fd08efa61dd9b11121e046dd2c8927304777374780a06167c5f674a8fd08efa61dd9b11121e046dd2c892730b76656c61722d746f6b656e0909090a06167c5f674a8fd08efa61dd9b11121e046dd2c8927312756e6976322d73686172652d6665652d746f09090909090909090909090909090909"; + + // Swap transaction + let swap = "000000000104009ef3889fd070159edcd8ef88a0ec87cea1592c83000000000000000000000000000f42400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000302000000060002169ef3889fd070159edcd8ef88a0ec87cea1592c830100000000000027100003167c5f674a8fd08efa61dd9b11121e046dd2c892730a756e6976322d636f72650300000000000000000103167c5f674a8fd08efa61dd9b11121e046dd2c892730a756e6976322d636f7265168c5e2f8d25627d6edebeb6d10fa3300f5acc8441086c6f6e67636f696e086c6f6e67636f696e0300000000000000000103167c5f674a8fd08efa61dd9b11121e046dd2c892730a756e6976322d636f7265168c5e2f8d25627d6edebeb6d10fa3300f5acc8441086c6f6e67636f696e086c6f6e67636f696e0300000000000000000102169ef3889fd070159edcd8ef88a0ec87cea1592c83168c5e2f8d25627d6edebeb6d10fa3300f5acc8441086c6f6e67636f696e086c6f6e67636f696e030000000000000000010316402da2c079e5d31d58b9cfc7286d1b1eb2f7834e0f616d6d2d7661756c742d76322d303116402da2c079e5d31d58b9cfc7286d1b1eb2f7834e0a746f6b656e2d616c657804616c65780300000000011c908a02162ec1a2dc2904ebc8b408598116c75e42c51afa2617726f757465722d76656c61722d616c65782d762d312d320d737761702d68656c7065722d6100000007010000000000000000000000000000271001000000000000000000000000011c908a040c00000002016106167c5f674a8fd08efa61dd9b11121e046dd2c892730477737478016206168c5e2f8d25627d6edebeb6d10fa3300f5acc8441086c6f6e67636f696e06167c5f674a8fd08efa61dd9b11121e046dd2c8927312756e6976322d73686172652d6665652d746f0c0000000201610616402da2c079e5d31d58b9cfc7286d1b1eb2f7834e0b746f6b656e2d776c6f6e6701620616402da2c079e5d31d58b9cfc7286d1b1eb2f7834e0a746f6b656e2d616c65780c0000000101610100000000000000000000000005f5e100"; + + // Versioned smart contract + let versioned_contract = "8080000000040060dbb32efe0c56e1d418c020f4cb71c556b6a60d0000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000301000000000602107468656e2d677265656e2d6d61636177000004cf3b3b2068656c6c6f2d776f726c6420636f6e74726163740a0a28646566696e652d636f6e7374616e742073656e6465722027535a324a365a593438475631455a35563256355242394d5036365357383650594b4b51394836445052290a28646566696e652d636f6e7374616e7420726563697069656e742027534d324a365a593438475631455a35563256355242394d5036365357383650594b4b51565838583047290a0a28646566696e652d66756e6769626c652d746f6b656e206e6f76656c2d746f6b656e2d3139290a2866742d6d696e743f206e6f76656c2d746f6b656e2d3139207531322073656e646572290a2866742d7472616e736665723f206e6f76656c2d746f6b656e2d31392075322073656e64657220726563697069656e74290a0a28646566696e652d6e6f6e2d66756e6769626c652d746f6b656e2068656c6c6f2d6e66742075696e74290a0a286e66742d6d696e743f2068656c6c6f2d6e66742075312073656e646572290a286e66742d6d696e743f2068656c6c6f2d6e66742075322073656e646572290a286e66742d7472616e736665723f2068656c6c6f2d6e66742075312073656e64657220726563697069656e74290a0a28646566696e652d7075626c69632028746573742d656d69742d6576656e74290a202028626567696e0a20202020287072696e7420224576656e74212048656c6c6f20776f726c64220a20202020286f6b207531290a2020290a290a0a28626567696e2028746573742d656d69742d6576656e7429290a0a28646566696e652d7075626c69632028746573742d6576656e742d7479706573290a202028626567696e0a2020202028756e777261702d70616e6963202866742d6d696e743f206e6f76656c2d746f6b656e2d313920753320726563697069656e7429290a2020202028756e777261702d70616e696320286e66742d6d696e743f2068656c6c6f2d6e667420753220726563697069656e7429290a2020202028756e777261702d70616e696320287374782d7472616e736665723f207536302074782d73656e6465722027535a324a365a593438475631455a35563256355242394d5036365357383650594b4b5139483644505229290a2020202028756e777261702d70616e696320287374782d6275726e3f207532302074782d73656e64657229290a20202020286f6b207531290a2020290a290a0a28646566696e652d6d61702073746f7265207b206b65793a20286275666620333229207d207b2076616c75653a20286275666620333229207d290a0a28646566696e652d7075626c696320286765742d76616c756520286b65792028627566662033322929290a202028626567696e0a20202020286d6174636820286d61702d6765743f2073746f7265207b206b65793a206b6579207d290a202020202020656e74727920286f6b20286765742076616c756520656e74727929290a202020202020286572722030290a20202020290a2020290a290a0a28646566696e652d7075626c696320287365742d76616c756520286b65792028627566662033322929202876616c75652028627566662033322929290a202028626567696e0a20202020286d61702d7365742073746f7265207b206b65793a206b6579207d207b2076616c75653a2076616c7565207d290a20202020286f6b207531290a2020290a290a"; // truncated for brevity + + // With 7 post conditions + let multi_post_conditions = "808000000004002d89de56fd4db19741957831926e9ba96cf04158000000000000000300000000000000000001b019126ffa434bd7c816b3e1daa3163e322aae6cde06585d22d46286570e4a491eecc2dcd214a42eae62584ddbe8a96382ff1f34edb4ecedeab0a6b6b1e07d2003020000000701031a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c641a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c640a737461636b61726f6f73010000000000000064000103000000000000007c01031a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c641a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c640a737461636b61726f6f7303000000000000006400010300000000000000f701031a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c641a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c640a737461636b61726f6f73050000000000000064000103000000000000017202031a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c641a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c64056e616d657302000000040000006410021a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c640f73656e642d737461636b61726f6f7300000001051a3b471808467d33eec688b7a7a75f06aad921ba6e"; + + // With fungible post conditions + let fungible_post_conditions = "808000000004003b471808467d33eec688b7a7a75f06aad921ba6e000000000000000100000000000000000000134ab418c3422c600bfeffb1a322b78edab12961fdea48f34cbbb4eae42a4a53401bf2a0d680e819028276cfa13c672a8031ddd17b46fda70a037fefb20e9e9203020000000101021a3b471808467d33eec688b7a7a75f06aad921ba6e1a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c640a737461636b61726f6f73030000000000000064021a2d89de56fd4db19741957831926e9ba96cf041580b68656c6c6f2d776f726c6414757365722d73656e642d737461636b61726f6f7300000001051a2d89de56fd4db19741957831926e9ba96cf04158"; + + // Token transfer + let token_transfer = "8080000000040156da933238491425e460d335d3af8e04fd3e59970000000000000000000000000000000000000001020164b3d6fc5f1ac5093343f4b48dcfda73d85dbfccec276418e71fc928acc412fc62525e67103bee36df5e7ed07b73b668a27ab3703ce2d018a98a161c46bdcac2000203020000000000051abaa6de6c1badf30afa816e2c66db3125034facab00000000002625a06d756c746973696720747800000000000000000000000000000000000000000000006f7a42ccdce26688916ef6c182001fd1c703941c1224a9845ee54db9918acf67000164b3d6fc5f1ac5093343f4b48dcfda73d85dbfccec276418e71fc928acc412fc62525e67103bee36df5e7ed07b73b668a27ab3703ce2d018a98a161c46bdcac2"; + + // Write each transaction type to a separate file + let transactions = [ + ("contract_call", contract_call), + ("swap", swap), + ("versioned_contract", versioned_contract), + ("multi_post_conditions", multi_post_conditions), + ("fungible_post_conditions", fungible_post_conditions), + ("token_transfer", token_transfer), + ]; + + for (name, hex_str) in transactions { + let bytes = decode(hex_str).expect("Invalid hex string"); + fs::write(format!("{}/{}_{}", corpus_dir, name, bytes.len()), bytes)?; + } + + Ok(()) +} + +fn main() { + generate_corpus().expect("Failed to generate corpus"); +} diff --git a/app/rust/Cargo.toml b/app/rust/Cargo.toml index 1f0e96cf..6d53f0a5 100644 --- a/app/rust/Cargo.toml +++ b/app/rust/Cargo.toml @@ -41,15 +41,6 @@ serde = { version = "1.0", features = ["derive"] } sha2 = { version = "0.9.1" } base64 = { version = "0.13.0" } - -[target.'cfg(fuzzing)'.dependencies] -no-std-compat = { version = "0.4.1", features = ["std"] } -sha2 = { version = "0.9.1" } -hex = { version = "0.4" } -serde-json-core = { version = "0.4.0", features = ["std"] } -serde = { version = "1.0", features = ["derive"] } -base64 = { version = "0.13.0" } - [profile.release] lto = false codegen-units = 1 diff --git a/app/rust/native/Cargo.toml b/app/rust/native/Cargo.toml index 550d0ac8..82593d9d 100644 --- a/app/rust/native/Cargo.toml +++ b/app/rust/native/Cargo.toml @@ -21,6 +21,7 @@ hex = { version = "0.4", default-features = false } serde = { version = "1.0", default-features = false, features = ["derive"] } serde-json-core = { version = "0.4.0", features = ["std"] } nom = { version = "7.1.2", default-features = false } +lexical-core = { version = "0.7", features = ["libm"] } [dependencies.arrayvec] @@ -39,11 +40,13 @@ base64 = { version = "0.13.0" } [target.'cfg(fuzzing)'.dependencies] -sha2 = { version = "0.9.1" } no-std-compat = { version = "0.4.1", features = ["std"] } +sha2 = { version = "0.9.1" } hex = { version = "0.4" } +serde-json-core = { version = "0.4.0", features = ["std"] } serde = { version = "1.0", features = ["derive"] } base64 = { version = "0.13.0" } +lexical-core = { version = "0.7", features = ["libm"] } [profile.release] lto = false diff --git a/app/rust/src/parser/transaction.rs b/app/rust/src/parser/transaction.rs index 2867d710..268a4af8 100644 --- a/app/rust/src/parser/transaction.rs +++ b/app/rust/src/parser/transaction.rs @@ -1,8 +1,8 @@ use core::fmt::Write; use nom::{ - branch::permutation, bytes::complete::take, number::complete::{be_u32, le_u8}, + sequence::tuple, }; use crate::{ @@ -211,7 +211,7 @@ impl<'a> Transaction<'a> { } pub fn from_bytes(bytes: &'a [u8]) -> Result { - match permutation(( + match tuple(( TransactionVersion::from_bytes, be_u32, TransactionAuth::from_bytes, diff --git a/app/rust/src/parser/transaction_payload/arguments.rs b/app/rust/src/parser/transaction_payload/arguments.rs index e4375ec9..d746ec3c 100644 --- a/app/rust/src/parser/transaction_payload/arguments.rs +++ b/app/rust/src/parser/transaction_payload/arguments.rs @@ -8,7 +8,7 @@ use crate::{ // The number of contract call arguments we can handle. // this can be adjusted, but keep in mind that higher values could // hit stack overflows issues. -pub const MAX_NUM_ARGS: u32 = 10; +pub const MAX_NUM_ARGS: u32 = 30; #[repr(C)] #[derive(Clone, PartialEq)] diff --git a/app/src/addr.c b/app/src/addr.c index 118e06b8..7bb07db8 100644 --- a/app/src/addr.c +++ b/app/src/addr.c @@ -1,26 +1,27 @@ /******************************************************************************* -* (c) 2020 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2020 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include + +#include "app_mode.h" #include "coin.h" +#include "crypto.h" #include "zxerror.h" -#include "zxmacros.h" #include "zxformat.h" -#include "app_mode.h" -#include "crypto.h" +#include "zxmacros.h" zxerr_t addr_getNumItems(uint8_t *num_items) { zemu_log_stack("addr_getNumItems"); @@ -31,15 +32,13 @@ zxerr_t addr_getNumItems(uint8_t *num_items) { return zxerr_ok; } -zxerr_t addr_getItem(int8_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) { +zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, + uint8_t *pageCount) { zemu_log_stack("addr_getItem"); switch (displayIdx) { case 0: snprintf(outKey, outKeyLen, "Address"); - pageString(outVal, outValLen, (char *) (G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1), pageIdx, pageCount); + pageString(outVal, outValLen, (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1), pageIdx, pageCount); return zxerr_ok; case 1: { if (!app_mode_expert()) { diff --git a/app/src/addr.h b/app/src/addr.h index 01406719..2aaf3acb 100644 --- a/app/src/addr.h +++ b/app/src/addr.h @@ -1,32 +1,32 @@ /******************************************************************************* -* (c) 2020 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2020 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #ifdef __cplusplus extern "C" { #endif +#include +#include "zxerror.h" /// Return the number of items in the address view zxerr_t addr_getNumItems(uint8_t *num_items); /// Gets an specific item from the address view (including paging) -zxerr_t addr_getItem(int8_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, +zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outValue, uint16_t outValueLen, uint8_t pageIdx, uint8_t *pageCount); #ifdef __cplusplus diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index 5736e561..7a054206 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -1,51 +1,48 @@ /******************************************************************************* -* (c) 2018, 2019 Zondax GmbH -* (c) 2016 Ledger -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2018, 2019 Zondax GmbH + * (c) 2016 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ -#include "app_main.h" - -#include -#include #include +#include +#include -#include "view.h" #include "actions.h" -#include "tx.h" #include "addr.h" -#include "crypto.h" +#include "app_main.h" #include "coin.h" -#include "zxmacros.h" +#include "crypto.h" +#include "tx.h" +#include "view.h" #include "view_internal.h" +#include "zxmacros.h" static bool tx_initialized = false; __Z_INLINE void extractHDPath(uint32_t rx, uint32_t offset, uint32_t path_len) { - if ((rx - offset) < sizeof(uint32_t) * path_len) { - THROW(APDU_CODE_WRONG_LENGTH); + THROW(APDU_CODE_WRONG_LENGTH); } MEMCPY(hdPath, G_io_apdu_buffer + offset, sizeof(uint32_t) * path_len); hdPath_len = path_len; } - - __Z_INLINE bool process_chunk(uint32_t rx) { - const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE]; + uint8_t payloadType = 0; + payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE]; if (rx < OFFSET_DATA) { THROW(APDU_CODE_WRONG_LENGTH); @@ -55,8 +52,7 @@ __Z_INLINE bool process_chunk(uint32_t rx) { THROW(APDU_CODE_INVALIDP1P2); } - - uint32_t added; + uint32_t added = 0; switch (payloadType) { case 0: tx_initialize(); @@ -89,33 +85,29 @@ __Z_INLINE bool process_chunk(uint32_t rx) { } __Z_INLINE void extract_default_path(uint32_t rx, uint32_t offset) { - extractHDPath(rx, offset, HDPATH_LEN_DEFAULT); // validate - bool mainnet = hdPath[0] == HDPATH_0_DEFAULT && - hdPath[1] == HDPATH_1_DEFAULT; + bool mainnet = false; + mainnet = hdPath[0] == HDPATH_0_DEFAULT && hdPath[1] == HDPATH_1_DEFAULT; mainnet |= (hdPath[0] == HDPATH_0_ALTERNATIVE); - const bool testnet = hdPath[0] == HDPATH_0_TESTNET && - hdPath[1] == HDPATH_1_TESTNET; + bool testnet = false; + testnet = hdPath[0] == HDPATH_0_TESTNET && hdPath[1] == HDPATH_1_TESTNET; - if (!mainnet && !testnet) + if (!mainnet && !testnet) { THROW(APDU_CODE_DATA_INVALID); - + } } __Z_INLINE void extract_identity_path(uint32_t rx, uint32_t offset) { - extractHDPath(rx, offset, HDPATH_LEN_AUTH); // validate - const bool identity_path = hdPath[0] == HDPATH_0_AUTH && - hdPath[1] == HDPATH_1_AUTH; - if (!identity_path) - THROW(APDU_CODE_DATA_INVALID); - + bool identity_path = false; + identity_path = hdPath[0] == HDPATH_0_AUTH && hdPath[1] == HDPATH_1_AUTH; + if (!identity_path) THROW(APDU_CODE_DATA_INVALID); } __Z_INLINE void handle_getversion(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { @@ -143,12 +135,15 @@ __Z_INLINE void handle_getversion(volatile uint32_t *flags, volatile uint32_t *t __Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { extract_default_path(rx, OFFSET_DATA); - uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; - uint8_t network = G_io_apdu_buffer[OFFSET_P2]; + uint8_t requireConfirmation = 0; + uint8_t network = 0; + requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; + network = G_io_apdu_buffer[OFFSET_P2]; // Set the address version - if (!set_network_version(network)) + if (!set_network_version(network)) { return THROW(APDU_CODE_DATA_INVALID); + } if (requireConfirmation) { app_fill_address(addr_secp256k1); @@ -194,7 +189,6 @@ __Z_INLINE void SignSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, u *flags |= IO_ASYNCH_REPLY; } - __Z_INLINE void handleSignSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { // check first for the expected path at initialization if (G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE] == 0) { @@ -216,10 +210,8 @@ __Z_INLINE void handleSignJwtSecp256K1(volatile uint32_t *flags, volatile uint32 void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { uint16_t sw = 0; - BEGIN_TRY - { - TRY - { + BEGIN_TRY { + TRY { if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { THROW(APDU_CODE_CLA_NOT_SUPPORTED); } @@ -270,27 +262,24 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { THROW(APDU_CODE_INS_NOT_SUPPORTED); } } - CATCH(EXCEPTION_IO_RESET) - { + CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } - CATCH_OTHER(e) - { - switch (e & 0xF000) { + CATCH_OTHER(err) { + switch (err & 0xF000) { case 0x6000: case APDU_CODE_OK: - sw = e; + sw = err; break; default: - sw = 0x6800 | (e & 0x7FF); + sw = 0x6800 | (err & 0x7FF); break; } G_io_apdu_buffer[*tx] = sw >> 8; G_io_apdu_buffer[*tx + 1] = sw; *tx += 2; } - FINALLY - { + FINALLY { } } END_TRY; diff --git a/app/src/c_api/rust.c b/app/src/c_api/rust.c index 4712ef3d..574c4cbb 100644 --- a/app/src/c_api/rust.c +++ b/app/src/c_api/rust.c @@ -1,9 +1,9 @@ #include -#include #include -#include "os.h" -#include "cx.h" +#include +#include "cx.h" +#include "os.h" uint16_t fp_uint64_to_str(char *out, uint16_t outLen, const uint64_t value, uint8_t decimals) { return fpuint64_to_str(out, outLen, value, decimals); diff --git a/app/src/coin.h b/app/src/coin.h index 3c283720..b01fbff0 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -1,18 +1,18 @@ /******************************************************************************* -* (c) 2020 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2020 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #if defined(APP_STANDARD) diff --git a/app/src/coin_standard.h b/app/src/coin_standard.h index 4817baa9..2de9fabd 100644 --- a/app/src/coin_standard.h +++ b/app/src/coin_standard.h @@ -1,30 +1,30 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #ifdef __cplusplus extern "C" { #endif -#include #include +#include -#define CLA 0x09 +#define CLA 0x09 -#define HDPATH_LEN_DEFAULT 5 +#define HDPATH_LEN_DEFAULT 5 // support m/888'/0'/ path #define HDPATH_LEN_AUTH 3 @@ -37,40 +37,40 @@ extern "C" { #define HDPATH_0_AUTH (0x80000000u | 888) #define HDPATH_1_AUTH (0x80000000u | 0) -#define HDPATH_0_ALTERNATIVE (0x80000000u | 5757) +#define HDPATH_0_ALTERNATIVE (0x80000000u | 5757) #define HDPATH_0_TESTNET (0x80000000u | 0x2cu) #define HDPATH_1_TESTNET (0x80000000u | 0x1u) // compressed key -#define PK_LEN_SECP256K1 33u +#define PK_LEN_SECP256K1 33u typedef enum { addr_secp256k1 = 0, } address_kind_e; -#define VIEW_ADDRESS_OFFSET_SECP256K1 PK_LEN_SECP256K1 -#define VIEW_ADDRESS_ITEM_COUNT 2 -#define VIEW_ADDRESS_LAST_PAGE_DEFAULT 255 +#define VIEW_ADDRESS_OFFSET_SECP256K1 PK_LEN_SECP256K1 +#define VIEW_ADDRESS_ITEM_COUNT 2 +#define VIEW_ADDRESS_LAST_PAGE_DEFAULT 255 -#define MENU_MAIN_APP_LINE1 "Stacks" -#define MENU_MAIN_APP_LINE2 "Ready" -#define APPVERSION_LINE1 "Stacks" -#define APPVERSION_LINE2 ("v" APPVERSION) +#define MENU_MAIN_APP_LINE1 "Stacks" +#define MENU_MAIN_APP_LINE2 "Ready" +#define APPVERSION_LINE1 "Stacks" +#define APPVERSION_LINE2 ("v" APPVERSION) -#define COIN_SECRET_REQUIRED_CLICKS 0 -#define MENU_MAIN_APP_LINE2_SECRET "??????" +#define COIN_SECRET_REQUIRED_CLICKS 0 +#define MENU_MAIN_APP_LINE2_SECRET "??????" -#define CRYPTO_BLOB_SKIP_BYTES 0 +#define CRYPTO_BLOB_SKIP_BYTES 0 -#define COIN_VERSION_MAINNET_SINGLESIG 22 -#define COIN_VERSION_TESTNET_SINGLESIG 26 +#define COIN_VERSION_MAINNET_SINGLESIG 22 +#define COIN_VERSION_TESTNET_SINGLESIG 26 -#define INS_GET_VERSION 0x00 -#define INS_GET_ADDR_SECP256K1 0x01 -#define INS_SIGN_SECP256K1 0x02 -#define INS_GET_AUTH_PUBKEY 0x03 -#define SIGN_JWT_SECP256K1 0x04 +#define INS_GET_VERSION 0x00 +#define INS_GET_ADDR_SECP256K1 0x01 +#define INS_SIGN_SECP256K1 0x02 +#define INS_GET_AUTH_PUBKEY 0x03 +#define SIGN_JWT_SECP256K1 0x04 #ifdef __cplusplus } diff --git a/app/src/common/actions.c b/app/src/common/actions.c index 8f065911..60b1e0d2 100644 --- a/app/src/common/actions.c +++ b/app/src/common/actions.c @@ -1,19 +1,19 @@ /******************************************************************************* -* (c) 2016 Ledger -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2016 Ledger + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "actions.h" diff --git a/app/src/common/actions.h b/app/src/common/actions.h index 93051fde..77190d8d 100644 --- a/app/src/common/actions.h +++ b/app/src/common/actions.h @@ -1,30 +1,31 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once +#include #include -#include "zxmacros.h" + +#include "apdu_codes.h" +#include "coin.h" #include "crypto.h" #include "cx.h" +#include "sha512.h" #include "tx.h" -#include "apdu_codes.h" -#include -#include "coin.h" #include "zxformat.h" -#include "sha512.h" +#include "zxmacros.h" // The initial tx hash is done in 3 blocks // this is the length in bytes of the first block @@ -67,10 +68,10 @@ extern uint8_t action_addr_len; // helper function to get the presig_hash of the transaction being signed -__Z_INLINE zxerr_t get_presig_hash(uint8_t* hash, uint16_t hashLen); +__Z_INLINE zxerr_t get_presig_hash(uint8_t *hash, uint16_t hashLen); // Helper function that appends the transaction auth_type, fee and nonce getting the hash of the result -__Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t* input_hash, uint16_t input_hashLen, uint8_t* hash, uint16_t hashLen); +__Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t *input_hash, uint16_t input_hashLen, uint8_t *hash, uint16_t hashLen); // Helper function to compute post_sighash from pre_sighash // Updates `hash` in place @@ -81,8 +82,8 @@ __Z_INLINE zxerr_t compute_post_sig_hash(uint8_t *hash, uint16_t hash_len, uint8 __Z_INLINE zxerr_t compute_sig_hash_chain(uint8_t *hash, uint16_t hash_len); __Z_INLINE void app_sign() { - uint8_t presig_hash[CX_SHA256_SIZE]; - uint8_t post_sighash_data[POST_SIGNHASH_DATA_LEN]; + uint8_t presig_hash[CX_SHA256_SIZE] = {0}; + uint8_t post_sighash_data[POST_SIGNHASH_DATA_LEN] = {0}; zxerr_t err = zxerr_ok; const uint8_t transaction_type = tx_get_transaction_type(); @@ -97,33 +98,32 @@ __Z_INLINE void app_sign() { // Validate post_sig_hashes of previous signers uint8_t hash_mode = -1; err = tx_hash_mode(&hash_mode); - if (err != zxerr_ok) { - zemu_log_stack("Error getting HashMode\n"); - } - else switch (hash_mode) { - case 0x00: // P2PKH - case 0x02: // P2WPKH - // Singlesig - // Shouldn't be here! - zemu_log_stack("HashMode is not multisig\n"); - err = zxerr_unknown; - break; - case 0x01: // P2SH sequential - case 0x03: // P2WSH sequential - // Sequential multisig - // Need to compute sighashes of all previous signers - err = compute_sig_hash_chain(presig_hash, CX_SHA256_SIZE); - break; - case 0x05: // PWSH non-sequential - case 0x07: // P2WSH non-sequential - // Non-sequential multisig - // No need to do anything - err = zxerr_ok; - break; - default: - zemu_log_stack("Invalid HashMode\n"); - err = zxerr_unknown; - break; + if (err == zxerr_ok) { + switch (hash_mode) { + case 0x00: // P2PKH + case 0x02: // P2WPKH + // Singlesig + // Shouldn't be here! + zemu_log_stack("HashMode is not multisig\n"); + err = zxerr_unknown; + break; + case 0x01: // P2SH sequential + case 0x03: // P2WSH sequential + // Sequential multisig + // Need to compute sighashes of all previous signers + err = compute_sig_hash_chain(presig_hash, CX_SHA256_SIZE); + break; + case 0x05: // PWSH non-sequential + case 0x07: // P2WSH non-sequential + // Non-sequential multisig + // No need to do anything + err = zxerr_ok; + break; + default: + zemu_log_stack("Invalid HashMode\n"); + err = zxerr_unknown; + break; + } } } @@ -136,7 +136,7 @@ __Z_INLINE void app_sign() { // Take "ownership" of the memory used by the transaction parser tx_reset_state(); - uint16_t replyLen; + uint16_t replyLen = 0; err = crypto_sign(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, presig_hash, CX_SHA256_SIZE, &replyLen); if (err != zxerr_ok) { set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR); @@ -153,7 +153,7 @@ __Z_INLINE void app_sign() { post_sighash_data[CX_SHA256_SIZE] = 0x00; // Now get the post_sighash from the data and write it down to the first 32-byte of the G_io_apdu_buffer - uint8_t hash_temp[SHA512_DIGEST_LENGTH]; + uint8_t hash_temp[SHA512_DIGEST_LENGTH] = {0}; // Now get the presig_hash sha512_256_ctx ctx; @@ -170,7 +170,6 @@ __Z_INLINE void app_sign() { SHA512_256_finish(&ctx, hash_temp); memcpy(G_io_apdu_buffer, hash_temp, CX_SHA256_SIZE); break; - } case Message: case Jwt: @@ -179,7 +178,7 @@ __Z_INLINE void app_sign() { // which is the hash that is signed allowing for easy signature verification memcpy(G_io_apdu_buffer, presig_hash, CX_SHA256_SIZE); break; - } + } default: { set_code(G_io_apdu_buffer, 0, APDU_CODE_SIGN_VERIFY_ERROR); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); @@ -236,7 +235,6 @@ __Z_INLINE uint8_t app_fill_auth_pubkey(address_kind_e kind) { return action_addr_len; } - __Z_INLINE void app_reply_address() { set_code(G_io_apdu_buffer, action_addr_len, APDU_CODE_OK); io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, action_addr_len + 2); @@ -249,7 +247,7 @@ __Z_INLINE void app_reply_error() { __Z_INLINE zxerr_t compute_post_sig_hash(uint8_t *hash, uint16_t hash_len, uint8_t *signer_data, uint16_t signer_data_len) { uint16_t expected_signer_data_len = 1 + PREVIOUS_SIGNER_SIG_LEN; - if ( (hash_len != CX_SHA256_SIZE) || (signer_data_len != expected_signer_data_len)) { + if ((hash_len != CX_SHA256_SIZE) || (signer_data_len != expected_signer_data_len)) { return zxerr_no_data; } @@ -273,7 +271,7 @@ __Z_INLINE zxerr_t compute_sig_hash_chain(uint8_t *hash, uint16_t hash_len) { // 1-byte pubkey type(compressed/uncompressed) // 65-byte previous signer signature(vrs) - uint8_t previous_signer_data[1 + PREVIOUS_SIGNER_SIG_LEN]; + uint8_t previous_signer_data[1 + PREVIOUS_SIGNER_SIG_LEN] = {0}; memset(previous_signer_data, 0, sizeof(previous_signer_data)); uint32_t num_fields = tx_num_multisig_fields(); @@ -325,7 +323,7 @@ __Z_INLINE zxerr_t compute_sig_hash_chain(uint8_t *hash, uint16_t hash_len) { return zxerr_ok; } -__Z_INLINE zxerr_t get_presig_hash(uint8_t* hash, uint16_t hashLen) { +__Z_INLINE zxerr_t get_presig_hash(uint8_t *hash, uint16_t hashLen) { zemu_log_stack("computing presig_hash"); uint8_t tx_auth[INITIAL_SIGHASH_AUTH_LEN]; @@ -343,47 +341,46 @@ __Z_INLINE zxerr_t get_presig_hash(uint8_t* hash, uint16_t hashLen) { const uint16_t data_len = tx_get_buffer_length() - CRYPTO_BLOB_SKIP_BYTES; switch (tx_typ) { - case Transaction: { - // Before hashing the transaction the auth field should be cleared - // and the sponsor set to signing sentinel. - uint16_t auth_len = 0; - auth_len = tx_presig_hash_data(tx_auth, INITIAL_SIGHASH_AUTH_LEN); - // prepare the last transaction block to be hashed - SHA512_256_update(&ctx, data, TRANSACTION_FIRST_BLOCK_LEN); - SHA512_256_update(&ctx, tx_auth, auth_len); - uint8_t *last_block = NULL; - uint8_t **last_block_ptr = &last_block; - - uint16_t last_block_len = tx_last_tx_block(last_block_ptr); - if (last_block == NULL || last_block_len == 0) { - return zxerr_no_data; + case Transaction: { + // Before hashing the transaction the auth field should be cleared + // and the sponsor set to signing sentinel. + uint16_t auth_len = 0; + auth_len = tx_presig_hash_data(tx_auth, INITIAL_SIGHASH_AUTH_LEN); + // prepare the last transaction block to be hashed + SHA512_256_update(&ctx, data, TRANSACTION_FIRST_BLOCK_LEN); + SHA512_256_update(&ctx, tx_auth, auth_len); + uint8_t *last_block = NULL; + uint8_t **last_block_ptr = &last_block; + + uint16_t last_block_len = tx_last_tx_block(last_block_ptr); + if (last_block == NULL || last_block_len == 0) { + return zxerr_no_data; + } + + SHA512_256_update(&ctx, last_block, last_block_len); + SHA512_256_finish(&ctx, hash_temp); + return append_fee_nonce_auth_hash(hash_temp, CX_SHA256_SIZE, hash, hashLen); } - - SHA512_256_update(&ctx, last_block, last_block_len); - SHA512_256_finish(&ctx, hash_temp); - return append_fee_nonce_auth_hash(hash_temp, CX_SHA256_SIZE, hash, hashLen); - } - case Message: - case Jwt: { - // we have byteString or JWT messages. The hash is the same for both types - cx_hash_sha256(data, data_len, hash, CX_SHA256_SIZE); - return zxerr_ok; - } - // special case is delegated to the rust side - case StructuredMsg: { - return tx_structured_msg_hash(hash, CX_SHA256_SIZE); - } - default: - return zxerr_no_data; + case Message: + case Jwt: { + // we have byteString or JWT messages. The hash is the same for both types + cx_hash_sha256(data, data_len, hash, CX_SHA256_SIZE); + return zxerr_ok; + } + // special case is delegated to the rust side + case StructuredMsg: { + return tx_structured_msg_hash(hash, CX_SHA256_SIZE); + } + default: + return zxerr_no_data; } } -__Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t* input_hash, uint16_t input_hashLen, uint8_t* hash, uint16_t hashLen) { - uint8_t presig_data[PRESIG_DATA_LEN]; +__Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t *input_hash, uint16_t input_hashLen, uint8_t *hash, uint16_t hashLen) { + uint8_t presig_data[PRESIG_DATA_LEN] = {0}; // uint8_t hash_temp[SHA512_DIGEST_LENGTH]; - if ( input_hashLen != CX_SHA256_SIZE ) - return zxerr_no_data; + if (input_hashLen != CX_SHA256_SIZE) return zxerr_no_data; memcpy(presig_data, input_hash, input_hashLen); @@ -391,8 +388,7 @@ __Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t* input_hash, uint16_t inpu uint8_t idx = CX_SHA256_SIZE; // append the tx auth type - if (tx_auth_flag(&presig_data[idx++]) != zxerr_ok) - return zxerr_no_data; + if (tx_auth_flag(&presig_data[idx++]) != zxerr_ok) return zxerr_no_data; // append the 8-byte transaction fee idx += tx_fee(&presig_data[idx], 8); @@ -400,8 +396,7 @@ __Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t* input_hash, uint16_t inpu // append the 8-byte transaction nonce idx += tx_nonce(&presig_data[idx], 8); - if (hashLen < CX_SHA256_SIZE || idx != PRESIG_DATA_LEN) - return zxerr_no_data; + if (hashLen < CX_SHA256_SIZE || idx != PRESIG_DATA_LEN) return zxerr_no_data; // Now get the hash sha512_256_ctx ctx; @@ -411,4 +406,3 @@ __Z_INLINE zxerr_t append_fee_nonce_auth_hash(uint8_t* input_hash, uint16_t inpu SHA512_256_finish(&ctx, hash); return zxerr_ok; } - diff --git a/app/src/common/main.c b/app/src/common/main.c index 87150f07..ed443c4a 100644 --- a/app/src/common/main.c +++ b/app/src/common/main.c @@ -1,43 +1,40 @@ /******************************************************************************* -* (c) 2016 Ledger -* (c) 2018, 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2016 Ledger + * (c) 2018, 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#include + #include "app_main.h" #include "view.h" -#include - -__attribute__((section(".boot"))) int -main(void) { +__attribute__((section(".boot"))) int main(void) { // exit critical section __asm volatile("cpsie i"); view_init(); os_boot(); - BEGIN_TRY - { - TRY - { + BEGIN_TRY { + TRY { app_init(); app_main(); } - CATCH_OTHER(e) - {} - FINALLY - {} + CATCH_OTHER(e) { + } + FINALLY { + } } END_TRY; } diff --git a/app/src/common/tx.c b/app/src/common/tx.c index 71cfb52b..b624ad7c 100644 --- a/app/src/common/tx.c +++ b/app/src/common/tx.c @@ -15,17 +15,19 @@ ********************************************************************************/ #include "tx.h" + +#include + #include "apdu_codes.h" #include "buffering.h" #include "parser.h" -#include #include "zxmacros.h" #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) || defined(TARGET_FLEX) -#define RAM_BUFFER_SIZE 8192 +#define RAM_BUFFER_SIZE 8192 #define FLASH_BUFFER_SIZE (85 * 1024) #elif defined(TARGET_NANOS) -#define RAM_BUFFER_SIZE 0 +#define RAM_BUFFER_SIZE 0 #define FLASH_BUFFER_SIZE 8192 #endif @@ -33,8 +35,7 @@ uint8_t ram_buffer[RAM_BUFFER_SIZE]; // Flash -typedef struct -{ +typedef struct { uint8_t buffer[FLASH_BUFFER_SIZE]; } storage_t; @@ -45,199 +46,163 @@ storage_t NV_CONST N_appdata_impl __attribute__((aligned(64))); static parser_context_t ctx_parsed_tx; -void tx_initialize() -{ - buffering_init( - ram_buffer, - sizeof(ram_buffer), - (uint8_t *)N_appdata.buffer, - sizeof(N_appdata.buffer)); +void tx_initialize() { + buffering_init(ram_buffer, sizeof(ram_buffer), (uint8_t *)N_appdata.buffer, sizeof(N_appdata.buffer)); } -void tx_reset() -{ +void tx_reset() { buffering_reset(); } -void tx_reset_state() -{ +void tx_reset_state() { parser_resetState(); } -uint32_t tx_append(unsigned char *buffer, uint32_t length) -{ +uint32_t tx_append(unsigned char *buffer, uint32_t length) { return buffering_append(buffer, length); } -uint32_t tx_get_buffer_length() -{ +uint32_t tx_get_buffer_length() { return buffering_get_buffer()->pos; } -uint8_t *tx_get_buffer() -{ +uint8_t *tx_get_buffer() { return buffering_get_buffer()->data; } -const char *tx_parse() -{ - uint8_t err = parser_parse( - &ctx_parsed_tx, - tx_get_buffer(), - tx_get_buffer_length()); +const char *tx_parse() { + uint8_t err = parser_parse(&ctx_parsed_tx, tx_get_buffer(), tx_get_buffer_length()); - if (err != parser_ok) - { + if (err != parser_ok) { return parser_getErrorDescription(err); } err = parser_validate(&ctx_parsed_tx); CHECK_APP_CANARY() - if (err != parser_ok) - { + if (err != parser_ok) { return parser_getErrorDescription(err); } return NULL; } -zxerr_t tx_getNumItems(uint8_t *num_items) -{ +zxerr_t tx_getNumItems(uint8_t *num_items) { parser_error_t err = parser_getNumItems(&ctx_parsed_tx, num_items); - if (err != parser_ok) - { + if (err != parser_ok) { return zxerr_no_data; } return zxerr_ok; } -zxerr_t tx_getItem(int8_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) -{ +zxerr_t tx_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outVal, uint16_t outValLen, uint8_t pageIdx, + uint8_t *pageCount) { uint8_t numItems = 0; CHECK_ZXERR(tx_getNumItems(&numItems)) - if (displayIdx < 0 || displayIdx > numItems) - { + if (displayIdx < 0 || displayIdx > numItems) { return zxerr_no_data; } - parser_error_t err = parser_getItem(&ctx_parsed_tx, - displayIdx, - outKey, outKeyLen, - outVal, outValLen, - pageIdx, pageCount); + parser_error_t err = + parser_getItem(&ctx_parsed_tx, displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount); // Convert error codes - if (err == parser_no_data || - err == parser_display_idx_out_of_range || - err == parser_display_page_out_of_range) + if (err == parser_no_data || err == parser_display_idx_out_of_range || err == parser_display_page_out_of_range) return zxerr_no_data; - if (err != parser_ok) + if (err != parser_ok) { return zxerr_unknown; + } return zxerr_ok; } -zxerr_t tx_auth_flag(uint8_t *flag) -{ - if (parser_tx_auth_flag(flag) != parser_ok) - return zxerr_unknown; +zxerr_t tx_auth_flag(uint8_t *flag) { + if (parser_tx_auth_flag(flag) != parser_ok) return zxerr_unknown; return zxerr_ok; } -uint8_t tx_fee(uint8_t *fee, uint16_t fee_len) -{ +uint8_t tx_fee(uint8_t *fee, uint16_t fee_len) { return parser_tx_fee(fee, fee_len); } -uint8_t tx_nonce(uint8_t *nonce, uint16_t nonce_len) -{ +uint8_t tx_nonce(uint8_t *nonce, uint16_t nonce_len) { return parser_tx_nonce(nonce, nonce_len); } -uint16_t tx_presig_hash_data(uint8_t *buf, uint16_t bufLen) -{ +uint16_t tx_presig_hash_data(uint8_t *buf, uint16_t bufLen) { return parser_presig_hash_data(buf, bufLen); } -uint16_t tx_last_tx_block(uint8_t **last_tx_block) -{ +uint16_t tx_last_tx_block(uint8_t **last_tx_block) { return parser_last_transaction_block(last_tx_block); } -int8_t tx_is_multisig() -{ +int8_t tx_is_multisig() { return parser_is_transaction_multisig(); } -zxerr_t tx_hash_mode(uint8_t *hash_mode) -{ +zxerr_t tx_hash_mode(uint8_t *hash_mode) { parser_error_t err = parser_hash_mode(hash_mode); // Convert error codes - if (err == parser_no_data) + if (err == parser_no_data) { return zxerr_no_data; + } - if (err != parser_ok) + if (err != parser_ok) { return zxerr_unknown; + } return zxerr_ok; } -uint16_t tx_previous_signer_data(uint8_t **data) -{ +uint16_t tx_previous_signer_data(uint8_t **data) { return parser_previous_signer_data(data); } -uint32_t tx_num_multisig_fields() -{ +uint32_t tx_num_multisig_fields() { return parser_num_multisig_fields(); } -zxerr_t tx_get_multisig_field(uint32_t index, uint8_t *id, uint8_t **data) -{ +zxerr_t tx_get_multisig_field(uint32_t index, uint8_t *id, uint8_t **data) { parser_error_t err = parser_get_multisig_field(index, id, data); // Convert error codes - if (err == parser_no_data) + if (err == parser_no_data) { return zxerr_no_data; + } - if (err != parser_ok) + if (err != parser_ok) { return zxerr_unknown; + } return zxerr_ok; } -transaction_type_t tx_get_transaction_type() -{ +transaction_type_t tx_get_transaction_type() { return parser_get_transaction_type(); } -zxerr_t tx_structured_msg_hash(uint8_t *out, uint16_t out_len) -{ +zxerr_t tx_structured_msg_hash(uint8_t *out, uint16_t out_len) { return parser_structured_msg_hash(out, out_len); } -uint16_t get_error_message(char *out, uint16_t outLen, parser_error_t error_code) -{ +uint16_t get_error_message(char *out, uint16_t outLen, parser_error_t error_code) { const char *error_message = parser_getErrorDescription(error_code); - if (error_message == NULL || outLen == 0) - { + if (error_message == NULL || outLen == 0) { return 0; } uint16_t len = strlen(error_message); - if (outLen < len) + if (outLen < len) { return 0; + } memcpy(out, error_message, len); diff --git a/app/src/common/tx.h b/app/src/common/tx.h index ff8ff986..ff61d754 100644 --- a/app/src/common/tx.h +++ b/app/src/common/tx.h @@ -1,24 +1,24 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once -#include "os.h" #include "coin.h" -#include "zxerror.h" +#include "os.h" #include "parser_common.h" +#include "zxerror.h" void tx_initialize(); @@ -51,9 +51,7 @@ const char *tx_parse(); zxerr_t tx_getNumItems(uint8_t *num_items); /// Gets an specific item from the transaction (including paging) -zxerr_t tx_getItem(int8_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, +zxerr_t tx_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, char *outValue, uint16_t outValueLen, uint8_t pageIdx, uint8_t *pageCount); // Gets the transaction authorization type @@ -81,7 +79,7 @@ uint8_t tx_nonce(uint8_t *nonce, uint16_t nonce_len); uint16_t tx_presig_hash_data(uint8_t *buf, uint16_t bufLen); // Gets a pointer to the last block in the transaction and returns its lenght -uint16_t tx_last_tx_block(uint8_t ** last_tx_block); +uint16_t tx_last_tx_block(uint8_t **last_tx_block); // Gets the pointer to the previous signer signature and required data // for signing a multisig transaction diff --git a/app/src/crypto.c b/app/src/crypto.c index 55203d20..036dfc6c 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -1,26 +1,27 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #include "crypto.h" -#include "sha512.h" + #include "coin.h" -#include "zxmacros.h" -#include "zxformat.h" -#include "rslib.h" #include "cx_errors.h" +#include "rslib.h" +#include "sha512.h" +#include "zxformat.h" +#include "zxmacros.h" uint8_t version; @@ -28,21 +29,20 @@ uint32_t hdPath[HDPATH_LEN_DEFAULT]; uint32_t hdPath_len; bool isTestnet() { - return hdPath[0] == HDPATH_0_TESTNET && - hdPath[1] == HDPATH_1_TESTNET; + return hdPath[0] == HDPATH_0_TESTNET && hdPath[1] == HDPATH_1_TESTNET; } #include "cx.h" bool ripemd160(uint8_t *in, uint16_t inLen, uint8_t *out) { cx_ripemd160_t rip160; - if( cx_ripemd160_init_no_throw(&rip160) == CX_OK && + if (cx_ripemd160_init_no_throw(&rip160) == CX_OK && cx_hash_no_throw(&rip160.header, CX_LAST, in, inLen, out, CX_RIPEMD160_SIZE) == CX_OK) { return true; - } else { - MEMZERO(out, CX_RIPEMD160_SIZE); - return false; } + + MEMZERO(out, CX_RIPEMD160_SIZE); + return false; } typedef struct { @@ -50,14 +50,13 @@ typedef struct { uint8_t address[50]; } __attribute__((packed)) answer_t; -#define VERSION_SIZE 1 +#define VERSION_SIZE 1 typedef struct { uint8_t hash_sha256[CX_SHA256_SIZE]; uint8_t hash_ripe[CX_RIPEMD160_SIZE]; } __attribute__((packed)) address_temp_t; - bool is_valid_network_version(uint8_t ver); // Set the network version to be used when getting the address from @@ -72,9 +71,11 @@ bool set_network_version(uint8_t network) { } bool is_valid_network_version(uint8_t ver) { - switch(ver) { - case COIN_VERSION_TESTNET_SINGLESIG: break; - case COIN_VERSION_MAINNET_SINGLESIG: break; + switch (ver) { + case COIN_VERSION_TESTNET_SINGLESIG: + break; + case COIN_VERSION_MAINNET_SINGLESIG: + break; default: { return false; } @@ -88,21 +89,22 @@ uint16_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t buffer_len) { } MEMZERO(buffer, buffer_len); - answer_t *const answer = (answer_t *) buffer; + answer_t *const answer = (answer_t *)buffer; - if(crypto_extractPublicKey(hdPath, HDPATH_LEN_DEFAULT, answer->publicKey, sizeof_field(answer_t, publicKey)) != zxerr_ok) { + if (crypto_extractPublicKey(hdPath, HDPATH_LEN_DEFAULT, answer->publicKey, sizeof_field(answer_t, publicKey)) != + zxerr_ok) { return 0; } address_temp_t address_temp; - if(!crypto_extractPublicKeyHash(address_temp.hash_ripe, CX_RIPEMD160_SIZE)) { + if (!crypto_extractPublicKeyHash(address_temp.hash_ripe, CX_RIPEMD160_SIZE)) { return 0; } - size_t outLen = sizeof_field(answer_t, address); - if ( !is_valid_network_version(version) ) - version = COIN_VERSION_MAINNET_SINGLESIG; + size_t outLen = 0; + outLen = sizeof_field(answer_t, address); + if (!is_valid_network_version(version)) version = COIN_VERSION_MAINNET_SINGLESIG; outLen = rs_c32_address(address_temp.hash_ripe, version, answer->address, outLen); return PK_LEN_SECP256K1 + outLen; @@ -114,16 +116,15 @@ uint16_t crypto_fillAuthkey_secp256k1(uint8_t *buffer, uint16_t buffer_len) { } MEMZERO(buffer, buffer_len); - answer_t *const answer = (answer_t *) buffer; + answer_t *const answer = (answer_t *)buffer; - if(crypto_extractPublicKey(hdPath, HDPATH_LEN_AUTH, answer->publicKey, sizeof_field(answer_t, publicKey)) != zxerr_ok) { + if (crypto_extractPublicKey(hdPath, HDPATH_LEN_AUTH, answer->publicKey, sizeof_field(answer_t, publicKey)) != zxerr_ok) { return 0; } return PK_LEN_SECP256K1; } - zxerr_t crypto_extractPublicKey(const uint32_t *path, uint32_t path_len, uint8_t *pubKey, uint16_t pubKeyLen) { cx_ecfp_public_key_t cx_publicKey; cx_ecfp_private_key_t cx_privateKey; @@ -135,10 +136,7 @@ zxerr_t crypto_extractPublicKey(const uint32_t *path, uint32_t path_len, uint8_t } zxerr_t error = zxerr_unknown; - CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, - path, - path_len, - privateKeyData, NULL)); + CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, path, path_len, privateKeyData, NULL)); CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &cx_privateKey)); CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey)); @@ -162,12 +160,12 @@ zxerr_t crypto_extractPublicKey(const uint32_t *path, uint32_t path_len, uint8_t } bool crypto_extractPublicKeyHash(uint8_t *pubKeyHash, uint16_t pubKeyLen) { - - if (pubKeyLen < CX_RIPEMD160_SIZE || pubKeyHash == NULL) + if (pubKeyLen < CX_RIPEMD160_SIZE || pubKeyHash == NULL) { return false; + } // gets the raw public key - uint8_t publicKey[PK_LEN_SECP256K1]; + uint8_t publicKey[PK_LEN_SECP256K1] = {0}; if (crypto_extractPublicKey(hdPath, HDPATH_LEN_DEFAULT, publicKey, PK_LEN_SECP256K1) != zxerr_ok) { return false; @@ -177,7 +175,7 @@ bool crypto_extractPublicKeyHash(uint8_t *pubKeyHash, uint16_t pubKeyLen) { { zemu_log("pubKey: ***"); char buffer[PK_LEN_SECP256K1 * 3]; - array_to_hexstr(buffer, PK_LEN_SECP256K1 * 3, publicKey, PK_LEN_SECP256K1 ); + array_to_hexstr(buffer, PK_LEN_SECP256K1 * 3, publicKey, PK_LEN_SECP256K1); zemu_log(buffer); zemu_log("\n"); } @@ -187,7 +185,7 @@ bool crypto_extractPublicKeyHash(uint8_t *pubKeyHash, uint16_t pubKeyLen) { address_temp_t address_temp; cx_hash_sha256(publicKey, PK_LEN_SECP256K1, address_temp.hash_sha256, CX_SHA256_SIZE); - return ripemd160(address_temp.hash_sha256, CX_SHA256_SIZE, pubKeyHash); // RIPEMD-160 + return ripemd160(address_temp.hash_sha256, CX_SHA256_SIZE, pubKeyHash); // RIPEMD-160 } typedef struct { @@ -202,61 +200,51 @@ typedef struct { } __attribute__((packed)) signature_t; -zxerr_t crypto_sign(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, uint16_t *sigSize) { +zxerr_t crypto_sign(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, + uint16_t *sigSize) { if (signatureMaxlen < sizeof_field(signature_t, der_signature)) { return zxerr_buffer_too_small; } - *sigSize=0; + *sigSize = 0; if (messageLen != CX_SHA256_SIZE) { return zxerr_out_of_bounds; } - #ifdef APP_TESTING - char tmpBuff[65] = {0}; - array_to_hexstr(tmpBuff, sizeof(tmpBuff), message, CX_SHA256_SIZE); - ZEMU_LOGF(100, "Digest: *** %s\n", tmpBuff) - #endif +#ifdef APP_TESTING + char tmpBuff[65] = {0}; + array_to_hexstr(tmpBuff, sizeof(tmpBuff), message, CX_SHA256_SIZE); + ZEMU_LOGF(100, "Digest: *** %s\n", tmpBuff) +#endif cx_ecfp_private_key_t cx_privateKey; - uint8_t privateKeyData[SK_LEN_25519]; + uint8_t privateKeyData[SK_LEN_25519] = {0}; unsigned int info = 0; - signature_t *const signature = (signature_t *) buffer; + signature_t *const signature = (signature_t *)buffer; zxerr_t zxerr = zxerr_unknown; - CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, - hdPath, - hdPath_len, - privateKeyData, NULL)); + CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, hdPath, hdPath_len, privateKeyData, NULL)); CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, 32, &cx_privateKey)); // Sign - size_t signatureLength = sizeof_field(signature_t, der_signature); - CATCH_CXERROR(cx_ecdsa_sign_no_throw(&cx_privateKey, - CX_RND_RFC6979 | CX_LAST, - CX_SHA256, - message, - CX_SHA256_SIZE, - signature->der_signature, - &signatureLength, - &info)); + size_t signatureLength = 0; + signatureLength = sizeof_field(signature_t, der_signature); + CATCH_CXERROR(cx_ecdsa_sign_no_throw(&cx_privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, message, CX_SHA256_SIZE, + signature->der_signature, &signatureLength, &info)); zxerr = zxerr_ok; - err_convert_e err = convertDERtoRSV(signature->der_signature, info, signature->r, signature->s, &signature->v); + err_convert_e err = convertDERtoRSV(signature->der_signature, info, signature->r, signature->s, &signature->v); if (err != no_error) { return zxerr_encoding_failed; } // return actual size using value from signatureLength - *sigSize = sizeof_field(signature_t, r) + - sizeof_field(signature_t, s) + - sizeof_field(signature_t, v) + - sizeof_field(signature_t, post_sighash) + - signatureLength; + *sigSize = sizeof_field(signature_t, r) + sizeof_field(signature_t, s) + sizeof_field(signature_t, v) + + sizeof_field(signature_t, post_sighash) + signatureLength; catch_cx_error: MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); diff --git a/app/src/crypto.h b/app/src/crypto.h index b0e4acfb..de6cfaa4 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -1,18 +1,18 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once @@ -20,13 +20,14 @@ extern "C" { #endif +#include +#include #include + #include "coin.h" -#include -#include #include "zxerror.h" -#define CHECKSUM_LENGTH 4 +#define CHECKSUM_LENGTH 4 extern uint32_t hdPath[HDPATH_LEN_DEFAULT]; extern uint32_t hdPath_len; @@ -46,10 +47,7 @@ bool crypto_extractPublicKeyHash(uint8_t *pubKey, uint16_t pubKeyLen); uint16_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t bufferLen); uint16_t crypto_fillAuthkey_secp256k1(uint8_t *buffer, uint16_t bufferLen); -zxerr_t crypto_sign(uint8_t *buffer, - uint16_t signatureMaxlen, - const uint8_t *message, - uint16_t messageLen, +zxerr_t crypto_sign(uint8_t *buffer, uint16_t signatureMaxlen, const uint8_t *message, uint16_t messageLen, uint16_t *sigSize); #ifdef __cplusplus diff --git a/app/src/parser.c b/app/src/parser.c index ed7e9ae9..a33e3cb1 100644 --- a/app/src/parser.c +++ b/app/src/parser.c @@ -1,24 +1,26 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ + +#include "parser.h" #include #include -#include "parser_txdef.h" -#include "parser.h" + #include "coin.h" +#include "parser_txdef.h" #include "rslib.h" static zxerr_t parser_allocate(); @@ -40,8 +42,8 @@ parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t d return parser_context_unexpected_size; } - if(parser_allocate() != zxerr_ok) { - return parser_init_context_empty ; + if (parser_allocate() != zxerr_ok) { + return parser_init_context_empty; } parser_error_t err = _read(ctx, &parser_state); @@ -49,18 +51,17 @@ parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t d } parser_error_t parser_validate(const parser_context_t *ctx) { - - uint8_t pubKeyHash[CX_RIPEMD160_SIZE]; + uint8_t pubKeyHash[CX_RIPEMD160_SIZE] = {0}; crypto_extractPublicKeyHash(pubKeyHash, CX_RIPEMD160_SIZE); // Checks if the data being processed is a transaction and if so, verify this device is allowed to sign this transaction - if ( parser_get_transaction_type() == Transaction ) { - if (_check_pubkey_hash(&parser_state, pubKeyHash, CX_RIPEMD160_SIZE) != parser_ok) - return parser_invalid_auth_type; + if (parser_get_transaction_type() == Transaction) { + if (_check_pubkey_hash(&parser_state, pubKeyHash, CX_RIPEMD160_SIZE) != parser_ok) { + return parser_invalid_auth_type; + } } - uint8_t numItems = 0; CHECK_PARSER_ERR(parser_getNumItems(ctx, &numItems)); @@ -79,18 +80,15 @@ parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_item return _getNumItems(ctx, &parser_state, num_items); } -parser_error_t parser_getItem(const parser_context_t *ctx, - uint16_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, - uint8_t pageIdx, uint8_t *pageCount) { +parser_error_t parser_getItem(const parser_context_t *ctx, uint16_t displayIdx, char *outKey, uint16_t outKeyLen, + char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { MEMZERO(outKey, outKeyLen); MEMZERO(outVal, outValLen); snprintf(outKey, outKeyLen, "?"); snprintf(outVal, outValLen, "?"); *pageCount = 0; - uint8_t numItems; + uint8_t numItems = 0; CHECK_PARSER_ERR(parser_getNumItems(ctx, &numItems)) CHECK_APP_CANARY() @@ -142,7 +140,7 @@ uint16_t parser_previous_signer_data(uint8_t **data) { return _previous_signer_data(&parser_state, data); } -zxerr_t parser_structured_msg_hash(uint8_t *out, uint16_t out_len){ +zxerr_t parser_structured_msg_hash(uint8_t *out, uint16_t out_len) { if (_structured_msg_hash(&parser_state, out, out_len) != parser_ok) { return zxerr_buffer_too_small; } @@ -153,10 +151,10 @@ zxerr_t parser_allocate() { if (parser_state.len % 4 != 0) { parser_state.len += parser_state.len % 4; } - if(parser_state.len > PARSER_BUFFER_SIZE) { + if (parser_state.len > PARSER_BUFFER_SIZE) { return zxerr_buffer_too_small; } - if(parser_state.state != NULL) { + if (parser_state.state != NULL) { return zxerr_unknown; } @@ -166,7 +164,7 @@ zxerr_t parser_allocate() { } zxerr_t parser_deallocate() { - if(parser_state.state == NULL) { + if (parser_state.state == NULL) { return zxerr_unknown; } parser_state.len = 0; @@ -178,7 +176,7 @@ void parser_resetState() { parser_deallocate(); } -transaction_type_t parser_get_transaction_type(){ +transaction_type_t parser_get_transaction_type() { return _transaction_type(&parser_state); } diff --git a/app/src/parser.h b/app/src/parser.h index 44bd28a6..0bfc6615 100644 --- a/app/src/parser.h +++ b/app/src/parser.h @@ -1,18 +1,18 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once @@ -20,18 +20,16 @@ extern "C" { #endif +#include "crypto.h" +#include "hexutils.h" #include "parser_common.h" #include "parser_txdef.h" -#include "hexutils.h" -#include "crypto.h" extern parser_tx_t parser_state; const char *parser_getErrorDescription(parser_error_t err); //// parses a tx buffer -parser_error_t parser_parse(parser_context_t *ctx, - const uint8_t *data, - size_t dataLen); +parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t dataLen); //// verifies tx fields parser_error_t parser_validate(const parser_context_t *ctx); @@ -40,12 +38,8 @@ parser_error_t parser_validate(const parser_context_t *ctx); parser_error_t parser_getNumItems(const parser_context_t *ctx, uint8_t *num_items); // retrieves a readable output for each field / page -parser_error_t parser_getItem(const parser_context_t *ctx, - uint16_t displayIdx, - char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, - uint8_t pageIdx, uint8_t *pageCount); - +parser_error_t parser_getItem(const parser_context_t *ctx, uint16_t displayIdx, char *outKey, uint16_t outKeyLen, + char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount); /// Gets the transaction authorization type parser_error_t parser_tx_auth_flag(uint8_t *flag); @@ -63,7 +57,7 @@ uint16_t parser_presig_hash_data(uint8_t *buf, uint16_t bufLen); // When signing the full transaction, The transaction hash has to be done in blocks. // this function returns a pointer to the last transaction block and its lenght -uint16_t parser_last_transaction_block(uint8_t ** last_tx_block); +uint16_t parser_last_transaction_block(uint8_t **last_block); // Returns 1 if the transaction is multisig, 0 otherwise int8_t parser_is_transaction_multisig(); diff --git a/app/src/parser_common.h b/app/src/parser_common.h index ae6f1c6d..b9799b79 100644 --- a/app/src/parser_common.h +++ b/app/src/parser_common.h @@ -1,30 +1,32 @@ /******************************************************************************* -* (c) 2019 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2019 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #ifdef __cplusplus extern "C" { #endif -#include #include +#include -#define CHECK_PARSER_ERR(CALL) { \ - parser_error_t err = CALL; \ - if (err!=parser_ok) return err;} +#define CHECK_PARSER_ERR(CALL) \ + { \ + parser_error_t err = CALL; \ + if (err != parser_ok) return err; \ + } typedef enum { // Generic errors @@ -84,14 +86,7 @@ typedef struct { uint16_t offset; } parser_context_t; -typedef enum _TransactionType { - Transaction, - Message, - Jwt, - StructuredMsg, - Invalid -} transaction_type_t; - +typedef enum _TransactionType { Transaction, Message, Jwt, StructuredMsg, Invalid } transaction_type_t; #ifdef __cplusplus } diff --git a/app/src/parser_txdef.h b/app/src/parser_txdef.h index 15fce689..34954643 100644 --- a/app/src/parser_txdef.h +++ b/app/src/parser_txdef.h @@ -1,18 +1,18 @@ /******************************************************************************* -* (c) 2020 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * (c) 2020 Zondax GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ #pragma once #include @@ -22,8 +22,8 @@ extern "C" { #endif -#include #include +#include typedef struct { uint8_t *state; From e504d0701722e31e9a464e245905952b1eef7efc Mon Sep 17 00:00:00 2001 From: neithanmo Date: Thu, 14 Nov 2024 20:45:47 +0100 Subject: [PATCH 3/5] Remove num contract call arguments limit --- .../src/parser/transaction_payload/arguments.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/rust/src/parser/transaction_payload/arguments.rs b/app/rust/src/parser/transaction_payload/arguments.rs index d746ec3c..0a5ac67c 100644 --- a/app/rust/src/parser/transaction_payload/arguments.rs +++ b/app/rust/src/parser/transaction_payload/arguments.rs @@ -1,14 +1,14 @@ use nom::{bytes::complete::take, number::complete::be_u32}; use crate::{ - check_canary, is_expert_mode, + check_canary, parser::{ParserError, Value, TX_DEPTH_LIMIT}, }; // The number of contract call arguments we can handle. // this can be adjusted, but keep in mind that higher values could // hit stack overflows issues. -pub const MAX_NUM_ARGS: u32 = 30; +// pub const MAX_NUM_ARGS: u32 = 30; #[repr(C)] #[derive(Clone, PartialEq)] @@ -22,9 +22,13 @@ impl<'a> Arguments<'a> { let (mut rem, num_args) = be_u32::<_, ParserError>(bytes)?; - if num_args > MAX_NUM_ARGS && !is_expert_mode() { - return Err(ParserError::InvalidTransactionPayload.into()); - } + // Remove this check, this does not affect memory consumption + // and allow user to sign streamline contract calls that in practice have + // more that 30 arguments, for example swap transactions. + // see: https://github.com/Zondax/ledger-stacks/issues/176 + // if num_args > MAX_NUM_ARGS && !is_expert_mode() { + // return Err(ParserError::InvalidTransactionPayload.into()); + // } // Parse all arguments so we can be sure that at runtime when each // argument is retrieved it does not crashes From 285c5a0b71810696b28d794569e7e14753a6867f Mon Sep 17 00:00:00 2001 From: neithanmo Date: Thu, 14 Nov 2024 23:10:47 +0100 Subject: [PATCH 4/5] Add cargo fmt --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88118764..532d4591 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,6 +57,10 @@ jobs: run: | cd ./app/rust cargo clippy --all-targets --features "clippy" + - name: cargo fmt + run: | + cd ./app/rust + cargo fmt build_ledger: needs: configure From a78ae07328a5c00174c5e7a6a4a83db3901c0612 Mon Sep 17 00:00:00 2001 From: neithanmo Date: Tue, 19 Nov 2024 21:37:20 +0100 Subject: [PATCH 5/5] Disable check for dev branch which is local and the working branch pre release --- .github/workflows/check_version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_version.yml b/.github/workflows/check_version.yml index 871d5fcc..c25b54b1 100644 --- a/.github/workflows/check_version.yml +++ b/.github/workflows/check_version.yml @@ -7,7 +7,7 @@ on: - main - develop - master # for safety reasons - - dev # for safety reasons + # - dev # for safety reasons jobs: configure: