From b747e957f0406703ccaa48bfc034d6cfd5656181 Mon Sep 17 00:00:00 2001 From: italo sampaio Date: Tue, 22 Nov 2022 11:17:57 -0300 Subject: [PATCH] Rework on UI unit test to change from function call list to a more behaviour based approach - Updated communication tests - Updated onboard tests - Updated pin tests - Updated unlock tests --- ledger/src/ui/test/communication/Makefile | 5 +- .../test/communication/test_communication.c | 43 ++++- ledger/src/ui/test/mock/cx.c | 14 +- ledger/src/ui/test/mock/cx.h | 4 +- ledger/src/ui/test/mock/os.c | 95 +++++------ ledger/src/ui/test/mock/os.h | 32 ++-- ledger/src/ui/test/onboard/test_onboard.c | 99 ++++++++--- ledger/src/ui/test/pin/test_pin.c | 155 ++++++++++-------- ledger/src/ui/test/unlock/test_unlock.c | 36 +++- 9 files changed, 311 insertions(+), 172 deletions(-) diff --git a/ledger/src/ui/test/communication/Makefile b/ledger/src/ui/test/communication/Makefile index d9b3227b..099696ff 100644 --- a/ledger/src/ui/test/communication/Makefile +++ b/ledger/src/ui/test/communication/Makefile @@ -25,7 +25,7 @@ MOCKDIR = ../mock CFLAGS = -I $(SRCDIR) -I $(MOCKDIR) -I ./ PROG = test.out -OBJS = os.o communication.o test_communication.o +OBJS = os.o pin.o communication.o test_communication.o all: $(PROG) @@ -41,6 +41,9 @@ communication.o: $(SRCDIR)/communication.c os.o: $(MOCKDIR)/os.c $(CC) $(CFLAGS) -c -o $@ $^ +pin.o: $(SRCDIR)/pin.c + $(CC) $(CFLAGS) -c -o $@ $^ + .PHONY: clean test clean: diff --git a/ledger/src/ui/test/communication/test_communication.c b/ledger/src/ui/test/communication/test_communication.c index 5aea87c0..1124233b 100644 --- a/ledger/src/ui/test/communication/test_communication.c +++ b/ledger/src/ui/test/communication/test_communication.c @@ -23,11 +23,13 @@ */ #include +#include #include #include "defs.h" #include "communication.h" #include "os.h" +#include "pin.h" void test_echo() { printf("Test echo...\n"); @@ -43,11 +45,46 @@ void test_get_mode() { void test_get_retries() { printf("Test get retries...\n"); - reset_mock_func_call_list(); + + unsigned char pin_buffer[] = "X1234567a"; + unsigned char wrong_pin[] = "Xa7654321"; + unsigned int rx = 4; + init_mock_ctx(); + for (int i = 0; i < strlen((const char *)pin_buffer); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, pin_buffer[i]); + assert(3 == update_pin_buffer(rx)); + } + + assert(3 == set_pin()); + assert(3 == get_retries()); + assert(0 == APDU_AT(2)); + + // Send wrong pin + for (int i = 0; i < strlen((const char *)wrong_pin); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, wrong_pin[i]); + assert(3 == update_pin_buffer(rx)); + } + assert(!unlock_with_pin(true)); + assert(3 == get_retries()); + assert(1 == APDU_AT(2)); + assert(!unlock_with_pin(true)); + assert(3 == get_retries()); + assert(2 == APDU_AT(2)); + assert(!unlock_with_pin(true)); + assert(3 == get_retries()); + assert(3 == APDU_AT(2)); + + // Send right pin again + for (int i = 0; i < strlen((const char *)pin_buffer); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, pin_buffer[i]); + assert(3 == update_pin_buffer(rx)); + } + assert(unlock_with_pin(true)); assert(3 == get_retries()); assert(0 == APDU_AT(2)); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_GLOBAL_PIN_RETRIES); - assert(get_mock_func_call_count() == 1); } int main() { diff --git a/ledger/src/ui/test/mock/cx.c b/ledger/src/ui/test/mock/cx.c index 885a985d..bb6b1a9a 100644 --- a/ledger/src/ui/test/mock/cx.c +++ b/ledger/src/ui/test/mock/cx.c @@ -24,8 +24,18 @@ #include "cx.h" -unsigned char mock_random_buffer[] = "random-buffer\0"; +static unsigned char mock_seed[32]; + +void set_mock_seed(const unsigned char *data, unsigned int len) { + for (unsigned int i = 0; i < len; i++) { + mock_seed[i] = data[i]; + } +} unsigned char *cx_rng(unsigned char *buffer, unsigned int len) { - return mock_random_buffer; + // Mock 32 random bytes + for (int i = 0; i < len; i++) { + buffer[i] = mock_seed[i]; + } + return 0; } \ No newline at end of file diff --git a/ledger/src/ui/test/mock/cx.h b/ledger/src/ui/test/mock/cx.h index 8a6b6a38..1e3ccf60 100644 --- a/ledger/src/ui/test/mock/cx.h +++ b/ledger/src/ui/test/mock/cx.h @@ -25,4 +25,6 @@ /** * generate a random buffer */ -unsigned char *cx_rng(unsigned char *buffer, unsigned int len); \ No newline at end of file +unsigned char *cx_rng(unsigned char *buffer, unsigned int len); + +void set_mock_seed(const unsigned char *data, unsigned int len); \ No newline at end of file diff --git a/ledger/src/ui/test/mock/os.c b/ledger/src/ui/test/mock/os.c index 9c6c5c04..a2c2c88a 100644 --- a/ledger/src/ui/test/mock/os.c +++ b/ledger/src/ui/test/mock/os.c @@ -21,36 +21,24 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ - +#include +#include +#include "defs.h" #include "os.h" #include "string.h" - -static mock_func_call_t mock_func_call_list[128]; -static size_t mock_func_call_count = 0; - -/** - * Mocks pin currently loaded to device - */ -unsigned char current_pin[10]; +#include "onboard.h" /** - * Helper functions to handle call list + * Mock context used to assert current state */ -void reset_mock_func_call_list() { - explicit_bzero(mock_func_call_list, sizeof(mock_func_call_list)); - mock_func_call_count = 0; -} - -void add_mock_func_call(mock_func_call_t func) { - mock_func_call_list[mock_func_call_count++] = func; -} +static mock_ctx_t mock_ctx; -mock_func_call_t get_mock_func_call(int order) { - return mock_func_call_list[order]; +void init_mock_ctx() { + memset(&mock_ctx, 0, sizeof(mock_ctx)); } -int get_mock_func_call_count() { - return mock_func_call_count; +void get_mock_ctx(mock_ctx_t *ctx) { + memcpy(ctx, &mock_ctx, sizeof(mock_ctx)); } /** @@ -66,32 +54,33 @@ void explicit_bzero(void *s, size_t len) { unsigned int os_global_pin_check(unsigned char *pin_buffer, unsigned char pin_length) { - add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - return !strncmp( - (const char *)pin_buffer, (const char *)current_pin, pin_length); + mock_ctx.device_unlocked = !strncmp((const char *)pin_buffer, + (const char *)mock_ctx.global_pin, + pin_length); + if (mock_ctx.device_unlocked) { + mock_ctx.retries = 0; + } else { + mock_ctx.retries++; + } + + return mock_ctx.device_unlocked; } void os_perso_set_pin(unsigned int identity, unsigned char *pin, unsigned int length) { - add_mock_func_call(MOCK_FUNC_OS_PERSO_SET_PIN); - strncpy((char *)current_pin, (char *)pin, length); + strncpy((char *)mock_ctx.global_pin, (char *)pin, length); } void os_global_pin_invalidate(void) { - add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE); + mock_ctx.device_unlocked = false; } void os_memset(void *dst, unsigned char c, unsigned int length) { memset(dst, c, length); } -void mock_set_pin(unsigned char *pin, size_t n) { - memcpy(current_pin, pin, n); -} - void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) { - add_mock_func_call(MOCK_FUNC_NVM_WRITE); if (src_adr == NULL) { // Treat as memory reset memset(dst_adr, 0, src_len); @@ -102,39 +91,37 @@ void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) { } void os_perso_wipe() { - add_mock_func_call(MOCK_FUNC_OS_PERSO_WIPE); -} - -void os_perso_derive_and_set_seed(unsigned char identity, - const char *prefix, - unsigned int prefix_length, - const char *passphrase, - unsigned int passphrase_length, - const char *words, - unsigned int words_length) { - add_mock_func_call(MOCK_FUNC_OS_PERSO_DERIVE_AND_SET_SEED); + // wipe global pin, seed and state + init_mock_ctx(); } void os_perso_finalize(void) { - add_mock_func_call(MOCK_FUNC_OS_PERSO_FINALIZE); + mock_ctx.device_onboarded = true; } unsigned int os_perso_isonboarded(void) { - add_mock_func_call(MOCK_FUNC_OS_PERSO_ISONBOARDED); - return 1; + return mock_ctx.device_onboarded; } unsigned int os_global_pin_retries(void) { - add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_RETRIES); - return 0; + return mock_ctx.retries; } +// Generated mnemonics buffer will be "mnemonics-generated-from:" unsigned int bolos_ux_mnemonic_from_data(unsigned char *in, unsigned int inLength, unsigned char *out, unsigned int outLength) { - add_mock_func_call(MOCK_FUNC_BOLOS_UX_MNEMONIC_FROM_DATA); - const char mnemonic[] = "the-mnemonics"; - strcpy((char *)out, mnemonic); - return strlen(mnemonic); -} \ No newline at end of file + sprintf((char *)out, "mnemonics-generated-from-%s", in); + return strlen((const char *)out); +} + +void os_perso_derive_and_set_seed(unsigned char identity, + const char *prefix, + unsigned int prefix_length, + const char *passphrase, + unsigned int passphrase_length, + const char *words, + unsigned int words_length) { + sprintf((char *)mock_ctx.global_seed, "seed-generated-from-%s", words); +} diff --git a/ledger/src/ui/test/mock/os.h b/ledger/src/ui/test/mock/os.h index a319844e..2e7ad43d 100644 --- a/ledger/src/ui/test/mock/os.h +++ b/ledger/src/ui/test/mock/os.h @@ -22,6 +22,7 @@ * IN THE SOFTWARE. */ +#include #include #include #include "cx.h" @@ -33,20 +34,6 @@ #define THROW(e) return e #define PIC(x) (x) -typedef enum { - MOCK_FUNC_OS_GLOBAL_PIN_CHECK, - MOCK_FUNC_OS_PERSO_SET_PIN, - MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE, - MOCK_FUNC_OS_MEMSET, - MOCK_FUNC_NVM_WRITE, - MOCK_FUNC_OS_PERSO_WIPE, - MOCK_FUNC_OS_PERSO_DERIVE_AND_SET_SEED, - MOCK_FUNC_OS_PERSO_FINALIZE, - MOCK_FUNC_OS_PERSO_ISONBOARDED, - MOCK_FUNC_BOLOS_UX_MNEMONIC_FROM_DATA, - MOCK_FUNC_OS_GLOBAL_PIN_RETRIES, -} mock_func_call_t; - /** * Mock APDU buffer */ @@ -54,12 +41,18 @@ typedef enum { extern unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; /** - * Helper functions to handle call list + * Mock context used to assert current state */ -void reset_mock_func_call_list(); -void add_mock_func_call(mock_func_call_t func); -mock_func_call_t get_mock_func_call(int order); -int get_mock_func_call_count(); +typedef struct { + unsigned char global_pin[10]; + unsigned char global_seed[257]; + bool device_unlocked; + bool device_onboarded; + unsigned int retries; +} mock_ctx_t; + +void init_mock_ctx(); +void get_mock_ctx(mock_ctx_t *ctx); /** * Mock calls for os API @@ -88,4 +81,3 @@ unsigned int os_global_pin_retries(void); * Other mocks */ void explicit_bzero(void *s, size_t len); -void mock_set_pin(unsigned char *pin, size_t n); diff --git a/ledger/src/ui/test/onboard/test_onboard.c b/ledger/src/ui/test/onboard/test_onboard.c index df65e01c..290089b6 100644 --- a/ledger/src/ui/test/onboard/test_onboard.c +++ b/ledger/src/ui/test/onboard/test_onboard.c @@ -67,7 +67,7 @@ void test_set_host_seed() { SET_APDU_AT(3, host_seed[i]); assert(0 == set_host_seed(rx, &onboard_ctx)); } - assert(0 == strncmp((char*)onboard_ctx.host_seed, host_seed, SEEDSIZE)); + assert(0 == strncmp((char *)onboard_ctx.host_seed, host_seed, SEEDSIZE)); } void test_onboard_device() { @@ -75,7 +75,9 @@ void test_onboard_device() { onboard_t onboard_ctx; reset_onboard_ctx(&onboard_ctx); // mock 32 bytes random host seed - const char host_seed[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + const unsigned char host_seed[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + // mock 32 bytes handom seed + const unsigned char seed[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; // device pin (with prepended length) const unsigned char valid_pin[] = "X1234567a"; unsigned int rx; @@ -90,27 +92,36 @@ void test_onboard_device() { // Mock RSK_SEED_CMD rx = 4; - for (int i = 0; i < strlen(host_seed); i++) { + for (int i = 0; i < strlen((const char *)host_seed); i++) { SET_APDU_AT(2, i); SET_APDU_AT(3, host_seed[i]); assert(0 == set_host_seed(rx, &onboard_ctx)); } - reset_mock_func_call_list(); + char expected_global_seed[257]; + memset(expected_global_seed, 0, sizeof(expected_global_seed)); + char generated_seed[SEEDSIZE]; + for (int i = 0; i < SEEDSIZE; i++) { + generated_seed[i] = host_seed[i] ^ seed[i]; + } + sprintf(expected_global_seed, + "seed-generated-from-mnemonics-generated-from-%s", + generated_seed); + + init_mock_ctx(); + set_mock_seed(seed, SEEDSIZE); assert(3 == onboard_device(&onboard_ctx)); assert(2 == APDU_AT(1)); assert(1 == APDU_AT(2)); - assert(get_mock_func_call(0) == MOCK_FUNC_NVM_WRITE); - assert(get_mock_func_call(1) == MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE); - assert(get_mock_func_call(2) == MOCK_FUNC_OS_PERSO_WIPE); - assert(get_mock_func_call(3) == MOCK_FUNC_BOLOS_UX_MNEMONIC_FROM_DATA); - assert(get_mock_func_call(4) == MOCK_FUNC_OS_PERSO_DERIVE_AND_SET_SEED); - assert(get_mock_func_call(5) == MOCK_FUNC_OS_PERSO_SET_PIN); - assert(get_mock_func_call(6) == MOCK_FUNC_OS_PERSO_FINALIZE); - assert(get_mock_func_call(7) == MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE); - assert(get_mock_func_call(8) == MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - assert(get_mock_func_call(9) == MOCK_FUNC_NVM_WRITE); - assert(get_mock_func_call_count() == 10); + + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(mock_ctx.device_unlocked == true); + assert(mock_ctx.device_onboarded == true); + assert(mock_ctx.retries == 0); + assert(!strcmp((const char *)(valid_pin + 1), + (const char *)mock_ctx.global_pin)); + assert(!strcmp(expected_global_seed, (const char *)mock_ctx.global_seed)); // Make sure all mnemonic and seed information is wiped after onboard_device char expected_words_buffer[sizeof(words_buffer)]; @@ -150,23 +161,69 @@ void test_onboard_device_invalid_pin() { assert(0 == set_host_seed(rx, &onboard_ctx)); } - reset_mock_func_call_list(); + init_mock_ctx(); // ERR_INVALID_PIN assert(0x69A0 == onboard_device(&onboard_ctx)); - assert(get_mock_func_call(0) == MOCK_FUNC_NVM_WRITE); - assert(get_mock_func_call_count() == 1); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + + // assert internal state was not affected + unsigned char expected_global_pin[sizeof(mock_ctx.global_pin)]; + memset(expected_global_pin, 0, sizeof(expected_global_pin)); + unsigned char expected_global_seed[sizeof(mock_ctx.global_seed)]; + memset(expected_global_seed, 0, sizeof(expected_global_seed)); + + assert(false == mock_ctx.device_onboarded); + assert(false == mock_ctx.device_unlocked); + assert(0 == mock_ctx.retries); + assert(0 == memcmp(expected_global_pin, + mock_ctx.global_pin, + sizeof(expected_global_pin))); + assert(0 == memcmp(expected_global_seed, + mock_ctx.global_seed, + sizeof(expected_global_seed))); } void test_is_onboarded() { printf("Test is onboarded...\n"); - reset_mock_func_call_list(); + + onboard_t onboard_ctx; + reset_onboard_ctx(&onboard_ctx); + // mock 32 bytes random host seed + const unsigned char host_seed[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + // device pin (with prepended length) + const unsigned char valid_pin[] = "X1234567a"; + unsigned int rx; + + // Mock RSK_PIN_CMD + rx = 4; + for (int i = 0; i < sizeof(valid_pin); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, valid_pin[i]); + assert(3 == update_pin_buffer(rx)); + } + + // Mock RSK_SEED_CMD + rx = 4; + for (int i = 0; i < strlen((const char *)host_seed); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, host_seed[i]); + assert(0 == set_host_seed(rx, &onboard_ctx)); + } + + assert(5 == is_onboarded()); + assert(0 == APDU_AT(1)); + assert(VERSION_MAJOR == APDU_AT(2)); + assert(VERSION_MINOR == APDU_AT(3)); + assert(VERSION_PATCH == APDU_AT(4)); + + onboard_device(&onboard_ctx); + assert(5 == is_onboarded()); assert(1 == APDU_AT(1)); assert(VERSION_MAJOR == APDU_AT(2)); assert(VERSION_MINOR == APDU_AT(3)); assert(VERSION_PATCH == APDU_AT(4)); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_PERSO_ISONBOARDED); - assert(get_mock_func_call_count() == 1); } int main() { diff --git a/ledger/src/ui/test/pin/test_pin.c b/ledger/src/ui/test/pin/test_pin.c index ed0621cb..edbf677b 100644 --- a/ledger/src/ui/test/pin/test_pin.c +++ b/ledger/src/ui/test/pin/test_pin.c @@ -52,53 +52,6 @@ void assert_pin(char *pin, bool expected) { assert(is_pin_valid() == expected); } -void test_update_pin_buffer() { - printf("Test update pin buffer...\n"); - - unsigned char pin_buffer[] = "X1234567a"; - unsigned int rx = 4; - for (int i = 0; i < strlen((const char *)pin_buffer); i++) { - SET_APDU_AT(2, i); - SET_APDU_AT(3, pin_buffer[i]); - assert(3 == update_pin_buffer(rx)); - } -} - -void test_set_pin() { - printf("Test set pin ok...\n"); - - unsigned char pin_buffer[] = "X1234567a"; - unsigned int rx = 4; - for (int i = 0; i < strlen((const char *)pin_buffer); i++) { - SET_APDU_AT(2, i); - SET_APDU_AT(3, pin_buffer[i]); - assert(3 == update_pin_buffer(rx)); - } - - reset_mock_func_call_list(); - assert(3 == set_pin()); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_PERSO_SET_PIN); - assert(get_mock_func_call(1) == MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE); - assert(get_mock_func_call(2) == MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - assert(get_mock_func_call_count() == 3); -} - -void test_set_pin_invalid() { - printf("Test set pin invalid...\n"); - - unsigned char pin_buffer[] = "X12345678"; - unsigned int rx = 4; - for (int i = 0; i < strlen((const char *)pin_buffer); i++) { - SET_APDU_AT(2, i); - SET_APDU_AT(3, pin_buffer[i]); - assert(3 == update_pin_buffer(rx)); - } - - reset_mock_func_call_list(); - assert(0x69A0 == set_pin()); // ERR_INVALID_PIN - assert(get_mock_func_call_count() == 0); -} - void test_validate_ok() { printf("Test validate pin OK...\n"); @@ -145,38 +98,102 @@ void test_validate_pin_non_alpha() { assert_pin("abcdefg", IS_NOT_VALID); } +void test_update_pin_buffer() { + printf("Test update pin buffer...\n"); + + unsigned char pin_buffer[] = "X1234567a"; + unsigned int rx = 4; + init_mock_ctx(); + for (int i = 0; i < strlen((const char *)pin_buffer); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, pin_buffer[i]); + assert(3 == update_pin_buffer(rx)); + } + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + const char *expected_global_pin[sizeof(mock_ctx.global_pin)]; + memset(expected_global_pin, 0, sizeof(expected_global_pin)); + assert(!strcmp((const char *)expected_global_pin, + (const char *)mock_ctx.global_pin)); +} + +void test_set_pin() { + printf("Test set pin ok...\n"); + + unsigned char pin_buffer[] = "X1234567a"; + unsigned int rx = 4; + init_mock_ctx(); + for (int i = 0; i < strlen((const char *)pin_buffer); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, pin_buffer[i]); + assert(3 == update_pin_buffer(rx)); + } + + assert(3 == set_pin()); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(true == mock_ctx.device_unlocked); +} + +void test_set_pin_invalid() { + printf("Test set pin invalid...\n"); + + unsigned char pin_buffer[] = "X12345678"; + unsigned int rx = 4; + init_mock_ctx(); + for (int i = 0; i < strlen((const char *)pin_buffer); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, pin_buffer[i]); + assert(3 == update_pin_buffer(rx)); + } + + assert(0x69A0 == set_pin()); // ERR_INVALID_PIN + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(false == mock_ctx.device_unlocked); +} + void test_unlock_with_pin() { printf("Test unlock with pin...\n"); - unsigned char pin_buffer[] = "1234567a"; + unsigned char pin_buffer[] = "X1234567a"; unsigned int rx = 4; + init_mock_ctx(); for (int i = 0; i < strlen((const char *)pin_buffer); i++) { SET_APDU_AT(2, i); SET_APDU_AT(3, pin_buffer[i]); assert(3 == update_pin_buffer(rx)); } - - reset_mock_func_call_list(); - assert(1 == unlock_with_pin(false)); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - assert(get_mock_func_call_count() == 1); + assert(3 == set_pin()); + assert(1 == unlock_with_pin(true)); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + // Skip prepended length + assert(!strcmp((const char *)(pin_buffer + 1), + (const char *)mock_ctx.global_pin)); + assert(true == mock_ctx.device_unlocked); } -void test_unlock_with_pin_prepended_length() { - printf("Test unlock with pin (prepended length)...\n"); +void test_unlock_with_pin_not_set() { + printf("Test unlock with pin (pin not set)...\n"); unsigned char pin_buffer[] = "X1234567a"; unsigned int rx = 4; + init_mock_ctx(); for (int i = 0; i < strlen((const char *)pin_buffer); i++) { SET_APDU_AT(2, i); SET_APDU_AT(3, pin_buffer[i]); assert(3 == update_pin_buffer(rx)); } - reset_mock_func_call_list(); - assert(1 == unlock_with_pin(true)); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - assert(get_mock_func_call_count() == 1); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(0 == unlock_with_pin(true)); + assert(false == mock_ctx.device_unlocked); + const char *expected_global_pin[sizeof(mock_ctx.global_pin)]; + memset(expected_global_pin, 0, sizeof(expected_global_pin)); + assert(!strcmp((const char *)expected_global_pin, + (const char *)mock_ctx.global_pin)); } void test_set_device_pin() { @@ -184,29 +201,33 @@ void test_set_device_pin() { unsigned char pin_buffer[] = "X1234567a"; unsigned int rx = 4; + init_mock_ctx(); for (int i = 0; i < strlen((const char *)pin_buffer); i++) { SET_APDU_AT(2, i); SET_APDU_AT(3, pin_buffer[i]); assert(3 == update_pin_buffer(rx)); } - reset_mock_func_call_list(); set_device_pin(); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_PERSO_SET_PIN); - assert(get_mock_func_call_count() == 1); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + // Skip prepended length + assert(!strcmp((const char *)(pin_buffer + 1), + (const char *)mock_ctx.global_pin)); + assert(false == mock_ctx.device_unlocked); } int main() { - test_update_pin_buffer(); - test_set_pin(); - test_set_pin_invalid(); - test_validate_ok(); test_validate_numeric_pin(); test_validate_pin_too_long(); test_validate_pin_too_short(); test_validate_pin_non_alpha(); + test_update_pin_buffer(); + test_set_pin(); + test_set_pin_invalid(); + test_validate_ok(); test_unlock_with_pin(); - test_unlock_with_pin_prepended_length(); + test_unlock_with_pin_not_set(); test_set_device_pin(); return 0; diff --git a/ledger/src/ui/test/unlock/test_unlock.c b/ledger/src/ui/test/unlock/test_unlock.c index cef6782e..6e34b558 100644 --- a/ledger/src/ui/test/unlock/test_unlock.c +++ b/ledger/src/ui/test/unlock/test_unlock.c @@ -36,20 +36,50 @@ void test_unlock() { unsigned char pin_buffer[] = "1234567a"; unsigned int rx = 4; + init_mock_ctx(); for (int i = 0; i < strlen((const char *)pin_buffer); i++) { SET_APDU_AT(2, i); SET_APDU_AT(3, pin_buffer[i]); assert(3 == update_pin_buffer(rx)); } - reset_mock_func_call_list(); + // assert(3 == set_pin()); + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(false == mock_ctx.device_unlocked); + os_perso_set_pin(0, pin_buffer, strlen((const char *)pin_buffer)); assert(3 == unlock()); - assert(get_mock_func_call(0) == MOCK_FUNC_OS_GLOBAL_PIN_CHECK); - assert(get_mock_func_call_count() == 1); + get_mock_ctx(&mock_ctx); + assert(true == mock_ctx.device_unlocked); + assert(1 == APDU_AT(2)); +} + +void test_unlock_wrong_pin() { + printf("Test unlock (wrong pin)...\n"); + + unsigned char pin_buffer[] = "1234567a"; + unsigned char wrong_pin[] = "a7654321"; + unsigned int rx = 4; + init_mock_ctx(); + for (int i = 0; i < strlen((const char *)wrong_pin); i++) { + SET_APDU_AT(2, i); + SET_APDU_AT(3, wrong_pin[i]); + assert(3 == update_pin_buffer(rx)); + } + + mock_ctx_t mock_ctx; + get_mock_ctx(&mock_ctx); + assert(false == mock_ctx.device_unlocked); + os_perso_set_pin(0, pin_buffer, strlen((const char *)pin_buffer)); + assert(3 == unlock()); + get_mock_ctx(&mock_ctx); + assert(false == mock_ctx.device_unlocked); + assert(0 == APDU_AT(2)); } int main() { test_unlock(); + test_unlock_wrong_pin(); return 0; }