Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factor out UI modules unlock and pin #97

Merged
merged 3 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 29 additions & 35 deletions ledger/src/ui/src/bolos_ux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[MAX_PIN_LENGTH + 2];

#ifdef OS_IO_SEPROXYHAL

Expand Down Expand Up @@ -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;

Expand All @@ -265,6 +265,7 @@ static void reset_if_starting(unsigned char cmd) {
G_bolos_ux_context.words_buffer_length = 0;
reset_attestation(&attestation_ctx);
reset_signer_authorization(&sigaut_ctx);
reset_pin(&pin_ctx);
}
}

Expand Down Expand Up @@ -321,11 +322,9 @@ 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;
}
tx = pin_cmd(&pin_ctx);
amendelzon marked this conversation as resolved.
Show resolved Hide resolved
// Save pin for authenticated operations
get_pin_ctx(&pin_ctx, G_pin_buffer);
THROW(APDU_OK);
break;
case RSK_IS_ONBOARD: // Wheter it's onboarded or not
Expand All @@ -347,8 +346,9 @@ static void sample_main(void) {
nvm_write(
(void *)PIC(N_onboarded_ui), (void *)&aux, sizeof(aux));

set_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
Expand Down Expand Up @@ -392,14 +392,18 @@ 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,
pin_ctx.pin_buffer.payload,
strlen((const char *)pin_ctx.pin_buffer.payload));
// 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()));
SET_APDU_AT(
2,
os_global_pin_check(
pin_ctx.pin_buffer.payload,
strlen((const char *)pin_ctx.pin_buffer.payload)));
// Clear pin buffer
explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer));
// Turn the onboarding flag on to mark onboarding
Expand All @@ -414,21 +418,13 @@ static void sample_main(void) {
case RSK_NEWPIN:
reset_if_starting(RSK_META_CMD_UIOP);

set_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 = new_pin_cmd(&pin_ctx);
// Clear pin buffer
explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer));
THROW(APDU_OK);
Expand Down Expand Up @@ -464,16 +460,13 @@ static void sample_main(void) {
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);
// pin_ctx.pin_raw instead of pin_ctx.pin_buffer.payload
set_pin_ctx(&pin_ctx, G_pin_buffer);
tx = unlock(&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);
Expand Down Expand Up @@ -652,8 +645,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));
set_pin_ctx(&pin_ctx, G_pin_buffer);
os_global_pin_check(pin_ctx.pin_raw,
strlen((const char *)pin_ctx.pin_raw));
G_bolos_ux_context.exit_code = BOLOS_UX_OK;
explicit_bzero(G_pin_buffer, sizeof(G_pin_buffer));
break;
Expand Down
1 change: 1 addition & 0 deletions ledger/src/ui/src/bolos_ux.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ typedef struct bolos_ux_context {
union {
att_t attestation;
sigaut_t sigaut;
pin_t pin;
};
};

Expand Down
65 changes: 52 additions & 13 deletions ledger/src/ui/src/pin.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include <string.h>

#include "apdu.h"
#include "os.h"
#include "err.h"
#include "pin.h"

Expand All @@ -33,29 +35,66 @@
#define IS_NUM(c) IS_IN_RANGE(c, '0', '9')
#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))

/*
* 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
* @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) {
size_t length =
strnlen((const char*)pin_ctx->pin_buffer.payload, MAX_PIN_LENGTH + 1);
if (length != MAX_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])) {
for (int i = 0; i < MAX_PIN_LENGTH; i++) {
if (!IS_ALPHANUM(pin_ctx->pin_buffer.payload[i])) {
return false;
}
if (hasAlpha || IS_ALPHA(pin[i])) {
if (hasAlpha || IS_ALPHA(pin_ctx->pin_buffer.payload[i])) {
hasAlpha = true;
}
}

return hasAlpha;
}

void get_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer) {
memcpy(pin_buffer, pin_ctx->pin_raw, sizeof(pin_ctx->pin_raw));
}

void set_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer) {
memcpy(pin_ctx->pin_raw, pin_buffer, sizeof(pin_ctx->pin_raw));
}
amendelzon marked this conversation as resolved.
Show resolved Hide resolved

void reset_pin(pin_t* pin_ctx) {
explicit_bzero(pin_ctx, sizeof(pin_t));
}

unsigned int pin_cmd(pin_t* pin_ctx) {
unsigned char index = APDU_AT(2);
if ((index >= 0) && (index <= MAX_PIN_LENGTH)) {
pin_ctx->pin_raw[index] = APDU_AT(3);
pin_ctx->pin_raw[index + 1] = 0;
}

return 3;
}

unsigned int new_pin_cmd(pin_t* pin_ctx) {
#ifndef DEBUG_BUILD
if (!is_pin_valid(pin_ctx)) {
THROW(ERR_INVALID_PIN);
}
#endif
// Set PIN
os_perso_set_pin(0,
pin_ctx->pin_buffer.payload,
strlen((const char*)pin_ctx->pin_buffer.payload));
// 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(pin_ctx->pin_buffer.payload,
strlen((const char*)pin_ctx->pin_buffer.payload)));
return output_index;
}
75 changes: 73 additions & 2 deletions ledger/src/ui/src/pin.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,79 @@

#include <stdbool.h>

#define PIN_LENGTH 8
#define MAX_PIN_LENGTH 8
#define MIN_PIN_LENGTH 4
amendelzon marked this conversation as resolved.
Show resolved Hide resolved

bool is_pin_valid(unsigned char *pin);
// Pin context
typedef struct {
union {
struct {
unsigned char length;
unsigned char payload[MAX_PIN_LENGTH + 1];
} pin_buffer;
unsigned char pin_raw[MAX_PIN_LENGTH + 2];
amendelzon marked this conversation as resolved.
Show resolved Hide resolved
};
} pin_t;

/*
* Reset the given pin context
*
* @arg[in] pin_ctx pin context
*/
void reset_pin(pin_t* pin_ctx);

// -----------------------------------------------------------------------
// 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] pin_ctx pin context
* @ret number of transmited bytes to the host
*/
unsigned int pin_cmd(pin_t* pin_ctx);

/*
* Implements RSK NEW PIN command.
*
* Sets the device pin.
*
* @arg[in] pin_ctx pin context
* @ret number of transmited bytes to the host
*/
unsigned int new_pin_cmd(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);

/*
* Retrieves the pin currently saved on pin_ctx to pin_buffer
*
* @arg[in] pin_ctx pin context
* @arg[out] pin_buffer output buffer where the pin should be copied
*/
void get_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer);

/*
* Saves the pin in pin_buffer to pin_ctx.
*
* @arg[out] pin_ctx pin context
* @arg[in] pin_buffer input buffer that holds the pin
*/
void set_pin_ctx(pin_t* pin_ctx, unsigned char* pin_buffer);

#endif
36 changes: 36 additions & 0 deletions ledger/src/ui/src/unlock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* 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"

unsigned int unlock(pin_t *pin_ctx) {
unsigned char output_index = OP;
SET_APDU_AT(output_index++,
os_global_pin_check(pin_ctx->pin_raw,
strlen((const char *)pin_ctx->pin_raw)));
return output_index;
}
Loading