diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index fdc2e33a..dabdba5a 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,8 +1,7 @@ { "env": { - "BOLOS_SDK": "~/.ledger/sdk/nanos-secure-sdk", - "BOLOS_ENV": "~/.ledger/env", - "GCC_COMPILER_NAME": "gcc-arm-none-eabi-10.3-2021.10" + "BOLOS_SDK": "~/.ledger/sdk", + "ARM_GCC": "~/.ledger/gcc-arm-none-eabi-13.2-2023.10" }, "configurations": [ { @@ -10,10 +9,13 @@ "includePath": [ "${workspaceFolder}/src", "${workspaceFolder}/build/**", - "${env:BOLOS_ENV}/${env:GCC_COMPILER_NAME}/arm-none-eabi/include", + "${env:ARM_GCC}/arm-none-eabi/include/*", "${env:BOLOS_SDK}/include/*", + "${env:BOLOS_SDK}/target/nanos/include/*", + "${env:BOLOS_SDK}/lib_bagl/include/*", "${env:BOLOS_SDK}/lib_ux/include/*", - "${env:BOLOS_SDK}/lib_cxng/include/*" + "${env:BOLOS_SDK}/lib_cxng/include/*", + "${env:BOLOS_SDK}/lib_standard_app/*" ], "defines": [ "TARGET_NANOS", @@ -43,12 +45,13 @@ "PATCH_VERSION=0", "IO_SEPROXYHAL_BUFFER_SIZE_B=128", "HAVE_UX_FLOW", - "DEBUG_BUILD=1", + "DEBUG=1", "HAVE_PRINTF", - "PRINTF=screen_printf" + "PRINTF=screen_printf", + "_DEFAULT_SOURCE" ], - "compilerPath": "${env:BOLOS_ENV}/${env:GCC_COMPILER_NAME}/bin/arm-none-eabi-gcc", - "cStandard": "c99", + "compilerPath": "${env:ARM_GCC}/bin/arm-none-eabi-gcc", + "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "gcc-arm", "browse": { diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..f044256a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,6 @@ +{ + "recommendations": [ + "ms-vscode.cpptools", + "LedgerHQ.ledger-dev-tools", + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 6b6ceecb..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "gdb", - "request": "attach", - "name": "Attach to gdbserver", - "executable": "${workspaceFolder}/bin/app.elf", - "target": ":1234", - "remote": true, - "cwd": "${workspaceFolder}", - "valuesFormatting": "parseText", - "gdbpath": "gdb-multiarch", - "autorun": [ - "set architecture arm", - "handle SIGILL nostop pass noprint", - "add-symbol-file ${workspaceFolder}/bin/app.elf 0x40000000", - "b *0x40000000", - "c" - ] - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index aef3d745..4be05ef5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,22 +1,9 @@ { "files.associations": { "*.h": "c", - "cstdio": "c", - "optional": "c", - "istream": "c", - "ostream": "c", - "ratio": "c", - "system_error": "c", - "array": "c", - "functional": "c", - "tuple": "c", - "type_traits": "c", - "utility": "c", - "limits": "c", - "numeric": "c", - "stop_token": "c" + "format": "c" }, - "C_Cpp.clang_format_path": "/usr/bin/clang-format", - "editor.formatOnSave": true, - "cmake.configureOnOpen": false + "editor.formatOnSave": false, + "python.terminal.activateEnvironment": false, + "git.ignoreLimitWarning": true, } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 7c430bc8..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "label": "make", - "type": "shell", - "command": "make clean && make", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "[debug] make", - "type": "shell", - "command": "make clean && make DEBUG=1", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "make clean", - "type": "shell", - "command": "make clean", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "make load", - "type": "shell", - "command": "make load", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "run unit tests", - "type": "shell", - "command": "cd unit-tests && rm -rf build && cmake -Bbuild -H. && make -C build && CTEST_OUTPUT_ON_FAILURE=1 make -C build test", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "run Speculos", - "type": "shell", - "command": "python3 ~/.ledger/speculos/speculos.py ${workspaceFolder}/bin/app.elf --ontop --sdk 2.1 --apdu-port 9999 --api-port 5000 --seed \"`cat ${workspaceFolder}/tests/seed.txt`\"", - "group": { - "kind": "build", - "isDefault": true - }, - "dependsOn": [ - "make debug" - ], - "problemMatcher": [] - }, - { - "label": "[debug] run Speculos", - "type": "shell", - "command": "python3 ~/.ledger/speculos/speculos.py -d ${workspaceFolder}/bin/app.elf --ontop --sdk 2.1 --apdu-port 9999 --api-port 5000 --seed \"`cat ${workspaceFolder}/tests/seed.txt`\"", - "group": { - "kind": "build", - "isDefault": true - }, - "dependsOn": [ - "make debug" - ], - "problemMatcher": [] - }, - { - "label": "run tests", - "type": "shell", - "command": "cd tests && npm --model=nanos run test", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [] - }, - { - "label": "kill Speculos", - "type": "shell", - "command": "pkill -f speculos.py", - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [] - } - ] -} \ No newline at end of file diff --git a/Makefile b/Makefile index 11fb0d14..8efc96bb 100644 --- a/Makefile +++ b/Makefile @@ -19,108 +19,92 @@ ifeq ($(BOLOS_SDK),) $(error Environment variable BOLOS_SDK is not set) endif -include Makefile.env include $(BOLOS_SDK)/Makefile.defines -APP_LOAD_PARAMS = --curve secp256k1 -ifeq ($(TARGET_NAME), TARGET_NANOX) -APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS -else -APP_LOAD_PARAMS += --appFlags 0x000 -endif -APP_LOAD_PARAMS += --path "44'/429'" -APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) - -# Pending review parameters -APP_LOAD_PARAMS += --tlvraw 9F:01 -DEFINES += HAVE_PENDING_REVIEW_SCREEN +######################################## +# Mandatory configuration # +######################################## +# Application name +APPNAME = "Ergo" -APPNAME = "Ergo" +# Application version APPVERSION_M = 0 APPVERSION_N = 0 APPVERSION_P = 4 -APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" - -ifeq ($(TARGET_NAME),TARGET_NANOS) - ICONNAME=icons/nanos_app.gif -else - ICONNAME=icons/nanox_app.gif -endif - -all: default - -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_BAGL HAVE_UX_FLOW HAVE_SPRINTF -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),TARGET_NANOX) - 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 - DEFINES += HAVE_GLO096 - DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64 - DEFINES += HAVE_BAGL_ELLIPSIS - 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 - -DEBUG = 0 -ifneq ($(DEBUG),0) - DEFINES += DEBUG_BUILD - DEFINES += HAVE_PRINTF - DEFINES += HAVE_BOLOS_APP_STACK_CANARY - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += PRINTF=screen_printf - else - DEFINES += PRINTF=mcu_usb_printf - endif -else - DEFINES += PRINTF\(...\)= -endif - -include Makefile.env - -CC := $(CLANGPATH)clang -CFLAGS += -O3 -Os -AS := $(GCCPATH)arm-none-eabi-gcc -LD := $(GCCPATH)arm-none-eabi-gcc -LDFLAGS += -O3 -Os -LDLIBS += -lm -lgcc -lc - -include $(BOLOS_SDK)/Makefile.glyphs +APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)" +# Application source files APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_ux - -ifeq ($(TARGET_NAME),TARGET_NANOX) - 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 - -dep/%.d: %.c Makefile -listvariants: - @echo VARIANTS COIN ergo +# Application icons following guidelines: +# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon +ICON_NANOS = icons/app_16px.gif +ICON_NANOX = icons/app_14px.gif +ICON_NANOSP = icons/app_14px.gif +#ICON_STAX = icons/app_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'/429'" # purpose=coin(44) / coin_type=Ergo(429) + +# 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. +VARIANT_PARAM = COIN +VARIANT_VALUES = ERGO + +# 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 +#DISABLE_DEBUG_LEDGER_ASSERT = 1 +#DISABLE_DEBUG_THROW = 1 + +include $(BOLOS_SDK)/Makefile.standard_app \ No newline at end of file diff --git a/Makefile.env b/Makefile.env deleted file mode 100644 index 96e8c37f..00000000 --- a/Makefile.env +++ /dev/null @@ -1,13 +0,0 @@ -ifneq ($(BOLOS_ENV),) -$(info BOLOS_ENV=$(BOLOS_ENV)) -CLANGPATH := $(BOLOS_ENV)/llvm-14-x86_64/bin/ -GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-10.3-2021.10/bin/ -else -$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH) -endif -ifeq ($(CLANGPATH),) -$(info CLANGPATH is not set: clang will be used from PATH) -endif -ifeq ($(GCCPATH),) -$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH) -endif \ No newline at end of file diff --git a/glyphs/icon_back.gif b/glyphs/icon_back.gif deleted file mode 100644 index a2a7e6d4..00000000 Binary files a/glyphs/icon_back.gif and /dev/null differ diff --git a/glyphs/icon_back_x.gif b/glyphs/icon_back_x.gif deleted file mode 100644 index ff043615..00000000 Binary files a/glyphs/icon_back_x.gif and /dev/null differ diff --git a/glyphs/icon_certificate.gif b/glyphs/icon_certificate.gif deleted file mode 100644 index 89b529f7..00000000 Binary files a/glyphs/icon_certificate.gif and /dev/null differ diff --git a/glyphs/icon_coggle.gif b/glyphs/icon_coggle.gif deleted file mode 100644 index 01c43b28..00000000 Binary files a/glyphs/icon_coggle.gif and /dev/null differ diff --git a/glyphs/icon_crossmark.gif b/glyphs/icon_crossmark.gif deleted file mode 100644 index 2dcf9d9e..00000000 Binary files a/glyphs/icon_crossmark.gif and /dev/null differ diff --git a/glyphs/icon_dashboard.gif b/glyphs/icon_dashboard.gif deleted file mode 100644 index 5c305517..00000000 Binary files a/glyphs/icon_dashboard.gif and /dev/null differ diff --git a/glyphs/icon_dashboard_x.gif b/glyphs/icon_dashboard_x.gif deleted file mode 100644 index 33d9b0a7..00000000 Binary files a/glyphs/icon_dashboard_x.gif and /dev/null differ diff --git a/glyphs/icon_down.gif b/glyphs/icon_down.gif deleted file mode 100644 index 4f4e39ee..00000000 Binary files a/glyphs/icon_down.gif and /dev/null differ diff --git a/glyphs/icon_eye.gif b/glyphs/icon_eye.gif deleted file mode 100644 index df4bb829..00000000 Binary files a/glyphs/icon_eye.gif and /dev/null differ diff --git a/glyphs/icon_left.gif b/glyphs/icon_left.gif deleted file mode 100644 index 524226ba..00000000 Binary files a/glyphs/icon_left.gif and /dev/null differ diff --git a/glyphs/icon_processing.gif b/glyphs/icon_processing.gif deleted file mode 100644 index 8fe937fa..00000000 Binary files a/glyphs/icon_processing.gif and /dev/null differ diff --git a/glyphs/icon_right.gif b/glyphs/icon_right.gif deleted file mode 100644 index 15ff3cf5..00000000 Binary files a/glyphs/icon_right.gif and /dev/null differ diff --git a/glyphs/icon_up.gif b/glyphs/icon_up.gif deleted file mode 100644 index 4e13c064..00000000 Binary files a/glyphs/icon_up.gif and /dev/null differ diff --git a/glyphs/icon_validate_14.gif b/glyphs/icon_validate_14.gif deleted file mode 100644 index ccb5cabe..00000000 Binary files a/glyphs/icon_validate_14.gif and /dev/null differ diff --git a/glyphs/icon_warning.gif b/glyphs/icon_warning.gif deleted file mode 100644 index 08bd4a73..00000000 Binary files a/glyphs/icon_warning.gif and /dev/null differ diff --git a/icons/nanox_app.gif b/icons/app_14px.gif similarity index 100% rename from icons/nanox_app.gif rename to icons/app_14px.gif diff --git a/icons/nanos_app.gif b/icons/app_16px.gif similarity index 100% rename from icons/nanos_app.gif rename to icons/app_16px.gif diff --git a/ledger_app.toml b/ledger_app.toml new file mode 100644 index 00000000..b223878c --- /dev/null +++ b/ledger_app.toml @@ -0,0 +1,8 @@ +[app] +build_directory = "./" +sdk = "C" +devices = ["nanos", "nanox", "nanos+"] + +[tests] +unit_directory = "./unit-tests/" +pytest_directory = "./tests/" diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h deleted file mode 100644 index c896ddfe..00000000 --- a/src/apdu/dispatcher.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "../types.h" - -/** - * Dispatch APDU command received to the right handler. - * - * @param[in] cmd - * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). - * - * @return zero or positive integer if success, negative integer otherwise. - * - */ -int apdu_dispatcher(const command_t *cmd); diff --git a/src/apdu/offsets.h b/src/apdu/offsets.h deleted file mode 100644 index 3db4bc14..00000000 --- a/src/apdu/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/apdu/parser.c b/src/apdu/parser.c deleted file mode 100644 index 418d8357..00000000 --- a/src/apdu/parser.c +++ /dev/null @@ -1,39 +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 "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 dfba3fd6..00000000 --- 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/apdu/dispatcher.c b/src/apdu_dispatcher.c similarity index 76% rename from src/apdu/dispatcher.c rename to src/apdu_dispatcher.c index c70a0153..b81a6654 100644 --- a/src/apdu/dispatcher.c +++ b/src/apdu_dispatcher.c @@ -1,19 +1,17 @@ #include #include -#include "dispatcher.h" -#include "../constants.h" -#include "../globals.h" -#include "../types.h" -#include "../sw.h" -#include "../helpers/io.h" -#include "../common/buffer.h" -#include "../commands/app_name.h" -#include "../commands/app_version.h" -#include "../commands/extpubkey/epk_handler.h" -#include "../commands/deriveaddress/da_handler.h" -#include "../commands/attestinput/ainpt_handler.h" -#include "../commands/signtx/stx_handler.h" +#include + +#include "apdu_dispatcher.h" +#include "constants.h" +#include "sw.h" +#include "commands/app_name.h" +#include "commands/app_version.h" +#include "commands/extpubkey/epk_handler.h" +#include "commands/deriveaddress/da_handler.h" +#include "commands/attestinput/ainpt_handler.h" +#include "commands/signtx/stx_handler.h" int apdu_dispatcher(const command_t *cmd) { if (cmd->cla != CLA) { @@ -21,7 +19,7 @@ int apdu_dispatcher(const command_t *cmd) { } buffer_t buf; - buffer_init(&buf, cmd->data, cmd->lc, cmd->lc); + buffer_init(&buf, cmd->data, cmd->lc); switch (cmd->ins) { case CMD_GET_APP_VERSION: diff --git a/src/types.h b/src/apdu_dispatcher.h similarity index 51% rename from src/types.h rename to src/apdu_dispatcher.h index 3c32d94f..adf0d075 100644 --- a/src/types.h +++ b/src/apdu_dispatcher.h @@ -1,18 +1,6 @@ #pragma once -#include // size_t -#include // uint*_t - -#include "constants.h" - -/** - * Enumeration for the status of IO. - */ -typedef enum { - READY, /// ready for new event - RECEIVED, /// data received - WAITING /// waiting -} io_state_e; +#include /** * Enumeration with expected INS of APDU commands. @@ -28,13 +16,12 @@ typedef enum { } command_e; /** - * Structure with fields of APDU command. + * Dispatch APDU command received to the right handler. + * + * @param[in] cmd + * Structured APDU command (CLA, INS, P1, P2, Lc, Command data). + * + * @return zero or positive integer if success, negative integer otherwise. + * */ -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; +int apdu_dispatcher(const command_t *cmd); diff --git a/src/app_main.c b/src/app_main.c new file mode 100644 index 00000000..da27a0d0 --- /dev/null +++ b/src/app_main.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * 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 +#include +#include +#include +#include + +#include "context.h" +#include "sw.h" +#include "apdu_dispatcher.h" +#include "ui/ui_menu.h" +#include "common/macros_ext.h" + +/** + * 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; + + // Initialize I/O + io_init(); + + // Initialize Global App Context + app_init(); + + // Show main menu + ui_menu_main(); + + 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_APDU_DATA_LENGTH); + continue; + } + + // Dispatch structured APDU command to handler + if (apdu_dispatcher(&cmd) < 0) { + PRINTF("=> apdu_dispatcher failure\n"); + return; + } + } +} diff --git a/src/commands/app_name.c b/src/commands/app_name.c index 6df643e6..474b4a69 100644 --- a/src/commands/app_name.c +++ b/src/commands/app_name.c @@ -4,14 +4,12 @@ #include "app_name.h" #include "../constants.h" -#include "../globals.h" -#include "../types.h" -#include "helpers/response.h" -#include "common/buffer.h" +#include "../helpers/response.h" +#include "../common/rwbuffer.h" int handler_get_app_name() { _Static_assert(APPNAME_LEN < MAX_APPNAME_LEN, "APPNAME must be at most 64 characters!"); - BUFFER_FROM_ARRAY_FULL(buf, (uint8_t *) PIC(APPNAME), APPNAME_LEN); + RW_BUFFER_FROM_ARRAY_FULL(buf, (uint8_t *) PIC(APPNAME), APPNAME_LEN); return res_ok_data(&buf); } diff --git a/src/commands/app_version.c b/src/commands/app_version.c index 44db447c..32a2bee2 100644 --- a/src/commands/app_version.c +++ b/src/commands/app_version.c @@ -2,11 +2,9 @@ #include // UINT8_MAX #include // _Static_assert #include "app_version.h" -#include "../globals.h" #include "../constants.h" -#include "../types.h" -#include "helpers/response.h" -#include "common/buffer.h" +#include "../helpers/response.h" +#include "../common/rwbuffer.h" int handler_get_version() { _Static_assert(APPVERSION_LEN == 4, "Length of (MAJOR || MINOR || PATCH || DEBUG) must be 4!"); @@ -17,10 +15,10 @@ int handler_get_version() { _Static_assert(PATCH_VERSION >= 0 && PATCH_VERSION <= UINT8_MAX, "PATCH version must be between 0 and 255!"); uint8_t version[APPVERSION_LEN] = {MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, 0}; -#ifdef DEBUG_BUILD +#ifdef DEBUG version[3] = 1; #endif - BUFFER_FROM_ARRAY_FULL(buf, version, APPVERSION_LEN); + RW_BUFFER_FROM_ARRAY_FULL(buf, version, APPVERSION_LEN); return res_ok_data(&buf); } diff --git a/src/commands/attestinput/ainpt_context.h b/src/commands/attestinput/ainpt_context.h index b94e6f68..8082ed24 100755 --- a/src/commands/attestinput/ainpt_context.h +++ b/src/commands/attestinput/ainpt_context.h @@ -5,7 +5,6 @@ #include #include "../../constants.h" #include "../../ergo/tx_ser_box.h" -#include "../../common/buffer.h" #include "../../helpers/input_frame.h" #include "../../ui/ui_application_id.h" diff --git a/src/commands/attestinput/ainpt_handler.c b/src/commands/attestinput/ainpt_handler.c index df22a923..8c01b4ca 100755 --- a/src/commands/attestinput/ainpt_handler.c +++ b/src/commands/attestinput/ainpt_handler.c @@ -1,32 +1,16 @@ +#include + #include "ainpt_handler.h" #include "ainpt_response.h" #include "ainpt_ui.h" -#include "../../globals.h" #include "../../helpers/session_id.h" #include "../../helpers/response.h" #include "../../helpers/sw_result.h" -#include "../../common/int_ops.h" -#include "../../common/macros.h" - -#include - -#define CONTEXT(gctx) gctx.ctx.attest_input +#include "../../common/safeint.h" +#include "../../common/macros_ext.h" -#define CHECK_COMMAND(_cmd) \ - if (_cmd != G_context.current_command) return handler_err(&CONTEXT(G_context), SW_BAD_STATE) - -#define CHECK_SESSION(session_id) \ - if (session_id != CONTEXT(G_context).session) \ - return handler_err(&CONTEXT(G_context), SW_BAD_SESSION_ID) - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_READ_PARAM(_ctx, _call) \ - if (!_call) return handler_err(_ctx, SW_NOT_ENOUGH_DATA) - -#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ - if (buffer_can_read(_buffer, 1)) return handler_err(_ctx, SW_TOO_MUCH_DATA) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" #define CHECK_CALL_RESULT_OK(_ctx, _call) \ do { \ @@ -50,6 +34,7 @@ static inline int handler_err(attest_input_ctx_t *ctx, uint16_t err) { ctx->state = ATTEST_INPUT_STATE_ERROR; + app_set_current_command(CMD_NONE); return res_error(err); } @@ -91,7 +76,7 @@ static inline int handle_init(attest_input_ctx_t *ctx, uint32_t ergo_tree_size, creation_height, registers_size, app_session_id_in = 0; uint8_t tokens_count; - CHECK_READ_PARAM(ctx, buffer_read_bytes(cdata, ctx->box_id, ERGO_ID_LEN)); + CHECK_READ_PARAM(ctx, buffer_move(cdata, ctx->box_id, ERGO_ID_LEN)); CHECK_READ_PARAM(ctx, buffer_read_u16(cdata, &ctx->box_index, BE)); CHECK_READ_PARAM(ctx, buffer_read_u64(cdata, &value, BE)); CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &ergo_tree_size, BE)); @@ -150,7 +135,7 @@ static inline int handle_registers_chunk(attest_input_ctx_t *ctx, buffer_t *cdat } static inline int handle_get_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], buffer_t *cdata) { CHECK_PROPER_STATE(ctx, ATTEST_INPUT_STATE_FINISHED); uint8_t index; @@ -162,36 +147,38 @@ static inline int handle_get_frame(attest_input_ctx_t *ctx, int handler_attest_input(buffer_t *cdata, attest_input_subcommand_e subcommand, uint8_t session_or_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + + attest_input_ctx_t* ctx = app_attest_input_context(); switch (subcommand) { case ATTEST_INPUT_SUBCOMMAND_INIT: if (session_or_token != 0x01 && session_or_token != 0x02) { - return res_error(SW_WRONG_P1P2); + return handler_err(ctx, SW_WRONG_P1P2); } - clear_context(&G_context, CMD_ATTEST_INPUT_BOX); - return handle_init(&CONTEXT(G_context), + app_set_current_command(CMD_ATTEST_INPUT_BOX); + return handle_init(ctx, cdata, session_or_token == 0x02, - G_context.app_session_id); + app_connected_app_id()); case ATTEST_INPUT_SUBCOMMAND_TREE_CHUNK: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_tree_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_tree_chunk(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_TOKENS: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_tokens(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_REGISTERS: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_registers_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_registers_chunk(ctx, cdata); case ATTEST_INPUT_SUBCOMMAND_GET_RESPONSE_FRAME: - CHECK_COMMAND(CMD_ATTEST_INPUT_BOX); - CHECK_SESSION(session_or_token); - return handle_get_frame(&CONTEXT(G_context), G_context.session_key, cdata); + CHECK_COMMAND(ctx, CMD_ATTEST_INPUT_BOX); + CHECK_SESSION(ctx, session_or_token); + return handle_get_frame(ctx, app_session_key(), cdata); default: - return res_error(SW_WRONG_SUBCOMMAND); + return handler_err(ctx, SW_WRONG_SUBCOMMAND); } } diff --git a/src/commands/attestinput/ainpt_handler.h b/src/commands/attestinput/ainpt_handler.h index 41124ad5..6905db75 100755 --- a/src/commands/attestinput/ainpt_handler.h +++ b/src/commands/attestinput/ainpt_handler.h @@ -4,8 +4,9 @@ #include // bool #include // uint*_t +#include + #include "ainpt_context.h" -#include "../../common/buffer.h" typedef enum { ATTEST_INPUT_SUBCOMMAND_INIT = 0x01, @@ -24,6 +25,8 @@ typedef enum { * Subcommand identifier. * @param[in] session_or_token * Whether data has access token or not, or session id (depends on subcommand) + * @param[in] app_context + * Whether data has access token or not, or session id (depends on subcommand) * * @return zero or positive integer if success, negative integer otherwise. * diff --git a/src/commands/attestinput/ainpt_response.c b/src/commands/attestinput/ainpt_response.c index 8be4d02f..23a063c5 100755 --- a/src/commands/attestinput/ainpt_response.c +++ b/src/commands/attestinput/ainpt_response.c @@ -1,78 +1,69 @@ +#include + #include "ainpt_response.h" #include "ainpt_context.h" -#include "../../globals.h" #include "../../helpers/response.h" #include "../../helpers/input_frame.h" -#include "../../helpers/io.h" + +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" static inline uint8_t get_frames_count(uint8_t tokens_count) { uint8_t frames_count = (tokens_count + (FRAME_MAX_TOKENS_COUNT - 1)) / FRAME_MAX_TOKENS_COUNT; return frames_count == 0 ? 1 : frames_count; } +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_attested_input_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], uint8_t index) { uint8_t frames_count = get_frames_count(ctx->tokens_table.count); if (index >= frames_count) { - return res_error(SW_BAD_FRAME_INDEX); + return send_error(SW_BAD_FRAME_INDEX); } - // Hack for stack overflow. Writing directly to the IO buffer. + // Hack for the stack overflow. Writing directly to the IO buffer. // Not elegant but works. - BUFFER_FROM_ARRAY_EMPTY(output, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + RW_BUFFER_FROM_ARRAY_EMPTY(output, G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&output, ctx->box_id, ERGO_ID_LEN)); + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, frames_count)); + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, index)); + CHECK_WRITE_PARAM(rw_buffer_write_u64(&output, ctx->box.value, BE)); - if (!buffer_write_bytes(&output, ctx->box_id, ERGO_ID_LEN)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u8(&output, frames_count)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u8(&output, index)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u64(&output, ctx->box.value, BE)) { - return res_error(SW_BUFFER_ERROR); - } uint8_t tokens_count = (ctx->tokens_table.count - index * FRAME_MAX_TOKENS_COUNT); tokens_count = MIN(tokens_count, FRAME_MAX_TOKENS_COUNT); - if (!buffer_write_u8(&output, tokens_count)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_u8(&output, tokens_count)); uint8_t offset = index * FRAME_MAX_TOKENS_COUNT; for (uint8_t i = offset; i < offset + tokens_count; i++) { - if (!buffer_write_bytes(&output, ctx->tokens_table.tokens[i], ERGO_ID_LEN)) { - return res_error(SW_BUFFER_ERROR); - } - if (!buffer_write_u64(&output, ctx->token_amounts[i], BE)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&output, ctx->tokens_table.tokens[i], ERGO_ID_LEN)); + CHECK_WRITE_PARAM(rw_buffer_write_u64(&output, ctx->token_amounts[i], BE)); } - if (!buffer_can_write(&output, CX_SHA256_SIZE)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_can_write(&output, CX_SHA256_SIZE)); cx_hmac_sha256(session_key, SESSION_KEY_LEN, - buffer_read_ptr(&output), - buffer_data_len(&output), - buffer_write_ptr(&output), + rw_buffer_read_ptr(&output), + rw_buffer_data_len(&output), + rw_buffer_write_ptr(&output), CX_SHA256_SIZE); - if (!buffer_seek_write_cur(&output, INPUT_FRAME_SIGNATURE_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_seek_write_cur(&output, INPUT_FRAME_SIGNATURE_LEN)); return res_ok_data(&output); } int send_response_attested_input_frame_count(uint8_t tokens_count) { uint8_t frames_count = get_frames_count(tokens_count); - BUFFER_FROM_VAR_FULL(buf, frames_count); + RW_BUFFER_FROM_VAR_FULL(buf, frames_count); return res_ok_data(&buf); } int send_response_attested_input_session_id(uint8_t session_id) { - BUFFER_FROM_VAR_FULL(buf, session_id); + RW_BUFFER_FROM_VAR_FULL(buf, session_id); return res_ok_data(&buf); } diff --git a/src/commands/attestinput/ainpt_response.h b/src/commands/attestinput/ainpt_response.h index 9967e80b..59292c77 100755 --- a/src/commands/attestinput/ainpt_response.h +++ b/src/commands/attestinput/ainpt_response.h @@ -13,7 +13,7 @@ * */ int send_response_attested_input_frame(attest_input_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], uint8_t index); /** diff --git a/src/commands/attestinput/ainpt_ui.c b/src/commands/attestinput/ainpt_ui.c index 47234d3b..d972cc69 100644 --- a/src/commands/attestinput/ainpt_ui.c +++ b/src/commands/attestinput/ainpt_ui.c @@ -4,25 +4,27 @@ #include "ainpt_ui.h" #include "ainpt_response.h" -#include "../../globals.h" -#include "../../common/macros.h" +#include "../../context.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_ainpt_display_confirm_step, pn, {&C_icon_processing, "Confirm Attest Input"}); static NOINLINE void ui_action_attest_input(bool approved, void* context) { - G_context.is_ui_busy = false; attest_input_ctx_t* ctx = (attest_input_ctx_t*) context; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->ui.app_token_value; + app_set_connected_app_id(ctx->ui.app_token_value); ctx->state = ATTEST_INPUT_STATE_APPROVED; send_response_attested_input_session_id(ctx->session); } else { + app_set_current_command(CMD_NONE); res_deny(); } @@ -33,19 +35,15 @@ int ui_display_access_token(uint32_t app_access_token, attest_input_ctx_t* conte context->ui.app_token_value = app_access_token; uint8_t screen = 0; - G_ux_flow[screen++] = &ux_ainpt_display_confirm_step; + ui_add_screen(&ux_ainpt_display_confirm_step, &screen); + if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, context->ui.app_token); + ui_add_screen(ui_application_id_screen(app_access_token, context->ui.app_token), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_attest_input, context, approve, reject); - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; - - ux_flow_init(0, G_ux_flow, NULL); - G_context.is_ui_busy = true; + ui_approve_reject_screens(ui_action_attest_input, + context, ui_next_sreen_ptr(&screen), ui_next_sreen_ptr(&screen)); + ui_display_screens(&screen); return 0; } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_context.h b/src/commands/deriveaddress/da_context.h index a39abd51..7b689f9a 100644 --- a/src/commands/deriveaddress/da_context.h +++ b/src/commands/deriveaddress/da_context.h @@ -2,7 +2,6 @@ #include #include "../../constants.h" -#include "../../common/bip32.h" #include "../../ui/ui_application_id.h" #include "../../ergo/address.h" diff --git a/src/commands/deriveaddress/da_handler.c b/src/commands/deriveaddress/da_handler.c index 9c69dd02..75e32afb 100644 --- a/src/commands/deriveaddress/da_handler.c +++ b/src/commands/deriveaddress/da_handler.c @@ -10,25 +10,30 @@ #include "da_ui.h" #include "da_response.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../types.h" #include "../../helpers/crypto.h" -#include "../../common/buffer.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/rwbuffer.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../helpers/session_id.h" #include "../../ergo/address.h" -#define CONTEXT(gcxt) G_context.ctx.derive_address +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" + +static inline int handler_err(derive_address_ctx_t *_ctx, uint16_t err) { + UNUSED(_ctx); + app_set_current_command(CMD_NONE); + return res_error(err); +} int handler_derive_address(buffer_t *cdata, bool display, bool has_access_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + app_set_current_command(CMD_DERIVE_ADDRESS); - clear_context(&G_context, CMD_DERIVE_ADDRESS); + derive_address_ctx_t *ctx = app_derive_address_context(); uint8_t bip32_path_len; uint32_t bip32_path[MAX_BIP32_PATH]; @@ -37,47 +42,38 @@ int handler_derive_address(buffer_t *cdata, bool display, bool has_access_token) uint32_t access_token = 0; uint8_t network_type = 0; - if (!buffer_read_u8(cdata, &network_type)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (!buffer_read_u8(cdata, &bip32_path_len) || - !buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (has_access_token && !buffer_read_u32(cdata, &access_token, BE)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (buffer_can_read(cdata, 1)) { - return res_error(SW_TOO_MUCH_DATA); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &network_type)); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &bip32_path_len)); + CHECK_READ_PARAM(ctx, buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)); + if (has_access_token) { + CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &access_token, BE)); } + CHECK_PARAMS_FINISHED(ctx, cdata); if (!bip32_path_validate(bip32_path, bip32_path_len, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ADDRESS_GE5)) { - return res_error(SW_BIP32_BAD_PATH); + return handler_err(ctx, SW_BIP32_BAD_PATH); } if (crypto_generate_public_key(bip32_path, bip32_path_len, public_key, NULL) != 0) { - return res_error(SW_INTERNAL_CRYPTO_ERROR); + return handler_err(ctx, SW_INTERNAL_CRYPTO_ERROR); } - if (!ergo_address_from_pubkey(network_type, public_key, CONTEXT(G_context).raw_address)) { + if (!ergo_address_from_pubkey(network_type, public_key, ctx->raw_address)) { return res_error(SW_ADDRESS_GENERATION_FAILED); } - if (!display && is_known_application(access_token, G_context.app_session_id)) { - return send_response_address(CONTEXT(G_context).raw_address); + if (!display && is_known_application(access_token, app_connected_app_id())) { + return send_response_address(ctx->raw_address); } - return ui_display_address(&CONTEXT(G_context), + return ui_display_address(ctx, !display, access_token, bip32_path, bip32_path_len, - CONTEXT(G_context).raw_address); + ctx->raw_address); } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_handler.h b/src/commands/deriveaddress/da_handler.h index 4ae714a0..15d725cf 100644 --- a/src/commands/deriveaddress/da_handler.h +++ b/src/commands/deriveaddress/da_handler.h @@ -4,8 +4,7 @@ #include // bool #include // uint*_t -#include "../../types.h" -#include "../../common/buffer.h" +#include /** * Handler for CMD_DERIVE_ADDRESS command. If successfully parse BIP32 path, diff --git a/src/commands/deriveaddress/da_response.c b/src/commands/deriveaddress/da_response.c index 6b595017..27524546 100644 --- a/src/commands/deriveaddress/da_response.c +++ b/src/commands/deriveaddress/da_response.c @@ -6,19 +6,24 @@ #include "../../sw.h" #include "../../constants.h" #include "../../context.h" -#include "../../globals.h" -#include "../../common/buffer.h" +#include "../../common/rwbuffer.h" #include "../../helpers/response.h" #include "../../ergo/address.h" +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" + +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_address(uint8_t address[static P2PK_ADDRESS_LEN]) { - BUFFER_NEW_LOCAL_EMPTY(response, P2PK_ADDRESS_LEN); + RW_BUFFER_NEW_LOCAL_EMPTY(response, P2PK_ADDRESS_LEN); - if (!buffer_write_bytes(&response, address, P2PK_ADDRESS_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, address, P2PK_ADDRESS_LEN)); - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); return res_ok_data(&response); } \ No newline at end of file diff --git a/src/commands/deriveaddress/da_ui.c b/src/commands/deriveaddress/da_ui.c index c0c53996..b9bd1a74 100644 --- a/src/commands/deriveaddress/da_ui.c +++ b/src/commands/deriveaddress/da_ui.c @@ -1,21 +1,21 @@ #include #include #include +#include #include "da_ui.h" #include "da_response.h" #include "da_context.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../common/base58.h" -#include "../../common/macros.h" +#include "../../common/macros_ext.h" #include "../../ergo/address.h" #include "../../helpers/response.h" #include "../../ui/ui_bip32_path.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_da_display_confirm_addr_step, pn, {&C_icon_eye, "Confirm Address"}); @@ -25,29 +25,35 @@ UX_STEP_NOCB(ux_da_display_address_step, bnnn_paging, { .title = "Address", - .text = G_context.ctx.derive_address.address, + .text = G_app_context.commands_ctx.derive_address.address, }); // Action static NOINLINE void ui_action_derive_address(bool approved, void* context) { derive_address_ctx_t* ctx = (derive_address_ctx_t*) context; - G_context.is_ui_busy = true; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); if (ctx->send) { send_response_address(ctx->raw_address); } else { - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); res_ok(); } } else { + app_set_current_command(CMD_NONE); res_deny(); } ui_menu_main(); } +static inline int send_error(uint16_t err) { + app_set_current_command(CMD_NONE); + return res_error(err); +} + // Display int ui_display_address(derive_address_ctx_t* ctx, bool send, @@ -60,15 +66,14 @@ int ui_display_address(derive_address_ctx_t* ctx, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ADDRESS_GE5)) { - return res_error(SW_BIP32_BAD_PATH); + return send_error(SW_BIP32_BAD_PATH); } ctx->app_token_value = app_access_token; ctx->send = send; uint8_t screen = 0; - G_ux_flow[screen++] = - send ? &ux_da_display_confirm_send_step : &ux_da_display_confirm_addr_step; + ui_add_screen(send ? &ux_da_display_confirm_send_step : &ux_da_display_confirm_addr_step, &screen); const ux_flow_step_t* b32_screen = ui_bip32_path_screen(bip32_path, @@ -77,10 +82,9 @@ int ui_display_address(derive_address_ctx_t* ctx, ctx->bip32_path, MEMBER_SIZE(derive_address_ctx_t, bip32_path)); if (b32_screen == NULL) { - return res_error(SW_BIP32_FORMATTING_FAILED); + return send_error(SW_BIP32_FORMATTING_FAILED); } - - G_ux_flow[screen++] = b32_screen; + ui_add_screen(b32_screen, &screen); memset(ctx->address, 0, MEMBER_SIZE(derive_address_ctx_t, address)); if (!send) { @@ -90,27 +94,21 @@ int ui_display_address(derive_address_ctx_t* ctx, MEMBER_SIZE(derive_address_ctx_t, address)); if (result == -1 || result >= P2PK_ADDRESS_STRING_MAX_LEN) { - return res_error(SW_ADDRESS_FORMATTING_FAILED); + return send_error(SW_ADDRESS_FORMATTING_FAILED); } - G_ux_flow[screen++] = &ux_da_display_address_step; + ui_add_screen(&ux_da_display_address_step, &screen); } if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, ctx->app_id); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_id), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_derive_address, ctx, approve, reject); - - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; + ui_approve_reject_screens(ui_action_derive_address, ctx, + ui_next_sreen_ptr(&screen), ui_next_sreen_ptr(&screen)); memmove(ctx->raw_address, raw_address, P2PK_ADDRESS_LEN); - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; + ui_display_screens(&screen); return 0; } diff --git a/src/commands/extpubkey/epk_context.h b/src/commands/extpubkey/epk_context.h index b87ee22e..07fe026f 100644 --- a/src/commands/extpubkey/epk_context.h +++ b/src/commands/extpubkey/epk_context.h @@ -2,7 +2,6 @@ #include #include "../../constants.h" -#include "../../common/bip32.h" #include "../../ui/ui_application_id.h" typedef struct { diff --git a/src/commands/extpubkey/epk_handler.c b/src/commands/extpubkey/epk_handler.c index 231480ec..8ce98e24 100644 --- a/src/commands/extpubkey/epk_handler.c +++ b/src/commands/extpubkey/epk_handler.c @@ -5,71 +5,71 @@ #include #include +#include #include "epk_handler.h" #include "epk_ui.h" #include "epk_response.h" #include "../../sw.h" -#include "../../globals.h" #include "../../context.h" -#include "../../types.h" #include "../../helpers/crypto.h" #include "../../helpers/response.h" -#include "../../common/buffer.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/macros_ext.h" #include "../../helpers/session_id.h" -#define CONTEXT(gctx) gctx.ctx.ext_pub_key + +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" + +static inline int handler_err(extended_public_key_ctx_t *_ctx, uint16_t err) { + UNUSED(_ctx); + app_set_current_command(CMD_NONE); + return res_error(err); +} int handler_get_extended_public_key(buffer_t *cdata, bool has_access_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + app_set_current_command(CMD_GET_EXTENDED_PUBLIC_KEY); - clear_context(&G_context, CMD_GET_EXTENDED_PUBLIC_KEY); + extended_public_key_ctx_t *ctx = app_extended_public_key_context(); uint8_t bip32_path_len; uint32_t bip32_path[MAX_BIP32_PATH]; uint32_t access_token = 0; - if (!buffer_read_u8(cdata, &bip32_path_len) || - !buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (has_access_token && !buffer_read_u32(cdata, &access_token, BE)) { - return res_error(SW_NOT_ENOUGH_DATA); - } - - if (buffer_can_read(cdata, 1)) { - return res_error(SW_TOO_MUCH_DATA); + CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &bip32_path_len)); + CHECK_READ_PARAM(ctx, buffer_read_bip32_path(cdata, bip32_path, (size_t) bip32_path_len)); + if (has_access_token) { + CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &access_token, BE)); } + CHECK_PARAMS_FINISHED(ctx, cdata); if (!bip32_path_validate(bip32_path, bip32_path_len, BIP32_HARDENED(44), BIP32_HARDENED(BIP32_ERGO_COIN), BIP32_PATH_VALIDATE_ACCOUNT_GE3)) { - return res_error(SW_BIP32_BAD_PATH); + return handler_err(ctx, SW_BIP32_BAD_PATH); } if (crypto_generate_public_key(bip32_path, bip32_path_len, - CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code) != 0) { - return res_error(SW_INTERNAL_CRYPTO_ERROR); + ctx->raw_public_key, + ctx->chain_code) != 0) { + return handler_err(ctx, SW_INTERNAL_CRYPTO_ERROR); } - if (is_known_application(access_token, G_context.app_session_id)) { - return send_response_extended_pubkey(CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code); + if (is_known_application(access_token, app_connected_app_id())) { + return send_response_extended_pubkey(ctx->raw_public_key, + ctx->chain_code); } - return ui_display_account(&CONTEXT(G_context), + return ui_display_account(ctx, access_token, bip32_path, bip32_path_len, - CONTEXT(G_context).raw_public_key, - CONTEXT(G_context).chain_code); + ctx->raw_public_key, + ctx->chain_code); } \ No newline at end of file diff --git a/src/commands/extpubkey/epk_handler.h b/src/commands/extpubkey/epk_handler.h index d63ccd6f..3ce9fc75 100644 --- a/src/commands/extpubkey/epk_handler.h +++ b/src/commands/extpubkey/epk_handler.h @@ -4,8 +4,7 @@ #include // bool #include // uint*_t -#include "../../types.h" -#include "../../common/buffer.h" +#include /** * Handler for CMD_GET_EXTENDED_PUBLIC_KEY command. If successfully parse BIP32 path, diff --git a/src/commands/extpubkey/epk_response.c b/src/commands/extpubkey/epk_response.c index 99b30786..f8473e45 100644 --- a/src/commands/extpubkey/epk_response.c +++ b/src/commands/extpubkey/epk_response.c @@ -6,27 +6,27 @@ #include "../../sw.h" #include "../../constants.h" #include "../../context.h" -#include "../../globals.h" -#include "../../common/buffer.h" +#include "../../common/rwbuffer.h" #include "../../helpers/response.h" +#define WRITE_ERROR_HANDLER send_error +#include "../../helpers/cmd_macros.h" + +static inline int send_error(uint16_t error) { + app_set_current_command(CMD_NONE); + return res_error(error); +} + int send_response_extended_pubkey(uint8_t raw_public_key[static PUBLIC_KEY_LEN], uint8_t chain_code[static CHAIN_CODE_LEN]) { - BUFFER_NEW_LOCAL_EMPTY(response, EXTENDED_PUBLIC_KEY_LEN); + RW_BUFFER_NEW_LOCAL_EMPTY(response, EXTENDED_PUBLIC_KEY_LEN); // Compressed pubkey - if (!buffer_write_u8(&response, ((raw_public_key[64] & 1) ? 0x03 : 0x02))) { - return false; - } - if (!buffer_write_bytes(&response, raw_public_key + 1, 32)) { - return false; - } - - if (!buffer_write_bytes(&response, chain_code, CHAIN_CODE_LEN)) { - return res_error(SW_BUFFER_ERROR); - } + CHECK_WRITE_PARAM(rw_buffer_write_u8(&response, ((raw_public_key[64] & 1) ? 0x03 : 0x02))); + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, raw_public_key + 1, 32)); + CHECK_WRITE_PARAM(rw_buffer_write_bytes(&response, chain_code, CHAIN_CODE_LEN)); - clear_context(&G_context, CMD_NONE); + app_set_current_command(CMD_NONE); return res_ok_data(&response); } \ No newline at end of file diff --git a/src/commands/extpubkey/epk_ui.c b/src/commands/extpubkey/epk_ui.c index d7e82df8..74b57d56 100644 --- a/src/commands/extpubkey/epk_ui.c +++ b/src/commands/extpubkey/epk_ui.c @@ -6,26 +6,26 @@ #include "epk_ui.h" #include "epk_response.h" -#include "../../globals.h" #include "../../context.h" #include "../../sw.h" -#include "../../common/bip32.h" -#include "../../common/macros.h" +#include "../../common/bip32_ext.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" #include "../../ui/ui_bip32_path.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" // Step with icon and text UX_STEP_NOCB(ux_epk_display_confirm_ext_pubkey_step, pn, {&C_icon_warning, "Ext PubKey Export"}); static NOINLINE void ui_action_get_extended_pubkey(bool approved, void* context) { extended_public_key_ctx_t* ctx = (extended_public_key_ctx_t*) context; - G_context.is_ui_busy = false; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); send_response_extended_pubkey(ctx->raw_public_key, ctx->chain_code); explicit_bzero(ctx, sizeof(extended_public_key_ctx_t)); } else { @@ -33,6 +33,8 @@ static NOINLINE void ui_action_get_extended_pubkey(bool approved, void* context) res_deny(); } + app_set_current_command(CMD_NONE); + ui_menu_main(); } @@ -51,7 +53,7 @@ int ui_display_account(extended_public_key_ctx_t* ctx, } uint8_t screen = 0; - G_ux_flow[screen++] = &ux_epk_display_confirm_ext_pubkey_step; + ui_add_screen(&ux_epk_display_confirm_ext_pubkey_step, &screen); const ux_flow_step_t* b32_step = ui_bip32_path_screen(bip32_path, @@ -60,28 +62,23 @@ int ui_display_account(extended_public_key_ctx_t* ctx, ctx->bip32_path, MEMBER_SIZE(extended_public_key_ctx_t, bip32_path)); if (b32_step == NULL) { + app_set_current_command(CMD_NONE); return res_error(SW_BIP32_FORMATTING_FAILED); } - G_ux_flow[screen++] = b32_step; + ui_add_screen(b32_step, &screen); if (app_access_token != 0) { - G_ux_flow[screen++] = ui_application_id_screen(app_access_token, ctx->app_token); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_token), &screen); } - const ux_flow_step_t** approve = &G_ux_flow[screen++]; - const ux_flow_step_t** reject = &G_ux_flow[screen++]; - ui_approve_reject_screens(ui_action_get_extended_pubkey, ctx, approve, reject); - - G_ux_flow[screen++] = FLOW_LOOP; - G_ux_flow[screen++] = FLOW_END_STEP; + ui_approve_reject_screens(ui_action_get_extended_pubkey, ctx, + ui_next_sreen_ptr(&screen), ui_next_sreen_ptr(&screen)); ctx->app_token_value = app_access_token; memmove(ctx->raw_public_key, raw_pub_key, PUBLIC_KEY_LEN); memmove(ctx->chain_code, chain_code, CHAIN_CODE_LEN); - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; + ui_display_screens(&screen); return 0; } diff --git a/src/commands/signtx/operations/stx_op_p2pk.c b/src/commands/signtx/operations/stx_op_p2pk.c index 376dd9dc..a6fdbb3a 100644 --- a/src/commands/signtx/operations/stx_op_p2pk.c +++ b/src/commands/signtx/operations/stx_op_p2pk.c @@ -1,28 +1,21 @@ +#include + #include "stx_op_p2pk.h" -#include "../../../common/macros.h" +#include "../../../context.h" +#include "../../../common/macros_ext.h" #include "../../../helpers/crypto.h" #include "../../../helpers/response.h" #include "../../../helpers/sw_result.h" #include "../../../ergo/schnorr.h" #include "../../../ergo/network_id.h" #include "../stx_ui.h" +#include "../../../ui/ui_main.h" -#include - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ - if (_ctx->state != _state1 && _ctx->state != _state2) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_SW_CALL_RESULT_OK(_ctx, _call) \ - do { \ - uint16_t res = _call; \ - if (res != SW_OK) return handler_err(_ctx, res); \ - } while (0) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../../helpers/cmd_macros.h" #define CHECK_TX_CALL_RESULT_OK(_tctx, _tcall) \ - CHECK_SW_CALL_RESULT_OK(_tctx, sw_from_tx_full_result(_tcall)) + CHECK_CALL_RESULT_SW_OK(_tctx, sw_from_tx_full_result(_tcall)) #define CHECK_TX_FINISHED(ctx) \ if (ergo_tx_serializer_full_is_finished(&ctx->transaction.tx)) { \ @@ -31,6 +24,7 @@ static inline uint16_t handler_err(sign_transaction_operation_p2pk_ctx_t *ctx, uint16_t err) { ctx->state = SIGN_TRANSACTION_OPERATION_P2PK_STATE_ERROR; + app_set_current_command(CMD_NONE); return err; } @@ -150,7 +144,7 @@ uint16_t stx_operation_p2pk_add_input(sign_transaction_operation_p2pk_ctx_t *ctx &p2pk_input_token_cb, (void *) ctx)); // Add input value to the amounts - CHECK_SW_CALL_RESULT_OK(ctx, stx_amounts_add_input(&ctx->amounts, erg_amount)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_amounts_add_input(&ctx->amounts, erg_amount)); // Switch state ctx->state = SIGN_TRANSACTION_OPERATION_P2PK_STATE_INPUTS_STARTED; return SW_OK; @@ -242,7 +236,7 @@ uint16_t stx_operation_p2pk_add_output_tree_chunk(sign_transaction_operation_p2p return handler_err(ctx, sw_from_tx_full_result(res)); } // Add chunk to the output info. Uses copied pointers. - CHECK_SW_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_output_info_add_tree_chunk(&ctx->transaction.ui.output, chunk, chunk_len, is_finished)); CHECK_TX_FINISHED(ctx); @@ -255,7 +249,7 @@ uint16_t stx_operation_p2pk_add_output_tree_fee(sign_transaction_operation_p2pk_ ctx, ergo_tx_serializer_full_add_box_miners_fee_tree(&ctx->transaction.tx, network_id_is_mainnet(ctx->network_id))); - CHECK_SW_CALL_RESULT_OK(ctx, stx_output_info_set_fee(&ctx->transaction.ui.output)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_output_info_set_fee(&ctx->transaction.ui.output)); CHECK_TX_FINISHED(ctx); return SW_OK; } @@ -268,7 +262,7 @@ uint16_t stx_operation_p2pk_add_output_tree_change(sign_transaction_operation_p2 CHECK_TX_CALL_RESULT_OK( ctx, ergo_tx_serializer_full_add_box_change_tree(&ctx->transaction.tx, pub_key)); - CHECK_SW_CALL_RESULT_OK(ctx, + CHECK_CALL_RESULT_SW_OK(ctx, stx_output_info_set_bip32(&ctx->transaction.ui.output, path, path_len)); CHECK_TX_FINISHED(ctx); return SW_OK; @@ -321,7 +315,7 @@ uint16_t ui_stx_operation_p2pk_show_token_and_path(sign_transaction_operation_p2 if (b32_step == NULL) { return SW_BIP32_FORMATTING_FAILED; } - G_ux_flow[screen++] = b32_step; + ui_add_screen(b32_step, &screen); if (!ui_stx_add_operation_approve_screens(&ctx->ui_approve.ui_approve, &screen, @@ -360,15 +354,17 @@ static NOINLINE void ui_stx_operation_p2pk_send_response(void *cb_context) { uint8_t secret[PRIVATE_KEY_LEN]; uint8_t signature[ERGO_SIGNATURE_LEN]; - BUFFER_FROM_ARRAY_FULL(res_sig, signature, ERGO_SIGNATURE_LEN); + RW_BUFFER_FROM_ARRAY_FULL(res_sig, signature, ERGO_SIGNATURE_LEN); if (ctx->state != SIGN_TRANSACTION_OPERATION_P2PK_STATE_FINALIZED) { + app_set_current_command(CMD_NONE); res_error(SW_BAD_STATE); return; } if (crypto_generate_private_key(ctx->bip32.path, ctx->bip32.len, secret) != 0) { explicit_bzero(ctx->schnorr_key, PRIVATE_KEY_LEN); + app_set_current_command(CMD_NONE); res_error(SW_INTERNAL_CRYPTO_ERROR); return; } @@ -381,6 +377,7 @@ static NOINLINE void ui_stx_operation_p2pk_send_response(void *cb_context) { if (finished) { res_ok_data(&res_sig); } else { + app_set_current_command(CMD_NONE); res_error(SW_SCHNORR_SIGNING_FAILED); } } diff --git a/src/commands/signtx/operations/stx_op_p2pk.h b/src/commands/signtx/operations/stx_op_p2pk.h index 611719b3..bb2ed078 100644 --- a/src/commands/signtx/operations/stx_op_p2pk.h +++ b/src/commands/signtx/operations/stx_op_p2pk.h @@ -3,7 +3,7 @@ #include "../stx_types.h" #include "../stx_amounts.h" #include "../stx_output.h" -#include "../../../common/bip32.h" +#include "../../../common/bip32_ext.h" #include "../../../ui/ui_application_id.h" #include "../../../ui/ui_bip32_path.h" diff --git a/src/commands/signtx/stx_amounts.c b/src/commands/signtx/stx_amounts.c index d071f604..272f8dbb 100644 --- a/src/commands/signtx/stx_amounts.c +++ b/src/commands/signtx/stx_amounts.c @@ -1,5 +1,5 @@ #include "stx_amounts.h" -#include "../../common/macros.h" +#include "../../common/macros_ext.h" static inline uint8_t find_token_index(const token_table_t *table, const uint8_t id[static ERGO_ID_LEN]) { diff --git a/src/commands/signtx/stx_amounts.h b/src/commands/signtx/stx_amounts.h index 75c9c69d..04e82380 100644 --- a/src/commands/signtx/stx_amounts.h +++ b/src/commands/signtx/stx_amounts.h @@ -5,7 +5,7 @@ #include #include "../../constants.h" #include "../../ergo/tx_ser_full.h" -#include "../../common/int_ops.h" +#include "../../common/safeint.h" #include "../../sw.h" typedef struct { diff --git a/src/commands/signtx/stx_handler.c b/src/commands/signtx/stx_handler.c index 2c0ec73f..59ed114e 100755 --- a/src/commands/signtx/stx_handler.c +++ b/src/commands/signtx/stx_handler.c @@ -1,48 +1,24 @@ +#include + #include "stx_handler.h" #include "stx_response.h" #include "stx_ui.h" -#include "../../globals.h" #include "../../helpers/session_id.h" #include "../../helpers/response.h" -#include "../../common/int_ops.h" -#include "../../common/macros.h" +#include "../../common/safeint.h" +#include "../../common/macros_ext.h" #include "../../helpers/crypto.h" #include "../../helpers/input_frame.h" #include "../../ergo/schnorr.h" #include "./operations/stx_op_p2pk.h" -#include - -#define CONTEXT(gctx) gctx.ctx.sign_tx - -#define CHECK_COMMAND(_cmd) \ - if (_cmd != G_context.current_command) return handler_err(&CONTEXT(G_context), SW_BAD_STATE) - -#define CHECK_SESSION(_session) \ - if (_session != CONTEXT(G_context).session) \ - return handler_err(&CONTEXT(G_context), SW_BAD_SESSION_ID) - -#define CHECK_PROPER_STATE(_ctx, _state) \ - if (_ctx->state != _state) return handler_err(_ctx, SW_BAD_STATE) +#define COMMAND_ERROR_HANDLER handler_err +#include "../../helpers/cmd_macros.h" -#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ - if (_ctx->state != _state1 && _ctx->state != _state2) return handler_err(_ctx, SW_BAD_STATE) - -#define CHECK_READ_PARAM(_ctx, _call) \ - if (!_call) return handler_err(_ctx, SW_NOT_ENOUGH_DATA) - -#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ - if (buffer_can_read(_buffer, 1)) return handler_err(_ctx, SW_TOO_MUCH_DATA) - -#define CHECK_CALL_RESULT_OK(_ctx, _call) \ - do { \ - uint16_t res = _call; \ - if (res != SW_OK) return handler_err(_ctx, res); \ - } while (0) - -static inline int handler_err(sign_transaction_ctx_t *ctx, uint16_t err) { +static inline int handler_err(sign_transaction_ctx_t* ctx, uint16_t err) { ctx->state = SIGN_TRANSACTION_STATE_ERROR; + app_set_current_command(CMD_NONE); return res_error(err); } @@ -70,12 +46,12 @@ static inline uint16_t bip32_public_key(uint32_t path[MAX_BIP32_PATH], return SW_OK; } -static inline int show_output_screen_if_needed(sign_transaction_ctx_t *ctx) { +static inline int show_output_screen_if_needed(sign_transaction_ctx_t* ctx) { // Should have switch for more ops // Check if we have to show screen if (stx_operation_p2pk_should_show_output_confirm_screen(&ctx->p2pk)) { // Show it - CHECK_CALL_RESULT_OK(ctx, ui_stx_operation_p2pk_show_output_confirm_screen(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, ui_stx_operation_p2pk_show_output_confirm_screen(&ctx->p2pk)); return 0; } // We don't need to show confirm screen @@ -89,11 +65,11 @@ static inline int handle_init_p2pk(sign_transaction_ctx_t *ctx, uint32_t app_session_id_in = 0; uint8_t network_id = 0; CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &network_id)); - CHECK_CALL_RESULT_OK(ctx, read_bip32_path(cdata, ctx->p2pk.bip32.path, &ctx->p2pk.bip32.len)); + CHECK_CALL_RESULT_SW_OK(ctx, read_bip32_path(cdata, ctx->p2pk.bip32.path, &ctx->p2pk.bip32.len)); CHECK_READ_PARAM(ctx, !(has_token && !buffer_read_u32(cdata, &app_session_id_in, BE))); CHECK_PARAMS_FINISHED(ctx, cdata); - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_init(&ctx->p2pk, ctx->p2pk.bip32.path, ctx->p2pk.bip32.len, network_id)); @@ -102,12 +78,12 @@ static inline int handle_init_p2pk(sign_transaction_ctx_t *ctx, ctx->session = session_id_new_random(ctx->session); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, - ui_stx_operation_p2pk_show_token_and_path( - &ctx->p2pk, - app_session_id_in, - is_known_application(app_session_id, app_session_id_in), - ctx)); + CHECK_CALL_RESULT_SW_OK(ctx, + ui_stx_operation_p2pk_show_token_and_path( + &ctx->p2pk, + app_session_id_in, + is_known_application(app_session_id, app_session_id_in), + ctx)); return 0; } @@ -123,24 +99,24 @@ static inline int handle_tx_start(sign_transaction_ctx_t *ctx, buffer_t *cdata) CHECK_PARAMS_FINISHED(ctx, cdata); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_start_tx(&ctx->p2pk, - inputs_count, - data_inputs_count, - outputs_count, - tokens_count)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_start_tx(&ctx->p2pk, + inputs_count, + data_inputs_count, + outputs_count, + tokens_count)); return res_ok(); } static inline int handle_tokens(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // switch between operations if more will be added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_tokens(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_tokens(&ctx->p2pk, cdata)); return res_ok(); } static inline int handle_input_frame(sign_transaction_ctx_t *ctx, - uint8_t session_key[static SESSION_KEY_LEN], + const uint8_t session_key[static SESSION_KEY_LEN], buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); uint8_t id_buffer[ERGO_ID_LEN]; @@ -167,7 +143,7 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, buffer_t tokens; uint8_t frames_count, frame_index, tokens_count; - CHECK_READ_PARAM(ctx, buffer_read_bytes(cdata, id_buffer, ERGO_ID_LEN)); + CHECK_READ_PARAM(ctx, buffer_move(cdata, id_buffer, ERGO_ID_LEN)); CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &frames_count)); CHECK_READ_PARAM(ctx, buffer_read_u8(cdata, &frame_index)); CHECK_READ_PARAM(ctx, buffer_read_u64(cdata, &value, BE)); @@ -175,9 +151,9 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, // Tokens sub buffer uint8_t tokens_len = tokens_count * FRAME_TOKEN_VALUE_PAIR_SIZE; - buffer_init(&tokens, buffer_read_ptr(cdata), tokens_len, tokens_len); + buffer_init(&tokens, buffer_read_ptr(cdata), tokens_len); // Seek to the frame end - if (!buffer_seek_read_cur(cdata, tokens_len + INPUT_FRAME_SIGNATURE_LEN)) { + if (!buffer_seek_cur(cdata, tokens_len + INPUT_FRAME_SIGNATURE_LEN)) { return handler_err(ctx, SW_NOT_ENOUGH_DATA); } // New input @@ -187,15 +163,15 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, CHECK_READ_PARAM(ctx, buffer_read_u32(cdata, &extension_len, BE)); // Add new input. Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_add_input(&ctx->p2pk, - id_buffer, - value, - frames_count, - extension_len)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_add_input(&ctx->p2pk, + id_buffer, + value, + frames_count, + extension_len)); } // Add tokens to the input. Swould be switch if more ops added - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_add_input_tokens(&ctx->p2pk, id_buffer, frame_index, &tokens)); @@ -205,14 +181,14 @@ static inline int handle_input_frame(sign_transaction_ctx_t *ctx, static inline int handle_input_context_extension(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_input_context_extension(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_input_context_extension(&ctx->p2pk, cdata)); return res_ok(); } static inline int handle_data_inputs(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_data_inputs(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_data_inputs(&ctx->p2pk, cdata)); return res_ok(); } @@ -230,20 +206,20 @@ static inline int handle_output_init(sign_transaction_ctx_t *ctx, buffer_t *cdat CHECK_PARAMS_FINISHED(ctx, cdata); // Add box. Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - stx_operation_p2pk_add_output(&ctx->p2pk, - value, - ergo_tree_size, - creation_height, - tokens_count, - registers_size)); + CHECK_CALL_RESULT_SW_OK(ctx, + stx_operation_p2pk_add_output(&ctx->p2pk, + value, + ergo_tree_size, + creation_height, + tokens_count, + registers_size)); return res_ok(); } static inline int handle_output_tree_chunk(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tree_chunk(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tree_chunk(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } @@ -251,7 +227,7 @@ static inline int handle_output_tree_fee(sign_transaction_ctx_t *ctx, buffer_t * CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); CHECK_PARAMS_FINISHED(ctx, cdata); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tree_fee(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tree_fee(&ctx->p2pk)); return show_output_screen_if_needed(ctx); } @@ -259,15 +235,15 @@ static inline int handle_output_tree_change(sign_transaction_ctx_t *ctx, buffer_ CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); uint8_t public_key[PUBLIC_KEY_LEN]; // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, - read_bip32_path(cdata, - ctx->p2pk.transaction.ui.output.bip32_path.path, - &ctx->p2pk.transaction.ui.output.bip32_path.len)); - CHECK_CALL_RESULT_OK(ctx, - bip32_public_key(ctx->p2pk.transaction.ui.output.bip32_path.path, - ctx->p2pk.transaction.ui.output.bip32_path.len, - public_key)); - CHECK_CALL_RESULT_OK( + CHECK_CALL_RESULT_SW_OK(ctx, + read_bip32_path(cdata, + ctx->p2pk.transaction.ui.output.bip32_path.path, + &ctx->p2pk.transaction.ui.output.bip32_path.len)); + CHECK_CALL_RESULT_SW_OK(ctx, + bip32_public_key(ctx->p2pk.transaction.ui.output.bip32_path.path, + ctx->p2pk.transaction.ui.output.bip32_path.len, + public_key)); + CHECK_CALL_RESULT_SW_OK( ctx, stx_operation_p2pk_add_output_tree_change(&ctx->p2pk, ctx->p2pk.transaction.ui.output.bip32_path.path, @@ -279,89 +255,91 @@ static inline int handle_output_tree_change(sign_transaction_ctx_t *ctx, buffer_ static inline int handle_output_tokens(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_tokens(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_tokens(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } static inline int handle_output_registers(sign_transaction_ctx_t *ctx, buffer_t *cdata) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, stx_operation_p2pk_add_output_registers(&ctx->p2pk, cdata)); + CHECK_CALL_RESULT_SW_OK(ctx, stx_operation_p2pk_add_output_registers(&ctx->p2pk, cdata)); return show_output_screen_if_needed(ctx); } static inline int handle_sign_confirm(sign_transaction_ctx_t *ctx) { CHECK_PROPER_STATE(ctx, SIGN_TRANSACTION_STATE_APPROVED); // Should be switch if more ops added - CHECK_CALL_RESULT_OK(ctx, ui_stx_operation_p2pk_show_confirm_screen(&ctx->p2pk)); + CHECK_CALL_RESULT_SW_OK(ctx, ui_stx_operation_p2pk_show_confirm_screen(&ctx->p2pk)); return 0; } int handler_sign_transaction(buffer_t *cdata, sign_transaction_subcommand_e subcommand, uint8_t session_or_token) { - if (G_context.is_ui_busy) { + if (app_is_ui_busy()) { return res_ui_busy(); } + sign_transaction_ctx_t *ctx = app_sign_transaction_context(); switch (subcommand) { case SIGN_TRANSACTION_SUBCOMMAND_SIGN_PK: if (session_or_token != 0x01 && session_or_token != 0x02) { return res_error(SW_WRONG_P1P2); } - clear_context(&G_context, CMD_SIGN_TRANSACTION); - return handle_init_p2pk(&CONTEXT(G_context), + app_set_current_command(CMD_SIGN_TRANSACTION); + + return handle_init_p2pk(ctx, cdata, session_or_token == 0x02, - G_context.app_session_id); + app_connected_app_id()); case SIGN_TRANSACTION_SUBCOMMAND_START_TX: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_tx_start(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_tx_start(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_TOKEN_IDS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_tokens(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_INPUT_FRAME: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_input_frame(&CONTEXT(G_context), G_context.session_key, cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_input_frame(ctx, app_session_key(), cdata); case SIGN_TRANSACTION_SUBCOMMAND_INPUT_CONTEXT_EXTENSION: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_input_context_extension(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_input_context_extension(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_DATA_INPUT: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_data_inputs(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_data_inputs(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_init(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_init(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_TREE_CHUNK: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_chunk(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_chunk(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_MINERS_FEE_TREE: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_fee(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_fee(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_CHANGE_TREE: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tree_change(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tree_change(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_TOKENS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_tokens(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_tokens(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_OUTPUT_REGISTERS: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_output_registers(&CONTEXT(G_context), cdata); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_output_registers(ctx, cdata); case SIGN_TRANSACTION_SUBCOMMAND_CONFIRM: - CHECK_COMMAND(CMD_SIGN_TRANSACTION); - CHECK_SESSION(session_or_token); - return handle_sign_confirm(&CONTEXT(G_context)); + CHECK_COMMAND(ctx, CMD_SIGN_TRANSACTION); + CHECK_SESSION(ctx, session_or_token); + return handle_sign_confirm(ctx); default: - return res_error(SW_WRONG_SUBCOMMAND); + return handler_err(ctx, SW_WRONG_SUBCOMMAND); } } diff --git a/src/commands/signtx/stx_handler.h b/src/commands/signtx/stx_handler.h index ff4076bb..28bf5eb7 100755 --- a/src/commands/signtx/stx_handler.h +++ b/src/commands/signtx/stx_handler.h @@ -4,8 +4,9 @@ #include // bool #include // uint*_t +#include + #include "stx_context.h" -#include "../../common/buffer.h" typedef enum { SIGN_TRANSACTION_SUBCOMMAND_SIGN_PK = 0x01, diff --git a/src/commands/signtx/stx_output.c b/src/commands/signtx/stx_output.c index d3f4fa86..d0d15e9a 100644 --- a/src/commands/signtx/stx_output.c +++ b/src/commands/signtx/stx_output.c @@ -1,7 +1,6 @@ #include "stx_output.h" #include "../../sw.h" -#include "../../common/macros.h" -#include "../../common/base58.h" +#include "../../common/macros_ext.h" #include "../../ergo/ergo_tree.h" #include "../../ergo/address.h" #include "../../helpers/sw_result.h" diff --git a/src/commands/signtx/stx_output.h b/src/commands/signtx/stx_output.h index 18ec74d7..7a15807a 100644 --- a/src/commands/signtx/stx_output.h +++ b/src/commands/signtx/stx_output.h @@ -5,7 +5,7 @@ #include // uint*_t #include // memset -#include "../../common/bip32.h" +#include "../../common/bip32_ext.h" #include "../../constants.h" #include "../../helpers/blake2b.h" #include "../../ergo/tx_ser_full.h" diff --git a/src/commands/signtx/stx_response.c b/src/commands/signtx/stx_response.c index 7c98445b..8f0ab3f8 100755 --- a/src/commands/signtx/stx_response.c +++ b/src/commands/signtx/stx_response.c @@ -1,8 +1,7 @@ #include "stx_response.h" -#include "../../globals.h" #include "../../helpers/response.h" int send_response_sign_transaction_session_id(uint8_t session_id) { - BUFFER_FROM_VAR_FULL(buf, session_id); + RW_BUFFER_FROM_VAR_FULL(buf, session_id); return res_ok_data(&buf); } diff --git a/src/commands/signtx/stx_ui.c b/src/commands/signtx/stx_ui.c index 9b4f035b..5f69f736 100644 --- a/src/commands/signtx/stx_ui.c +++ b/src/commands/signtx/stx_ui.c @@ -1,21 +1,22 @@ #include #include #include +#include +#include #include "stx_ui.h" #include "stx_response.h" -#include "../../globals.h" -#include "../../common/macros.h" +#include "../../context.h" +#include "../../common/macros_ext.h" #include "../../helpers/response.h" -#include "../../common/int_ops.h" -#include "../../common/base58.h" -#include "../../common/format.h" +#include "../../common/safeint.h" #include "../../ergo/address.h" #include "../../ui/ui_application_id.h" #include "../../ui/ui_approve_reject.h" #include "../../ui/ui_dynamic_flow.h" #include "../../ui/ui_menu.h" +#include "../../ui/ui_main.h" #ifdef TARGET_NANOS #define ERGO_ID_UI_CHARACTERS_HALF 7 @@ -66,13 +67,14 @@ static NOINLINE void ui_stx_operation_approve_action(bool approved, void* contex sign_transaction_ui_aprove_ctx_t* ctx = (sign_transaction_ui_aprove_ctx_t*) context; sign_transaction_ctx_t* sign_tx = (sign_transaction_ctx_t*) ctx->sign_tx_context; - G_context.is_ui_busy = false; + app_set_ui_busy(false); if (approved) { - G_context.app_session_id = ctx->app_token_value; + app_set_connected_app_id(ctx->app_token_value); sign_tx->state = SIGN_TRANSACTION_STATE_APPROVED; send_response_sign_transaction_session_id(sign_tx->session); } else { + app_set_current_command(CMD_NONE); res_deny(); } @@ -87,15 +89,15 @@ bool ui_stx_add_operation_approve_screens(sign_transaction_ui_aprove_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 3) return false; if (!is_known_application) { - G_ux_flow[(*screen)++] = ui_application_id_screen(app_access_token, ctx->app_token); + ui_add_screen(ui_application_id_screen(app_access_token, ctx->app_token), screen); } ctx->app_token_value = app_access_token; ctx->sign_tx_context = sign_tx; ctx->is_known_application = is_known_application; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_approve_action, ctx, approve, reject); + ui_approve_reject_screens(ui_stx_operation_approve_action, ctx, + ui_next_sreen_ptr(screen), + ui_next_sreen_ptr(screen)); return true; } @@ -209,12 +211,15 @@ static NOINLINE uint16_t ui_stx_display_output_state(uint8_t screen, static NOINLINE void ui_stx_operation_output_confirm_action(bool approved, void* context) { UNUSED(context); - G_context.is_ui_busy = false; + app_set_ui_busy(false); + if (approved) { res_ok(); } else { + app_set_current_command(CMD_NONE); res_deny(); } + ui_menu_main(); } @@ -226,7 +231,7 @@ bool ui_stx_add_output_screens(sign_transaction_ui_output_confirm_ctx_t* ctx, memset(ctx, 0, sizeof(sign_transaction_ui_output_confirm_ctx_t)); - G_ux_flow[(*screen)++] = &ux_stx_display_output_confirm_step; + ui_add_screen(&ux_stx_display_output_confirm_step, screen); uint8_t info_screen_count = 1; // Address screen if (stx_output_info_type(output) != SIGN_TRANSACTION_OUTPUT_INFO_TYPE_BIP32) { @@ -244,9 +249,8 @@ bool ui_stx_add_output_screens(sign_transaction_ui_output_confirm_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 2) return false; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_output_confirm_action, NULL, approve, reject); + ui_approve_reject_screens(ui_stx_operation_output_confirm_action, + NULL, ui_next_sreen_ptr(screen), ui_next_sreen_ptr(screen)); ctx->network_id = network_id; ctx->output = output; @@ -322,14 +326,16 @@ static NOINLINE uint16_t ui_stx_display_tx_state(uint8_t screen, // TX approve/reject callback static NOINLINE void ui_stx_operation_execute_action(bool approved, void* context) { - G_context.is_ui_busy = false; + app_set_ui_busy(false); + sign_transaction_ui_sign_confirm_ctx_t* ctx = (sign_transaction_ui_sign_confirm_ctx_t*) context; if (approved) { ctx->op_response_cb(ctx->op_cb_context); } else { res_deny(); } - clear_context(&G_context, CMD_NONE); + + app_set_current_command(CMD_NONE); ui_menu_main(); } @@ -346,7 +352,7 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, uint8_t tokens_count = stx_amounts_non_zero_tokens_count(amounts); - G_ux_flow[(*screen)++] = &ux_stx_display_sign_confirm_step; + ui_add_screen(&ux_stx_display_sign_confirm_step, screen); if (!ui_add_dynamic_flow_screens(screen, op_screen_count + 2 + (2 * tokens_count), @@ -358,9 +364,8 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, if (MAX_NUMBER_OF_SCREENS - *screen < 2) return false; - const ux_flow_step_t** approve = &G_ux_flow[(*screen)++]; - const ux_flow_step_t** reject = &G_ux_flow[(*screen)++]; - ui_approve_reject_screens(ui_stx_operation_execute_action, ctx, approve, reject); + ui_approve_reject_screens(ui_stx_operation_execute_action, ctx, + ui_next_sreen_ptr(screen), ui_next_sreen_ptr(screen)); ctx->op_screen_count = op_screen_count; ctx->op_screen_cb = screen_cb; @@ -372,14 +377,5 @@ bool ui_stx_add_transaction_screens(sign_transaction_ui_sign_confirm_ctx_t* ctx, } bool ui_stx_display_screens(uint8_t screen_count) { - if (MAX_NUMBER_OF_SCREENS - screen_count < 2) return false; - - G_ux_flow[screen_count++] = FLOW_LOOP; - G_ux_flow[screen_count++] = FLOW_END_STEP; - - ux_flow_init(0, G_ux_flow, NULL); - - G_context.is_ui_busy = true; - - return true; + return ui_display_screens(&screen_count); } diff --git a/src/common/base58.c b/src/common/base58.c deleted file mode 100644 index 0965abfd..00000000 --- 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 f214afd8..00000000 --- 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.h b/src/common/bip32.h deleted file mode 100644 index 6b501ad7..00000000 --- a/src/common/bip32.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include // size_t -#include // uint*_t -#include // bool - -/** - * Maximum length of BIP32 path allowed. - */ -#define MAX_BIP32_PATH 10 - -#define BIP32_HARDENED_CONSTANT 0x80000000u - -#define BIP32_HARDENED(x) (BIP32_HARDENED_CONSTANT + x) - -typedef enum { - BIP32_PATH_VALIDATE_COIN, - BIP32_PATH_VALIDATE_COIN_GE2_HARD, - BIP32_PATH_VALIDATE_ACCOUNT_E3, - BIP32_PATH_VALIDATE_ACCOUNT_GE3, - BIP32_PATH_VALIDATE_ADDRESS_E5, - BIP32_PATH_VALIDATE_ADDRESS_GE5 -} bip32_path_validation_type_e; - -/** - * 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, uint8_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); - -bool bip32_path_validate(const uint32_t *bip32_path, - uint8_t bip32_path_len, - uint32_t type, - uint32_t coin, - bip32_path_validation_type_e vtype); diff --git a/src/common/bip32.c b/src/common/bip32_ext.c similarity index 60% rename from src/common/bip32.c rename to src/common/bip32_ext.c index 286483e4..60994a7f 100644 --- a/src/common/bip32.c +++ b/src/common/bip32_ext.c @@ -20,74 +20,7 @@ #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, uint8_t out_len) { - if (out_len == 0 || out_len > MAX_BIP32_PATH) { - return false; - } - - uint8_t offset = 0; - - for (uint8_t i = 0; i < out_len; i++) { - if (offset + 4 > 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] & (BIP32_HARDENED_CONSTANT - 1)); - written = strlen(out + offset); - if (written == 0 || written >= out_len - offset) { - memset(out, 0, out_len); - return false; - } - offset += written; - - if ((bip32_path[i] & BIP32_HARDENED_CONSTANT) != 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; -} +#include "bip32_ext.h" bool bip32_path_validate(const uint32_t *bip32_path, uint8_t bip32_path_len, diff --git a/src/common/bip32_ext.h b/src/common/bip32_ext.h new file mode 100644 index 00000000..1ca16a8b --- /dev/null +++ b/src/common/bip32_ext.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#define BIP32_HARDENED_CONSTANT 0x80000000u + +#define BIP32_HARDENED(x) (BIP32_HARDENED_CONSTANT + x) + +typedef enum { + BIP32_PATH_VALIDATE_COIN, + BIP32_PATH_VALIDATE_COIN_GE2_HARD, + BIP32_PATH_VALIDATE_ACCOUNT_E3, + BIP32_PATH_VALIDATE_ACCOUNT_GE3, + BIP32_PATH_VALIDATE_ADDRESS_E5, + BIP32_PATH_VALIDATE_ADDRESS_GE5 +} bip32_path_validation_type_e; + +bool bip32_path_validate(const uint32_t *bip32_path, + uint8_t bip32_path_len, + uint32_t type, + uint32_t coin, + bip32_path_validation_type_e vtype); diff --git a/src/common/buffer.c b/src/common/buffer.c deleted file mode 100755 index 8a936e48..00000000 --- a/src/common/buffer.c +++ /dev/null @@ -1,241 +0,0 @@ -#include // uint*_t -#include // size_t -#include // bool -#include // memmove - -#include "buffer.h" -#include "read.h" -#include "write.h" -#include "bip32.h" - -bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->write_offset) { - return false; - } - - buffer->read_offset = offset; - - return true; -} - -bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset) { - if (buffer->read_offset + offset < buffer->read_offset || // overflow - buffer->read_offset + offset > buffer->write_offset) { // exceed buffer size - return false; - } - - buffer->read_offset += offset; - - return true; -} - -bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->write_offset) { - return false; - } - - buffer->read_offset = buffer->write_offset - offset; - - return true; -} - -bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->write_offset = offset; - - return true; -} - -bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset) { - if (buffer->write_offset + offset < buffer->write_offset || // overflow - buffer->write_offset + offset > buffer->size) { // exceed buffer size - return false; - } - - buffer->write_offset += offset; - - return true; -} - -bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset) { - if (offset > buffer->size) { - return false; - } - - buffer->write_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->read_offset]; - buffer_seek_read_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->read_offset) - : read_u16_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_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->read_offset) - : read_u32_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_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->read_offset) - : read_u64_le(buffer->ptr, buffer->read_offset)); - - buffer_seek_read_cur(buffer, 8); - - return true; -} - -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len) { - if (!bip32_path_read(buffer->ptr + buffer->read_offset, - buffer->write_offset - buffer->read_offset, - out, - out_len)) { - return false; - } - - buffer_seek_read_cur(buffer, sizeof(*out) * out_len); - - return true; -} - -bool buffer_write_u8(buffer_t *buffer, uint8_t value) { - if (!buffer_can_write(buffer, 1)) { - return false; - } - - buffer->ptr[buffer->write_offset] = value; - buffer_seek_write_cur(buffer, 1); - - return true; -} - -bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 2)) { - return false; - } - - if (endianness == BE) { - write_u16_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u16_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 2); - - return true; -} - -bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 4)) { - return false; - } - - if (endianness == BE) { - write_u32_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u32_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 4); - - return true; -} - -bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness) { - if (!buffer_can_write(buffer, 8)) { - return false; - } - - if (endianness == BE) { - write_u64_be(buffer->ptr, buffer->write_offset, value); - } else { - write_u64_le(buffer->ptr, buffer->write_offset, value); - } - - buffer_seek_write_cur(buffer, 8); - - return true; -} - -bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len) { - if (buffer_data_len(buffer) < out_len) { - return false; - } - - memmove(out, buffer->ptr + buffer->read_offset, out_len); - - buffer_seek_read_cur(buffer, out_len); - - return true; -} - -bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len) { - if (buffer_data_len(buffer) > out_len) { - return false; - } - memmove(out, buffer->ptr + buffer->read_offset, buffer_data_len(buffer)); - return true; -} - -bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len) { - if (!buffer_can_write(buffer, from_len)) { - return false; - } - - memcpy(buffer->ptr + buffer->write_offset, from, from_len); - - buffer_seek_write_cur(buffer, from_len); - - return true; -} - -void buffer_shift_data(buffer_t *buffer) { - if (buffer->read_offset == 0) return; - size_t data_len = buffer_data_len(buffer); - memmove(buffer->ptr, buffer->ptr + buffer->read_offset, data_len); - buffer->write_offset = data_len; - buffer->read_offset = 0; -} diff --git a/src/common/buffer_ext.h b/src/common/buffer_ext.h new file mode 100644 index 00000000..d7661f11 --- /dev/null +++ b/src/common/buffer_ext.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +/** + * Initialize buffer. + * + * @param[out] buffer + * Pointer to input buffer struct. + * @param[in] ptr + * Pointer to byte buffert. + * @param[in] data_size + * Data size of the buffer. + * + */ +static inline void buffer_init(buffer_t *buffer, + const uint8_t *ptr, + size_t data_size) { + buffer->ptr = ptr; + buffer->offset = 0; + buffer->size = data_size; +} + +/** + * Return read pointer to the start of the data. + * + * @param[in] buffer + * Pointer to input buffer struct. + * + */ +static inline const uint8_t *buffer_read_ptr(const buffer_t *buffer) { + return buffer->ptr + buffer->offset; +} + +/** + * Tell whether buffer has bytes to read or not. + * + * @param[in] buffer + * Pointer to input buffer struct. + * + * @return length of the data in buffer. + * + */ +static inline size_t buffer_data_len(const buffer_t *buffer) { + return buffer->size - buffer->offset; +} \ No newline at end of file diff --git a/src/common/format.c b/src/common/format.c deleted file mode 100644 index ede55c44..00000000 --- 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" - -int 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 -1; - } - - size_t index = 0; - - while (--ptr >= temp) { - dst[index++] = *ptr; - } - - dst[index] = '\0'; - - return index; -} - -int 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 -1; - } - } - out[i] = in + '0'; - out[i + 1] = '\0'; - - uint8_t j = 0, count = i + 1; - 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 count; -} - -int 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) <= 0) { - return -1; - } - - size_t digits = strlen(buffer); - - if (digits <= decimals) { - if (dst_len <= 2 + decimals - digits) { - return -1; - } - *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); - return 2 + decimals; - } else { - if (dst_len <= digits + 1 + decimals) { - return -1; - } - - const size_t shift = digits - decimals; - memmove(dst, buffer, shift); - dst[shift] = '.'; - strncpy(dst + shift + 1, buffer + shift, decimals); - return digits + 1; - } -} - -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; -} diff --git a/src/common/format.h b/src/common/format.h deleted file mode 100644 index 1dc5c55f..00000000 --- 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 number of bytes written if success, -1 otherwise. - * - */ -int 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 number of bytes written if success, -1 otherwise. - * - */ -int 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 number of bytes written if success, -1 otherwise. - * - */ -int format_fpu64(char *dst, size_t dst_len, const uint64_t value, uint8_t decimals); - -/** - * Format byte buffer to lowercase 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/varint.c b/src/common/gve.c similarity index 92% rename from src/common/varint.c rename to src/common/gve.c index a1222fee..5e604690 100644 --- a/src/common/varint.c +++ b/src/common/gve.c @@ -5,7 +5,7 @@ // Created by Yehor Popovych on 11.08.2021. // -#include "varint.h" +#include "gve.h" gve_result_e gve_get_i16(buffer_t *buffer, int16_t *val) { int32_t i32; @@ -73,7 +73,7 @@ gve_result_e gve_get_u64(buffer_t *buffer, uint64_t *val) { return res; } -gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val) { +gve_result_e gve_put_u64(rw_buffer_t *buffer, uint64_t val) { uint8_t out[10]; size_t i = 0; do { @@ -82,6 +82,5 @@ gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val) { if (val) byte |= 0x80U; out[i++] = byte; } while (val); - return buffer_write_bytes(buffer, out, i) ? GVE_OK : GVE_ERR_DATA_SIZE; - ; + return rw_buffer_write_bytes(buffer, out, i) ? GVE_OK : GVE_ERR_DATA_SIZE; } diff --git a/src/common/varint.h b/src/common/gve.h similarity index 63% rename from src/common/varint.h rename to src/common/gve.h index ce8e6fd4..308ac5e3 100755 --- a/src/common/varint.h +++ b/src/common/gve.h @@ -9,8 +9,8 @@ #include #include +#include "rwbuffer.h" #include "zigzag.h" -#include "buffer.h" typedef enum { GVE_OK = 0, GVE_ERR_INT_TO_BIG, GVE_ERR_DATA_SIZE } gve_result_e; @@ -29,32 +29,32 @@ gve_result_e gve_get_u32(buffer_t *buffer, uint32_t *val); gve_result_e gve_get_i64(buffer_t *buffer, int64_t *val); gve_result_e gve_get_u64(buffer_t *buffer, uint64_t *val); -gve_result_e gve_put_u64(buffer_t *buffer, uint64_t val); +gve_result_e gve_put_u64(rw_buffer_t *buffer, uint64_t val); -static inline gve_result_e gve_put_i64(buffer_t *buffer, int64_t val) { +static inline gve_result_e gve_put_i64(rw_buffer_t *buffer, int64_t val) { return gve_put_u64(buffer, zigzag_encode_i64(val)); } -static inline gve_result_e gve_put_u32(buffer_t *buffer, uint32_t val) { +static inline gve_result_e gve_put_u32(rw_buffer_t *buffer, uint32_t val) { return gve_put_u64(buffer, val); } -static inline gve_result_e gve_put_i32(buffer_t *buffer, int32_t val) { +static inline gve_result_e gve_put_i32(rw_buffer_t *buffer, int32_t val) { return gve_put_u64(buffer, zigzag_encode_i32(val)); } -static inline gve_result_e gve_put_u8(buffer_t *buffer, uint8_t val) { - return buffer_write_bytes(buffer, &val, 1) ? GVE_OK : GVE_ERR_DATA_SIZE; +static inline gve_result_e gve_put_u8(rw_buffer_t *buffer, uint8_t val) { + return rw_buffer_write_u8(buffer, val) ? GVE_OK : GVE_ERR_DATA_SIZE; } -static inline gve_result_e gve_put_i8(buffer_t *buffer, int8_t val) { +static inline gve_result_e gve_put_i8(rw_buffer_t *buffer, int8_t val) { return gve_put_u8(buffer, (uint8_t) val); } -static inline gve_result_e gve_put_i16(buffer_t *buffer, int16_t val) { +static inline gve_result_e gve_put_i16(rw_buffer_t *buffer, int16_t val) { return gve_put_u32(buffer, (uint32_t) zigzag_encode_i32(val)); } -static inline gve_result_e gve_put_u16(buffer_t *buffer, uint16_t val) { +static inline gve_result_e gve_put_u16(rw_buffer_t *buffer, uint16_t val) { return gve_put_u64(buffer, val); } diff --git a/src/common/macros.h b/src/common/macros_ext.h similarity index 69% rename from src/common/macros.h rename to src/common/macros_ext.h index 4a6f4000..f4d085d3 100644 --- a/src/common/macros.h +++ b/src/common/macros_ext.h @@ -1,9 +1,6 @@ #pragma once -/** - * Macro for the size of a specific structure field. - */ -#define MEMBER_SIZE(type, member) (sizeof(((type *) 0)->member)) +#include /** * Macro for disabling inlining for function (GCC & Clang) diff --git a/src/common/read.c b/src/common/read.c deleted file mode 100644 index c8ee851f..00000000 --- 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 61cfa8c0..00000000 --- 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/rwbuffer.c b/src/common/rwbuffer.c new file mode 100755 index 00000000..6f8f3f9f --- /dev/null +++ b/src/common/rwbuffer.c @@ -0,0 +1,111 @@ +#include // uint*_t +#include // size_t +#include // bool +#include // memmove + +#include +#include "rwbuffer.h" + +bool rw_buffer_seek_write_set(rw_buffer_t *buffer, size_t offset) { + if (offset > buffer->size) { + return false; + } + buffer->read.size = offset; + return true; +} + +bool rw_buffer_seek_write_cur(rw_buffer_t *buffer, size_t offset) { + if (buffer->read.size + offset < buffer->read.size || // overflow + buffer->read.size + offset > buffer->size) { // exceed buffer size + return false; + } + buffer->read.size += offset; + return true; +} + +bool rw_buffer_seek_write_end(rw_buffer_t *buffer, size_t offset) { + if (offset > buffer->size) { + return false; + } + buffer->read.size = buffer->size - offset; + return true; +} + +bool rw_buffer_write_u8(rw_buffer_t *buffer, uint8_t value) { + if (!rw_buffer_can_write(buffer, 1)) { + return false; + } + + ((uint8_t *)buffer->read.ptr)[buffer->read.size] = value; + + rw_buffer_seek_write_cur(buffer, 1); + return true; +} + +bool rw_buffer_write_u16(rw_buffer_t *buffer, uint16_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 2)) { + return false; + } + + if (endianness == BE) { + write_u16_be((uint8_t*)buffer->read.ptr, buffer->read.size, value); + } else { + write_u16_le((uint8_t*)buffer->read.ptr, buffer->read.size, value); + } + + rw_buffer_seek_write_cur(buffer, 2); + + return true; +} + +bool rw_buffer_write_u32(rw_buffer_t *buffer, uint32_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 4)) { + return false; + } + + if (endianness == BE) { + write_u32_be((uint8_t*)buffer->read.ptr, buffer->size, value); + } else { + write_u32_le((uint8_t*)buffer->read.ptr, buffer->size, value); + } + + rw_buffer_seek_write_cur(buffer, 4); + + return true; +} + +bool rw_buffer_write_u64(rw_buffer_t *buffer, uint64_t value, endianness_t endianness) { + if (!rw_buffer_can_write(buffer, 8)) { + return false; + } + + if (endianness == BE) { + write_u64_be((uint8_t*)buffer->read.ptr, buffer->size, value); + } else { + write_u64_le((uint8_t*)buffer->read.ptr, buffer->size, value); + } + + rw_buffer_seek_write_cur(buffer, 8); + + return true; +} + +bool rw_buffer_write_bytes(rw_buffer_t *buffer, const uint8_t *from, size_t from_len) { + if (!rw_buffer_can_write(buffer, from_len)) { + return false; + } + + memmove((uint8_t*)buffer->read.ptr + buffer->size, from, from_len); + + rw_buffer_seek_write_cur(buffer, from_len); + + return true; +} + +void rw_buffer_shift_data(rw_buffer_t *buffer) { + if (buffer->read.offset == 0) return; + size_t data_len = rw_buffer_data_len(buffer); + memmove((uint8_t*)buffer->read.ptr, buffer->read.ptr + buffer->read.offset, data_len); + buffer->read.size = data_len; + buffer->read.offset = 0; +} diff --git a/src/common/buffer.h b/src/common/rwbuffer.h similarity index 60% rename from src/common/buffer.h rename to src/common/rwbuffer.h index 70dd4fcf..e0f1de97 100755 --- a/src/common/buffer.h +++ b/src/common/rwbuffer.h @@ -1,47 +1,36 @@ #pragma once -#include // uint*_t -#include // size_t -#include // bool +#include "buffer_ext.h" -#define BUFFER_FROM_ARRAY_FULL(name, array, size) \ - buffer_t name; \ - buffer_init(&name, array, size, size) +#define RW_BUFFER_FROM_ARRAY_FULL(_name, _array, _size) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, _array, _size, _size) -#define BUFFER_FROM_ARRAY_EMPTY(name, array, size) \ - buffer_t name; \ - buffer_init(&name, array, size, 0) +#define RW_BUFFER_FROM_ARRAY_EMPTY(_name, _array, _size) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, _array, _size, 0) -#define BUFFER_FROM_VAR_FULL(name, var) \ - buffer_t name; \ - buffer_init(&name, &var, sizeof(var), sizeof(var)) +#define RW_BUFFER_FROM_VAR_FULL(_name, _var) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, &_var, sizeof(_var), sizeof(_var)) -#define BUFFER_FROM_VAR_EMPTY(name, var) \ - buffer_t name; \ - buffer_init(&name, &var, sizeof(var), 0) +#define RW_BUFFER_FROM_VAR_EMPTY(_name, _var) \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, &_var, sizeof(_var), 0) -#define BUFFER_NEW_LOCAL_EMPTY(name, size) \ - uint8_t __##name[size]; \ - buffer_t name; \ - buffer_init(&name, __##name, size, 0) - -/** - * Enumeration for endianness. - */ -typedef enum { - BE, /// Big Endian - LE /// Little Endian -} endianness_t; +#define RW_BUFFER_NEW_LOCAL_EMPTY(_name, _size) \ + uint8_t __##_name[_size]; \ + rw_buffer_t _name; \ + rw_buffer_init(&_name, __##_name, _size, 0) /** * Struct for buffer with size and read+write offset. */ typedef struct { - uint8_t *ptr; /// Pointer to byte buffer - uint16_t size; /// Size of byte buffer - uint16_t read_offset; /// Read offset in byte buffer - uint16_t write_offset; /// Write offset in byte buffer -} buffer_t; + buffer_t read; /// read buffer. size is a write offset. + size_t size; /// full allocated size of the buffer +} rw_buffer_t; + /** * Initialize buffer. @@ -56,14 +45,12 @@ typedef struct { * Data size of the buffer. * */ -static inline void buffer_init(buffer_t *buffer, - uint8_t *ptr, - uint16_t buf_size, - uint16_t data_size) { - buffer->ptr = ptr; +static inline void rw_buffer_init(rw_buffer_t *buffer, + uint8_t *ptr, + size_t buf_size, + size_t data_size) { + buffer_init(&buffer->read, ptr, data_size); buffer->size = buf_size; - buffer->read_offset = 0; - buffer->write_offset = data_size; } /** @@ -73,87 +60,87 @@ static inline void buffer_init(buffer_t *buffer, * Pointer to input buffer struct. * */ -static inline void buffer_empty(buffer_t *buffer) { - buffer->read_offset = 0; - buffer->write_offset = 0; +static inline void rw_buffer_empty(rw_buffer_t *buffer) { + buffer->read.offset = 0; + buffer->read.size = 0; } /** - * Return read pointer to the start of the data. + * Tell whether buffer has bytes to read or not. * * @param[in] buffer * Pointer to input buffer struct. * + * @return length of the data in buffer. + * */ -static inline uint8_t *buffer_read_ptr(const buffer_t *buffer) { - return buffer->ptr + buffer->read_offset; +static inline size_t rw_buffer_data_len(const rw_buffer_t *buffer) { + return buffer_data_len(&buffer->read); } /** - * Return write pointer to the start of the empty space. + * Tell whether buffer can write bytes or not. * * @param[in] buffer * Pointer to input buffer struct. * + * @return length of the empty space in buffer. + * */ -static inline uint8_t *buffer_write_ptr(const buffer_t *buffer) { - return buffer->ptr + buffer->write_offset; +static inline size_t rw_buffer_empty_space_len(const rw_buffer_t *buffer) { + return buffer->size - buffer->read.size; } /** - * Tell whether buffer can read bytes or not. + * Return read pointer to the start of the data. * * @param[in] buffer * Pointer to input buffer struct. - * @param[in] n - * Number of bytes to read in buffer. - * - * @return true if success, false otherwise. * */ -static inline bool buffer_can_read(const buffer_t *buffer, uint16_t n) { - return (buffer->write_offset - buffer->read_offset) >= n; +static inline const uint8_t *rw_buffer_read_ptr(const rw_buffer_t *buffer) { + return buffer_read_ptr(&buffer->read); } /** - * Tell whether buffer can write bytes or not. + * Return write pointer to the start of the empty space. * * @param[in] buffer * Pointer to input buffer struct. - * @param[in] n - * Number of bytes to write in buffer. - * - * @return true if success, false otherwise. * */ -static inline bool buffer_can_write(const buffer_t *buffer, uint16_t n) { - return (buffer->size - buffer->write_offset) >= n; +static inline uint8_t *rw_buffer_write_ptr(rw_buffer_t *buffer) { + return ((uint8_t* )buffer->read.ptr) + buffer->read.size; } /** - * Tell whether buffer can write bytes or not. + * 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 length of the empty space in buffer. + * @return true if success, false otherwise. * */ -static inline uint16_t buffer_empty_space_len(const buffer_t *buffer) { - return buffer->size - buffer->write_offset; +static inline bool rw_buffer_can_read(const rw_buffer_t *buffer, size_t n) { + return buffer_can_read(&buffer->read, n); } /** - * Tell whether buffer has bytes to read or not. + * Tell whether buffer can write bytes or not. * * @param[in] buffer * Pointer to input buffer struct. + * @param[in] n + * Number of bytes to write in buffer. * - * @return length of the data in buffer. + * @return true if success, false otherwise. * */ -static inline uint16_t buffer_data_len(const buffer_t *buffer) { - return buffer->write_offset - buffer->read_offset; +static inline bool rw_buffer_can_write(const rw_buffer_t *buffer, size_t n) { + return rw_buffer_empty_space_len(buffer) >= n; } /** @@ -165,8 +152,8 @@ static inline uint16_t buffer_data_len(const buffer_t *buffer) { * @return current read position in the buffer. * */ -static inline uint16_t buffer_read_position(const buffer_t *buffer) { - return buffer->read_offset; +static inline size_t rw_buffer_read_position(const rw_buffer_t *buffer) { + return buffer->read.offset; } /** @@ -178,8 +165,8 @@ static inline uint16_t buffer_read_position(const buffer_t *buffer) { * @return current write position in the buffer. * */ -static inline uint16_t buffer_write_position(const buffer_t *buffer) { - return buffer->write_offset; +static inline size_t rw_buffer_write_position(const rw_buffer_t *buffer) { + return buffer->read.size; } /** @@ -193,7 +180,9 @@ static inline uint16_t buffer_write_position(const buffer_t *buffer) { * @return true if success, false otherwise. * */ -bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_set(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_set(&buffer->read, offset); +} /** * Seek the buffer read position relatively to current offset. @@ -201,12 +190,14 @@ bool buffer_seek_read_set(buffer_t *buffer, uint16_t offset); * @param[in,out] buffer * Pointer to input buffer struct. * @param[in] offset - * Offset to seek relatively to `buffer->read_offset`. + * Offset to seek relatively to `buffer->read.offset`. * * @return true if success, false otherwise. * */ -bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_cur(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_cur(&buffer->read, offset); +} /** * Seek the buffer read position relatively to the end of the data. @@ -214,12 +205,14 @@ bool buffer_seek_read_cur(buffer_t *buffer, uint16_t offset); * @param[in,out] buffer * Pointer to input buffer struct. * @param[in] offset - * Offset to seek relatively to `buffer->write_offset`. + * Offset to seek relatively to `buffer->read.size`. * * @return true if success, false otherwise. * */ -bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset); +static inline bool rw_buffer_seek_read_end(rw_buffer_t *buffer, size_t offset) { + return buffer_seek_end(&buffer->read, offset); +} /** * Seek the buffer write position to specific offset. @@ -232,7 +225,7 @@ bool buffer_seek_read_end(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_set(rw_buffer_t *buffer, size_t offset); /** * Seek the buffer write position relatively to current offset. @@ -245,7 +238,7 @@ bool buffer_seek_write_set(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_cur(rw_buffer_t *buffer, size_t offset); /** * Seek the buffer write position relatively to the buffer end. @@ -258,7 +251,7 @@ bool buffer_seek_write_cur(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset); +bool rw_buffer_seek_write_end(rw_buffer_t *buffer, size_t offset); /** * Read 1 byte from buffer into uint8_t. @@ -271,7 +264,9 @@ bool buffer_seek_write_end(buffer_t *buffer, uint16_t offset); * @return true if success, false otherwise. * */ -bool buffer_read_u8(buffer_t *buffer, uint8_t *value); +static inline bool rw_buffer_read_u8(rw_buffer_t *buffer, uint8_t *value) { + return buffer_read_u8(&buffer->read, value); +} /** * Read 2 bytes from buffer into uint16_t. @@ -286,7 +281,9 @@ bool buffer_read_u8(buffer_t *buffer, uint8_t *value); * @return true if success, false otherwise. * */ -bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u16(rw_buffer_t *buffer, uint16_t *value, endianness_t endianness) { + return buffer_read_u16(&buffer->read, value, endianness); +} /** * Read 4 bytes from buffer into uint32_t. @@ -301,7 +298,9 @@ bool buffer_read_u16(buffer_t *buffer, uint16_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u32(rw_buffer_t *buffer, uint32_t *value, endianness_t endianness) { + return buffer_read_u32(&buffer->read, value, endianness); +} /** * Read 8 bytes from buffer into uint64_t. @@ -316,7 +315,9 @@ bool buffer_read_u32(buffer_t *buffer, uint32_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness); +static inline bool rw_buffer_read_u64(rw_buffer_t *buffer, uint64_t *value, endianness_t endianness) { + return buffer_read_u64(&buffer->read, value, endianness); +} /** * Read BIP32 path from buffer. @@ -331,7 +332,9 @@ bool buffer_read_u64(buffer_t *buffer, uint64_t *value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len); +static inline bool rw_buffer_read_bip32_path(rw_buffer_t *buffer, uint32_t *out, size_t out_len) { + return buffer_read_bip32_path(&buffer->read, out, out_len); +} /** * Move bytes from buffer. @@ -346,7 +349,9 @@ bool buffer_read_bip32_path(buffer_t *buffer, uint32_t *out, uint8_t out_len); * @return true if success, false otherwise. * */ -bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len); +static inline bool rw_buffer_read_bytes(rw_buffer_t *buffer, uint8_t *out, size_t out_len) { + return buffer_move(&buffer->read, out, out_len); +} /** * Copy bytes from buffer without its modification. @@ -361,7 +366,9 @@ bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, uint16_t out_len); * @return true if success, false otherwise. * */ -bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len); +static inline bool rw_buffer_copy_bytes(const rw_buffer_t *buffer, uint8_t *out, size_t out_len) { + return buffer_copy(&buffer->read, out, out_len); +} /** * Write 1 byte to buffer from uint8_t. @@ -374,7 +381,7 @@ bool buffer_copy_bytes(const buffer_t *buffer, uint8_t *out, uint16_t out_len); * @return true if success, false otherwise. * */ -bool buffer_write_u8(buffer_t *buffer, uint8_t value); +bool rw_buffer_write_u8(rw_buffer_t *buffer, uint8_t value); /** * Write 2 bytes to buffer from uint16_t. @@ -389,7 +396,7 @@ bool buffer_write_u8(buffer_t *buffer, uint8_t value); * @return true if success, false otherwise. * */ -bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness); +bool rw_buffer_write_u16(rw_buffer_t *buffer, uint16_t value, endianness_t endianness); /** * Write 4 bytes to buffer from uint32_t. @@ -404,7 +411,7 @@ bool buffer_write_u16(buffer_t *buffer, uint16_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness); +bool rw_buffer_write_u32(rw_buffer_t *buffer, uint32_t value, endianness_t endianness); /** * Write 8 bytes to buffer from uint64_t. @@ -419,7 +426,7 @@ bool buffer_write_u32(buffer_t *buffer, uint32_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness); +bool rw_buffer_write_u64(rw_buffer_t *buffer, uint64_t value, endianness_t endianness); /** * Write bytes to buffer. @@ -434,7 +441,7 @@ bool buffer_write_u64(buffer_t *buffer, uint64_t value, endianness_t endianness) * @return true if success, false otherwise. * */ -bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len); +bool rw_buffer_write_bytes(rw_buffer_t *buffer, const uint8_t *from, size_t from_len); /** * Move all data to the start of the buffer. @@ -443,4 +450,4 @@ bool buffer_write_bytes(buffer_t *buffer, const uint8_t *from, uint16_t from_len * Pointer to input buffer struct. * */ -void buffer_shift_data(buffer_t *buffer); +void rw_buffer_shift_data(rw_buffer_t *buffer); diff --git a/src/common/int_ops.h b/src/common/safeint.h similarity index 100% rename from src/common/int_ops.h rename to src/common/safeint.h diff --git a/src/common/write.c b/src/common/write.c deleted file mode 100644 index 58bc8f4e..00000000 --- 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 0418f5c6..00000000 --- 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/context.c b/src/context.c index 7eba075b..dcd21a1a 100644 --- a/src/context.c +++ b/src/context.c @@ -1,15 +1,26 @@ #include // uint*_t #include // memset, explicit_bzero +#include #include "context.h" +#include "./common/macros_ext.h" -void clear_context(global_ctx_t* context, command_e current_command) { - uint8_t session_key[SESSION_KEY_LEN] = {0}; - uint32_t app_session = context->app_session_id; - memcpy(session_key, context->session_key, SESSION_KEY_LEN); - explicit_bzero(context, sizeof(global_ctx_t)); - memcpy(context->session_key, session_key, SESSION_KEY_LEN); - context->app_session_id = app_session; - context->current_command = current_command; - context->is_ui_busy = false; +// Saved here to store it outside of the stack +app_ctx_t G_app_context; + +void app_init(void) { + // Clear context + explicit_bzero(&G_app_context, sizeof(app_ctx_t)); + + // Generate random key for session + cx_rng(G_app_context.session_key, MEMBER_SIZE(app_ctx_t, session_key)); + + // Reset context to default values + app_set_current_command(CMD_NONE); +} + +void app_set_current_command(command_e current_command) { + explicit_bzero(&G_app_context.commands_ctx, MEMBER_SIZE(app_ctx_t, commands_ctx)); + app_set_ui_busy(false); + G_app_context.current_command = current_command; } \ No newline at end of file diff --git a/src/context.h b/src/context.h index f802f7c5..fc3d714f 100644 --- a/src/context.h +++ b/src/context.h @@ -1,16 +1,16 @@ #pragma once -#include "types.h" +#include "apdu_dispatcher.h" #include "commands/extpubkey/epk_context.h" #include "commands/deriveaddress/da_context.h" #include "commands/attestinput/ainpt_context.h" #include "commands/signtx/stx_context.h" /** - * Structure for global context. + * Structure for application context. */ typedef struct { - uint32_t app_session_id; + uint32_t connected_app_id; uint8_t session_key[SESSION_KEY_LEN]; command_e current_command; /// current command bool is_ui_busy; @@ -19,10 +19,90 @@ typedef struct { sign_transaction_ctx_t sign_tx; derive_address_ctx_t derive_address; extended_public_key_ctx_t ext_pub_key; - } ctx; -} global_ctx_t; + } commands_ctx; +} app_ctx_t; /** - * Clear context saving app token and session key + * Global application context +*/ +extern app_ctx_t G_app_context; + +/** + * Check is ui busy +*/ +static inline bool app_is_ui_busy() { + return G_app_context.is_ui_busy; +} + +/** + * Set UI busy +*/ +static inline void app_set_ui_busy(bool is_busy) { + G_app_context.is_ui_busy = is_busy; +} + +/** + * Get connected application id. +*/ +static inline uint32_t app_connected_app_id(void) { + return G_app_context.connected_app_id; +} + +/** + * Set connected application id. +*/ +static inline void app_set_connected_app_id(uint32_t id) { + G_app_context.connected_app_id = id; +} + +/** + * Get session key. +*/ +static inline const uint8_t* app_session_key(void) { + return G_app_context.session_key; +} + +/** + * Get current command key. +*/ +static inline command_e app_current_command(void) { + return G_app_context.current_command; +} + +/** + * Attest Input command context +*/ +static inline attest_input_ctx_t* app_attest_input_context(void) { + return &G_app_context.commands_ctx.attest_input; +} + +/** + * Sign Transaction command context +*/ +static inline sign_transaction_ctx_t* app_sign_transaction_context(void) { + return &G_app_context.commands_ctx.sign_tx; +} + +/** + * Derive Address command context +*/ +static inline derive_address_ctx_t* app_derive_address_context(void) { + return &G_app_context.commands_ctx.derive_address; +} + +/** + * Extended Public Key command context +*/ +static inline extended_public_key_ctx_t* app_extended_public_key_context(void) { + return &G_app_context.commands_ctx.ext_pub_key; +} + +/** + * Init application context +*/ +void app_init(void); + +/** + * Switch context state to the command */ -void clear_context(global_ctx_t* context, command_e current_command); \ No newline at end of file +void app_set_current_command(command_e current_command); \ No newline at end of file diff --git a/src/ergo/address.c b/src/ergo/address.c index 02e46f10..53bbb92d 100644 --- a/src/ergo/address.c +++ b/src/ergo/address.c @@ -6,47 +6,48 @@ #include #include +#include + #include "address.h" #include "network_id.h" -#include "../common/base58.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" #include "../helpers/blake2b.h" static inline bool _ergo_address_from_pubkey(uint8_t network, const uint8_t* public_key, uint8_t address[static P2PK_ADDRESS_LEN], bool is_compressed) { - BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2PK_ADDRESS_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2PK_ADDRESS_LEN); if (!network_id_is_valid(network)) { return false; } // P2PK + network id - if (!buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2PK + network)) { + if (!rw_buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2PK + network)) { return false; } if (is_compressed) { - if (!buffer_write_bytes(&buffer, public_key, COMPRESSED_PUBLIC_KEY_LEN)) { + if (!rw_buffer_write_bytes(&buffer, public_key, COMPRESSED_PUBLIC_KEY_LEN)) { return false; } } else { // Compress pubkey - if (!buffer_write_u8(&buffer, ((public_key[64] & 1) ? 0x03 : 0x02))) { + if (!rw_buffer_write_u8(&buffer, ((public_key[64] & 1) ? 0x03 : 0x02))) { return false; } - if (!buffer_write_bytes(&buffer, public_key + 1, COMPRESSED_PUBLIC_KEY_LEN - 1)) { + if (!rw_buffer_write_bytes(&buffer, public_key + 1, COMPRESSED_PUBLIC_KEY_LEN - 1)) { return false; } } uint8_t hash[BLAKE2B_256_DIGEST_LEN] = {0}; - if (!blake2b_256(buffer_read_ptr(&buffer), buffer_data_len(&buffer), hash)) { + if (!blake2b_256(rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer), hash)) { return false; } // Checksum - if (!buffer_write_bytes(&buffer, hash, ADDRESS_CHECKSUM_LEN)) { + if (!rw_buffer_write_bytes(&buffer, hash, ADDRESS_CHECKSUM_LEN)) { return false; } @@ -68,23 +69,23 @@ bool ergo_address_from_compressed_pubkey(uint8_t network, bool ergo_address_from_script_hash(uint8_t network, const uint8_t hash[static P2SH_HASH_LEN], uint8_t address[static P2SH_ADDRESS_LEN]) { - BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2SH_ADDRESS_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(buffer, address, P2SH_ADDRESS_LEN); if (!network_id_is_valid(network)) { return false; } // P2SH + network id - if (!buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2SH + network)) { + if (!rw_buffer_write_u8(&buffer, ERGO_ADDRESS_TYPE_P2SH + network)) { return false; } - if (!buffer_write_bytes(&buffer, hash, P2SH_HASH_LEN)) { + if (!rw_buffer_write_bytes(&buffer, hash, P2SH_HASH_LEN)) { return false; } uint8_t checksum[BLAKE2B_256_DIGEST_LEN] = {0}; - if (!blake2b_256(buffer_read_ptr(&buffer), buffer_data_len(&buffer), checksum)) { + if (!blake2b_256(rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer), checksum)) { return false; } // Checksum - if (!buffer_write_bytes(&buffer, checksum, ADDRESS_CHECKSUM_LEN)) { + if (!rw_buffer_write_bytes(&buffer, checksum, ADDRESS_CHECKSUM_LEN)) { return false; } return true; diff --git a/src/ergo/ergo_tree.c b/src/ergo/ergo_tree.c index d75910ec..1416c449 100644 --- a/src/ergo/ergo_tree.c +++ b/src/ergo/ergo_tree.c @@ -2,7 +2,7 @@ #include #include #include "address.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" static const uint8_t C_ERGO_TREE_P2PK_PREFIX[ERGO_TREE_P2PK_PREFIX_LEN] = {0x00, 0x08, 0xcd}; @@ -35,14 +35,14 @@ static const uint8_t C_ERGO_TREE_MINERS_HASH_FEE_MAINNET[105] = { void ergo_tree_generate_p2pk(const uint8_t raw_public_key[static PUBLIC_KEY_LEN], uint8_t tree[ERGO_TREE_P2PK_LEN]) { - BUFFER_FROM_ARRAY_EMPTY(out, tree, ERGO_TREE_P2PK_LEN); + RW_BUFFER_FROM_ARRAY_EMPTY(out, tree, ERGO_TREE_P2PK_LEN); // Prefix - buffer_write_bytes(&out, PIC(C_ERGO_TREE_P2PK_PREFIX), ERGO_TREE_P2PK_PREFIX_LEN); + rw_buffer_write_bytes(&out, PIC(C_ERGO_TREE_P2PK_PREFIX), ERGO_TREE_P2PK_PREFIX_LEN); // Compressed pubkey - buffer_write_u8(&out, ((raw_public_key[64] & 1) ? 0x03 : 0x02)); - buffer_write_bytes(&out, raw_public_key + 1, 32); + rw_buffer_write_u8(&out, ((raw_public_key[64] & 1) ? 0x03 : 0x02)); + rw_buffer_write_bytes(&out, raw_public_key + 1, 32); } bool ergo_tree_parse_p2pk(const uint8_t tree[ERGO_TREE_P2PK_LEN], diff --git a/src/ergo/tx_ser_box.c b/src/ergo/tx_ser_box.c index b2366157..4b9d7d0c 100755 --- a/src/ergo/tx_ser_box.c +++ b/src/ergo/tx_ser_box.c @@ -1,8 +1,8 @@ #include "tx_ser_box.h" #include #include "ergo_tree.h" -#include "../common/varint.h" -#include "../common/macros.h" +#include "../common/gve.h" +#include "../common/macros_ext.h" #define CHECK_PROPER_STATE(_ctx, _state) \ if (_ctx->state != _state) return res_error(_ctx, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_STATE) @@ -22,19 +22,19 @@ static inline ergo_tx_serializer_box_result_e res_error(ergo_tx_serializer_box_c static inline ergo_tx_serializer_box_result_e add_height_and_token_count( ergo_tx_serializer_box_context_t* context) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); if (gve_put_u32(&buffer, context->creation_height) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u8(&buffer, context->tokens_count) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } return ERGO_TX_SERIALIZER_BOX_RES_OK; @@ -42,11 +42,11 @@ static inline ergo_tx_serializer_box_result_e add_height_and_token_count( static NOINLINE ergo_tx_serializer_box_result_e add_empty_registers_count(ergo_tx_serializer_box_context_t* context) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 1); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 1); if (gve_put_u8(&buffer, 0) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } return ERGO_TX_SERIALIZER_BOX_RES_OK; @@ -105,11 +105,11 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_init( return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_TOO_MUCH_DATA); } - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); if (gve_put_u64(&buffer, value) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } @@ -139,7 +139,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tree( if (!blake2b_update(context->hash, buffer_read_ptr(tree_chunk), len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - if (!buffer_seek_read_cur(tree_chunk, len)) { + if (!buffer_seek_cur(tree_chunk, len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } context->ergo_tree_size -= len; @@ -183,7 +183,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( buffer_t* input, const token_table_t* table) { CHECK_PROPER_STATE(context, ERGO_TX_SERIALIZER_BOX_STATE_TREE_ADDED); - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); while (buffer_data_len(input) > 0) { union { @@ -197,7 +197,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( } if (table == NULL) { // no token table. working with full ids. - if (!buffer_read_bytes(input, token_id.id, ERGO_ID_LEN)) { + if (!buffer_move(input, token_id.id, ERGO_ID_LEN)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_ID); } // hashing input id @@ -213,13 +213,13 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_INDEX); } // hashing index - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u32(&buffer, token_id.index) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } if (!blake2b_update(context->hash, - buffer_read_ptr(&buffer), - buffer_data_len(&buffer))) { + rw_buffer_read_ptr(&buffer), + rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } } @@ -228,11 +228,11 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_tokens( if (!buffer_read_u64(input, &value, BE)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BAD_TOKEN_VALUE); } - buffer_empty(&buffer); + rw_buffer_empty(&buffer); if (gve_put_u64(&buffer, value) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } @@ -267,7 +267,7 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_add_registers( if (!blake2b_update(context->hash, buffer_read_ptr(registers_chunk), len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - if (!buffer_seek_read_cur(registers_chunk, len)) { + if (!buffer_seek_cur(registers_chunk, len)) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } context->registers_size -= len; @@ -292,11 +292,11 @@ ergo_tx_serializer_box_result_e ergo_tx_serializer_box_id_hash( return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } - BUFFER_NEW_LOCAL_EMPTY(buffer, 4); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 4); if (gve_put_u16(&buffer, box_index) != GVE_OK) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_BUFFER); } - if (!blake2b_update(context->hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(context->hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return res_error(context, ERGO_TX_SERIALIZER_BOX_RES_ERR_HASHER); } diff --git a/src/ergo/tx_ser_box.h b/src/ergo/tx_ser_box.h index e3239662..21ee2e03 100755 --- a/src/ergo/tx_ser_box.h +++ b/src/ergo/tx_ser_box.h @@ -2,8 +2,10 @@ #include #include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" #include "tx_ser_table.h" diff --git a/src/ergo/tx_ser_full.c b/src/ergo/tx_ser_full.c index e4d59fa1..64e7c06a 100755 --- a/src/ergo/tx_ser_full.c +++ b/src/ergo/tx_ser_full.c @@ -1,6 +1,6 @@ #include "tx_ser_full.h" -#include "../common/varint.h" -#include "../common/macros.h" +#include "../common/gve.h" +#include "../common/macros_ext.h" #include #define CHECK_PROPER_STATE(_ctx, _state) \ @@ -113,9 +113,9 @@ static inline ergo_tx_serializer_full_result_e map_box_result(ergo_tx_serializer } static inline bool hash_u16(cx_blake2b_t* hash, uint16_t u16) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 4); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 4); if (gve_put_u16(&buffer, u16) != GVE_OK) return false; - return blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer)); + return blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer)); } static NOINLINE ergo_tx_serializer_full_result_e @@ -276,7 +276,7 @@ ergo_tx_serializer_full_result_e ergo_tx_serializer_full_add_data_inputs( return res_error(context, ERGO_TX_SERIALIZER_FULL_RES_ERR_TOO_MANY_DATA_INPUTS); } uint8_t box_id[ERGO_ID_LEN]; - if (!buffer_read_bytes(inputs, box_id, ERGO_ID_LEN)) { + if (!buffer_move(inputs, box_id, ERGO_ID_LEN)) { return res_error(context, ERGO_TX_SERIALIZER_FULL_RES_ERR_BAD_DATA_INPUT); } if (!blake2b_update(context->hash, box_id, ERGO_ID_LEN)) { diff --git a/src/ergo/tx_ser_full.h b/src/ergo/tx_ser_full.h index 1e81e884..eb941f15 100755 --- a/src/ergo/tx_ser_full.h +++ b/src/ergo/tx_ser_full.h @@ -2,11 +2,13 @@ #include #include + +#include + #include "../constants.h" #include "tx_ser_table.h" #include "tx_ser_box.h" #include "tx_ser_input.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" typedef enum { diff --git a/src/ergo/tx_ser_input.c b/src/ergo/tx_ser_input.c index 95c32988..648fb80c 100644 --- a/src/ergo/tx_ser_input.c +++ b/src/ergo/tx_ser_input.c @@ -1,5 +1,6 @@ #include "tx_ser_input.h" #include +#include "../common/buffer_ext.h" #define CHECK_PROPER_STATE(_ctx, _state) \ if (_ctx->state != _state) return res_error(_ctx, ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_STATE) @@ -54,7 +55,7 @@ ergo_tx_serializer_input_result_e ergo_tx_serializer_input_add_tokens( while (buffer_data_len(tokens) > 0) { uint8_t token_id[ERGO_ID_LEN]; uint64_t token_value; - if (!buffer_read_bytes(tokens, token_id, ERGO_ID_LEN)) { + if (!buffer_move(tokens, token_id, ERGO_ID_LEN)) { return res_error(context, ERGO_TX_SERIALIZER_INPUT_RES_ERR_BAD_TOKEN_ID); } if (!buffer_read_u64(tokens, &token_value, BE)) { diff --git a/src/ergo/tx_ser_input.h b/src/ergo/tx_ser_input.h index b1d7e56f..27d428f6 100644 --- a/src/ergo/tx_ser_input.h +++ b/src/ergo/tx_ser_input.h @@ -2,8 +2,10 @@ #include #include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" #include "tx_ser_table.h" diff --git a/src/ergo/tx_ser_table.c b/src/ergo/tx_ser_table.c index da64d581..b0a76f02 100755 --- a/src/ergo/tx_ser_table.c +++ b/src/ergo/tx_ser_table.c @@ -1,5 +1,5 @@ #include "tx_ser_table.h" -#include "../common/varint.h" +#include "../common/gve.h" static inline ergo_tx_serializer_table_result_e parse_token(buffer_t* tokens, token_table_t* table, @@ -7,7 +7,7 @@ static inline ergo_tx_serializer_table_result_e parse_token(buffer_t* tokens, if (table->count >= tokens_max) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_TOO_MANY_TOKENS; } - if (!buffer_read_bytes(tokens, table->tokens[table->count++], ERGO_ID_LEN)) { + if (!buffer_move(tokens, table->tokens[table->count++], ERGO_ID_LEN)) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_BAD_TOKEN_ID; } return ERGO_TX_SERIALIZER_TABLE_RES_OK; @@ -44,11 +44,11 @@ ergo_tx_serializer_table_result_e ergo_tx_serializer_table_add( ergo_tx_serializer_table_result_e ergo_tx_serializer_table_hash( const ergo_tx_serializer_table_context_t* context, cx_blake2b_t* hash) { - BUFFER_NEW_LOCAL_EMPTY(buffer, 10); + RW_BUFFER_NEW_LOCAL_EMPTY(buffer, 10); if (gve_put_u32(&buffer, context->tokens_table->count) != GVE_OK) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_BUFFER; } - if (!blake2b_update(hash, buffer_read_ptr(&buffer), buffer_data_len(&buffer))) { + if (!blake2b_update(hash, rw_buffer_read_ptr(&buffer), rw_buffer_data_len(&buffer))) { return ERGO_TX_SERIALIZER_TABLE_RES_ERR_HASHER; } for (uint8_t i = 0; i < context->tokens_table->count; i++) { diff --git a/src/ergo/tx_ser_table.h b/src/ergo/tx_ser_table.h index da23d87d..69fb69ca 100755 --- a/src/ergo/tx_ser_table.h +++ b/src/ergo/tx_ser_table.h @@ -2,8 +2,10 @@ #include #include + +#include + #include "../constants.h" -#include "../common/buffer.h" #include "../helpers/blake2b.h" typedef struct { diff --git a/src/globals.h b/src/globals.h deleted file mode 100644 index 29d1f529..00000000 --- a/src/globals.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include - -#include "types.h" -#include "constants.h" -#include "context.h" -#include "helpers/io.h" - -/** - * Global buffer for interactions between SE and MCU. - */ -extern uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; - -/** - * Global structure to perform asynchronous UX aside IO operations. - */ -extern ux_state_t G_ux; - -/** - * Global structure with the parameters to exchange with the BOLOS UX application. - */ -extern bolos_ux_params_t G_ux_params; - -/** - * Global context for user requests. - */ -extern global_ctx_t G_context; - -/** - * Global array for UI screen flow - */ -extern ux_flow_step_t const *G_ux_flow[MAX_NUMBER_OF_SCREENS + 1]; \ No newline at end of file diff --git a/src/helpers/cmd_macros.h b/src/helpers/cmd_macros.h new file mode 100644 index 00000000..98f8b6ab --- /dev/null +++ b/src/helpers/cmd_macros.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "../context.h" +#include "../sw.h" + +#define CHECK_COMMAND(_ctx, _cmd) \ + if (_cmd != app_current_command()) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_SESSION(_ctx, _session_id) \ + if (_session_id != _ctx->session) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_SESSION_ID) + +#define CHECK_PROPER_STATE(_ctx, _state) \ + if (_ctx->state != _state) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_PROPER_STATES(_ctx, _state1, _state2) \ + if (_ctx->state != _state1 && _ctx->state != _state2) return COMMAND_ERROR_HANDLER(_ctx, SW_BAD_STATE) + +#define CHECK_READ_PARAM(_ctx, _call) \ + if (!_call) return COMMAND_ERROR_HANDLER(_ctx, SW_NOT_ENOUGH_DATA) + +#define CHECK_PARAMS_FINISHED(_ctx, _buffer) \ + if (buffer_can_read(_buffer, 1)) return COMMAND_ERROR_HANDLER(_ctx, SW_TOO_MUCH_DATA) + +#define CHECK_CALL_RESULT_SW_OK(_ctx, _call) \ + do { \ + uint16_t _res = _call; \ + if (_res != SW_OK) return COMMAND_ERROR_HANDLER(_ctx, _res); \ + } while (0) + +#define CHECK_WRITE_PARAM(_call) \ + if (!_call) return WRITE_ERROR_HANDLER(SW_BUFFER_ERROR) \ No newline at end of file diff --git a/src/helpers/crypto.c b/src/helpers/crypto.c index a1dce889..7d6417e4 100644 --- a/src/helpers/crypto.c +++ b/src/helpers/crypto.c @@ -20,7 +20,6 @@ #include // bool #include "crypto.h" -#include "globals.h" #define PRIVATE_KEY_SIZE 32 @@ -28,31 +27,23 @@ uint16_t crypto_derive_private_key(cx_ecfp_private_key_t *private_key, uint8_t chain_code[static CHAIN_CODE_LEN], const uint32_t *bip32_path, uint8_t bip32_path_len) { - uint8_t raw_private_key[PRIVATE_KEY_SIZE] = {0}; - uint16_t result = 0; - BEGIN_TRY { - TRY { - // derive the seed with bip32_path - os_perso_derive_node_bip32(CX_CURVE_256K1, - bip32_path, - bip32_path_len, - raw_private_key, - chain_code); - // new private_key from raw - cx_ecfp_init_private_key(CX_CURVE_256K1, - raw_private_key, - sizeof(raw_private_key), - private_key); - } - CATCH_OTHER(e) { - result = e; - } - FINALLY { - explicit_bzero(raw_private_key, sizeof(raw_private_key)); - } - } - END_TRY; - return result; + uint8_t raw_private_key[64] = {0}; + + // derive the seed with bip32_path + cx_err_t result = os_derive_bip32_no_throw(CX_CURVE_256K1, + bip32_path, + bip32_path_len, + raw_private_key, + chain_code); + if (result != CX_OK) { return (uint16_t)result; } + + // new private_key from raw + result = cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, + raw_private_key, + PRIVATE_KEY_SIZE, + private_key); + explicit_bzero(raw_private_key, sizeof(raw_private_key)); + return (uint16_t)result; } uint16_t crypto_generate_private_key(const uint32_t *bip32_path, diff --git a/src/helpers/input_frame.c b/src/helpers/input_frame.c index 96f44556..51d39228 100644 --- a/src/helpers/input_frame.c +++ b/src/helpers/input_frame.c @@ -1,4 +1,5 @@ #include "input_frame.h" +#include "../common/buffer_ext.h" uint8_t input_frame_data_length(const buffer_t* input) { if (!buffer_can_read(input, FRAME_MIN_SIZE)) { @@ -12,7 +13,7 @@ uint8_t input_frame_data_length(const buffer_t* input) { return data_len; } -uint8_t* input_frame_signature_ptr(const buffer_t* input) { +const uint8_t* input_frame_signature_ptr(const buffer_t* input) { uint8_t data_len = input_frame_data_length(input); if (data_len == 0) return NULL; return buffer_read_ptr(input) + data_len; diff --git a/src/helpers/input_frame.h b/src/helpers/input_frame.h index b4017079..7699d291 100644 --- a/src/helpers/input_frame.h +++ b/src/helpers/input_frame.h @@ -2,9 +2,11 @@ #include #include + #include + #include "../constants.h" -#include "../common/buffer.h" +#include "../common/buffer_ext.h" #include "../ergo/tx_ser_table.h" #define FRAME_MAX_TOKENS_COUNT 4 @@ -15,4 +17,4 @@ #define FRAME_MAX_SIZE (FRAME_MIN_SIZE + FRAME_MAX_TOKENS_COUNT * FRAME_TOKEN_VALUE_PAIR_SIZE) uint8_t input_frame_data_length(const buffer_t* input); -uint8_t* input_frame_signature_ptr(const buffer_t* input); \ No newline at end of file +const uint8_t* input_frame_signature_ptr(const buffer_t* input); \ No newline at end of file diff --git a/src/helpers/io.c b/src/helpers/io.c deleted file mode 100644 index 03a7cb40..00000000 --- a/src/helpers/io.c +++ /dev/null @@ -1,161 +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 - -#include -#include - -#include "io.h" -#include "../globals.h" -#include "../sw.h" -#include "../common/buffer.h" -#include "../common/write.h" - -void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t *) element); -} - -uint8_t io_event(__attribute__((unused)) uint8_t channel) { - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - 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); - } - /* fallthrough */ - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: - UX_DISPLAYED_EVENT({}); - break; - 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) { - size_t len = buffer_data_len(rdata); - if (len > IO_APDU_BUFFER_SIZE - 2 || // - !buffer_copy_bytes(rdata, G_io_apdu_buffer, sizeof(G_io_apdu_buffer))) { - return io_send_sw(SW_WRONG_RESPONSE_LENGTH); - } - G_output_len = len; - } else { - G_output_len = 0; - } - - 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/helpers/io.h b/src/helpers/io.h deleted file mode 100644 index 7859289a..00000000 --- a/src/helpers/io.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "../types.h" -#include "../common/buffer.h" - -void io_seproxyhal_display(const bagl_element_t *element); - -/** - * 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 and update G_output_len. - * - * @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/helpers/response.h b/src/helpers/response.h index 8031c64e..587b8235 100644 --- a/src/helpers/response.h +++ b/src/helpers/response.h @@ -2,31 +2,26 @@ #include -#include "io.h" +#include #include "../sw.h" -#include "../types.h" -#include "../context.h" -#include "../globals.h" -#include "../common/buffer.h" +#include "../common/rwbuffer.h" static inline int res_ok() { return io_send_sw(SW_OK); } +static inline int res_ok_data(const rw_buffer_t* data) { + return io_send_response_buffer(&data->read, SW_OK); +} + static inline int res_ui_busy() { return io_send_sw(SW_BUSY); } static inline int res_deny() { - clear_context(&G_context, CMD_NONE); return io_send_sw(SW_DENY); } -static inline int res_ok_data(const buffer_t* data) { - return io_send_response(data, SW_OK); -} - static inline int res_error(uint16_t code) { - clear_context(&G_context, CMD_NONE); return io_send_sw(code); } \ No newline at end of file diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 837d2432..00000000 --- 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 -#include -#include - -#include "types.h" -#include "globals.h" -#include "sw.h" -#include "ui/ui_menu.h" -#include "apdu/parser.h" -#include "apdu/dispatcher.h" -#include "common/macros.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; -ux_flow_step_t const *G_ux_flow[MAX_NUMBER_OF_SCREENS + 1]; - -/** - * 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 - clear_context(&G_context, CMD_NONE); - - // Set zero session id - G_context.app_session_id = 0; - - // Generate random key for session - cx_rng(G_context.session_key, MEMBER_SIZE(global_ctx_t, session_key)); - - 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)) { - io_send_sw(SW_WRONG_APDU_DATA_LENGTH); - CLOSE_TRY; - continue; - } - - // 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) { - clear_context(&G_context, CMD_NONE); - 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 (;;) { - // Reset UI - memset(&G_ux, 0, sizeof(G_ux)); - - BEGIN_TRY { - TRY { - io_seproxyhal_init(); - -#ifdef TARGET_NANOX - G_io_app.plane_mode = os_setting_get(OS_SETTING_PLANEMODE, NULL, 0); -#endif // TARGET_NANOX - - USB_power(0); - USB_power(1); - - ui_menu_main(); - -#ifdef HAVE_BLE - BLE_power(0, NULL); - BLE_power(1, "Nano X"); -#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/ui/ui_bip32_path.c b/src/ui/ui_bip32_path.c index 8d68ec8d..b65bce6f 100644 --- a/src/ui/ui_bip32_path.c +++ b/src/ui/ui_bip32_path.c @@ -1,5 +1,5 @@ #include "ui_bip32_path.h" -#include "../common/bip32.h" +#include "../common/bip32_ext.h" static ux_layout_bnnn_paging_params_t G_ui_path_params[1]; diff --git a/src/ui/ui_dynamic_flow.c b/src/ui/ui_dynamic_flow.c index c1c1962f..25b7b9ee 100644 --- a/src/ui/ui_dynamic_flow.c +++ b/src/ui/ui_dynamic_flow.c @@ -1,10 +1,11 @@ #include "ui_dynamic_flow.h" -#include "../globals.h" #include "../constants.h" +#include "../context.h" #include "../helpers/response.h" -#include "../common/macros.h" +#include "../common/macros_ext.h" #include "ui_menu.h" +#include "ui_main.h" #include @@ -37,8 +38,8 @@ void bnnn_paging_edgecase() { if (res == SW_OK) { \ switch_method(); \ } else { \ + app_set_current_command(CMD_NONE); \ res_error(res); \ - clear_context(&G_context, CMD_NONE); \ ui_menu_main(); \ } \ } while (0) @@ -100,9 +101,9 @@ bool ui_add_dynamic_flow_screens(uint8_t *screen, G_dynamic_flow_context.current_screen = INDEX_NOT_EXIST; G_dynamic_flow_context.show_cb = show_cb; - G_ux_flow[(*screen)++] = &ux_dynamic_upper_delimiter_step; - G_ux_flow[(*screen)++] = &ux_dynamic_step; - G_ux_flow[(*screen)++] = &ux_dynamic_lower_delimiter_step; + ui_add_screen(&ux_dynamic_upper_delimiter_step, screen); + ui_add_screen(&ux_dynamic_step, screen); + ui_add_screen(&ux_dynamic_lower_delimiter_step, screen); return true; } diff --git a/src/ui/ui_dynamic_flow.h b/src/ui/ui_dynamic_flow.h index 66b8abe1..01e869c6 100644 --- a/src/ui/ui_dynamic_flow.h +++ b/src/ui/ui_dynamic_flow.h @@ -3,7 +3,6 @@ #include #include #include -#include "../globals.h" typedef uint16_t (*ui_dynamic_flow_show_screen_cb)(uint8_t, char *, char *, void *); diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c new file mode 100644 index 00000000..d5150766 --- /dev/null +++ b/src/ui/ui_main.c @@ -0,0 +1,5 @@ +#include "ui_main.h" + +#ifdef HAVE_BAGL +ux_flow_step_t const *G_ux_flow_steps[MAX_NUMBER_OF_SCREENS + 1]; +#endif \ No newline at end of file diff --git a/src/ui/ui_main.h b/src/ui/ui_main.h new file mode 100644 index 00000000..5a4c0f44 --- /dev/null +++ b/src/ui/ui_main.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include "../constants.h" +#include "../context.h" + +#ifdef HAVE_BAGL +/** + * Global array for UI screen flow + */ +extern ux_flow_step_t const *G_ux_flow_steps[MAX_NUMBER_OF_SCREENS + 1]; + +static inline const ux_flow_step_t** ui_next_sreen_ptr(uint8_t* position) { + if (*position >= MAX_NUMBER_OF_SCREENS) return NULL; + return &G_ux_flow_steps[(*position)++]; +} + +static inline bool ui_add_screen(const ux_flow_step_t* screen, uint8_t* position) { + if (*position >= MAX_NUMBER_OF_SCREENS) return false; + G_ux_flow_steps[(*position)++] = screen; + return true; +} + +static inline bool ui_display_screens(uint8_t *postition) { + if (MAX_NUMBER_OF_SCREENS - *postition < 2) return false; + + G_ux_flow_steps[(*postition)++] = FLOW_LOOP; + G_ux_flow_steps[(*postition)++] = FLOW_END_STEP; + + ux_flow_init(0, G_ux_flow_steps, NULL); + + app_set_ui_busy(true); + + return true; +} + +#endif + diff --git a/src/ui/ui_menu.c b/src/ui/ui_menu.c index 6c621e6f..c11aaa5f 100644 --- a/src/ui/ui_menu.c +++ b/src/ui/ui_menu.c @@ -19,8 +19,8 @@ #include #include -#include "../globals.h" #include "ui_menu.h" +#include "ui_main.h" UX_STEP_NOCB(ux_menu_ready_step, pnn, {&C_app_logo, APPNAME, "is ready"}); UX_STEP_CB(ux_menu_about_step, pb, ui_menu_about(), {&C_icon_certificate, "About"}); @@ -31,25 +31,25 @@ void ui_menu_main() { ux_stack_push(); } - G_ux_flow[0] = &ux_menu_ready_step; - G_ux_flow[1] = &ux_menu_about_step; - G_ux_flow[2] = &ux_menu_exit_step; - G_ux_flow[3] = FLOW_LOOP; - G_ux_flow[4] = FLOW_END_STEP; + uint8_t screen = 0; + ui_add_screen(&ux_menu_ready_step, &screen); + ui_add_screen(&ux_menu_about_step, &screen); + ui_add_screen(&ux_menu_exit_step, &screen); + ui_display_screens(&screen); - ux_flow_init(0, G_ux_flow, NULL); + app_set_ui_busy(false); } -UX_STEP_NOCB(ux_menu_info_step, bn, {APPNAME " App", "(c) 2023 Ergo"}); +UX_STEP_NOCB(ux_menu_info_step, bn, {APPNAME " App", "(c) 2024 Ergo"}); UX_STEP_NOCB(ux_menu_version_step, bn, {"Version", APPVERSION}); UX_STEP_CB(ux_menu_back_step, pb, ui_menu_main(), {&C_icon_back, "Back"}); void ui_menu_about() { - G_ux_flow[0] = &ux_menu_info_step; - G_ux_flow[1] = &ux_menu_version_step; - G_ux_flow[2] = &ux_menu_back_step; - G_ux_flow[3] = FLOW_LOOP; - G_ux_flow[4] = FLOW_END_STEP; + uint8_t screen = 0; + ui_add_screen(&ux_menu_info_step, &screen); + ui_add_screen(&ux_menu_version_step, &screen); + ui_add_screen(&ux_menu_back_step, &screen); + ui_display_screens(&screen); - ux_flow_init(0, G_ux_flow, NULL); + app_set_ui_busy(false); } diff --git a/src/ui/ui_menu.h b/src/ui/ui_menu.h index d9c69e08..c4258c9e 100644 --- a/src/ui/ui_menu.h +++ b/src/ui/ui_menu.h @@ -8,4 +8,4 @@ void ui_menu_main(void); /** * Show about submenu (copyright, date). */ -void ui_menu_about(void); +void ui_menu_about(void);