Skip to content

Commit 269b532

Browse files
committed
async command processing for hijack mode
1 parent 3c548fd commit 269b532

File tree

1 file changed

+60
-18
lines changed

1 file changed

+60
-18
lines changed

src/u2f_device.c

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ const uint8_t _hijack_code[U2F_HIJACK_ORIGIN_TOTAL][U2F_APPID_SIZE] = {
9494
}
9595
};
9696

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+
97106
typedef struct {
98107
uint8_t reserved;
99108
uint8_t appId[U2F_APPID_SIZE];
@@ -284,31 +293,64 @@ static uint16_t _frame_hijack_report(char *report, uint16_t len, uint16_t report
284293

285294
static void _hijack(const U2F_AUTHENTICATE_REQ *req)
286295
{
287-
static char hijack_cmd[COMMANDER_REPORT_SIZE] = {0};
288-
char *report;
289-
int report_len;
296+
static HIJACK_STATE state = HIJACK_STATE_IDLE;
297+
static char hijack_io_buffer[COMMANDER_REPORT_SIZE] = {0};
298+
char byte_report[U2F_FRAME_SIZE + 1] = {0};
299+
uint16_t report_len;
290300
size_t kh_len = MIN(U2F_MAX_KH_SIZE - 2, strlens((const char *)req->keyHandle + 2));
291301
uint8_t tot = req->keyHandle[0];
292302
uint8_t cnt = req->keyHandle[1];
293303
size_t idx = cnt * (U2F_MAX_KH_SIZE - 2);
294304

295-
if (idx + kh_len < sizeof(hijack_cmd)) {
296-
memcpy(hijack_cmd + idx, req->keyHandle + 2, kh_len);
297-
hijack_cmd[idx + kh_len] = '\0';
298-
}
305+
switch (state) {
306+
case HIJACK_STATE_PROCESSING_COMMAND:
307+
// Previous command is still processing, for example, waiting for a touch button press
308+
byte_report[0] = state;
309+
report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report));
310+
u2f_queue_message((const uint8_t *)byte_report, report_len);
311+
break;
312+
case HIJACK_STATE_RESPONSE_READY:
313+
// Previous command finished processing; return the response
314+
report_len = _frame_hijack_report(hijack_io_buffer, strlens(hijack_io_buffer),
315+
COMMANDER_REPORT_SIZE);
316+
u2f_queue_message((const uint8_t *)hijack_io_buffer, report_len);
317+
utils_zero(hijack_io_buffer, sizeof(hijack_io_buffer));
318+
state = HIJACK_STATE_IDLE;
319+
break;
320+
case HIJACK_STATE_INCOMPLETE_COMMAND:
321+
case HIJACK_STATE_IDLE: {
322+
if (idx + kh_len < sizeof(hijack_io_buffer)) {
323+
// Fill the buffer with the command to process
324+
snprintf(hijack_io_buffer + idx, sizeof(hijack_io_buffer) - idx, "%.*s",
325+
kh_len, req->keyHandle + 2);
326+
}
299327

300-
if (cnt + 1 < tot) {
301-
// Need more data. Acknowledge by returning a 1-byte empty report.
302-
char empty_report[U2F_FRAME_SIZE + 1] = {0};
303-
report_len = _frame_hijack_report(empty_report, 1, sizeof(empty_report));
304-
u2f_send_message((const uint8_t *)empty_report, report_len);
305-
return;
306-
}
328+
if (cnt + 1 < tot) {
329+
// Command string is incomplete; acknowledge receipt of USB frame
330+
state = HIJACK_STATE_INCOMPLETE_COMMAND;
331+
byte_report[0] = state;
332+
report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report));
333+
u2f_queue_message((const uint8_t *)byte_report, report_len);
334+
break;
335+
}
307336

308-
report = commander(hijack_cmd);
309-
report_len = _frame_hijack_report(report, strlens(report), COMMANDER_REPORT_SIZE);
310-
utils_zero(hijack_cmd, sizeof(hijack_cmd));
311-
u2f_send_message((const uint8_t *)report, report_len);
337+
// Acknowledge receipt of command
338+
state = HIJACK_STATE_PROCESSING_COMMAND;
339+
byte_report[0] = state;
340+
report_len = _frame_hijack_report(byte_report, 1, sizeof(byte_report));
341+
u2f_queue_message((const uint8_t *)byte_report, report_len);
342+
usb_reply_queue_send();
343+
344+
// Process the command and fill the buffer with the response
345+
char *report = commander(hijack_io_buffer);
346+
utils_zero(hijack_io_buffer, sizeof(hijack_io_buffer));
347+
snprintf(hijack_io_buffer, sizeof(hijack_io_buffer), "%s", report);
348+
state = HIJACK_STATE_RESPONSE_READY;
349+
break;
350+
}
351+
default:
352+
break;
353+
}
312354
}
313355

314356

0 commit comments

Comments
 (0)