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__