mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-03 12:00:59 +00:00
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
This commit is contained in:
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…
Reference in New Issue
Block a user