diff --git a/ledger/src/ui/src/bolos_ux.c b/ledger/src/ui/src/bolos_ux.c index b1012363..cce8554f 100644 --- a/ledger/src/ui/src/bolos_ux.c +++ b/ledger/src/ui/src/bolos_ux.c @@ -52,16 +52,13 @@ #include "attestation.h" #include "signer_authorization.h" #include "memutil.h" +#include "unlock.h" // Onboarded with the UI flag const unsigned char N_onboarded_ui[1] = {0}; // PIN buffer used for authenticated operations -unsigned char G_pin_buffer[PIN_LENGTH + 2]; -// Skip the prepended length of pin buffer -#define G_PIN_BUFFER_PAYLOAD (G_pin_buffer + 1) -// Unify pin buffer length -#define G_PIN_BUFFER_LEN() strlen((const char *)G_PIN_BUFFER_PAYLOAD) +unsigned char G_pin_buffer[PIN_BUFFER_LENGTH]; #ifdef OS_IO_SEPROXYHAL @@ -243,6 +240,9 @@ void io_seproxyhal_display(const bagl_element_t *element) { // Signer authorization context shorthand #define sigaut_ctx (G_bolos_ux_context.sigaut) +// Pin context shorthand +#define pin_ctx (G_bolos_ux_context.pin) + // Operation being currently executed static unsigned char curr_cmd; @@ -258,13 +258,12 @@ static void reset_if_starting(unsigned char cmd) { curr_cmd = cmd; explicit_bzero(G_bolos_ux_context.words_buffer, sizeof(G_bolos_ux_context.words_buffer)); - explicit_bzero(G_bolos_ux_context.pin_buffer, - sizeof(G_bolos_ux_context.pin_buffer)); explicit_bzero(G_bolos_ux_context.string_buffer, sizeof(G_bolos_ux_context.string_buffer)); G_bolos_ux_context.words_buffer_length = 0; reset_attestation(&attestation_ctx); reset_signer_authorization(&sigaut_ctx); + reset_pin_ctx(&pin_ctx); } } @@ -321,11 +320,8 @@ static void sample_main(void) { break; case RSK_PIN_CMD: // Send pin_buffer reset_if_starting(RSK_META_CMD_UIOP); - pin = APDU_AT(2); - if ((pin >= 0) && (pin <= PIN_LENGTH)) { - G_pin_buffer[pin] = APDU_AT(3); - G_pin_buffer[pin + 1] = 0; - } + init_pin_ctx(&pin_ctx, G_pin_buffer); + tx = update_pin_buffer(rx, &pin_ctx); THROW(APDU_OK); break; case RSK_IS_ONBOARD: // Wheter it's onboarded or not @@ -347,8 +343,9 @@ static void sample_main(void) { nvm_write( (void *)PIC(N_onboarded_ui), (void *)&aux, sizeof(aux)); + init_pin_ctx(&pin_ctx, G_pin_buffer); #ifndef DEBUG_BUILD - if (!is_pin_valid(G_PIN_BUFFER_PAYLOAD)) { + if (!is_pin_valid(&pin_ctx)) { THROW(ERR_INVALID_PIN); } #endif @@ -392,14 +389,14 @@ static void sample_main(void) { sizeof(G_bolos_ux_context.words_buffer)); // Set PIN os_perso_set_pin( - 0, G_PIN_BUFFER_PAYLOAD, G_PIN_BUFFER_LEN()); + 0, GET_PIN(&pin_ctx), GET_PIN_LENGTH(&pin_ctx)); // Finalize onboarding os_perso_finalize(); os_global_pin_invalidate(); SET_APDU_AT(1, 2); SET_APDU_AT(2, - os_global_pin_check(G_PIN_BUFFER_PAYLOAD, - G_PIN_BUFFER_LEN())); + os_global_pin_check(GET_PIN(&pin_ctx), + GET_PIN_LENGTH(&pin_ctx))); // Clear pin buffer explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer)); // Turn the onboarding flag on to mark onboarding @@ -413,22 +410,13 @@ static void sample_main(void) { break; case RSK_NEWPIN: reset_if_starting(RSK_META_CMD_UIOP); - + init_pin_ctx(&pin_ctx, G_pin_buffer); #ifndef DEBUG_BUILD - if (!is_pin_valid(G_PIN_BUFFER_PAYLOAD)) { + if (!is_pin_valid(&pin_ctx)) { THROW(ERR_INVALID_PIN); } #endif - // Set PIN - os_perso_set_pin( - 0, G_PIN_BUFFER_PAYLOAD, G_PIN_BUFFER_LEN()); - // check PIN - os_global_pin_invalidate(); - SET_APDU_AT(1, 2); - SET_APDU_AT(2, - os_global_pin_check(G_PIN_BUFFER_PAYLOAD, - G_PIN_BUFFER_LEN())); - tx = 3; + tx = set_device_pin(rx, &pin_ctx); // Clear pin buffer explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer)); THROW(APDU_OK); @@ -462,18 +450,12 @@ static void sample_main(void) { break; case RSK_UNLOCK_CMD: // Unlock reset_if_starting(RSK_META_CMD_UIOP); - // RSK_UNLOCK_CMD does not send the prepended length, - // so we kept this call backwards compatible, using - // G_pin_buffer instead of G_PIN_BUFFER_PAYLOAD - SET_APDU_AT( - 2, - os_global_pin_check( - G_pin_buffer, strlen((const char *)G_pin_buffer))); - tx = 5; - THROW(APDU_OK); + init_pin_ctx(&pin_ctx, G_pin_buffer); + tx = unlock(rx, &pin_ctx); // The pin value will also be used in // BOLOS_UX_CONSENT_APP_ADD command, so we can't wipe the // pin buffer here + THROW(APDU_OK); break; case RSK_END_CMD: // return to dashboard reset_if_starting(RSK_END_CMD); @@ -652,8 +634,9 @@ void bolos_ux_main(void) { // PIN is invalidated so we must check it again. The pin value // used here is the same as in RSK_UNLOCK_CMD, so we also // don't have a prepended length byte - os_global_pin_check(G_pin_buffer, - strlen((const char *)G_pin_buffer)); + init_pin_ctx(&pin_ctx, G_pin_buffer); + os_global_pin_check(pin_ctx.pin_buffer, + strlen((const char *)pin_ctx.pin_buffer)); G_bolos_ux_context.exit_code = BOLOS_UX_OK; explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer)); break; diff --git a/ledger/src/ui/src/bolos_ux.h b/ledger/src/ui/src/bolos_ux.h index 2622e928..b81f7159 100644 --- a/ledger/src/ui/src/bolos_ux.h +++ b/ledger/src/ui/src/bolos_ux.h @@ -160,14 +160,10 @@ typedef struct bolos_ux_context { union { att_t attestation; sigaut_t sigaut; + pin_t pin; }; }; -#define MAX_PIN_LENGTH 8 -#define MIN_PIN_LENGTH 4 - char pin_buffer[MAX_PIN_LENGTH + - 1]; // length prepended for custom pin length - // filled up during os_ux syscall when called by user or bolos. bolos_ux_params_t parameters; diff --git a/ledger/src/ui/src/pin.c b/ledger/src/ui/src/pin.c index ffbaccdb..cf8f6d8e 100644 --- a/ledger/src/ui/src/pin.c +++ b/ledger/src/ui/src/pin.c @@ -24,6 +24,8 @@ #include +#include "apdu.h" +#include "os.h" #include "err.h" #include "pin.h" @@ -37,25 +39,97 @@ * Validates that the pin has exactly PIN_LENGTH alphanumeric characters * with at least one alphabetic character. * - * @arg[in] pin null-terminated string representing the pin to validate + * @arg[in] pin_ctx pin context (with prepended length) * @ret true if pin is valid, false otherwise */ -bool is_pin_valid(unsigned char *pin) { +bool is_pin_valid(pin_t* pin_ctx) { // PIN_LENGTH is the only length accepted - size_t length = strnlen((const char *)pin, PIN_LENGTH + 1); - if (length != PIN_LENGTH) { + if (GET_PIN_LENGTH(pin_ctx) != PIN_LENGTH) { return false; } // Check if PIN is alphanumeric bool hasAlpha = false; for (int i = 0; i < PIN_LENGTH; i++) { - if (!IS_ALPHANUM(pin[i])) { + if (!IS_ALPHANUM(GET_PIN(pin_ctx)[i])) { return false; } - if (hasAlpha || IS_ALPHA(pin[i])) { + if (hasAlpha || IS_ALPHA(GET_PIN(pin_ctx)[i])) { hasAlpha = true; } } return hasAlpha; +} + +/* + * Reset the given pin context to point to a target buffer + * + * @arg[out] pin_ctx pin context + * @arg[in] pin_buffer pin buffer to which the pin context should point + */ +void init_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer) { + pin_ctx->pin_buffer = pin_buffer; +} + +/* + * Reset the given pin context + * + * @arg[in] pin_ctx pin context + */ +void reset_pin_ctx(pin_t* pin_ctx) { + explicit_bzero(pin_ctx, sizeof(pin_t)); +} + +/* + * Implements RSK PIN command. + * + * Receives one byte at a time and updates the pin context, adding a null byte + * at the end. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int update_pin_buffer(volatile unsigned int rx, pin_t* pin_ctx) { + // Should receive 1 byte per call + if (APDU_DATA_SIZE(rx) != 1) { + THROW(PROT_INVALID); + } + + unsigned char index = APDU_OP(); + if ((index >= 0) && (index <= PIN_LENGTH)) { + pin_ctx->pin_buffer[index] = APDU_AT(DATA); + pin_ctx->pin_buffer[index + 1] = 0; + } + + return 3; +} + +/* + * Implements RSK NEW PIN command. + * + * Sets the device pin. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int set_device_pin(volatile unsigned int rx, pin_t* pin_ctx) { + // NEW_PIN command does not use any input from apdu buffer + UNUSED(rx); + +#ifndef DEBUG_BUILD + if (!is_pin_valid(pin_ctx)) { + THROW(ERR_INVALID_PIN); + } +#endif + // Set PIN + os_perso_set_pin(0, GET_PIN(pin_ctx), GET_PIN_LENGTH(pin_ctx)); + // check PIN + os_global_pin_invalidate(); + unsigned char output_index = CMDPOS; + SET_APDU_AT(output_index++, 2); + SET_APDU_AT(output_index++, + os_global_pin_check(GET_PIN(pin_ctx), GET_PIN_LENGTH(pin_ctx))); + return output_index; } \ No newline at end of file diff --git a/ledger/src/ui/src/pin.h b/ledger/src/ui/src/pin.h index 0f5ac3b7..0eb270bd 100644 --- a/ledger/src/ui/src/pin.h +++ b/ledger/src/ui/src/pin.h @@ -28,7 +28,70 @@ #include #define PIN_LENGTH 8 +#define PIN_BUFFER_LENGTH (PIN_LENGTH + 2) -bool is_pin_valid(unsigned char *pin); +// Pin context +typedef struct { + unsigned char* pin_buffer; +} pin_t; + +// Helper macros for pin context manipulation +#define GET_PIN(pin_ctx) ((unsigned char*)((pin_ctx)->pin_buffer + 1)) +#define GET_PIN_LENGTH(pin_ctx) strlen((const char*)GET_PIN(pin_ctx)) + +/* + * Reset the given pin context + * + * @arg[in] pin_ctx pin context + */ +void reset_pin_ctx(pin_t* pin_ctx); + +/* + * Reset the given pin context to point to a target buffer + * + * @arg[out] pin_ctx pin context + * @arg[in] pin_buffer pin buffer to which the pin context should point + */ +void init_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer); + +// ----------------------------------------------------------------------- +// RSK protocol implementation +// ----------------------------------------------------------------------- + +/* + * Implements RSK PIN command. + * + * Receives one byte at a time and updates the pin context, adding a null byte + * at the end. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int update_pin_buffer(volatile unsigned int rx, pin_t* pin_ctx); + +/* + * Implements RSK NEW PIN command. + * + * Sets the device pin. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int set_device_pin(volatile unsigned int rx, pin_t* pin_ctx); + +// ----------------------------------------------------------------------- +// Pin manipulation utilities +// ----------------------------------------------------------------------- + +/* + * Validates that the pin has exactly PIN_LENGTH alphanumeric characters + * with at least one alphabetic character. + * + * @arg[in] pin_ctx pin context (with prepended length) + * @ret true if pin is valid, false otherwise + */ +bool is_pin_valid(pin_t* pin_ctx); #endif \ No newline at end of file diff --git a/ledger/src/ui/src/unlock.c b/ledger/src/ui/src/unlock.c new file mode 100644 index 00000000..e8e3592f --- /dev/null +++ b/ledger/src/ui/src/unlock.c @@ -0,0 +1,48 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "apdu.h" +#include "os.h" +#include "string.h" +#include "unlock.h" + +/* + * Implements RSK UNLOCK command. + * + * Unlocks the device. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int unlock(volatile unsigned int rx, pin_t *pin_ctx) { + // Unlock command does not use any input from apdu buffer + UNUSED(rx); + + unsigned char output_index = OP; + SET_APDU_AT(output_index++, + os_global_pin_check(pin_ctx->pin_buffer, + strlen((const char *)pin_ctx->pin_buffer))); + return output_index; +} diff --git a/ledger/src/ui/src/unlock.h b/ledger/src/ui/src/unlock.h new file mode 100644 index 00000000..e631d1f1 --- /dev/null +++ b/ledger/src/ui/src/unlock.h @@ -0,0 +1,41 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __UNLOCK +#define __UNLOCK + +#include "pin.h" + +/* + * Implements RSK UNLOCK command. + * + * Unlocks the device. + * + * @arg[in] rx number of received bytes from the Host + * @arg[in] pin_ctx pin context + * @ret number of transmited bytes to the host + */ +unsigned int unlock(volatile unsigned int rx, pin_t *pin_ctx); + +#endif diff --git a/ledger/src/ui/test/mock/apdu.h b/ledger/src/ui/test/mock/apdu.h new file mode 120000 index 00000000..946c51db --- /dev/null +++ b/ledger/src/ui/test/mock/apdu.h @@ -0,0 +1 @@ +../../../common/src/apdu.h \ No newline at end of file diff --git a/ledger/src/ui/test/mock/os.c b/ledger/src/ui/test/mock/os.c new file mode 100644 index 00000000..1590a831 --- /dev/null +++ b/ledger/src/ui/test/mock/os.c @@ -0,0 +1,62 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "os.h" +#include "string.h" + +/** + * Mocks pin currently loaded to device + */ +unsigned char current_pin[10]; + +/** + * APDU buffer + */ +unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +unsigned int os_global_pin_check(unsigned char *pin_buffer, + unsigned char pin_length) { + return !strncmp( + (const char *)pin_buffer, (const char *)current_pin, pin_length); +} + +void explicit_bzero(void *s, size_t len) { + memset(s, '\0', len); + /* Compiler barrier. */ + asm volatile("" ::: "memory"); +} + +void os_perso_set_pin(unsigned int identity, + unsigned char *pin, + unsigned int length) { + // Do nothing +} + +void os_global_pin_invalidate(void) { + // Do nothing +} + +void mock_set_pin(unsigned char *pin, size_t n) { + memcpy(current_pin, pin, n); +} \ No newline at end of file diff --git a/ledger/src/ui/test/mock/os.h b/ledger/src/ui/test/mock/os.h new file mode 100644 index 00000000..deb74c04 --- /dev/null +++ b/ledger/src/ui/test/mock/os.h @@ -0,0 +1,53 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +/** + * Utility macros + */ +#define UNUSED(x) (void)x +#define THROW(e) return e + +/** + * Mock APDU buffer + */ +#define IO_APDU_BUFFER_SIZE 85 +extern unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE]; + +/** + * Mock calls for os API + */ +unsigned int os_global_pin_check(unsigned char *pin_buffer, + unsigned char pin_length); +void os_perso_set_pin(unsigned int identity, + unsigned char *pin, + unsigned int length); +void os_global_pin_invalidate(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/pin/Makefile b/ledger/src/ui/test/pin/Makefile index 3906a2aa..864df04c 100644 --- a/ledger/src/ui/test/pin/Makefile +++ b/ledger/src/ui/test/pin/Makefile @@ -21,10 +21,11 @@ # SOFTWARE. SRCDIR = ../../src -CFLAGS = -I $(SRCDIR) -I ./ +MOCKDIR = ../mock +CFLAGS = -I $(SRCDIR) -I $(MOCKDIR) -I ./ PROG = test.out -OBJS = pin.o test_pin.o +OBJS = os.o pin.o test_pin.o all: $(PROG) @@ -37,6 +38,9 @@ test_pin.o: test_pin.c pin.o: $(SRCDIR)/pin.c $(CC) $(CFLAGS) -c -o $@ $^ +os.o: $(MOCKDIR)/os.c + $(CC) $(CFLAGS) -c -o $@ $^ + .PHONY: clean test clean: diff --git a/ledger/src/ui/test/pin/test_pin.c b/ledger/src/ui/test/pin/test_pin.c index de2e2c85..d4933b0d 100644 --- a/ledger/src/ui/test/pin/test_pin.c +++ b/ledger/src/ui/test/pin/test_pin.c @@ -29,52 +29,73 @@ #include "pin.h" +#define IS_VALID true +#define IS_NOT_VALID false + +void set_payload(pin_t *pin_ctx, unsigned char *payload, size_t n) { + memcpy(GET_PIN(pin_ctx), payload, n); +} + +void assert_pin(char *pin, bool expected) { + unsigned char pin_length = (char)strlen(pin); + unsigned char *pin_buffer = malloc(pin_length + 2); + pin_buffer[0] = pin_length; + strcpy((char *)pin_buffer + 1, pin); + + pin_t pin_ctx; + init_pin_ctx(&pin_ctx, pin_buffer); + assert(is_pin_valid(&pin_ctx) == expected); + free(pin_buffer); +} + void test_ok() { printf("Test OK...\n"); - assert(is_pin_valid((unsigned char*)"abcdefgh")); - assert(is_pin_valid((unsigned char*)"8b23ef1s")); - assert(is_pin_valid((unsigned char*)"MN22P3S9")); - assert(is_pin_valid((unsigned char*)"MN22P3S9")); + assert_pin("abcdefgh", IS_VALID); + assert_pin("8b23ef1s", IS_VALID); + assert_pin("MN22P3S9", IS_VALID); + assert_pin("MN22p3s9", IS_VALID); } void test_numeric_pin() { printf("Test pin with only numbers...\n"); - assert(!is_pin_valid((unsigned char*)"1234")); - assert(!is_pin_valid((unsigned char*)"123456")); - assert(!is_pin_valid((unsigned char*)"12345678")); - assert(!is_pin_valid((unsigned char*)"1234567890")); + assert_pin("1234", IS_NOT_VALID); + assert_pin("123456", IS_NOT_VALID); + assert_pin("12345678", IS_NOT_VALID); + assert_pin("1234567890", IS_NOT_VALID); } void test_pin_too_long() { printf("Test pin buffer too long...\n"); - assert(!is_pin_valid((unsigned char*)"abcdefghi")); - assert(!is_pin_valid((unsigned char*)"8b23ef1s85")); - assert(!is_pin_valid((unsigned char*)"MN22P3S9P20")); - assert(!is_pin_valid((unsigned char*)"MNOPQRSTQDAS")); + assert_pin("abcdefghi", IS_NOT_VALID); + assert_pin("8b23ef1s85", IS_NOT_VALID); + assert_pin("MN22P3S9P20", IS_NOT_VALID); + assert_pin("MNOPQRSTQDAS", IS_NOT_VALID); } void test_pin_too_short() { printf("Test pin buffer too short...\n"); - assert(!is_pin_valid((unsigned char*)"abcdefg")); - assert(!is_pin_valid((unsigned char*)"8b23ef")); - assert(!is_pin_valid((unsigned char*)"MN22P")); - assert(!is_pin_valid((unsigned char*)"MNOP")); + assert_pin("abcdefg", IS_NOT_VALID); + assert_pin("8b23ef", IS_NOT_VALID); + assert_pin("MN22P", IS_NOT_VALID); + assert_pin("MNOP", IS_NOT_VALID); } void test_pin_non_alpha() { printf("Test pin non alpha chars...\n"); - assert(!is_pin_valid((unsigned char*)"a1-@.;")); - assert(!is_pin_valid((unsigned char*)"!@#$^&*")); - assert(!is_pin_valid((unsigned char*)"(),./;']")); + assert_pin("a1-@.;", IS_NOT_VALID); + assert_pin("!@#$^&*", IS_NOT_VALID); + assert_pin("(),./;']", IS_NOT_VALID); + assert_pin("abcdefg", IS_NOT_VALID); } int main() { test_ok(); + test_numeric_pin(); test_pin_too_long(); test_pin_too_short(); diff --git a/ledger/src/ui/test/unlock/Makefile b/ledger/src/ui/test/unlock/Makefile new file mode 100644 index 00000000..e0024619 --- /dev/null +++ b/ledger/src/ui/test/unlock/Makefile @@ -0,0 +1,53 @@ +# The MIT License (MIT) +# +# Copyright (c) 2021 RSK Labs Ltd +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +SRCDIR = ../../src +MOCKDIR = ../mock +CFLAGS = -I $(SRCDIR) -I $(MOCKDIR) + +PROG = test.out +OBJS = os.o pin.o unlock.o test_unlock.o + +all: $(PROG) + +$(PROG): $(OBJS) + $(CC) -o $@ $^ + +test_unlock.o: test_unlock.c + $(CC) $(CFLAGS) -c -o $@ $^ + +unlock.o: $(SRCDIR)/unlock.c + $(CC) $(CFLAGS) -c -o $@ $^ + +pin.o: $(SRCDIR)/pin.c + $(CC) $(CFLAGS) -c -o $@ $^ + +os.o: $(MOCKDIR)/os.c + $(CC) $(CFLAGS) -c -o $@ $^ + +.PHONY: clean test + +clean: + rm -f $(PROG) ./*.o + +test: all + ./$(PROG) diff --git a/ledger/src/ui/test/unlock/test_unlock.c b/ledger/src/ui/test/unlock/test_unlock.c new file mode 100644 index 00000000..22cb14eb --- /dev/null +++ b/ledger/src/ui/test/unlock/test_unlock.c @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2021 RSK Labs Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "apdu.h" +#include "os.h" +#include "unlock.h" + +void test_ok() { + printf("Test OK...\n"); + + pin_t pin_ctx; + init_pin_ctx(&pin_ctx, (unsigned char *)"1234567a\0\0"); + + unsigned int tx = unlock(&pin_ctx); + assert(tx == 3); + assert(APDU_OP() == 1); +} + +void test_wrong_pin() { + printf("Test wrong pin...\n"); + + pin_t pin_ctx; + init_pin_ctx(&pin_ctx, (unsigned char *)"wrong-pin\0"); + + unsigned int tx = unlock(&pin_ctx); + assert(tx == 3); + assert(APDU_OP() == 0); +} + +int main() { + // Set device pin + mock_set_pin((unsigned char *)"1234567a", strlen("1234567a")); + + test_ok(); + test_wrong_pin(); + + return 0; +}