1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 23:48:12 +00:00

More standard conform behaviour

Tested with u2f-ref-code/u2f-tests.
Known incompatibility:
 - changed challenge invalidates button press.
This commit is contained in:
Jochen Hoenicke 2016-05-24 00:24:14 +02:00
parent 96f30a0ba7
commit 68b34af19e
5 changed files with 77 additions and 78 deletions

View File

@ -57,7 +57,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
// button acked - check buttons // button acked - check buttons
if (acked) { if (acked) {
usbDelay(3500); usbDelay(3300);
buttonUpdate(); buttonUpdate();
if (button.YesUp) { if (button.YesUp) {
result = true; result = true;
@ -163,7 +163,7 @@ bool protectPin(bool use_cached)
} }
layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL); layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
// wait one second // wait one second
usbDelay(840000); usbDelay(800000);
wait--; wait--;
} }
const char *pin; const char *pin;

View File

@ -44,8 +44,8 @@
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b))
// About 1/2 Second according to values used in protect.c // About 1/2 Second according to values used in protect.c
#define U2F_TIMEOUT 840000/2 #define U2F_TIMEOUT (800000/2)
#define U2F_OUT_PKT_BUFFER_LEN 16 #define U2F_OUT_PKT_BUFFER_LEN 128
// Initialise without a cid // Initialise without a cid
static uint32_t cid = 0; static uint32_t cid = 0;
@ -120,36 +120,6 @@ char *debugInt(const uint32_t i)
static uint32_t dialog_timeout = 0; static uint32_t dialog_timeout = 0;
void LayoutHomeAfterTimeout(void)
{
static bool timeoutLock = false;
if (timeoutLock || dialog_timeout == 0)
return; // Dialog has cleared or already in loop
timeoutLock = true;
U2F_STATE rs = last_req_state;
U2F_STATE bs = INIT;
while (dialog_timeout-- && rs == last_req_state && bs == 0) {
usbPoll(); // may trigger new request
bs = buttonState();
}
timeoutLock = false;
if (rs != last_req_state)
return; // Reset by new request don't clear screen
if (dialog_timeout == 0) {
last_req_state += BTN_NO; // Timeout is like button no
}
else {
last_req_state += bs;
dialog_timeout = 0;
}
layoutHome();
}
uint32_t next_cid(void) uint32_t next_cid(void)
{ {
// extremely unlikely but hey // extremely unlikely but hey
@ -171,6 +141,18 @@ U2F_ReadBuffer *reader;
void u2fhid_read(char tiny, const U2FHID_FRAME *f) void u2fhid_read(char tiny, const U2FHID_FRAME *f)
{ {
// Always handle init packets directly
if (f->init.cmd == U2FHID_INIT) {
u2fhid_init(f);
if (tiny && reader && f->cid == cid) {
// abort current channel
reader->cmd = 0;
reader->len = 0;
reader->seq = 255;
}
return;
}
if (tiny) { if (tiny) {
// read continue packet // read continue packet
if (reader == 0 || cid != f->cid) { if (reader == 0 || cid != f->cid) {
@ -178,11 +160,19 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *f)
return; return;
} }
if ((f->type & TYPE_INIT) || reader->seq != f->cont.seq) { if ((f->type & TYPE_INIT) && reader->seq == 255) {
u2fhid_init_cmd(f); u2fhid_init_cmd(f);
return; return;
} }
if (reader->seq != f->cont.seq) {
send_u2fhid_error(f->cid, ERR_INVALID_SEQ);
reader->cmd = 0;
reader->len = 0;
reader->seq = 255;
return;
}
// check out of bounds // check out of bounds
if ((reader->buf_ptr - reader->buf) >= (signed) reader->len if ((reader->buf_ptr - reader->buf) >= (signed) reader->len
|| (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) || (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf))
@ -204,11 +194,6 @@ void u2fhid_init_cmd(const U2FHID_FRAME *f) {
memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data)); memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data));
reader->buf_ptr += sizeof(f->init.data); reader->buf_ptr += sizeof(f->init.data);
cid = f->cid; cid = f->cid;
// Check length isnt bigger than spec max
if (reader->len > sizeof(reader->buf)) {
reader->len = 0;
return send_u2fhid_error(cid, ERR_INVALID_LEN);
}
} }
void u2fhid_read_start(const U2FHID_FRAME *f) { void u2fhid_read_start(const U2FHID_FRAME *f) {
@ -217,13 +202,20 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
return; return;
} }
// Broadcast is reserved for init
if (f->cid == CID_BROADCAST || f->cid == 0) {
send_u2fhid_error(f->cid, ERR_INVALID_CID);
return;
}
if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) {
send_u2fhid_error(f->cid, ERR_INVALID_LEN);
return;
}
reader = &readbuffer; reader = &readbuffer;
u2fhid_init_cmd(f); u2fhid_init_cmd(f);
// Broadcast is reserved for init
if (f->cid == CID_BROADCAST && reader->cmd != U2FHID_INIT)
return;
usbTiny(1); usbTiny(1);
for(;;) { for(;;) {
// Do we need to wait for more data // Do we need to wait for more data
@ -234,8 +226,9 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
while (reader->seq == lastseq && reader->cmd == lastcmd) { while (reader->seq == lastseq && reader->cmd == lastcmd) {
if (counter-- == 0) { if (counter-- == 0) {
// timeout // timeout
send_u2fhid_error(cid, ERR_MSG_TIMEOUT);
cid = 0; cid = 0;
send_u2fhid_error(f->cid, ERR_MSG_TIMEOUT); reader = 0;
usbTiny(0); usbTiny(0);
return; return;
} }
@ -245,15 +238,15 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
// We have all the data // We have all the data
switch (reader->cmd) { switch (reader->cmd) {
case 0:
// message was aborted by init
break;
case U2FHID_PING: case U2FHID_PING:
u2fhid_ping(reader->buf, reader->len); u2fhid_ping(reader->buf, reader->len);
break; break;
case U2FHID_MSG: case U2FHID_MSG:
u2fhid_msg((APDU *)reader->buf, reader->len); u2fhid_msg((APDU *)reader->buf, reader->len);
break; break;
case U2FHID_INIT:
u2fhid_init((const U2FHID_INIT_REQ *)reader->buf);
break;
case U2FHID_WINK: case U2FHID_WINK:
u2fhid_wink(reader->buf, reader->len); u2fhid_wink(reader->buf, reader->len);
break; break;
@ -264,6 +257,7 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
// wait for next commmand/ button press // wait for next commmand/ button press
reader->cmd = 0; reader->cmd = 0;
reader->seq = 255;
uint8_t bs = 0; uint8_t bs = 0;
while (dialog_timeout-- && bs == 0 && reader->cmd == 0) { while (dialog_timeout-- && bs == 0 && reader->cmd == 0) {
usbPoll(); // may trigger new request usbPoll(); // may trigger new request
@ -279,6 +273,7 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
dialog_timeout = 0; dialog_timeout = 0;
} }
cid = 0; cid = 0;
reader = 0;
usbTiny(0); usbTiny(0);
layoutHome(); layoutHome();
return; return;
@ -311,20 +306,27 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len)
queue_u2f_pkt(&f); queue_u2f_pkt(&f);
} }
void u2fhid_init(const U2FHID_INIT_REQ *init_req) void u2fhid_init(const U2FHID_FRAME *in)
{ {
debugLog(0, "", "u2fhid_init"); const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data;
U2FHID_FRAME f; U2FHID_FRAME f;
U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data; U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data;
debugLog(0, "", "u2fhid_init");
if (in->cid == 0) {
send_u2fhid_error(in->cid, ERR_INVALID_CID);
return;
}
MEMSET_BZERO(&f, sizeof(f)); MEMSET_BZERO(&f, sizeof(f));
f.cid = cid; f.cid = in->cid;
f.init.cmd = U2FHID_INIT; f.init.cmd = U2FHID_INIT;
f.init.bcnth = 0; f.init.bcnth = 0;
f.init.bcntl = U2FHID_INIT_RESP_SIZE; f.init.bcntl = U2FHID_INIT_RESP_SIZE;
memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce)); memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce));
resp->cid = cid == CID_BROADCAST ? next_cid() : cid; resp->cid = in->cid == CID_BROADCAST ? next_cid() : in->cid;
resp->versionInterface = U2FHID_IF_VERSION; resp->versionInterface = U2FHID_IF_VERSION;
resp->versionMajor = VERSION_MAJOR; resp->versionMajor = VERSION_MAJOR;
resp->versionMinor = VERSION_MINOR; resp->versionMinor = VERSION_MINOR;
@ -358,8 +360,6 @@ uint8_t *u2f_out_data(void)
void u2fhid_msg(const APDU *a, uint32_t len) void u2fhid_msg(const APDU *a, uint32_t len)
{ {
static bool lock = false;
if ((APDU_LEN(*a) + sizeof(APDU)) > len) { if ((APDU_LEN(*a) + sizeof(APDU)) > len) {
debugLog(0, "", "BAD APDU LENGTH"); debugLog(0, "", "BAD APDU LENGTH");
debugInt(APDU_LEN(*a)); debugInt(APDU_LEN(*a));
@ -367,12 +367,10 @@ void u2fhid_msg(const APDU *a, uint32_t len)
return; return;
} }
// Very crude locking, incase another message comes in while we wait. This if (a->cla != 0) {
// actually can probably be removed as no code inside calls usbPoll anymore send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED);
if (lock) return;
return send_u2fhid_error(cid, ERR_CHANNEL_BUSY); }
lock = true;
switch (a->ins) { switch (a->ins) {
case U2F_REGISTER: case U2F_REGISTER:
@ -388,10 +386,6 @@ void u2fhid_msg(const APDU *a, uint32_t len)
debugLog(0, "", "u2f unknown cmd"); debugLog(0, "", "u2f unknown cmd");
send_u2f_error(U2F_SW_INS_NOT_SUPPORTED); send_u2f_error(U2F_SW_INS_NOT_SUPPORTED);
} }
lock = false;
//LayoutHomeAfterTimeout();
} }
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len)
@ -447,10 +441,15 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err)
void u2f_version(const APDU *a) void u2f_version(const APDU *a)
{ {
if (APDU_LEN(*a) != 0) {
debugLog(0, "", "u2f version - badlen");
send_u2f_error(U2F_SW_WRONG_LENGTH);
return;
}
// INCLUDES SW_NO_ERROR // INCLUDES SW_NO_ERROR
static const uint8_t version_response[] = {'U', '2', 'F', '_', static const uint8_t version_response[] = {'U', '2', 'F', '_',
'V', '2', 0x90, 0x00}; 'V', '2', 0x90, 0x00};
(void)a;
debugLog(0, "", "u2f version"); debugLog(0, "", "u2f version");
send_u2f_msg(version_response, sizeof(version_response)); send_u2f_msg(version_response, sizeof(version_response));
} }
@ -553,7 +552,7 @@ void u2f_register(const APDU *a)
debugLog(0, "", "u2f register"); debugLog(0, "", "u2f register");
if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) {
debugLog(0, "", "u2f register - badlen"); debugLog(0, "", "u2f register - badlen");
send_u2f_error(U2F_SW_WRONG_DATA); send_u2f_error(U2F_SW_WRONG_LENGTH);
return; return;
} }
@ -571,7 +570,7 @@ void u2f_register(const APDU *a)
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
buttonUpdate(); // Clear button state buttonUpdate(); // Clear button state
layoutU2FDialog("Register", getReadableAppId(req->appId)); layoutU2FDialog("Register", getReadableAppId(req->appId));
dialog_timeout = U2F_TIMEOUT; dialog_timeout = 10*U2F_TIMEOUT;
last_req_state = REG; last_req_state = REG;
return; return;
} }
@ -580,7 +579,7 @@ void u2f_register(const APDU *a)
if (last_req_state == REG) { if (last_req_state == REG) {
// error: testof-user-presence is required // error: testof-user-presence is required
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
dialog_timeout = U2F_TIMEOUT; dialog_timeout = 10*U2F_TIMEOUT;
return; return;
} }
@ -640,6 +639,7 @@ void u2f_register(const APDU *a)
1 /* keyhandleLen */ + resp->keyHandleLen + 1 /* keyhandleLen */ + resp->keyHandleLen +
sizeof(U2F_ATT_CERT) + sig_len + 2; sizeof(U2F_ATT_CERT) + sig_len + 2;
last_req_state = INIT;
send_u2f_msg(data, l); send_u2f_msg(data, l);
return; return;
} }
@ -655,7 +655,7 @@ void u2f_authenticate(const APDU *a)
if (APDU_LEN(*a) < 64) { /// FIXME: decent value if (APDU_LEN(*a) < 64) { /// FIXME: decent value
debugLog(0, "", "u2f authenticate - badlen"); debugLog(0, "", "u2f authenticate - badlen");
send_u2f_error(U2F_SW_WRONG_DATA); send_u2f_error(U2F_SW_WRONG_LENGTH);
return; return;
} }
@ -699,19 +699,16 @@ void u2f_authenticate(const APDU *a)
if (last_req_state == INIT) { if (last_req_state == INIT) {
// error: testof-user-presence is required // error: testof-user-presence is required
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
buttonUpdate(); // Clear button state buttonUpdate(); // Clear button state
layoutU2FDialog("Authenticate", getReadableAppId(req->appId)); layoutU2FDialog("Authenticate", getReadableAppId(req->appId));
dialog_timeout = U2F_TIMEOUT;
last_req_state = AUTH; last_req_state = AUTH;
return;
} }
// Awaiting Keypress // Awaiting Keypress
if (last_req_state == AUTH) { if (last_req_state == AUTH) {
// error: testof-user-presence is required // error: testof-user-presence is required
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
dialog_timeout = U2F_TIMEOUT; dialog_timeout = 10*U2F_TIMEOUT;
return; return;
} }
@ -753,10 +750,10 @@ void u2f_authenticate(const APDU *a)
memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) -
U2F_MAX_EC_SIG_SIZE + sig_len, U2F_MAX_EC_SIG_SIZE + sig_len,
"\x90\x00", 2); "\x90\x00", 2);
last_req_state = INIT;
send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) -
U2F_MAX_EC_SIG_SIZE + sig_len + U2F_MAX_EC_SIG_SIZE + sig_len +
2); 2);
last_req_state = INIT;
} }
} }

View File

@ -39,7 +39,7 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *buf);
void u2fhid_init_cmd(const U2FHID_FRAME *f); void u2fhid_init_cmd(const U2FHID_FRAME *f);
void u2fhid_read_start(const U2FHID_FRAME *f); void u2fhid_read_start(const U2FHID_FRAME *f);
bool u2fhid_write(uint8_t *buf); bool u2fhid_write(uint8_t *buf);
void u2fhid_init(const U2FHID_INIT_REQ *init_req); void u2fhid_init(const U2FHID_FRAME *in);
void u2fhid_ping(const uint8_t *buf, uint32_t len); void u2fhid_ping(const uint8_t *buf, uint32_t len);
void u2fhid_wink(const uint8_t *buf, uint32_t len); void u2fhid_wink(const uint8_t *buf, uint32_t len);
void u2fhid_sync(const uint8_t *buf, uint32_t len); void u2fhid_sync(const uint8_t *buf, uint32_t len);

View File

@ -129,8 +129,10 @@ extern "C"
// Command status responses // Command status responses
#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR #define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR
#define U2F_SW_WRONG_DATA 0x6984 // SW_WRONG_DATA #define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH
#define U2F_SW_DATA_INVALID 0x6984 // SW_WRONG_DATA
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED
#define U2F_SW_WRONG_DATA 0x6a80 // SW_WRONG_DATA
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED #define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED
#define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED #define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED

View File

@ -165,14 +165,14 @@ static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 2,
}, { }, {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 2,
}}; }};
static const struct usb_interface_descriptor hid_iface_u2f[] = {{ static const struct usb_interface_descriptor hid_iface_u2f[] = {{