Skip to content

Commit 83ec9d3

Browse files
committed
update unit tests
1 parent 269b532 commit 83ec9d3

File tree

4 files changed

+65
-39
lines changed

4 files changed

+65
-39
lines changed

src/u2f_device.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727

28+
#include <stdio.h>
2829
#include <string.h>
2930

3031
#include "bip32.h"
@@ -65,7 +66,7 @@
6566
static uint32_t _cid = 0;
6667
volatile bool _state_continue = false;
6768
volatile uint16_t _current_time_ms = 0;
68-
const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = {
69+
const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = {
6970
{
7071
/* Corresponds to U2F client challenge filled with `0xdb` */
7172
/* Origin `https://digitalbitbox.com` */
@@ -94,15 +95,6 @@ const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = {
9495
}
9596
};
9697

97-
typedef enum HIJACK_STATE {
98-
// Do not change the order!
99-
// Order affects third party integrations that make use of the hijack mode
100-
HIJACK_STATE_RESPONSE_READY,
101-
HIJACK_STATE_PROCESSING_COMMAND,
102-
HIJACK_STATE_INCOMPLETE_COMMAND,
103-
HIJACK_STATE_IDLE,
104-
} HIJACK_STATE;
105-
10698
typedef struct {
10799
uint8_t reserved;
108100
uint8_t appId[U2F_APPID_SIZE];
@@ -297,7 +289,7 @@ static void _hijack(const U2F_AUTHENTICATE_REQ *req)
297289
static char hijack_io_buffer[COMMANDER_REPORT_SIZE] = {0};
298290
char byte_report[U2F_FRAME_SIZE + 1] = {0};
299291
uint16_t report_len;
300-
size_t kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2));
292+
int kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2));
301293
uint8_t tot = req->keyHandle[0];
302294
uint8_t cnt = req->keyHandle[1];
303295
size_t idx = cnt * (U2F_MAX_KH_SIZE - 2);
@@ -369,7 +361,7 @@ static void _authenticate(const USB_APDU *a)
369361
for (i = 0; i < U2F_HIJACK_ORIGIN_TOTAL; i++) {
370362
// As an alternative interface, hijack the U2F AUTH key handle data field.
371363
// Slower but works in browsers for specified sites without requiring an extension.
372-
if (MEMEQ(req->appId, _hijack_code[i], U2F_APPID_SIZE)) {
364+
if (MEMEQ(req->appId, U2F_HIJACK_CODE[i], U2F_APPID_SIZE)) {
373365
if (!(memory_report_ext_flags() & MEM_EXT_MASK_U2F_HIJACK)) {
374366
// Abort U2F hijack commands if the U2F_hijack bit is not set (== disabled).
375367
u2f_queue_error_hid(_cid, U2FHID_ERR_CHANNEL_BUSY);

src/u2f_device.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@
4040

4141
extern const uint8_t U2F_HIJACK_CODE[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE];
4242

43+
typedef enum HIJACK_STATE {
44+
// Do not change the order!
45+
// Order affects third party integrations that make use of the hijack mode
46+
HIJACK_STATE_RESPONSE_READY,
47+
HIJACK_STATE_PROCESSING_COMMAND,
48+
HIJACK_STATE_INCOMPLETE_COMMAND,
49+
HIJACK_STATE_IDLE,
50+
} HIJACK_STATE;
51+
4352

4453
void u2f_queue_message(const uint8_t *data, const uint32_t len);
4554
void u2f_queue_error_hid(uint32_t fcid, uint8_t err);

tests/api.h

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -326,31 +326,6 @@ static int api_hid_init(void)
326326
#endif
327327

328328

329-
static void api_hid_read(uint8_t *key)
330-
{
331-
int res;
332-
int u2fhid_cmd = TEST_U2FAUTH_HIJACK ? U2FHID_MSG : U2FHID_HWW;
333-
memset(HID_REPORT, 0, HID_REPORT_SIZE);
334-
res = api_hid_read_frames(HWW_CID, u2fhid_cmd, HID_REPORT, HID_REPORT_SIZE);
335-
if (res < 0) {
336-
strcpy(decrypted_report, "/* " API_READ_ERROR " */");
337-
return;
338-
}
339-
if (TEST_U2FAUTH_HIJACK) {
340-
// If the hijack command was sent in chunks, the first chunks return empty frames.
341-
// The last chunk holds the JSON response. So poll until get a non-empty frame.
342-
// First 5 bytes are the frame header.
343-
// Set the appended U2F success byte 0x90 to zero. Otherwise cannot decrypt.
344-
char *r = (char *)(HID_REPORT + 5);
345-
r[strlens(r) - 1] = 0;
346-
strlens(r) ? api_decrypt_report(r, key) : api_hid_read(key);
347-
} else {
348-
api_decrypt_report((char *)HID_REPORT, key);
349-
}
350-
//printf("received: >>%s<<\n", api_read_decrypted_report());
351-
}
352-
353-
354329
static void api_hid_send_len(const char *cmd, int cmdlen)
355330
{
356331
if (TEST_U2FAUTH_HIJACK) {
@@ -401,6 +376,50 @@ static void api_hid_send_encrypt(const char *cmd, uint8_t *key)
401376
}
402377

403378

379+
static void api_hid_read(uint8_t *key)
380+
{
381+
int res;
382+
int u2fhid_cmd = TEST_U2FAUTH_HIJACK ? U2FHID_MSG : U2FHID_HWW;
383+
memset(HID_REPORT, 0, HID_REPORT_SIZE);
384+
res = api_hid_read_frames(HWW_CID, u2fhid_cmd, HID_REPORT, HID_REPORT_SIZE);
385+
if (res < 0) {
386+
strcpy(decrypted_report, "/* " API_READ_ERROR " */");
387+
return;
388+
}
389+
if (TEST_U2FAUTH_HIJACK) {
390+
// If the hijack command was sent in multiple chunks, the first chunks are replied
391+
// with a single-byte (framed) having the value HIJACK_STATE_INCOMPLETE_COMMAND.
392+
//
393+
// After receiving the all chunks, the firware replies with a single-byte
394+
// HIJACK_STATE_PROCESSING_COMMAND.
395+
//
396+
// The client can poll the firmware for the JSON response by sending a single-byte
397+
// (framed) having any value. If the firmware is busy, for example waiting for user touch
398+
// button press, the firmware will reply with a single-byte HIJACK_STATE_PROCESSING_COMMAND.
399+
// If the firmware finished processing, the reply will contain the JSON response.
400+
//
401+
// The first 5 bytes are the frame header. The last two bytes contain the U2F status,
402+
// which should be the success bytes \x90\x00 in order for the U2F hijack approach
403+
// to work in browsers.
404+
char *r = (char *)(HID_REPORT + 1 + U2F_CTR_SIZE);
405+
r[strlens(r) - 1] = 0;
406+
if (strlens(r) == 1) {
407+
if (r[0] == HIJACK_STATE_PROCESSING_COMMAND) {
408+
api_hid_send(" ");
409+
}
410+
api_hid_read(key);
411+
} else if (strlens(r) > 1) {
412+
api_decrypt_report(r, key);
413+
} else {
414+
strcpy(decrypted_report, "/* " API_READ_ERROR " */");
415+
}
416+
} else {
417+
api_decrypt_report((char *)HID_REPORT, key);
418+
}
419+
//printf("received: >>%s<<\n", api_read_decrypted_report());
420+
}
421+
422+
404423
static void api_send_cmd(const char *command, uint8_t *key)
405424
{
406425
memset(command_sent, 0, sizeof(command_sent));

tests/tests_api.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,16 +1059,20 @@ static void tests_u2f(void)
10591059
api_format_send_cmd(cmd_str(CMD_backup),
10601060
"{\"erase\":\"u2f_test_0.pdf\"}",
10611061
KEY_STANDARD);
1062+
ASSERT_SUCCESS;
1063+
10621064
// U2F command runs
10631065
api_hid_send_frame(&f);
10641066
api_hid_read_frame(&r);
10651067
u_assert_int_eq(r.cid, cid);
10661068
u_assert_int_eq(r.init.cmd, U2FHID_WINK);
10671069
u_assert_int_eq(r.init.bcntl, 0);
10681070

1069-
// Disable U2F
1071+
// Disable U2F - Must be done through HWW interface.
1072+
TEST_U2FAUTH_HIJACK = 0;
10701073
api_format_send_cmd(cmd_str(CMD_feature_set), "{\"U2F\":false}", KEY_STANDARD);
10711074
ASSERT_SUCCESS;
1075+
TEST_U2FAUTH_HIJACK = test_u2fauth_hijack;
10721076

10731077
api_format_send_cmd(cmd_str(CMD_device), attr_str(ATTR_info), KEY_STANDARD);
10741078
if (TEST_U2FAUTH_HIJACK) {
@@ -1097,9 +1101,11 @@ static void tests_u2f(void)
10971101
ASSERT_REPORT_HAS("\"U2F_hijack\":true");
10981102

10991103

1100-
// Disable U2F hijack
1104+
// Disable U2F - Must be done through HWW interface.
1105+
TEST_U2FAUTH_HIJACK = 0;
11011106
api_format_send_cmd(cmd_str(CMD_feature_set), "{\"U2F_hijack\":false}", KEY_STANDARD);
11021107
ASSERT_SUCCESS;
1108+
TEST_U2FAUTH_HIJACK = test_u2fauth_hijack;
11031109

11041110
api_format_send_cmd(cmd_str(CMD_device), attr_str(ATTR_info), KEY_STANDARD);
11051111
if (TEST_U2FAUTH_HIJACK) {

0 commit comments

Comments
 (0)