mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-24 15:28:10 +00:00
da98a3a6fd
Instead of reflashing the whole storage, we use a designated area in the second storage block, where we mark each PIN failure by a single zero bit. This is because one can set bits in flash to zero but not to one. If the PIN was entered successfully the whole word is set to zero and the next word stores the new PIN failure counter.
243 lines
6.1 KiB
C
243 lines
6.1 KiB
C
/*
|
|
* This file is part of the TREZOR project.
|
|
*
|
|
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
|
*
|
|
* This library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "protect.h"
|
|
#include "storage.h"
|
|
#include "messages.h"
|
|
#include "usb.h"
|
|
#include "oled.h"
|
|
#include "buttons.h"
|
|
#include "pinmatrix.h"
|
|
#include "fsm.h"
|
|
#include "layout2.h"
|
|
#include "util.h"
|
|
#include "debug.h"
|
|
|
|
bool protectAbortedByInitialize = false;
|
|
|
|
bool protectButton(ButtonRequestType type, bool confirm_only)
|
|
{
|
|
ButtonRequest resp;
|
|
bool result = false;
|
|
bool acked = false;
|
|
#if DEBUG_LINK
|
|
bool debug_decided = false;
|
|
#endif
|
|
|
|
memset(&resp, 0, sizeof(ButtonRequest));
|
|
resp.has_code = true;
|
|
resp.code = type;
|
|
usbTiny(1);
|
|
msg_write(MessageType_MessageType_ButtonRequest, &resp);
|
|
|
|
for (;;) {
|
|
usbPoll();
|
|
|
|
// check for ButtonAck
|
|
if (msg_tiny_id == MessageType_MessageType_ButtonAck) {
|
|
msg_tiny_id = 0xFFFF;
|
|
acked = true;
|
|
}
|
|
|
|
// button acked - check buttons
|
|
if (acked) {
|
|
usbDelay(3500);
|
|
buttonUpdate();
|
|
if (button.YesUp) {
|
|
result = true;
|
|
break;
|
|
}
|
|
if (!confirm_only && button.NoUp) {
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check for Cancel / Initialize
|
|
if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
if (msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
protectAbortedByInitialize = true;
|
|
}
|
|
msg_tiny_id = 0xFFFF;
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
#if DEBUG_LINK
|
|
// check DebugLink
|
|
if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) {
|
|
msg_tiny_id = 0xFFFF;
|
|
DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny;
|
|
result = dld->yes_no;
|
|
debug_decided = true;
|
|
}
|
|
|
|
if (acked && debug_decided) {
|
|
break;
|
|
}
|
|
|
|
if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) {
|
|
msg_tiny_id = 0xFFFF;
|
|
fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
usbTiny(0);
|
|
|
|
return result;
|
|
}
|
|
|
|
const char *requestPin(PinMatrixRequestType type, const char *text)
|
|
{
|
|
PinMatrixRequest resp;
|
|
memset(&resp, 0, sizeof(PinMatrixRequest));
|
|
resp.has_type = true;
|
|
resp.type = type;
|
|
usbTiny(1);
|
|
msg_write(MessageType_MessageType_PinMatrixRequest, &resp);
|
|
pinmatrix_start(text);
|
|
for (;;) {
|
|
usbPoll();
|
|
if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) {
|
|
msg_tiny_id = 0xFFFF;
|
|
PinMatrixAck *pma = (PinMatrixAck *)msg_tiny;
|
|
pinmatrix_done(pma->pin); // convert via pinmatrix
|
|
usbTiny(0);
|
|
return pma->pin;
|
|
}
|
|
if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
pinmatrix_done(0);
|
|
if (msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
protectAbortedByInitialize = true;
|
|
}
|
|
msg_tiny_id = 0xFFFF;
|
|
usbTiny(0);
|
|
return 0;
|
|
}
|
|
#if DEBUG_LINK
|
|
if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) {
|
|
msg_tiny_id = 0xFFFF;
|
|
fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool protectPin(bool use_cached)
|
|
{
|
|
if (!storage.has_pin || storage.pin[0] == 0 || (use_cached && session_isPinCached())) {
|
|
return true;
|
|
}
|
|
uint32_t *fails = storage_getPinFailsPtr();
|
|
uint32_t wait = ~*fails;
|
|
while (wait > 0) {
|
|
// convert wait to secstr string
|
|
char secstrbuf[20];
|
|
strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf));
|
|
char *secstr = secstrbuf + 9;
|
|
uint32_t secs = wait;
|
|
while (secs > 0 && secstr >= secstrbuf) {
|
|
secstr--;
|
|
*secstr = (secs % 10) + '0';
|
|
secs /= 10;
|
|
}
|
|
if (wait == 1) {
|
|
secstrbuf[16] = 0;
|
|
}
|
|
layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
|
|
// wait one second
|
|
usbDelay(840000);
|
|
wait--;
|
|
}
|
|
const char *pin;
|
|
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:");
|
|
if (!pin) {
|
|
fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled");
|
|
return false;
|
|
}
|
|
if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) {
|
|
session_cachePin();
|
|
storage_resetPinFails(fails);
|
|
return true;
|
|
} else {
|
|
fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool protectChangePin(void)
|
|
{
|
|
const char *pin;
|
|
char pin1[17], pin2[17];
|
|
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, "Please enter new PIN:");
|
|
if (!pin) {
|
|
return false;
|
|
}
|
|
strlcpy(pin1, pin, sizeof(pin1));
|
|
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, "Please re-enter new PIN:");
|
|
if (!pin) {
|
|
return false;
|
|
}
|
|
strlcpy(pin2, pin, sizeof(pin2));
|
|
if (strcmp(pin1, pin2) == 0) {
|
|
storage_setPin(pin1);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool protectPassphrase(void)
|
|
{
|
|
if (!storage.has_passphrase_protection || !storage.passphrase_protection || session_isPassphraseCached()) {
|
|
return true;
|
|
}
|
|
|
|
PassphraseRequest resp;
|
|
memset(&resp, 0, sizeof(PassphraseRequest));
|
|
usbTiny(1);
|
|
msg_write(MessageType_MessageType_PassphraseRequest, &resp);
|
|
|
|
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL);
|
|
|
|
bool result;
|
|
for (;;) {
|
|
usbPoll();
|
|
if (msg_tiny_id == MessageType_MessageType_PassphraseAck) {
|
|
msg_tiny_id = 0xFFFF;
|
|
PassphraseAck *ppa = (PassphraseAck *)msg_tiny;
|
|
session_cachePassphrase(ppa->passphrase);
|
|
result = true;
|
|
break;
|
|
}
|
|
if (msg_tiny_id == MessageType_MessageType_Cancel || msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
if (msg_tiny_id == MessageType_MessageType_Initialize) {
|
|
protectAbortedByInitialize = true;
|
|
}
|
|
msg_tiny_id = 0xFFFF;
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
usbTiny(0);
|
|
layoutHome();
|
|
return result;
|
|
}
|