diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml index 69976cd09..6f7de5c8e 100644 --- a/.github/workflows/build_and_functional_tests.yml +++ b/.github/workflows/build_and_functional_tests.yml @@ -34,3 +34,4 @@ jobs: with: download_app_binaries_artifact: "compiled_app_binaries" test_dir: "tests_liquid" + run_for_devices: '["nanosp","nanox"]' diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index f9b73c349..100443464 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -17,13 +17,11 @@ on: jobs: job_build: - name: Compilation for NanoS, X, and S+ + name: Compilation for Nano X, and S+ strategy: matrix: include: - - model: nanos - SDK: "$NANOS_SDK" - model: nanox SDK: "$NANOX_SDK" - model: nanosp @@ -115,7 +113,6 @@ jobs: strategy: matrix: include: - - model: nanos - model: nanox - model: nanosp @@ -139,8 +136,8 @@ jobs: - name: Run tests run: | - cd tests_liquid_main pip install --prefer-binary -r requirements.txt + cd tests_liquid_main PYTHONPATH=$PYTHONPATH:/speculos pytest --tb=short -v --device=${{matrix.model}} --speculos_api_port 5000 job_test_testnet: @@ -148,7 +145,6 @@ jobs: strategy: matrix: include: - - model: nanos - model: nanox - model: nanosp @@ -172,8 +168,8 @@ jobs: - name: Run tests run: | - cd tests_liquid_testnet pip install --prefer-binary -r requirements.txt + cd tests_liquid_testnet PYTHONPATH=$PYTHONPATH:/speculos pytest --tb=short -v --device=${{matrix.model}} --speculos_api_port 5000 job_test_python_lib_legacyapp: @@ -199,9 +195,9 @@ jobs: - name: Run tests run: | + pip install --prefer-binary -r requirements.txt cd bitcoin_client/tests - pip install -r requirements.txt - PYTHONPATH=$PYTHONPATH:/speculos pytest --headless --timeout=300 --model=nanos + PYTHONPATH=$PYTHONPATH:/speculos pytest --headless --timeout=300 --model=nanosp job_test_js_lib: if: false diff --git a/.github/workflows/codeql-workflow.yml b/.github/workflows/codeql-workflow.yml index 71bca058d..dc017b7e6 100644 --- a/.github/workflows/codeql-workflow.yml +++ b/.github/workflows/codeql-workflow.yml @@ -28,18 +28,14 @@ jobs: language: [ 'cpp' ] runs-on: ubuntu-latest container: - image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest - permissions: - actions: read - contents: read - security-events: write + image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest steps: - name: Clone uses: actions/checkout@v4 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} queries: security-and-quality @@ -49,5 +45,5 @@ jobs: make BOLOS_SDK=${{ matrix.SDK }} - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/Makefile b/Makefile index b40e659cc..bd2ed4e7a 100644 --- a/Makefile +++ b/Makefile @@ -27,35 +27,9 @@ ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif -include $(BOLOS_SDK)/Makefile.defines - -# TODO: Compile with the right path restrictions -# -# The right path restriction would be something like -# --path "*'/0'" -# for mainnet, and -# --path "*'/1'" -# for testnet. -# -# That is, restrict the BIP-44 coin_type, but not the purpose. -# However, such wildcards are not currently supported by the OS. -# -# Note that the app still requires explicit user approval before exporting -# any xpub outside of a small set of allowed standard paths. - # Application allowed derivation curves. CURVE_APP_LOAD_PARAMS = secp256k1 -# Application allowed derivation paths. -# -# If there would be a dedicated SDK function returning master key -# fingerprint without the need to derive the root pubkey, the proper path -# configuration should be: -# -# PATH_APP_LOAD_PARAMS = "44'/1'" "48'/1'" "49'/1'" "84'/1'" "86'/1'" -# -PATH_APP_LOAD_PARAMS = "" - # Allowed SLIP21 paths PATH_SLIP21_APP_LOAD_PARAMS = "LEDGER-Wallet policy" @@ -83,65 +57,70 @@ VARIANT_VALUES = liquid_regtest liquid_testnet liquid ######################################## # Application custom permissions # ######################################## -HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1 HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 ifeq ($(COIN),liquid_regtest) - -# Liquid regtest -DEFINES += BIP32_PUBKEY_VERSION=0x043587CF -DEFINES += BIP32_PRIVKEY_VERSION=0x04358394 -DEFINES += BIP44_COIN_TYPE=1 -DEFINES += COIN_P2PKH_VERSION=111 -DEFINES += COIN_P2SH_VERSION=75 -DEFINES += COIN_PREFIX_CONFIDENTIAL=4 -DEFINES += HAVE_LIQUID -DEFINES += LIQUID_NET_REGTEST -DEFINES += COIN_COINID_SHORT=\"tLBTC\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"ert\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"el\" - -APPNAME = "Liquid Regtest" + # Application allowed derivation paths (Liquid testnet/regtest). + PATH_APP_LOAD_PARAMS = "*/1'" # purpose=* / coin_type=Testnet(1) + + # Liquid regtest + DEFINES += BIP32_PUBKEY_VERSION=0x043587CF + DEFINES += BIP32_PRIVKEY_VERSION=0x04358394 + DEFINES += BIP44_COIN_TYPE=1 + DEFINES += COIN_P2PKH_VERSION=111 + DEFINES += COIN_P2SH_VERSION=75 + DEFINES += COIN_PREFIX_CONFIDENTIAL=4 + DEFINES += HAVE_LIQUID + DEFINES += LIQUID_NET_REGTEST + DEFINES += COIN_COINID_SHORT=\"tLBTC\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"ert\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"el\" + + APPNAME = "Liquid Regtest" else ifeq ($(COIN),liquid_testnet) - -# Liquid testnet -DEFINES += BIP32_PUBKEY_VERSION=0x043587CF -DEFINES += BIP32_PRIVKEY_VERSION=0x04358394 -DEFINES += BIP44_COIN_TYPE=1 -DEFINES += COIN_P2PKH_VERSION=36 -DEFINES += COIN_P2SH_VERSION=19 -DEFINES += COIN_PREFIX_CONFIDENTIAL=23 -DEFINES += HAVE_LIQUID -DEFINES += LIQUID_NET_TESTNET -DEFINES += COIN_COINID_SHORT=\"tLBTC\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"tex\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"tlq\" - -APPNAME = "Liquid Testnet" + # Application allowed derivation paths (Liquid testnet/regtest). + PATH_APP_LOAD_PARAMS = "*/1'" # purpose=* / coin_type=Testnet(1) + + # Liquid testnet + DEFINES += BIP32_PUBKEY_VERSION=0x043587CF + DEFINES += BIP32_PRIVKEY_VERSION=0x04358394 + DEFINES += BIP44_COIN_TYPE=1 + DEFINES += COIN_P2PKH_VERSION=36 + DEFINES += COIN_P2SH_VERSION=19 + DEFINES += COIN_PREFIX_CONFIDENTIAL=23 + DEFINES += HAVE_LIQUID + DEFINES += LIQUID_NET_TESTNET + DEFINES += COIN_COINID_SHORT=\"tLBTC\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"tex\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"tlq\" + + APPNAME = "Liquid Testnet" else ifeq ($(COIN),liquid) - -# Liquid -DEFINES += BIP32_PUBKEY_VERSION=0x0488B21E -DEFINES += BIP32_PRIVKEY_VERSION=0x0488ADE4 -DEFINES += BIP44_COIN_TYPE=1776 -DEFINES += COIN_P2PKH_VERSION=57 -DEFINES += COIN_P2SH_VERSION=39 -DEFINES += COIN_PREFIX_CONFIDENTIAL=12 -DEFINES += HAVE_LIQUID -DEFINES += LIQUID_NET_MAINNET -DEFINES += COIN_COINID_SHORT=\"LBTC\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"ex\" -DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"lq\" - -APPNAME = "Liquid" + # Application allowed derivation paths (Liquid main network, liquidv1). + PATH_APP_LOAD_PARAMS = "*/1776'" # purpose=* / coin_type=Liquid(1776) + + # Liquid + DEFINES += BIP32_PUBKEY_VERSION=0x0488B21E + DEFINES += BIP32_PRIVKEY_VERSION=0x0488ADE4 + DEFINES += BIP44_COIN_TYPE=1776 + DEFINES += COIN_P2PKH_VERSION=57 + DEFINES += COIN_P2SH_VERSION=39 + DEFINES += COIN_PREFIX_CONFIDENTIAL=12 + DEFINES += HAVE_LIQUID + DEFINES += LIQUID_NET_MAINNET + DEFINES += COIN_COINID_SHORT=\"LBTC\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX=\"ex\" + DEFINES += COIN_NATIVE_SEGWIT_PREFIX_CONFIDENTIAL=\"lq\" + + APPNAME = "Liquid" else -ifeq ($(filter clean,$(MAKECMDGOALS)),) -$(error Unsupported COIN - use liquid_regtest, liquid_testnet, liquid) -endif + ifeq ($(filter clean,$(MAKECMDGOALS)),) + $(error Unsupported COIN - use liquid_regtest, liquid_testnet, liquid) + endif endif ifneq (,$(findstring liquid,$(COIN))) diff --git a/ledger_app.toml b/ledger_app.toml index 5b8fbaad2..b5a17a988 100644 --- a/ledger_app.toml +++ b/ledger_app.toml @@ -1,7 +1,7 @@ [app] build_directory = "./" sdk = "C" -devices = ["nanos", "nanox", "nanos+"] +devices = ["nanox", "nanos+"] [tests] unit_directory = "./unit-tests/" diff --git a/liquid-update-snapshots.sh b/liquid-update-snapshots.sh new file mode 100755 index 000000000..b3146b17a --- /dev/null +++ b/liquid-update-snapshots.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# liquid-update-snapshots.sh +# Update reference display snapshots for all devices and Liquid build configurations + +set -e # Exit on error unless explicitly handled + +# Define colors and styles for output +BOLD='\033[1m' +TEAL='\033[0;36m' +GREEN='\033[1;32m' +YELLOW='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color, no style + +# Ensure the script is running inside a Python virtual environment +if [ -z "$VIRTUAL_ENV" ]; then + echo -e "${RED}${BOLD}Error: This script must be run inside a Python virtual environment. Please activate your virtual environment and try again.${NC}" + exit 1 +fi + +# Ensure the script is run from the correct directory +LEDGER_APP_TOML="ledger_app.toml" +if [ ! -f $LEDGER_APP_TOML ]; then + echo -e "${RED}${BOLD}Error: ledger_app.toml not found. Please run this script from the project root directory.${NC}" + exit 1 +fi + +# Map from coin to test directory +COIN_TO_TESTDIR_KEYS=("liquid_regtest" "liquid_testnet" "liquid") +COIN_TO_TESTDIR_VALUES=("tests_liquid" "tests_liquid_testnet" "tests_liquid_main") + +# Map from device to SDK key and value +DEVICE_TO_SDK_KEYS=("nanos" "nanosp" "nanox") +DEVICE_TO_SDK_VALUES=("NANOS_SDK" "NANOSP_SDK" "NANOX_SDK") + +# Extract DEVICES from ledger_app.toml, replacing "nanos+" with "nanosp" +DEVICES=($(grep -E 'devices = \[.*\]' "$LEDGER_APP_TOML" | sed -E 's/devices = \[(.*)\]/\1/' | tr -d '"' | tr ',' '\n' | sed 's/nanos+/nanosp/')) + +# Extract COINS from VARIANT_VALUES in the Makefile +MAKEFILE_PATH="Makefile" +COINS=($(grep -E '^VARIANT_VALUES\s*=' "$MAKEFILE_PATH" | awk -F'= ' '{print $2}' | tr ' ' '\n')) + +# Function to get value from a plain array "map" +get_value_from_map() { + local key="$1" + local keys=("${!2}") + local values=("${!3}") + for i in "${!keys[@]}"; do + if [[ "${keys[$i]}" == "$key" ]]; then + echo "${values[$i]}" + return + fi + done + echo "" +} + +SUMMARY=() + +LATEST_VERSION=$(grep -E '^## \[[0-9]+\.[0-9]+\.[0-9]+' CHANGELOG.md | head -n 1 | sed -E 's/^## \[([0-9]+\.[0-9]+\.[0-9]+)\].*/\1/') +echo -e "${TEAL}${BOLD}Using latest version: ${GREEN}${LATEST_VERSION}${NC}" + +# Print obtained DEVICES and COINS +echo -e "${TEAL}${BOLD}Devices: ${GREEN}${DEVICES[@]}${NC}" +echo -e "${TEAL}${BOLD}Coins: ${GREEN}${COINS[@]}${NC}" + +# Stop any running simulator instance from a previous run +echo -e "Stopping any existing simulator instance..." +docker stop SPECULOS_SIM > /dev/null 2>&1 || true +sleep 3 + +# Loop through each coin and device combination +echo -e "Building and testing all configurations..." + +for COIN in "${COINS[@]}"; do + TESTDIR=$(get_value_from_map "$COIN" COIN_TO_TESTDIR_KEYS[@] COIN_TO_TESTDIR_VALUES[@]) + if [ -z "$TESTDIR" ]; then + echo -e "${YELLOW}${BOLD}No test directory defined for $COIN. Skipping...${NC}" + continue + fi + + for DEVICE in "${DEVICES[@]}"; do + SDK=$(get_value_from_map "$DEVICE" DEVICE_TO_SDK_KEYS[@] DEVICE_TO_SDK_VALUES[@]) + if [ -z "$SDK" ]; then + echo -e "${YELLOW}${BOLD}No SDK found for $DEVICE. Skipping...${NC}" + continue + fi + + CONFIG_NAME="$COIN / $DEVICE" + + echo -e "${TEAL}${BOLD}=== Cleaning build for $CONFIG_NAME ===${NC}" + docker exec -it app-bitcoin-new-container bash -c 'make -C ./ clean' + + echo -e "${TEAL}${BOLD}=== Building for $CONFIG_NAME ===${NC}" + BUILD_LOG=$(mktemp) + if docker exec -it app-bitcoin-new-container bash -c "export BOLOS_SDK=\${$SDK} && make -C ./ -B -j COIN=$COIN" >"$BUILD_LOG" 2>&1; then + BUILD_RESULT="✅ Build OK" + else + if grep -q "ImportError: cannot import name 'Buffer' from 'typing_extensions'" "$BUILD_LOG" || \ + grep -q "cp: cannot stat 'build/nanos/bin/app.apdu'" "$BUILD_LOG"; then + echo "⚠️ Known Docker-related issue detected. Ignoring and continuing..." + BUILD_RESULT="⚠️ Build has known issue" + else + echo -e "${RED}${BOLD}❌ Build failed due to an unknown issue. Stopping.${NC}\n--- Begin Build Log ---" + cat "$BUILD_LOG" + echo "--- End Build Log ---" + rm "$BUILD_LOG" + exit 1 + fi + fi + rm "$BUILD_LOG" + + echo -e "${TEAL}${BOLD}=== Starting simulator for $CONFIG_NAME ===${NC}" + docker run \ + --rm \ + -d \ + --name SPECULOS_SIM \ + -v "$(pwd)/bin:/speculos/apps" \ + -p 1234:1234 -p 5000:5000 -p 5001:5001 -p 9999:9999 -p 40000:40000 \ + -e SPECULOS_APPNAME="Liquid:${LATEST_VERSION}" \ + ghcr.io/ledgerhq/speculos:latest \ + --seed "glory promote mansion idle axis finger extra february uncover one trip resource lawn turtle enact monster seven myth punch hobby comfort wild raise skin" \ + --model "$DEVICE" \ + --api-port 5000 \ + --apdu-port 5001 \ + --display headless \ + apps/app.elf + + echo "Waiting for simulator to initialize..." + sleep 5 + + echo -e "${TEAL}${BOLD}=== Running golden snapshot tests for $CONFIG_NAME ===${NC}" + pushd "$TESTDIR" > /dev/null + if pytest -W ignore::DeprecationWarning --device "$DEVICE" --speculos_api_port 5000 --golden_run; then + TEST_RESULT="✅ Snapshots Updated" + else + TEST_RESULT="❌ Snapshot Update Failed" + fi + popd > /dev/null + + echo "Stopping simulator..." + docker stop SPECULOS_SIM > /dev/null + sleep 3 + + SUMMARY+=("$CONFIG_NAME → $BUILD_RESULT / $TEST_RESULT") + echo + done +done + +echo -e "${TEAL}${BOLD}========== SNAPSHOT UPDATE SUMMARY ==========${NC}" +for RESULT in "${SUMMARY[@]}"; do + echo "$RESULT" +done diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..2febb424c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +# requirements for the various test suites + +pytest>=6.1.1,<7.0.0 +pytest-benchmark>=4.0.0,<5.0.0 +pytest-timeout>=2.1.0,<3.0.0 +ledgercomm>=1.1.0,<1.2.0 +ecdsa>=0.16.1,<0.17.0 +typing-extensions>=3.7,<4.0 +embit>=0.7.0,<0.8.0 +mnemonic==0.20 +bip32>=3.4,<4.0 +speculos>=0.21.2 +ragger[speculos, ledgerwallet]>=1.37.0 +-e ./bitcoin_client # path relative to the current working directory; assume it's the root of the repo diff --git a/src/crypto.c b/src/crypto.c index f523bddaa..dfe72b8da 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -37,8 +37,8 @@ #include "common/read.h" #include "common/write.h" -#include "cxram_stash.h" -#include "debug-helpers/debug.h" +#include "../boilerplate/sw.h" +#include "../debug-helpers/debug.h" #include "crypto.h" @@ -290,26 +290,28 @@ bool crypto_generate_compressed_pubkey_pair(const uint8_t privkey[static 32], return ok; } -bool crypto_get_compressed_pubkey_at_path(const uint32_t bip32_path[], - uint8_t bip32_path_len, - uint8_t pubkey[static 33], - uint8_t chain_code[]) { +cx_err_t crypto_get_compressed_pubkey_at_path(const uint32_t bip32_path[], + uint8_t bip32_path_len, + uint8_t pubkey[static 33], + uint8_t chain_code[]) { uint8_t raw_public_key[65]; + cx_err_t error = CX_OK; - if (bip32_derive_get_pubkey_256(CX_CURVE_256K1, - bip32_path, - bip32_path_len, - raw_public_key, - chain_code, - CX_SHA512) != CX_OK) { - return false; + error = bip32_derive_get_pubkey_256(CX_CURVE_256K1, + bip32_path, + bip32_path_len, + raw_public_key, + chain_code, + CX_SHA512); + if (error != CX_OK) { + return error; } if (crypto_get_compressed_pubkey(raw_public_key, pubkey) < 0) { - return false; + return CX_INTERNAL_ERROR; } - return true; + return error; } uint32_t crypto_get_key_fingerprint(const uint8_t pub_key[static 33]) { @@ -319,12 +321,15 @@ uint32_t crypto_get_key_fingerprint(const uint8_t pub_key[static 33]) { return read_u32_be(key_rip, 0); } -uint32_t crypto_get_master_key_fingerprint(void) { - uint8_t master_pub_key[33]; - uint32_t bip32_path[] = {}; - LEDGER_ASSERT(crypto_get_compressed_pubkey_at_path(bip32_path, 0, master_pub_key, NULL), - "It never fails"); - return crypto_get_key_fingerprint(master_pub_key); +uint32_t crypto_get_master_key_fingerprint() { + uint8_t master_key_identifier[CX_RIPEMD160_SIZE] = {0}; + + int res = os_perso_get_master_key_identifier(master_key_identifier, CX_RIPEMD160_SIZE); + LEDGER_ASSERT( + res == CX_OK, + "Unexpected error in os_perso_get_master_key_identifier computation. Returned: %d", + res); + return read_u32_be(master_key_identifier, 0); } bool crypto_derive_symmetric_key(const char *label, size_t label_len, uint8_t key[static 32]) { @@ -353,23 +358,26 @@ bool crypto_derive_symmetric_key(const char *label, size_t label_len, uint8_t ke return res; } -int get_extended_pubkey_at_path(const uint32_t bip32_path[], - uint8_t bip32_path_len, - uint32_t bip32_pubkey_version, - serialized_extended_pubkey_t *out_pubkey) { +cx_err_t get_extended_pubkey_at_path(const uint32_t bip32_path[], + uint8_t bip32_path_len, + uint32_t bip32_pubkey_version, + serialized_extended_pubkey_t *out_pubkey) { // find parent key's fingerprint and child number uint32_t parent_fingerprint = 0; uint32_t child_number = 0; + cx_err_t error = CX_OK; + if (bip32_path_len > 0) { // here we reuse the storage for the parent keys that we will later use // for the response, in order to save memory uint8_t parent_pubkey[33]; - if (!crypto_get_compressed_pubkey_at_path(bip32_path, - bip32_path_len - 1, - parent_pubkey, - NULL)) { - return -1; + error = crypto_get_compressed_pubkey_at_path(bip32_path, + bip32_path_len - 1, + parent_pubkey, + NULL); + if (error != CX_OK) { + return error; } parent_fingerprint = crypto_get_key_fingerprint(parent_pubkey); @@ -381,14 +389,31 @@ int get_extended_pubkey_at_path(const uint32_t bip32_path[], write_u32_be(out_pubkey->parent_fingerprint, 0, parent_fingerprint); write_u32_be(out_pubkey->child_number, 0, child_number); - if (!crypto_get_compressed_pubkey_at_path(bip32_path, - bip32_path_len, - out_pubkey->compressed_pubkey, - out_pubkey->chain_code)) { - return -1; + return crypto_get_compressed_pubkey_at_path(bip32_path, + bip32_path_len, + out_pubkey->compressed_pubkey, + out_pubkey->chain_code); +} + +uint16_t cx_err_to_sw(cx_err_t error) { + if (error == CX_OK) { + return SW_OK; } - return 0; + /* The error codes are not currently defined in the SDK */ + if (error == 0x4212) { + PRINTF( + "Attempt to derive a key at root level without " + "HAVE_APPLICATION_FLAG_DERIVE_MASTER permission.\n"); + return SW_NOT_SUPPORTED; + } + if (error == 0x4215) { + PRINTF("Attempt to derive a key at unauthorized path.\n"); + return SW_NOT_SUPPORTED; + } + + PRINTF("Failed getting bip32 pubkey, error = 0x%08X\n", error); + return SW_BAD_STATE; } int base58_encode_address(const uint8_t in[20], uint32_t version, char *out, size_t out_len) { diff --git a/src/crypto.h b/src/crypto.h index a79140a54..c90ae6b95 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -318,10 +318,10 @@ void crypto_get_checksum(const uint8_t *in, uint16_t in_len, uint8_t out[static * * @return true on success, false in case of error. */ -WARN_UNUSED_RESULT bool crypto_get_compressed_pubkey_at_path(const uint32_t bip32_path[], - uint8_t bip32_path_len, - uint8_t pubkey[static 33], - uint8_t chain_code[]); +WARN_UNUSED_RESULT cx_err_t crypto_get_compressed_pubkey_at_path(const uint32_t bip32_path[], + uint8_t bip32_path_len, + uint8_t pubkey[static 33], + uint8_t chain_code[]); /** * Computes the fingerprint of a compressed key as per BIP32; that is, the first 4 bytes of the @@ -355,10 +355,10 @@ uint32_t crypto_get_master_key_fingerprint(void); * * @return 0 on success, or -1 on error. */ -WARN_UNUSED_RESULT int get_extended_pubkey_at_path(const uint32_t bip32_path[], - uint8_t bip32_path_len, - uint32_t bip32_pubkey_version, - serialized_extended_pubkey_t *out_pubkey); +WARN_UNUSED_RESULT cx_err_t get_extended_pubkey_at_path(const uint32_t bip32_path[], + uint8_t bip32_path_len, + uint32_t bip32_pubkey_version, + serialized_extended_pubkey_t *out_pubkey); /** * Derives the level-1 symmetric key at the given label using SLIP-0021. @@ -559,3 +559,13 @@ WARN_UNUSED_RESULT int validate_serialized_extended_pubkey(const char *pubkey, const uint32_t bip32_path[], int bip32_path_len, uint32_t bip32_pubkey_version); + +/** + * Converts cx_err_t to 2-bytes SW and prints out debug information. + * + * @param[in] error + * Cryptographic error code + * + * @return SW (SW_OK on success, other value on error). + */ +uint16_t cx_err_to_sw(cx_err_t error); diff --git a/src/handler/get_extended_pubkey.c b/src/handler/get_extended_pubkey.c index 9c56176e8..7b5b5f684 100644 --- a/src/handler/get_extended_pubkey.c +++ b/src/handler/get_extended_pubkey.c @@ -139,12 +139,13 @@ void handler_get_extended_pubkey(dispatcher_context_t *dc, uint8_t protocol_vers } serialized_extended_pubkey_check_t pubkey_check; - if (0 > get_extended_pubkey_at_path(bip32_path, - bip32_path_len, - BIP32_PUBKEY_VERSION, - &pubkey_check.serialized_extended_pubkey)) { - PRINTF("Failed getting bip32 pubkey\n"); - SEND_SW(dc, SW_BAD_STATE); + uint16_t sw = + cx_err_to_sw(get_extended_pubkey_at_path(bip32_path, + bip32_path_len, + BIP32_PUBKEY_VERSION, + &pubkey_check.serialized_extended_pubkey)); + if (SW_OK != sw) { + SEND_SW(dc, sw); return; } diff --git a/src/handler/get_master_fingerprint.c b/src/handler/get_master_fingerprint.c index e1993c390..63305ef93 100644 --- a/src/handler/get_master_fingerprint.c +++ b/src/handler/get_master_fingerprint.c @@ -17,6 +17,8 @@ #include +#include "os_seed.h" + #include "boilerplate/dispatcher.h" #include "boilerplate/sw.h" #include "../commands.h" @@ -27,14 +29,12 @@ void handler_get_master_fingerprint(dispatcher_context_t *dc, uint8_t protocol_version) { (void) protocol_version; - uint8_t master_pubkey[33]; - if (!crypto_get_compressed_pubkey_at_path((uint32_t[]){}, 0, master_pubkey, NULL)) { + uint8_t master_key_identifier[CX_RIPEMD160_SIZE] = {0}; + + if (os_perso_get_master_key_identifier(master_key_identifier, CX_RIPEMD160_SIZE) != CX_OK) { SEND_SW(dc, SW_BAD_STATE); // should never happen return; } - uint8_t master_fingerprint_be[4]; - write_u32_be(master_fingerprint_be, 0, crypto_get_key_fingerprint(master_pubkey)); - - SEND_RESPONSE(dc, master_fingerprint_be, sizeof(master_fingerprint_be), SW_OK); + SEND_RESPONSE(dc, master_key_identifier, 4, SW_OK); } diff --git a/src/handler/lib/policy.c b/src/handler/lib/policy.c index 5595ab279..5cdf48d27 100644 --- a/src/handler/lib/policy.c +++ b/src/handler/lib/policy.c @@ -1501,10 +1501,10 @@ bool is_wallet_policy_standard(dispatcher_context_t *dispatcher_context, // generate pubkey and check if it matches serialized_extended_pubkey_t derived_pubkey; - if (0 > get_extended_pubkey_at_path(key_info.master_key_derivation, - key_info.master_key_derivation_len, - BIP32_PUBKEY_VERSION, - &derived_pubkey)) { + if (CX_OK != get_extended_pubkey_at_path(key_info.master_key_derivation, + key_info.master_key_derivation_len, + BIP32_PUBKEY_VERSION, + &derived_pubkey)) { PRINTF("Failed to derive pubkey\n"); return false; } diff --git a/src/handler/register_wallet.c b/src/handler/register_wallet.c index deb020dfb..48e443a6c 100644 --- a/src/handler/register_wallet.c +++ b/src/handler/register_wallet.c @@ -196,13 +196,13 @@ void handler_register_wallet(dispatcher_context_t *dc, uint8_t protocol_version) read_u32_be(key_info.master_key_fingerprint, 0) == master_key_fingerprint) { // we verify that we can actually generate the same pubkey serialized_extended_pubkey_t pubkey_derived; - int serialized_pubkey_len = - get_extended_pubkey_at_path(key_info.master_key_derivation, - key_info.master_key_derivation_len, - BIP32_PUBKEY_VERSION, - &pubkey_derived); - if (serialized_pubkey_len == -1) { - SEND_SW(dc, SW_BAD_STATE); + uint16_t sw = + cx_err_to_sw(get_extended_pubkey_at_path(key_info.master_key_derivation, + key_info.master_key_derivation_len, + BIP32_PUBKEY_VERSION, + &pubkey_derived)); + if (SW_OK != sw) { + SEND_SW(dc, sw); (void) ui_post_processing_confirm_wallet_registration(dc, false); return; } diff --git a/src/handler/sign_psbt.c b/src/handler/sign_psbt.c index 3f1073062..36c9509b2 100644 --- a/src/handler/sign_psbt.c +++ b/src/handler/sign_psbt.c @@ -1174,10 +1174,10 @@ fill_placeholder_info_if_internal(dispatcher_context_t *dc, { // it could be a collision on the fingerprint; we verify that we can actually generate // the same pubkey - if (0 > get_extended_pubkey_at_path(key_info.master_key_derivation, - key_info.master_key_derivation_len, - BIP32_PUBKEY_VERSION, - &placeholder_info->pubkey)) { + if (CX_OK != get_extended_pubkey_at_path(key_info.master_key_derivation, + key_info.master_key_derivation_len, + BIP32_PUBKEY_VERSION, + &placeholder_info->pubkey)) { SEND_SW(dc, SW_BAD_STATE); return false; } diff --git a/src/swap/handle_check_address.c b/src/swap/handle_check_address.c index 1c954ec5d..4b5650f08 100644 --- a/src/swap/handle_check_address.c +++ b/src/swap/handle_check_address.c @@ -112,10 +112,8 @@ int handle_check_address(check_address_parameters_t* params) { return false; } - if (!crypto_get_compressed_pubkey_at_path(path.path, - path.length, - compressed_public_key, - NULL)) { + if (CX_OK != + crypto_get_compressed_pubkey_at_path(path.path, path.length, compressed_public_key, NULL)) { return 0; } char address[MAX_ADDRESS_LENGTH_STR + 1]; @@ -135,4 +133,4 @@ int handle_check_address(check_address_parameters_t* params) { } PRINTF("Addresses match\n"); return 1; -} \ No newline at end of file +} diff --git a/src/ui/display.c b/src/ui/display.c index 0f91ecb39..fbbe6fd02 100644 --- a/src/ui/display.c +++ b/src/ui/display.c @@ -70,12 +70,31 @@ static bool io_ui_process(dispatcher_context_t *context, bool set_dirty) { // We are not waiting for the client's input, nor we are doing computations on the device io_clear_processing_timeout(); +#ifdef TARGET_NANOS io_seproxyhal_general_status(); do { io_seproxyhal_spi_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0); io_seproxyhal_handle_event(); io_seproxyhal_general_status(); } while (io_seproxyhal_spi_is_status_sent() && !g_ux_flow_ended); +#else // TARGET_NANOS + do { + int status = os_io_rx_evt(G_io_rx_buffer, sizeof(G_io_rx_buffer), NULL, true); + if (status > 1 && (size_t) (status - 1) <= sizeof(G_io_seproxyhal_spi_buffer)) { + switch (G_io_rx_buffer[0]) { + case OS_IO_PACKET_TYPE_SE_EVT: + case OS_IO_PACKET_TYPE_SEPH: + memcpy(G_io_seproxyhal_spi_buffer, &G_io_rx_buffer[1], status - 1); + io_event(CHANNEL_APDU); + break; + + default: + // Drop received APDUs silently during modal UI + break; + } + } + } while (!g_ux_flow_ended); +#endif // TARGET_NANOS // We're back at work, we want to show the "Processing..." screen when appropriate io_start_processing_timeout(); diff --git a/tests_liquid/requirements.txt b/tests_liquid/requirements.txt index d8554a27a..4c4900149 100644 --- a/tests_liquid/requirements.txt +++ b/tests_liquid/requirements.txt @@ -1,9 +1,2 @@ -pytest>=6.1.1,<7.0.0 -pytest-timeout>=2.1.0,<3.0.0 -ledgercomm>=1.1.0,<1.2.0 -ecdsa>=0.16.1,<0.17.0 -typing-extensions>=3.7,<4.0 -embit>=0.7.0,<0.8.0 -mnemonic==0.20 -bip32>=3.4,<4.0 -ragger[speculos, ledgerwallet]>=1.6.0 \ No newline at end of file +# The reusable ragger workflow expects a requirements.txt file in the tests directory, but we want to just use the one in the repository's root. +-r ../requirements.txt diff --git a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_0/00002.png b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_0/00002.png index 690fd0268..ec4f7e28b 100644 Binary files a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_0/00002.png and b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_0/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00000.png b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00000.png index 8a9432bd6..ae7ff35fc 100644 Binary files a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00000.png and b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00000.png differ diff --git a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00001.png b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00001.png index 212d3b21e..a3be7d8d9 100644 Binary files a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00001.png and b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00001.png differ diff --git a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00002.png b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00002.png index dd9c46984..10ea68f9b 100644 Binary files a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00002.png and b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_0_1/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png index 690fd0268..ec4f7e28b 100644 Binary files a/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png and b/tests_liquid/snapshots/nanosp/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png index 8ed992b5f..96859a0a8 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png index 575c5d8b1..546b6b131 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png index 7d609fa86..7bf11e1fd 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png index 8ed992b5f..2cf2115b4 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png index 575c5d8b1..f3fb18af4 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png index 7d609fa86..23c13d0b4 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png index 8ed992b5f..48fc4d761 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png index 575c5d8b1..19b8f9f93 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png index 7d609fa86..7f4b16466 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png index 8ed992b5f..2ba4d741a 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png index 575c5d8b1..1eb6c7d43 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png index 7d609fa86..fa6a10bce 100644 Binary files a/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png and b/tests_liquid/snapshots/nanosp/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_0/00002.png b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_0/00002.png index 690fd0268..ec4f7e28b 100644 Binary files a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_0/00002.png and b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00000.png b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00000.png index 8a9432bd6..ae7ff35fc 100644 Binary files a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00000.png and b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00000.png differ diff --git a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00001.png b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00001.png index 212d3b21e..a3be7d8d9 100644 Binary files a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00001.png and b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00001.png differ diff --git a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00002.png b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00002.png index dd9c46984..10ea68f9b 100644 Binary files a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00002.png and b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_0_1/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png index 690fd0268..ec4f7e28b 100644 Binary files a/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png and b/tests_liquid/snapshots/nanox/test_get_extended_pubkey_non_standard_reject_early_0_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png index 8ed992b5f..96859a0a8 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png index 575c5d8b1..546b6b131 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png index 7d609fa86..7bf11e1fd 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Legacy_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png index 8ed992b5f..2cf2115b4 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png index 575c5d8b1..f3fb18af4 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png index 7d609fa86..23c13d0b4 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Native_Segwit_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png index 8ed992b5f..48fc4d761 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png index 575c5d8b1..19b8f9f93 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png index 7d609fa86..7f4b16466 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Nested_Segwit_1_0/00002.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png index 8ed992b5f..2ba4d741a 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00000.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png index 575c5d8b1..1eb6c7d43 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00001.png differ diff --git a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png index 7d609fa86..fa6a10bce 100644 Binary files a/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png and b/tests_liquid/snapshots/nanox/test_register_unusual_singlesig_accounts_Unusual_Taproot_1_0/00002.png differ diff --git a/tests_liquid/test_get_extended_pubkey.py b/tests_liquid/test_get_extended_pubkey.py index 3cd39ac23..c92c76ce6 100644 --- a/tests_liquid/test_get_extended_pubkey.py +++ b/tests_liquid/test_get_extended_pubkey.py @@ -2,6 +2,7 @@ from ragger_bitcoin import RaggerClient from ragger.navigator import Navigator +from ragger.backend import SpeculosBackend from ragger.firmware import Firmware from ragger.error import ExceptionRAPDU @@ -59,15 +60,32 @@ def test_get_extended_pubkey_non_standard(navigator: Navigator, firmware: Firmwa # Test the successful UX flow for a non-standard path (here, root path) # (Slow test, not feasible to repeat it for many paths) - pub_key = client.get_extended_pubkey( - path="m", # root pubkey - display=True, - navigator=navigator, - instructions=pubkey_instruction_approve(firmware), - testname=test_name - ) + # The test will be re-enabled for Speculos once the installation parameters are supported + if isinstance(client.transport_client, SpeculosBackend): + pytest.skip("The test derives key at root level - now prohibited and the reinforcement is not yet implemented in Speculos.") - assert pub_key == "tpubD6NzVbkrYhZ4YgUx2ZLNt2rLYAMTdYysCRzKoLu2BeSHKvzqPaBDvf17GeBPnExUVPkuBpx4kniP964e2MxyzzazcXLptxLXModSVCVEV1T" + # Deriving a key at root level without HAVE_APPLICATION_FLAG_DERIVE_MASTER permission + with pytest.raises(ExceptionRAPDU) as e: + pub_key = client.get_extended_pubkey( + path="m", # root pubkey + display=True, + navigator=navigator, + instructions=pubkey_instruction_approve(firmware), + testname=test_name + ) + assert DeviceException.exc.get(e.value.status) == NotSupportedError + assert len(e.value.data) == 0 + # Deriving a key at unauthorized path + with pytest.raises(ExceptionRAPDU) as e: + pub_key = client.get_extended_pubkey( + path="m/44'/2'/333'", + display=True, + navigator=navigator, + instructions=pubkey_instruction_approve(firmware), + testname=test_name + ) + assert DeviceException.exc.get(e.value.status) == NotSupportedError + assert len(e.value.data) == 0 @pytest.mark.use_on_backend("speculos") @@ -76,9 +94,22 @@ def test_get_extended_pubkey_non_standard_reject_early(navigator: Navigator, fir # Test rejecting after the "Reject if you're not sure" warning # (Slow test, not feasible to repeat it for many paths) + # Deriving with a suspicious path without displaying + with pytest.raises(ExceptionRAPDU) as e: + client.get_extended_pubkey( + path="m/46'/1'/333'", + display=False, + navigator=navigator, + instructions=pubkey_instruction_reject_early(firmware), + testname=test_name + ) + assert DeviceException.exc.get(e.value.status) == NotSupportedError + assert len(e.value.data) == 0 + + # Deriving with a suspicious path with displaying, but rejecting as early as the path is displayed with pytest.raises(ExceptionRAPDU) as e: client.get_extended_pubkey( - path="m/111'/222'/333'", + path="m/46'/1'/333'", display=True, navigator=navigator, instructions=pubkey_instruction_reject_early(firmware), @@ -94,9 +125,10 @@ def test_get_extended_pubkey_non_standard_reject(navigator: Navigator, firmware: # Test rejecting at the end # (Slow test, not feasible to repeat it for many paths) + # Deriving with a suspicious path with displaying, but rejecting on the last screen with pytest.raises(ExceptionRAPDU) as e: client.get_extended_pubkey( - path="m/111'/222'/333'", + path="m/46'/1'/333'", display=True, navigator=navigator, instructions=pubkey_reject(firmware), diff --git a/tests_liquid/test_register_wallet.py b/tests_liquid/test_register_wallet.py index cc354ae34..add56c6a9 100644 --- a/tests_liquid/test_register_wallet.py +++ b/tests_liquid/test_register_wallet.py @@ -349,7 +349,7 @@ def test_register_unusual_singlesig_accounts(navigator: Navigator, firmware: Fir run_register_test(navigator, client, speculos_globals, WalletPolicy( name="Unusual Legacy", descriptor_template="pkh(@0/**)", - keys_info=["[f5acc2fd/1'/2'/3']tpubDCsHVWwqALkDzorr5zdc91Wj93zR3so1kUEH6LWsPrLtC9MVPjb8NEQwCzhPM4TEFP6KbgmTb7xAsyrbf3oEBh31Q7iAKhzMHj2FZ5YGNrr"] + keys_info=["[f5acc2fd/44'/1'/10']tpubDCwYjpDhUdPGp21gSpVay2QPJVh6WNySWMXPhbcu1DsxH31dF7mY18oibbu5RxCLBc1Szerjscuc3D5HyvfYqfRvc9mesewnFqGmPjney4d"] ), instructions=register_wallet_instruction_approve_unusual(firmware), test_name=f"{test_name}_Unusual_Legacy") @@ -357,7 +357,7 @@ def test_register_unusual_singlesig_accounts(navigator: Navigator, firmware: Fir run_register_test(navigator, client, speculos_globals, WalletPolicy( name="Unusual Nested SegWit", descriptor_template="sh(wpkh(@0/**))", - keys_info=["[f5acc2fd/1'/2'/3']tpubDCsHVWwqALkDzorr5zdc91Wj93zR3so1kUEH6LWsPrLtC9MVPjb8NEQwCzhPM4TEFP6KbgmTb7xAsyrbf3oEBh31Q7iAKhzMHj2FZ5YGNrr"] + keys_info=["[f5acc2fd/49'/1'/0']tpubDC871vGLAiKPcwAw22EjhKVLk5L98UGXBEcGR8gpcigLQVDDfgcYW24QBEyTHTSFEjgJgbaHU8CdRi9vmG4cPm1kPLmZhJEP17FMBdNheh3"] ), instructions=register_wallet_instruction_approve_unusual(firmware), test_name=f"{test_name}_Unusual_Nested_Segwit") @@ -365,7 +365,7 @@ def test_register_unusual_singlesig_accounts(navigator: Navigator, firmware: Fir run_register_test(navigator, client, speculos_globals, WalletPolicy( name="Unusual Native SegWit", descriptor_template="wpkh(@0/**)", - keys_info=["[f5acc2fd/1'/2'/3']tpubDCsHVWwqALkDzorr5zdc91Wj93zR3so1kUEH6LWsPrLtC9MVPjb8NEQwCzhPM4TEFP6KbgmTb7xAsyrbf3oEBh31Q7iAKhzMHj2FZ5YGNrr"] + keys_info=["[f5acc2fd/84'/1'/0']tpubDCtKfsNyRhULjZ9XMS4VKKtVcPdVDi8MKUbcSD9MJDyjRu1A2ND5MiipozyyspBT9bg8upEp7a8EAgFxNxXn1d7QkdbL52Ty5jiSLcxPt1P"] ), instructions=register_wallet_instruction_approve_unusual(firmware), test_name=f"{test_name}_Unusual_Native_Segwit") @@ -373,7 +373,7 @@ def test_register_unusual_singlesig_accounts(navigator: Navigator, firmware: Fir run_register_test(navigator, client, speculos_globals, WalletPolicy( name="Unusual Taproot", descriptor_template="tr(@0/**)", - keys_info=["[f5acc2fd/1'/2'/3']tpubDCsHVWwqALkDzorr5zdc91Wj93zR3so1kUEH6LWsPrLtC9MVPjb8NEQwCzhPM4TEFP6KbgmTb7xAsyrbf3oEBh31Q7iAKhzMHj2FZ5YGNrr"] + keys_info=["[f5acc2fd/86'/1'/0']tpubDDKYE6BREvDsSWMazgHoyQWiJwYaDDYPbCFjYxN3HFXJP5fokeiK4hwK5tTLBNEDBwrDXn8cQ4v9b2xdW62Xr5yxoQdMu1v6c7UDXYVH27U"] ), instructions=register_wallet_instruction_approve_unusual(firmware), test_name=f"{test_name}_Unusual_Taproot") diff --git a/tests_liquid_main/requirements.txt b/tests_liquid_main/requirements.txt index d8554a27a..4c4900149 100644 --- a/tests_liquid_main/requirements.txt +++ b/tests_liquid_main/requirements.txt @@ -1,9 +1,2 @@ -pytest>=6.1.1,<7.0.0 -pytest-timeout>=2.1.0,<3.0.0 -ledgercomm>=1.1.0,<1.2.0 -ecdsa>=0.16.1,<0.17.0 -typing-extensions>=3.7,<4.0 -embit>=0.7.0,<0.8.0 -mnemonic==0.20 -bip32>=3.4,<4.0 -ragger[speculos, ledgerwallet]>=1.6.0 \ No newline at end of file +# The reusable ragger workflow expects a requirements.txt file in the tests directory, but we want to just use the one in the repository's root. +-r ../requirements.txt diff --git a/tests_liquid_testnet/requirements.txt b/tests_liquid_testnet/requirements.txt index d8554a27a..4c4900149 100644 --- a/tests_liquid_testnet/requirements.txt +++ b/tests_liquid_testnet/requirements.txt @@ -1,9 +1,2 @@ -pytest>=6.1.1,<7.0.0 -pytest-timeout>=2.1.0,<3.0.0 -ledgercomm>=1.1.0,<1.2.0 -ecdsa>=0.16.1,<0.17.0 -typing-extensions>=3.7,<4.0 -embit>=0.7.0,<0.8.0 -mnemonic==0.20 -bip32>=3.4,<4.0 -ragger[speculos, ledgerwallet]>=1.6.0 \ No newline at end of file +# The reusable ragger workflow expects a requirements.txt file in the tests directory, but we want to just use the one in the repository's root. +-r ../requirements.txt diff --git a/unit-tests/mock_includes/lcx_common.h b/unit-tests/mock_includes/lcx_common.h index 5cecb1e18..c1f116091 100644 --- a/unit-tests/mock_includes/lcx_common.h +++ b/unit-tests/mock_includes/lcx_common.h @@ -41,6 +41,9 @@ typedef struct uint64_s uint64bits_t; typedef uint64_t uint64bits_t; #endif +/** Type of error code */ +typedef uint32_t cx_err_t; + // clang-format off /** * @brief Cryptography flags