Added callback for PIN timeout

When PIN is entered or changed and their were failed tries the function
waits for time (exponential slow down).  For every second it waits, it
now calls back into python to give it the chance to show a message.

GUI still needs to be implemented
pull/25/head
Jochen Hoenicke 7 years ago
parent 9f2bbb0e1a
commit 87f7054e46

@ -25,20 +25,20 @@ STATIC mp_obj_t mod_trezorconfig_init(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_init_obj, mod_trezorconfig_init);
/// def unlock(pin: str) -> bool:
/// def unlock(pin: str, waitcallback: (int -> None)) -> bool:
/// '''
/// Attempts to unlock the storage with given PIN. Returns True on
/// success, False on failure.
/// '''
STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin) {
STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin, mp_obj_t waitcallback) {
mp_buffer_info_t buf;
mp_get_buffer_raise(pin, &buf, MP_BUFFER_READ);
if (sectrue != storage_unlock(buf.buf, buf.len)) {
if (sectrue != storage_unlock(buf.buf, buf.len, waitcallback)) {
return mp_const_false;
}
return mp_const_true;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_unlock_obj, mod_trezorconfig_unlock);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_unlock_obj, mod_trezorconfig_unlock);
/// def has_pin() -> bool:
/// '''
@ -52,21 +52,21 @@ STATIC mp_obj_t mod_trezorconfig_has_pin(void) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_has_pin_obj, mod_trezorconfig_has_pin);
/// def change_pin(pin: str, newpin: str) -> bool:
/// def change_pin(pin: str, newpin: str, waitcallback: (int -> None)) -> bool:
/// '''
/// Change PIN. Returns True on success, False on failure.
/// '''
STATIC mp_obj_t mod_trezorconfig_change_pin(mp_obj_t pin, mp_obj_t newpin) {
STATIC mp_obj_t mod_trezorconfig_change_pin(mp_obj_t pin, mp_obj_t newpin, mp_obj_t waitcallback) {
mp_buffer_info_t pinbuf;
mp_get_buffer_raise(pin, &pinbuf, MP_BUFFER_READ);
mp_buffer_info_t newbuf;
mp_get_buffer_raise(newpin, &newbuf, MP_BUFFER_READ);
if (sectrue != storage_change_pin(pinbuf.buf, pinbuf.len, newbuf.buf, newbuf.len)) {
if (sectrue != storage_change_pin(pinbuf.buf, pinbuf.len, newbuf.buf, newbuf.len, waitcallback)) {
return mp_const_false;
}
return mp_const_true;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_change_pin_obj, mod_trezorconfig_change_pin);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_trezorconfig_change_pin_obj, mod_trezorconfig_change_pin);
/// def get(app: int, key: int) -> bytes:
/// '''

@ -10,6 +10,8 @@
#include "common.h"
#include "norcow.h"
#include "../../trezorhal/flash.h"
#include "py/runtime.h"
#include "py/obj.h"
// Norcow storage key of configured PIN.
#define PIN_KEY 0x0000
@ -89,14 +91,11 @@ static secbool pin_cmp(const uint8_t *pin, size_t pinlen)
}
}
static secbool pin_check(const uint8_t *pin, size_t len)
static secbool pin_get_fails(const uint32_t **pinfail, uint32_t *pofs)
{
uint32_t ofs = 0;
uint32_t ctr;
const void *vpinfail;
const uint32_t *pinfail = NULL;
uint16_t pinfaillen;
unsigned int ofs;
// The PIN_FAIL_KEY points to an area of words, initialized to
// 0xffffffff (meaning no pin failures). The first non-zero word
// in this area is the current pin failure counter. If PIN_FAIL_KEY
@ -106,36 +105,51 @@ static secbool pin_check(const uint8_t *pin, size_t len)
// indicating that the next word is the pin failure counter.
// Find the current pin failure counter
secbool found = secfalse;
if (secfalse != norcow_get(PIN_FAIL_KEY, &vpinfail, &pinfaillen)) {
pinfail = vpinfail;
*pinfail = vpinfail;
for (ofs = 0; ofs < pinfaillen / sizeof(uint32_t); ofs++) {
if (pinfail[ofs]) {
found = sectrue;
break;
if (((const uint32_t *) vpinfail)[ofs]) {
*pinfail = vpinfail;
*pofs = ofs;
return sectrue;
}
}
}
if (found == secfalse) {
// No pin failure section, or all entries used -> create a new one.
uint32_t pinarea[PIN_FAIL_SECTOR_SIZE];
memset(pinarea, 0xff, sizeof(pinarea));
if (sectrue != norcow_set(PIN_FAIL_KEY, pinarea, sizeof(pinarea))) {
return secfalse;
}
if (sectrue != norcow_get(PIN_FAIL_KEY, &vpinfail, &pinfaillen)) {
return secfalse;
}
pinfail = vpinfail;
ofs = 0;
// No pin failure section, or all entries used -> create a new one.
uint32_t pinarea[PIN_FAIL_SECTOR_SIZE];
memset(pinarea, 0xff, sizeof(pinarea));
if (sectrue != norcow_set(PIN_FAIL_KEY, pinarea, sizeof(pinarea))) {
return secfalse;
}
if (sectrue != norcow_get(PIN_FAIL_KEY, &vpinfail, &pinfaillen)) {
return secfalse;
}
*pinfail = vpinfail;
*pofs = 0;
return sectrue;
}
static secbool pin_check(const uint8_t *pin, size_t len, mp_obj_t callback)
{
const uint32_t *pinfail = NULL;
uint32_t ofs;
uint32_t ctr;
// Get the pin failure counter
if (pin_get_fails(&pinfail, &ofs) != sectrue) {
return secfalse;
}
// Read current failure counter
ctr = pinfail[ofs];
// Wipe storage if too many failures
pin_fails_check_max(ctr);
// Sleep for ~ctr seconds before checking the PIN.
for (uint32_t wait = ~ctr; wait > 0; wait--) {
mp_obj_t waitobj = mp_obj_new_int(wait);
mp_call_function_1(callback, waitobj);
hal_delay(1000);
}
@ -146,6 +160,7 @@ static secbool pin_check(const uint8_t *pin, size_t len)
return secfalse;
}
if (sectrue != pin_cmp(pin, len)) {
// Wipe storage if too many failures
pin_fails_check_max(ctr << 1);
return secfalse;
}
@ -155,10 +170,10 @@ static secbool pin_check(const uint8_t *pin, size_t len)
return sectrue;
}
secbool storage_unlock(const uint8_t *pin, size_t len)
secbool storage_unlock(const uint8_t *pin, size_t len, mp_obj_t callback)
{
unlocked = secfalse;
if (sectrue == initialized && sectrue == pin_check(pin, len)) {
if (sectrue == initialized && sectrue == pin_check(pin, len, callback)) {
unlocked = sectrue;
}
return unlocked;
@ -191,12 +206,12 @@ secbool storage_has_pin(void)
return sectrue * (0 != spinlen);
}
secbool storage_change_pin(const uint8_t *pin, size_t len, const uint8_t *newpin, size_t newlen)
secbool storage_change_pin(const uint8_t *pin, size_t len, const uint8_t *newpin, size_t newlen, mp_obj_t callback)
{
if (sectrue != initialized || sectrue != unlocked || newlen > PIN_MAXLEN) {
return secfalse;
}
if (sectrue != pin_check(pin, len)) {
if (sectrue != pin_check(pin, len, callback)) {
return secfalse;
}
return norcow_set(PIN_KEY, newpin, newlen);

@ -8,11 +8,13 @@
#include <stdint.h>
#include <stddef.h>
#include "../../trezorhal/secbool.h"
#include "py/obj.h"
void storage_init(void);
void storage_wipe(void);
secbool storage_unlock(const uint8_t *pin, size_t len);
secbool storage_unlock(const uint8_t *pin, size_t len, mp_obj_t callback);
secbool storage_has_pin(void);
secbool storage_change_pin(const uint8_t *pin, size_t len, const uint8_t *newpin, size_t newlen);
uint32_t storage_pin_wait_time(void);
secbool storage_change_pin(const uint8_t *pin, size_t len, const uint8_t *newpin, size_t newlen, mp_obj_t callback);
secbool storage_get(uint16_t key, const void **val, uint16_t *len);
secbool storage_set(uint16_t key, const void *val, uint16_t len);

@ -62,7 +62,11 @@ async def layout_change_pin(ctx, msg):
else:
new_pin = await request_pin_confirm(ctx)
config.change_pin(curr_pin, new_pin)
def show_timeout(wait):
# TODO
return
config.change_pin(curr_pin, new_pin, show_timeout)
if new_pin:
return Success(message='PIN changed')

@ -5,13 +5,19 @@ from trezor import ui
from apps.common.request_pin import request_pin
def show_timeout(wait):
# TODO
from trezor import log
log.debug('PIN', 'waiting %d seconds', wait)
async def unlock_layout():
while True:
if config.has_pin():
pin = await request_pin()
else:
pin = ''
if config.unlock(pin):
if config.unlock(pin, show_timeout):
return
else:
await unlock_failed()

Loading…
Cancel
Save