From 2edc3ecada66011da95249e4d2efb7178b151dc1 Mon Sep 17 00:00:00 2001 From: douglasbakkum Date: Tue, 18 Jun 2019 07:04:21 +0200 Subject: [PATCH 1/5] u2f hijack bugfix: empty return frame when need more data --- src/u2f/u2f.h | 1 + src/u2f_device.c | 55 ++++++++++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/u2f/u2f.h b/src/u2f/u2f.h index 96bc188c..b9b036f7 100644 --- a/src/u2f/u2f.h +++ b/src/u2f/u2f.h @@ -20,6 +20,7 @@ #define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate #define U2F_MAX_EC_SIG_SIZE 72 // Max size of ANS.1 DER encoded EC signature #define U2F_CTR_SIZE 4 // Size of counter field +#define U2F_FRAME_SIZE (3 + U2F_CTR_SIZE)// 1-byte flag | 4-byte counter | 2-byte status #define U2F_APPID_SIZE 32 // Size of application id #define U2F_NONCE_LENGTH 32 // Size of challenge nonce #define U2F_UNCOMPRESSED_POINT 0x04 // Uncompressed point format diff --git a/src/u2f_device.c b/src/u2f_device.c index edbbf0b6..184f9926 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -258,15 +258,35 @@ static void u2f_device_register(const USB_APDU *a) } +/* + * Add flag, U2F counter, and return code framing to the U2F data packet for + * the U2F hijack communication. Return the lenght of the framed report. + */ +static uint16_t _frame_hijack_report(char *report, uint16_t len, uint16_t report_size) +{ + uint16_t report_len = len + U2F_FRAME_SIZE; + if (report_len > COMMANDER_REPORT_SIZE || report_len > report_size) { + return 0; + } + const uint32_t ctr = memory_u2f_count_iter(); + memmove(report + 1 + U2F_CTR_SIZE, report, len); + report[0] = 0; // Flags + report[1] = (ctr >> 24) & 0xff; + report[2] = (ctr >> 16) & 0xff; + report[3] = (ctr >> 8) & 0xff; + report[4] = ctr & 0xff; + // Append success bytes so that response gets through U2F client code. + // Otherwise, the client will resend sign requests until timing out. + // Errors encoded in JSON-formatted report. + memcpy(report + report_len - 2, "\x90\x00", 2); + return report_len; +} + static void u2f_device_hijack(const U2F_AUTHENTICATE_REQ *req) { static char hijack_cmd[COMMANDER_REPORT_SIZE] = {0}; - - const uint32_t ctr = memory_u2f_count_iter(); - char empty_report[3 + U2F_CTR_SIZE] = {0};// 1-byte flag | 4-byte ctr | 2-byte status char *report; int report_len; - size_t kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2)); uint8_t tot = req->keyHandle[0]; uint8_t cnt = req->keyHandle[1]; @@ -278,27 +298,16 @@ static void u2f_device_hijack(const U2F_AUTHENTICATE_REQ *req) } if (cnt + 1 < tot) { - // Need more data. Acknowledge by returning an empty report. - report = empty_report; - report_len = sizeof(empty_report); - } else { - report = commander(hijack_cmd); - report_len = MIN(strlens(report) + sizeof(empty_report), COMMANDER_REPORT_SIZE); - memmove(report + 1 + U2F_CTR_SIZE, report, MIN(strlens(report), - COMMANDER_REPORT_SIZE - U2F_CTR_SIZE - 1)); - memset(hijack_cmd, 0, sizeof(hijack_cmd)); + // Need more data. Acknowledge by returning a 1-byte empty report. + char empty_report[U2F_FRAME_SIZE + 1] = {0}; + report_len = _frame_hijack_report(empty_report, 1, sizeof(empty_report)); + u2f_send_message((const uint8_t *)empty_report, report_len); + return; } - report[0] = 0;// Flags - report[1] = (ctr >> 24) & 0xff; - report[2] = (ctr >> 16) & 0xff; - report[3] = (ctr >> 8) & 0xff; - report[4] = ctr & 0xff; - - // Append success bytes so that response gets through U2F client code. - // Otherwise, the client will resend sign requests until timing out. - // Errors encoded in JSON-formatted report. - memcpy(report + report_len - 2, "\x90\x00", 2); + report = commander(hijack_cmd); + report_len = _frame_hijack_report(report, strlens(report), COMMANDER_REPORT_SIZE); + utils_zero(hijack_cmd, sizeof(hijack_cmd)); u2f_send_message((const uint8_t *)report, report_len); } From eefda0fd9dd6fcf425664cd037f5da74d54f43ae Mon Sep 17 00:00:00 2001 From: douglasbakkum Date: Tue, 18 Jun 2019 07:16:04 +0200 Subject: [PATCH 2/5] u2f.c: adopt v2 `_` notation for static var/func --- src/u2f_device.c | 212 +++++++++++++++++++++++------------------------ 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/src/u2f_device.c b/src/u2f_device.c index 184f9926..f56c0072 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -62,10 +62,10 @@ #endif -static uint32_t cid = 0; -volatile bool u2f_state_continue = false; -volatile uint16_t u2f_current_time_ms = 0; -const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { +static uint32_t _cid = 0; +volatile bool _state_continue = false; +volatile uint16_t _current_time_ms = 0; +const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { { /* Corresponds to U2F client challenge filled with `0xdb` */ /* Origin `https://digitalbitbox.com` */ @@ -120,21 +120,21 @@ typedef struct { } U2F_ReadBuffer; -static U2F_ReadBuffer reader; +static U2F_ReadBuffer _reader; -static uint32_t next_cid(void) +static uint32_t _next_cid(void) { do { - cid = random_uint32(0); - } while (cid == 0 || cid == U2FHID_CID_BROADCAST); - return cid; + _cid = random_uint32(0); + } while (_cid == 0 || _cid == U2FHID_CID_BROADCAST); + return _cid; } void u2f_send_message(const uint8_t *data, const uint32_t len) { - usb_reply_queue_load_msg(U2FHID_MSG, data, len, cid); + usb_reply_queue_load_msg(U2FHID_MSG, data, len, _cid); } @@ -151,7 +151,7 @@ void u2f_send_err_hid(uint32_t fcid, uint8_t err) } -static void u2f_send_error(const uint16_t err) +static void _send_error(const uint16_t err) { uint8_t data[2]; data[0] = err >> 8 & 0xFF; @@ -160,10 +160,10 @@ static void u2f_send_error(const uint16_t err) } -static void u2f_device_version(const USB_APDU *a) +static void _version(const USB_APDU *a) { if (APDU_LEN(*a) != 0) { - u2f_send_error(U2F_SW_WRONG_LENGTH); + _send_error(U2F_SW_WRONG_LENGTH); return; } @@ -172,8 +172,8 @@ static void u2f_device_version(const USB_APDU *a) } -static void u2f_keyhandle_gen(const uint8_t *appId, uint8_t *nonce, uint8_t *privkey, - uint8_t *mac) +static void _keyhandle_gen(const uint8_t *appId, uint8_t *nonce, uint8_t *privkey, + uint8_t *mac) { uint8_t hash[SHA256_DIGEST_LENGTH]; for (;;) { @@ -190,17 +190,17 @@ static void u2f_keyhandle_gen(const uint8_t *appId, uint8_t *nonce, uint8_t *pri } -static void u2f_device_register(const USB_APDU *a) +static void _register(const USB_APDU *a) { const U2F_REGISTER_REQ *req = (const U2F_REGISTER_REQ *)a->data; if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { - u2f_send_error(U2F_SW_WRONG_LENGTH); + _send_error(U2F_SW_WRONG_LENGTH); return; } if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { - u2f_send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } else { @@ -213,11 +213,11 @@ static void u2f_device_register(const USB_APDU *a) utils_zero(data, sizeof(data)); if (random_bytes(nonce, sizeof(nonce), 0) == DBB_ERROR) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } - u2f_keyhandle_gen(req->appId, nonce, privkey, mac); + _keyhandle_gen(req->appId, nonce, privkey, mac); ecc_get_public_key65(privkey, (uint8_t *)&resp->pubKey, ECC_SECP256r1); @@ -237,7 +237,7 @@ static void u2f_device_register(const USB_APDU *a) if (ecc_sign(U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, ECC_SECP256r1)) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } @@ -282,7 +282,7 @@ static uint16_t _frame_hijack_report(char *report, uint16_t len, uint16_t report return report_len; } -static void u2f_device_hijack(const U2F_AUTHENTICATE_REQ *req) +static void _hijack(const U2F_AUTHENTICATE_REQ *req) { static char hijack_cmd[COMMANDER_REPORT_SIZE] = {0}; char *report; @@ -312,7 +312,7 @@ static void u2f_device_hijack(const U2F_AUTHENTICATE_REQ *req) } -static void u2f_device_authenticate(const USB_APDU *a) +static void _authenticate(const USB_APDU *a) { uint8_t privkey[U2F_EC_KEY_SIZE], nonce[U2F_NONCE_LENGTH], mac[SHA256_DIGEST_LENGTH], sig[64], i; @@ -320,50 +320,50 @@ static void u2f_device_authenticate(const USB_APDU *a) U2F_AUTHENTICATE_SIG_STR sig_base; if (APDU_LEN(*a) < U2F_KEYHANDLE_LEN) { // actual size could vary - u2f_send_error(U2F_SW_WRONG_LENGTH); + _send_error(U2F_SW_WRONG_LENGTH); return; } for (i = 0; i < U2F_HIJACK_ORIGIN_TOTAL; i++) { // As an alternative interface, hijack the U2F AUTH key handle data field. // Slower but works in browsers for specified sites without requiring an extension. - if (MEMEQ(req->appId, U2F_HIJACK_CODE[i], U2F_APPID_SIZE)) { + if (MEMEQ(req->appId, _hijack_code[i], U2F_APPID_SIZE)) { if (!(memory_report_ext_flags() & MEM_EXT_MASK_U2F_HIJACK)) { // Abort U2F hijack commands if the U2F_hijack bit is not set (== disabled). - u2f_send_err_hid(cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_send_err_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); } else { - u2f_device_hijack(req); + _hijack(req); } return; } } if (req->keyHandleLen != U2F_KEYHANDLE_LEN) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } memcpy(nonce, req->keyHandle + sizeof(mac), sizeof(nonce)); - u2f_keyhandle_gen(req->appId, nonce, privkey, mac); + _keyhandle_gen(req->appId, nonce, privkey, mac); if (!MEMEQ(req->keyHandle, mac, SHA256_DIGEST_LENGTH)) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } if (a->p1 == U2F_AUTH_CHECK_ONLY) { - u2f_send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } if (a->p1 != U2F_AUTH_ENFORCE) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { - u2f_send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } else { @@ -385,7 +385,7 @@ static void u2f_device_authenticate(const USB_APDU *a) memcpy(sig_base.challenge, req->challenge, U2F_NONCE_LENGTH); if (ecc_sign(privkey, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, ECC_SECP256r1)) { - u2f_send_error(U2F_SW_WRONG_DATA); + _send_error(U2F_SW_WRONG_DATA); return; } @@ -400,25 +400,25 @@ static void u2f_device_authenticate(const USB_APDU *a) } -static void u2f_device_reset_state(void) +static void _reset_state(void) { - memset(&reader, 0, sizeof(reader)); - u2f_state_continue = false; + memset(&_reader, 0, sizeof(_reader)); + _state_continue = false; } -static void u2f_device_ping(const uint8_t *buf, uint32_t len) +static void _cmd_ping(const uint8_t *buf, uint32_t len) { - usb_reply_queue_load_msg(U2FHID_PING, buf, len, cid); + usb_reply_queue_load_msg(U2FHID_PING, buf, len, _cid); } -static void u2f_device_wink(const uint8_t *buf, uint32_t len) +static void _cmd_wink(const uint8_t *buf, uint32_t len) { (void)buf; if (len > 0) { - u2f_send_err_hid(cid, U2FHID_ERR_INVALID_LEN); + u2f_send_err_hid(_cid, U2FHID_ERR_INVALID_LEN); return; } @@ -426,14 +426,14 @@ static void u2f_device_wink(const uint8_t *buf, uint32_t len) USB_FRAME f; utils_zero(&f, sizeof(f)); - f.cid = cid; + f.cid = _cid; f.init.cmd = U2FHID_WINK; f.init.bcntl = 0; usb_reply_queue_add(&f); } - -static void u2f_device_sync(const uint8_t *buf, uint32_t len) +/* +static void _cmd_sync(const uint8_t *buf, uint32_t len) { // TODO - implement (void) buf; @@ -441,15 +441,15 @@ static void u2f_device_sync(const uint8_t *buf, uint32_t len) } -static void u2f_device_lock(const uint8_t *buf, uint32_t len) +static void _cmd_lock(const uint8_t *buf, uint32_t len) { // TODO - implement (void) buf; (void) len; } +*/ - -static void u2f_device_init(const USB_FRAME *in) +static void _cmd_init(const USB_FRAME *in) { const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; USB_FRAME f; @@ -468,7 +468,7 @@ static void u2f_device_init(const USB_FRAME *in) utils_zero(&resp, sizeof(resp)); memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce)); - resp.cid = in->cid == U2FHID_CID_BROADCAST ? next_cid() : in->cid; + resp.cid = in->cid == U2FHID_CID_BROADCAST ? _next_cid() : in->cid; resp.versionInterface = U2FHID_IF_VERSION; resp.versionMajor = DIGITAL_BITBOX_VERSION_MAJOR; resp.versionMinor = DIGITAL_BITBOX_VERSION_MINOR; @@ -479,104 +479,104 @@ static void u2f_device_init(const USB_FRAME *in) } -static void u2f_device_msg(const USB_APDU *a, uint32_t len) +static void _cmd_msg(const USB_APDU *a, uint32_t len) { if ((APDU_LEN(*a) + sizeof(USB_APDU)) > len) { return; } if (a->cla != 0) { - u2f_send_error(U2F_SW_CLA_NOT_SUPPORTED); + _send_error(U2F_SW_CLA_NOT_SUPPORTED); return; } switch (a->ins) { case U2F_REGISTER: - u2f_device_register(a); + _register(a); break; case U2F_AUTHENTICATE: - u2f_device_authenticate(a); + _authenticate(a); break; case U2F_VERSION: - u2f_device_version(a); + _version(a); break; default: - u2f_send_error(U2F_SW_INS_NOT_SUPPORTED); + _send_error(U2F_SW_INS_NOT_SUPPORTED); } } -static void u2f_device_cmd_cont(const USB_FRAME *f) +static void _continue(const USB_FRAME *f) { (void) f; - if ((reader.buf_ptr - reader.buf) < (signed)reader.len) { + if ((_reader.buf_ptr - _reader.buf) < (signed)_reader.len) { // Need more data return; } - u2f_state_continue = false; + _state_continue = false; - if ( (reader.cmd < U2FHID_VENDOR_FIRST) && + if ( (_reader.cmd < U2FHID_VENDOR_FIRST) && !(memory_report_ext_flags() & MEM_EXT_MASK_U2F) ) { // Abort U2F commands if the U2F bit is not set (==U2F disabled). // Vendor specific commands are passed through. - u2f_send_err_hid(cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_send_err_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); } else { // Received all data - switch (reader.cmd) { + switch (_reader.cmd) { case U2FHID_PING: - u2f_device_ping(reader.buf, reader.len); + _cmd_ping(_reader.buf, _reader.len); break; case U2FHID_MSG: - u2f_device_msg((USB_APDU *)reader.buf, reader.len); + _cmd_msg((USB_APDU *)_reader.buf, _reader.len); break; case U2FHID_WINK: - u2f_device_wink(reader.buf, reader.len); + _cmd_wink(_reader.buf, _reader.len); break; case U2FHID_HWW: { char *report; - reader.buf[MIN(reader.len, sizeof(reader.buf) - 1)] = '\0';// NULL terminate - report = commander((const char *)reader.buf); - usb_reply_queue_load_msg(U2FHID_HWW, (const uint8_t *)report, strlens(report), cid); + _reader.buf[MIN(_reader.len, sizeof(_reader.buf) - 1)] = '\0';// NULL terminate + report = commander((const char *)_reader.buf); + usb_reply_queue_load_msg(U2FHID_HWW, (const uint8_t *)report, strlens(report), _cid); break; } default: - u2f_send_err_hid(cid, U2FHID_ERR_INVALID_CMD); + u2f_send_err_hid(_cid, U2FHID_ERR_INVALID_CMD); break; } } // Finished - u2f_device_reset_state(); - cid = 0; + _reset_state(); + _cid = 0; } -static void u2f_device_cmd_init(const USB_FRAME *f) +static void _init(const USB_FRAME *f) { if (f->cid == U2FHID_CID_BROADCAST || f->cid == 0) { u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_CID); return; } - if ((unsigned)U2FHID_MSG_LEN(*f) > sizeof(reader.buf)) { + if ((unsigned)U2FHID_MSG_LEN(*f) > sizeof(_reader.buf)) { u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_LEN); return; } - memset(&reader, 0, sizeof(reader)); - reader.seq = 0; - reader.buf_ptr = reader.buf; - reader.len = U2FHID_MSG_LEN(*f); - reader.cmd = f->type; - memcpy(reader.buf_ptr, f->init.data, sizeof(f->init.data)); - reader.buf_ptr += sizeof(f->init.data); - cid = f->cid; - - u2f_current_time_ms = 0; - u2f_state_continue = true; - u2f_device_cmd_cont(f); + memset(&_reader, 0, sizeof(_reader)); + _reader.seq = 0; + _reader.buf_ptr = _reader.buf; + _reader.len = U2FHID_MSG_LEN(*f); + _reader.cmd = f->type; + memcpy(_reader.buf_ptr, f->init.data, sizeof(f->init.data)); + _reader.buf_ptr += sizeof(f->init.data); + _cid = f->cid; + + _current_time_ms = 0; + _state_continue = true; + _continue(f); } @@ -585,53 +585,53 @@ void u2f_device_run(const USB_FRAME *f) if ((f->type & U2FHID_TYPE_MASK) == U2FHID_TYPE_INIT) { if (f->init.cmd == U2FHID_INIT) { - u2f_device_init(f); - if (f->cid == cid) { - u2f_device_reset_state(); + _cmd_init(f); + if (f->cid == _cid) { + _reset_state(); } - } else if (u2f_state_continue) { - if (f->cid == cid) { + } else if (_state_continue) { + if (f->cid == _cid) { usb_reply_queue_clear(); - u2f_device_reset_state(); + _reset_state(); u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_SEQ); } else { u2f_send_err_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); } } else { - u2f_device_cmd_init(f); + _init(f); } goto exit; } if ((f->type & U2FHID_TYPE_MASK) == U2FHID_TYPE_CONT) { - if (!u2f_state_continue) { + if (!_state_continue) { goto exit; } - if (cid != f->cid) { + if (_cid != f->cid) { u2f_send_err_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); goto exit; } - if (reader.seq != f->cont.seq) { + if (_reader.seq != f->cont.seq) { usb_reply_queue_clear(); - u2f_device_reset_state(); + _reset_state(); u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_SEQ); goto exit; } // Check bounds - if ((reader.buf_ptr - reader.buf) >= (signed) reader.len - || (reader.buf_ptr + sizeof(f->cont.data) - reader.buf) > (signed) sizeof( - reader.buf)) { + if ((_reader.buf_ptr - _reader.buf) >= (signed) _reader.len + || (_reader.buf_ptr + sizeof(f->cont.data) - _reader.buf) > (signed) sizeof( + _reader.buf)) { goto exit; } - reader.seq++; - memcpy(reader.buf_ptr, f->cont.data, sizeof(f->cont.data)); - reader.buf_ptr += sizeof(f->cont.data); - u2f_device_cmd_cont(f); + _reader.seq++; + memcpy(_reader.buf_ptr, f->cont.data, sizeof(f->cont.data)); + _reader.buf_ptr += sizeof(f->cont.data); + _continue(f); } exit: @@ -641,15 +641,15 @@ void u2f_device_run(const USB_FRAME *f) void u2f_device_timeout(void) { - if (!u2f_state_continue) { + if (!_state_continue) { return; } - u2f_current_time_ms += 40; + _current_time_ms += 40; - if (u2f_current_time_ms > U2F_TIMEOUT) { - u2f_device_reset_state(); - u2f_send_err_hid(cid, U2FHID_ERR_MSG_TIMEOUT); + if (_current_time_ms > U2F_TIMEOUT) { + _reset_state(); + u2f_send_err_hid(_cid, U2FHID_ERR_MSG_TIMEOUT); usb_reply_queue_send(); } } From 3c548fdf0ea5b5c874ffa939c7ab15720e057f34 Mon Sep 17 00:00:00 2001 From: douglasbakkum Date: Wed, 19 Jun 2019 08:21:17 +0200 Subject: [PATCH 3/5] refactor naming 'send' -> 'queue' where more accurate --- src/u2f_device.c | 68 ++++++++++++++++++++++++------------------------ src/u2f_device.h | 4 +-- src/usb.c | 6 ++++- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/u2f_device.c b/src/u2f_device.c index f56c0072..2c368f7f 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -132,16 +132,15 @@ static uint32_t _next_cid(void) } -void u2f_send_message(const uint8_t *data, const uint32_t len) +void u2f_queue_message(const uint8_t *data, const uint32_t len) { usb_reply_queue_load_msg(U2FHID_MSG, data, len, _cid); } -void u2f_send_err_hid(uint32_t fcid, uint8_t err) +void u2f_queue_error_hid(uint32_t fcid, uint8_t err) { USB_FRAME f; - utils_zero(&f, sizeof(f)); f.cid = fcid; f.init.cmd = U2FHID_ERROR; @@ -151,24 +150,24 @@ void u2f_send_err_hid(uint32_t fcid, uint8_t err) } -static void _send_error(const uint16_t err) +static void _queue_error(const uint16_t err) { uint8_t data[2]; data[0] = err >> 8 & 0xFF; data[1] = err & 0xFF; - u2f_send_message(data, 2); + u2f_queue_message(data, 2); } static void _version(const USB_APDU *a) { if (APDU_LEN(*a) != 0) { - _send_error(U2F_SW_WRONG_LENGTH); + _queue_error(U2F_SW_WRONG_LENGTH); return; } static const uint8_t version_response[] = {'U', '2', 'F', '_', 'V', '2', 0x90, 0x00}; - u2f_send_message(version_response, sizeof(version_response)); + u2f_queue_message(version_response, sizeof(version_response)); } @@ -195,12 +194,12 @@ static void _register(const USB_APDU *a) const U2F_REGISTER_REQ *req = (const U2F_REGISTER_REQ *)a->data; if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { - _send_error(U2F_SW_WRONG_LENGTH); + _queue_error(U2F_SW_WRONG_LENGTH); return; } if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { - _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _queue_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } else { @@ -213,7 +212,7 @@ static void _register(const USB_APDU *a) utils_zero(data, sizeof(data)); if (random_bytes(nonce, sizeof(nonce), 0) == DBB_ERROR) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } @@ -237,7 +236,7 @@ static void _register(const USB_APDU *a) if (ecc_sign(U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, ECC_SECP256r1)) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } @@ -253,7 +252,7 @@ static void _register(const USB_APDU *a) 1 /* keyhandleLen */ + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2; - u2f_send_message(data, len); + u2f_queue_message(data, len); } } @@ -282,6 +281,7 @@ static uint16_t _frame_hijack_report(char *report, uint16_t len, uint16_t report return report_len; } + static void _hijack(const U2F_AUTHENTICATE_REQ *req) { static char hijack_cmd[COMMANDER_REPORT_SIZE] = {0}; @@ -320,7 +320,7 @@ static void _authenticate(const USB_APDU *a) U2F_AUTHENTICATE_SIG_STR sig_base; if (APDU_LEN(*a) < U2F_KEYHANDLE_LEN) { // actual size could vary - _send_error(U2F_SW_WRONG_LENGTH); + _queue_error(U2F_SW_WRONG_LENGTH); return; } @@ -330,7 +330,7 @@ static void _authenticate(const USB_APDU *a) if (MEMEQ(req->appId, _hijack_code[i], U2F_APPID_SIZE)) { if (!(memory_report_ext_flags() & MEM_EXT_MASK_U2F_HIJACK)) { // Abort U2F hijack commands if the U2F_hijack bit is not set (== disabled). - u2f_send_err_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_queue_error_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); } else { _hijack(req); } @@ -339,7 +339,7 @@ static void _authenticate(const USB_APDU *a) } if (req->keyHandleLen != U2F_KEYHANDLE_LEN) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } @@ -348,22 +348,22 @@ static void _authenticate(const USB_APDU *a) _keyhandle_gen(req->appId, nonce, privkey, mac); if (!MEMEQ(req->keyHandle, mac, SHA256_DIGEST_LENGTH)) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } if (a->p1 == U2F_AUTH_CHECK_ONLY) { - _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _queue_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } if (a->p1 != U2F_AUTH_ENFORCE) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } if (touch_button_press(TOUCH_TIMEOUT) != DBB_TOUCHED) { - _send_error(U2F_SW_CONDITIONS_NOT_SATISFIED); + _queue_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } else { @@ -385,7 +385,7 @@ static void _authenticate(const USB_APDU *a) memcpy(sig_base.challenge, req->challenge, U2F_NONCE_LENGTH); if (ecc_sign(privkey, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, ECC_SECP256r1)) { - _send_error(U2F_SW_WRONG_DATA); + _queue_error(U2F_SW_WRONG_DATA); return; } @@ -395,7 +395,7 @@ static void _authenticate(const USB_APDU *a) memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len, "\x90\x00", 2); - u2f_send_message(buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); + u2f_queue_message(buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); } } @@ -418,7 +418,7 @@ static void _cmd_wink(const uint8_t *buf, uint32_t len) (void)buf; if (len > 0) { - u2f_send_err_hid(_cid, U2FHID_ERR_INVALID_LEN); + u2f_queue_error_hid(_cid, U2FHID_ERR_INVALID_LEN); return; } @@ -456,7 +456,7 @@ static void _cmd_init(const USB_FRAME *in) U2FHID_INIT_RESP resp; if (in->cid == 0) { - u2f_send_err_hid(in->cid, U2FHID_ERR_INVALID_CID); + u2f_queue_error_hid(in->cid, U2FHID_ERR_INVALID_CID); return; } @@ -486,7 +486,7 @@ static void _cmd_msg(const USB_APDU *a, uint32_t len) } if (a->cla != 0) { - _send_error(U2F_SW_CLA_NOT_SUPPORTED); + _queue_error(U2F_SW_CLA_NOT_SUPPORTED); return; } @@ -501,7 +501,7 @@ static void _cmd_msg(const USB_APDU *a, uint32_t len) _version(a); break; default: - _send_error(U2F_SW_INS_NOT_SUPPORTED); + _queue_error(U2F_SW_INS_NOT_SUPPORTED); } } @@ -521,7 +521,7 @@ static void _continue(const USB_FRAME *f) !(memory_report_ext_flags() & MEM_EXT_MASK_U2F) ) { // Abort U2F commands if the U2F bit is not set (==U2F disabled). // Vendor specific commands are passed through. - u2f_send_err_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_queue_error_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); } else { // Received all data switch (_reader.cmd) { @@ -542,7 +542,7 @@ static void _continue(const USB_FRAME *f) break; } default: - u2f_send_err_hid(_cid, U2FHID_ERR_INVALID_CMD); + u2f_queue_error_hid(_cid, U2FHID_ERR_INVALID_CMD); break; } } @@ -556,12 +556,12 @@ static void _continue(const USB_FRAME *f) static void _init(const USB_FRAME *f) { if (f->cid == U2FHID_CID_BROADCAST || f->cid == 0) { - u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_CID); + u2f_queue_error_hid(f->cid, U2FHID_ERR_INVALID_CID); return; } if ((unsigned)U2FHID_MSG_LEN(*f) > sizeof(_reader.buf)) { - u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_LEN); + u2f_queue_error_hid(f->cid, U2FHID_ERR_INVALID_LEN); return; } @@ -593,9 +593,9 @@ void u2f_device_run(const USB_FRAME *f) if (f->cid == _cid) { usb_reply_queue_clear(); _reset_state(); - u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_SEQ); + u2f_queue_error_hid(f->cid, U2FHID_ERR_INVALID_SEQ); } else { - u2f_send_err_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_queue_error_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); } } else { _init(f); @@ -610,14 +610,14 @@ void u2f_device_run(const USB_FRAME *f) } if (_cid != f->cid) { - u2f_send_err_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); + u2f_queue_error_hid(f->cid, U2FHID_ERR_CHANNEL_BUSY); goto exit; } if (_reader.seq != f->cont.seq) { usb_reply_queue_clear(); _reset_state(); - u2f_send_err_hid(f->cid, U2FHID_ERR_INVALID_SEQ); + u2f_queue_error_hid(f->cid, U2FHID_ERR_INVALID_SEQ); goto exit; } @@ -649,7 +649,7 @@ void u2f_device_timeout(void) if (_current_time_ms > U2F_TIMEOUT) { _reset_state(); - u2f_send_err_hid(_cid, U2FHID_ERR_MSG_TIMEOUT); + u2f_queue_error_hid(_cid, U2FHID_ERR_MSG_TIMEOUT); usb_reply_queue_send(); } } diff --git a/src/u2f_device.h b/src/u2f_device.h index 39aca07d..24beff01 100644 --- a/src/u2f_device.h +++ b/src/u2f_device.h @@ -41,8 +41,8 @@ extern const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE]; -void u2f_send_message(const uint8_t *data, const uint32_t len); -void u2f_send_err_hid(uint32_t fcid, uint8_t err); +void u2f_queue_message(const uint8_t *data, const uint32_t len); +void u2f_queue_error_hid(uint32_t fcid, uint8_t err); void u2f_device_run(const USB_FRAME *f); void u2f_device_timeout(void); diff --git a/src/usb.c b/src/usb.c index 31248d7b..f4310021 100644 --- a/src/usb.c +++ b/src/usb.c @@ -71,7 +71,7 @@ void usb_u2f_report(const unsigned char *command) } if (c->type >= U2FHID_VENDOR_FIRST) { // Disable vendor defined commands in u2f interface - u2f_send_err_hid(c->cid, U2FHID_ERR_INVALID_CMD); + u2f_queue_error_hid(c->cid, U2FHID_ERR_INVALID_CMD); usb_reply_queue_send(); return; } @@ -79,6 +79,10 @@ void usb_u2f_report(const unsigned char *command) } +/* + * Callback passed to the low level driver. + * Called after a report is sent to the host computer. + */ void usb_report_sent(void) { usb_reply_queue_send(); From 269b5321ac92062a7a7877d7c56c8489a8ed7d2b Mon Sep 17 00:00:00 2001 From: douglasbakkum Date: Thu, 20 Jun 2019 08:03:21 +0200 Subject: [PATCH 4/5] async command processing for hijack mode --- src/u2f_device.c | 78 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/src/u2f_device.c b/src/u2f_device.c index 2c368f7f..01cfdce1 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -94,6 +94,15 @@ const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { } }; +typedef enum HIJACK_STATE { + // Do not change the order! + // Order affects third party integrations that make use of the hijack mode + HIJACK_STATE_RESPONSE_READY, + HIJACK_STATE_PROCESSING_COMMAND, + HIJACK_STATE_INCOMPLETE_COMMAND, + HIJACK_STATE_IDLE, +} HIJACK_STATE; + typedef struct { uint8_t reserved; uint8_t appId[U2F_APPID_SIZE]; @@ -284,31 +293,64 @@ static uint16_t _frame_hijack_report(char *report, uint16_t len, uint16_t report static void _hijack(const U2F_AUTHENTICATE_REQ *req) { - static char hijack_cmd[COMMANDER_REPORT_SIZE] = {0}; - char *report; - int report_len; + static HIJACK_STATE state = HIJACK_STATE_IDLE; + static char hijack_io_buffer[COMMANDER_REPORT_SIZE] = {0}; + char byte_report[U2F_FRAME_SIZE + 1] = {0}; + uint16_t report_len; size_t kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2)); uint8_t tot = req->keyHandle[0]; uint8_t cnt = req->keyHandle[1]; size_t idx = cnt * (U2F_MAX_KH_SIZE - 2); - if (idx + kh_len < sizeof(hijack_cmd)) { - memcpy(hijack_cmd + idx, req->keyHandle + 2, kh_len); - hijack_cmd[idx + kh_len] = '\0'; - } + switch (state) { + case HIJACK_STATE_PROCESSING_COMMAND: + // Previous command is still processing, for example, waiting for a touch button press + byte_report[0] = state; + report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report)); + u2f_queue_message((const uint8_t *)byte_report, report_len); + break; + case HIJACK_STATE_RESPONSE_READY: + // Previous command finished processing; return the response + report_len = _frame_hijack_report(hijack_io_buffer, strlens(hijack_io_buffer), + COMMANDER_REPORT_SIZE); + u2f_queue_message((const uint8_t *)hijack_io_buffer, report_len); + utils_zero(hijack_io_buffer, sizeof(hijack_io_buffer)); + state = HIJACK_STATE_IDLE; + break; + case HIJACK_STATE_INCOMPLETE_COMMAND: + case HIJACK_STATE_IDLE: { + if (idx + kh_len < sizeof(hijack_io_buffer)) { + // Fill the buffer with the command to process + snprintf(hijack_io_buffer + idx, sizeof(hijack_io_buffer) - idx, "%.*s", + kh_len, req->keyHandle + 2); + } - if (cnt + 1 < tot) { - // Need more data. Acknowledge by returning a 1-byte empty report. - char empty_report[U2F_FRAME_SIZE + 1] = {0}; - report_len = _frame_hijack_report(empty_report, 1, sizeof(empty_report)); - u2f_send_message((const uint8_t *)empty_report, report_len); - return; - } + if (cnt + 1 < tot) { + // Command string is incomplete; acknowledge receipt of USB frame + state = HIJACK_STATE_INCOMPLETE_COMMAND; + byte_report[0] = state; + report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report)); + u2f_queue_message((const uint8_t *)byte_report, report_len); + break; + } - report = commander(hijack_cmd); - report_len = _frame_hijack_report(report, strlens(report), COMMANDER_REPORT_SIZE); - utils_zero(hijack_cmd, sizeof(hijack_cmd)); - u2f_send_message((const uint8_t *)report, report_len); + // Acknowledge receipt of command + state = HIJACK_STATE_PROCESSING_COMMAND; + byte_report[0] = state; + report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report)); + u2f_queue_message((const uint8_t *)byte_report, report_len); + usb_reply_queue_send(); + + // Process the command and fill the buffer with the response + char *report = commander(hijack_io_buffer); + utils_zero(hijack_io_buffer, sizeof(hijack_io_buffer)); + snprintf(hijack_io_buffer, sizeof(hijack_io_buffer), "%s", report); + state = HIJACK_STATE_RESPONSE_READY; + break; + } + default: + break; + } } From 83ec9d3fbd821806aae20cd718b09914824b2ded Mon Sep 17 00:00:00 2001 From: douglasbakkum Date: Thu, 27 Jun 2019 14:02:01 +0200 Subject: [PATCH 5/5] update unit tests --- src/u2f_device.c | 16 +++-------- src/u2f_device.h | 9 +++++++ tests/api.h | 69 ++++++++++++++++++++++++++++++----------------- tests/tests_api.c | 10 +++++-- 4 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/u2f_device.c b/src/u2f_device.c index 01cfdce1..bdd97bb7 100644 --- a/src/u2f_device.c +++ b/src/u2f_device.c @@ -25,6 +25,7 @@ */ +#include #include #include "bip32.h" @@ -65,7 +66,7 @@ static uint32_t _cid = 0; volatile bool _state_continue = false; volatile uint16_t _current_time_ms = 0; -const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { +const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { { /* Corresponds to U2F client challenge filled with `0xdb` */ /* Origin `https://digitalbitbox.com` */ @@ -94,15 +95,6 @@ const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = { } }; -typedef enum HIJACK_STATE { - // Do not change the order! - // Order affects third party integrations that make use of the hijack mode - HIJACK_STATE_RESPONSE_READY, - HIJACK_STATE_PROCESSING_COMMAND, - HIJACK_STATE_INCOMPLETE_COMMAND, - HIJACK_STATE_IDLE, -} HIJACK_STATE; - typedef struct { uint8_t reserved; uint8_t appId[U2F_APPID_SIZE]; @@ -297,7 +289,7 @@ static void _hijack(const U2F_AUTHENTICATE_REQ *req) static char hijack_io_buffer[COMMANDER_REPORT_SIZE] = {0}; char byte_report[U2F_FRAME_SIZE + 1] = {0}; uint16_t report_len; - size_t kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2)); + int kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2)); uint8_t tot = req->keyHandle[0]; uint8_t cnt = req->keyHandle[1]; size_t idx = cnt * (U2F_MAX_KH_SIZE - 2); @@ -369,7 +361,7 @@ static void _authenticate(const USB_APDU *a) for (i = 0; i < U2F_HIJACK_ORIGIN_TOTAL; i++) { // As an alternative interface, hijack the U2F AUTH key handle data field. // Slower but works in browsers for specified sites without requiring an extension. - if (MEMEQ(req->appId, _hijack_code[i], U2F_APPID_SIZE)) { + if (MEMEQ(req->appId, U2F_HIJACK_CODE[i], U2F_APPID_SIZE)) { if (!(memory_report_ext_flags() & MEM_EXT_MASK_U2F_HIJACK)) { // Abort U2F hijack commands if the U2F_hijack bit is not set (== disabled). u2f_queue_error_hid(_cid, U2FHID_ERR_CHANNEL_BUSY); diff --git a/src/u2f_device.h b/src/u2f_device.h index 24beff01..df846ef7 100644 --- a/src/u2f_device.h +++ b/src/u2f_device.h @@ -40,6 +40,15 @@ extern const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE]; +typedef enum HIJACK_STATE { + // Do not change the order! + // Order affects third party integrations that make use of the hijack mode + HIJACK_STATE_RESPONSE_READY, + HIJACK_STATE_PROCESSING_COMMAND, + HIJACK_STATE_INCOMPLETE_COMMAND, + HIJACK_STATE_IDLE, +} HIJACK_STATE; + void u2f_queue_message(const uint8_t *data, const uint32_t len); void u2f_queue_error_hid(uint32_t fcid, uint8_t err); diff --git a/tests/api.h b/tests/api.h index eda78f2f..3d13b136 100644 --- a/tests/api.h +++ b/tests/api.h @@ -326,31 +326,6 @@ static int api_hid_init(void) #endif -static void api_hid_read(uint8_t *key) -{ - int res; - int u2fhid_cmd = TEST_U2FAUTH_HIJACK ? U2FHID_MSG : U2FHID_HWW; - memset(HID_REPORT, 0, HID_REPORT_SIZE); - res = api_hid_read_frames(HWW_CID, u2fhid_cmd, HID_REPORT, HID_REPORT_SIZE); - if (res < 0) { - strcpy(decrypted_report, "/* " API_READ_ERROR " */"); - return; - } - if (TEST_U2FAUTH_HIJACK) { - // If the hijack command was sent in chunks, the first chunks return empty frames. - // The last chunk holds the JSON response. So poll until get a non-empty frame. - // First 5 bytes are the frame header. - // Set the appended U2F success byte 0x90 to zero. Otherwise cannot decrypt. - char *r = (char *)(HID_REPORT + 5); - r[strlens(r) - 1] = 0; - strlens(r) ? api_decrypt_report(r, key) : api_hid_read(key); - } else { - api_decrypt_report((char *)HID_REPORT, key); - } - //printf("received: >>%s<<\n", api_read_decrypted_report()); -} - - static void api_hid_send_len(const char *cmd, int cmdlen) { if (TEST_U2FAUTH_HIJACK) { @@ -401,6 +376,50 @@ static void api_hid_send_encrypt(const char *cmd, uint8_t *key) } +static void api_hid_read(uint8_t *key) +{ + int res; + int u2fhid_cmd = TEST_U2FAUTH_HIJACK ? U2FHID_MSG : U2FHID_HWW; + memset(HID_REPORT, 0, HID_REPORT_SIZE); + res = api_hid_read_frames(HWW_CID, u2fhid_cmd, HID_REPORT, HID_REPORT_SIZE); + if (res < 0) { + strcpy(decrypted_report, "/* " API_READ_ERROR " */"); + return; + } + if (TEST_U2FAUTH_HIJACK) { + // If the hijack command was sent in multiple chunks, the first chunks are replied + // with a single-byte (framed) having the value HIJACK_STATE_INCOMPLETE_COMMAND. + // + // After receiving the all chunks, the firware replies with a single-byte + // HIJACK_STATE_PROCESSING_COMMAND. + // + // The client can poll the firmware for the JSON response by sending a single-byte + // (framed) having any value. If the firmware is busy, for example waiting for user touch + // button press, the firmware will reply with a single-byte HIJACK_STATE_PROCESSING_COMMAND. + // If the firmware finished processing, the reply will contain the JSON response. + // + // The first 5 bytes are the frame header. The last two bytes contain the U2F status, + // which should be the success bytes \x90\x00 in order for the U2F hijack approach + // to work in browsers. + char *r = (char *)(HID_REPORT + 1 + U2F_CTR_SIZE); + r[strlens(r) - 1] = 0; + if (strlens(r) == 1) { + if (r[0] == HIJACK_STATE_PROCESSING_COMMAND) { + api_hid_send(" "); + } + api_hid_read(key); + } else if (strlens(r) > 1) { + api_decrypt_report(r, key); + } else { + strcpy(decrypted_report, "/* " API_READ_ERROR " */"); + } + } else { + api_decrypt_report((char *)HID_REPORT, key); + } + //printf("received: >>%s<<\n", api_read_decrypted_report()); +} + + static void api_send_cmd(const char *command, uint8_t *key) { memset(command_sent, 0, sizeof(command_sent)); diff --git a/tests/tests_api.c b/tests/tests_api.c index 6b57a784..3255af00 100644 --- a/tests/tests_api.c +++ b/tests/tests_api.c @@ -1059,6 +1059,8 @@ static void tests_u2f(void) api_format_send_cmd(cmd_str(CMD_backup), "{\"erase\":\"u2f_test_0.pdf\"}", KEY_STANDARD); + ASSERT_SUCCESS; + // U2F command runs api_hid_send_frame(&f); api_hid_read_frame(&r); @@ -1066,9 +1068,11 @@ static void tests_u2f(void) u_assert_int_eq(r.init.cmd, U2FHID_WINK); u_assert_int_eq(r.init.bcntl, 0); - // Disable U2F + // Disable U2F - Must be done through HWW interface. + TEST_U2FAUTH_HIJACK = 0; api_format_send_cmd(cmd_str(CMD_feature_set), "{\"U2F\":false}", KEY_STANDARD); ASSERT_SUCCESS; + TEST_U2FAUTH_HIJACK = test_u2fauth_hijack; api_format_send_cmd(cmd_str(CMD_device), attr_str(ATTR_info), KEY_STANDARD); if (TEST_U2FAUTH_HIJACK) { @@ -1097,9 +1101,11 @@ static void tests_u2f(void) ASSERT_REPORT_HAS("\"U2F_hijack\":true"); - // Disable U2F hijack + // Disable U2F - Must be done through HWW interface. + TEST_U2FAUTH_HIJACK = 0; api_format_send_cmd(cmd_str(CMD_feature_set), "{\"U2F_hijack\":false}", KEY_STANDARD); ASSERT_SUCCESS; + TEST_U2FAUTH_HIJACK = test_u2fauth_hijack; api_format_send_cmd(cmd_str(CMD_device), attr_str(ATTR_info), KEY_STANDARD); if (TEST_U2FAUTH_HIJACK) {