diff --git a/firmware/u2f.c b/firmware/u2f.c
index 33a5f1c1d0..18ef2797b1 100644
--- a/firmware/u2f.c
+++ b/firmware/u2f.c
@@ -42,7 +42,7 @@
// About 1/2 Second according to values used in protect.c
#define U2F_TIMEOUT (800000/2)
-#define U2F_OUT_PKT_BUFFER_LEN 128
+#define U2F_OUT_PKT_BUFFER_LEN 130
// Initialise without a cid
static uint32_t cid = 0;
@@ -100,8 +100,13 @@ uint32_t next_cid(void)
return cid;
}
+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-hid-protocol-v1.2-ps-20170411.html#message--and-packet-structure
+// states the following:
+// With a packet size of 64 bytes (max for full-speed devices), this means that
+// the maximum message payload length is 64 - 7 + 128 * (64 - 5) = 7609 bytes.
+#define U2F_MAXIMUM_PAYLOAD_LENGTH 7609
typedef struct {
- uint8_t buf[57+127*59];
+ uint8_t buf[U2F_MAXIMUM_PAYLOAD_LENGTH];
uint8_t *buf_ptr;
uint32_t len;
uint8_t seq;
@@ -282,7 +287,7 @@ void u2fhid_init(const U2FHID_FRAME *in)
{
const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data;
U2FHID_FRAME f;
- U2FHID_INIT_RESP resp;
+ U2FHID_INIT_RESP resp = {0};
debugLog(0, "", "u2fhid_init");
@@ -295,7 +300,7 @@ void u2fhid_init(const U2FHID_FRAME *in)
f.cid = in->cid;
f.init.cmd = U2FHID_INIT;
f.init.bcnth = 0;
- f.init.bcntl = U2FHID_INIT_RESP_SIZE;
+ f.init.bcntl = sizeof(resp);
memcpy(resp.nonce, init_req->nonce, sizeof(init_req->nonce));
resp.cid = in->cid == CID_BROADCAST ? next_cid() : in->cid;
@@ -363,6 +368,11 @@ void u2fhid_msg(const APDU *a, uint32_t len)
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len)
{
+ if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) {
+ debugLog(0, "", "send_u2fhid_msg failed");
+ return;
+ }
+
U2FHID_FRAME f;
uint8_t *p = (uint8_t *)data;
uint32_t l = len;
diff --git a/firmware/u2f/u2f.h b/firmware/u2f/u2f.h
index 62979a3160..b067713963 100644
--- a/firmware/u2f/u2f.h
+++ b/firmware/u2f/u2f.h
@@ -1,143 +1,113 @@
-/*
- Copyright (C) 2013-2015 Yubico AB
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program; if not, see .
-*/
-
-// Common U2F raw message format header.
-// 2014-08-14 J Ehrensvard, Yubico, Inc.
+/**
+ * Copyright FIDO Alliance, 2017
+ *
+ * Licensed under CC-BY:
+ * https://creativecommons.org/licenses/by/4.0/legalcode
+ *
+ * Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
+ */
#ifndef __U2F_H_INCLUDED__
#define __U2F_H_INCLUDED__
-#ifdef _MSC_VER // Windows
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
+#ifdef _MSC_VER // Windows
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include
#endif
#ifdef __cplusplus
-extern "C"
-{
+extern "C" {
#endif
// General constants
-#define U2F_EC_KEY_SIZE 32 // EC key size in bytes
-#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
-#define U2F_MAX_KH_SIZE 128 // Max size of key handle
-#define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate
-#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature
-#define U2F_CTR_SIZE 4 // Size of counter field
-#define U2F_APPID_SIZE 32 // Size of application id
-#define U2F_CHAL_SIZE 32 // Size of challenge
+#define U2F_EC_KEY_SIZE 32 // EC key size in bytes
+#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
+#define U2F_MAX_KH_SIZE 128 // Max size of key handle
+#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate
+#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature
+#define U2F_CTR_SIZE 4 // Size of counter field
+#define U2F_APPID_SIZE 32 // Size of application id
+#define U2F_CHAL_SIZE 32 // Size of challenge
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
// EC (uncompressed) point
-#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format
+#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format
- typedef struct
- {
- uint8_t pointFormat; // Point type
- uint8_t x[U2F_EC_KEY_SIZE]; // X-value
- uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
- } U2F_EC_POINT;
+typedef struct __attribute__((packed)) {
+ uint8_t pointFormat; // Point type
+ uint8_t x[U2F_EC_KEY_SIZE]; // X-value
+ uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
+} U2F_EC_POINT;
// U2F native commands
-#define U2F_REGISTER 0x01 // Registration command
-#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
-#define U2F_VERSION 0x03 // Read version string command
+#define U2F_REGISTER 0x01 // Registration command
+#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
+#define U2F_VERSION 0x03 // Read version string command
-#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
-#define U2F_VENDOR_LAST 0x7f // Last vendor defined command
+#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
+#define U2F_VENDOR_LAST 0xbf // Last vendor defined command
// U2F_CMD_REGISTER command defines
-#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
-#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
+#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
+#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
- typedef struct
- {
- uint8_t chal[U2F_CHAL_SIZE]; // Challenge
- uint8_t appId[U2F_APPID_SIZE]; // Application id
- } U2F_REGISTER_REQ;
+typedef struct __attribute__((packed)) {
+ uint8_t chal[U2F_CHAL_SIZE]; // Challenge
+ uint8_t appId[U2F_APPID_SIZE]; // Application id
+} U2F_REGISTER_REQ;
- typedef struct
- {
- uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
- U2F_EC_POINT pubKey; // Generated public key
- uint8_t keyHandleLen; // Length of key handle
- uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle
- U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
- U2F_MAX_EC_SIG_SIZE]; // Registration signature
- } U2F_REGISTER_RESP;
+typedef struct __attribute__((packed)) {
+ uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
+ U2F_EC_POINT pubKey; // Generated public key
+ uint8_t keyHandleLen; // Length of key handle
+ uint8_t keyHandleCertSig[
+ U2F_MAX_KH_SIZE + // Key handle
+ U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
+ U2F_MAX_EC_SIG_SIZE]; // Registration signature
+} U2F_REGISTER_RESP;
// U2F_CMD_AUTHENTICATE command defines
// Authentication control byte
-#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
-#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
-#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
+#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
+#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
+#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
- typedef struct
- {
- uint8_t chal[U2F_CHAL_SIZE]; // Challenge
- uint8_t appId[U2F_APPID_SIZE]; // Application id
- uint8_t keyHandleLen; // Length of key handle
- uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
- } U2F_AUTHENTICATE_REQ;
+typedef struct __attribute__((packed)) {
+ uint8_t chal[U2F_CHAL_SIZE]; // Challenge
+ uint8_t appId[U2F_APPID_SIZE]; // Application id
+ uint8_t keyHandleLen; // Length of key handle
+ uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
+} U2F_AUTHENTICATE_REQ;
- typedef struct
- {
- uint8_t flags; // U2F_AUTH_FLAG_ values
- uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
- uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
- } U2F_AUTHENTICATE_RESP;
-
-// Common raw message format (ISO7816-4:2005 mapping)
-
- typedef struct
- {
- uint8_t cla; // Class - reserved
- uint8_t ins; // U2F instruction
- uint8_t p1; // U2F parameter 1
- uint8_t p2; // U2F parameter 2
- uint8_t lc1; // Length field, set to zero
- uint8_t lc2; // Length field, MSB
- uint8_t lc3; // Length field, LSB
- uint8_t data[1]; // Data field
- } U2F_MSG;
+typedef struct __attribute__((packed)) {
+ uint8_t flags; // U2F_AUTH_FLAG_ values
+ uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
+ uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
+} U2F_AUTHENTICATE_RESP;
// Command status responses
-#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR
-#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_WRONG_DATA 0x6a80 // SW_WRONG_DATA
-#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_NO_ERROR 0x9000 // SW_NO_ERROR
+#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH
+#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA
+#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED
+#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED
+#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED
+#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00 // SW_CLA_NOT_SUPPORTED
#ifdef __cplusplus
}
#endif
-#endif // __U2F_H_INCLUDED__
+#endif // __U2F_H_INCLUDED__
diff --git a/firmware/u2f/u2f_hid.h b/firmware/u2f/u2f_hid.h
index 326a3fc223..f29059da21 100644
--- a/firmware/u2f/u2f_hid.h
+++ b/firmware/u2f/u2f_hid.h
@@ -1,142 +1,132 @@
-/*
- Copyright (C) 2013-2015 Yubico AB
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1, or (at your option) any
- later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
- General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with this program; if not, see .
-*/
-
-// Common U2F HID transport header.
-// 2014-08-21 J Ehrensvard, Yubico, Inc.
+/**
+ * Copyright FIDO Alliance, 2017
+ *
+ * Licensed under CC-BY:
+ * https://creativecommons.org/licenses/by/4.0/legalcode
+ *
+ * Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com
+ */
#ifndef __U2FHID_H_INCLUDED__
#define __U2FHID_H_INCLUDED__
-#ifdef _MSC_VER // Windows
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
+#ifdef _MSC_VER // Windows
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
#else
#include
#endif
#ifdef __cplusplus
-extern "C"
-{
+extern "C" {
#endif
-// Size of HID reports
+// Size of HID reports
-#define HID_RPT_SIZE 64 // Default size of raw HID report
+#define HID_RPT_SIZE 64 // Default size of raw HID report
// Frame layout - command- and continuation frames
-#define CID_BROADCAST 0xffffffff // Broadcast channel id
+#define CID_BROADCAST 0xffffffff // Broadcast channel id
-#define TYPE_MASK 0x80 // Frame type mask
-#define TYPE_INIT 0x80 // Initial frame identifier
-#define TYPE_CONT 0x00 // Continuation frame identifier
+#define TYPE_MASK 0x80 // Frame type mask
+#define TYPE_INIT 0x80 // Initial frame identifier
+#define TYPE_CONT 0x00 // Continuation frame identifier
- typedef struct
- {
- uint32_t cid; // Channel identifier
- union
- {
- uint8_t type; // Frame type - b7 defines type
- struct
- {
- uint8_t cmd; // Command - b7 set
- uint8_t bcnth; // Message byte count - high part
- uint8_t bcntl; // Message byte count - low part
- uint8_t data[HID_RPT_SIZE - 7]; // Data payload
- } init;
- struct
- {
- uint8_t seq; // Sequence number - b7 cleared
- uint8_t data[HID_RPT_SIZE - 5]; // Data payload
- } cont;
- };
- } U2FHID_FRAME;
+typedef struct __attribute__((packed)) {
+ uint32_t cid; // Channel identifier
+ union __attribute__((packed)) {
+ uint8_t type; // Frame type - b7 defines type
+ struct __attribute__((packed)) {
+ uint8_t cmd; // Command - b7 set
+ uint8_t bcnth; // Message byte count - high part
+ uint8_t bcntl; // Message byte count - low part
+ uint8_t data[HID_RPT_SIZE - 7]; // Data payload
+ } init;
+ struct __attribute__((packed)) {
+ uint8_t seq; // Sequence number - b7 cleared
+ uint8_t data[HID_RPT_SIZE - 5]; // Data payload
+ } cont;
+ };
+} U2FHID_FRAME;
#define FRAME_TYPE(f) ((f).type & TYPE_MASK)
#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK)
-#define MSG_LEN(f) (((f).init.bcnth << 8) + (f).init.bcntl)
+#define MSG_LEN(f) ((f).init.bcnth*256 + (f).init.bcntl)
#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK)
// HID usage- and usage-page definitions
-#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
-#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection
-#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
-#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
+#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
+#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection
+#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
+#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
-// General constants
+// General constants
-#define U2FHID_IF_VERSION 2 // Current interface implementation version
-#define U2FHID_FRAME_TIMEOUT 500 // Default frame timeout in ms
-#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
+#define U2FHID_IF_VERSION 2 // Current interface implementation version
+#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
// U2FHID native commands
-#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
-#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame
-#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
-#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization
-#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
-#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response
+#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
+#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame
+#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
+#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization
+#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
+#define U2FHID_SYNC (TYPE_INIT | 0x3c) // Protocol resync command
+#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response
-#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
-#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command
+#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
+#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command
// U2FHID_INIT command defines
-#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
-#define CAPFLAG_WINK 0x01 // Device supports WINK command
-#define CAPFLAG_LOCK 0x02 // Device supports LOCK command
+#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
+#define CAPFLAG_WINK 0x01 // Device supports WINK command
+#define CAPFLAG_LOCK 0x02 // Device supports LOCK command
- typedef struct
- {
- uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
- } U2FHID_INIT_REQ;
+typedef struct __attribute__((packed)) {
+ uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
+} U2FHID_INIT_REQ;
- typedef struct
- {
- uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
- uint32_t cid; // Channel identifier
- uint8_t versionInterface; // Interface version
- uint8_t versionMajor; // Major version number
- uint8_t versionMinor; // Minor version number
- uint8_t versionBuild; // Build version number
- uint8_t capFlags; // Capabilities flags
- } U2FHID_INIT_RESP;
+typedef struct __attribute__((packed)) {
+ uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
+ uint32_t cid; // Channel identifier
+ uint8_t versionInterface; // Interface version
+ uint8_t versionMajor; // Major version number
+ uint8_t versionMinor; // Minor version number
+ uint8_t versionBuild; // Build version number
+ uint8_t capFlags; // Capabilities flags
+} U2FHID_INIT_RESP;
-#define U2FHID_INIT_RESP_SIZE 17
+// U2FHID_SYNC command defines
+
+typedef struct __attribute__((packed)) {
+ uint8_t nonce; // Client application nonce
+} U2FHID_SYNC_REQ;
+
+typedef struct __attribute__((packed)) {
+ uint8_t nonce; // Client application nonce
+} U2FHID_SYNC_RESP;
// Low-level error codes. Return as negatives.
-#define ERR_NONE 0x00 // No error
-#define ERR_INVALID_CMD 0x01 // Invalid command
-#define ERR_INVALID_PAR 0x02 // Invalid parameter
-#define ERR_INVALID_LEN 0x03 // Invalid message length
-#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing
-#define ERR_MSG_TIMEOUT 0x05 // Message has timed out
-#define ERR_CHANNEL_BUSY 0x06 // Channel busy
-#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
-#define ERR_INVALID_CID 0x0b // Command not allowed on this cid
-#define ERR_OTHER 0x7f // Other unspecified error
+#define ERR_NONE 0x00 // No error
+#define ERR_INVALID_CMD 0x01 // Invalid command
+#define ERR_INVALID_PAR 0x02 // Invalid parameter
+#define ERR_INVALID_LEN 0x03 // Invalid message length
+#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing
+#define ERR_MSG_TIMEOUT 0x05 // Message has timed out
+#define ERR_CHANNEL_BUSY 0x06 // Channel busy
+#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
+#define ERR_INVALID_CID 0x0b // Message on CID 0
+#define ERR_OTHER 0x7f // Other unspecified error
#ifdef __cplusplus
}
#endif
-#endif // __U2FHID_H_INCLUDED__
+#endif // __U2FHID_H_INCLUDED__