diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 40040d6..c8658da 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install cmocka run: | sudo apt update @@ -37,7 +37,7 @@ jobs: lcov --directory . -b "$(realpath build/)" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info lcov --directory . -b "$(realpath build/)" --remove coverage.info '*/unit-tests/*' -o coverage.info genhtml coverage.info -o coverage - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: code-coverage path: tests/unit/coverage diff --git a/.github/workflows/codeql-workflow.yml b/.github/workflows/codeql-workflow.yml index 54c50f2..7f74a6f 100644 --- a/.github/workflows/codeql-workflow.yml +++ b/.github/workflows/codeql-workflow.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 diff --git a/.github/workflows/lint-workflow.yml b/.github/workflows/lint-workflow.yml index 5340045..612bd44 100644 --- a/.github/workflows/lint-workflow.yml +++ b/.github/workflows/lint-workflow.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Lint uses: DoozyX/clang-format-lint-action@v0.14 @@ -32,7 +32,7 @@ jobs: steps: - name: Clone - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9f957aa --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.1.3] - 2024-??-?? + +### Fix + +- Bug #38: some applications were randomly lowering capital characters, leading passwords containing + capital characters to be almost always wrong. + +## [1.1.2] - 2023-10-12 (Stax only) + +### Fix + +- Updated porting to Stax SDK evolutions + +## [1.1.1] - 2023-04-25 (Stax only) + +### Fix + +- Derivation path changed, from `44'/1` to `5265220'` + +## [1.1.0] - 2023-04-12 (Stax only) + +### Add + +- Stax porting + +## [1.0.2] - 2022-03-02 + +Original Passwords application diff --git a/Makefile b/Makefile index ea5cb50..40f86c2 100644 --- a/Makefile +++ b/Makefile @@ -28,20 +28,19 @@ APPVERSION_N=1 APPVERSION_P=2 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -APP_LOAD_PARAMS=--appFlags 0x40 --path "5265220'" --curve secp256k1 $(COMMON_LOAD_PARAMS) +VARIANT_PARAM = NONE +VARIANT_VALUES = pwmgr -DEFINES += APPNAME=\"$(APPNAME)\" -DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) PATCH_VERSION=$(APPVERSION_P) -DEFINES += APPVERSION=\"$(APPVERSION)\" +CURVE_APP_LOAD_PARAMS = secp256k1 +PATH_APP_LOAD_PARAMS = "5265220'" +HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1 -ifeq ($(TARGET_NAME),TARGET_NANOS) - ICONNAME=icons/nanos_icon_password_manager.gif -else ifeq ($(TARGET_NAME), TARGET_STAX) - ICONNAME=icons/stax_icon_password_manager_32px.gif -else - ICONNAME=icons/nanox_icon_password_manager.gif -endif +DEFINES += APPNAME=\"$(APPNAME)\" +ICON_NANOS = icons/nanos_icon_password_manager.gif +ICON_NANOSP = icons/nanox_icon_password_manager.gif +ICON_NANOX = icons/nanox_icon_password_manager.gif +ICON_STAX = icons/stax_icon_password_manager_32px.gif DEFINES += OS_IO_SEPROXYHAL DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=4 IO_HID_EP_LENGTH=64 HAVE_USB_APDU @@ -88,53 +87,10 @@ else DEFINES += POPULATE endif -# Enabling debug PRINTF -DEBUG ?= 0 -ifneq ($(DEBUG),0) - $(info DEBUG ENABLED) - DEFINES += HAVE_STACK_OVERFLOW_CHECK HAVE_PRINTF - ifeq ($(TARGET_NAME),TARGET_NANOS) - DEFINES += PRINTF=screen_printf - else - DEFINES += PRINTF=mcu_usb_printf - endif -else - $(info DEBUG DISABLED) - DEFINES += PRINTF\(...\)= -endif - -############## -# Compiler # -############## -CC := $(CLANGPATH)clang -AS := $(GCCPATH)arm-none-eabi-gcc -LD := $(GCCPATH)arm-none-eabi-gcc -LDLIBS += -lm -lgcc -lc - -# import rules to compile glyphs(/pone) -include $(BOLOS_SDK)/Makefile.glyphs - ### computed variables APP_SOURCE_PATH += src -SDK_SOURCE_PATH += lib_stusb lib_stusb_impl - -ifneq ($(TARGET_NAME), TARGET_NANOS) -ifneq ($(TARGET_NAME), TARGET_STAX) - SDK_SOURCE_PATH += lib_ux -endif -endif - -load: all - python -m ledgerblue.loadApp $(APP_LOAD_PARAMS) - -delete: - python -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS) - -# import generic rules from the sdk -include $(BOLOS_SDK)/Makefile.rules #add dependency on custom makefile filename dep/%.d: %.c Makefile -listvariants: - @echo VARIANTS NONE pwmgr +include $(BOLOS_SDK)/Makefile.standard_app diff --git a/include/hid_mapping.h b/include/hid_mapping.h index 070ba1b..310af42 100644 --- a/include/hid_mapping.h +++ b/include/hid_mapping.h @@ -15,9 +15,11 @@ * limitations under the License. ********************************************************************************/ -#ifndef HID_MAPPING_H +#pragma once #define HID_MAPPING_H +#define SHIFT_KEY 0x02 +#define ALT_KEY 0x04 #include @@ -29,5 +31,3 @@ enum hid_mapping_e { typedef enum hid_mapping_e hid_mapping_t; void map_char(hid_mapping_t mapping, uint8_t key, uint8_t *out); - -#endif diff --git a/src/apdu_handlers/dump_metadatas.c b/src/apdu_handlers/dump_metadatas.c index 19ab01b..77ebc5d 100644 --- a/src/apdu_handlers/dump_metadatas.c +++ b/src/apdu_handlers/dump_metadatas.c @@ -1,7 +1,7 @@ #include "dump_metadatas.h" +#include "error.h" #include "globals.h" #include "io.h" -#include "sw.h" #include "password_ui_flows.h" int dump_metadatas() { @@ -31,8 +31,7 @@ int dump_metadatas() { app_state.bytes_transferred += payload_size; - const buf_t response = {.bytes = G_io_apdu_buffer, - .size = payload_size + TRANSFER_PAYLOAD_OFFSET}; - - return send(&response, SW_OK); + return io_send_response_pointer(G_io_apdu_buffer, + payload_size + TRANSFER_PAYLOAD_OFFSET, + SW_OK); } diff --git a/src/apdu_handlers/get_app_config.c b/src/apdu_handlers/get_app_config.c index 6601f70..a81243d 100644 --- a/src/apdu_handlers/get_app_config.c +++ b/src/apdu_handlers/get_app_config.c @@ -15,21 +15,21 @@ * limitations under the License. ********************************************************************************/ +#include #include #include #include #include -#include "../password_ui_flows.h" +#include "error.h" #include "get_app_config.h" -#include "io.h" -#include "sw.h" -#include "types.h" #include "globals.h" +#include "password_ui_flows.h" +#include "types.h" int get_app_config(uint8_t p1, uint8_t p2, __attribute__((unused)) const buf_t* input) { if (p1 != 0 || p2 != 0) { - return send_sw(SW_WRONG_P1P2); + return io_send_sw(SW_WRONG_P1P2); } uint8_t* config = G_io_apdu_buffer; @@ -43,8 +43,6 @@ int get_app_config(uint8_t p1, uint8_t p2, __attribute__((unused)) const buf_t* config[offset++] = N_storage.keyboard_layout; config[offset++] = N_storage.press_enter_after_typing; - const buf_t buf = {.bytes = config, .size = offset}; - ui_idle(); - return send(&buf, SW_OK); + return io_send_response_pointer(config, offset, SW_OK); } diff --git a/src/apdu_handlers/load_metadatas.c b/src/apdu_handlers/load_metadatas.c index 5fccb56..8809304 100644 --- a/src/apdu_handlers/load_metadatas.c +++ b/src/apdu_handlers/load_metadatas.c @@ -1,13 +1,14 @@ -#include "load_metadatas.h" -#include "io.h" +#include + +#include "error.h" #include "globals.h" -#include "sw.h" +#include "load_metadatas.h" #include "metadata.h" #include "password_ui_flows.h" int load_metadatas(uint8_t p1, uint8_t p2, const buf_t *input) { if ((p1 != 0 && p1 != P1_LAST_CHUNK) || p2 != 0) { - return send_sw(SW_WRONG_P1P2); + return io_send_sw(SW_WRONG_P1P2); } if (app_state.user_approval == false) { app_state.bytes_transferred = 0; @@ -17,7 +18,7 @@ int load_metadatas(uint8_t p1, uint8_t p2, const buf_t *input) { } if (input->size > sizeof(N_storage.metadatas) - app_state.bytes_transferred) { - return send_sw(SW_WRONG_DATA_LENGTH); + return io_send_sw(SW_WRONG_DATA_LENGTH); } override_metadatas(app_state.bytes_transferred, (void *) input->bytes, input->size); @@ -28,9 +29,9 @@ int load_metadatas(uint8_t p1, uint8_t p2, const buf_t *input) { app_state.user_approval = false; ui_idle(); if (compact_metadata()) { - return send_sw(SW_METADATAS_PARSING_ERROR); + return io_send_sw(SW_METADATAS_PARSING_ERROR); } } - return send_sw(SW_OK); + return io_send_sw(SW_OK); } diff --git a/src/main.c b/src/app_main.c similarity index 71% rename from src/main.c rename to src/app_main.c index f26dba0..3a5864a 100644 --- a/src/main.c +++ b/src/app_main.c @@ -15,40 +15,38 @@ * limitations under the License. ********************************************************************************/ -#include "os.h" -#include "cx.h" +#include +#include +#include +#include +#include #include +#include -#include "os_io_seproxyhal.h" -#include "string.h" +#include +#include +#include +#include #include "glyphs.h" - -#include "ctr_drbg.h" -#include "hid_mapping.h" -#include "password_generation.h" -#include "usbd_hid_impl.h" -#include "io.h" -#include "sw.h" - -#include "password_ui_flows.h" -#include "password_typing.h" +#include "dispatcher.h" +#include "error.h" #include "globals.h" #include "metadata.h" -#include "dispatcher.h" +#include "password_ui_flows.h" +#include "password_typing.h" -unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; const internalStorage_t N_storage_real; app_state_t app_state; volatile unsigned int G_led_status; -void app_init() { +void app_main() { + int input_len = 0; + init_storage(); memset(&app_state, 0, sizeof(app_state)); -} -void app_main() { - int input_len = 0; + ui_idle(); app_state.io.output_len = 0; app_state.io.state = READY; @@ -64,14 +62,14 @@ void app_main() { for (;;) { BEGIN_TRY { TRY { - input_len = recv(); + input_len = io_recv_command(); if (input_len == -1) { return; } PRINTF("=> %.*H\n", input_len, G_io_apdu_buffer); if (input_len < OFFSET_CDATA || input_len - OFFSET_CDATA != G_io_apdu_buffer[OFFSET_LC]) { - send_sw(SW_WRONG_DATA_LENGTH); + io_send_sw(SW_WRONG_DATA_LENGTH); continue; } if (dispatch() < 0) { @@ -82,7 +80,7 @@ void app_main() { THROW(EXCEPTION_IO_RESET); } CATCH_OTHER(e) { - send_sw(e); + io_send_sw(e); } FINALLY { } @@ -101,41 +99,3 @@ void app_exit(void) { } END_TRY_L(exit); } - -__attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); - - // ensure exception will work as planned - os_boot(); - -#if defined(HAVE_NBGL) - nbgl_objInit(); -#elif defined(HAVE_BAGL) - UX_INIT(); -#endif - - BEGIN_TRY { - TRY { - io_seproxyhal_init(); - - app_init(); - - USB_power(0); - USB_power(1); - - ui_idle(); - - app_main(); - } - CATCH_OTHER(e) { - } - FINALLY { - } - } - END_TRY; - - app_exit(); - - return 0; -} diff --git a/src/dispatcher.c b/src/dispatcher.c index b23fca7..09ee698 100644 --- a/src/dispatcher.c +++ b/src/dispatcher.c @@ -15,21 +15,22 @@ * limitations under the License. ********************************************************************************/ +#include +#include #include -#include "dispatcher.h" -#include "types.h" -#include "globals.h" -#include "io.h" -#include "sw.h" #include "apdu_handlers/dump_metadatas.h" #include "apdu_handlers/load_metadatas.h" #include "apdu_handlers/get_app_config.h" +#include "dispatcher.h" +#include "error.h" +#include "globals.h" #include "tests/tests.h" +#include "types.h" int dispatch() { if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { - return send_sw(SW_CLA_NOT_SUPPORTED); + return io_send_sw(SW_CLA_NOT_SUPPORTED); } uint8_t ins = G_io_apdu_buffer[OFFSET_INS]; @@ -56,6 +57,6 @@ int dispatch() { return test_dispatcher(p1, p2, &input); #endif default: - return send_sw(SW_INS_NOT_SUPPORTED); + return io_send_sw(SW_INS_NOT_SUPPORTED); } } diff --git a/src/error.c b/src/error.c index 6f4b0a3..22cb2c6 100644 --- a/src/error.c +++ b/src/error.c @@ -1,13 +1,16 @@ #include "error.h" static const message_pair_t ERR_MESSAGES[5] = { - {"", ""}, // OK - {"Write Error", "Database is full"}, // ERR_NO_MORE_SPACE_AVAILABLE - {"Write Error", - "Database should be repaired, please contact Ledger Support"}, // ERR_CORRUPTED_METADATA - {"Erase Error", "Database already empty"}, // ERR_NO_METADATA - {"Write Error", "Entry is too big"} // ERR_METADATA_ENTRY_TOO_BIG -}; + // OK + {}, + // ERR_NO_MORE_SPACE_AVAILABLE + {"Write Error", "Database is full"}, + // ERR_CORRUPTED_METADATA + {"Write Error", "Database should be repaired, please contact Ledger Support"}, + // ERR_NO_METADATA + {"Erase Error", "Database already empty"}, + // ERR_METADATA_ENTRY_TOO_BIG + {"Write Error", "Entry is too big"}}; message_pair_t get_error(const error_type_t error) { return ERR_MESSAGES[error]; diff --git a/src/error.h b/src/error.h index 512c1b3..1ec9d75 100644 --- a/src/error.h +++ b/src/error.h @@ -2,4 +2,21 @@ #include "types.h" +#define SW_OK 0x9000 +#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 +#define SW_WRONG_P1P2 0x6A86 +#define SW_WRONG_DATA_LENGTH 0x6A87 +#define SW_INS_NOT_SUPPORTED 0x6D00 +#define SW_CLA_NOT_SUPPORTED 0x6E00 +#define SW_APPNAME_TOO_LONG 0xB000 +#define SW_METADATAS_PARSING_ERROR 0x6F10 + +typedef enum error_type_e { + OK = 0, + ERR_NO_MORE_SPACE_AVAILABLE = 1, + ERR_CORRUPTED_METADATA = 2, + ERR_NO_METADATA = 3, + ERR_METADATA_ENTRY_TOO_BIG = 4 +} error_type_t; + message_pair_t get_error(const error_type_t error); diff --git a/src/globals.h b/src/globals.h index a8f9c18..6f5d37a 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1,20 +1,13 @@ #pragma once -#include "os.h" -#include "os_io_seproxyhal.h" +#include +#include #include "types.h" extern const internalStorage_t N_storage_real; extern app_state_t app_state; extern volatile unsigned int G_led_status; -#define OFFSET_CLA 0 -#define OFFSET_INS 1 -#define OFFSET_P1 2 -#define OFFSET_P2 3 -#define OFFSET_LC 4 -#define OFFSET_CDATA 5 - #define CLA 0xE0 #define N_storage (*(volatile internalStorage_t*) PIC(&N_storage_real)) diff --git a/src/hid_mapping.c b/src/hid_mapping.c index 5b00c68..d792b95 100644 --- a/src/hid_mapping.c +++ b/src/hid_mapping.c @@ -25,273 +25,149 @@ static const uint8_t TWOPOWER[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; -static const uint8_t MAP_QWERTY[] = { - // alt mask from ascii 0x20 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - // shift mask from ascii 0x20 - 0x7E, - 0x0f, - 0x00, - 0xd4, - 0xff, - 0xff, - 0xff, - 0xc7, - 0x00, - 0x00, - 0x00, - 0x78, - // key codes from ascii 0x20 - 0x2c, - 0x1e, - 0x34, - 0x20, - 0x21, - 0x22, - 0x24, - 0x34, - 0x26, - 0x27, - 0x25, - 0x2e, - 0x36, - 0x2d, - 0x37, - 0x38, - 0x27, - 0x1e, - 0x1f, - 0x20, - 0x21, - 0x22, - 0x23, - 0x24, - 0x25, - 0x26, - 0x33, - 0x33, - 0x36, - 0x2e, - 0x37, - 0x38, - 0x1f, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f, - 0x10, - 0x11, - 0x12, - 0x13, - 0x14, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1a, - 0x1b, - 0x1c, - 0x1d, - 0x2f, - 0x31, - 0x30, - 0x23, - 0x2d, - 0x35, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f, - 0x10, - 0x11, - 0x12, - 0x13, - 0x14, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1a, - 0x1b, - 0x1c, - 0x1d, - 0x2f, - 0x31, - 0x30, - 0x35}; +typedef struct mapping_s { + uint8_t qwerty; + uint8_t azerty; +} mapping_t; -static const uint8_t MAP_AZERTY[] = { - // altgr mask from ascii 0x20 - 0x08, - 0x00, - 0x00, - 0x00, - 0x01, - 0x00, - 0x00, - 0x78, - 0x01, - 0x00, - 0x00, - 0x78, +static const mapping_t MAP[] = { + // alt mask from ascii 0x20 + {0x00, 0x08}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x00, 0x01}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x00, 0x78}, + {0x00, 0x01}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x00, 0x78}, // shift mask from ascii 0x20 - 0x20, - 0xc8, - 0xff, - 0xc3, - 0xfe, - 0xff, - 0xff, - 0x07, - 0x00, - 0x00, - 0x00, - 0x00, + {0x7E, 0x20}, + {0x0f, 0xc8}, + {0x00, 0xff}, + {0xd4, 0xc3}, + {0xff, 0xfe}, + {0xff, 0xff}, + {0xff, 0xff}, + {0xc7, 0x07}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x00, 0x00}, + {0x78, 0x00}, // key codes from ascii 0x20 - 0x2c, - 0x38, - 0x20, - 0x20, - 0x30, - 0x34, - 0x1e, - 0x21, - 0x22, - 0x2d, - 0x32, - 0x2e, - 0x10, - 0x23, - 0x36, - 0x37, - 0x27, - 0x1e, - 0x1f, - 0x20, - 0x21, - 0x22, - 0x23, - 0x24, - 0x25, - 0x26, - 0x37, - 0x36, - 0x64, - 0x2e, - 0x64, - 0x10, - 0x27, - 0x14, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f, - 0x33, - 0x11, - 0x12, - 0x13, - 0x04, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1d, - 0x1b, - 0x1c, - 0x1a, - 0x22, - 0x25, - 0x2D, - 0x26, - 0x25, - 0x24, - 0x14, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0a, - 0x0b, - 0x0c, - 0x0d, - 0x0e, - 0x0f, - 0x33, - 0x11, - 0x12, - 0x13, - 0x04, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1d, - 0x1b, - 0x1c, - 0x1a, - 0x21, - 0x23, - 0x2e, - 0x1f}; + {0x2c, 0x2c}, // ' ' (i = 32 - 8) + {0x1e, 0x38}, // '!' + {0x34, 0x20}, // '"' + {0x20, 0x20}, // '#' + {0x21, 0x30}, // '$' + {0x22, 0x34}, // '%' + {0x24, 0x1e}, // '&' + {0x34, 0x21}, // ''' + {0x26, 0x22}, // '(' + {0x27, 0x2d}, // ')' + {0x25, 0x32}, // '*' + {0x2e, 0x2e}, // '+' + {0x36, 0x10}, // ',' + {0x2d, 0x23}, // '-' + {0x37, 0x36}, // '.' + {0x38, 0x37}, // '/' + {0x27, 0x27}, // '0' (i = 48 - 8) + {0x1e, 0x1e}, // '1' + {0x1f, 0x1f}, + {0x20, 0x20}, + {0x21, 0x21}, + {0x22, 0x22}, + {0x23, 0x23}, + {0x24, 0x24}, + {0x25, 0x25}, + {0x26, 0x26}, // '9' + {0x33, 0x37}, // ':' + {0x33, 0x36}, // ';' + {0x36, 0x64}, // '<' + {0x2e, 0x2e}, // '=' + {0x37, 0x64}, // '>' + {0x38, 0x10}, // '?' + {0x1f, 0x27}, // '@' + {0x04, 0x14}, // 'A' (i = 65 - 8) + {0x05, 0x05}, + {0x06, 0x06}, + {0x07, 0x07}, + {0x08, 0x08}, + {0x09, 0x09}, + {0x0a, 0x0a}, + {0x0b, 0x0b}, + {0x0c, 0x0c}, + {0x0d, 0x0d}, + {0x0e, 0x0e}, + {0x0f, 0x0f}, + {0x10, 0x33}, + {0x11, 0x11}, + {0x12, 0x12}, + {0x13, 0x13}, + {0x14, 0x04}, + {0x15, 0x15}, + {0x16, 0x16}, + {0x17, 0x17}, + {0x18, 0x18}, + {0x19, 0x19}, + {0x1a, 0x1d}, + {0x1b, 0x1b}, + {0x1c, 0x1c}, + {0x1d, 0x1a}, // 'Z' (i = 90 - 8) + {0x2f, 0x22}, // '[' + {0x31, 0x25}, // '\' + {0x30, 0x2D}, // ']' + {0x23, 0x26}, // '^' + {0x2d, 0x25}, // '_' + {0x35, 0x24}, // '`' + {0x04, 0x14}, // 'a' (i = 97 - 8) + {0x05, 0x05}, + {0x06, 0x06}, + {0x07, 0x07}, + {0x08, 0x08}, + {0x09, 0x09}, + {0x0a, 0x0a}, + {0x0b, 0x0b}, + {0x0c, 0x0c}, + {0x0d, 0x0d}, + {0x0e, 0x0e}, + {0x0f, 0x0f}, + {0x10, 0x33}, + {0x11, 0x11}, + {0x12, 0x12}, + {0x13, 0x13}, + {0x14, 0x04}, + {0x15, 0x15}, + {0x16, 0x16}, + {0x17, 0x17}, + {0x18, 0x18}, + {0x19, 0x19}, + {0x1a, 0x1d}, + {0x1b, 0x1b}, + {0x1c, 0x1c}, + {0x1d, 0x1a}, // 'z' (i = 122 - 8) + {0x2f, 0x21}, // '{' + {0x31, 0x23}, // '|' + {0x30, 0x2e}, // '}' + {0x35, 0x1f}, // '~' (i = 126 - 8) +}; #if 0 // a good test string out = "a&b~c#d {e\"f'g(h -i _j)k=l+m [n |o \\p^q @r ]s }t$u!v:w/x;y.z,A?B D`EFGHIJKLMNOPQRSTUVWXYZ0123456789"; #endif -void map_char(hid_mapping_t mapping, uint8_t key, uint8_t *out) { - uint8_t keyDiv8, twoPower, keyCode, altUsed, shiftUsed; - uint8_t *map; +static uint8_t get_char(uint8_t index, hid_mapping_t mapping) { + // all mapping != AZERTY fall back to QWERTY + some adjustments + return (mapping == HID_MAPPING_AZERTY ? MAP[index].azerty : MAP[index].qwerty); +} - switch (mapping) { - default: - // THROW(EXCEPTION); - case HID_MAPPING_QWERTY: - map = (uint8_t *) MAP_QWERTY; - break; - case HID_MAPPING_AZERTY: - map = (uint8_t *) MAP_AZERTY; - break; - } +void map_char(hid_mapping_t mapping, uint8_t key, uint8_t *out) { + uint8_t keyDiv8, twoPower, keyCode; + bool altUsed, shiftUsed; if (key < KEYCODE_START) { THROW(EXCEPTION); @@ -302,10 +178,10 @@ void map_char(hid_mapping_t mapping, uint8_t key, uint8_t *out) { } keyDiv8 = (key / 8); twoPower = TWOPOWER[key % 8]; - altUsed = ((map[keyDiv8] & twoPower) != 0); - shiftUsed = ((map[MOD_MASK_LENGTH + keyDiv8] & twoPower) != 0); - keyCode = map[MOD2_MASK_LENGTH + key]; - out[0] = (altUsed ? 0x40 : 0x00) | (shiftUsed ? 0x02 : 0x00); + altUsed = ((get_char(keyDiv8, mapping) & twoPower) != 0); + shiftUsed = ((get_char(MOD_MASK_LENGTH + keyDiv8, mapping) & twoPower) != 0); + keyCode = get_char(MOD2_MASK_LENGTH + key, mapping); + out[0] = (altUsed ? ALT_KEY : 0x00) | (shiftUsed ? SHIFT_KEY : 0x00); out[1] = 0x00; out[2] = keyCode; } diff --git a/src/io.c b/src/io.c deleted file mode 100644 index 55ce571..0000000 --- a/src/io.c +++ /dev/null @@ -1,151 +0,0 @@ -/******************************************************************************* - * Password Manager application - * (c) 2017-2023 Ledger SAS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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" - -#if !defined(TARGET_STAX) -void io_seproxyhal_display(const bagl_element_t *element) { - io_seproxyhal_display_default((bagl_element_t *) element); -} -#endif - -uint8_t io_event(__attribute__((unused)) uint8_t channel) { - switch (G_io_seproxyhal_spi_buffer[0]) { - case SEPROXYHAL_TAG_FINGER_EVENT: - UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer); - break; -#if !defined(HAVE_NBGL) - case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT: - UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer); - break; -#endif - 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 */ - __attribute__((fallthrough)); - default: - UX_DEFAULT_EVENT(); - break; - case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT: -#if !defined(HAVE_NBGL) - UX_DISPLAYED_EVENT({}); -#endif -#ifdef HAVE_NBGL - UX_DEFAULT_EVENT(); -#endif // HAVE_NBGL - break; - case SEPROXYHAL_TAG_TICKER_EVENT: - UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); - 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) { - reset(); - } - - return 0; - } else { - return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0); - } - default: - THROW(INVALID_PARAMETER); - } - - return 0; -} - -int recv() { - int ret; - - switch (app_state.io.state) { - case READY: - app_state.io.state = RECEIVED; - ret = io_exchange(CHANNEL_APDU, app_state.io.output_len); - break; - case RECEIVED: - app_state.io.state = WAITING; - ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, app_state.io.output_len); - app_state.io.state = RECEIVED; - break; - case WAITING: - app_state.io.state = READY; - ret = -1; - break; - } - - return ret; -} - -int send(const buf_t *buf, uint16_t sw) { - int ret; - - if (buf != NULL) { - memmove(G_io_apdu_buffer, buf->bytes, buf->size); - app_state.io.output_len = buf->size; - PRINTF("<= %.*H %02X%02X\n", buf->size, buf->bytes, sw >> 8, sw & 0xFF); - } else { - app_state.io.output_len = 0; - PRINTF("<= %02X%02X\n", sw >> 8, sw & 0xFF); - } - - G_io_apdu_buffer[app_state.io.output_len++] = (uint8_t)(sw >> 8); - G_io_apdu_buffer[app_state.io.output_len++] = (uint8_t)(sw & 0xFF); - - switch (app_state.io.state) { - case READY: - ret = -1; - break; - case RECEIVED: - app_state.io.state = READY; - ret = 0; - break; - case WAITING: - ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, app_state.io.output_len); - app_state.io.output_len = 0; - app_state.io.state = READY; - break; - } - - return ret; -} - -int send_sw(uint16_t sw) { - return send(NULL, sw); -} diff --git a/src/io.h b/src/io.h deleted file mode 100644 index 51c1969..0000000 --- a/src/io.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -#include "types.h" - -#if !defined(TARGET_STAX) -void io_seproxyhal_display(const bagl_element_t *element); -#endif - -uint8_t io_event(uint8_t channel); -uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len); -int recv(void); -int send(const buf_t *buf, uint16_t sw); -int send_sw(uint16_t sw); diff --git a/src/metadata.h b/src/metadata.h index 4f36fd7..a128e8c 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -2,6 +2,7 @@ #include +#include "error.h" #include "types.h" #define METADATA_PTR(offset) (&N_storage.metadatas[offset]) diff --git a/src/password_generation.c b/src/password_generation.c index 49fd553..fb3a22e 100644 --- a/src/password_generation.c +++ b/src/password_generation.c @@ -15,10 +15,7 @@ * limitations under the License. ********************************************************************************/ -#include -#include #include - #include static const char *SETS[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 26 diff --git a/src/password_typing.c b/src/password_typing.c index df1aa73..3762e9b 100644 --- a/src/password_typing.c +++ b/src/password_typing.c @@ -8,36 +8,34 @@ #include "password_typing.h" #include "globals.h" -static const uint8_t EMPTY_REPORT[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t SPACE_REPORT[] = {0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t CAPS_REPORT[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t CAPS_LOCK_REPORT[] = {0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t ENTER_REPORT[] = {0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00}; - -uint8_t entropyProvided; +#define REPORT_SIZE 8 +static const uint8_t EMPTY_REPORT[REPORT_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t SPACE_REPORT[REPORT_SIZE] = {0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t CAPS_REPORT[REPORT_SIZE] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t CAPS_LOCK_REPORT[REPORT_SIZE] = + {0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t ENTER_REPORT[REPORT_SIZE] = {0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00}; + +bool entropyProvided; uint8_t entropy[32]; static int entropyProvider2(__attribute__((unused)) void *context, unsigned char *buffer, __attribute__((unused)) size_t bufferSize) { if (entropyProvided) { - // PRINTF("no more entropy\n"); return 1; } memcpy(buffer, entropy, 32); - // PRINTF("entropy: %.*H\n", 32, entropy); - entropyProvided = 1; + entropyProvided = true; return 0; } -void io_usb_send_ep_wait(unsigned int ep, - unsigned char *buf, - unsigned int len, - __attribute__((unused)) unsigned int timeout_cs) { - io_usb_send_ep(ep, buf, len, 20); +#ifndef TESTING +static void usb_write_wait(unsigned char *buf) { + io_usb_send_ep(HID_EPIN_ADDR, buf, REPORT_SIZE, 60); // wait until transfer timeout, or ended - while (G_io_app.usb_ep_timeouts[ep & 0x7F].timeout) { + while (G_io_app.usb_ep_timeouts[HID_EPIN_ADDR & 0x7F].timeout) { if (!io_seproxyhal_spi_is_status_sent()) { io_seproxyhal_general_status(); } @@ -45,6 +43,11 @@ void io_usb_send_ep_wait(unsigned int ep, io_seproxyhal_handle_event(); } } +#else +static void usb_write_wait(__attribute__((unused)) unsigned char *buf) { + return; +} +#endif // TESTING bool type_password(uint8_t *data, uint32_t dataSize, @@ -56,7 +59,7 @@ bool type_password(uint8_t *data, uint32_t led_status; uint8_t tmp[64]; uint8_t i; - uint8_t report[8]; + uint8_t report[REPORT_SIZE] = {0}; cx_hash_sha256(data, dataSize, tmp, sizeof(tmp)); derive[0] = DERIVE_PASSWORD_PATH; @@ -68,10 +71,9 @@ bool type_password(uint8_t *data, if (os_derive_bip32_no_throw(CX_CURVE_SECP256K1, derive, 9, tmp, tmp + 32) != CX_OK) { return false; } - // PRINTF("pwseed %.*H\n", 64, tmp); cx_hash_sha256(tmp, 64, entropy, sizeof(entropy)); memset(tmp, 0, sizeof(tmp)); - entropyProvided = 0; + entropyProvided = false; mbedtls_ctr_drbg_context ctx; mbedtls_ctr_drbg_init(&ctx); if (mbedtls_ctr_drbg_seed(&ctx, entropyProvider2, NULL, NULL, 0) != 0) { @@ -84,24 +86,29 @@ bool type_password(uint8_t *data, generate_password(&ctx, setMask, minFromSet, tmp, size); - memset(report, 0, sizeof(report)); - // Insert EMPTY_REPORT CAPS_REPORT EMPTY_REPORT to avoid undesired capital letter on KONSOLE led_status = G_led_status; - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) CAPS_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + // Insert EMPTY_REPORT CAPS_REPORT EMPTY_REPORT to avoid undesired capital letter on KONSOLE + usb_write_wait((uint8_t *) EMPTY_REPORT); + usb_write_wait((uint8_t *) CAPS_REPORT); + usb_write_wait((uint8_t *) EMPTY_REPORT); // toggle shift if set. if (led_status & 2) { - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) CAPS_LOCK_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + usb_write_wait((uint8_t *) CAPS_LOCK_REPORT); + usb_write_wait((uint8_t *) EMPTY_REPORT); } + for (i = 0; i < size; i++) { // If keyboard layout not initialized, use the default map_char(N_storage.keyboard_layout, tmp[i], report); - io_usb_send_ep_wait(HID_EPIN_ADDR, report, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + + usb_write_wait(report); + if (report[0] & SHIFT_KEY) { + usb_write_wait((uint8_t *) CAPS_REPORT); + } else { + usb_write_wait((uint8_t *) EMPTY_REPORT); + } // for international keyboard, make sure to insert space after special symbols if (N_storage.keyboard_layout == HID_MAPPING_QWERTY_INTL) { @@ -112,22 +119,23 @@ bool type_password(uint8_t *data, case '~': case '^': // insert a extra space to validate the symbol - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) SPACE_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + usb_write_wait((uint8_t *) SPACE_REPORT); + usb_write_wait((uint8_t *) EMPTY_REPORT); break; } } } + usb_write_wait((uint8_t *) EMPTY_REPORT); // restore shift state if (led_status & 2) { - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) CAPS_LOCK_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + usb_write_wait((uint8_t *) CAPS_LOCK_REPORT); + usb_write_wait((uint8_t *) EMPTY_REPORT); } if (N_storage.press_enter_after_typing) { // press enter - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) ENTER_REPORT, 8, 20); - io_usb_send_ep_wait(HID_EPIN_ADDR, (uint8_t *) EMPTY_REPORT, 8, 20); + usb_write_wait((uint8_t *) ENTER_REPORT); + usb_write_wait((uint8_t *) EMPTY_REPORT); } return true; diff --git a/src/password_typing.h b/src/password_typing.h index fc5234b..2939c95 100644 --- a/src/password_typing.h +++ b/src/password_typing.h @@ -1,12 +1,9 @@ #pragma once -#include "stdint.h" -#include "password_generation.h" +#include + +#include -void io_usb_send_ep_wait(unsigned int ep, - unsigned char *buf, - unsigned int len, - unsigned int timeout_cs); bool type_password(uint8_t *data, uint32_t dataSize, uint8_t *out, diff --git a/src/password_ui_flows.c b/src/password_ui_flows.c index 2b741ed..76074d7 100644 --- a/src/password_ui_flows.c +++ b/src/password_ui_flows.c @@ -1,18 +1,17 @@ -#include -#include +#include +#include #include +#include #include +#include "dispatcher.h" #include "error.h" +#include "globals.h" +#include "metadata.h" #include "password_ui_flows.h" #include "password.h" -#include "globals.h" #include "password_typing.h" -#include "metadata.h" -#include "dispatcher.h" -#include "sw.h" -#include "io.h" #define LINE_1_SIZE 16 char line_buffer_1[LINE_1_SIZE]; @@ -29,9 +28,6 @@ char line_buffer_2[PASSWORD_MAX_SIZE + 1]; #define TXT_PRESS_ENTER "Press Enter" #define TXT_DONT_PRESS_ENTER "Don't press Enter" -ux_state_t G_ux; -bolos_ux_params_t G_ux_params; - #if defined(TARGET_STAX) #include "stax/ui.h" @@ -43,7 +39,7 @@ void ui_request_user_approval(message_pair_t *msg) { display_approval_page(msg); } -#else +#else // if defined(TARGET_STAX) #include "keyboard.h" #include "options.h" @@ -65,7 +61,7 @@ app_state.user_approval = true; dispatch(), UX_STEP_CB( generic_cancel_step, pb, -send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); ui_idle(), +io_send_sw(SW_CONDITIONS_OF_USE_NOT_SATISFIED); ui_idle(), { &C_icon_back, "Cancel", @@ -92,7 +88,7 @@ static void select_password_and_apply_cb(); static void type_password_cb(const size_t offset); static void show_password_cb(const size_t offset); static void reset_password_cb(const size_t offset); -static void ui_error(message_pair_t err); +static void ui_error(error_type_t error); // clang-format off UX_STEP_INIT( @@ -200,7 +196,7 @@ static void reset_password_cb(const size_t offset) { PRINTF("reset_password_cb\n"); error_type_t err = delete_password_at_offset(offset); if (err != OK) { - ui_error(get_error(err)); + ui_error(err); return; } ui_idle(); @@ -236,7 +232,7 @@ static void toggle_password_setting(uint8_t caller_id, uint8_t symbols_bitflag); static void create_password_entry(); #if defined(TARGET_NANOS) static void display_nickname_explanation(); -#endif +#endif // #if defined(TARGET_NANOS) static void enter_password_nickname(); // clang-format off @@ -332,7 +328,7 @@ static void create_password_entry() { error_type_t err = create_new_password(G_keyboard_ctx.words_buffer, strlen(G_keyboard_ctx.words_buffer)); if (err != OK) { - ui_error(get_error(err)); + ui_error(err); return; } ui_idle(); @@ -377,7 +373,8 @@ bnnn_paging, UX_FLOW(err_corrupted_memory_flow, &err_corrupted_memory_step, &generic_cancel_step); -static void ui_error(message_pair_t err) { +static void ui_error(error_type_t error) { + message_pair_t err = get_error(error); strlcpy(line_buffer_1, (char*) PIC(err.first), strlen(err.first) + 1); strlcpy(line_buffer_2, (char*) PIC(err.second), strlen(err.second) + 1); ux_flow_init(0, err_corrupted_memory_flow, NULL); @@ -638,4 +635,4 @@ void ui_idle() { } } -#endif +#endif // else( if defined(TARGET_STAX) ) diff --git a/src/sw.h b/src/sw.h deleted file mode 100644 index eb84b62..0000000 --- a/src/sw.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#define SW_OK 0x9000 -#define SW_CONDITIONS_OF_USE_NOT_SATISFIED 0x6985 -#define SW_WRONG_P1P2 0x6A86 -#define SW_WRONG_DATA_LENGTH 0x6A87 -#define SW_INS_NOT_SUPPORTED 0x6D00 -#define SW_CLA_NOT_SUPPORTED 0x6E00 -#define SW_APPNAME_TOO_LONG 0xB000 -#define SW_METADATAS_PARSING_ERROR 0x6F10 diff --git a/src/tests/tests.c b/src/tests/tests.c index 0c320e0..4436f08 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -1,7 +1,8 @@ -#include "tests.h" -#include "sw.h" -#include "io.h" +#include + +#include "error.h" #include "password_typing.h" +#include "tests.h" /* Takes a metadata as an input (charset + seed) and returns a 20 char password*/ int test_generate_password(const buf_t *input) { @@ -18,8 +19,7 @@ int test_generate_password(const buf_t *input) { enabledSets, (const uint8_t *) PIC(DEFAULT_MIN_SET), sizeof(out_buffer)); - const buf_t response = {.bytes = out_buffer, .size = 20}; - return send(&response, SW_OK); + return io_send_response_pointer(out_buffer, 20, SW_OK); } int test_dispatcher(uint8_t p1, __attribute__((unused)) uint8_t p2, const buf_t *input) { @@ -27,6 +27,6 @@ int test_dispatcher(uint8_t p1, __attribute__((unused)) uint8_t p2, const buf_t case GENERATE_PASSWORD: return test_generate_password(input); default: - return send_sw(SW_INS_NOT_SUPPORTED + 1); + return io_send_sw(SW_INS_NOT_SUPPORTED + 1); } } diff --git a/src/types.h b/src/types.h index a290c00..e8ff9c2 100644 --- a/src/types.h +++ b/src/types.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -20,8 +21,6 @@ typedef struct internalStorage_t { #endif } internalStorage_t; -typedef enum { READY, RECEIVED, WAITING } io_state_e; - typedef enum { GET_APP_CONFIG = 0x03, DUMP_METADATAS = 0x04, @@ -50,11 +49,3 @@ typedef struct message_pair_s { const char* first; const char* second; } message_pair_t; - -typedef enum error_type_e { - OK = 0, - ERR_NO_MORE_SPACE_AVAILABLE = 1, - ERR_CORRUPTED_METADATA = 2, - ERR_NO_METADATA = 3, - ERR_METADATA_ENTRY_TOO_BIG = 4 -} error_type_t; diff --git a/tests/functional/snapshots/stax/all_passwords_deleted_screen.png b/tests/functional/snapshots/stax/all_passwords_deleted_screen.png index daace81..242b76e 100644 Binary files a/tests/functional/snapshots/stax/all_passwords_deleted_screen.png and b/tests/functional/snapshots/stax/all_passwords_deleted_screen.png differ diff --git a/tests/functional/snapshots/stax/password_created_screen.png b/tests/functional/snapshots/stax/password_created_screen.png index 1ea6854..cce5b29 100644 Binary files a/tests/functional/snapshots/stax/password_created_screen.png and b/tests/functional/snapshots/stax/password_created_screen.png differ diff --git a/tests/functional/snapshots/stax/password_deleted_screen.png b/tests/functional/snapshots/stax/password_deleted_screen.png index 7f7b3a6..55a4297 100644 Binary files a/tests/functional/snapshots/stax/password_deleted_screen.png and b/tests/functional/snapshots/stax/password_deleted_screen.png differ diff --git a/tests/functional/stax/test_ui.py b/tests/functional/stax/test_ui.py index c1e34da..842ac53 100644 --- a/tests/functional/stax/test_ui.py +++ b/tests/functional/stax/test_ui.py @@ -13,9 +13,10 @@ def format_instructions(instructions: Iterable[Union[NavIns, CustomNavInsID]]) - @pytest.mark.use_on_firmware("stax") def test_immediate_quit(navigator): - navigator.navigate(format_instructions([CustomNavInsID.HOME_TO_QUIT]), - screen_change_before_first_instruction=False, - screen_change_after_last_instruction=False) + with pytest.raises(ConnectionError): + navigator.navigate(format_instructions([CustomNavInsID.HOME_TO_QUIT]), + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False) @pytest.mark.use_on_firmware("stax") @@ -25,9 +26,10 @@ def test_settings_screens(navigator): CustomNavInsID.SETTINGS_TO_HOME, CustomNavInsID.HOME_TO_QUIT ]) - navigator.navigate(instructions, - screen_change_before_first_instruction=False, - screen_change_after_last_instruction=False) + with pytest.raises(ConnectionError): + navigator.navigate(instructions, + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False) @pytest.mark.use_on_firmware("stax") @@ -81,7 +83,6 @@ def test_create_password(navigator, functional_test_directory): NavIns(CustomNavInsID.KEYBOARD_WRITE, ("e", )), NavIns(CustomNavInsID.KEYBOARD_WRITE, ("w", )), CustomNavInsID.KEYBOARD_TO_CONFIRM, - NavIns(NavInsID.WAIT, (2.5, )), # return to list to see the newly created password CustomNavInsID.MENU_TO_DISPLAY, ]) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index ad5bfc5..dd40e12 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -41,12 +41,15 @@ add_compile_definitions(HAVE_BOLOS_UX) add_compile_definitions(TARGET_STAX) add_compile_definitions(OS_IO_SEPROXYHAL) -include_directories(../../src ./mocks/) +include_directories(../../src ../../include ./mocks/) add_executable(test_stax_password_list stax/test_password_list.c) - add_library(password_list SHARED ../../src/stax/password_list.c) - target_link_libraries(test_stax_password_list PUBLIC cmocka gcov password_list bsd) -add_test(test_stax_password_list test_stax_password_list) +add_executable(test_hid_mapping test_hid_mapping.c) +add_library(hid_mapping SHARED ../../src/hid_mapping.c) +target_link_libraries(test_hid_mapping PUBLIC cmocka gcov hid_mapping bsd) + +add_test(stax_password_list test_stax_password_list) +add_test(hid_mapping test_hid_mapping) diff --git a/tests/unit/mocks/os.h b/tests/unit/mocks/os.h index 195c239..d56a5f3 100644 --- a/tests/unit/mocks/os.h +++ b/tests/unit/mocks/os.h @@ -6,6 +6,8 @@ #include #define PRINTF printf +#define THROW(X) return +#define EXCEPTION 1 bool bolos_ux_mnemonic_check(const unsigned char* buffer, unsigned int length) { diff --git a/tests/unit/stax/test_password_list.c b/tests/unit/stax/test_password_list.c index 49701d3..1b3f958 100644 --- a/tests/unit/stax/test_password_list.c +++ b/tests/unit/stax/test_password_list.c @@ -47,7 +47,7 @@ static void test_password_list_passwords(void **state __attribute__((unused))) { for (size_t i = 0; i < (sizeof(strings) / sizeof(strings[0])); i++) { assert_true(password_list_add_password(i, i, strings[i], strlen(strings[i]) + 1)); } - char **passwords = password_list_passwords(); + const char * const *passwords = password_list_passwords(); for (size_t i = 0; i < (sizeof(strings) / sizeof(strings[0])); i++) { assert_string_equal(passwords[i], strings[i]); assert_string_equal(password_list_get_password(i), strings[i]); @@ -73,7 +73,7 @@ static void test_password_list_reset_buffer(void **state __attribute__((unused)) assert_true(password_list_add_password(i, i, strings[i], strlen(strings[i]) + 1)); } password_list_reset_buffer(); - char **passwords = password_list_passwords(); + const char * const *passwords = password_list_passwords(); for (size_t i = 0; i < (sizeof(strings) / sizeof(strings[0])); i++) { // all passwords have been removed assert_ptr_equal(*passwords[i], NULL); diff --git a/tests/unit/test_hid_mapping.c b/tests/unit/test_hid_mapping.c new file mode 100644 index 0000000..866e77c --- /dev/null +++ b/tests/unit/test_hid_mapping.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include + +#include "hid_mapping.h" + + +const char *test = "a&b~c#d {e\"f'g(h -i _j)k=l+m [n |o \\p^q @r ]s }t$u!v:w/x;y.z,A?B D`EFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + +void check_map(uint8_t *map, uint8_t first, uint8_t third) { + assert_int_equal(map[0], first); + assert_int_equal(map[1], 0); + assert_int_equal(map[2], third); +} + +static void test_map_char_qwerty_regular(void **state __attribute__((unused))) { + uint8_t map[3] = {0, 0, 0}; + map_char(HID_MAPPING_QWERTY, 'a', map); + check_map(map, 0, 0x4); + map_char(HID_MAPPING_QWERTY, 'z', map); + check_map(map, 0, 0x1d); + map_char(HID_MAPPING_QWERTY, 'q', map); + check_map(map, 0, 0x14); + map_char(HID_MAPPING_QWERTY, 'w', map); + check_map(map, 0, 0x1a); + map_char(HID_MAPPING_QWERTY, '1', map); + check_map(map, 0, 0x1e); + map_char(HID_MAPPING_QWERTY, '8', map); + check_map(map, 0, 0x25); + map_char(HID_MAPPING_QWERTY, '.', map); + check_map(map, 0, 0x37); +} + +static void test_map_char_qwerty_shift(void **state __attribute__((unused))) { + uint8_t map[3] = {0, 0, 0}; + map_char(HID_MAPPING_QWERTY, 'A', map); + check_map(map, SHIFT_KEY, 0x4); + map_char(HID_MAPPING_QWERTY, 'Z', map); + check_map(map, SHIFT_KEY, 0x1d); + map_char(HID_MAPPING_QWERTY, 'Q', map); + check_map(map, SHIFT_KEY, 0x14); + map_char(HID_MAPPING_QWERTY, 'W', map); + check_map(map, SHIFT_KEY, 0x1a); + map_char(HID_MAPPING_QWERTY, '!', map); + check_map(map, SHIFT_KEY, 0x1e); + map_char(HID_MAPPING_QWERTY, '*', map); + check_map(map, SHIFT_KEY, 0x25); + map_char(HID_MAPPING_QWERTY, '>', map); + check_map(map, SHIFT_KEY, 0x37); +} + +static void test_map_char_azerty_regular(void **state __attribute__((unused))) { + uint8_t map[3] = {0, 0, 0}; + map_char(HID_MAPPING_AZERTY, 'q', map); + check_map(map, 0, 0x4); + map_char(HID_MAPPING_AZERTY, 'w', map); + check_map(map, 0, 0x1d); + map_char(HID_MAPPING_AZERTY, 'a', map); + check_map(map, 0, 0x14); + map_char(HID_MAPPING_AZERTY, 'z', map); + check_map(map, 0, 0x1a); + map_char(HID_MAPPING_AZERTY, '&', map); + check_map(map, 0, 0x1e); + map_char(HID_MAPPING_AZERTY, '_', map); + check_map(map, 0, 0x25); + map_char(HID_MAPPING_AZERTY, ':', map); + check_map(map, 0, 0x37); +} + +static void test_map_char_azerty_shift(void **state __attribute__((unused))) { + uint8_t map[3] = {0, 0, 0}; + map_char(HID_MAPPING_AZERTY, 'Q', map); + check_map(map, SHIFT_KEY, 0x4); + map_char(HID_MAPPING_AZERTY, 'W', map); + check_map(map, SHIFT_KEY, 0x1d); + map_char(HID_MAPPING_AZERTY, 'A', map); + check_map(map, SHIFT_KEY, 0x14); + map_char(HID_MAPPING_AZERTY, 'Z', map); + check_map(map, SHIFT_KEY, 0x1a); + map_char(HID_MAPPING_AZERTY, '1', map); + check_map(map, SHIFT_KEY, 0x1e); + map_char(HID_MAPPING_AZERTY, '8', map); + check_map(map, SHIFT_KEY, 0x25); + map_char(HID_MAPPING_AZERTY, '/', map); + check_map(map, SHIFT_KEY, 0x37); +} + +static void test_map_char_azerty_alt(void **state __attribute__((unused))) { + uint8_t map[3] = {0, 0, 0}; + map_char(HID_MAPPING_AZERTY, '@', map); + check_map(map, ALT_KEY, 0x27); + map_char(HID_MAPPING_AZERTY, '`', map); + check_map(map, ALT_KEY, 0x24); +} + +int main() { + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_map_char_qwerty_regular, NULL, NULL), + cmocka_unit_test_setup_teardown(test_map_char_qwerty_shift, NULL, NULL), + cmocka_unit_test_setup_teardown(test_map_char_azerty_regular, NULL, NULL), + cmocka_unit_test_setup_teardown(test_map_char_azerty_shift, NULL, NULL), + cmocka_unit_test_setup_teardown(test_map_char_azerty_alt, NULL, NULL), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +}