Skip to content

Commit

Permalink
Merge pull request #2 from coderofstuff/main
Browse files Browse the repository at this point in the history
Merge security audited changes
  • Loading branch information
agrojean-ledger authored Jan 3, 2024
2 parents 648c585 + ae2bff4 commit 1d19f4f
Show file tree
Hide file tree
Showing 98 changed files with 756 additions and 227 deletions.
7 changes: 7 additions & 0 deletions .clusterfuzzlite/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest AS LITE_BUILDER

FROM gcr.io/oss-fuzz-base/base-builder:v1
COPY . $SRC/app-kaspa
COPY ./.clusterfuzzlite/build.sh $SRC/
COPY --from=LITE_BUILDER /opt/ledger-secure-sdk $SRC/app-kaspa/BOLOS_SDK
WORKDIR $SRC/app-kaspa
11 changes: 11 additions & 0 deletions .clusterfuzzlite/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash -eu

# build fuzzers

pushd fuzzing
cmake -DBOLOS_SDK=../BOLOS_SDK -Bbuild -H.
make -C build
mv ./build/fuzz_tx_parser $OUT
mv ./build/fuzz_txin_parser $OUT
mv ./build/fuzz_txout_parser $OUT
popd
1 change: 1 addition & 0 deletions .clusterfuzzlite/project.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
language: c
40 changes: 40 additions & 0 deletions .github/workflows/cflite_cron.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: ClusterFuzzLite cron tasks
on:
workflow_dispatch:
push:
branches:
- main # Use your actual default branch here.
schedule:
- cron: '0 13 * * 6' # At 01:00 PM, only on Saturday
permissions: read-all
jobs:
Fuzzing:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- mode: batch
sanitizer: address
- mode: batch
sanitizer: memory
- mode: prune
sanitizer: address
- mode: coverage
sanitizer: coverage
steps:
- name: Build Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
language: c # Change this to the language you are fuzzing.
sanitizer: ${{ matrix.sanitizer }}
- name: Run Fuzzers (${{ matrix.mode }} - ${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 300 # 5 minutes
mode: ${{ matrix.mode }}
sanitizer: ${{ matrix.sanitizer }}
43 changes: 43 additions & 0 deletions .github/workflows/cflite_pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: ClusterFuzzLite PR fuzzing
on:
pull_request:
paths:
- '**'
permissions: read-all
jobs:
PR:
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
cancel-in-progress: true
strategy:
fail-fast: false
matrix:
sanitizer: [address, undefined, memory] # Override this with the sanitizers you want.
steps:
- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
with:
language: c # Change this to the language you are fuzzing.
github-token: ${{ secrets.GITHUB_TOKEN }}
sanitizer: ${{ matrix.sanitizer }}
# Optional but recommended: used to only run fuzzers that are affected
# by the PR.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to "main"
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages".
- name: Run Fuzzers (${{ matrix.sanitizer }})
id: run
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fuzz-seconds: 300 # 5 minutes
mode: 'code-change'
sanitizer: ${{ matrix.sanitizer }}
output-sarif: true
# Optional but recommended: used to download the corpus produced by
# batch fuzzing.
# storage-repo: https://${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/OWNER/STORAGE-REPO-NAME.git
# storage-repo-branch: main # Optional. Defaults to "main"
# storage-repo-branch-coverage: gh-pages # Optional. Defaults to "gh-pages".
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ APPNAME = "Kaspa"
# Application version
APPVERSION_M = 1
APPVERSION_N = 0
APPVERSION_P = 1
APPVERSION_P = 2
APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"

ifeq ($(TARGET_NAME),TARGET_NANOS)
Expand Down
20 changes: 11 additions & 9 deletions doc/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
| `GET_APP_NAME` | 0x04 | Get ASCII encoded application name |
| `GET_PUBLIC_KEY` | 0x05 | Get public key given BIP32 path |
| `SIGN_TX` | 0x06 | Sign transaction given transaction info, utxos and outputs |
| `SIGN_MESSAGE` | 0x07 | Sign the personal message |

## GET_VERSION

Expand Down Expand Up @@ -55,11 +56,11 @@ Keys for kaspa normally use the derivation path `m/44'/111111'/<account>'/<type>

| CData Part | Description |
| --- | --- |
| `purpose` | Must be `44'` or `80000002c` |
| `coin_type` | Must be `111111'` or `8001b207` |
| `account` | Current wallets all use `80000000` (aka. `0'`) for default account but any value from `00000000` to `11111111` is accepted if passed |
| `type` | Current wallets use either `00000000` for Receive Address or `00000001` for Change Address, but any value from `00000000` to `11111111` is accepted if passed |
| `index` | Any value from `00000000` to `11111111` if passed |
| `purpose` | Must be `44'` or `0x80000002c` |
| `coin_type` | Must be `111111'` or `0x8001b207` |
| `account` | Current wallets all use `0x80000000` (aka. `0'`) for default account but any value from `0x80000000` to `0xFFFFFFFF` is accepted if passed |
| `type` | Current wallets use either `0x00000000` for Receive Address or `0x00000001` for Change Address, but any value from `0x00000000` to `0xFFFFFFFF` is accepted if passed |
| `index` | Any value from `0x00000000` to `0xFFFFFFFF` if passed |

If you want to generate addresses using a root public key,

Expand Down Expand Up @@ -88,7 +89,7 @@ Transactions signed with ECDSA are currently not supported.

| P1 Value | Usage | CData |
| --- | --- | --- |
| 0x00 | Sending transaction metadata | `version (2)` \|\| `output_len (1)` \|\| `input_len (1)` |
| 0x00 | Sending transaction metadata | `version (2)` \|\| `output_len (1)` \|\| `input_len (1)` \|\| `change_address_type (1)` \|\| `change_address_index (4)` \|\| `account (4)` |
| 0x01 | Sending a tx output | `value (8)` \|\| `script_public_key (34/35)` |
| 0x02 | Sending a tx input | `value (8)` \|\| `tx_id (32)` \|\| `address_type (1)` \|\| `address_index (4)` \|\| `outpoint_index (1)` |
| 0x03 | Requesting for next signature | - |
Expand All @@ -102,7 +103,7 @@ Transactions signed with ECDSA are currently not supported.
`P2` value is used only if `P1 in {0x00, 0x01, 0x02}`. If `P1 = 0x03`, `P2` is ignored.

#### Flow
1. Send the first APDU `P1 = 0x00` with the version, output length and input length
1. Send the first APDU `P1 = 0x00` with the version, output length and input length, change address type and index, and account (for UTXOs and change)
2. For each output (up to 2), send `P1 = 0x01` with the output CData
3. For each UTXO input send `P1 = 0x02` with the input CData. When sending the last UTXO input set `P2 = 0x00` to indicate that it is the last APDU. The signatures will later be sent back to you in the same order these inputs come in.
4. [Display] User will be able to view the transaction info and choose to `Approve` or `Reject`.
Expand Down Expand Up @@ -133,12 +134,13 @@ Transactions signed with ECDSA are currently not supported.

| CLA | INS | P1 | P2 | Lc | CData |
| --- | --- | --- | --- | --- | --- |
| 0xE0 | 0x07 | 0x00 | 0x00 | var | `address_type (1)` \|\| `address_index (4)` \|\|<br>`message_len (1 bytes)` \|\| `message (var bytes)` |
| 0xE0 | 0x07 | 0x00 | 0x00 | var | `address_type (1)` \|\| `address_index (4)` \|\|<br>`account (4)` \|\|<br>`message_len (1 bytes)` \|\| `message (var bytes)` |

| CData Part | Description |
| --- | --- |
| `address_type` | Either `00` for Receive Address or `01` for Change Address |
| `address_index` | Any value from `00000000` to `11111111` |
| `address_index` | Any value from `00000000` to `FFFFFFFF` |
| `account` | Any value from `80000000` to `FFFFFFFF` |
| `message_len` | How long the message is. Must be a value from `1` to `128`, inclusive |
| `message` | The message to sign |

Expand Down
6 changes: 5 additions & 1 deletion doc/TRANSACTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ For ECDSA-signed addresses (supported by this app only as a send address), it be
| `n_outputs` | 1 | The number of outputs. Exactly 1 or 2.
| `change_address_type` | 1 | `0` if `RECEIVE` or `1` if `CHANGE`* |
| `change_address_index` | 4 | `0x00000000` to `0xFFFFFFFF`**|
| `account` | 4 | `0x80000000` to `0xFFFFFFFF`, normally should use `0x80000000` (the default account)***|

\* While this will be used for the change, the path may be either `RECEIVE` or `CHANGE`.
This is necessary in case the user wants to send the change back to the same address.
In this case, the `change_address_type` has to be set to `RECEIVE`.

\*\* `change_address_type` and `change_address_index` are ignored if `n_outputs == 1`. If `n_outputs == 2` then the path defined here must resolve to the same `script_public_key` in `outputs[1]`.

\*\*\* `account` is the BIP44 account. A transaction can only come from a single account. Current Kaspa ecosystem only uses `0'` (or `0x80000000`) but support this is in anticipation of wider account-based support.

### Transaction Input

Total bytes: 46
Expand All @@ -54,7 +58,7 @@ Total bytes: 43 (max)
| Field | Size (bytes) | Description |
| --- | --- | --- |
| `value` | 8 | The amount of KAS in sompi that will go send to the address |
| `script_public_key` | 35 | Schnorr: `20` + public_key (32 bytes) + `ac` <br/> ECDSA: `20` + public_key (33 bytes) + `ab` <br/> P2SH: `aa20` + public_key (32 bytes) + `87` |
| `script_public_key` | 35 | Schnorr: `0x20` + public_key (32 bytes) + `0xac` <br/> ECDSA: `0x20` + public_key (33 bytes) + `0xab` <br/> P2SH: `0xaa, 0x20` + script_hash (32 bytes) + `0x87` |

### Transaction Requirements
- Fee = (total inputs amount) - (total outputs amount)
Expand Down
60 changes: 33 additions & 27 deletions fuzzing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,53 @@ endif()
project(FuzzTxParser
VERSION 1.0
DESCRIPTION "Fuzzing of transaction parser"
LANGUAGES CXX)
LANGUAGES C)

# guard against bad build-type strings
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
message(FATAL_ERROR "Fuzzer needs to be built with Clang")
endif()

if (NOT DEFINED BOLOS_SDK)
message(FATAL_ERROR "BOLOS_SDK environment variable not found.")
endif()

# guard against in-source builds
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
endif()

# compatible with ClusterFuzzLite
if (NOT DEFINED ENV{LIB_FUZZING_ENGINE})
set(COMPILATION_FLAGS_ "-g -Wall -fsanitize=fuzzer,address,undefined")
else()
set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}")
endif()

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_compile_definitions(MAX_INPUT_COUNT=15 MAX_MESSAGE_LEN=200 USB_SEGMENT_SIZE=64)

string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_})

include(extra/TxParser.cmake)

add_executable(fuzz_tx_parser fuzz_tx_parser.cc)
add_executable(fuzz_txout_parser fuzz_txout_parser.cc)
add_executable(fuzz_txin_parser fuzz_txin_parser.cc)

target_compile_options(fuzz_tx_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-g -O2 -fsanitize=fuzzer,address,undefined>
)
target_compile_options(fuzz_txout_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-g -O2 -fsanitize=fuzzer,address,undefined>
)
target_compile_options(fuzz_txin_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-g -O2 -fsanitize=fuzzer,address,undefined>
)

target_link_libraries(fuzz_tx_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-fsanitize=fuzzer,address,undefined>
PUBLIC txparser
)
target_link_libraries(fuzz_txout_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-fsanitize=fuzzer,address,undefined>
PUBLIC txparser
)
target_link_libraries(fuzz_txin_parser
PRIVATE $<$<C_COMPILER_ID:Clang>:-fsanitize=fuzzer,address,undefined>
PUBLIC txparser
)
add_executable(fuzz_tx_parser fuzz_tx_parser.c)
add_executable(fuzz_txout_parser fuzz_txout_parser.c)
add_executable(fuzz_txin_parser fuzz_txin_parser.c)

target_compile_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS})
target_link_options(fuzz_tx_parser PUBLIC ${COMPILATION_FLAGS})
target_link_libraries(fuzz_tx_parser PUBLIC txparser)

target_compile_options(fuzz_txout_parser PUBLIC ${COMPILATION_FLAGS})
target_link_options(fuzz_txout_parser PUBLIC ${COMPILATION_FLAGS})
target_link_libraries(fuzz_txout_parser PUBLIC txparser)

target_compile_options(fuzz_txin_parser PUBLIC ${COMPILATION_FLAGS})
target_link_options(fuzz_txin_parser PUBLIC ${COMPILATION_FLAGS})
target_link_libraries(fuzz_txin_parser PUBLIC txparser)
43 changes: 31 additions & 12 deletions fuzzing/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# Fuzzing on transaction parser

## Setup

Change `~/ledger/app-kaspa` to wherever you actual `app-kaspa` folder is.

```
docker run --rm -it -v ~/kaspa/ledger/app-kaspa:/app ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest bash
```

## Compilation


In `fuzzing` folder

```
cmake -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -Bbuild -H.
cmake -DBOLOS_SDK=$NANOSP_SDK -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H.
```

cmake -DCMAKE_C_COMPILER=/tmp/llvm-project/build/bin/clang \
-DCMAKE_CXX_COMPILER=/tmp/llvm-project/build/bin/clang++ \
-DGCC_INSTALL_PREFIX=/usr/lib/gcc/x86_64-alpine-linux-musl/10.3.1/ \
-Bbuild -H.

then

```
Expand All @@ -23,22 +27,37 @@ make -C build

```
./build/fuzz_tx_parser
./build/fuzz_txin_parser
./build/fuzz_txout_parser
```

## Extra installs
## LLVM Compile

Use this if you want to build the LLVM from scratch and use it

A pre-compiled version of the ones this fuzzing needs is in `llvm-headers`.

Update your docker run to:
```
apk add build-base libc-dev linux-headers libexecinfo-dev llvm12 compiler-rt
docker run -it -v ~/ledger/app-kaspa:/app -v ~/llvm-project:/tmp/llvm-project ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest bash
apk add build-base libc-dev linux-headers libexecinfo-dev compiler-rt
apk del llvm15
```

## LLVM Compile
Clone the LLVM project from: https://github.com/llvm/llvm-project
```
git clone https://github.com/llvm/llvm-project ~/llvm-project
```

```
cd /tmp/llvm-project
mkdir build
cd build
cmake ../llvm/ -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/tmp/llvm-project/build/ -DBUILD_SHARED_LIBS=on -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" -DLLVM_ENABLE_BACKTRACES=OFF -DCOMPILER_RT_BUILD_GWP_ASAN=OFF
cmake ../llvm/ -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/tmp/llvm-project/build/ -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=on -DLLVM_ENABLE_PROJECTS="clang;compiler-rt" -DLLVM_ENABLE_BACKTRACES=OFF -DCOMPILER_RT_BUILD_GWP_ASAN=OFF
make -j8
cp /tmp/llvm-project/build/lib/clang/15.0.0/lib/linux/libclang* /usr/lib/clang/12.0.1/lib/linux/
```
cp /tmp/llvm-project/build/lib/clang/16/lib/x86_64-unknown-linux-gnu/libclang_rt.asan.a /usr/lib/clang/12.0.1/lib/linux/libclang_rt.asan-x86_64.a
cp /tmp/llvm-project/build/lib/clang/16/lib/x86_64-unknown-linux-gnu/libclang_rt.fuzzer.a /usr/lib/clang/12.0.1/lib/linux/libclang_rt.fuzzer-x86_64.a
```
20 changes: 12 additions & 8 deletions fuzzing/extra/TxParser.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@ project(TxParser
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
set(CMAKE_C_FLAGS_DEBUG
"${CMAKE_C_FLAGS_DEBUG} -Werror -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0"
"${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0"
)

add_library(txparser SHARED
${CMAKE_CURRENT_SOURCE_DIR}/../src/common/bip32.c
${CMAKE_CURRENT_SOURCE_DIR}/../src/common/read.c
${CMAKE_CURRENT_SOURCE_DIR}/../src/common/write.c
${CMAKE_CURRENT_SOURCE_DIR}/../src/common/buffer.c
${CMAKE_CURRENT_SOURCE_DIR}/../src/common/format.c
add_library(txparser
${BOLOS_SDK}/lib_standard_app/format.c
${BOLOS_SDK}/lib_standard_app/buffer.c
${BOLOS_SDK}/lib_standard_app/read.c
${BOLOS_SDK}/lib_standard_app/varint.c
${BOLOS_SDK}/lib_standard_app/bip32.c
${BOLOS_SDK}/lib_standard_app/write.c
${CMAKE_CURRENT_SOURCE_DIR}/../src/transaction/deserialize.c
)

set_target_properties(txparser PROPERTIES SOVERSION 1)

target_include_directories(txparser PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../src)
target_include_directories(txparser PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../src
${BOLOS_SDK}/lib_standard_app
)
Loading

0 comments on commit 1d19f4f

Please sign in to comment.