Skip to content

Commit

Permalink
update unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasbakkum committed Jun 28, 2019
1 parent 269b532 commit 83ec9d3
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 39 deletions.
16 changes: 4 additions & 12 deletions src/u2f_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/


#include <stdio.h>
#include <string.h>

#include "bip32.h"
Expand Down Expand Up @@ -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` */
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions src/u2f_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
69 changes: 44 additions & 25 deletions tests/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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));
Expand Down
10 changes: 8 additions & 2 deletions tests/tests_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1059,16 +1059,20 @@ 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);
u_assert_int_eq(r.cid, cid);
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) {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 83ec9d3

Please sign in to comment.