Reformatting.

This commit is contained in:
2019-08-23 13:27:30 +01:00
parent 03dba21ad4
commit 01dad2ee0a
42 changed files with 859 additions and 987 deletions

View File

@@ -18,19 +18,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
enum APDU : uint8_t
{
U2F_REG = 0x01,
U2F_AUTH = 0x02,
U2F_VER = 0x03
};
enum APDU : uint8_t { U2F_REG = 0x01, U2F_AUTH = 0x02, U2F_VER = 0x03 };
enum APDU_STATUS : uint16_t
{
SW_NO_ERROR = 0x9000,
SW_WRONG_LENGTH = 0x6700,
enum APDU_STATUS : uint16_t {
SW_NO_ERROR = 0x9000,
SW_WRONG_LENGTH = 0x6700,
SW_CONDITIONS_NOT_SATISFIED = 0x6985,
SW_WRONG_DATA = 0x6A80,
SW_INS_NOT_SUPPORTED = 0x6D00,
SW_COMMAND_NOT_ALLOWED = 0x6E00,
SW_WRONG_DATA = 0x6A80,
SW_INS_NOT_SUPPORTED = 0x6D00,
SW_COMMAND_NOT_ALLOWED = 0x6E00,
};

View File

@@ -23,15 +23,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define ARCHITECTURE ARCH_ANDROID
#if ARCHITECTURE == ARCH_RASPBERRY_PI
#define STORAGE_PREFIX "/usr/share/"
#define HID_DEV "/dev/hidg0"
#define DEBUG_STREAMS "/tmp/"
# define STORAGE_PREFIX "/usr/share/"
# define HID_DEV "/dev/hidg0"
# define DEBUG_STREAMS "/tmp/"
// #define DEBUG_MSGS
#define LEDS
# define LEDS
#elif ARCHITECTURE == ARCH_ANDROID
#define STORAGE_PREFIX "/sdcard/U2F/"
#define HID_DEV "/dev/hidg2"
#define DEBUG_STREAMS "/data/local/tmp/"
# define STORAGE_PREFIX "/sdcard/U2F/"
# define HID_DEV "/dev/hidg2"
# define DEBUG_STREAMS "/data/local/tmp/"
// #define DEBUG_MSGS
#endif

View File

@@ -19,19 +19,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
template <typename InContainer, typename OutContainer>
void b64encode(const InContainer &iContainer, OutContainer &oContainer);
void b64encode(const InContainer& iContainer, OutContainer& oContainer);
template <typename InContainer, typename OutContainer>
void b64decode(const InContainer &container, OutContainer &oContainer);
void b64decode(const InContainer& container, OutContainer& oContainer);
template <typename InContainer, typename Elem, size_t count>
void b64encode(const InContainer &iContainer, std::array<Elem, count> &oArr);
void b64encode(const InContainer& iContainer, std::array<Elem, count>& oArr);
template <typename InContainer, typename Elem, size_t count>
void b64decode(const InContainer &iContainer, std::array<Elem, count> &oArr);
void b64decode(const InContainer& iContainer, std::array<Elem, count>& oArr);
template <typename InContainerIter, typename OutContainerIter>
void b64encode(const InContainerIter beginIter, const InContainerIter endIter, OutContainerIter oBeginIter);
void b64encode(const InContainerIter beginIter, const InContainerIter endIter,
OutContainerIter oBeginIter);
template <typename InContainerIter, typename OutContainerIter>
void b64decode(const InContainerIter beginIter, const InContainerIter endIter, OutContainerIter oBeginIter);
void b64decode(const InContainerIter beginIter, const InContainerIter endIter,
OutContainerIter oBeginIter);

View File

@@ -15,76 +15,60 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Certificates.hpp"
//You may not actually want to use these values -
// You may not actually want to use these values -
// having been shared publicly, these may be vulnerable to exploits.
// However, generating your own attestation certificate makes your device
// uniquely identifiable across platforms / services, etc.
// You can generate your own using the method detailed in the README.
uint8_t attestCert[] = {
0x30, 0x82, 0x02, 0x29, 0x30, 0x82, 0x01, 0xd0, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x09, 0x00, 0x8a, 0xe2, 0x21, 0x3f, 0x2f, 0x8b, 0x72, 0x52,
0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
0x30, 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31,
0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x55, 0x32,
0x46, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x74, 0x50, 0x46, 0x53, 0x71, 0x54,
0x71, 0x6f, 0x5a, 0x6d, 0x62, 0x37, 0x38, 0x61, 0x6a, 0x6f, 0x2f, 0x75,
0x58, 0x50, 0x73, 0x51, 0x3d, 0x3d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38,
0x30, 0x36, 0x33, 0x30, 0x31, 0x39, 0x30, 0x37, 0x35, 0x31, 0x5a, 0x17,
0x0d, 0x32, 0x38, 0x30, 0x36, 0x32, 0x37, 0x31, 0x39, 0x30, 0x37, 0x35,
0x31, 0x5a, 0x30, 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61,
0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74,
0x64, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20,
0x55, 0x32, 0x46, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x74, 0x50, 0x46, 0x53,
0x71, 0x54, 0x71, 0x6f, 0x5a, 0x6d, 0x62, 0x37, 0x38, 0x61, 0x6a, 0x6f,
0x2f, 0x75, 0x58, 0x50, 0x73, 0x51, 0x3d, 0x3d, 0x30, 0x59, 0x30, 0x13,
0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x32,
0x41, 0xc3, 0xb8, 0x96, 0x97, 0xd8, 0x90, 0x66, 0x41, 0x88, 0x96, 0xd4,
0x73, 0xb6, 0x37, 0xf7, 0x85, 0x29, 0xaf, 0x3b, 0x15, 0x0f, 0x83, 0x61,
0x67, 0xea, 0xc9, 0xb2, 0xdb, 0x82, 0xb3, 0x2c, 0x99, 0x60, 0x8a, 0x98,
0x7c, 0xd4, 0x04, 0xa0, 0x92, 0x22, 0x05, 0xaa, 0xf7, 0x7a, 0x91, 0x02,
0x03, 0xdd, 0x15, 0x88, 0x87, 0x6a, 0x26, 0xe9, 0xee, 0xcf, 0x99, 0xb1,
0x66, 0xc0, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55,
0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcf, 0x7f, 0xfa, 0x7d, 0xc4, 0x8d,
0xba, 0x60, 0x52, 0x4c, 0xb6, 0x16, 0x2e, 0x88, 0x62, 0xc7, 0x8c, 0xfc,
0xe0, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
0x16, 0x80, 0x14, 0xcf, 0x7f, 0xfa, 0x7d, 0xc4, 0x8d, 0xba, 0x60, 0x52,
0x4c, 0xb6, 0x16, 0x2e, 0x88, 0x62, 0xc7, 0x8c, 0xfc, 0xe0, 0x63, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30,
0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x72,
0x25, 0x89, 0xc1, 0x32, 0x54, 0x66, 0xf8, 0x0e, 0x58, 0x77, 0xe3, 0xb5,
0x62, 0x47, 0x33, 0x18, 0x5a, 0xdc, 0x28, 0x6a, 0x4a, 0x56, 0xcb, 0x58,
0x63, 0xe3, 0xa1, 0x02, 0x6a, 0xf0, 0xd8, 0x02, 0x20, 0x65, 0x26, 0x84,
0x7c, 0xc3, 0x3b, 0x7d, 0x6a, 0x22, 0x0c, 0x22, 0x3d, 0xc8, 0x43, 0xb7,
0x84, 0x8b, 0x7b, 0x48, 0x23, 0xb0, 0x1e, 0x13, 0x35, 0x1d, 0x1a, 0x90,
0x44, 0x62, 0x6c, 0xab, 0x9b
0x30, 0x82, 0x02, 0x29, 0x30, 0x82, 0x01, 0xd0, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00,
0x8a, 0xe2, 0x21, 0x3f, 0x2f, 0x8b, 0x72, 0x52, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
0x3d, 0x04, 0x03, 0x02, 0x30, 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f,
0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x29, 0x30, 0x27, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x55, 0x32, 0x46, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x74, 0x50,
0x46, 0x53, 0x71, 0x54, 0x71, 0x6f, 0x5a, 0x6d, 0x62, 0x37, 0x38, 0x61, 0x6a, 0x6f, 0x2f, 0x75,
0x58, 0x50, 0x73, 0x51, 0x3d, 0x3d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x36, 0x33, 0x30,
0x31, 0x39, 0x30, 0x37, 0x35, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x36, 0x32, 0x37, 0x31,
0x39, 0x30, 0x37, 0x35, 0x31, 0x5a, 0x30, 0x70, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a,
0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69,
0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x29, 0x30,
0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x20, 0x55, 0x32, 0x46, 0x20, 0x4b, 0x65, 0x79, 0x20,
0x74, 0x50, 0x46, 0x53, 0x71, 0x54, 0x71, 0x6f, 0x5a, 0x6d, 0x62, 0x37, 0x38, 0x61, 0x6a, 0x6f,
0x2f, 0x75, 0x58, 0x50, 0x73, 0x51, 0x3d, 0x3d, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0x32, 0x41, 0xc3, 0xb8, 0x96, 0x97, 0xd8, 0x90, 0x66, 0x41, 0x88, 0x96, 0xd4,
0x73, 0xb6, 0x37, 0xf7, 0x85, 0x29, 0xaf, 0x3b, 0x15, 0x0f, 0x83, 0x61, 0x67, 0xea, 0xc9, 0xb2,
0xdb, 0x82, 0xb3, 0x2c, 0x99, 0x60, 0x8a, 0x98, 0x7c, 0xd4, 0x04, 0xa0, 0x92, 0x22, 0x05, 0xaa,
0xf7, 0x7a, 0x91, 0x02, 0x03, 0xdd, 0x15, 0x88, 0x87, 0x6a, 0x26, 0xe9, 0xee, 0xcf, 0x99, 0xb1,
0x66, 0xc0, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
0x04, 0x14, 0xcf, 0x7f, 0xfa, 0x7d, 0xc4, 0x8d, 0xba, 0x60, 0x52, 0x4c, 0xb6, 0x16, 0x2e, 0x88,
0x62, 0xc7, 0x8c, 0xfc, 0xe0, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
0x16, 0x80, 0x14, 0xcf, 0x7f, 0xfa, 0x7d, 0xc4, 0x8d, 0xba, 0x60, 0x52, 0x4c, 0xb6, 0x16, 0x2e,
0x88, 0x62, 0xc7, 0x8c, 0xfc, 0xe0, 0x63, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x72, 0x25, 0x89, 0xc1, 0x32,
0x54, 0x66, 0xf8, 0x0e, 0x58, 0x77, 0xe3, 0xb5, 0x62, 0x47, 0x33, 0x18, 0x5a, 0xdc, 0x28, 0x6a,
0x4a, 0x56, 0xcb, 0x58, 0x63, 0xe3, 0xa1, 0x02, 0x6a, 0xf0, 0xd8, 0x02, 0x20, 0x65, 0x26, 0x84,
0x7c, 0xc3, 0x3b, 0x7d, 0x6a, 0x22, 0x0c, 0x22, 0x3d, 0xc8, 0x43, 0xb7, 0x84, 0x8b, 0x7b, 0x48,
0x23, 0xb0, 0x1e, 0x13, 0x35, 0x1d, 0x1a, 0x90, 0x44, 0x62, 0x6c, 0xab, 0x9b
};
uint8_t attestPrivKey[] = {
0x7e, 0xbd, 0x91, 0x05, 0x5a, 0x80, 0x9f, 0x36, 0xe5, 0x2f, 0xe0, 0xd0,
0xa9, 0x63, 0x0c, 0x86, 0x04, 0xb1, 0x04, 0xe3, 0xd1, 0xfb, 0xd0, 0x83,
0xc7, 0x2e, 0x2f, 0x34, 0xb6, 0xd6, 0xa4, 0xb2
};
uint8_t attestPrivKey[] = { 0x7e, 0xbd, 0x91, 0x05, 0x5a, 0x80, 0x9f, 0x36, 0xe5, 0x2f, 0xe0,
0xd0, 0xa9, 0x63, 0x0c, 0x86, 0x04, 0xb1, 0x04, 0xe3, 0xd1, 0xfb,
0xd0, 0x83, 0xc7, 0x2e, 0x2f, 0x34, 0xb6, 0xd6, 0xa4, 0xb2 };
uint8_t attestPubKey[] = {
0x04, 0x32, 0x41, 0xc3, 0xb8, 0x96, 0x97, 0xd8, 0x90, 0x66, 0x41, 0x88,
0x96, 0xd4, 0x73, 0xb6, 0x37, 0xf7, 0x85, 0x29, 0xaf, 0x3b, 0x15, 0x0f,
0x83, 0x61, 0x67, 0xea, 0xc9, 0xb2, 0xdb, 0x82, 0xb3, 0x2c, 0x99, 0x60,
0x8a, 0x98, 0x7c, 0xd4, 0x04, 0xa0, 0x92, 0x22, 0x05, 0xaa, 0xf7, 0x7a,
0x91, 0x02, 0x03, 0xdd, 0x15, 0x88, 0x87, 0x6a, 0x26, 0xe9, 0xee, 0xcf,
0x99, 0xb1, 0x66, 0xc0, 0x01
};
uint8_t attestPubKey[] = { 0x04, 0x32, 0x41, 0xc3, 0xb8, 0x96, 0x97, 0xd8, 0x90, 0x66, 0x41,
0x88, 0x96, 0xd4, 0x73, 0xb6, 0x37, 0xf7, 0x85, 0x29, 0xaf, 0x3b,
0x15, 0x0f, 0x83, 0x61, 0x67, 0xea, 0xc9, 0xb2, 0xdb, 0x82, 0xb3,
0x2c, 0x99, 0x60, 0x8a, 0x98, 0x7c, 0xd4, 0x04, 0xa0, 0x92, 0x22,
0x05, 0xaa, 0xf7, 0x7a, 0x91, 0x02, 0x03, 0xdd, 0x15, 0x88, 0x87,
0x6a, 0x26, 0xe9, 0xee, 0xcf, 0x99, 0xb1, 0x66, 0xc0, 0x01 };

View File

@@ -17,24 +17,23 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Channel.hpp"
#include <stdexcept>
#include "u2f.hpp"
#include "U2F_CMD.hpp"
#include "u2f.hpp"
#include <iostream>
#include <stdexcept>
using namespace std;
Channel::Channel(const uint32_t channelID)
: cid{ channelID }, initState{ ChannelInitState::Unitialised }, lockedState{ ChannelLockedState::Unlocked }
{}
: cid{ channelID }, initState{ ChannelInitState::Unitialised }, lockedState{
ChannelLockedState::Unlocked
} {}
uint32_t Channel::getCID() const
{
uint32_t Channel::getCID() const {
return cid;
}
void Channel::handle(const U2FMessage& uMsg)
{
void Channel::handle(const U2FMessage& uMsg) {
if (uMsg.cmd == U2FHID_INIT)
this->initState = ChannelInitState::Initialised;
else if (uMsg.cid != this->cid)
@@ -51,12 +50,10 @@ void Channel::handle(const U2FMessage& uMsg)
return cmd->respond(this->cid);
}
void Channel::init(const ChannelInitState newInitState)
{
void Channel::init(const ChannelInitState newInitState) {
this->initState = newInitState;
}
void Channel::lock(const ChannelLockedState newLockedState)
{
void Channel::lock(const ChannelLockedState newLockedState) {
this->lockedState = newLockedState;
}

View File

@@ -17,34 +17,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "U2FMessage.hpp"
#include <cstdint>
#include <memory>
#include "U2FMessage.hpp"
enum class ChannelInitState
{
Unitialised,
Initialised
};
enum class ChannelLockedState
{
Locked,
Unlocked
};
class Channel
{
protected:
uint32_t cid;
ChannelInitState initState;
ChannelLockedState lockedState;
public:
Channel(const uint32_t channelID);
void handle(const U2FMessage& uMsg);
uint32_t getCID() const;
void init(const ChannelInitState newInitState);
void lock(const ChannelLockedState newLockedState);
enum class ChannelInitState { Unitialised, Initialised };
enum class ChannelLockedState { Locked, Unlocked };
class Channel {
protected:
uint32_t cid;
ChannelInitState initState;
ChannelLockedState lockedState;
public:
Channel(const uint32_t channelID);
void handle(const U2FMessage& uMsg);
uint32_t getCID() const;
void init(const ChannelInitState newInitState);
void lock(const ChannelLockedState newLockedState);
};

View File

@@ -17,19 +17,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Controller.hpp"
#include "u2f.hpp"
#include <iostream>
#include "IO.hpp"
#include "LED.hpp"
#include "u2f.hpp"
#include <iostream>
using namespace std;
Controller::Controller(const uint32_t startChannel)
: channels{}, currChannel{ startChannel }
{}
Controller::Controller(const uint32_t startChannel) : channels{}, currChannel{ startChannel } {}
void Controller::handleTransaction()
{
void Controller::handleTransaction() {
auto msg = U2FMessage::readNonBlock();
if (!msg)
@@ -38,33 +35,28 @@ void Controller::handleTransaction()
handleTransaction(*msg);
}
void Controller::handleTransaction(const U2FMessage& msg)
{
try
{
if (channels.size() != 0 && chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - lastMessage) < chrono::seconds(5))
void Controller::handleTransaction(const U2FMessage& msg) {
try {
if (channels.size() != 0 &&
chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - lastMessage) <
chrono::seconds(5))
toggleACTLED();
else
enableACTLED(false);
} catch (runtime_error& ignored) {
}
catch (runtime_error& ignored)
{}
lastMessage = chrono::system_clock::now();
auto opChannel = msg.cid;
if (msg.cmd == U2FHID_INIT)
{
if (msg.cmd == U2FHID_INIT) {
opChannel = nextChannel();
auto channel = Channel{ opChannel };
try
{
channels.emplace(opChannel, channel); //In case of wrap-around replace existing one
}
catch (...)
{
try {
channels.emplace(opChannel, channel); // In case of wrap-around replace existing one
} catch (...) {
channels.insert(make_pair(opChannel, channel));
}
}
@@ -77,8 +69,7 @@ void Controller::handleTransaction(const U2FMessage& msg)
channels.at(opChannel).handle(msg);
}
uint32_t Controller::nextChannel()
{
uint32_t Controller::nextChannel() {
do
currChannel++;
while (currChannel == 0xFFFFFFFF || currChannel == 0);

View File

@@ -17,21 +17,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <map>
#include <chrono>
#include "Channel.hpp"
#include <chrono>
#include <map>
class Controller
{
protected:
std::map<uint32_t, Channel> channels;
uint32_t currChannel;
std::chrono::system_clock::time_point lastMessage;
class Controller {
protected:
std::map<uint32_t, Channel> channels;
uint32_t currChannel;
std::chrono::system_clock::time_point lastMessage;
public:
Controller(const uint32_t startChannel = 1);
public:
Controller(const uint32_t startChannel = 1);
void handleTransaction();
void handleTransaction(const U2FMessage& msg);
uint32_t nextChannel();
void handleTransaction();
void handleTransaction(const U2FMessage& msg);
uint32_t nextChannel();
};

View File

@@ -20,7 +20,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std;
vector<uint8_t> beEncode(const uint8_t* val, const size_t byteCount)
{
return { reverse_iterator<const uint8_t *>(val + byteCount), reverse_iterator<const uint8_t *>(val) };
vector<uint8_t> beEncode(const uint8_t* val, const size_t byteCount) {
return { reverse_iterator<const uint8_t*>(val + byteCount),
reverse_iterator<const uint8_t*>(val) };
}

View File

@@ -17,13 +17,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <cstdint>
#include <vector>
template <typename Type>
std::vector<uint8_t> beEncode(const Type val);
std::vector<uint8_t> beEncode(const uint8_t* val, const std::size_t byteCount);
#define FIELD(name) reinterpret_cast<const uint8_t*>(&name), (reinterpret_cast<const uint8_t*>(&name) + sizeof(name))
#define FIELD_BE(name) reverse_iterator<const uint8_t*>(reinterpret_cast<const uint8_t*>(&name) + sizeof(name)), reverse_iterator<const uint8_t*>(reinterpret_cast<const uint8_t*>(&name))
#define FIELD(name) \
reinterpret_cast<const uint8_t*>(&name), \
(reinterpret_cast<const uint8_t*>(&name) + sizeof(name))
#define FIELD_BE(name) \
reverse_iterator<const uint8_t*>(reinterpret_cast<const uint8_t*>(&name) + sizeof(name)), \
reverse_iterator<const uint8_t*>(reinterpret_cast<const uint8_t*>(&name))

74
IO.cpp
View File

@@ -17,24 +17,24 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "IO.hpp"
#include "Streams.hpp"
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctime>
#include <chrono>
#include <ratio>
#include <array>
#include <string>
#include <stdexcept>
#include <memory>
#include <cstdio>
#include <android/log.h>
#include "u2f.hpp"
#include "Macro.hpp"
#include "Streams.hpp"
#include "U2FDevice.hpp"
#include "u2f.hpp"
#include <android/log.h>
#include <array>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <fcntl.h>
#include <iostream>
#include <memory>
#include <ratio>
#include <stdexcept>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
@@ -45,15 +45,14 @@ string binaryDirectory{};
string cacheDirectory{ DEBUG_STREAMS };
// Thanks to https://stackoverflow.com/a/478960
vector<uint8_t> execOutput(const string &cmd);
void execInput(const string &cmd, const vector<uint8_t> &stdinData);
vector<uint8_t> execOutput(const string& cmd);
void execInput(const string& cmd, const vector<uint8_t>& stdinData);
vector<uint8_t> readNonBlock(const size_t count)
{
vector<uint8_t> readNonBlock(const size_t count) {
if (!bytesAvailable(count))
return vector<uint8_t>{};
auto &buffer = getBuffer();
auto& buffer = getBuffer();
auto buffStart = buffer.begin(), buffEnd = buffer.begin() + count;
vector<uint8_t> bytes{ buffStart, buffEnd };
buffer.erase(buffStart, buffEnd);
@@ -63,20 +62,17 @@ vector<uint8_t> readNonBlock(const size_t count)
return bytes;
}
void write(const vector<uint8_t> &bytes)
{
__android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Writing %zu bytes", bytes.size());
void write(const vector<uint8_t>& bytes) {
__android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Writing %zu bytes", bytes.size());
execInput("su -c \"" + binaryDirectory + "/U2FAndroid_Write\"", bytes);
}
bool bytesAvailable(const size_t count)
{
bool bytesAvailable(const size_t count) {
auto startTime = std::chrono::high_resolution_clock::now();
const timespec iterDelay{ 0, 10000000 };
chrono::duration<double, milli> delay{ 0 };
while (delay.count() < U2FHID_TRANS_TIMEOUT)
{
while (delay.count() < U2FHID_TRANS_TIMEOUT) {
if (getBuffer().size() >= count) {
#ifdef DEBUG_MSGS
clog << "Requested " << count << " bytes" << endl;
@@ -84,7 +80,7 @@ bool bytesAvailable(const size_t count)
return true;
}
nanosleep(&iterDelay, nullptr);
delay = chrono::high_resolution_clock::now() - startTime;
delay = chrono::high_resolution_clock::now() - startTime;
}
#ifdef DEBUG_MSGS
@@ -94,20 +90,18 @@ bool bytesAvailable(const size_t count)
return false;
}
vector<uint8_t>& bufferVar()
{
vector<uint8_t>& bufferVar() {
static vector<uint8_t> buffer{};
return buffer;
}
vector<uint8_t>& getBuffer()
{
auto &buff = bufferVar();
vector<uint8_t>& getBuffer() {
auto& buff = bufferVar();
vector<uint8_t> bytes = execOutput("su -c \"" + binaryDirectory + "/U2FAndroid_Read\"");
if (!bytes.empty())
{
__android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Reading bytes: got %zu", bytes.size());
if (!bytes.empty()) {
__android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Reading bytes: got %zu",
bytes.size());
buff.insert(buff.end(), bytes.begin(), bytes.end());
#ifdef DEBUG_STREAMS
@@ -118,8 +112,7 @@ vector<uint8_t>& getBuffer()
return buff;
}
vector<uint8_t> execOutput(const string &cmd)
{
vector<uint8_t> execOutput(const string& cmd) {
// NOLINT(hicpp-member-init)
array<char, HID_RPT_SIZE> buffer;
vector<uint8_t> result{};
@@ -133,8 +126,7 @@ vector<uint8_t> execOutput(const string &cmd)
return result;
}
void execInput(const string &cmd, const vector<uint8_t> &stdinData)
{
void execInput(const string& cmd, const vector<uint8_t>& stdinData) {
assert(stdinData.size() % HID_RPT_SIZE == 0);
size_t writtenBytes = 0;

6
IO.hpp
View File

@@ -24,9 +24,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
extern std::string binaryDirectory;
extern std::string cacheDirectory;
//Returns either the number of bytes specified,
//or returns empty vector without discarding bytes from HID stream
// Returns either the number of bytes specified,
// or returns empty vector without discarding bytes from HID stream
std::vector<uint8_t> readNonBlock(const size_t count);
//Blocking write to HID stream - shouldn't block for too long
// Blocking write to HID stream - shouldn't block for too long
void write(const std::vector<uint8_t>& data);

15
LED.cpp
View File

@@ -24,19 +24,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std;
bool& ledState()
{
bool& ledState() {
static bool state = true;
return state;
}
bool getLEDState()
{
bool getLEDState() {
return ledState();
}
void disableACTTrigger([[maybe_unused]] bool nowDisabled)
{
void disableACTTrigger([[maybe_unused]] bool nowDisabled) {
#ifdef LEDS
ofstream trigFile{ "/sys/class/leds/led0/trigger", ofstream::out | ofstream::trunc };
@@ -48,8 +45,7 @@ void disableACTTrigger([[maybe_unused]] bool nowDisabled)
#endif
}
void enableACTLED([[maybe_unused]] bool nowOn)
{
void enableACTLED([[maybe_unused]] bool nowOn) {
#ifdef LEDS
if (nowOn == getLEDState())
return;
@@ -66,7 +62,6 @@ void enableACTLED([[maybe_unused]] bool nowOn)
#endif
}
void toggleACTLED()
{
void toggleACTLED() {
enableACTLED(!getLEDState());
}

View File

@@ -17,7 +17,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <unistd.h>
#include <string>
#include <unistd.h>
#define ERR() if (errno != 0) perror((string{ "(" } + __FILE__ + ":" + to_string(__LINE__) + ")" + " " + __PRETTY_FUNCTION__).c_str()), errno = 0
#define ERR() \
if (errno != 0) \
perror( \
(string{ "(" } + __FILE__ + ":" + to_string(__LINE__) + ")" + " " + __PRETTY_FUNCTION__) \
.c_str()), \
errno = 0

View File

@@ -18,24 +18,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Packet.hpp"
#include "IO.hpp"
#include "Streams.hpp"
#include "u2f.hpp"
#include <cstring>
#include <iostream>
#include <unistd.h>
#include "Streams.hpp"
using namespace std;
shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t rCMD)
{
shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t rCMD) {
static size_t bytesRead = 0;
static uint8_t bcnth;
static uint8_t bcntl;
static decltype(InitPacket::data) dataBytes;
vector<uint8_t> bytes{};
switch (bytesRead)
{
switch (bytesRead) {
case 0:
bytes = readNonBlock(1);
@@ -62,7 +60,8 @@ shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t
if (bytes.size() == 0)
return {};
copy(bytes.begin(), bytes.end(), dataBytes.begin());;
copy(bytes.begin(), bytes.end(), dataBytes.begin());
;
bytesRead += bytes.size();
[[fallthrough]];
@@ -74,56 +73,56 @@ shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t
}
auto p = make_shared<InitPacket>();
p->cid = rCID;
p->cmd = rCMD;
p->cid = rCID;
p->cmd = rCMD;
p->bcnth = bcnth;
p->bcntl = bcntl;
p->data = dataBytes;
p->data = dataBytes;
#ifdef DEBUG_STREAMS
auto hPStream = getHostPacketStream().get();
fprintf(hPStream, "\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>CMD</th>\n"
"\t\t\t\t\t<th>BCNTH</th>\n"
"\t\t\t\t\t<th>BCNTL</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">", p->cid, p->cmd, p->bcnth, p->bcntl);
fprintf(hPStream,
"\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>CMD</th>\n"
"\t\t\t\t\t<th>BCNTH</th>\n"
"\t\t\t\t\t<th>BCNTL</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">",
p->cid, p->cmd, p->bcnth, p->bcntl);
for (auto elem : dataBytes)
fprintf(hPStream, "%3u ", elem);
fprintf(hPStream, "</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>"
"\t\t<br />");
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>"
"\t\t<br />");
#endif
bytesRead = 0;
return p;
}
shared_ptr<ContPacket> ContPacket::getPacket(const uint32_t rCID, const uint8_t rSeq)
{
shared_ptr<ContPacket> ContPacket::getPacket(const uint32_t rCID, const uint8_t rSeq) {
static size_t readBytes = 0;
static decltype(ContPacket::data) dataBytes;
vector<uint8_t> bytes{};
auto p = make_shared<ContPacket>();
if (readBytes != dataBytes.size())
{
if (readBytes != dataBytes.size()) {
dataBytes = {};
bytes = readNonBlock(dataBytes.size());
@@ -140,48 +139,48 @@ shared_ptr<ContPacket> ContPacket::getPacket(const uint32_t rCID, const uint8_t
#ifdef DEBUG_STREAMS
auto hPStream = getHostPacketStream().get();
fprintf(hPStream, "\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>SEQ</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">", p->cid, p->seq);
fprintf(hPStream,
"\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>SEQ</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">",
p->cid, p->seq);
for (auto elem : dataBytes)
fprintf(hPStream, "%3u ", elem);
fprintf(hPStream, "</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />");
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />");
#endif
readBytes = 0;
return p;
}
shared_ptr<Packet> Packet::getPacket()
{
shared_ptr<Packet> Packet::getPacket() {
static size_t bytesRead = 0;
vector<uint8_t> bytes{};
static uint32_t cid;
static uint8_t b;
static uint8_t b;
shared_ptr<Packet> packet{};
switch (bytesRead)
{
switch (bytesRead) {
case 0:
bytes = readNonBlock(4);
if (bytes.size() == 0)
return {};
@@ -200,19 +199,16 @@ shared_ptr<Packet> Packet::getPacket()
[[fallthrough]];
case 5:
if (b & TYPE_MASK)
{
//Init packet
if (b & TYPE_MASK) {
// Init packet
packet = InitPacket::getPacket(cid, b);
if (packet)
bytesRead = 0;
return packet;
}
else
{
//Cont packet
} else {
// Cont packet
packet = ContPacket::getPacket(cid, b);
if (packet)
@@ -225,97 +221,98 @@ shared_ptr<Packet> Packet::getPacket()
}
}
void Packet::writePacket()
{
memset(this->buf, 0, HID_RPT_SIZE);
void Packet::writePacket() {
memset(this->buf, 0, HID_RPT_SIZE);
memcpy(this->buf, &cid, 4);
}
void InitPacket::writePacket()
{
void InitPacket::writePacket() {
Packet::writePacket();
#ifdef DEBUG_STREAMS
auto devStream = getComDevStream().get();
auto devStream = getComDevStream().get();
#endif
memcpy(this->buf + 4, &cmd, 1);
memcpy(this->buf + 5, &bcnth, 1);
memcpy(this->buf + 6, &bcntl, 1);
memcpy(this->buf + 4, &cmd, 1);
memcpy(this->buf + 5, &bcnth, 1);
memcpy(this->buf + 6, &bcntl, 1);
memcpy(this->buf + 7, data.data(), data.size());
write(vector<uint8_t>{ this->buf, this->buf + sizeof(this->buf) });
#ifdef DEBUG_STREAMS
fwrite(this->buf, 1, sizeof(this->buf), devStream);
fwrite(this->buf, 1, sizeof(this->buf), devStream);
auto dPStream = getDevPacketStream().get();
fprintf(dPStream, "\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>CMD</th>\n"
"\t\t\t\t\t<th>BCNTH</th>\n"
"\t\t\t\t\t<th>BCNTL</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">", cid, cmd, bcnth, bcntl);
fprintf(dPStream,
"\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>CMD</th>\n"
"\t\t\t\t\t<th>BCNTH</th>\n"
"\t\t\t\t\t<th>BCNTL</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">",
cid, cmd, bcnth, bcntl);
for (auto elem : data)
fprintf(dPStream, "%3u ", elem);
fprintf(dPStream, "</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>"
"\t\t<br />");
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>"
"\t\t<br />");
#endif
}
void ContPacket::writePacket()
{
void ContPacket::writePacket() {
Packet::writePacket();
#ifdef DEBUG_STREAMS
auto devStream = getComDevStream().get();
auto devStream = getComDevStream().get();
#endif
memcpy(this->buf + 4, &seq, 1);
memcpy(this->buf + 4, &seq, 1);
memcpy(this->buf + 5, data.data(), data.size());
write(vector<uint8_t>{this->buf, this->buf + HID_RPT_SIZE });
write(vector<uint8_t>{ this->buf, this->buf + HID_RPT_SIZE });
#ifdef DEBUG_STREAMS
fwrite(this->buf, HID_RPT_SIZE, 1, devStream);
fwrite(this->buf, HID_RPT_SIZE, 1, devStream);
auto dPStream = getDevPacketStream().get();
fprintf(dPStream, "\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>SEQ</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">", cid, seq);
fprintf(dPStream,
"\t\t<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CID</th>\n"
"\t\t\t\t\t<th>SEQ</th>\n"
"\t\t\t\t\t<th class=\"data\">DATA</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%08X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td class=\"data\">",
cid, seq);
for (auto elem : data)
fprintf(dPStream, "%3u ", elem);
fprintf(dPStream, "</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />");
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />");
#endif
}

View File

@@ -17,48 +17,45 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "u2f.hpp"
#include <array>
#include <cstdint>
#include <memory>
#include <array>
#include "u2f.hpp"
struct Packet
{
public:
uint32_t cid;
uint8_t buf[HID_RPT_SIZE];
struct Packet {
public:
uint32_t cid;
uint8_t buf[HID_RPT_SIZE];
protected:
Packet() = default;
virtual void writePacket();
protected:
Packet() = default;
virtual void writePacket();
public:
static std::shared_ptr<Packet> getPacket();
virtual ~Packet() = default;
public:
static std::shared_ptr<Packet> getPacket();
virtual ~Packet() = default;
};
struct InitPacket : Packet
{
public:
uint8_t cmd;
uint8_t bcnth;
uint8_t bcntl;
std::array<uint8_t, HID_RPT_SIZE - 7> data{};
struct InitPacket : Packet {
public:
uint8_t cmd;
uint8_t bcnth;
uint8_t bcntl;
std::array<uint8_t, HID_RPT_SIZE - 7> data{};
public:
InitPacket() = default;
static std::shared_ptr<InitPacket> getPacket(const uint32_t rCID, const uint8_t rCMD);
void writePacket() override;
public:
InitPacket() = default;
static std::shared_ptr<InitPacket> getPacket(const uint32_t rCID, const uint8_t rCMD);
void writePacket() override;
};
struct ContPacket : Packet
{
public:
uint8_t seq;
std::array<uint8_t, HID_RPT_SIZE - 5> data{};
struct ContPacket : Packet {
public:
uint8_t seq;
std::array<uint8_t, HID_RPT_SIZE - 5> data{};
public:
ContPacket() = default;
static std::shared_ptr<ContPacket> getPacket(const uint32_t rCID, const uint8_t rSeq);
void writePacket() override;
public:
ContPacket() = default;
static std::shared_ptr<ContPacket> getPacket(const uint32_t rCID, const uint8_t rSeq);
void writePacket() override;
};

View File

@@ -21,27 +21,24 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std;
//Ripped from https://github.com/pratikd650/Teensy_U2F/blob/master/Teensy_U2F.cpp
void appendSignatureAsDER(vector<uint8_t> &response, const array<uint8_t, 64> &signature)
{
// Ripped from https://github.com/pratikd650/Teensy_U2F/blob/master/Teensy_U2F.cpp
void appendSignatureAsDER(vector<uint8_t>& response, const array<uint8_t, 64>& signature) {
response.push_back(0x30); // Start of ASN.1 SEQUENCE
response.push_back(68); //total length from (2 * (32 + 2)) to (2 * (33 + 2))
response.push_back(68); // total length from (2 * (32 + 2)) to (2 * (33 + 2))
size_t countByte = response.size() - 1;
// Loop twice - for R and S
for(unsigned int i = 0; i < 2; i++)
{
for (unsigned int i = 0; i < 2; i++) {
unsigned int sigOffs = i * 32;
auto offset = signature.begin() + sigOffs;
response.push_back(0x02); //header: integer
response.push_back(32); //32 byte
if (signature[sigOffs] > 0x7f)
{
response.push_back(0x02); // header: integer
response.push_back(32); // 32 byte
if (signature[sigOffs] > 0x7f) {
// Integer needs to be represented in 2's completement notion
response.back()++;
response.push_back(0); // add leading 0, to indicate it is a positive number
response[countByte]++;
}
copy(offset, offset + 32, back_inserter(response)); //R or S value
copy(offset, offset + 32, back_inserter(response)); // R or S value
}
}

View File

@@ -17,11 +17,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <vector>
#include <array>
#include <vector>
using Digest = std::array<uint8_t, 32>;
using Digest = std::array<uint8_t, 32>;
using Signature = std::array<uint8_t, 64>;
//Ripped from https://github.com/pratikd650/Teensy_U2F/blob/master/Teensy_U2F.cpp
void appendSignatureAsDER(std::vector<uint8_t> &response, const Signature &signature);
// Ripped from https://github.com/pratikd650/Teensy_U2F/blob/master/Teensy_U2F.cpp
void appendSignatureAsDER(std::vector<uint8_t>& response, const Signature& signature);

View File

@@ -17,50 +17,49 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Storage.hpp"
#include <exception>
#include <sstream>
#include "Base64.tpp"
#include <exception>
#include <iostream>
#include <sstream>
using namespace std;
std::string Storage::filename{};
std::map<Storage::KeyHandle, Storage::AppParam> Storage::appParams{};
std::map<Storage::KeyHandle, Storage::PrivKey> Storage::privKeys{};
std::map<Storage::KeyHandle, Storage::PubKey> Storage::pubKeys{};
std::map<Storage::KeyHandle, Storage::PrivKey> Storage::privKeys{};
std::map<Storage::KeyHandle, Storage::PubKey> Storage::pubKeys{};
std::map<Storage::KeyHandle, Storage::KeyCount> Storage::keyCounts{};
void Storage::init(const string &dirPrefix)
{
void Storage::init(const string& dirPrefix) {
Storage::filename = dirPrefix + "U2F_Priv_Keys.txt";
ifstream file{ Storage::filename };
init(file);
}
void Storage::init(std::istream &inputStream)
{
void Storage::init(std::istream& inputStream) {
string line;
size_t lineNumber = 0;
while (getline(inputStream, line))
{
while (getline(inputStream, line)) {
auto strLineNum = to_string(lineNumber);
stringstream ss{ line };
string keyHStr, appStr, privStr, pubStr, keyCStr;
ss >> keyHStr >> appStr >> privStr >> pubStr >> keyCStr;
string keyHStr, appStr, privStr, pubStr, keyCStr;
ss >> keyHStr >> appStr >> privStr >> pubStr >> keyCStr;
if (!ss)
throw runtime_error{ string{ "Invalid syntax of line " } + strLineNum };
char *endP = nullptr;
Storage::KeyHandle keyH{ static_cast<Storage::KeyHandle>(strtoull(keyHStr.c_str(), &endP, 10)) };
char* endP = nullptr;
Storage::KeyHandle keyH{ static_cast<Storage::KeyHandle>(
strtoull(keyHStr.c_str(), &endP, 10)) };
if (!endP)
throw runtime_error{ "Invalid keyhandle format on line " + strLineNum };
endP = nullptr;
Storage::KeyCount keyC{ static_cast<Storage::KeyCount>(strtoull(keyCStr.c_str(), &endP, 10)) };
Storage::KeyCount keyC{ static_cast<Storage::KeyCount>(
strtoull(keyCStr.c_str(), &endP, 10)) };
if (!endP)
throw runtime_error{ "Invalid key count format on line " + strLineNum };
@@ -68,35 +67,32 @@ void Storage::init(std::istream &inputStream)
Storage::AppParam appParam{};
b64decode(appStr, appParam);
Storage::PrivKey privKey{};
Storage::PrivKey privKey{};
b64decode(privStr, privKey);
Storage::PubKey pubKey{};
Storage::PubKey pubKey{};
b64decode(pubStr, pubKey);
Storage::appParams[keyH] = appParam;
Storage::privKeys[keyH] = privKey;
Storage::pubKeys[keyH] = pubKey;
Storage::privKeys[keyH] = privKey;
Storage::pubKeys[keyH] = pubKey;
Storage::keyCounts[keyH] = keyC;
lineNumber++;
}
}
void Storage::save()
{
void Storage::save() {
ofstream file{ Storage::filename };
Storage::save(file);
}
void Storage::save(ostream &outputStream)
{
for (auto &keypair : Storage::appParams)
{
const auto& keyID = keypair.first;
void Storage::save(ostream& outputStream) {
for (auto& keypair : Storage::appParams) {
const auto& keyID = keypair.first;
const auto& appParam = keypair.second;
const auto& privKey = Storage::privKeys[keyID];
const auto& pubKey = Storage::pubKeys[keyID];
const auto& privKey = Storage::privKeys[keyID];
const auto& pubKey = Storage::pubKeys[keyID];
const auto& keyCount = Storage::keyCounts[keyID];
outputStream << keyID;

View File

@@ -17,32 +17,31 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <map>
#include <array>
#include <string>
#include <fstream>
#include <map>
#include <string>
class Storage
{
class Storage {
public:
using KeyHandle = uint32_t;
using KeyCount = uint32_t;
using AppParam = std::array<uint8_t, 32>;
using PrivKey = std::array<uint8_t, 32>;
using PubKey = std::array<uint8_t, 65>;
using KeyCount = uint32_t;
using AppParam = std::array<uint8_t, 32>;
using PrivKey = std::array<uint8_t, 32>;
using PubKey = std::array<uint8_t, 65>;
protected:
Storage() = default;
protected:
Storage() = default;
static std::string filename;
static std::string filename;
public:
static void init(const std::string &dirPrefix = "");
static void init(std::istream &inputStream);
static void save();
static void save(std::ostream &outputStream);
static std::map<KeyHandle, AppParam> appParams;
static std::map<KeyHandle, PrivKey> privKeys;
static std::map<KeyHandle, PubKey> pubKeys;
static std::map<KeyHandle, KeyCount> keyCounts;
public:
static void init(const std::string& dirPrefix = "");
static void init(std::istream& inputStream);
static void save();
static void save(std::ostream& outputStream);
static std::map<KeyHandle, AppParam> appParams;
static std::map<KeyHandle, PrivKey> privKeys;
static std::map<KeyHandle, PubKey> pubKeys;
static std::map<KeyHandle, KeyCount> keyCounts;
};

View File

@@ -18,27 +18,26 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Streams.hpp"
#include "IO.hpp"
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
#include <fcntl.h>
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
#ifdef DEBUG_STREAMS
FILE* initHTML(FILE *fPtr, const string &title);
void closeHTML(FILE *fPtr);
FILE* initHTML(FILE* fPtr, const string& title);
void closeHTML(FILE* fPtr);
#endif
shared_ptr<int> getHostDescriptor()
{
shared_ptr<int> getHostDescriptor() {
static shared_ptr<int> descriptor{};
descriptor.reset(new int{ open(HID_DEV, O_RDWR | O_NONBLOCK | O_APPEND) }, [](int* fd){
close(*fd);
delete fd;
descriptor.reset(new int{ open(HID_DEV, O_RDWR | O_NONBLOCK | O_APPEND) }, [](int* fd) {
close(*fd);
delete fd;
});
if (*descriptor == -1)
@@ -48,12 +47,12 @@ shared_ptr<int> getHostDescriptor()
}
#ifdef DEBUG_STREAMS
shared_ptr<FILE> getComHostStream()
{
static shared_ptr<FILE> stream{ fopen((cacheDirectory + "comhost.txt").c_str(), "wb"), [](FILE *f){
clog << "Closing comhost stream" << endl;
fclose(f);
} };
shared_ptr<FILE> getComHostStream() {
static shared_ptr<FILE> stream{ fopen((cacheDirectory + "comhost.txt").c_str(), "wb"),
[](FILE* f) {
clog << "Closing comhost stream" << endl;
fclose(f);
} };
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -61,12 +60,14 @@ shared_ptr<FILE> getComHostStream()
return stream;
}
shared_ptr<FILE> getHostPacketStream()
{
static shared_ptr<FILE> stream{ initHTML(fopen((cacheDirectory + "hostpackets.html").c_str(), "wb"), "Host Packets"), [](FILE *f){
clog << "Closing hostPackets stream" << endl;
closeHTML(f);
} };
shared_ptr<FILE> getHostPacketStream() {
static shared_ptr<FILE> stream{
initHTML(fopen((cacheDirectory + "hostpackets.html").c_str(), "wb"), "Host Packets"),
[](FILE* f) {
clog << "Closing hostPackets stream" << endl;
closeHTML(f);
}
};
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -74,12 +75,14 @@ shared_ptr<FILE> getHostPacketStream()
return stream;
}
shared_ptr<FILE> getHostAPDUStream()
{
static shared_ptr<FILE> stream{ initHTML(fopen((cacheDirectory + "hostAPDU.html").c_str(), "wb"), "Host APDU"), [](FILE *f){
clog << "Closing host APDU stream" << endl;
closeHTML(f);
} };
shared_ptr<FILE> getHostAPDUStream() {
static shared_ptr<FILE> stream{
initHTML(fopen((cacheDirectory + "hostAPDU.html").c_str(), "wb"), "Host APDU"),
[](FILE* f) {
clog << "Closing host APDU stream" << endl;
closeHTML(f);
}
};
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -87,12 +90,12 @@ shared_ptr<FILE> getHostAPDUStream()
return stream;
}
shared_ptr<FILE> getComDevStream()
{
static shared_ptr<FILE> stream{ fopen((cacheDirectory + "comdev.txt").c_str(), "wb"), [](FILE *f){
clog << "Closing comdev stream" << endl;
fclose(f);
} };
shared_ptr<FILE> getComDevStream() {
static shared_ptr<FILE> stream{ fopen((cacheDirectory + "comdev.txt").c_str(), "wb"),
[](FILE* f) {
clog << "Closing comdev stream" << endl;
fclose(f);
} };
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -100,12 +103,14 @@ shared_ptr<FILE> getComDevStream()
return stream;
}
shared_ptr<FILE> getDevPacketStream()
{
static shared_ptr<FILE> stream{ initHTML(fopen((cacheDirectory + "devpackets.html").c_str(), "wb"), "Dev Packets"), [](FILE *f){
clog << "Closing devPackets stream" << endl;
closeHTML(f);
} };
shared_ptr<FILE> getDevPacketStream() {
static shared_ptr<FILE> stream{
initHTML(fopen((cacheDirectory + "devpackets.html").c_str(), "wb"), "Dev Packets"),
[](FILE* f) {
clog << "Closing devPackets stream" << endl;
closeHTML(f);
}
};
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -113,12 +118,13 @@ shared_ptr<FILE> getDevPacketStream()
return stream;
}
shared_ptr<FILE> getDevAPDUStream()
{
static shared_ptr<FILE> stream{ initHTML(fopen((cacheDirectory + "devAPDU.html").c_str(), "wb"), "Dev APDU"), [](FILE *f){
clog << "Closing dev APDU stream" << endl;
closeHTML(f);
} };
shared_ptr<FILE> getDevAPDUStream() {
static shared_ptr<FILE> stream{ initHTML(fopen((cacheDirectory + "devAPDU.html").c_str(), "wb"),
"Dev APDU"),
[](FILE* f) {
clog << "Closing dev APDU stream" << endl;
closeHTML(f);
} };
if (!stream)
clog << "Stream is unavailable" << endl;
@@ -126,54 +132,54 @@ shared_ptr<FILE> getDevAPDUStream()
return stream;
}
FILE* initHTML(FILE *fPtr, const string &title)
{
fprintf(fPtr, "<html>\n"
"\t<head>\n"
"\t\t<title>%s</title>\n"
"\t\t<style>\n"
"\t\t\ttable {\n"
"\t\t\t\tdisplay: table;\n"
"\t\t\t\twidth: 100%%;\n"
"\t\t\t\tborder-collapse: collapse;\n"
"\t\t\t\tbox-sizing: border-box;\n"
"\t\t\t}\n"
"\n"
"\t\t\tth.data {\n"
"\t\t\t\ttext-align: left;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd {\n"
"\t\t\t\tfont-family: \"Courier New\", Courier, monospace;\n"
"\t\t\t\twhite-space: pre;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd.data {\n"
"\t\t\t\toverflow: hidden;\n"
"\t\t\t\ttext-overflow: ellipsis;\n"
"\t\t\t\tmax-width:1px;\n"
"\t\t\t\twidth:100%%;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd.data:hover {\n"
"\t\t\t\twhite-space: pre-wrap;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttable, th, td {\n"
"\t\t\t\tborder: 1px solid black;\n"
"\t\t\t}\n"
"\t\t</style>\n"
"\t</head>\n"
"\n"
"\t<body>", title.c_str());
FILE* initHTML(FILE* fPtr, const string& title) {
fprintf(fPtr,
"<html>\n"
"\t<head>\n"
"\t\t<title>%s</title>\n"
"\t\t<style>\n"
"\t\t\ttable {\n"
"\t\t\t\tdisplay: table;\n"
"\t\t\t\twidth: 100%%;\n"
"\t\t\t\tborder-collapse: collapse;\n"
"\t\t\t\tbox-sizing: border-box;\n"
"\t\t\t}\n"
"\n"
"\t\t\tth.data {\n"
"\t\t\t\ttext-align: left;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd {\n"
"\t\t\t\tfont-family: \"Courier New\", Courier, monospace;\n"
"\t\t\t\twhite-space: pre;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd.data {\n"
"\t\t\t\toverflow: hidden;\n"
"\t\t\t\ttext-overflow: ellipsis;\n"
"\t\t\t\tmax-width:1px;\n"
"\t\t\t\twidth:100%%;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttd.data:hover {\n"
"\t\t\t\twhite-space: pre-wrap;\n"
"\t\t\t}\n"
"\n"
"\t\t\ttable, th, td {\n"
"\t\t\t\tborder: 1px solid black;\n"
"\t\t\t}\n"
"\t\t</style>\n"
"\t</head>\n"
"\n"
"\t<body>",
title.c_str());
return fPtr;
}
void closeHTML(FILE *fPtr)
{
void closeHTML(FILE* fPtr) {
fprintf(fPtr, "\t</body>\n"
"</html>");
"</html>");
fclose(fPtr);
}
#endif

View File

@@ -17,11 +17,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "Architecture.hpp"
#include <cstdio>
#include <memory>
#include "Architecture.hpp"
std::shared_ptr<int> getHostDescriptor();
std::shared_ptr<int> getHostDescriptor();
#ifdef DEBUG_STREAMS
std::shared_ptr<FILE> getComHostStream();

View File

@@ -17,11 +17,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "Architecture.hpp"
#include <iostream>
#include "Storage.hpp"
#include "Controller.hpp"
#include "LED.hpp"
#include "Storage.hpp"
#include <csignal>
#include <iostream>
#include <unistd.h>
using namespace std;
@@ -31,13 +31,10 @@ void signalCallback(int signum);
volatile bool contProc = true;
bool initialiseLights(const string& prog) {
try
{
try {
disableACTTrigger(true);
enableACTLED(false);
}
catch (runtime_error &e)
{
} catch (runtime_error& e) {
cerr << e.what() << endl;
return false;
@@ -46,20 +43,15 @@ bool initialiseLights(const string& prog) {
return true;
}
int handleTransactions(const string& prog, const string& privKeyDir)
{
int handleTransactions(const string& prog, const string& privKeyDir) {
signal(SIGINT, signalCallback);
Storage::init(privKeyDir);
Controller ch{ 0xF1D00000 };
while (contProc)
{
try
{
while (contProc) {
try {
ch.handleTransaction();
}
catch (const runtime_error &e)
{
} catch (const runtime_error& e) {
cerr << e.what() << endl;
raise(SIGINT);
@@ -73,13 +65,10 @@ int handleTransactions(const string& prog, const string& privKeyDir)
}
bool deinitialiseLights(const string& prog) {
try
{
try {
disableACTTrigger(false);
enableACTLED(true);
}
catch (runtime_error &e)
{
} catch (runtime_error& e) {
cerr << e.what() << endl;
return false;
@@ -88,8 +77,7 @@ bool deinitialiseLights(const string& prog) {
return true;
}
void signalCallback([[maybe_unused]] int signum)
{
void signalCallback([[maybe_unused]] int signum) {
contProc = false;
clog << "\nClosing" << endl;
}

View File

@@ -24,4 +24,3 @@ extern volatile bool contProc;
bool initialiseLights(const std::string& prog);
bool deinitialiseLights(const std::string& prog);
int handleTransactions(const std::string& prog, const std::string& privKeyDir);

View File

@@ -17,37 +17,34 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2FMessage.hpp"
#include "IO.hpp"
#include "Packet.hpp"
#include <stdexcept>
#include <iostream>
#include <iomanip>
#include "Streams.hpp"
#include "u2f.hpp"
#include "IO.hpp"
#include <iomanip>
#include <iostream>
#include <stdexcept>
using namespace std;
shared_ptr<U2FMessage> U2FMessage::readNonBlock()
{
const static size_t startSeq = (size_t)-1ull;
static size_t currSeq = startSeq;
static uint16_t messageSize;
static uint32_t cid;
static uint8_t cmd;
shared_ptr<U2FMessage> U2FMessage::readNonBlock() {
const static size_t startSeq = (size_t)-1ull;
static size_t currSeq = startSeq;
static uint16_t messageSize;
static uint32_t cid;
static uint8_t cmd;
static vector<uint8_t> dataBytes;
shared_ptr<Packet> p{};
if (currSeq == startSeq)
{
if (currSeq == startSeq) {
cid = 0;
cmd = 0;
messageSize = 0;
dataBytes = {};
shared_ptr<InitPacket> initPack{};
do
{
do {
p = Packet::getPacket();
if (!p)
@@ -59,43 +56,46 @@ shared_ptr<U2FMessage> U2FMessage::readNonBlock()
if (!initPack)
cerr << "Spurious cont. packet" << endl;
#endif
} while (!initPack); //Spurious cont. packet - spec states ignore
} while (!initPack); // Spurious cont. packet - spec states ignore
messageSize = ((static_cast<uint16_t>(initPack->bcnth) << 8u) + initPack->bcntl);
const uint16_t copyByteCount = min(static_cast<uint16_t>(initPack->data.size()), messageSize);
const uint16_t copyByteCount =
min(static_cast<uint16_t>(initPack->data.size()), messageSize);
cid = initPack->cid;
cmd = initPack->cmd;
copy(initPack->data.begin(), initPack->data.begin() + copyByteCount, back_inserter(dataBytes));
copy(initPack->data.begin(), initPack->data.begin() + copyByteCount,
back_inserter(dataBytes));
currSeq = 0;
}
while (messageSize > dataBytes.size() && static_cast<bool>(p = Packet::getPacket())) //While there is a packet
while (messageSize > dataBytes.size() &&
static_cast<bool>(p = Packet::getPacket())) // While there is a packet
{
auto contPack = dynamic_pointer_cast<ContPacket>(p);
if (!contPack) //Spurious init. packet
if (!contPack) // Spurious init. packet
{
#ifdef DEBUG_MSGS
cerr << "Spurious init. packet" << endl;
#endif
currSeq = startSeq; //Reset
currSeq = startSeq; // Reset
return {};
}
if (contPack->cid != cid) //Cont. packet of different CID
if (contPack->cid != cid) // Cont. packet of different CID
{
#ifdef DEBUG_MSGS
cerr << "Invalid CID: was handling channel 0x" << hex << cid << " and received packet from channel 0x" << contPack->cid << dec << endl;
cerr << "Invalid CID: was handling channel 0x" << hex << cid
<< " and received packet from channel 0x" << contPack->cid << dec << endl;
#endif
U2FMessage::error(contPack->cid, ERR_CHANNEL_BUSY);
currSeq = startSeq;
return {};
}
if (contPack->seq != currSeq)
{
if (contPack->seq != currSeq) {
#ifdef DEBUG_MSGS
cerr << "Invalid packet seq. value" << endl;
#endif
@@ -105,15 +105,18 @@ shared_ptr<U2FMessage> U2FMessage::readNonBlock()
}
const uint16_t remainingBytes = messageSize - dataBytes.size();
const uint16_t copyBytes = min(static_cast<uint16_t>(contPack->data.size()), remainingBytes);
const uint16_t copyBytes =
min(static_cast<uint16_t>(contPack->data.size()), remainingBytes);
dataBytes.insert(dataBytes.end(), contPack->data.begin(), contPack->data.begin() + copyBytes);
dataBytes.insert(dataBytes.end(), contPack->data.begin(),
contPack->data.begin() + copyBytes);
currSeq++;
}
if (messageSize != dataBytes.size()) {
#ifdef DEBUG_MSGS
cerr << "Invalid message size: " << messageSize << " when received " << dataBytes.size() << endl;
cerr << "Invalid message size: " << messageSize << " when received " << dataBytes.size()
<< endl;
#endif
return {};
}
@@ -125,8 +128,7 @@ shared_ptr<U2FMessage> U2FMessage::readNonBlock()
return message;
}
void U2FMessage::write()
{
void U2FMessage::write() {
const uint16_t bytesToWrite = this->data.size();
uint16_t bytesWritten = 0;
@@ -141,7 +143,8 @@ void U2FMessage::write()
p.bcntl = bcntl;
{
uint16_t initialByteCount = min(static_cast<uint16_t>(p.data.size()), static_cast<uint16_t>(bytesToWrite - bytesWritten));
uint16_t initialByteCount = min(static_cast<uint16_t>(p.data.size()),
static_cast<uint16_t>(bytesToWrite - bytesWritten));
copy(data.begin(), data.begin() + initialByteCount, p.data.begin());
bytesWritten += initialByteCount;
}
@@ -151,58 +154,57 @@ void U2FMessage::write()
uint8_t seq = 0;
while (bytesWritten != bytesToWrite)
{
while (bytesWritten != bytesToWrite) {
ContPacket p{};
p.cid = cid;
p.seq = seq;
uint16_t newByteCount = min(static_cast<uint16_t>(p.data.size()), static_cast<uint16_t>(bytesToWrite - bytesWritten));
copy(data.begin() + bytesWritten, data.begin() + bytesWritten + newByteCount, p.data.begin());
uint16_t newByteCount = min(static_cast<uint16_t>(p.data.size()),
static_cast<uint16_t>(bytesToWrite - bytesWritten));
copy(data.begin() + bytesWritten, data.begin() + bytesWritten + newByteCount,
p.data.begin());
p.writePacket();
seq++;
bytesWritten += newByteCount;
}
if (cmd == U2FHID_MSG)
{
if (cmd == U2FHID_MSG) {
#ifdef DEBUG_STREAMS
auto dAS = getDevAPDUStream().get();
fprintf(dAS, "<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>DATA</th>\n"
"\t\t\t\t\t<th>ERR</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td class=\"data\">");
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>DATA</th>\n"
"\t\t\t\t\t<th>ERR</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td class=\"data\">");
for (size_t i = 0; i < data.size() - 2; i++)
fprintf(dAS, "%3u ", data[i]);
#endif
uint16_t err = data[data.size() - 2] << 8;
err |= data.back();
#ifdef DEBUG_STREAMS
fprintf(dAS, "</td>\n"
"\t\t\t\t\t<td>0x%04X</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />", err);
fprintf(dAS,
"</td>\n"
"\t\t\t\t\t<td>0x%04X</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />",
err);
#endif
}
}
U2FMessage::U2FMessage(const uint32_t nCID, const uint8_t nCMD)
: cid{ nCID }, cmd{ nCMD }
{}
U2FMessage::U2FMessage(const uint32_t nCID, const uint8_t nCMD) : cid{ nCID }, cmd{ nCMD } {}
void U2FMessage::error(const uint32_t tCID, const uint8_t tErr)
{
void U2FMessage::error(const uint32_t tCID, const uint8_t tErr) {
U2FMessage msg{};
msg.cid = tCID;
msg.cmd = U2FHID_ERROR;

View File

@@ -18,21 +18,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include <cstdint>
#include <vector>
#include <memory>
#include <cstdint>
#include <vector>
struct U2FMessage
{
public:
uint32_t cid;
uint8_t cmd;
std::vector<uint8_t> data;
struct U2FMessage {
public:
uint32_t cid;
uint8_t cmd;
std::vector<uint8_t> data;
public:
U2FMessage() = default;
U2FMessage(const uint32_t nCID, const uint8_t nCMD);
static std::shared_ptr<U2FMessage> readNonBlock();
void write();
static void error(const uint32_t tCID, const uint8_t tErr);
public:
U2FMessage() = default;
U2FMessage(const uint32_t nCID, const uint8_t nCMD);
static std::shared_ptr<U2FMessage> readNonBlock();
void write();
static void error(const uint32_t tCID, const uint8_t tErr);
};

View File

@@ -17,33 +17,29 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2F_Authenticate_APDU.hpp"
#include "Field.hpp"
#include "U2FMessage.hpp"
#include "u2f.hpp"
#include "Field.tpp"
#include "APDU.hpp"
#include <iostream>
#include "Field.hpp"
#include "Field.tpp"
#include "Signature.hpp"
#include "U2FMessage.hpp"
#include "micro-ecc/uECC.h"
#include "u2f.hpp"
#include <iostream>
#include <mbedtls/sha256.h>
using namespace std;
U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vector<uint8_t> &data)
: U2F_Msg_CMD{ msg }
{
if (p2 != 0)
{
//Invalid U2F (APDU) parameter detected
U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD& msg, const vector<uint8_t>& data)
: U2F_Msg_CMD{ msg } {
if (p2 != 0) {
// Invalid U2F (APDU) parameter detected
throw APDU_STATUS::SW_CONDITIONS_NOT_SATISFIED;
}
else if (data.size() < 66)
{
//Invalid authentication request
} else if (data.size() < 66) {
// Invalid authentication request
throw APDU_STATUS::SW_WRONG_LENGTH;
}
copy(data.begin() + 0, data.begin() + 32, challengeP.begin());
copy(data.begin() + 0, data.begin() + 32, challengeP.begin());
copy(data.begin() + 32, data.begin() + 64, appParam.begin());
uint8_t keyHLen = data[64];
@@ -51,21 +47,18 @@ U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vecto
copy(data.begin() + 65, data.begin() + 65 + keyHLen, back_inserter(keyH));
}
void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
{
if (keyH.size() != sizeof(Storage::KeyHandle))
{
//Respond with error code - key handle is of wrong size
void U2F_Authenticate_APDU::respond(const uint32_t channelID) const {
if (keyH.size() != sizeof(Storage::KeyHandle)) {
// Respond with error code - key handle is of wrong size
cerr << "Invalid key handle length" << endl;
this->error(channelID, APDU_STATUS::SW_WRONG_DATA);
return;
}
auto keyHB = *reinterpret_cast<const Storage::KeyHandle*>(keyH.data());
if (Storage::appParams.find(keyHB) == Storage::appParams.end())
{
//Respond with error code - key handle doesn't exist in storage
if (Storage::appParams.find(keyHB) == Storage::appParams.end()) {
// Respond with error code - key handle doesn't exist in storage
cerr << "Invalid key handle" << endl;
this->error(channelID, SW_WRONG_DATA);
return;
@@ -77,11 +70,10 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
msg.cid = channelID;
msg.cmd = U2FHID_MSG;
auto &response = msg.data;
auto& response = msg.data;
APDU_STATUS statusCode = APDU_STATUS::SW_NO_ERROR;
switch (p1)
{
switch (p1) {
case ControlCode::CheckOnly:
if (appMatches)
statusCode = APDU_STATUS::SW_CONDITIONS_NOT_SATISFIED;
@@ -92,9 +84,9 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
msg.write();
return;
case ControlCode::EnforcePresenceSign:
//Continue processing
// Continue processing
case ControlCode::DontEnforcePresenceSign:
//Continue processing
// Continue processing
break;
default:
@@ -104,7 +96,7 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
}
const auto& privKey = Storage::privKeys[keyHB];
auto& keyCount = Storage::keyCounts[keyHB];
auto& keyCount = Storage::keyCounts[keyHB];
keyCount++;
response.push_back(0x01);
@@ -117,7 +109,8 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
mbedtls_sha256_init(&shaContext);
mbedtls_sha256_starts(&shaContext, 0);
mbedtls_sha256_update(&shaContext, reinterpret_cast<const uint8_t *>(appParam.data()), sizeof(appParam));
mbedtls_sha256_update(&shaContext, reinterpret_cast<const uint8_t*>(appParam.data()),
sizeof(appParam));
uint8_t userPresence{ 1u };
mbedtls_sha256_update(&shaContext, &userPresence, 1);
const auto beCounter = beEncode(keyCount);

View File

@@ -17,23 +17,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "U2F_Msg_CMD.hpp"
#include "Storage.hpp"
#include "U2F_Msg_CMD.hpp"
struct U2F_Authenticate_APDU : U2F_Msg_CMD
{
struct U2F_Authenticate_APDU : U2F_Msg_CMD {
uint8_t controlByte;
std::array<uint8_t, 32> challengeP;
Storage::AppParam appParam;
std::vector<uint8_t> keyH;
Storage::AppParam appParam;
std::vector<uint8_t> keyH;
public:
U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const std::vector<uint8_t> &data);
public:
U2F_Authenticate_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data);
virtual void respond(const uint32_t channelID) const override;
virtual void respond(const uint32_t channelID) const override;
enum ControlCode
{
enum ControlCode {
CheckOnly = 0x07,
EnforcePresenceSign = 0x03,
DontEnforcePresenceSign = 0x08

View File

@@ -17,19 +17,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2F_CMD.hpp"
#include "u2f.hpp"
#include "U2F_Msg_CMD.hpp"
#include "U2F_Init_CMD.hpp"
#include "U2F_Msg_CMD.hpp"
#include "U2F_Ping_CMD.hpp"
#include "u2f.hpp"
using namespace std;
shared_ptr<U2F_CMD> U2F_CMD::get(const U2FMessage& uMsg)
{
try
{
switch (uMsg.cmd)
{
shared_ptr<U2F_CMD> U2F_CMD::get(const U2FMessage& uMsg) {
try {
switch (uMsg.cmd) {
case U2FHID_PING:
return make_shared<U2F_Ping_CMD>(uMsg);
case U2FHID_MSG:
@@ -40,9 +37,7 @@ shared_ptr<U2F_CMD> U2F_CMD::get(const U2FMessage& uMsg)
U2FMessage::error(uMsg.cid, ERR_INVALID_CMD);
return {};
}
}
catch (runtime_error& ignored)
{
} catch (runtime_error& ignored) {
U2FMessage::error(uMsg.cid, ERR_OTHER);
return {};
}

View File

@@ -17,16 +17,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <memory>
#include "U2FMessage.hpp"
#include <memory>
struct U2F_CMD
{
protected:
U2F_CMD() = default;
struct U2F_CMD {
protected:
U2F_CMD() = default;
public:
virtual ~U2F_CMD() = default;
static std::shared_ptr<U2F_CMD> get(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const = 0;
}; //For polymorphic type casting
public:
virtual ~U2F_CMD() = default;
static std::shared_ptr<U2F_CMD> get(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const = 0;
}; // For polymorphic type casting

View File

@@ -17,23 +17,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2F_Init_CMD.hpp"
#include <stdexcept>
#include "u2f.hpp"
#include "Field.hpp"
#include "u2f.hpp"
#include <stdexcept>
using namespace std;
U2F_Init_CMD::U2F_Init_CMD(const U2FMessage& uMsg)
{
U2F_Init_CMD::U2F_Init_CMD(const U2FMessage& uMsg) {
if (uMsg.cmd != U2FHID_INIT)
throw runtime_error{ "Failed to get U2F Init message" };
else if (uMsg.cid != CID_BROADCAST)
{
else if (uMsg.cid != CID_BROADCAST) {
U2FMessage::error(uMsg.cid, ERR_OTHER);
throw runtime_error{ "Invalid CID for init command" };
}
else if (uMsg.data.size() != INIT_NONCE_SIZE)
{
} else if (uMsg.data.size() != INIT_NONCE_SIZE) {
U2FMessage::error(uMsg.cid, ERR_INVALID_LEN);
throw runtime_error{ "Init nonce is incorrect size" };
}
@@ -41,19 +37,18 @@ U2F_Init_CMD::U2F_Init_CMD(const U2FMessage& uMsg)
this->nonce = *reinterpret_cast<const uint64_t*>(uMsg.data.data());
}
void U2F_Init_CMD::respond(const uint32_t channelID) const
{
void U2F_Init_CMD::respond(const uint32_t channelID) const {
U2FMessage msg{};
msg.cid = CID_BROADCAST;
msg.cmd = U2FHID_INIT;
msg.data.insert(msg.data.end(), FIELD(this->nonce));
msg.data.insert(msg.data.end(), FIELD(channelID));
msg.data.push_back(2); //Protocol version
msg.data.push_back(1); //Major device version
msg.data.push_back(0); //Minor device version
msg.data.push_back(1); //Build device version
msg.data.push_back(CAPFLAG_WINK); //Wink capability
msg.data.push_back(2); // Protocol version
msg.data.push_back(1); // Major device version
msg.data.push_back(0); // Minor device version
msg.data.push_back(1); // Build device version
msg.data.push_back(CAPFLAG_WINK); // Wink capability
msg.write();
}

View File

@@ -17,16 +17,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "U2FMessage.hpp"
#include "U2F_CMD.hpp"
#include <cstdint>
#include <memory>
#include "U2F_CMD.hpp"
#include "U2FMessage.hpp"
struct U2F_Init_CMD : U2F_CMD
{
struct U2F_Init_CMD : U2F_CMD {
uint64_t nonce;
public:
U2F_Init_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
public:
U2F_Init_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
};

View File

@@ -18,119 +18,99 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "U2F_Msg_CMD.hpp"
#include "APDU.hpp"
#include "Field.hpp"
#include "Streams.hpp"
#include "U2FMessage.hpp"
#include "U2F_Authenticate_APDU.hpp"
#include "U2F_Register_APDU.hpp"
#include "U2F_Version_APDU.hpp"
#include "U2F_Authenticate_APDU.hpp"
#include "U2FMessage.hpp"
#include "u2f.hpp"
#include "APDU.hpp"
#include <iostream>
#include "Streams.hpp"
#include "Field.hpp"
using namespace std;
uint32_t U2F_Msg_CMD::getLe(const uint32_t byteCount, vector<uint8_t> bytes)
{
if (byteCount != 0)
{
//Le must be length of data in bytes
uint32_t U2F_Msg_CMD::getLe(const uint32_t byteCount, vector<uint8_t> bytes) {
if (byteCount != 0) {
// Le must be length of data in bytes
switch (byteCount)
{
switch (byteCount) {
case 1:
return (bytes[0] == 0 ? 256 : bytes[0]);
case 2:
//Don't handle non-compliance with spec here
//This case is only possible if extended Lc used
//CBA
// Don't handle non-compliance with spec here
// This case is only possible if extended Lc used
// CBA
return (bytes[0] == 0 && bytes[1] == 0 ? 65536 : (bytes[0] << 8) + bytes[1]);
case 3:
//Don't handle non-compliance with spec here
//This case is only possible if extended Lc not used
//CBA
// Don't handle non-compliance with spec here
// This case is only possible if extended Lc not used
// CBA
if (bytes[0] != 0)
throw runtime_error{ "First byte of 3-byte Le should be 0"};
throw runtime_error{ "First byte of 3-byte Le should be 0" };
return (bytes[1] == 0 && bytes[2] == 0 ? 65536 : (bytes[1] << 8) + bytes[2]);
default:
throw runtime_error{ "Too much data for command" };
}
}
else
} else
return 0;
}
shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
{
shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg) {
if (uMsg.cmd != U2FHID_MSG)
throw runtime_error{ "Failed to get U2F Msg uMsg" };
else if (uMsg.data.size() < 4)
{
else if (uMsg.data.size() < 4) {
U2F_Msg_CMD::error(uMsg.cid, APDU_STATUS::SW_WRONG_LENGTH);
throw runtime_error{ "Msg data is incorrect size" };
}
U2F_Msg_CMD cmd;
auto &dat = uMsg.data;
auto& dat = uMsg.data;
cmd.cla = dat[0];
if (cmd.cla != 0)
{
if (cmd.cla != 0) {
U2F_Msg_CMD::error(uMsg.cid, APDU_STATUS::SW_COMMAND_NOT_ALLOWED);
throw runtime_error{ "Invalid CLA value in U2F Message" };
}
cmd.ins = dat[1];
cmd.p1 = dat[2];
cmd.p2 = dat[3];
cmd.p1 = dat[2];
cmd.p2 = dat[3];
vector<uint8_t> data{ dat.begin() + 4, dat.end() };
const uint32_t cBCount = data.size();
auto startPtr = data.begin(), endPtr = data.end();
if (usesData.at(cmd.ins) || data.size() > 3)
{
if (cBCount == 0)
{
if (usesData.at(cmd.ins) || data.size() > 3) {
if (cBCount == 0) {
U2F_Msg_CMD::error(uMsg.cid, APDU_STATUS::SW_WRONG_LENGTH);
throw runtime_error{ "Invalid command - should have attached data" };
}
if (data[0] != 0) //1 byte length
if (data[0] != 0) // 1 byte length
{
cmd.lc = data[0];
startPtr++;
}
else
{
} else {
cmd.lc = (data[1] << 8) + data[2];
startPtr += 3;
}
endPtr = startPtr + cmd.lc;
try
{
try {
cmd.le = getLe(data.end() - endPtr, vector<uint8_t>(endPtr, data.end()));
}
catch (runtime_error& ignored)
{
} catch (runtime_error& ignored) {
U2F_Msg_CMD::error(uMsg.cid, APDU_STATUS::SW_WRONG_LENGTH);
throw;
}
}
else
{
} else {
cmd.lc = 0;
endPtr = startPtr;
try
{
try {
cmd.le = getLe(cBCount, data);
}
catch (runtime_error& ignored)
{
} catch (runtime_error& ignored) {
U2F_Msg_CMD::error(uMsg.cid, APDU_STATUS::SW_WRONG_LENGTH);
throw;
}
@@ -141,42 +121,44 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
#ifdef DEBUG_STREAMS
auto hAS = getHostAPDUStream().get();
fprintf(hAS, "<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CLA</th>\n"
"\t\t\t\t\t<th>INS</th>\n"
"\t\t\t\t\t<th>P1</th>\n"
"\t\t\t\t\t<th>P2</th>\n"
"\t\t\t\t\t<th>Lc</th>\n"
"\t\t\t\t\t<th>Data</th>\n"
"\t\t\t\t\t<th>Le</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%02X</td>\n"
"\t\t\t\t\t<td>0x%02X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%3u</td>\n"
"\t\t\t\t\t<td class=\"data\">", cmd.cla, cmd.ins, cmd.p1, cmd.p2, cmd.lc);
fprintf(hAS,
"<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CLA</th>\n"
"\t\t\t\t\t<th>INS</th>\n"
"\t\t\t\t\t<th>P1</th>\n"
"\t\t\t\t\t<th>P2</th>\n"
"\t\t\t\t\t<th>Lc</th>\n"
"\t\t\t\t\t<th>Data</th>\n"
"\t\t\t\t\t<th>Le</th>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</thead>\n"
"\t\t\t<tbody>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<td>0x%02X</td>\n"
"\t\t\t\t\t<td>0x%02X</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%u</td>\n"
"\t\t\t\t\t<td>%3u</td>\n"
"\t\t\t\t\t<td class=\"data\">",
cmd.cla, cmd.ins, cmd.p1, cmd.p2, cmd.lc);
for (auto b : dBytes)
fprintf(hAS, "%3u ", b);
fprintf(hAS, "</td>\n"
"\t\t\t\t\t<td>%5u</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />", cmd.le);
fprintf(hAS,
"</td>\n"
"\t\t\t\t\t<td>%5u</td>\n"
"\t\t\t\t</tr>\n"
"\t\t\t</tbody>\n"
"\t\t</table>\n"
"\t\t<br />",
cmd.le);
#endif
try
{
switch (cmd.ins)
{
try {
switch (cmd.ins) {
case APDU::U2F_REG:
return make_shared<U2F_Register_APDU>(cmd, dBytes);
case APDU::U2F_AUTH:
@@ -187,17 +169,14 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
cerr << "Invalid command used" << endl;
throw APDU_STATUS::SW_INS_NOT_SUPPORTED;
}
}
catch (const APDU_STATUS e)
{
} catch (const APDU_STATUS e) {
U2F_Msg_CMD::error(uMsg.cid, e);
throw runtime_error{ "APDU construction error" };
return {};
}
}
void U2F_Msg_CMD::error(const uint32_t channelID, const uint16_t errCode)
{
void U2F_Msg_CMD::error(const uint32_t channelID, const uint16_t errCode) {
clog << "U2F_Msg_CMD::error " << errCode << endl;
U2FMessage msg{};
msg.cid = channelID;
@@ -206,13 +185,10 @@ void U2F_Msg_CMD::error(const uint32_t channelID, const uint16_t errCode)
msg.write();
}
const map<uint8_t, bool> U2F_Msg_CMD::usesData = {
{ U2F_REG, true },
{ U2F_AUTH, true },
{ U2F_VER, false }
};
const map<uint8_t, bool> U2F_Msg_CMD::usesData = { { U2F_REG, true },
{ U2F_AUTH, true },
{ U2F_VER, false } };
void U2F_Msg_CMD::respond(const uint32_t channelID) const
{
void U2F_Msg_CMD::respond(const uint32_t channelID) const {
U2F_Msg_CMD::error(channelID, static_cast<uint16_t>(APDU_STATUS::SW_INS_NOT_SUPPORTED));
}

View File

@@ -20,27 +20,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "U2F_CMD.hpp"
#include <cstdint>
#include <map>
#include <vector>
#include <memory>
#include <vector>
struct U2F_Msg_CMD : U2F_CMD
{
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
struct U2F_Msg_CMD : U2F_CMD {
uint8_t cla;
uint8_t ins;
uint8_t p1;
uint8_t p2;
uint32_t lc;
uint32_t le;
const static std::map<uint8_t, bool> usesData;
protected:
static uint32_t getLe(const uint32_t byteCount, std::vector<uint8_t> bytes);
U2F_Msg_CMD() = default;
protected:
static uint32_t getLe(const uint32_t byteCount, std::vector<uint8_t> bytes);
U2F_Msg_CMD() = default;
public:
static std::shared_ptr<U2F_Msg_CMD> generate(const U2FMessage& uMsg);
static void error(const uint32_t channelID, const uint16_t errCode);
void respond(const uint32_t channelID) const;
public:
static std::shared_ptr<U2F_Msg_CMD> generate(const U2FMessage& uMsg);
static void error(const uint32_t channelID, const uint16_t errCode);
void respond(const uint32_t channelID) const;
};

View File

@@ -21,15 +21,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std;
U2F_Ping_CMD::U2F_Ping_CMD(const U2FMessage& uMsg)
: nonce{ uMsg.data }
{
U2F_Ping_CMD::U2F_Ping_CMD(const U2FMessage& uMsg) : nonce{ uMsg.data } {
if (uMsg.cmd != U2FHID_PING)
throw runtime_error{ "Failed to get U2F ping message" };
}
void U2F_Ping_CMD::respond(const uint32_t channelID) const
{
void U2F_Ping_CMD::respond(const uint32_t channelID) const {
U2FMessage msg{};
msg.cid = channelID;
msg.cmd = U2FHID_PING;

View File

@@ -17,16 +17,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "U2FMessage.hpp"
#include "U2F_CMD.hpp"
#include <cstdint>
#include <memory>
#include "U2F_CMD.hpp"
#include "U2FMessage.hpp"
struct U2F_Ping_CMD : U2F_CMD
{
struct U2F_Ping_CMD : U2F_CMD {
std::vector<uint8_t> nonce;
public:
U2F_Ping_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
public:
U2F_Ping_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
};

View File

@@ -17,73 +17,69 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2F_Register_APDU.hpp"
#include <exception>
#include <cstring>
#include "micro-ecc/uECC.h"
#include "Certificates.hpp"
#include <mbedtls/sha256.h>
#include <iostream>
#include "APDU.hpp"
#include "U2FMessage.hpp"
#include "u2f.hpp"
#include "Certificates.hpp"
#include "Signature.hpp"
#include "U2FMessage.hpp"
#include "micro-ecc/uECC.h"
#include "u2f.hpp"
#include <cstring>
#include <exception>
#include <iostream>
#include <mbedtls/sha256.h>
using namespace std;
U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD &msg, const vector<uint8_t> &data)
: U2F_Msg_CMD{ msg }
{
if (data.size() != 64)
{
//Incorrect registration size
U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD& msg, const vector<uint8_t>& data)
: U2F_Msg_CMD{ msg } {
if (data.size() != 64) {
// Incorrect registration size
throw APDU_STATUS::SW_WRONG_LENGTH;
}
else if ((p1 != 0x00 && p1 != 0x03) || p2 != 0x00) //According to spec, 0x03 not allowed here
//However, browsers seem to do it, so...
} else if ((p1 != 0x00 && p1 != 0x03) || p2 != 0x00) // According to spec, 0x03 not allowed here
// However, browsers seem to do it, so...
{
//Invalid U2F Message (APDU) parameters detected
// Invalid U2F Message (APDU) parameters detected
throw APDU_STATUS::SW_INS_NOT_SUPPORTED;
}
copy(data.data() + 0, data.data() + 32, challengeP.begin());
copy(data.data() + 0, data.data() + 32, challengeP.begin());
copy(data.data() + 32, data.data() + 64, appP.begin());
//Use crypto lib to generate keypair
// Use crypto lib to generate keypair
Storage::PrivKey privKey{};
Storage::PubKey pubKey{};
//First byte must be 0x04 for some reason
// First byte must be 0x04 for some reason
pubKey[0] = 0x04;
uECC_make_key(pubKey.data() + 1, privKey.data(), uECC_secp256r1());
this->keyH = Storage::appParams.size(); //To increment the key handle
this->keyH = Storage::appParams.size(); // To increment the key handle
Storage::appParams[this->keyH] = appP;
Storage::privKeys[this->keyH] = privKey;
Storage::pubKeys[this->keyH] = pubKey;
Storage::privKeys[this->keyH] = privKey;
Storage::pubKeys[this->keyH] = pubKey;
Storage::keyCounts[this->keyH] = 0;
}
void U2F_Register_APDU::respond(const uint32_t channelID) const
{
void U2F_Register_APDU::respond(const uint32_t channelID) const {
U2FMessage m{};
m.cid = channelID;
m.cmd = U2FHID_MSG;
auto& response = m.data;
const auto appParam = Storage::appParams[this->keyH];
const auto pubKey = Storage::pubKeys[this->keyH];
const auto pubKey = Storage::pubKeys[this->keyH];
response.push_back(0x05);
copy(pubKey.begin(), pubKey.end(), back_inserter(response));
response.push_back(sizeof(this->keyH));
auto fakeKeyHBytes = reinterpret_cast<const uint8_t *>(&this->keyH);
auto fakeKeyHBytes = reinterpret_cast<const uint8_t*>(&this->keyH);
copy(fakeKeyHBytes, fakeKeyHBytes + sizeof(this->keyH), back_inserter(response));
copy(attestCert, end(attestCert), back_inserter(response));
//Gen signature
// Gen signature
Digest digest;
{
mbedtls_sha256_context shaContext;
@@ -94,13 +90,18 @@ void U2F_Register_APDU::respond(const uint32_t channelID) const
uint8_t byteReserved = 0;
mbedtls_sha256_update(&shaContext, reinterpret_cast<unsigned char*>(&byteReserved), 1);
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(appParam.data()), appParam.size());
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(appParam.data()),
appParam.size());
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(challengeP.data()), challengeP.size());
mbedtls_sha256_update(&shaContext,
reinterpret_cast<const unsigned char*>(challengeP.data()),
challengeP.size());
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(&keyH), sizeof(keyH));
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(&keyH),
sizeof(keyH));
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(pubKey.data()), pubKey.size());
mbedtls_sha256_update(&shaContext, reinterpret_cast<const unsigned char*>(pubKey.data()),
pubKey.size());
mbedtls_sha256_finish(&shaContext, digest.data());
mbedtls_sha256_free(&shaContext);
@@ -109,7 +110,7 @@ void U2F_Register_APDU::respond(const uint32_t channelID) const
Signature signature;
uECC_sign(attestPrivKey, digest.data(), digest.size(), signature.data(), uECC_secp256r1());
//Append signature as DER
// Append signature as DER
appendSignatureAsDER(response, signature);
response.push_back(static_cast<uint16_t>(APDU_STATUS::SW_NO_ERROR) >> 8);

View File

@@ -17,18 +17,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "U2F_Msg_CMD.hpp"
#include "Storage.hpp"
#include "U2F_Msg_CMD.hpp"
struct U2F_Register_APDU : U2F_Msg_CMD
{
struct U2F_Register_APDU : U2F_Msg_CMD {
std::array<uint8_t, 32> challengeP;
Storage::AppParam appP;
Storage::KeyHandle keyH;
Storage::AppParam appP;
Storage::KeyHandle keyH;
public:
U2F_Register_APDU(const U2F_Msg_CMD &msg, const std::vector<uint8_t> &data);
public:
U2F_Register_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data);
void respond(const uint32_t channelID) const override;
void respond(const uint32_t channelID) const override;
};

View File

@@ -17,25 +17,23 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "U2F_Version_APDU.hpp"
#include <iostream>
#include "APDU.hpp"
#include "Field.hpp"
#include "U2FMessage.hpp"
#include "u2f.hpp"
#include "Field.hpp"
#include "APDU.hpp"
#include <iostream>
using namespace std;
U2F_Version_APDU::U2F_Version_APDU(const U2F_Msg_CMD &msg, const std::vector<uint8_t> &data)
{
//Don't actually respond yet unless invalid
U2F_Version_APDU::U2F_Version_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data) {
// Don't actually respond yet unless invalid
if (msg.p1 != 0 || msg.p2 != 0)
throw APDU_STATUS::SW_INS_NOT_SUPPORTED;
else if (data.size() != 0)
throw APDU_STATUS::SW_WRONG_LENGTH;
}
void U2F_Version_APDU::respond(const uint32_t channelID) const
{
void U2F_Version_APDU::respond(const uint32_t channelID) const {
char ver[]{ 'U', '2', 'F', '_', 'V', '2' };
U2FMessage m{};

View File

@@ -19,9 +19,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "U2F_Msg_CMD.hpp"
struct U2F_Version_APDU : U2F_Msg_CMD
{
public:
U2F_Version_APDU(const U2F_Msg_CMD &msg, const std::vector<uint8_t> &data);
void respond(const uint32_t channelID) const override;
struct U2F_Version_APDU : U2F_Msg_CMD {
public:
U2F_Version_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data);
void respond(const uint32_t channelID) const override;
};

View File

@@ -1,38 +1,33 @@
#include "U2FDevice.hpp"
#include "Architecture.hpp"
#include "U2FDevice.hpp"
#include <execinfo.h>
#include <iostream>
#ifdef DEBUG_MSGS
//Courtesy StackOverflow answer https://stackoverflow.com/a/3356421
void terminateHandler()
{
void *trace_elems[20];
int trace_elem_count(backtrace(trace_elems, 20));
char **stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
for (int i = 0; i < trace_elem_count; ++i)
{
std::cout << stack_syms[i] << "\n";
}
free(stack_syms);
// Courtesy StackOverflow answer https://stackoverflow.com/a/3356421
void terminateHandler() {
void* trace_elems[20];
int trace_elem_count(backtrace(trace_elems, 20));
char** stack_syms(backtrace_symbols(trace_elems, trace_elem_count));
for (int i = 0; i < trace_elem_count; ++i) {
std::cout << stack_syms[i] << "\n";
}
free(stack_syms);
exit(1);
exit(1);
}
#endif
int main(int argc, char **argv) {
int main(int argc, char** argv) {
#ifdef DEBUG_MSGS
std::set_terminate(terminate_handler);
#endif
int retCode = handleTransactions(argv[0], argc == 2 ? argv[1] : STORAGE_PREFIX);
try
{
try {
initialiseLights(argv[0]);
deinitialiseLights(argv[0]);
}
catch (std::exception &e)
{
} catch (std::exception& e) {
std::cerr << "Exception in code: " << e.what() << std::endl;
throw;
}

141
u2f.hpp
View File

@@ -5,123 +5,122 @@
#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 <stdint.h>
# include <stdint.h>
#endif
#ifdef __cplusplus
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;
};
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;
#define FRAME_TYPE(f) ((f).type & TYPE_MASK)
#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK)
#define MSG_LEN(f) ((f).init.bcnth*256 + (f).init.bcntl)
#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK)
#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK)
#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
// General constants
#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 U2FHID_IF_VERSION 2 // Current interface implementation version
#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
// General constants
#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_SYNC (TYPE_INIT | 0x3c) // Protocol resync command
#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 INIT_NONCE_SIZE 8 // Size of channel initialization challenge
#define CAPFLAG_WINK 0x01 // Device supports WINK command
typedef struct {
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
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
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;
// U2FHID_SYNC command defines
typedef struct {
uint8_t nonce; // Client application nonce
uint8_t nonce; // Client application nonce
} U2FHID_SYNC_REQ;
typedef struct {
uint8_t nonce; // Client application nonce
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_SYNC_FAIL 0x0b // SYNC command failed
#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_SYNC_FAIL 0x0b // SYNC command failed
#define ERR_OTHER 0x7f // Other unspecified error
#ifdef __cplusplus
}
#endif
#endif // __U2FHID_H_INCLUDED__
#endif // __U2FHID_H_INCLUDED__