From 1a27771b25d47dd0f63bb346276dcdfe69c8b2c4 Mon Sep 17 00:00:00 2001 From: vbouzon Date: Sun, 30 Jul 2023 11:55:07 +0200 Subject: [PATCH] Rebase on latest boilerplate 1a07884 --- .doxygen/Doxyfile | 2 +- .github/workflows/unit_tests.yml | 7 + .gitignore | 3 + .vscode/20-ledger.ledgerblue.rules | 1 + .vscode/c_cpp_properties.json | 3 +- .vscode/extensions.json | 5 + .vscode/settings.json | 20 +- .vscode/tasks.json | 152 +++++++++++--- Makefile | 181 +++++++---------- README.md | 2 +- glyphs/app_boilerplate_16px.gif | Bin 0 -> 67 bytes glyphs/app_boilerplate_64px.gif | Bin 0 -> 297 bytes glyphs/boilerplate_logo.gif | Bin 66 -> 0 bytes glyphs/icon_back.gif | Bin 74 -> 0 bytes glyphs/icon_back_x.gif | Bin 1123 -> 0 bytes glyphs/icon_certificate.gif | Bin 1133 -> 0 bytes glyphs/icon_coggle.gif | Bin 1128 -> 0 bytes glyphs/icon_crossmark.gif | Bin 1131 -> 0 bytes glyphs/icon_dashboard.gif | Bin 1133 -> 0 bytes glyphs/icon_dashboard_x.gif | Bin 1126 -> 0 bytes glyphs/icon_down.gif | Bin 1100 -> 0 bytes glyphs/icon_eye.gif | Bin 1130 -> 0 bytes glyphs/icon_left.gif | Bin 1101 -> 0 bytes glyphs/icon_processing.gif | Bin 1130 -> 0 bytes glyphs/icon_right.gif | Bin 1100 -> 0 bytes glyphs/icon_up.gif | Bin 1100 -> 0 bytes glyphs/icon_validate_14.gif | Bin 1125 -> 0 bytes glyphs/icon_warning.gif | Bin 1130 -> 0 bytes icons/app_boilerplate_14px.gif | Bin 0 -> 72 bytes icons/app_boilerplate_16px.gif | Bin 0 -> 67 bytes icons/app_boilerplate_32px.gif | Bin 0 -> 943 bytes icons/nanos_app_boilerplate.gif | Bin 895 -> 0 bytes icons/nanox_app_boilerplate.gif | Bin 895 -> 0 bytes src/address.c | 31 +-- src/address.h | 2 + src/apdu/dispatcher.c | 10 +- src/apdu/dispatcher.h | 4 +- src/apdu/parser.c | 40 ---- src/apdu/parser.h | 22 -- src/app_main.c | 78 +++++++ src/common/base58.c | 155 -------------- src/common/base58.h | 52 ----- src/common/bip32.c | 87 -------- src/common/bip32.h | 47 ----- src/common/buffer.c | 165 --------------- src/common/buffer.h | 192 ------------------ src/common/format.c | 157 -------------- src/common/format.h | 69 ------- src/common/macros.h | 6 - src/common/read.c | 64 ------ src/common/read.h | 82 -------- src/common/segwit_addr.h | 115 ----------- src/common/varint.c | 101 --------- src/common/varint.h | 52 ----- src/common/write.c | 64 ------ src/common/write.h | 82 -------- src/crypto.c | 10 +- src/crypto.h | 48 +---- src/handler/encrypt_data.c | 3 - src/handler/encrypt_data.h | 2 +- src/handler/get_app_name.c | 9 +- src/handler/get_public_key.c | 30 ++- src/handler/get_public_key.h | 8 +- src/handler/get_response.c | 2 - src/handler/get_version.c | 16 +- src/handler/sign_event.c | 3 - src/handler/sign_event.h | 3 +- src/{common/segwit_addr.c => helper/bech32.c} | 65 +----- src/helper/bech32.h | 32 +++ src/helper/send_reponse.c | 13 +- src/helper/send_response.h | 2 +- src/io.c | 184 ----------------- src/io.h | 65 ------ src/main.c | 160 --------------- src/offsets.h | 26 --- src/types.h | 26 +-- src/ui/action/validate.c | 1 - src/ui/action/validate.h | 2 + src/ui/{display_bagl.c => bagl_display.c} | 15 +- src/ui/display.h | 2 +- src/ui/display_nbgl.c | 2 +- src/ui/menu_bagl.c | 4 +- src/ui/menu_nbgl.c | 25 ++- .../boilerplate_command_sender.py | 25 --- tests/requirements.txt | 2 +- tests/test_encrypt_decrypt.py | 30 --- tests/test_error_cmd.py | 67 +++--- tests/test_name_version.py | 2 +- tests/test_pubkey_cmd.py | 49 +++-- tests/test_version_cmd.py | 6 +- tests/utils.py | 3 +- unit-tests/CMakeLists.txt | 57 +++--- unit-tests/test_apdu_parser.c | 41 ---- unit-tests/test_base58.c | 34 ---- unit-tests/test_bip32.c | 101 --------- unit-tests/test_buffer.c | 155 -------------- unit-tests/test_format.c | 105 ---------- unit-tests/test_write.c | 64 ------ 98 files changed, 521 insertions(+), 3031 deletions(-) create mode 100644 .vscode/20-ledger.ledgerblue.rules create mode 100644 .vscode/extensions.json create mode 100644 glyphs/app_boilerplate_16px.gif create mode 100644 glyphs/app_boilerplate_64px.gif delete mode 100644 glyphs/boilerplate_logo.gif delete mode 100644 glyphs/icon_back.gif delete mode 100644 glyphs/icon_back_x.gif delete mode 100644 glyphs/icon_certificate.gif delete mode 100644 glyphs/icon_coggle.gif delete mode 100644 glyphs/icon_crossmark.gif delete mode 100644 glyphs/icon_dashboard.gif delete mode 100644 glyphs/icon_dashboard_x.gif delete mode 100644 glyphs/icon_down.gif delete mode 100644 glyphs/icon_eye.gif delete mode 100644 glyphs/icon_left.gif delete mode 100644 glyphs/icon_processing.gif delete mode 100644 glyphs/icon_right.gif delete mode 100644 glyphs/icon_up.gif delete mode 100644 glyphs/icon_validate_14.gif delete mode 100644 glyphs/icon_warning.gif create mode 100644 icons/app_boilerplate_14px.gif create mode 100644 icons/app_boilerplate_16px.gif create mode 100644 icons/app_boilerplate_32px.gif delete mode 100644 icons/nanos_app_boilerplate.gif delete mode 100644 icons/nanox_app_boilerplate.gif delete mode 100644 src/apdu/parser.c delete mode 100644 src/apdu/parser.h create mode 100644 src/app_main.c delete mode 100644 src/common/base58.c delete mode 100644 src/common/base58.h delete mode 100644 src/common/bip32.c delete mode 100644 src/common/bip32.h delete mode 100644 src/common/buffer.c delete mode 100644 src/common/buffer.h delete mode 100644 src/common/format.c delete mode 100644 src/common/format.h delete mode 100644 src/common/macros.h delete mode 100644 src/common/read.c delete mode 100644 src/common/read.h delete mode 100644 src/common/segwit_addr.h delete mode 100644 src/common/varint.c delete mode 100644 src/common/varint.h delete mode 100644 src/common/write.c delete mode 100644 src/common/write.h rename src/{common/segwit_addr.c => helper/bech32.c} (62%) create mode 100644 src/helper/bech32.h delete mode 100755 src/io.c delete mode 100644 src/io.h delete mode 100644 src/main.c delete mode 100644 src/offsets.h rename src/ui/{display_bagl.c => bagl_display.c} (94%) delete mode 100644 tests/test_encrypt_decrypt.py delete mode 100644 unit-tests/test_apdu_parser.c delete mode 100644 unit-tests/test_base58.c delete mode 100644 unit-tests/test_bip32.c delete mode 100644 unit-tests/test_buffer.c delete mode 100644 unit-tests/test_format.c delete mode 100644 unit-tests/test_write.c diff --git a/.doxygen/Doxyfile b/.doxygen/Doxyfile index 535c052..ce68435 100644 --- a/.doxygen/Doxyfile +++ b/.doxygen/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "Boilerplate" +PROJECT_NAME = "Ledgstr" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index d617a00..4bdc85d 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -20,9 +20,16 @@ jobs: - name: Clone uses: actions/checkout@v3 + - name: Clone SDK + uses: actions/checkout@v3 + with: + repository: ledgerHQ/ledger-secure-sdk + path: sdk + - name: Build unit tests run: | cd unit-tests/ + export BOLOS_SDK=../sdk cmake -Bbuild -H. && make -C build && make -C build test - name: Generate code coverage diff --git a/.gitignore b/.gitignore index 17df42c..6850c09 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ __pycache__/ # Doxygen doc/html doc/latex + +# Virtual env for sideload (macOS and Windows) +ledger/ diff --git a/.vscode/20-ledger.ledgerblue.rules b/.vscode/20-ledger.ledgerblue.rules new file mode 100644 index 0000000..945dd5b --- /dev/null +++ b/.vscode/20-ledger.ledgerblue.rules @@ -0,0 +1 @@ +SUBSYSTEMS=="usb", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0006|6000|6001|6002|6003|6004|6005|6006|6007|6008|6009|600a|600b|600c|600d|600e|600f|6010|6011|6012|6013|6014|6015|6016|6017|6018|6019|601a|601b|601c|601d|601e|601f", TAG+="uaccess", TAG+="udev-acl" diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 311d377..3da766f 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -42,8 +42,7 @@ "browse": { "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" - }, - "configurationProvider": "ms-vscode.makefile-tools" + } } ], "version": 4 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c9623b9 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-vscode.cpptools", + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 9258178..f6fecb8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,13 @@ { "files.associations": { - "*.h": "c", - "string": "c" + "*.h": "c" }, - "C_Cpp.clang_format_path": "/usr/bin/clang-format-11", - "editor.formatOnSave": true, - "python.testing.pytestArgs": [ - "tests" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true -} \ No newline at end of file + "C_Cpp.clang_format_path": "/usr/bin/clang-format", + "editor.formatOnSave": false, + "task.autoDetect": "off", + "python.terminal.activateEnvironment": false, + "buid_dir_relative_path":".", + "linux_udev_ledgerblue_rule_file":"20-ledger.ledgerblue.rules", + "docker_image": "ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest", + "container_name": "${workspaceFolderBasename}-container", +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 167e70c..9eda288 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,33 +2,53 @@ "version": "2.0.0", "tasks": [ { - "label": "make", + "label": "Run dev-tools image", "type": "shell", - "command": "make clean && make", + // Checks if a container with the name ${config:container_name} exists, and if it does, it is stopped and removed before a new container is created using the same name and other specified configuration parameters + "linux" : { + "command": "docker ps -a --format '{{.Names}}' | grep -q ${config:container_name} && (docker container stop ${config:container_name} && docker container rm ${config:container_name}) ; docker pull ${config:docker_image} && docker run --user $(id -u):$(id -g) --privileged -e DISPLAY=$DISPLAY -v '/dev/bus/usb:/dev/bus/usb' -v '/tmp/.X11-unix:/tmp/.X11-unix' -v '${workspaceFolder}:/app' -t -d --name ${config:container_name} ${config:docker_image}", + }, + "windows" : { + "command": "if (docker ps -a --format '{{.Names}}' | Select-String -Quiet ${config:container_name}) { docker container stop ${config:container_name}; docker container rm ${config:container_name} }; docker pull ${config:docker_image}; docker run --privileged -e DISPLAY='host.docker.internal:0' -v '${workspaceFolder}:/app' -t -d --name ${config:container_name} ${config:docker_image} ", + }, + "osx" : { + "command": "xhost + ; docker ps -a --format '{{.Names}}' | grep -q ${config:container_name} && (docker container stop ${config:container_name} && docker container rm ${config:container_name}) ; docker pull ${config:docker_image} && docker run --user $(id -u):$(id -g) --privileged -e DISPLAY='host.docker.internal:0' -v '/tmp/.X11-unix:/tmp/.X11-unix' -v '${workspaceFolder}:/app' -t -d --name ${config:container_name} ${config:docker_image}", + }, "group": { "kind": "build", "isDefault": true }, - "problemMatcher": [ - "$gcc" - ] + "problemMatcher": [] }, { - "label": "[debug] make", + "label": "Open dev-tools container terminal", "type": "shell", - "command": "make clean && make DEBUG=1", + // Opens a terminal of the dev-tools container. + "command": "docker exec -it ${config:container_name} bash", "group": { "kind": "build", "isDefault": true }, + "problemMatcher": [] + }, + { + "label": "Build app", + "type": "shell", + // Builds the app in release mode using the make command, inside the docker container. + "command": "docker exec -it ${config:container_name} bash -c 'export BOLOS_SDK=$(echo ${input:sdk}) && make -j'", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [ "$gcc" ] }, { - "label": "make clean", + "label": "Build app [debug]", "type": "shell", - "command": "make clean", + // Builds the app with debug mode enabled using the make command, inside the docker container. + "command": "docker exec -it ${config:container_name} bash -c 'export BOLOS_SDK=$(echo ${input:sdk}) && make -j DEBUG=1'", "group": { "kind": "build", "isDefault": true @@ -38,9 +58,10 @@ ] }, { - "label": "make load", + "label": "Clean build files", "type": "shell", - "command": "make load", + // Cleans all app build files (for all device models). + "command": "docker exec -it ${config:container_name} bash -c 'make clean'", "group": { "kind": "build", "isDefault": true @@ -50,47 +71,43 @@ ] }, { - "label": "run unit tests", + "label": "Test app with Speculos", "type": "shell", - "command": "cd unit-tests && rm -rf build && cmake -Bbuild -H. && make -C build && CTEST_OUTPUT_ON_FAILURE=1 make -C build test", + // Runs the app on the speculos emulator for the selected device model, in the docker container. + "command":"docker exec -it ${config:container_name} bash -c 'speculos --model ${input:model} build/${input:model}/bin/app.elf'", "group": { "kind": "build", "isDefault": true }, - "problemMatcher": [ - "$gcc" - ] + "problemMatcher": [] }, { - "label": "run Speculos", + "label": "Kill Speculos", "type": "shell", - "command": "python /path/to/speculos/speculos.py ${workspaceFolder}/bin/app.elf --ontop --sdk 1.6 --apdu-port 9999 --button-port 42000 --automation-port 43000", + // Kills speculos emulator in the docker container. + "command": "docker exec -it ${config:container_name} bash -c 'pkill -f speculos'", "group": { "kind": "build", "isDefault": true }, - "dependsOn": [ - "make debug" - ], "problemMatcher": [] }, { - "label": "[debug] run Speculos", + "label": "Run functional tests", "type": "shell", - "command": "python /path/to/speculos/speculos.py -d ${workspaceFolder}/bin/app.elf --ontop --sdk 1.6 --apdu-port 9999 --button-port 42000 --automation-port 43000", + // Runs functional tests inside the docker container (with Qt display disabled). + "command": "docker exec -it ${config:container_name} bash -c 'pytest tests/ --tb=short -v --device ${input:model}'", "group": { "kind": "build", "isDefault": true }, - "dependsOn": [ - "make debug" - ], "problemMatcher": [] }, { - "label": "run tests", + "label": "Run functional tests (with display)", "type": "shell", - "command": "cd tests && pytest", + // Runs functional tests inside the docker container (with Qt display enabled). + "command": "docker exec -it ${config:container_name} bash -c 'pytest tests/ --tb=short -v --device ${input:model} --display'", "group": { "kind": "build", "isDefault": true @@ -98,14 +115,87 @@ "problemMatcher": [] }, { - "label": "kill Speculos", + "label": "Install tests requirements", "type": "shell", - "command": "pkill -f speculos.py", + // Installs functional tests python requirements in the docker container. + "command":"docker exec -it -u 0 ${config:container_name} bash -c 'apk add gcc musl-dev python3-dev && pip install -r tests/requirements.txt'", "group": { "kind": "build", "isDefault": true }, "problemMatcher": [] + }, + { + "label": "Load app on device", + "type": "shell", + "linux" : { + // Executes make load in the container to load the app on a physical device. + "command": "docker exec -it ${config:container_name} bash -c 'export BOLOS_SDK=$(echo ${input:sdk}) && make load'", + }, + "windows" : { + // Side loads the app APDU file using ledgerblue runScript. + "command": "cmd.exe /C '.\\ledger\\Scripts\\activate.bat && python -m ledgerblue.runScript --scp --fileName ${config:buid_dir_relative_path}/bin/app.apdu --elfFile ${config:buid_dir_relative_path}/bin/app.elf'", + }, + "osx" : { + // Side loads the app APDU file using ledgerblue runScript. + "command": "source ledger/bin/activate && python3 -m ledgerblue.runScript --scp --fileName ${config:buid_dir_relative_path}/bin/app.apdu --elfFile ${config:buid_dir_relative_path}/bin/app.elf", + }, + "group": { + "kind": "build", + "isDefault": true + }, + "dependsOn": [ + "Install app loading requirements" + ], + "problemMatcher": [] + }, + // ------------------------------------------------------------------------------ + // Helper tasks put in 'test' group so they are hidden from the build tasks menu. + // ------------------------------------------------------------------------------ + { + "label": "Install app loading requirements", + "type": "shell", + "linux" : { + // Copies the ledger udev rule file to the /etc/udev/rules.d/ directory if it does not exist, then reloads the rules and triggers udev. + "command": "if [ ! -f '/etc/udev/rules.d/${config:linux_udev_ledgerblue_rule_file}' ]; then sudo cp .vscode/${config:linux_udev_ledgerblue_rule_file} /etc/udev/rules.d/ && sudo udevadm control --reload-rules && sudo udevadm trigger; fi", + }, + "windows" : { + // Checks that virtual env is installed, otherwise installs it. Then installs ledgerblue in a virtualenv. + "command": "cmd.exe /C 'if not exist ledger (python -m pip install virtualenv && python -m venv ledger && call ledger\\Scripts\\activate.bat && python -m pip install ledgerblue)'", + }, + "osx" : { + // Checks that virtual env is installed, otherwise installs it. Then installs ledgerblue in a virtualenv. + "command": "[ -n '$VIRTUAL_ENV' ] || if ! python3 -m virtualenv --version >/dev/null 2>&1; then python3 -m pip install virtualenv; fi && [ -d 'ledger' ] || python3 -m virtualenv ledger && source ledger/bin/activate && python3 -m pip show ledgerblue >/dev/null 2>&1 || python3 -m pip install ledgerblue", + }, + "group": { + "kind": "test", + "isDefault": true + }, + "problemMatcher": [] + }, + ], + "inputs": [ + { + "id" : "sdk", + "type": "pickString", + "description": "Choose a SDK to build with", + "options": [ + "$NANOS_SDK", + "$NANOX_SDK", + "$NANOSP_SDK", + "$STAX_SDK", + ] + }, + { + "id" : "model", + "type": "pickString", + "description": "Which model to run speculos for ?", + "options": [ + "nanos", + "nanox", + "nanosp", + "stax", + ] } ] -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index 9412a64..b92fc7c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # **************************************************************************** # Ledger App Boilerplate -# (c) 2020 Ledger SAS. +# (c) 2023 Ledger SAS. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -21,119 +21,88 @@ endif include $(BOLOS_SDK)/Makefile.defines -APP_LOAD_PARAMS = --curve secp256k1 -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) -APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS -else -APP_LOAD_PARAMS += --appFlags 0x000 -endif -APP_LOAD_PARAMS += --path "44'/1237'" -APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) +######################################## +# Mandatory configuration # +######################################## +# Application name +APPNAME = "Ledgstr" -APPNAME = "Ledgstr" +# Application version APPVERSION_M = 1 -APPVERSION_N = 0 -APPVERSION_P = 4 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -ifeq ($(TARGET_NAME),TARGET_NANOS) - ICONNAME=icons/nanos_app_boilerplate.gif -else ifeq ($(TARGET_NAME),TARGET_STAX) - ICONNAME=icons/stax_app_boilerplate_32px.gif -else - ICONNAME=icons/nanox_app_boilerplate.gif -endif - -DEFINES += $(DEFINES_LIB) -DEFINES += APPNAME=\"$(APPNAME)\" -DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) PATCH_VERSION=$(APPVERSION_P) -DEFINES += OS_IO_SEPROXYHAL -DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U -DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU -DEFINES += USB_SEGMENT_SIZE=64 -DEFINES += BLE_SEGMENT_SIZE=32 -DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL="" -DEFINES += UNUSED\(x\)=\(void\)x - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) - DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU -endif - -ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128 -else - DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300 -endif - -ifeq ($(TARGET_NAME),TARGET_STAX) - DEFINES += NBGL_QRCODE -else - DEFINES += HAVE_BAGL HAVE_UX_FLOW - ifneq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += HAVE_GLO096 - DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64 - DEFINES += HAVE_BAGL_ELLIPSIS # long label truncation feature - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX - DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX - endif -endif - -DEBUG ?= 0 -ifneq ($(DEBUG),0) - DEFINES += HAVE_PRINTF - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += PRINTF=screen_printf - else - DEFINES += PRINTF=mcu_usb_printf - endif -else - DEFINES += PRINTF\(...\)= -endif - -CC := $(CLANGPATH)clang -AS := $(GCCPATH)arm-none-eabi-gcc -LD := $(GCCPATH)arm-none-eabi-gcc -LDLIBS += -lm -lgcc -lc - -include $(BOLOS_SDK)/Makefile.glyphs +APPVERSION_N = 1 +APPVERSION_P = 0 +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" +# Application source files APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl - -ifneq ($(TARGET_NAME),TARGET_STAX) -SDK_SOURCE_PATH += lib_ux -endif - -ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_STAX)) - SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl -endif -load: all - python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS) - -load-offline: all - python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS) --offline - -delete: - python3 -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) - -include $(BOLOS_SDK)/Makefile.rules - -# Prepare `listvariants` mandatory target. -# This target output must contains: -# - `VARIANTS` which is used as a marker for the tools parsing the output. -# - which is the name of the parameter which should be set +# Application icons following guidelines: +# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon +ICON_NANOS = icons/app_boilerplate_16px.gif +ICON_NANOX = icons/app_boilerplate_14px.gif +ICON_NANOSP = icons/app_boilerplate_14px.gif +ICON_STAX = icons/app_boilerplate_32px.gif + +# Application allowed derivation curves. +# Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1 +# If your app needs it, you can specify multiple curves by using: +# `CURVE_APP_LOAD_PARAMS = ` +CURVE_APP_LOAD_PARAMS = secp256k1 + +# Application allowed derivation paths. +# You should request a specific path for your app. +# This serve as an isolation mechanism. +# Most application will have to request a path according to the BIP-0044 +# and SLIP-0044 standards. +# If your app needs it, you can specify multiple path by using: +# `PATH_APP_LOAD_PARAMS = "44'/1'" "45'/1'"` +PATH_APP_LOAD_PARAMS = "44'/1237'" # purpose=coin(44) / coin_type=Testnet(1) + +# Setting to allow building variant applications +# - is the name of the parameter which should be set # to specify the variant that should be build. # - a list of variant that can be build using this app code. # * It must at least contains one value. # * Values can be the app ticker or anything else but should be unique. -# -# Deployment scripts will use this Makefile target to retrieve the list of -# available variants and then call `make -j =` for each -# in . VARIANT_PARAM = COIN VARIANT_VALUES = BOL -listvariants: - @echo VARIANTS $(VARIANT_PARAM) $(VARIANT_VALUES) + +# Enabling DEBUG flag will enable PRINTF and disable optimizations +#DEBUG = 1 + +######################################## +# Application custom permissions # +######################################## +# See SDK `include/appflags.h` for the purpose of each permission +#HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1 +#HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1 +#HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1 +#HAVE_APPLICATION_FLAG_LIBRARY = 1 + +######################################## +# Application communication interfaces # +######################################## +ENABLE_BLUETOOTH = 1 +#ENABLE_NFC = 1 + +######################################## +# NBGL custom features # +######################################## +ENABLE_NBGL_QRCODE = 1 +#ENABLE_NBGL_KEYBOARD = 1 +#ENABLE_NBGL_KEYPAD = 1 + +######################################## +# Features disablers # +######################################## +# These advanced settings allow to disable some feature that are by +# default enabled in the SDK `Makefile.standard_app`. +#DISABLE_STANDARD_APP_FILES = 1 +#DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1 # To allow custom size declaration +#DISABLE_STANDARD_APP_DEFINES = 1 # Will set all the following disablers +#DISABLE_STANDARD_SNPRINTF = 1 +#DISABLE_STANDARD_USB = 1 +#DISABLE_STANDARD_WEBUSB = 1 +#DISABLE_STANDARD_BAGL_UX_FLOW = 1 + +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/README.md b/README.md index faf1092..b4962da 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Due to device memory limits, the app can only manage ## Build ```sh -sudo docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest + sudo docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest make ``` diff --git a/glyphs/app_boilerplate_16px.gif b/glyphs/app_boilerplate_16px.gif new file mode 100644 index 0000000000000000000000000000000000000000..63f7f66409c0c6b8fa7f14cf68104801756426bb GIT binary patch literal 67 zcmZ?wbh9u|6krfwXkY+=|NsB%fM}2i1Cvru|4OdCJombcOuR1NLGwTVS-pRo{%o( zk%@8+p(E*%O0oj5JT14Q-F`RWaaL+RJJUgQ+DkQn;m9eO{!^&k$!8lMm2($%H7NK8 zC^1*o6|u*+`0%)Rt-tZX-WIxFXFu_-M^{koft8@tV&eS0h>K3+WzZeF2$9j=Hj vef{o8El;Cf?=G2dZoiN3%-^aihx(~|M=)47TCEZ)w6u_r#EBHG6aWA_TF#0B literal 0 HcmV?d00001 diff --git a/glyphs/boilerplate_logo.gif b/glyphs/boilerplate_logo.gif deleted file mode 100644 index 8c6e48515e0d7ec32809b7adfdab8adf20f217ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66 zcmZ?wbhEHb6krfwXkcLY|NlP&1A`6_1Nj0B3`~kG{VPw4U%b@)&M|BK8JorLG#989 UojnoJ7B%UO`#M8ceO3l*0GP5C=l}o! diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif deleted file mode 100644 index a2a7e6d4fa290e4875992d4024e988d14b91df26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZxP`3=Lf^oD9vKom`v^ z4IGV}EX^$3V0vBhlS^|`^GaZPQxJOHaOwpmh};68%`T}$nPsUdZbkXI3Sf_0W#V>= zGfwlMdQ)(_#RaEceV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|LV6Zqk*xT9KSX)_In46iJ z7#kTH=@}C@U!{$jiyfNJ~jdh>MAe2nz`c@bmHVaC32Tu(PqUFf%a% wONgH=z;c3tK?g*D$_@r5iJtzIs~KwUGz+zPEiKD<-x8T<*15Dbij~0{0O2}{jsO4v diff --git a/glyphs/icon_certificate.gif b/glyphs/icon_certificate.gif deleted file mode 100644 index 89b529f792aeb77c8cc3b4d4782d8280b3c6c204..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1133 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZxP`3=Lf^oD9vKom`v^ z4IGV}EX^$3V0vBhlS^|`^GaZPQxJOHaOwpmh};68%`T}$nPsUdZbkXI3Sf_0W#V>= zGfwlMdQ)(_#RaEceV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|LV6Zqk*xT9KSX)_In46iJ z7#kTH=@}C@U!{$jiyfNJ~jdh>MAe2nz`c@bmHVaC32Tu(PqUFf%a% zONgH=z;c3tK?g*D$_@r5rJnxG17}|h+i z#(Mch>H3D2mX`VkM*2oZx= z8BX({dQ)(_1?YGj{?G?HMjsTtNYM=w0;VAl6P|d19C-3i%>$zB`;K7M%r?(Lh`uU@`*{_N?K$B!O9xPR~No!hr=-nf44>XplvE?zi)?(CV< zr%s+Ye(dOx!-ozY*uQV@p5424?%2L<>z2)%Hf~tIZta@Yt5&X9zHI4|#fug$m_Kjs zoY}Kx&X_)J>XgZoCQj(@>+R|8>g;H5Yi((6YHX;ltF5W7s;nq4D=jH5DlEv)%gxEo z%FIYlOHD~mN=%54i;annii`*k3k?Yl3Jmb~^Y!ue^7L?bb9Hfca&)k_v$e6dva~Qa zGc_?bGBnWF)78<|($r8_Q&mw`QdE$ala-N{l9Uh^6BQ8_5)|O)h+i z#(Mch>H3D2mX`VkM*2oZxP`3=Lf^oD9vKom`v^ z4IGV}EX^$3V0vBhlS^|`^GaZPQxJMxaOwpmh};68%`T}$nPsUdZbkXI3Sf_0W#V>= zBTn<6dQ)(_#R;cgeV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|LU=%qz*xT9KSX)_In46iJ z7#kTH=@}C@U!{$jiyfNJ~jdh>MAe2nz`c@bmHVaC32Tu(PqUFf%a% zONgH=z;c3tK?g*D$_@r5g`R%S3EQ{LsG1P=G9yPZ?_TW!_O_JIo#INXvMrLH1~M>M F0{{d^jh+i z#(Mch>H3D2mX`VkM*2oZx|Z5PF?(>IEf;+ybD@E~!PCWvMA{Mftf3V2@j6;&zJ# zPV=C8Q*gV*5~p5$pkwqw(Tfz_Fd<+X0x{u<7s!Dp|I|ESnlAz-ZpQ!r{{H#>>*tT} z-@bnN{ORL|_wU}mdHw3;i|5atK6(7;;e-44?%uh5>*kH?*REcZ;0$^0LyB;-bQW{Jh+p?5xa; z^t9BJ|cQ;oTXD3GodplbjYb#3&b2C#D zVqwaWPR5VIe^Qem-6vZZ1v^b~aWPW+p~p z3GtH!SWYl7=zs`N*}=f1)WgepeBpkH7I)L>0efyf`cv6&*0!WWPeHu$lGW7Enz_D= G4Aua{vX6rR diff --git a/glyphs/icon_dashboard_x.gif b/glyphs/icon_dashboard_x.gif deleted file mode 100644 index 33d9b0a74a263937a8cbb3b7c4ccfd4bd4fd2a3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1126 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZx= z5l-`({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A5 z6JsMo1ARSR9c?X54RtkD6=fww1$jAH8EGj=32`w|5n&-g0e(JS9&Rp94t6$H7G@?! zUc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDi`Y;NgdWMu4QWZ>pz zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF8LAmYFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-I6icj50lNgEH3i8fKwls^#1W@feV|kH(V`kA1WZ04CM4AY z(t84%^TORUA=Po(!~qs&z(JU`qar2$B!L7a`@1}1N-;w-Lrew&K=vgZQZhY z)5ZeMTG_VdAT{+S(zE>X{jm6Nr?&Zaj`McQIQehVWA};$o%uI|73_73^0#s@+FtPL0rFC}Ia4}c|0Jk%O AU;qFB diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif deleted file mode 100644 index df4bb829e6d06e0bde643b1b96fde45c093edef1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1130 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZxP`3=Lf^oD9vKom`v^ z4IGV}EX^$3V0vBhlS^|`^GaZPQxJOHaOwpmh};68%`T}$nPsUdZbkXI3Sf_0W#V>= zGfwlMdQ)(_#RaEceV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|LV6Zqk*xT9KSX)_In46iJ z7#kTH=@}C@U!{$jiyfNJ~jdh>MAe2nz`c@bmHVaC32Tu(PqUFf%a% zONgH=z;c3tK?g*D$_@r5`JVojvmYFo*YYB?T-40^%iq9xH)NNlPJ66kronvNgOR}+ E02G{#(EtDd diff --git a/glyphs/icon_left.gif b/glyphs/icon_left.gif deleted file mode 100644 index 524226ba11247d9c5f797801400fd630071a049a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1101 zcmZ?wbhEHbWMN=u_`m=H|NsA2{K*1lD*orL$SqJvNi0bO(*Nx%3KEmEQ%e+*Qqwc@ zY?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDkcY~W;U?r3IeWZ>*# zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF45}GLFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-I6l1JT0lNgEH3i8fKwls^!~~~SeV|kH(V`kA1WZ04CM4AY z(t84%^TORUA=Po(!~qs&z(JU`qar2$B!L7a`@1}1N-;w-Lrew&K=vgZQZhY z)5ZeMTG_VdAT{+S(zE>X{jm6Nr?&Zaj`McQIQehVWA};$o%uI|73_73^0#s@+FmbdLb7tJW=fuch4FGsN BgIfRq diff --git a/glyphs/icon_processing.gif b/glyphs/icon_processing.gif deleted file mode 100644 index 8fe937facc2d11dfa878b61d3f46055ae87996e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1130 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZx= z8BX({dQ)(_1?YGj{?G?HMjsTtNYM=w0;VAl6P|d19C-3i%>$zB`;K7M%r?(Lh`uU@`*{_N?K$B!O9xPR~No!hr=-nf44>XplvE?zi)?(CV< zr%s+Ye(dOx!-ozY*uQV@p5424?%2L<>z2)%Hf~tIZta@Yt5&X9zHI4|#fug$m_Kjs zoY}Kx&X_)J>XgZoCQj(@>+R|8>g;H5Yi((6YHX;ltF5W7s;nq4D=jH5DlEv)%gxEo z%FIYlOHD~mN=%54i;annii`*k3k?Yl3Jmb~^Y!ue^7L?bb9Hfca&)k_v$e6dva~Qa zGc_?bGBnWF)78<|($r8_Q&mw`QdE$ala-N{l9Uh^6BQ8_5)|O)c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDkcY~W;U?r3IcWZ>*# zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&BF2&x%HFGwpWEr5aq7{EoD zWvMA{Mftf3V1HX>!rg-A6jL{>P64|FqBRA{B|u*wIm7^`R(+sT^wFXkCIn1AASNW$ z0@Eju15Nk;OB7P`fT_I*n5-H9|NHyr_phHnzJL4r<@2Wx@87+B^ZM1x7tfzPee(Fx z!w2{8-Mw@B*3BE&uU)-z`O?J;=g*xzbNbZD6UUDoJ#zTa!2|pE?cK9`*UlZ=w{6|B zdDF%X>({MavwGFa70Z_`U9x!5!Ugl^&7CuQ*322xr%jzQdD6rQ{e8VX-Cdm>?QN|s z%}tFB^>wv1)m4=h1nAc$w`R`@o}*+(NU2R;bEa6!9jrm z{(inb-d>&_?ryFw&Q6XF_I9>5)>f7l=4PfQ#zuw)`g*!L+FF_#>T0Sg%1Vj~@^Z2= z(o&KV;$osA!a{-q{CvDTJltHI9PDhYEX+)d3=BG;5&~3eFfg(6@U>OF>g8gv1_1YR Bf|mdQ diff --git a/glyphs/icon_up.gif b/glyphs/icon_up.gif deleted file mode 100644 index 4e13c064f7605feb2e6e04a48a3133e5c95912cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1100 zcmZ?wbhEHbWM^Pu_`m=H|NsA2{K*1lD*orL$SqJvNi0bO(*Nx%3KEmEQ%e+*Qqwc@ zY?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*btCX0MpOk6^Wap-qB64UF}T4Rno+txOE8OpFwuK*`RgC?(A*$i)q66_97Elu=SrV5P5L zUS6(Ou9shwu5V~*X{m2uq;F)T3sj(6T$u;-oo-&SvJ%j-AOl=di<65o3raHc^Aw8G ztP+#*OG|8(lob9$J&;=fH#M(V59}GeYG-AXPsowK%`DC^;3VTp46jft7PnYGO%#QAmD%4lD=*GV)9Ei!<^I z6r7#GL8hSLo0y!L2NcundS0ve;2nVDi`Y;NgdWMu4SWZ>pz zXy|I@XlQBVYUE;UXz6Nc_}|je8K&7KKe;qFHLnDwIR&oS!~m)pMK4GzC@p}31Q@_Y znPsUdZbkXI3SfU*Wy0Np?i3fSP64|FqBRA{B|u*w9AfN>Q>#AEDf(zp4HE(;9}p9g zYJuq!$bqK&|0N2kdBD_O1WeY9|Ns5{^ZVD&AK$-y{qp(KhxhN^zIpxX<%{Rfo<4c} z=;4F=_wL@gee33p>({PcxqRv3h4bgmo;iK$#u35cm<%;FYmM&SmXyJnS^XAT(J!|HS>C>i8nLKIYg#NzXp6;&Bj`p_J zmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3jP$hBl;otug!s7FnCPg;i14t`kl>)e z0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A56JsMo1ARSR9c?X54RtkD6=fww1$jAH z8EGj=32`w|5n&-g0e(JS9v*HkP7Zc9Ru*O^Mg|5QPzeDlH5i!KTar5~xYlqnSOWmI C)q;Qk diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif deleted file mode 100644 index ccb5cabe38d16ff857d540b64742e4b8346a6949..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1125 zcmZ?wbhEHbh+i z#(Mch>H3D2mX`VkM*2oZx= z0Z#LvdQ)(_#So`neV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A5 z6JsMo1ARSR9c?X54RtkD6=fww1$jAH8EGj=32`w|5n&-g0e(JS9&Rp94t6$H7G@?! zUh+i z#(Mch>H3D2mX`VkM*2oZxP`3=Lf^oD9vKom`v^ z4IGV}EX^$3V0vBhlS^|`^GaZPQxJMhaOwpmh};68%`T}$nPsUdZbkXI3Sf_0W#V>= zAx`t4dQ)(_#R#WfeV}9XLD7p8-7q0w8Uiuli5JL$C;!wuV45!iCT_<6|Nj2@{p;tC z@87({PcxqRv3h4bgmo;iK$ z#u35cm<%;FYmM&SmXyJnS^XAT( zJ!|HS>C>i8nLKIYg#NzXp6;&Bj`p_Jmgc6$hWfhNn(C^`it@73lH#Jmg8aPPob0U3 zjP$hBl;otug!s7FnCPg;i14t`kl>)e0DnJUA8#*D4|g|L7iT9&2YWkP8*3{|3v)A5 z6JsMo1ARSR9c?X54RtkD6=fww1$jAH8EGj=32`w|5n&-g0e(JS9&Rp94t6$H7G@?! zU86_Pkv2uV`Q)f0P2pAa|nV6WEnVDHwSXfzE+1S|F+1WWbI5;^uxwyEvxw(0G zczAhv`T6+;1Ox;H1%-r!goTAgL_|bIMa9L%B_$=Lq@<*!rDbJh<>cfP6ciK{6_u2f zl$DiLRaG@KG&D6ewY0RfwY7D1b@lc24Gatn4GoQqjEs$qO-xKoO-;?r%Z+=!o$NOA|j%qqN1atV`5@rV`CE&6O)sZQ&LjW($ezt z^NWg#N=iy9Dk>@~D{E?MYHMrj>gww2>l+#x8XFs%nwnZ#TH4y$y1To3dwVBLm@skT z#7UDTO`be?%9JV7r%#_TW5%pmvu4kpJ$LThg$oxhTC`~K;>AmsE?u!=#mbc{SFKvL zdiClxYu2n?yLQ8d4I4LZ+_Y)a)~#E&ZQHhU=gwWbcJ0}-XWzbk2M!!Kbm-9G!-tO? zIdb&q(PPJs9Y22j#EBCpPo6w;=FG*57cX79bnV);>({T}xN+mwty_2Q+_``M{(}b( z9zJ~d`0?W>Po6w`_U!rd=PzEoc=__>t5>hyym|BX?b~(}q!zyJLC!|?y&C?YikbU--(louE{rZ5Ht|89@)c zrs>A}^=NKZT{g?iahK0Zp~vTDS|$oT(cHAeZINUzpR3nJr3*_<)Qv=Em8e~vZ@bY+ zXI9ax%k56<@1;~3=mc#P-9Jxtcj?RP8|6B?T)6|+#%#-*ueG%LOP>3DGha3q25SHu C@Zy*N literal 0 HcmV?d00001 diff --git a/icons/nanos_app_boilerplate.gif b/icons/nanos_app_boilerplate.gif deleted file mode 100644 index 0cc43b7d4b8a25120853dee551878e14907d2a25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 895 zcmW-fF^d>P6oltu5@QMp*aUJ&(gee%kq2U82&fRfMh;=oBEm&sz)tWFtc9kzB3NZg zgGkuU|1n+IKN3(8gmLe-Sa$cp&U@d?XGf1dy!Yf9uHgsZ*1s1Ifd6n8d!4;KJv*QP z0s;&K4QPc%G@%(S=s+)Yq6^*V!2m{K5JMQo2qrKKlbFIZX0U)&Si};Rv9kY03LzrI z$i8gtDzKn}cdZ(#RW(*qHCIb@RIlo+uIjFy8mLh8M>xS*oa7Xz zIl~36;v$#0%oPSqF=WJ;*$6iA5-3RUCZYzlQlpyGtQK{smpav@ZuMwDqco@?4QoUb znx#oiX<9Q{&?+rzNy}PMpp-&Iij_@&n_UJC8Qx~N!L8irCO5mq9q#2$ce&d=9`Gm+ zddR~b@q}l2(o>%Hj2FDhi(c}wR~$Iy(2-*&XF=F*Y$Us{UEEPA3x<=t0Tar4s)#~&R3e)R0G%e;T*^`no! w)!)C}J9_=(kLx)3;@9hM+!{CD{Oa*Lm0*=j9>zjn8Gw>VFn9W#1fXV3M>0> zgoqF$h3w1LCLzK^?HU`{$R;+k6QJY;)U96X(SQauq+yNHh$b|tDNSpZ zX0)J1EooV+w4y+vBE?E68^I<{LxzpoMBLy;H@VrZ+~N**y35_}fD35r; zlb-UlXL-g8Ui6Zey~-;N96ECBl(Xq?vsqBVh1zCRLp4@YHCL-@sgCNbuIjE{)l&mC zSVJ{jqiUokYOl?p1XsNzahavFr~#zwOH+Ql7(hBT%r&1sdE zbfhy~=}xcoWFUhX%5X+yBomp;RHid4Gg-)Dma?2xS*KzAU?wF|%gdGm)4 zZr%Uv*yl_?)c( diff --git a/src/address.c b/src/address.c index 4caba5c..f61ed04 100644 --- a/src/address.c +++ b/src/address.c @@ -25,38 +25,9 @@ #include "address.h" +#include "helper/bech32.h" #include "transaction/types.h" -#include "common/segwit_addr.h" - -static int convert_bits(uint8_t* out, - size_t* outlen, - int outbits, - const uint8_t* in, - size_t inlen, - int inbits, - int pad) { - uint32_t val = 0; - int bits = 0; - uint32_t maxv = (((uint32_t) 1) << outbits) - 1; - while (inlen--) { - val = (val << inbits) | *(in++); - bits += inbits; - while (bits >= outbits) { - bits -= outbits; - out[(*outlen)++] = (val >> bits) & maxv; - } - } - if (pad) { - if (bits) { - out[(*outlen)++] = (val << (outbits - bits)) & maxv; - } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { - return 0; - } - return 1; -} - bool address_from_pubkey(const uint8_t public_key[static 64], uint8_t* out, size_t out_len) { char address[ADDRESS_BECH32_LEN] = {0}; diff --git a/src/address.h b/src/address.h index 15da888..0bb9119 100644 --- a/src/address.h +++ b/src/address.h @@ -4,6 +4,8 @@ #include // size_t #include // bool +#include "helper/bech32.h" + /** * Convert public key to address. * diff --git a/src/apdu/dispatcher.c b/src/apdu/dispatcher.c index 2e343d0..c3d89ad 100644 --- a/src/apdu/dispatcher.c +++ b/src/apdu/dispatcher.c @@ -18,20 +18,20 @@ #include #include +#include "buffer.h" +#include "io.h" + #include "dispatcher.h" #include "../constants.h" #include "../globals.h" #include "../types.h" -#include "../io.h" #include "../sw.h" -#include "../common/buffer.h" #include "../handler/get_version.h" #include "../handler/get_app_name.h" #include "../handler/get_public_key.h" -#include "../handler/get_response.h" -#include "../handler/sign_event.h" #include "../handler/encrypt_data.h" -#include "../helper/send_response.h" +#include "../handler/sign_event.h" +#include "../handler/get_response.h" int apdu_dispatcher(const command_t *cmd) { if (cmd->cla != CLA) { diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h index f9f5e5a..191ce3f 100644 --- a/src/apdu/dispatcher.h +++ b/src/apdu/dispatcher.h @@ -1,5 +1,7 @@ #pragma once +#include "parser.h" + #include "../types.h" /** @@ -17,7 +19,7 @@ /** * Parameter 1 for maximum APDU number. */ -#define P1_MAX 0x10 +#define P1_MAX 0x03 /** * Dispatch APDU command received to the right handler. diff --git a/src/apdu/parser.c b/src/apdu/parser.c deleted file mode 100644 index cbf4336..0000000 --- a/src/apdu/parser.c +++ /dev/null @@ -1,40 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (c) 2020 Ledger SAS. - * - * 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 // size_t -#include // uint*_t -#include // bool - -#include "parser.h" -#include "../types.h" -#include "../offsets.h" - -bool apdu_parser(command_t *cmd, uint8_t *buf, size_t buf_len) { - // Check minimum length and Lc field of APDU command - if (buf_len < OFFSET_CDATA || buf_len - OFFSET_CDATA != buf[OFFSET_LC]) { - return false; - } - - cmd->cla = buf[OFFSET_CLA]; - cmd->ins = (command_e) buf[OFFSET_INS]; - cmd->p1 = buf[OFFSET_P1]; - cmd->p2 = buf[OFFSET_P2]; - cmd->lc = buf[OFFSET_LC]; - cmd->data = (buf[OFFSET_LC] > 0) ? buf + OFFSET_CDATA : NULL; - - return true; -} diff --git a/src/apdu/parser.h b/src/apdu/parser.h deleted file mode 100644 index dfba3fd..0000000 --- a/src/apdu/parser.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include // size_t -#include // uint*_t -#include // bool - -#include "../types.h" - -/** - * Parse APDU command from byte buffer. - * - * @param[out] cmd - * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). - * @param[in] buf - * Byte buffer with raw APDU command. - * @param[in] buf_len - * Length of byte buffer. - * - * @return true if success, false otherwise. - * - */ -bool apdu_parser(command_t *cmd, uint8_t *buf, size_t buf_len); diff --git a/src/app_main.c b/src/app_main.c new file mode 100644 index 0000000..a5f43f2 --- /dev/null +++ b/src/app_main.c @@ -0,0 +1,78 @@ +/***************************************************************************** + * Ledger App Boilerplate. + * (c) 2020 Ledger SAS. + * + * 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 // uint*_t +#include // memset, explicit_bzero + +#include "os.h" +#include "ux.h" + +#include "types.h" +#include "globals.h" +#include "io.h" +#include "sw.h" +#include "ui/menu.h" +#include "apdu/dispatcher.h" + +global_ctx_t G_context; + +/** + * Handle APDU command received and send back APDU response using handlers. + */ +void app_main() { + // Length of APDU command received in G_io_apdu_buffer + int input_len = 0; + // Structured APDU command + command_t cmd; + + io_init(); + + ui_menu_main(); + + // Reset context + explicit_bzero(&G_context, sizeof(G_context)); + + for (;;) { + // Receive command bytes in G_io_apdu_buffer + if ((input_len = io_recv_command()) < 0) { + PRINTF("=> io_recv_command failure\n"); + return; + } + + // Parse APDU command from G_io_apdu_buffer + if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { + PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); + io_send_sw(SW_WRONG_DATA_LENGTH); + continue; + } + + PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", + cmd.cla, + cmd.ins, + cmd.p1, + cmd.p2, + cmd.lc, + cmd.lc, + cmd.data); + + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } + } +} diff --git a/src/common/base58.c b/src/common/base58.c deleted file mode 100644 index 4c15dbd..0000000 --- a/src/common/base58.c +++ /dev/null @@ -1,155 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // size_t -#include // uint*_t -#include // memmove, memset -#include // bool - -#include "base58.h" - -uint8_t const BASE58_TABLE[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // - 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xFF, 0xFF, // - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // - 0x10, 0xFF, 0x11, 0x12, 0x13, 0x14, 0x15, 0xFF, 0x16, 0x17, 0x18, 0x19, // - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // - 0xFF, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, // - 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, // - 0x37, 0x38, 0x39, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // -}; - -char const BASE58_ALPHABET[] = { - '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', // - 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', // - 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', // - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' // -}; - -int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len) { - uint8_t tmp[MAX_DEC_INPUT_SIZE] = {0}; - uint8_t buffer[MAX_DEC_INPUT_SIZE] = {0}; - uint8_t j; - uint8_t start_at; - uint8_t zero_count = 0; - - if (in_len > MAX_DEC_INPUT_SIZE || in_len < 2) { - return -1; - } - - memmove(tmp, in, in_len); - - for (uint8_t i = 0; i < in_len; i++) { - if (in[i] >= sizeof(BASE58_TABLE)) { - return -1; - } - - tmp[i] = BASE58_TABLE[(int) in[i]]; - - if (tmp[i] == 0xFF) { - return -1; - } - } - - while ((zero_count < in_len) && (tmp[zero_count] == 0)) { - ++zero_count; - } - - j = in_len; - start_at = zero_count; - while (start_at < in_len) { - uint16_t remainder = 0; - for (uint8_t div_loop = start_at; div_loop < in_len; div_loop++) { - uint16_t digit256 = (uint16_t)(tmp[div_loop] & 0xFF); - uint16_t tmp_div = remainder * 58 + digit256; - tmp[div_loop] = (uint8_t)(tmp_div / 256); - remainder = tmp_div % 256; - } - - if (tmp[start_at] == 0) { - ++start_at; - } - - buffer[--j] = (uint8_t) remainder; - } - - while ((j < in_len) && (buffer[j] == 0)) { - ++j; - } - - int length = in_len - (j - zero_count); - - if ((int) out_len < length) { - return -1; - } - - memmove(out, buffer + j - zero_count, length); - - return length; -} - -int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len) { - uint8_t buffer[MAX_ENC_INPUT_SIZE * 138 / 100 + 1] = {0}; - size_t i, j; - size_t stop_at; - size_t zero_count = 0; - size_t output_size; - - if (in_len > MAX_ENC_INPUT_SIZE) { - return -1; - } - - while ((zero_count < in_len) && (in[zero_count] == 0)) { - ++zero_count; - } - - output_size = (in_len - zero_count) * 138 / 100 + 1; - stop_at = output_size - 1; - for (size_t start_at = zero_count; start_at < in_len; start_at++) { - int carry = in[start_at]; - for (j = output_size - 1; (int) j >= 0; j--) { - carry += 256 * buffer[j]; - buffer[j] = carry % 58; - carry /= 58; - - if (j <= stop_at - 1 && carry == 0) { - break; - } - } - stop_at = j; - } - - j = 0; - while (j < output_size && buffer[j] == 0) { - j += 1; - } - - if (out_len < zero_count + output_size - j) { - return -1; - } - - memset(out, BASE58_ALPHABET[0], zero_count); - - i = zero_count; - while (j < output_size) { - out[i++] = BASE58_ALPHABET[buffer[j++]]; - } - - return i; -} diff --git a/src/common/base58.h b/src/common/base58.h deleted file mode 100644 index f214afd..0000000 --- a/src/common/base58.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include // size_t -#include // uint*_t -#include // bool - -/** - * Maximum length of input when decoding in base 58. - */ -#define MAX_DEC_INPUT_SIZE 164 -/** - * Maximum length of input when encoding in base 58. - */ -#define MAX_ENC_INPUT_SIZE 120 - -/** - * Decode input string in base 58. - * - * @see https://tools.ietf.org/html/draft-msporny-base58-02 - * - * @param[in] in - * Pointer to input string buffer. - * @param[in] in_len - * Length of the input string buffer. - * @param[out] out - * Pointer to output byte buffer. - * @param[in] out_len - * Maximum length to write in output byte buffer. - * - * @return number of bytes decoded, -1 otherwise. - * - */ -int base58_decode(const char *in, size_t in_len, uint8_t *out, size_t out_len); - -/** - * Encode input bytes in base 58. - * - * @see https://tools.ietf.org/html/draft-msporny-base58-02 - * - * @param[in] in - * Pointer to input byte buffer. - * @param[in] in_len - * Length of the input byte buffer. - * @param[out] out - * Pointer to output string buffer. - * @param[in] out_len - * Maximum length to write in output byte buffer. - * - * @return number of bytes encoded, -1 otherwise. - * - */ -int base58_encode(const uint8_t *in, size_t in_len, char *out, size_t out_len); diff --git a/src/common/bip32.c b/src/common/bip32.c deleted file mode 100644 index a6ac6e5..0000000 --- a/src/common/bip32.c +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // snprintf -#include // memset, strlen -#include // size_t -#include // uint*_t -#include // bool - -#include "bip32.h" -#include "read.h" - -bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, size_t out_len) { - if (out_len == 0 || out_len > MAX_BIP32_PATH) { - return false; - } - - size_t offset = 0; - - for (size_t i = 0; i < out_len; i++) { - if (offset > in_len) { - return false; - } - out[i] = read_u32_be(in, offset); - offset += 4; - } - - return true; -} - -bool bip32_path_format(const uint32_t *bip32_path, - size_t bip32_path_len, - char *out, - size_t out_len) { - if (bip32_path_len == 0 || bip32_path_len > MAX_BIP32_PATH) { - return false; - } - - size_t offset = 0; - - for (uint16_t i = 0; i < bip32_path_len; i++) { - size_t written; - - snprintf(out + offset, out_len - offset, "%d", bip32_path[i] & 0x7FFFFFFFu); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - - if ((bip32_path[i] & 0x80000000u) != 0) { - snprintf(out + offset, out_len - offset, "'"); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - } - - if (i != bip32_path_len - 1) { - snprintf(out + offset, out_len - offset, "/"); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - } - } - - return true; -} diff --git a/src/common/bip32.h b/src/common/bip32.h deleted file mode 100644 index 3e2491e..0000000 --- a/src/common/bip32.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include // size_t -#include // uint*_t -#include // bool - -/** - * Maximum length of BIP32 path allowed. - */ -#define MAX_BIP32_PATH 10 - -/** - * Read BIP32 path from byte buffer. - * - * @param[in] in - * Pointer to input byte buffer. - * @param[in] in_len - * Length of input byte buffer. - * @param[out] out - * Pointer to output 32-bit integer buffer. - * @param[in] out_len - * Number of BIP32 paths read in the output buffer. - * - * @return true if success, false otherwise. - * - */ -bool bip32_path_read(const uint8_t *in, size_t in_len, uint32_t *out, size_t out_len); - -/** - * Format BIP32 path as string. - * - * @param[in] bip32_path - * Pointer to 32-bit integer input buffer. - * @param[in] bip32_path_len - * Maximum number of BIP32 paths in the input buffer. - * @param[out] out string - * Pointer to output string. - * @param[in] out_len - * Length of the output string. - * - * @return true if success, false otherwise. - * - */ -bool bip32_path_format(const uint32_t *bip32_path, - size_t bip32_path_len, - char *out, - size_t out_len); diff --git a/src/common/buffer.c b/src/common/buffer.c deleted file mode 100644 index 3bd617b..0000000 --- a/src/common/buffer.c +++ /dev/null @@ -1,165 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // uint*_t -#include // size_t -#include // bool -#include // memmove - -#include "buffer.h" -#include "read.h" -#include "varint.h" -#include "bip32.h" - -bool buffer_can_read(const buffer_t *buffer, size_t n) { - return buffer->size - buffer->offset >= n; -} - -bool buffer_seek_set(buffer_t *buffer, size_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->offset = offset; - - return true; -} - -bool buffer_seek_cur(buffer_t *buffer, size_t offset) { - if (buffer->offset + offset < buffer->offset || // overflow - buffer->offset + offset > buffer->size) { // exceed buffer size - return false; - } - - buffer->offset += offset; - - return true; -} - -bool buffer_seek_end(buffer_t *buffer, size_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->offset = buffer->size - offset; - - return true; -} - -bool buffer_read_u8(buffer_t *buffer, uint8_t *value) { - if (!buffer_can_read(buffer, 1)) { - *value = 0; - - return false; - } - - *value = buffer->ptr[buffer->offset]; - buffer_seek_cur(buffer, 1); - - return true; -} - -bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 2)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u16_be(buffer->ptr, buffer->offset) - : read_u16_le(buffer->ptr, buffer->offset)); - - buffer_seek_cur(buffer, 2); - - return true; -} - -bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 4)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u32_be(buffer->ptr, buffer->offset) - : read_u32_le(buffer->ptr, buffer->offset)); - - buffer_seek_cur(buffer, 4); - - return true; -} - -bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness) { - if (!buffer_can_read(buffer, 8)) { - *value = 0; - - return false; - } - - *value = ((endianness == BE) ? read_u64_be(buffer->ptr, buffer->offset) - : read_u64_le(buffer->ptr, buffer->offset)); - - buffer_seek_cur(buffer, 8); - - return true; -} - -bool buffer_read_varint(buffer_t *buffer, uint64_t *value) { - int length = varint_read(buffer->ptr + buffer->offset, buffer->size - buffer->offset, value); - - if (length < 0) { - *value = 0; - - return false; - } - - buffer_seek_cur(buffer, (size_t) length); - - return true; -} - -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, size_t out_len) { - if (!bip32_path_read(buffer->ptr + buffer->offset, - buffer->size - buffer->offset, - out, - out_len)) { - return false; - } - - buffer_seek_cur(buffer, sizeof(*out) * out_len); - - return true; -} - -bool buffer_copy(const buffer_t *buffer, uint8_t *out, size_t out_len) { - if (buffer->size - buffer->offset > out_len) { - return false; - } - - memmove(out, buffer->ptr + buffer->offset, buffer->size - buffer->offset); - - return true; -} - -bool buffer_move(buffer_t *buffer, uint8_t *out, size_t out_len) { - if (!buffer_copy(buffer, out, out_len)) { - return false; - } - - buffer_seek_cur(buffer, out_len); - - return true; -} diff --git a/src/common/buffer.h b/src/common/buffer.h deleted file mode 100644 index ae3e829..0000000 --- a/src/common/buffer.h +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once - -#include // uint*_t -#include // size_t -#include // bool - -/** - * Enumeration for endianness. - */ -typedef enum { - BE, /// Big Endian - LE /// Little Endian -} endianness_t; - -/** - * Struct for buffer with size and offset. - */ -typedef struct { - const uint8_t *ptr; /// Pointer to byte buffer - size_t size; /// Size of byte buffer - size_t offset; /// Offset in byte buffer -} buffer_t; - -/** - * Tell whether buffer can read bytes or not. - * - * @param[in] buffer - * Pointer to input buffer struct. - * @param[in] n - * Number of bytes to read in buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_can_read(const buffer_t *buffer, size_t n); - -/** - * Seek the buffer to specific offset. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[in] offset - * Specific offset to seek. - * - * @return true if success, false otherwise. - * - */ -bool buffer_seek_set(buffer_t *buffer, size_t offset); - -/** - * Seek buffer relatively to current offset. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[in] offset - * Offset to seek relatively to `buffer->offset`. - * - * @return true if success, false otherwise. - * - */ -bool buffer_seek_cur(buffer_t *buffer, size_t offset); - -/** - * Seek the buffer relatively to the end. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[in] offset - * Offset to seek relatively to `buffer->size`. - * - * @return true if success, false otherwise. - * - */ -bool buffer_seek_end(buffer_t *buffer, size_t offset); - -/** - * Read 1 byte from buffer into uint8_t. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] value - * Pointer to 8-bit unsigned integer read from buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_u8(buffer_t *buffer, uint8_t *value); - -/** - * Read 2 bytes from buffer into uint16_t. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] value - * Pointer to 16-bit unsigned integer read from buffer. - * @param[in] endianness - * Either BE (Big Endian) or LE (Little Endian). - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness); - -/** - * Read 4 bytes from buffer into uint32_t. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] value - * Pointer to 32-bit unsigned integer read from buffer. - * @param[in] endianness - * Either BE (Big Endian) or LE (Little Endian). - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness); - -/** - * Read 8 bytes from buffer into uint64_t. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] value - * Pointer to 64-bit unsigned integer read from buffer. - * @param[in] endianness - * Either BE (Big Endian) or LE (Little Endian). - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness); - -/** - * Read Bitcoin-like varint from buffer into uint64_t. - * - * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] value - * Pointer to 64-bit unsigned integer read from buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_varint(buffer_t *buffer, uint64_t *value); - -/** - * Read BIP32 path from buffer. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] out - * Pointer to output 32-bit integer buffer. - * @param[in] out_len - * Number of BIP32 paths read in the output buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, size_t out_len); - -/** - * Copy bytes from buffer without moving offset. - * - * @param[in] buffer - * Pointer to input buffer struct. - * @param[out] out - * Pointer to output byte buffer. - * @param[in] out_len - * Length of output byte buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_copy(const buffer_t *buffer, uint8_t *out, size_t out_len); - -/** - * Move bytes from buffer. - * - * @param[in,out] buffer - * Pointer to input buffer struct. - * @param[out] out - * Pointer to output byte buffer. - * @param[in] out_len - * Length of output byte buffer. - * - * @return true if success, false otherwise. - * - */ -bool buffer_move(buffer_t *buffer, uint8_t *out, size_t out_len); diff --git a/src/common/format.c b/src/common/format.c deleted file mode 100644 index d616c29..0000000 --- a/src/common/format.c +++ /dev/null @@ -1,157 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // size_t -#include // int*_t, uint*_t -#include // strncpy, memmove -#include // bool - -#include "format.h" - -bool format_i64(char *dst, size_t dst_len, const int64_t value) { - char temp[] = "-9223372036854775808"; - - char *ptr = temp; - int64_t num = value; - int sign = 1; - - if (value < 0) { - sign = -1; - } - - while (num != 0) { - *ptr++ = '0' + (num % 10) * sign; - num /= 10; - } - - if (value < 0) { - *ptr++ = '-'; - } else if (value == 0) { - *ptr++ = '0'; - } - - int distance = (ptr - temp) + 1; - - if ((int) dst_len < distance) { - return false; - } - - size_t index = 0; - - while (--ptr >= temp) { - dst[index++] = *ptr; - } - - dst[index] = '\0'; - - return true; -} - -bool format_u64(char *out, size_t outLen, uint64_t in) { - uint8_t i = 0; - - if (outLen == 0) { - return false; - } - outLen--; - - while (in > 9) { - out[i] = in % 10 + '0'; - in /= 10; - i++; - if (i + 1 > outLen) { - return false; - } - } - out[i] = in + '0'; - out[i + 1] = '\0'; - - uint8_t j = 0; - char tmp; - - // revert the string - while (j < i) { - // swap out[j] and out[i] - tmp = out[j]; - out[j] = out[i]; - out[i] = tmp; - - i--; - j++; - } - return true; -} - -bool format_fpu64(char *dst, size_t dst_len, const uint64_t value, uint8_t decimals) { - char buffer[21] = {0}; - - if (!format_u64(buffer, sizeof(buffer), value)) { - return false; - } - - size_t digits = strlen(buffer); - - if (digits <= decimals) { - if (dst_len <= 2 + decimals - digits) { - return false; - } - *dst++ = '0'; - *dst++ = '.'; - for (uint16_t i = 0; i < decimals - digits; i++, dst++) { - *dst = '0'; - } - dst_len -= 2 + decimals - digits; - strncpy(dst, buffer, dst_len); - } else { - if (dst_len <= digits + 1 + decimals) { - return false; - } - - const size_t shift = digits - decimals; - memmove(dst, buffer, shift); - dst[shift] = '.'; - strncpy(dst + shift + 1, buffer + shift, decimals); - } - - return true; -} - -int format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len) { - if (out_len < 2 * in_len + 1) { - return -1; - } - - const char hex[] = "0123456789ABCDEF"; - size_t i = 0; - int written = 0; - - while (i < in_len && (i * 2 + (2 + 1)) <= out_len) { - uint8_t high_nibble = (in[i] & 0xF0) >> 4; - *out = hex[high_nibble]; - out++; - - uint8_t low_nibble = in[i] & 0x0F; - *out = hex[low_nibble]; - out++; - - i++; - written += 2; - } - - *out = '\0'; - - return written + 1; -} diff --git a/src/common/format.h b/src/common/format.h deleted file mode 100644 index f145748..0000000 --- a/src/common/format.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include // size_t -#include // int*_t, uint*_t -#include // bool - -/** - * Format 64-bit signed integer as string. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit signed integer to format. - * - * @return true if success, false otherwise. - * - */ -bool format_i64(char *dst, size_t dst_len, const int64_t value); - -/** - * Format 64-bit unsigned integer as string. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit unsigned integer to format. - * - * @return true if success, false otherwise. - * - */ -bool format_u64(char *dst, size_t dst_len, uint64_t value); - -/** - * Format 64-bit unsigned integer as string with decimals. - * - * @param[out] dst - * Pointer to output string. - * @param[in] dst_len - * Length of output string. - * @param[in] value - * 64-bit unsigned integer to format. - * @param[in] decimals - * Number of digits after decimal separator. - * - * @return true if success, false otherwise. - * - */ -bool format_fpu64(char *dst, size_t dst_len, const uint64_t value, uint8_t decimals); - -/** - * Format byte buffer to uppercase hexadecimal string. - * - * @param[in] in - * Pointer to input byte buffer. - * @param[in] in_len - * Length of input byte buffer. - * @param[out] out - * Pointer to output string. - * @param[in] out_len - * Length of output string. - * - * @return number of bytes written if success, -1 otherwise. - * - */ -int format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len); diff --git a/src/common/macros.h b/src/common/macros.h deleted file mode 100644 index 13f75a3..0000000 --- a/src/common/macros.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -/** - * Macro for the size of a specific structure field. - */ -#define MEMBER_SIZE(type, member) (sizeof(((type *) 0)->member)) diff --git a/src/common/read.c b/src/common/read.c deleted file mode 100644 index c8ee851..0000000 --- a/src/common/read.c +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // uint*_t -#include // size_t - -uint16_t read_u16_be(const uint8_t *ptr, size_t offset) { - return (uint16_t) ptr[offset + 0] << 8 | // - (uint16_t) ptr[offset + 1] << 0; -} - -uint32_t read_u32_be(const uint8_t *ptr, size_t offset) { - return (uint32_t) ptr[offset + 0] << 24 | // - (uint32_t) ptr[offset + 1] << 16 | // - (uint32_t) ptr[offset + 2] << 8 | // - (uint32_t) ptr[offset + 3] << 0; -} - -uint64_t read_u64_be(const uint8_t *ptr, size_t offset) { - return (uint64_t) ptr[offset + 0] << 56 | // - (uint64_t) ptr[offset + 1] << 48 | // - (uint64_t) ptr[offset + 2] << 40 | // - (uint64_t) ptr[offset + 3] << 32 | // - (uint64_t) ptr[offset + 4] << 24 | // - (uint64_t) ptr[offset + 5] << 16 | // - (uint64_t) ptr[offset + 6] << 8 | // - (uint64_t) ptr[offset + 7] << 0; -} - -uint16_t read_u16_le(const uint8_t *ptr, size_t offset) { - return (uint16_t) ptr[offset + 0] << 0 | // - (uint16_t) ptr[offset + 1] << 8; -} - -uint32_t read_u32_le(const uint8_t *ptr, size_t offset) { - return (uint32_t) ptr[offset + 0] << 0 | // - (uint32_t) ptr[offset + 1] << 8 | // - (uint32_t) ptr[offset + 2] << 16 | // - (uint32_t) ptr[offset + 3] << 24; -} - -uint64_t read_u64_le(const uint8_t *ptr, size_t offset) { - return (uint64_t) ptr[offset + 0] << 0 | // - (uint64_t) ptr[offset + 1] << 8 | // - (uint64_t) ptr[offset + 2] << 16 | // - (uint64_t) ptr[offset + 3] << 24 | // - (uint64_t) ptr[offset + 4] << 32 | // - (uint64_t) ptr[offset + 5] << 40 | // - (uint64_t) ptr[offset + 6] << 48 | // - (uint64_t) ptr[offset + 7] << 56; -} diff --git a/src/common/read.h b/src/common/read.h deleted file mode 100644 index 61cfa8c..0000000 --- a/src/common/read.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include // uint*_t -#include // size_t - -/** - * Read 2 bytes as Big Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 2 bytes value read from buffer. - * - */ -uint16_t read_u16_be(const uint8_t *ptr, size_t offset); - -/** - * Read 4 bytes as Big Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 4 bytes value read from buffer. - * - */ -uint32_t read_u32_be(const uint8_t *ptr, size_t offset); - -/** - * Read 8 bytes as Big Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 8 bytes value read from buffer. - * - */ -uint64_t read_u64_be(const uint8_t *ptr, size_t offset); - -/** - * Read 2 bytes as Little Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 2 bytes value read from buffer. - * - */ -uint16_t read_u16_le(const uint8_t *ptr, size_t offset); - -/** - * Read 4 bytes as Little Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 4 bytes value read from buffer. - * - */ -uint32_t read_u32_le(const uint8_t *ptr, size_t offset); - -/** - * Read 8 bytes as Little Endian from byte buffer. - * - * @param[in] ptr - * Pointer to byte buffer. - * @param[in] offset - * Offset in the byte buffer. - * - * @return 8 bytes value read from buffer. - * - */ -uint64_t read_u64_le(const uint8_t *ptr, size_t offset); diff --git a/src/common/segwit_addr.h b/src/common/segwit_addr.h deleted file mode 100644 index 1a6f2c0..0000000 --- a/src/common/segwit_addr.h +++ /dev/null @@ -1,115 +0,0 @@ -// clang-format off - -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef _SEGWIT_ADDR_H_ -#define _SEGWIT_ADDR_H_ 1 - -#include - - -/** Encode a SegWit address - * - * Out: output: Pointer to a buffer of size 73 + strlen(hrp) that will be - * updated to contain the null-terminated address. - * In: hrp: Pointer to the null-terminated human readable part to use - * (chain/network specific). - * ver: Version of the witness program (between 0 and 16 inclusive). - * prog: Data bytes for the witness program (between 2 and 40 bytes). - * prog_len: Number of data bytes in prog. - * Returns 1 if successful. - */ -int segwit_addr_encode( - char *output, - const char *hrp, - int ver, - const uint8_t *prog, - size_t prog_len -); - -/** Decode a SegWit address - * - * Out: ver: Pointer to an int that will be updated to contain the witness - * program version (between 0 and 16 inclusive). - * prog: Pointer to a buffer of size 40 that will be updated to - * contain the witness program bytes. - * prog_len: Pointer to a size_t that will be updated to contain the length - * of bytes in prog. - * hrp: Pointer to the null-terminated human readable part that is - * expected (chain/network specific). - * addr: Pointer to the null-terminated address. - * Returns 1 if successful. - */ -int segwit_addr_decode( - int* ver, - uint8_t* prog, - size_t* prog_len, - const char* hrp, - const char* addr -); - -/** Supported encodings. */ -typedef enum { - BECH32_ENCODING_NONE, - BECH32_ENCODING_BECH32, - BECH32_ENCODING_BECH32M -} bech32_encoding; - -/** Encode a Bech32 or Bech32m string - * - * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that - * will be updated to contain the null-terminated Bech32 string. - * In: hrp : Pointer to the null-terminated human readable part. - * data : Pointer to an array of 5-bit values. - * data_len: Length of the data array. - * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). - * Returns 4 if successful. - */ -int bech32_encode( - char *output, - const char *hrp, - const uint8_t *data, - size_t data_len, - bech32_encoding enc -); - -/** Decode a Bech32 or Bech32m string - * - * Out: hrp: Pointer to a buffer of size strlen(input) - 6. Will be - * updated to contain the null-terminated human readable part. - * data: Pointer to a buffer of size strlen(input) - 8 that will - * hold the encoded 5-bit data values. - * data_len: Pointer to a size_t that will be updated to be the number - * of entries in data. - * In: input: Pointer to a null-terminated Bech32 string. - * Returns BECH32_ENCODING_BECH32{,M} to indicate decoding was successful - * with the specified encoding standard. BECH32_ENCODING_NONE is returned if - * decoding failed. - */ -bech32_encoding bech32_decode( - char *hrp, - uint8_t *data, - size_t *data_len, - const char *input -); - -#endif \ No newline at end of file diff --git a/src/common/varint.c b/src/common/varint.c deleted file mode 100644 index d04fbb2..0000000 --- a/src/common/varint.c +++ /dev/null @@ -1,101 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // uint*_t -#include // size_t -#include // bool - -#include "varint.h" -#include "write.h" -#include "read.h" - -uint8_t varint_size(uint64_t value) { - if (value <= 0xFC) { - return 1; - } - - if (value <= UINT16_MAX) { - return 3; - } - - if (value <= UINT32_MAX) { - return 5; - } - - return 9; // <= UINT64_MAX -} - -int varint_read(const uint8_t *in, size_t in_len, uint64_t *value) { - if (in_len < 1) { - return -1; - } - - uint8_t prefix = in[0]; - - if (prefix == 0xFD) { - if (in_len < 3) { - return -1; - } - *value = (uint64_t) read_u16_le(in, 1); - return 3; - } - - if (prefix == 0xFE) { - if (in_len < 5) { - return -1; - } - *value = (uint64_t) read_u32_le(in, 1); - return 5; - } - - if (prefix == 0xFF) { - if (in_len < 9) { - return -1; - } - *value = (uint64_t) read_u64_le(in, 1); - return 9; - } - - *value = (uint64_t) prefix; // prefix <= 0xFC - - return 1; -} - -int varint_write(uint8_t *out, size_t offset, uint64_t value) { - uint8_t varint_len = varint_size(value); - - switch (varint_len) { - case 1: - out[offset] = (uint8_t) value; - break; - case 3: - out[offset++] = 0xFD; - write_u16_le(out, offset, (uint16_t) value); - break; - case 5: - out[offset++] = 0xFE; - write_u32_le(out, offset, (uint32_t) value); - break; - case 9: - out[offset++] = 0xFF; - write_u64_le(out, offset, (uint64_t) value); - break; - default: - return -1; - } - - return varint_len; -} diff --git a/src/common/varint.h b/src/common/varint.h deleted file mode 100644 index 80aeb43..0000000 --- a/src/common/varint.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include // uint*_t -#include // size_t -#include // bool - -/** - * Size of value represented as Bitcoin-like varint. - * - * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer - * - * @param[in] value - * 64-bit unsigned integer to compute varint size. - * - * @return number of bytes to write value as varint (1, 3, 5 or 9 bytes). - * - */ -uint8_t varint_size(uint64_t value); - -/** - * Read Bitcoin-like varint from byte buffer. - * - * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer - * - * @param[in] in - * Pointer to input byte buffer. - * @param[in] in_len - * Length of the input byte buffer. - * @param[out] value - * Pointer to 64-bit unsigned integer to output varint. - * - * @return number of bytes read (1, 3, 5 or 9 bytes), -1 otherwise. - * - */ -int varint_read(const uint8_t *in, size_t in_len, uint64_t *value); - -/** - * Write Bitcoin-like varint to byte buffer. - * - * @see https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer - * - * @param[out] out - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 64-bit unsigned integer to write as varint. - * - * @return number of bytes written (1, 3, 5 or 9 bytes), -1 otherwise. - * - */ -int varint_write(uint8_t *out, size_t offset, uint64_t value); diff --git a/src/common/write.c b/src/common/write.c deleted file mode 100644 index 90ec141..0000000 --- a/src/common/write.c +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * (c) 2020 Ledger SAS. - * - * 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 // uint*_t -#include // size_t - -void write_u16_be(uint8_t *ptr, size_t offset, uint16_t value) { - ptr[offset + 0] = (uint8_t)(value >> 8); - ptr[offset + 1] = (uint8_t)(value >> 0); -} - -void write_u32_be(uint8_t *ptr, size_t offset, uint32_t value) { - ptr[offset + 0] = (uint8_t)(value >> 24); - ptr[offset + 1] = (uint8_t)(value >> 16); - ptr[offset + 2] = (uint8_t)(value >> 8); - ptr[offset + 3] = (uint8_t)(value >> 0); -} - -void write_u64_be(uint8_t *ptr, size_t offset, uint64_t value) { - ptr[offset + 0] = (uint8_t)(value >> 56); - ptr[offset + 1] = (uint8_t)(value >> 48); - ptr[offset + 2] = (uint8_t)(value >> 40); - ptr[offset + 3] = (uint8_t)(value >> 32); - ptr[offset + 4] = (uint8_t)(value >> 24); - ptr[offset + 5] = (uint8_t)(value >> 16); - ptr[offset + 6] = (uint8_t)(value >> 8); - ptr[offset + 7] = (uint8_t)(value >> 0); -} - -void write_u16_le(uint8_t *ptr, size_t offset, uint16_t value) { - ptr[offset + 0] = (uint8_t)(value >> 0); - ptr[offset + 1] = (uint8_t)(value >> 8); -} - -void write_u32_le(uint8_t *ptr, size_t offset, uint32_t value) { - ptr[offset + 0] = (uint8_t)(value >> 0); - ptr[offset + 1] = (uint8_t)(value >> 8); - ptr[offset + 2] = (uint8_t)(value >> 16); - ptr[offset + 3] = (uint8_t)(value >> 24); -} - -void write_u64_le(uint8_t *ptr, size_t offset, uint64_t value) { - ptr[offset + 0] = (uint8_t)(value >> 0); - ptr[offset + 1] = (uint8_t)(value >> 8); - ptr[offset + 2] = (uint8_t)(value >> 16); - ptr[offset + 3] = (uint8_t)(value >> 24); - ptr[offset + 4] = (uint8_t)(value >> 32); - ptr[offset + 5] = (uint8_t)(value >> 40); - ptr[offset + 6] = (uint8_t)(value >> 48); - ptr[offset + 7] = (uint8_t)(value >> 56); -} diff --git a/src/common/write.h b/src/common/write.h deleted file mode 100644 index 0418f5c..0000000 --- a/src/common/write.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include // uint*_t -#include // size_t - -/** - * Write 16-bit unsigned integer value as Big Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 16-bit unsigned integer to write in output byte buffer as Big Endian. - * - */ -void write_u16_be(const uint8_t *ptr, size_t offset, uint16_t value); - -/** - * Write 32-bit unsigned integer value as Big Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 32-bit unsigned integer to write in output byte buffer as Big Endian. - * - */ -void write_u32_be(uint8_t *ptr, size_t offset, uint32_t value); - -/** - * Write 64-bit unsigned integer value as Big Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 64-bit unsigned integer to write in output byte buffer as Big Endian. - * - */ -void write_u64_be(uint8_t *ptr, size_t offset, uint64_t value); - -/** - * Write 16-bit unsigned integer value as Little Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 16-bit unsigned integer to write in output byte buffer as Little Endian. - * - */ -void write_u16_le(uint8_t *ptr, size_t offset, uint16_t value); - -/** - * Write 32-bit unsigned integer value as Little Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 32-bit unsigned integer to write in output byte buffer as Little Endian. - * - */ -void write_u32_le(uint8_t *ptr, size_t offset, uint32_t value); - -/** - * Write 64-bit unsigned integer value as Little Endian. - * - * @param[out] ptr - * Pointer to output byte buffer. - * @param[in] offset - * Offset in the output byte buffer. - * @param[in] value - * 64-bit unsigned integer to write in output byte buffer as Little Endian. - * - */ -void write_u64_le(uint8_t *ptr, size_t offset, uint64_t value); diff --git a/src/crypto.c b/src/crypto.c index 0c92e3c..28e9e11 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -25,6 +25,7 @@ const uint32_t default_path[] = {44 | 0x80000000, 1237 | 0x80000000, 0 | 0x80000000, 0, 0}; + int crypto_derive_private_key(cx_ecfp_private_key_t *private_key, uint8_t chain_code[static 32], const uint32_t *bip32_path, @@ -58,15 +59,6 @@ int crypto_derive_private_key(cx_ecfp_private_key_t *private_key, return error; } -void crypto_init_public_key(cx_ecfp_private_key_t *private_key, - cx_ecfp_public_key_t *public_key, - uint8_t raw_public_key[static 64]) { - // generate corresponding public key - cx_ecfp_generate_pair(CX_CURVE_256K1, public_key, private_key, 1); - - memmove(raw_public_key, public_key->W + 1, 64); -} - int crypto_sign_event(void) { cx_ecfp_private_key_t private_key = {0}; uint8_t chain_code[32] = {0}; diff --git a/src/crypto.h b/src/crypto.h index 6ecd9b1..148f950 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -6,52 +6,10 @@ #include "os.h" #include "cx.h" -/** - * Derive private key given BIP32 path. - * - * @param[out] private_key - * Pointer to private key. - * @param[out] chain_code - * Pointer to 32 bytes array for chain code. - * @param[in] bip32_path - * Pointer to buffer with BIP32 path. - * @param[in] bip32_path_len - * Number of path in BIP32 path. - * - * @return 0 on success, error number otherwise. - * - */ + +int crypto_sign_event(void); + int crypto_derive_private_key(cx_ecfp_private_key_t *private_key, uint8_t chain_code[static 32], const uint32_t *bip32_path, uint8_t bip32_path_len); - -/** - * Initialize public key given private key. - * - * @param[in] private_key - * Pointer to private key. - * @param[out] public_key - * Pointer to public key. - * @param[out] raw_public_key - * Pointer to raw public key. - * - * @throw INVALID_PARAMETER - * - */ -void crypto_init_public_key(cx_ecfp_private_key_t *private_key, - cx_ecfp_public_key_t *public_key, - uint8_t raw_public_key[static 64]); - -/** - * Sign message hash in global context. - * - * @see G_context.bip32_path, G_context.tx_info.m_hash, - * G_context.tx_info.signature. - * - * @return 0 on success, error number otherwise. - * - */ -int crypto_sign_message(void); - -int crypto_sign_event(void); diff --git a/src/handler/encrypt_data.c b/src/handler/encrypt_data.c index cd48862..49f46e3 100644 --- a/src/handler/encrypt_data.c +++ b/src/handler/encrypt_data.c @@ -26,10 +26,7 @@ #include "encrypt_data.h" #include "../globals.h" #include "../types.h" -#include "../io.h" #include "../sw.h" -#include "../crypto.h" -#include "../common/buffer.h" #include "../ui/display.h" #include "../ui/action/validate.h" #include "../helper/send_response.h" diff --git a/src/handler/encrypt_data.h b/src/handler/encrypt_data.h index c8bc660..15e9768 100644 --- a/src/handler/encrypt_data.h +++ b/src/handler/encrypt_data.h @@ -5,7 +5,7 @@ #include // uint*_t #include "../types.h" -#include "../common/buffer.h" +#include "buffer.h" int handler_encrypt(buffer_t *cdata, uint8_t chunk, bool more); diff --git a/src/handler/get_app_name.c b/src/handler/get_app_name.c index 50276a1..1eabb8b 100644 --- a/src/handler/get_app_name.c +++ b/src/handler/get_app_name.c @@ -17,18 +17,17 @@ #include // uint*_t +#include "io.h" +#include "buffer.h" + #include "get_app_name.h" #include "../constants.h" #include "../globals.h" -#include "../io.h" #include "../sw.h" #include "../types.h" -#include "common/buffer.h" int handler_get_app_name() { _Static_assert(APPNAME_LEN < MAX_APPNAME_LEN, "APPNAME must be at most 64 characters!"); - buffer_t rdata = {.ptr = (uint8_t *) PIC(APPNAME), .size = APPNAME_LEN, .offset = 0}; - - return io_send_response(&rdata, SW_OK); + return io_send_response_pointer(PIC(APPNAME), APPNAME_LEN, SW_OK); } diff --git a/src/handler/get_public_key.c b/src/handler/get_public_key.c index cee080e..f923574 100644 --- a/src/handler/get_public_key.c +++ b/src/handler/get_public_key.c @@ -22,14 +22,14 @@ #include "os.h" #include "cx.h" +#include "io.h" +#include "buffer.h" +#include "crypto_helpers.h" #include "get_public_key.h" #include "../globals.h" #include "../types.h" -#include "../io.h" #include "../sw.h" -#include "../crypto.h" -#include "../common/buffer.h" #include "../ui/display.h" #include "../helper/send_response.h" @@ -40,26 +40,24 @@ int handler_get_public_key(bool display) { G_context.req_type = CONFIRM_ADDRESS; G_context.state = STATE_NONE; - cx_ecfp_private_key_t private_key = {0}; - cx_ecfp_public_key_t public_key = {0}; uint8_t chain_code[32]; + uint8_t public_key[65]; - // derive private key according to BIP32 path - int error = crypto_derive_private_key(&private_key, - chain_code, - pubdefault_path, - sizeof(pubdefault_path) / sizeof(pubdefault_path[0])); - if (error != 0) { + cx_err_t error = bip32_derive_get_pubkey_256(CX_CURVE_256K1, + pubdefault_path, + sizeof(pubdefault_path) / sizeof(pubdefault_path[0]), + public_key, + chain_code, + CX_SHA512); + + memmove(G_context.pk_info.raw_public_key, public_key + 1, 64); + if (error != CX_OK) { return io_send_sw(error); } - // generate corresponding public key - crypto_init_public_key(&private_key, &public_key, G_context.pk_info.raw_public_key); - // reset private key - explicit_bzero(&private_key, sizeof(private_key)); if (display) { return ui_display_address(); } return helper_send_response_pubkey(); -} \ No newline at end of file +} diff --git a/src/handler/get_public_key.h b/src/handler/get_public_key.h index b0604a3..764eea9 100644 --- a/src/handler/get_public_key.h +++ b/src/handler/get_public_key.h @@ -4,10 +4,8 @@ #include // bool #include // uint*_t +#include "buffer.h" + #include "../types.h" -#include "../common/buffer.h" -/** - * Handler for GET_PUBLIC_KEY command. - */ -int handler_get_public_key(bool display); \ No newline at end of file +int handler_get_public_key(bool display); diff --git a/src/handler/get_response.c b/src/handler/get_response.c index 95cffe3..15f7ee4 100644 --- a/src/handler/get_response.c +++ b/src/handler/get_response.c @@ -26,9 +26,7 @@ #include "encrypt_data.h" #include "../globals.h" #include "../types.h" -#include "../io.h" #include "../sw.h" -#include "../common/buffer.h" #include "../helper/send_response.h" int handler_get_response() { diff --git a/src/handler/get_version.c b/src/handler/get_version.c index e32a5e2..bf37ec1 100644 --- a/src/handler/get_version.c +++ b/src/handler/get_version.c @@ -19,13 +19,14 @@ #include // UINT8_MAX #include // _Static_assert +#include "io.h" +#include "buffer.h" + #include "get_version.h" #include "../globals.h" #include "../constants.h" -#include "../io.h" #include "../sw.h" #include "../types.h" -#include "common/buffer.h" int handler_get_version() { _Static_assert(APPVERSION_LEN == 3, "Length of (MAJOR || MINOR || PATCH) must be 3!"); @@ -36,11 +37,10 @@ int handler_get_version() { _Static_assert(PATCH_VERSION >= 0 && PATCH_VERSION <= UINT8_MAX, "PATCH version must be between 0 and 255!"); - return io_send_response( - &(const buffer_t){.ptr = (uint8_t[APPVERSION_LEN]){(uint8_t) MAJOR_VERSION, - (uint8_t) MINOR_VERSION, - (uint8_t) PATCH_VERSION}, - .size = APPVERSION_LEN, - .offset = 0}, + return io_send_response_pointer( + (const uint8_t *) &(uint8_t[APPVERSION_LEN]){(uint8_t) MAJOR_VERSION, + (uint8_t) MINOR_VERSION, + (uint8_t) PATCH_VERSION}, + APPVERSION_LEN, SW_OK); } diff --git a/src/handler/sign_event.c b/src/handler/sign_event.c index dc38b91..47cf040 100644 --- a/src/handler/sign_event.c +++ b/src/handler/sign_event.c @@ -26,10 +26,7 @@ #include "get_public_key.h" #include "../globals.h" #include "../types.h" -#include "../io.h" #include "../sw.h" -#include "../crypto.h" -#include "../common/buffer.h" #include "../ui/display.h" #include "../ui/action/validate.h" diff --git a/src/handler/sign_event.h b/src/handler/sign_event.h index 1c311dc..033921a 100644 --- a/src/handler/sign_event.h +++ b/src/handler/sign_event.h @@ -4,7 +4,8 @@ #include // bool #include // uint*_t +#include "buffer.h" + #include "../types.h" -#include "../common/buffer.h" int handler_sign_event(buffer_t *cdata, bool display); diff --git a/src/common/segwit_addr.c b/src/helper/bech32.c similarity index 62% rename from src/common/segwit_addr.c rename to src/helper/bech32.c index 0d3e8c1..f989a75 100644 --- a/src/common/segwit_addr.c +++ b/src/helper/bech32.c @@ -1,31 +1,4 @@ -// clang-format off - -/* Copyright (c) 2017, 2021 Pieter Wuille - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include -#include -#include - -#include "segwit_addr.h" +#include "bech32.h" static uint32_t bech32_polymod_step(uint32_t pre) { uint8_t b = pre >> 25; @@ -40,7 +13,6 @@ static uint32_t bech32_polymod_step(uint32_t pre) { static uint32_t bech32_final_constant(bech32_encoding enc) { if (enc == BECH32_ENCODING_BECH32) return 1; if (enc == BECH32_ENCODING_BECH32M) return 0x2bc830a3; - assert(0); return 0; // suppress compiler warning on missing return value } @@ -156,7 +128,7 @@ bech32_encoding bech32_decode(char* hrp, uint8_t *data, size_t *data_len, const } } -static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { +int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { uint32_t val = 0; int bits = 0; uint32_t maxv = (((uint32_t)1) << outbits) - 1; @@ -177,36 +149,3 @@ static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t } return 1; } - -int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { - uint8_t data[65]; - size_t datalen = 0; - bech32_encoding enc = BECH32_ENCODING_BECH32; - if (witver > 16) return 0; - if (witver == 0 && witprog_len != 20 && witprog_len != 32) return 0; - if (witprog_len < 2 || witprog_len > 40) return 0; - if (witver > 0) enc = BECH32_ENCODING_BECH32M; - data[0] = witver; - convert_bits(data + 1, &datalen, 5, witprog, witprog_len, 8, 1); - ++datalen; - return bech32_encode(output, hrp, data, datalen, enc); -} - -int segwit_addr_decode(int* witver, uint8_t* witdata, size_t* witdata_len, const char* hrp, const char* addr) { - uint8_t data[84]; - char hrp_actual[84]; - size_t data_len; - bech32_encoding enc = bech32_decode(hrp_actual, data, &data_len, addr); - if (enc == BECH32_ENCODING_NONE) return 0; - if (data_len == 0 || data_len > 65) return 0; - if (strncmp(hrp, hrp_actual, 84) != 0) return 0; - if (data[0] > 16) return 0; - if (data[0] == 0 && enc != BECH32_ENCODING_BECH32) return 0; - if (data[0] > 0 && enc != BECH32_ENCODING_BECH32M) return 0; - *witdata_len = 0; - if (!convert_bits(witdata, witdata_len, 8, data + 1, data_len - 1, 5, 0)) return 0; - if (*witdata_len < 2 || *witdata_len > 40) return 0; - if (data[0] == 0 && *witdata_len != 20 && *witdata_len != 32) return 0; - *witver = data[0]; - return 1; -} \ No newline at end of file diff --git a/src/helper/bech32.h b/src/helper/bech32.h new file mode 100644 index 0000000..6ef97bd --- /dev/null +++ b/src/helper/bech32.h @@ -0,0 +1,32 @@ +#pragma once + +#include // uint*_t +#include // size_t +#include // bool + +/** Supported encodings. */ +typedef enum { + BECH32_ENCODING_NONE, + BECH32_ENCODING_BECH32, + BECH32_ENCODING_BECH32M +} bech32_encoding; + +/** Encode a Bech32 or Bech32m string + * + * Out: output: Pointer to a buffer of size strlen(hrp) + data_len + 8 that + * will be updated to contain the null-terminated Bech32 string. + * In: hrp : Pointer to the null-terminated human readable part. + * data : Pointer to an array of 5-bit values. + * data_len: Length of the data array. + * enc: Which encoding to use (BECH32_ENCODING_BECH32{,M}). + * Returns 4 if successful. + */ +int bech32_encode( + char *output, + const char *hrp, + const uint8_t *data, + size_t data_len, + bech32_encoding enc +); + +int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad); diff --git a/src/helper/send_reponse.c b/src/helper/send_reponse.c index db67e5a..80f62d3 100644 --- a/src/helper/send_reponse.c +++ b/src/helper/send_reponse.c @@ -23,7 +23,6 @@ #include "../constants.h" #include "../globals.h" #include "../sw.h" -#include "common/buffer.h" int helper_send_response_pubkey() { uint8_t resp[1 + 1 + PUBKEY_LEN] = {0}; @@ -34,7 +33,7 @@ int helper_send_response_pubkey() { memmove(resp + offset, G_context.pk_info.raw_public_key, PUBKEY_LEN); offset += PUBKEY_LEN; - return io_send_response(&(const buffer_t){.ptr = resp, .size = offset, .offset = 0}, SW_OK); + return io_send_response_buffer(&(const buffer_t){.ptr = resp, .size = offset, .offset = 0}, SW_OK); } int helper_send_response_event() { @@ -45,7 +44,7 @@ int helper_send_response_event() { memmove(resp + offset, G_context.event_info.signature, G_context.event_info.signature_len); offset += G_context.event_info.signature_len; - return io_send_response(&(const buffer_t){.ptr = resp, .size = offset, .offset = 0}, SW_OK); + return io_send_response_buffer(&(const buffer_t){.ptr = resp, .size = offset, .offset = 0}, SW_OK); } int io_send_framed_response(const buffer_t *rdata) { @@ -53,7 +52,7 @@ int io_send_framed_response(const buffer_t *rdata) { return -1; // io_send_framed_response_continue must be used. if (rdata == NULL || rdata->size - rdata->offset <= IO_APDU_BUFFER_SIZE - 2) - return io_send_response(rdata, SW_OK); + return io_send_response_buffer(rdata, SW_OK); G_context.state = STATE_IN_TRANSFER; G_context.in_transfer = @@ -64,7 +63,7 @@ int io_send_framed_response(const buffer_t *rdata) { .offset = G_context.in_transfer.offset}; G_context.in_transfer.offset += IO_APDU_BUFFER_SIZE - 2; - return io_send_response(&frame, SW_OK_MORE_DATA_AVAILABLE); + return io_send_response_buffer(&frame, SW_OK_MORE_DATA_AVAILABLE); } int io_send_framed_response_continue() { @@ -72,7 +71,7 @@ int io_send_framed_response_continue() { return -1; // io_send_framed_response must be used before. if (G_context.in_transfer.size - G_context.in_transfer.offset <= IO_APDU_BUFFER_SIZE - 2) { - return io_send_response(&G_context.in_transfer, SW_OK); + return io_send_response_buffer(&G_context.in_transfer, SW_OK); } buffer_t frame = (const buffer_t){.ptr = G_context.in_transfer.ptr, @@ -81,5 +80,5 @@ int io_send_framed_response_continue() { G_context.in_transfer.offset += IO_APDU_BUFFER_SIZE - 2; - return io_send_response(&frame, SW_OK_MORE_DATA_AVAILABLE); + return io_send_response_buffer(&frame, SW_OK_MORE_DATA_AVAILABLE); } \ No newline at end of file diff --git a/src/helper/send_response.h b/src/helper/send_response.h index 9f62423..9eba11b 100644 --- a/src/helper/send_response.h +++ b/src/helper/send_response.h @@ -1,8 +1,8 @@ #pragma once #include "os.h" +#include "io.h" -#include "../common/macros.h" #include "buffer.h" /** diff --git a/src/io.c b/src/io.c deleted file mode 100755 index f7cb4c4..0000000 --- a/src/io.c +++ /dev/null @@ -1,184 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (c) 2021 Ledger SAS. - * - * 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 - -#include "os.h" -#include "ux.h" - -#ifdef HAVE_NBGL -#include "nbgl_touch.h" -#include "nbgl_page.h" -#endif // HAVE_NBGL - -#include "io.h" -#include "globals.h" -#include "sw.h" -#include "common/buffer.h" -#include "common/write.h" - -#ifdef HAVE_BAGL -void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default(element); -} -#endif // HAVE_BAGL - -uint8_t io_event(uint8_t channel) { - (void) channel; - - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: -#ifdef HAVE_BAGL - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); -#endif // HAVE_BAGL - break; - case SEPROXYHAL_TAG_STATUS_EVENT: - if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && // - !(U4BE(G_io_seproxyhal_spi_buffer, 3) & // - SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) { - THROW(EXCEPTION_IO_RESET); - } - __attribute__((fallthrough)); - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#ifdef HAVE_BAGL - UX_DISPLAYED_EVENT({}); -#endif // HAVE_BAGL -#ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif // HAVE_NBGL - break; -#ifdef HAVE_NBGL - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif // HAVE_NBGL - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - break; - default: - UX_DEFAULT_EVENT(); - break; - } - - if (!io_seproxyhal_spi_is_status_sent()) { - io_seproxyhal_general_status(); - } - - return 1; -} - -uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len) { - switch (channel & ~(IO_FLAGS)) { - case CHANNEL_KEYBOARD: - break; - case CHANNEL_SPI: - if (tx_len) { - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - if (channel & IO_RESET_AFTER_REPLIED) { - halt(); - } - - return 0; - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); - } - default: - THROW(INVALID_PARAMETER); - } - - return 0; -} - -/** - * Variable containing the length of the APDU response to send back. - */ -static uint32_t G_output_len = 0; - -/** - * IO state (READY, RECEIVING, WAITING). - */ -static io_state_e G_io_state = READY; - -void io_init() { - // Reset length of APDU response - G_output_len = 0; - G_io_state = READY; -} - -int io_recv_command() { - int ret = -1; - - switch (G_io_state) { - case READY: - G_io_state = RECEIVED; - ret = io_exchange(CHANNEL_APDU, G_output_len); - break; - case RECEIVED: - G_io_state = WAITING; - ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, G_output_len); - G_io_state = RECEIVED; - break; - case WAITING: - G_io_state = READY; - ret = -1; - break; - } - - return ret; -} - -int io_send_response(const buffer_t *rdata, uint16_t sw) { - int ret = -1; - - if (rdata != NULL) { - if (rdata->size - rdata->offset > IO_APDU_BUFFER_SIZE - 2 || // - !buffer_copy(rdata, G_io_apdu_buffer, sizeof(G_io_apdu_buffer))) { - return io_send_sw(SW_WRONG_RESPONSE_LENGTH); - } - G_output_len = rdata->size - rdata->offset; - PRINTF("<= SW=%04X | RData=%.*H\n", sw, rdata->size, rdata->ptr); - } else { - G_output_len = 0; - PRINTF("<= SW=%04X | RData=\n", sw); - } - - write_u16_be(G_io_apdu_buffer, G_output_len, sw); - G_output_len += 2; - - switch (G_io_state) { - case READY: - ret = -1; - break; - case RECEIVED: - G_io_state = READY; - ret = 0; - break; - case WAITING: - ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len); - G_output_len = 0; - G_io_state = READY; - break; - } - - return ret; -} - -int io_send_sw(uint16_t sw) { - return io_send_response(NULL, sw); -} diff --git a/src/io.h b/src/io.h deleted file mode 100644 index 6f7be0c..0000000 --- a/src/io.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -#include "ux.h" -#include "os_io_seproxyhal.h" - -#include "types.h" -#include "common/buffer.h" - -#ifdef HAVE_BAGL -void io_seproxyhal_display(const bagl_element_t *element); -#endif // HAVE_BAGL - -/** - * IO callback called when an interrupt based channel has received - * data to be processed. - * - * @return 1 if success, 0 otherwise. - * - */ -uint8_t io_event(uint8_t channel); - -uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len); - -/** - * Initialize the APDU I/O state. - * - * This function must be called before calling any other I/O function. - */ -void io_init(void); - -/** - * Receive APDU command in G_io_apdu_buffer. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_recv_command(void); - -/** - * Send APDU response (response data + status word) by filling - * G_io_apdu_buffer. - * - * @param[in] rdata - * Buffer with APDU response data. - * @param[in] sw - * Status word of APDU response. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_send_response(const buffer_t *rdata, uint16_t sw); - -/** - * Send APDU response (only status word) by filling - * G_io_apdu_buffer. - * - * @param[in] sw - * Status word of APDU response. - * - * @return zero or positive integer if success, -1 otherwise. - * - */ -int io_send_sw(uint16_t sw); diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 42df33d..0000000 --- a/src/main.c +++ /dev/null @@ -1,160 +0,0 @@ -/***************************************************************************** - * Ledger App Boilerplate. - * (c) 2020 Ledger SAS. - * - * 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 // uint*_t -#include // memset, explicit_bzero - -#include "os.h" -#include "ux.h" - -#include "types.h" -#include "globals.h" -#include "io.h" -#include "sw.h" -#include "ui/menu.h" -#include "apdu/parser.h" -#include "apdu/dispatcher.h" - -uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; -global_ctx_t G_context; - -/** - * Handle APDU command received and send back APDU response using handlers. - */ -void app_main() { - // Length of APDU command received in G_io_apdu_buffer - int input_len = 0; - // Structured APDU command - command_t cmd; - - io_init(); - - // Reset context - explicit_bzero(&G_context, sizeof(G_context)); - - for (;;) { - BEGIN_TRY { - TRY { - // Reset structured APDU command - memset(&cmd, 0, sizeof(cmd)); - - // Receive command bytes in G_io_apdu_buffer - if ((input_len = io_recv_command()) < 0) { - CLOSE_TRY; - return; - } - - // Parse APDU command from G_io_apdu_buffer - if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) { - PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer); - io_send_sw(SW_WRONG_DATA_LENGTH); - CLOSE_TRY; - continue; - } - - PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n", - cmd.cla, - cmd.ins, - cmd.p1, - cmd.p2, - cmd.lc, - cmd.lc, - cmd.data); - - // Dispatch structured APDU command to handler - if (apdu_dispatcher(&cmd) < 0) { - CLOSE_TRY; - return; - } - } - CATCH(EXCEPTION_IO_RESET) { - THROW(EXCEPTION_IO_RESET); - } - CATCH_OTHER(e) { - io_send_sw(e); - } - FINALLY { - } - END_TRY; - } - } -} - -/** - * Exit the application and go back to the dashboard. - */ -void app_exit() { - BEGIN_TRY_L(exit) { - TRY_L(exit) { - os_sched_exit(-1); - } - FINALLY_L(exit) { - } - } - END_TRY_L(exit); -} - -/** - * Main loop to setup USB, Bluetooth, UI and launch app_main(). - */ -__attribute__((section(".boot"))) int main() { - __asm volatile("cpsie i"); - - os_boot(); - - for (;;) { - // Initialize the UX system - UX_INIT(); - - BEGIN_TRY { - TRY { - io_seproxyhal_init(); - -#ifdef HAVE_BLE - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // HAVE_BLE - USB_power(0); - USB_power(1); - - ui_menu_main(); - -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, NULL); -#endif // HAVE_BLE - app_main(); - } - CATCH(EXCEPTION_IO_RESET) { - CLOSE_TRY; - continue; - } - CATCH_ALL { - CLOSE_TRY; - break; - } - FINALLY { - } - } - END_TRY; - } - - app_exit(); - - return 0; -} diff --git a/src/offsets.h b/src/offsets.h deleted file mode 100644 index 3db4bc1..0000000 --- a/src/offsets.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -/** - * Offset of instruction class. - */ -#define OFFSET_CLA 0 -/** - * Offset of instruction code. - */ -#define OFFSET_INS 1 -/** - * Offset of instruction parameter 1. - */ -#define OFFSET_P1 2 -/** - * Offset of instruction parameter 2. - */ -#define OFFSET_P2 3 -/** - * Offset of command data length. - */ -#define OFFSET_LC 4 -/** - * Offset of command data. - */ -#define OFFSET_CDATA 5 diff --git a/src/types.h b/src/types.h index 36d43c6..c66498a 100644 --- a/src/types.h +++ b/src/types.h @@ -3,19 +3,10 @@ #include // size_t #include // uint*_t +#include "buffer.h" + #include "constants.h" #include "transaction/types.h" -#include "common/bip32.h" -#include "common/buffer.h" - -/** - * Enumeration for the status of IO. - */ -typedef enum { - READY, /// ready for new event - RECEIVED, /// data received - WAITING /// waiting -} io_state_e; /** * Enumeration with expected INS of APDU commands. @@ -29,19 +20,6 @@ typedef enum { DECRYPT_DATA = 0x09, GET_RESPONSE = 0xC0 } command_e; - -/** - * Structure with fields of APDU command. - */ -typedef struct { - uint8_t cla; /// Instruction class - command_e ins; /// Instruction code - uint8_t p1; /// Instruction parameter 1 - uint8_t p2; /// Instruction parameter 2 - uint8_t lc; /// Length of command data - uint8_t *data; /// Command data -} command_t; - /** * Enumeration with parsing state. */ diff --git a/src/ui/action/validate.c b/src/ui/action/validate.c index e18215c..287d71b 100644 --- a/src/ui/action/validate.c +++ b/src/ui/action/validate.c @@ -20,7 +20,6 @@ #include "validate.h" #include "../menu.h" #include "../../sw.h" -#include "../../crypto.h" #include "../../globals.h" #include "../../helper/send_response.h" diff --git a/src/ui/action/validate.h b/src/ui/action/validate.h index dcce2e4..6356a63 100644 --- a/src/ui/action/validate.h +++ b/src/ui/action/validate.h @@ -2,5 +2,7 @@ #include // bool +#include "../../crypto.h" + void validate_pubkey(bool choice); int validate_event(bool choice); diff --git a/src/ui/display_bagl.c b/src/ui/bagl_display.c similarity index 94% rename from src/ui/display_bagl.c rename to src/ui/bagl_display.c index 07d8849..3e09080 100644 --- a/src/ui/display_bagl.c +++ b/src/ui/bagl_display.c @@ -26,17 +26,17 @@ #include "os.h" #include "ux.h" #include "glyphs.h" +#include "io.h" +#include "bip32.h" +#include "format.h" #include "display.h" #include "constants.h" #include "../globals.h" -#include "../io.h" #include "../sw.h" #include "../address.h" #include "action/validate.h" #include "../transaction/types.h" -#include "../common/bip32.h" -#include "../common/format.h" #include "../menu.h" static action_validate_cb g_validate_callback; @@ -81,12 +81,11 @@ UX_STEP_CB(ux_display_reject_step, "Reject", }); -// FLOW to display address and BIP32 path: +// FLOW to display address: // #1 screen: eye icon + "Confirm Address" -// #2 screen: display BIP32 Path -// #3 screen: display address -// #4 screen: approve button -// #5 screen: reject button +// #2 screen: display address +// #3 screen: approve button +// #4 screen: reject button UX_FLOW(ux_display_pubkey_flow, &ux_display_confirm_addr_step, &ux_display_address_step, diff --git a/src/ui/display.h b/src/ui/display.h index dc424ca..a4f55ff 100644 --- a/src/ui/display.h +++ b/src/ui/display.h @@ -7,6 +7,6 @@ */ typedef void (*action_validate_cb)(bool); -int ui_display_address(void); +int ui_display_address(void); int ui_display_event(void); diff --git a/src/ui/display_nbgl.c b/src/ui/display_nbgl.c index cdd2453..5f44fdb 100644 --- a/src/ui/display_nbgl.c +++ b/src/ui/display_nbgl.c @@ -120,7 +120,7 @@ static void review_choice_event_hash(bool confirm) { if (confirm) { // display a status page and go back to main validate_event(true); - nbgl_useCaseStatus("TRANSACTION\nSIGNED", true, ui_menu_main); + nbgl_useCaseStatus("EVENT\nSIGNED", true, ui_menu_main); } else { ask_transaction_rejection_confirmation(); } diff --git a/src/ui/menu_bagl.c b/src/ui/menu_bagl.c index d927a4f..9482742 100644 --- a/src/ui/menu_bagl.c +++ b/src/ui/menu_bagl.c @@ -24,7 +24,7 @@ #include "../globals.h" #include "menu.h" -UX_STEP_NOCB(ux_menu_ready_step, pnn, {&C_boilerplate_logo, "Ledgstr", "is ready"}); +UX_STEP_NOCB(ux_menu_ready_step, pnn, {&C_app_boilerplate_16px, "Ledgstr", "is ready"}); UX_STEP_NOCB(ux_menu_version_step, bn, {"Version", APPVERSION}); UX_STEP_CB(ux_menu_about_step, pb, ui_menu_about(), {&C_icon_certificate, "About"}); UX_STEP_VALID(ux_menu_exit_step, pb, os_sched_exit(-1), {&C_icon_dashboard_x, "Quit"}); @@ -49,7 +49,7 @@ void ui_menu_main() { ux_flow_init(0, ux_menu_main_flow, NULL); } -UX_STEP_NOCB(ux_menu_info_step, bn, {"Ledgstr App", "(c) 2020 Ledger"}); +UX_STEP_NOCB(ux_menu_info_step, bn, {"Ledgstr App", "vbouzon"}); UX_STEP_CB(ux_menu_back_step, pb, ui_menu_main(), {&C_icon_back, "Back"}); // FLOW for the about submenu: diff --git a/src/ui/menu_nbgl.c b/src/ui/menu_nbgl.c index 834da52..a783975 100644 --- a/src/ui/menu_nbgl.c +++ b/src/ui/menu_nbgl.c @@ -31,13 +31,21 @@ void app_quit(void) { } void ui_menu_main(void) { - nbgl_useCaseHome(APPNAME, &C_boilerplate_logo, NULL, false, ui_menu_about, app_quit); +#define SETTINGS_BUTTON_DISABLED (false) + nbgl_useCasePlugInHome("Ledgstr plugin", + "Nostr", + &C_app_boilerplate_64px, + NULL, + NULL, + SETTINGS_BUTTON_DISABLED, + ui_menu_about, + app_quit); } // 'About' menu static const char* const INFO_TYPES[] = {"Version", "Developer"}; -static const char* const INFO_CONTENTS[] = {APPVERSION, "Ledger"}; +static const char* const INFO_CONTENTS[] = {APPVERSION, "vbouzon"}; static bool nav_callback(uint8_t page, nbgl_pageContent_t* content) { UNUSED(page); @@ -49,7 +57,16 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t* content) { } void ui_menu_about() { - nbgl_useCaseSettings(APPNAME, 0, 1, false, ui_menu_main, nav_callback, NULL); +#define TOTAL_PAGE_NB (1) +#define INIT_PAGE_INDEX (0) +#define DISABLE_SUB_SETTINGS (false) + nbgl_useCaseSettings(APPNAME, + INIT_PAGE_INDEX, + TOTAL_PAGE_NB, + DISABLE_SUB_SETTINGS, + ui_menu_main, + nav_callback, + NULL); } -#endif \ No newline at end of file +#endif diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py index 2e5246b..82ba665 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/boilerplate_command_sender.py @@ -174,30 +174,5 @@ def decrypt(self, publickey: bytes, iv: bytes, hash: bytes) -> bytes: arr += response.data return arr - @contextmanager - def sign_tx(self, path: str, transaction: bytes) -> Generator[None, None, None]: - self.backend.exchange(cla=CLA, - ins=InsType.SIGN_TX, - p1=P1.P1_START, - p2=P2.P2_MORE, - data=pack_derivation_path(path)) - messages = split_message(transaction, MAX_APDU_LEN) - idx: int = P1.P1_START + 1 - - for msg in messages[:-1]: - self.backend.exchange(cla=CLA, - ins=InsType.SIGN_TX, - p1=idx, - p2=P2.P2_MORE, - data=msg) - idx += 1 - - with self.backend.exchange_async(cla=CLA, - ins=InsType.SIGN_TX, - p1=idx, - p2=P2.P2_LAST, - data=messages[-1]) as response: - yield response - def get_async_response(self) -> Optional[RAPDU]: return self.backend.last_async_response diff --git a/tests/requirements.txt b/tests/requirements.txt index 1dc698b..4e3b2b2 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -5,4 +5,4 @@ Jinja2==3.1.2 Flask==2.1.2 ecdsa>=0.16.1,<0.17.0 pysha3>=1.0.0,<2.0.0 -funcy \ No newline at end of file +funcy diff --git a/tests/test_encrypt_decrypt.py b/tests/test_encrypt_decrypt.py deleted file mode 100644 index 3540a4c..0000000 --- a/tests/test_encrypt_decrypt.py +++ /dev/null @@ -1,30 +0,0 @@ -from application_client.boilerplate_transaction import Transaction -from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors -from application_client.boilerplate_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response, unpack_sign_event_response -from ragger.backend import RaisePolicy -from ragger.navigator import NavInsID -from utils import ROOT_SCREENSHOT_PATH, check_signature_validity - - -def test_encrypt_decrypt(firmware, backend, navigator, test_name): - - text = "H" - - client = BoilerplateCommandSender(backend) - response = client.encrypt(publickey=bytes.fromhex("e6c3340cf1385c48dd1967c28b70234e7528245b3c089a601b3e42176ef7d1604dbac701e7e5c8a37f26c3ff73e6feadf75017942a2f43c86ab6f4aaa41c8672"), - hash=text.encode()) - - # Cyphered data size (big endian) - # assert bytes(response[0:4]) == bytes.fromhex("20000000") - assert response[4] == 16 - - iv = bytes(response[5:21]) - cyphered_data = bytes(response[21:]) - - response = client.decrypt(publickey=bytes.fromhex("e6c3340cf1385c48dd1967c28b70234e7528245b3c089a601b3e42176ef7d1604dbac701e7e5c8a37f26c3ff73e6feadf75017942a2f43c86ab6f4aaa41c8672"), - iv=iv, - hash=cyphered_data) - - # assert bytes(response[0:4]) == bytes.fromhex("20000000") - uncyphered_data = bytes(response[4:]) - assert uncyphered_data.decode().strip('\x00') == text diff --git a/tests/test_error_cmd.py b/tests/test_error_cmd.py index 7f3983a..1c3f1a6 100644 --- a/tests/test_error_cmd.py +++ b/tests/test_error_cmd.py @@ -1,56 +1,57 @@ -from ragger.backend import RaisePolicy +import pytest + +from ragger.error import ExceptionRAPDU from application_client.boilerplate_command_sender import CLA, InsType, P1, P2, Errors # Ensure the app returns an error when a bad CLA is used def test_bad_cla(backend): - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - rapdu = backend.exchange(cla=CLA + 1, ins=InsType.GET_VERSION) - assert rapdu.status == Errors.SW_CLA_NOT_SUPPORTED + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA + 1, ins=InsType.GET_VERSION) + assert e.value.status == Errors.SW_CLA_NOT_SUPPORTED # Ensure the app returns an error when a bad INS is used def test_bad_ins(backend): - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - rapdu = backend.exchange(cla=CLA, ins=0xff) - assert rapdu.status == Errors.SW_INS_NOT_SUPPORTED + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=0xff) + assert e.value.status == Errors.SW_INS_NOT_SUPPORTED # Ensure the app returns an error when a bad P1 or P2 is used def test_wrong_p1p2(backend): - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - rapdu = backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START + 1, p2=P2.P2_LAST) - assert rapdu.status == Errors.SW_WRONG_P1P2 - rapdu = backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START, p2=P2.P2_MORE) - assert rapdu.status == Errors.SW_WRONG_P1P2 - rapdu = backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START + 1, p2=P2.P2_LAST) - assert rapdu.status == Errors.SW_WRONG_P1P2 - rapdu = backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_MORE) - assert rapdu.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START + 1, p2=P2.P2_LAST) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START, p2=P2.P2_MORE) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START + 1, p2=P2.P2_LAST) + assert e.value.status == Errors.SW_WRONG_P1P2 + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_MORE) + assert e.value.status == Errors.SW_WRONG_P1P2 # Ensure the app returns an error when a bad data length is used def test_wrong_data_length(backend): - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING # APDUs must be at least 5 bytes: CLA, INS, P1, P2, Lc. - rapdu = backend.exchange_raw(b"E0030000") - assert rapdu.status == Errors.SW_WRONG_DATA_LENGTH + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange_raw(b"E0030000") + assert e.value.status == Errors.SW_WRONG_DATA_LENGTH # APDUs advertises a too long length - rapdu = backend.exchange_raw(b"E003000005") - assert rapdu.status == Errors.SW_WRONG_DATA_LENGTH + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange_raw(b"E003000005") + assert e.value.status == Errors.SW_WRONG_DATA_LENGTH # Ensure there is no state confusion when trying wrong APDU sequences def test_invalid_state(backend): - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - rapdu = backend.exchange(cla=CLA, - ins=InsType.ENCRYPT, - p1=P1.P1_START + 1, # Try to continue a flow instead of start a new one - p2=P2.P2_MORE, - data=b"abcde") # data is not parsed in this case - assert rapdu.status == Errors.SW_BAD_STATE + with pytest.raises(ExceptionRAPDU) as e: + backend.exchange(cla=CLA, + ins=InsType.SIGN_TX, + p1=P1.P1_START + 1, # Try to continue a flow instead of start a new one + p2=P2.P2_MORE, + data=b"abcde") # data is not parsed in this case + assert e.value.status == Errors.SW_BAD_STATE diff --git a/tests/test_name_version.py b/tests/test_name_version.py index 51388da..1481951 100644 --- a/tests/test_name_version.py +++ b/tests/test_name_version.py @@ -12,4 +12,4 @@ def test_get_app_and_version(backend, backend_name): app_name, version = unpack_get_app_and_version_response(response.data) assert app_name == "Ledgstr" - assert version == "1.0.4" + assert version == "1.1.0" diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py index e68569b..71eb410 100644 --- a/tests/test_pubkey_cmd.py +++ b/tests/test_pubkey_cmd.py @@ -1,11 +1,14 @@ +import pytest + from application_client.boilerplate_command_sender import BoilerplateCommandSender, Errors from application_client.boilerplate_response_unpacker import unpack_get_public_key_response from ragger.bip import calculate_public_key_and_chaincode, CurveChoice -from ragger.backend import RaisePolicy +from ragger.error import ExceptionRAPDU from ragger.navigator import NavInsID, NavIns from utils import ROOT_SCREENSHOT_PATH + # In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode def test_get_public_key_no_confirm(backend): client = BoilerplateCommandSender(backend) @@ -16,10 +19,11 @@ def test_get_public_key_no_confirm(backend): assert public_key.hex() == ref_public_key + # # In this test we check that the GET_PUBLIC_KEY works in confirmation mode # def test_get_public_key_confirm_accepted(firmware, backend, navigator, test_name): # client = BoilerplateCommandSender(backend) -# path = "m/44'/0'/0'/0/0" +# path = "m/44'/1'/0'/0/0" # with client.get_public_key_with_confirmation(path=path): # if firmware.device.startswith("nano"): # navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, @@ -32,7 +36,6 @@ def test_get_public_key_no_confirm(backend): # NavInsID.USE_CASE_REVIEW_TAP, # NavIns(NavInsID.TOUCH, (200, 335)), # NavInsID.USE_CASE_ADDRESS_CONFIRMATION_EXIT_QR, -# NavInsID.USE_CASE_ADDRESS_CONFIRMATION_TAP, # NavInsID.USE_CASE_ADDRESS_CONFIRMATION_CONFIRM, # NavInsID.USE_CASE_STATUS_DISMISS # ] @@ -50,23 +53,19 @@ def test_get_public_key_no_confirm(backend): # # In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses # def test_get_public_key_confirm_refused(firmware, backend, navigator, test_name): # client = BoilerplateCommandSender(backend) -# path = "m/44'/0'/0'/0/0" +# path = "m/44'/1'/0'/0/0" # if firmware.device.startswith("nano"): -# with client.get_public_key_with_confirmation(path=path): -# # Disable raising when trying to unpack an error APDU -# backend.raise_policy = RaisePolicy.RAISE_NOTHING -# navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, -# [NavInsID.BOTH_CLICK], -# "Reject", -# ROOT_SCREENSHOT_PATH, -# test_name) - -# response = client.get_async_response() - +# with pytest.raises(ExceptionRAPDU) as e: +# with client.get_public_key_with_confirmation(path=path): +# navigator.navigate_until_text_and_compare(NavInsID.RIGHT_CLICK, +# [NavInsID.BOTH_CLICK], +# "Reject", +# ROOT_SCREENSHOT_PATH, +# test_name) # # Assert that we have received a refusal -# assert response.status == Errors.SW_DENY -# assert len(response.data) == 0 +# assert e.value.status == Errors.SW_DENY +# assert len(e.value.data) == 0 # else: # instructions_set = [ # [ @@ -80,13 +79,11 @@ def test_get_public_key_no_confirm(backend): # ] # ] # for i, instructions in enumerate(instructions_set): -# with client.get_public_key_with_confirmation(path=path): -# backend.raise_policy = RaisePolicy.RAISE_NOTHING -# navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, -# test_name + f"/part{i}", -# instructions) -# response = client.get_async_response() - +# with pytest.raises(ExceptionRAPDU) as e: +# with client.get_public_key_with_confirmation(path=path): +# navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, +# test_name + f"/part{i}", +# instructions) # # Assert that we have received a refusal -# assert response.status == Errors.SW_DENY -# assert len(response.data) == 0 +# assert e.value.status == Errors.SW_DENY +# assert len(e.value.data) == 0 diff --git a/tests/test_version_cmd.py b/tests/test_version_cmd.py index 8a34a5c..99966e3 100644 --- a/tests/test_version_cmd.py +++ b/tests/test_version_cmd.py @@ -2,13 +2,11 @@ from application_client.boilerplate_response_unpacker import unpack_get_version_response # Taken from the Makefile, to update every time the Makefile version is bumped -MAJOR = 1 +MAJOR = 2 MINOR = 0 -PATCH = 4 +PATCH = 0 # In this test we check the behavior of the device when asked to provide the app version - - def test_version(backend): # Use the app interface instead of raw interface client = BoilerplateCommandSender(backend) diff --git a/tests/utils.py b/tests/utils.py index 16c728e..cb52233 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -19,4 +19,5 @@ def check_signature_validity(public_key: bytes, signature: bytes, message: bytes ) return pk.verify(signature=signature, data=message, - hashfunc=None) + hashfunc=keccak_256, + sigdecode=sigdecode_der) diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 60f2fec..3aedc33 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -36,33 +36,38 @@ endif() add_compile_definitions(TEST) include_directories(../src) +include_directories($ENV{BOLOS_SDK}/lib_standard_app) -add_executable(test_base58 test_base58.c) -add_executable(test_bip32 test_bip32.c) -add_executable(test_buffer test_buffer.c) -add_executable(test_format test_format.c) -add_executable(test_write test_write.c) -add_executable(test_apdu_parser test_apdu_parser.c) +# add_executable(test_tx_parser test_tx_parser.c) +# add_executable(test_tx_utils test_tx_utils.c) -add_library(base58 SHARED ../src/common/base58.c) -add_library(bip32 SHARED ../src/common/bip32.c) -add_library(buffer SHARED ../src/common/buffer.c) -add_library(read SHARED ../src/common/read.c) -add_library(write SHARED ../src/common/write.c) -add_library(format SHARED ../src/common/format.c) -add_library(varint SHARED ../src/common/varint.c) -add_library(apdu_parser SHARED ../src/apdu/parser.c) +add_library(base58 SHARED $ENV{BOLOS_SDK}/lib_standard_app/base58.c) +add_library(bip32 SHARED $ENV{BOLOS_SDK}/lib_standard_app/bip32.c) +add_library(buffer SHARED $ENV{BOLOS_SDK}/lib_standard_app/buffer.c) +add_library(read SHARED $ENV{BOLOS_SDK}/lib_standard_app/read.c) +add_library(write SHARED $ENV{BOLOS_SDK}/lib_standard_app/write.c) +add_library(format SHARED $ENV{BOLOS_SDK}/lib_standard_app/format.c) +add_library(varint SHARED $ENV{BOLOS_SDK}/lib_standard_app/varint.c) +add_library(apdu_parser SHARED $ENV{BOLOS_SDK}/lib_standard_app/parser.c) +# add_library(transaction_deserialize ../src/transaction/deserialize.c) +# add_library(transaction_serialize ../src/transaction/serialize.c) +# add_library(transaction_utils ../src/transaction/utils.c) -target_link_libraries(test_base58 PUBLIC cmocka gcov base58) -target_link_libraries(test_bip32 PUBLIC cmocka gcov bip32 read) -target_link_libraries(test_buffer PUBLIC cmocka gcov buffer bip32 varint write read) -target_link_libraries(test_format PUBLIC cmocka gcov format) -target_link_libraries(test_write PUBLIC cmocka gcov write) -target_link_libraries(test_apdu_parser PUBLIC cmocka gcov apdu_parser) +# target_link_libraries(test_tx_parser PUBLIC +# transaction_deserialize +# transaction_serialize +# buffer +# bip32 +# cmocka +# gcov +# write +# read +# varint +# transaction_utils) +# target_link_libraries(test_tx_utils PUBLIC +# cmocka +# gcov +# transaction_utils) -add_test(test_base58 test_base58) -add_test(test_bip32 test_bip32) -add_test(test_buffer test_buffer) -add_test(test_format test_format) -add_test(test_write test_write) -add_test(test_apdu_parser test_apdu_parser) +# add_test(test_tx_parser test_tx_parser) +# add_test(test_tx_utils test_tx_utils) diff --git a/unit-tests/test_apdu_parser.c b/unit-tests/test_apdu_parser.c deleted file mode 100644 index 99ee07d..0000000 --- a/unit-tests/test_apdu_parser.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "types.h" -#include "apdu/parser.h" - -static void test_apdu_parser(void **state) { - (void) state; - uint8_t apdu_bad_min_len[] = {0xE0, 0x03, 0x00, 0x00}; // less than 5 bytes - uint8_t apdu_bad_lc[] = {0xE0, 0x03, 0x00, 0x00, 0x01}; // Lc = 1 but no data - uint8_t apdu[] = {0xE0, 0x03, 0x01, 0x02, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04}; - - command_t cmd; - - memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_min_len, sizeof(apdu_bad_min_len))); - - memset(&cmd, 0, sizeof(cmd)); - assert_false(apdu_parser(&cmd, apdu_bad_lc, sizeof(apdu_bad_min_len))); - - memset(&cmd, 0, sizeof(cmd)); - assert_true(apdu_parser(&cmd, apdu, sizeof(apdu))); - assert_int_equal(cmd.cla, 0xE0); - assert_int_equal(cmd.ins, 0x03); - assert_int_equal(cmd.p1, 0x01); - assert_int_equal(cmd.p2, 0x02); - assert_int_equal(cmd.lc, 5); - assert_memory_equal(cmd.data, ((uint8_t[]){0x00, 0x01, 0x02, 0x03, 0x04}), cmd.lc); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_apdu_parser)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_base58.c b/unit-tests/test_base58.c deleted file mode 100644 index f7f5e45..0000000 --- a/unit-tests/test_base58.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/base58.h" - -static void test_base58(void **state) { - (void) state; - - const char in[] = "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z"; - const char expected_out[] = "The quick brown fox jumps over the lazy dog."; - uint8_t out[100] = {0}; - int out_len = base58_decode(in, sizeof(in) - 1, out, sizeof(out)); - assert_int_equal(out_len, strlen(expected_out)); - assert_string_equal((char *) out, expected_out); - - const char in2[] = "The quick brown fox jumps over the lazy dog."; - const char expected_out2[] = "USm3fpXnKG5EUBx2ndxBDMPVciP5hGey2Jh4NDv6gmeo1LkMeiKrLJUUBk6Z"; - char out2[100] = {0}; - int out_len2 = base58_encode((uint8_t *) in2, sizeof(in2) - 1, out2, sizeof(out2)); - assert_int_equal(out_len2, strlen(expected_out2)); - assert_string_equal((char *) out2, expected_out2); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_base58)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_bip32.c b/unit-tests/test_bip32.c deleted file mode 100644 index f71383b..0000000 --- a/unit-tests/test_bip32.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "common/bip32.h" - -static void test_bip32_format(void **state) { - (void) state; - - char output[30]; - bool b = false; - - b = bip32_path_format((const uint32_t[5]){0x8000002C, 0x80000000, 0x80000000, 0, 0}, - 5, - output, - sizeof(output)); - assert_true(b); - assert_string_equal(output, "44'/0'/0'/0/0"); - - b = bip32_path_format((const uint32_t[5]){0x8000002C, 0x80000001, 0x80000000, 0, 0}, - 5, - output, - sizeof(output)); - assert_true(b); - assert_string_equal(output, "44'/1'/0'/0/0"); -} - -static void test_bad_bip32_format(void **state) { - (void) state; - - char output[30]; - bool b = true; - - // More than MAX_BIP32_PATH (=10) - b = bip32_path_format( - (const uint32_t[11]){0x8000002C, 0x80000000, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0}, - 11, - output, - sizeof(output)); - assert_false(b); - - // No BIP32 path (=0) - b = bip32_path_format(NULL, 0, output, sizeof(output)); - assert_false(b); -} - -static void test_bip32_read(void **state) { - (void) state; - - // clang-format off - uint8_t input[20] = { - 0x80, 0x00, 0x00, 0x2C, - 0x80, 0x00, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - uint32_t expected[5] = {0x8000002C, 0x80000001, 0x80000000, 0, 0}; - uint32_t output[5] = {0}; - bool b = false; - - b = bip32_path_read(input, sizeof(input), output, 5); - assert_true(b); - assert_memory_equal(output, expected, 5); -} - -static void test_bad_bip32_read(void **state) { - (void) state; - - // clang-format off - uint8_t input[20] = { - 0x80, 0x00, 0x00, 0x2C, - 0x80, 0x00, 0x00, 0x01, - 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - uint32_t output[10] = {0}; - - // buffer too small (5 BIP32 paths instead of 10) - assert_false(bip32_path_read(input, sizeof(input), output, 10)); - - // No BIP32 path - assert_false(bip32_path_read(input, sizeof(input), output, 0)); - - // More than MAX_BIP32_PATH (=10) - assert_false(bip32_path_read(input, sizeof(input), output, 20)); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_bip32_format), - cmocka_unit_test(test_bad_bip32_format), - cmocka_unit_test(test_bip32_read), - cmocka_unit_test(test_bad_bip32_read)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_buffer.c b/unit-tests/test_buffer.c deleted file mode 100644 index e2d1efa..0000000 --- a/unit-tests/test_buffer.c +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#include "common/buffer.h" - -static void test_buffer_can_read(void **state) { - (void) state; - - uint8_t temp[20] = {0}; - buffer_t buf = {.ptr = temp, .size = sizeof(temp), .offset = 0}; - - assert_true(buffer_can_read(&buf, 20)); - - assert_true(buffer_seek_cur(&buf, 20)); - assert_false(buffer_can_read(&buf, 1)); -} - -static void test_buffer_seek(void **state) { - (void) state; - - uint8_t temp[20] = {0}; - buffer_t buf = {.ptr = temp, .size = sizeof(temp), .offset = 0}; - - assert_true(buffer_can_read(&buf, 20)); - - assert_true(buffer_seek_cur(&buf, 20)); // seek at offset 20 - assert_false(buffer_can_read(&buf, 1)); // can't read 1 byte - assert_false(buffer_seek_cur(&buf, 1)); // can't move at offset 21 - - assert_true(buffer_seek_end(&buf, 19)); - assert_int_equal(buf.offset, 1); - assert_false(buffer_seek_end(&buf, 21)); // can't seek at offset -1 - - assert_true(buffer_seek_set(&buf, 10)); - assert_int_equal(buf.offset, 10); - assert_false(buffer_seek_set(&buf, 21)); // can't seek at offset 21 -} - -static void test_buffer_read(void **state) { - (void) state; - - // clang-format off - uint8_t temp[15] = { - 0xFF, - 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E - }; - buffer_t buf = {.ptr = temp, .size = sizeof(temp), .offset = 0}; - - uint8_t first = 0; - assert_true(buffer_read_u8(&buf, &first)); - assert_int_equal(first, 255); // 0xFF - assert_true(buffer_seek_end(&buf, 0)); // seek at offset 19 - assert_false(buffer_read_u8(&buf, &first)); // can't read 1 byte - - uint16_t second = 0; - assert_true(buffer_seek_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_read_u16(&buf, &second, BE)); // big endian - assert_int_equal(second, 258); // 0x01 0x02 - assert_true(buffer_seek_set(&buf, 1)); // set back to offset 1 - assert_true(buffer_read_u16(&buf, &second, LE)); // little endian - assert_int_equal(second, 513); // 0x02 0x01 - assert_true(buffer_seek_set(&buf, 14)); // seek at offset 14 - assert_false(buffer_read_u16(&buf, &second, BE)); // can't read 2 bytes - - uint32_t third = 0; - assert_true(buffer_seek_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_read_u32(&buf, &third, BE)); // big endian - assert_int_equal(third, 50595078); // 0x03 0x04 0x05 0x06 - assert_true(buffer_seek_set(&buf, 3)); // set back to offset 3 - assert_true(buffer_read_u32(&buf, &third, LE)); // little endian - assert_int_equal(third, 100992003); // 0x06 0x05 0x04 0x03 - assert_true(buffer_seek_set(&buf, 12)); // seek at offset 12 - assert_false(buffer_read_u32(&buf, &third, BE)); // can't read 4 bytes - - uint64_t fourth = 0; - assert_true(buffer_seek_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_read_u64(&buf, &fourth, BE)); // big endian - assert_int_equal(fourth, 506664896818842894); // 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E - assert_true(buffer_seek_set(&buf, 7)); // set back to offset 7 - assert_true(buffer_read_u64(&buf, &fourth, LE)); // little endian - assert_int_equal(fourth, 1012478732780767239); // 0x0E 0x0D 0x0C 0x0B 0x0A 0x09 0x08 0x07 - assert_true(buffer_seek_set(&buf, 8)); // seek at offset 8 - assert_false(buffer_read_u64(&buf, &fourth, BE)); // can't read 8 bytes - - // clang-format off - uint8_t temp_varint[] = { - 0xFC, // 1 byte varint - 0xFD, 0x00, 0x01, // 2 bytes varint - 0xFE, 0x00, 0x01, 0x02, 0x03, // 4 bytes varint - 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 // 8 bytes varint - - }; - buffer_t buf_varint = {.ptr = temp_varint, .size = sizeof(temp_varint), .offset = 0}; - uint64_t varint = 0; - assert_true(buffer_read_varint(&buf_varint, &varint)); - assert_int_equal(varint, 0xFC); - assert_true(buffer_read_varint(&buf_varint, &varint)); - assert_int_equal(varint, 0x0100); - assert_true(buffer_read_varint(&buf_varint, &varint)); - assert_int_equal(varint, 0x03020100); - assert_true(buffer_read_varint(&buf_varint, &varint)); - assert_int_equal(varint, 0x0706050403020100); - assert_false(buffer_read_varint(&buf_varint, &varint)); -} - -static void test_buffer_copy(void **state) { - (void) state; - - uint8_t output[5] = {0}; - uint8_t temp[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; - buffer_t buf = {.ptr = temp, .size = sizeof(temp), .offset = 0}; - - assert_true(buffer_copy(&buf, output, sizeof(output))); - assert_memory_equal(output, temp, sizeof(output)); - - uint8_t output2[3] = {0}; - assert_true(buffer_seek_set(&buf, 2)); - assert_true(buffer_copy(&buf, output2, sizeof(output2))); - assert_memory_equal(output2, ((uint8_t[3]){0x03, 0x04, 0x05}), 3); - assert_true(buffer_seek_set(&buf, 0)); // seek at offset 0 - assert_false(buffer_copy(&buf, output2, sizeof(output2))); // can't read 5 bytes -} - -static void test_buffer_move(void **state) { - (void) state; - - uint8_t output[5] = {0}; - uint8_t temp[5] = {0x01, 0x02, 0x03, 0x04, 0x05}; - buffer_t buf = {.ptr = temp, .size = sizeof(temp), .offset = 0}; - - assert_true(buffer_move(&buf, output, sizeof(output))); - assert_memory_equal(output, temp, sizeof(output)); - assert_int_equal(buf.offset, sizeof(output)); - - uint8_t output2[3] = {0}; - assert_true(buffer_seek_set(&buf, 0)); // seek at offset 0 - assert_false(buffer_move(&buf, output2, sizeof(output2))); // can't read 5 bytes -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_buffer_can_read), - cmocka_unit_test(test_buffer_seek), - cmocka_unit_test(test_buffer_read), - cmocka_unit_test(test_buffer_copy), - cmocka_unit_test(test_buffer_move)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_format.c b/unit-tests/test_format.c deleted file mode 100644 index 7423e18..0000000 --- a/unit-tests/test_format.c +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/format.h" - -static void test_format_i64(void **state) { - (void) state; - - char temp[22] = {0}; - - int64_t value = 0; - assert_true(format_i64(temp, sizeof(temp), value)); - assert_string_equal(temp, "0"); - - value = (int64_t) 9223372036854775807ull; // MAX_INT64 - memset(temp, 0, sizeof(temp)); - assert_true(format_i64(temp, sizeof(temp), value)); - assert_string_equal(temp, "9223372036854775807"); - - // buffer too small - assert_false(format_i64(temp, sizeof(temp) - 5, value)); - - value = (int64_t) -9223372036854775808ull; // MIN_INT64 - memset(temp, 0, sizeof(temp)); - assert_true(format_i64(temp, sizeof(temp), value)); - assert_string_equal(temp, "-9223372036854775808"); -} - -static void test_format_u64(void **state) { - (void) state; - - char temp[21] = {0}; - - uint64_t value = 0; - assert_true(format_u64(temp, sizeof(temp), value)); - assert_string_equal(temp, "0"); - - value = (uint64_t) 18446744073709551615ull; // MAX_UNT64 - memset(temp, 0, sizeof(temp)); - assert_true(format_u64(temp, sizeof(temp), value)); - assert_string_equal(temp, "18446744073709551615"); - - // buffer too small - assert_false(format_u64(temp, sizeof(temp) - 5, value)); -} - -static void test_format_fpu64(void **state) { - (void) state; - - char temp[22] = {0}; - - uint64_t amount = 100000000ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_true(format_fpu64(temp, sizeof(temp), amount, 8)); - assert_string_equal(temp, "1.00000000"); // BTC - - amount = 24964823ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_true(format_fpu64(temp, sizeof(temp), amount, 8)); - assert_string_equal(temp, "0.24964823"); // BTC - - amount = 100ull; // satoshi - memset(temp, 0, sizeof(temp)); - assert_true(format_fpu64(temp, sizeof(temp), amount, 8)); - assert_string_equal(temp, "0.00000100"); // BTC - // buffer too small - assert_false(format_fpu64(temp, sizeof(temp) - 16, amount, 8)); - - char temp2[50] = {0}; - - amount = 1000000000000000000ull; // wei - assert_true(format_fpu64(temp2, sizeof(temp2), amount, 18)); - assert_string_equal(temp2, "1.000000000000000000"); // ETH - - // buffer too small - assert_false(format_fpu64(temp2, sizeof(temp2) - 20, amount, 18)); -} - -static void test_format_hex(void **state) { - (void) state; - - uint8_t address[] = {0xde, 0xb, 0x29, 0x56, 0x69, 0xa9, 0xfd, 0x93, 0xd5, 0xf2, - 0x8d, 0x9e, 0xc8, 0x5e, 0x40, 0xf4, 0xcb, 0x69, 0x7b, 0xae}; - char output[2 * sizeof(address) + 1] = {0}; - - assert_int_equal(2 * sizeof(address) + 1, - format_hex(address, sizeof(address), output, sizeof(output))); - assert_string_equal(output, "DE0B295669A9FD93D5F28D9EC85E40F4CB697BAE"); - assert_int_equal(-1, format_hex(address, sizeof(address), output, sizeof(address))); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_format_i64), - cmocka_unit_test(test_format_u64), - cmocka_unit_test(test_format_fpu64), - cmocka_unit_test(test_format_hex)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -} diff --git a/unit-tests/test_write.c b/unit-tests/test_write.c deleted file mode 100644 index 08f37f7..0000000 --- a/unit-tests/test_write.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "common/write.h" - -static void test_write(void **state) { - (void) state; - - uint8_t tmp2[2] = {0}; - - uint8_t expected2[2] = {0x01, 0x07}; - write_u16_be(tmp2, 0, (uint16_t) 263U); - assert_memory_equal(tmp2, expected2, sizeof(expected2)); - - memset(tmp2, 0, sizeof(tmp2)); - expected2[0] = 0x07; - expected2[1] = 0x01; - write_u16_le(tmp2, 0, (uint16_t) 263U); - assert_memory_equal(tmp2, expected2, sizeof(expected2)); - - uint8_t tmp4[4] = {0}; - - uint8_t expected4[4] = {0x01, 0x3B, 0xAC, 0xC7}; - write_u32_be(tmp4, 0, (uint32_t) 20688071UL); - assert_memory_equal(tmp4, expected4, sizeof(expected4)); - - memset(tmp4, 0, sizeof(tmp4)); - expected4[0] = 0xC7; - expected4[1] = 0xAC; - expected4[2] = 0x3B; - expected4[3] = 0x01; - write_u32_le(tmp4, 0, (uint32_t) 20688071UL); - assert_memory_equal(tmp4, expected4, sizeof(expected4)); - - uint8_t tmp8[8] = {0}; - - uint8_t expected8[8] = {0xEB, 0x68, 0x44, 0xC0, 0x2C, 0x61, 0xB0, 0x99}; - write_u64_be(tmp8, 0, (uint64_t) 16962883588659982489ULL); - assert_memory_equal(tmp8, expected8, sizeof(expected8)); - - memset(tmp8, 0, sizeof(tmp8)); - expected8[0] = 0x99; - expected8[1] = 0xB0; - expected8[2] = 0x61; - expected8[3] = 0x2C; - expected8[4] = 0xC0; - expected8[5] = 0x44; - expected8[6] = 0x68; - expected8[7] = 0xEB; - write_u64_le(tmp8, 0, (uint64_t) 16962883588659982489ULL); - assert_memory_equal(tmp8, expected8, sizeof(expected8)); -} - -int main() { - const struct CMUnitTest tests[] = {cmocka_unit_test(test_write)}; - - return cmocka_run_group_tests(tests, NULL, NULL); -}