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,15 +18,9 @@ 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
{
enum APDU_STATUS : uint16_t {
SW_NO_ERROR = 0x9000,
SW_WRONG_LENGTH = 0x6700,
SW_CONDITIONS_NOT_SATISFIED = 0x6985,

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

@@ -18,73 +18,57 @@ 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,30 +17,21 @@ 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 ChannelInitState { Unitialised, Initialised };
enum class ChannelLockedState
{
Locked,
Unlocked
};
enum class ChannelLockedState { Locked, Unlocked };
class Channel
{
protected:
class Channel {
protected:
uint32_t cid;
ChannelInitState initState;
ChannelLockedState lockedState;
public:
public:
Channel(const uint32_t channelID);
void handle(const U2FMessage& uMsg);

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,18 +17,17 @@ 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:
class Controller {
protected:
std::map<uint32_t, Channel> channels;
uint32_t currChannel;
std::chrono::system_clock::time_point lastMessage;
public:
public:
Controller(const uint32_t startChannel = 1);
void handleTransaction();

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))

70
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)
{
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;
@@ -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]];
@@ -82,7 +81,8 @@ shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t
#ifdef DEBUG_STREAMS
auto hPStream = getHostPacketStream().get();
fprintf(hPStream, "\t\t<table>\n"
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"
@@ -98,7 +98,8 @@ shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t
"\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);
"\t\t\t\t\t<td class=\"data\">",
p->cid, p->cmd, p->bcnth, p->bcntl);
for (auto elem : dataBytes)
fprintf(hPStream, "%3u ", elem);
@@ -114,16 +115,14 @@ shared_ptr<InitPacket> InitPacket::getPacket(const uint32_t rCID, const uint8_t
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,7 +139,8 @@ 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"
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"
@@ -152,7 +152,8 @@ shared_ptr<ContPacket> ContPacket::getPacket(const uint32_t rCID, const uint8_t
"\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);
"\t\t\t\t\t<td class=\"data\">",
p->cid, p->seq);
for (auto elem : dataBytes)
fprintf(hPStream, "%3u ", elem);
@@ -168,8 +169,7 @@ shared_ptr<ContPacket> ContPacket::getPacket(const uint32_t rCID, const uint8_t
return p;
}
shared_ptr<Packet> Packet::getPacket()
{
shared_ptr<Packet> Packet::getPacket() {
static size_t bytesRead = 0;
vector<uint8_t> bytes{};
@@ -177,8 +177,7 @@ shared_ptr<Packet> Packet::getPacket()
static uint8_t b;
shared_ptr<Packet> packet{};
switch (bytesRead)
{
switch (bytesRead) {
case 0:
bytes = readNonBlock(4);
@@ -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,14 +221,12 @@ shared_ptr<Packet> Packet::getPacket()
}
}
void Packet::writePacket()
{
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
@@ -249,7 +243,8 @@ void InitPacket::writePacket()
fwrite(this->buf, 1, sizeof(this->buf), devStream);
auto dPStream = getDevPacketStream().get();
fprintf(dPStream, "\t\t<table>\n"
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"
@@ -265,7 +260,8 @@ void InitPacket::writePacket()
"\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);
"\t\t\t\t\t<td class=\"data\">",
cid, cmd, bcnth, bcntl);
for (auto elem : data)
fprintf(dPStream, "%3u ", elem);
@@ -278,8 +274,7 @@ void InitPacket::writePacket()
#endif
}
void ContPacket::writePacket()
{
void ContPacket::writePacket() {
Packet::writePacket();
#ifdef DEBUG_STREAMS
@@ -288,14 +283,15 @@ void ContPacket::writePacket()
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);
auto dPStream = getDevPacketStream().get();
fprintf(dPStream, "\t\t<table>\n"
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"
@@ -307,7 +303,8 @@ void ContPacket::writePacket()
"\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);
"\t\t\t\t\t<td class=\"data\">",
cid, seq);
for (auto elem : data)
fprintf(dPStream, "%3u ", elem);

View File

@@ -17,47 +17,44 @@ 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:
struct Packet {
public:
uint32_t cid;
uint8_t buf[HID_RPT_SIZE];
protected:
protected:
Packet() = default;
virtual void writePacket();
public:
public:
static std::shared_ptr<Packet> getPacket();
virtual ~Packet() = default;
};
struct InitPacket : Packet
{
public:
struct InitPacket : Packet {
public:
uint8_t cmd;
uint8_t bcnth;
uint8_t bcntl;
std::array<uint8_t, HID_RPT_SIZE - 7> data{};
public:
public:
InitPacket() = default;
static std::shared_ptr<InitPacket> getPacket(const uint32_t rCID, const uint8_t rCMD);
void writePacket() override;
};
struct ContPacket : Packet
{
public:
struct ContPacket : Packet {
public:
uint8_t seq;
std::array<uint8_t, HID_RPT_SIZE - 5> data{};
public:
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 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,10 +17,10 @@ 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;
@@ -30,21 +30,18 @@ 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;
@@ -53,14 +50,16 @@ void Storage::init(std::istream &inputStream)
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 };
@@ -83,16 +82,13 @@ void Storage::init(std::istream &inputStream)
}
}
void Storage::save()
{
void Storage::save() {
ofstream file{ Storage::filename };
Storage::save(file);
}
void Storage::save(ostream &outputStream)
{
for (auto &keypair : Storage::appParams)
{
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];

View File

@@ -17,13 +17,12 @@ 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;
@@ -31,16 +30,16 @@ public:
using PrivKey = std::array<uint8_t, 32>;
using PubKey = std::array<uint8_t, 65>;
protected:
protected:
Storage() = default;
static std::string filename;
public:
static void init(const std::string &dirPrefix = "");
static void init(std::istream &inputStream);
public:
static void init(const std::string& dirPrefix = "");
static void init(std::istream& inputStream);
static void save();
static void save(std::ostream &outputStream);
static void save(std::ostream& outputStream);
static std::map<KeyHandle, AppParam> appParams;
static std::map<KeyHandle, PrivKey> privKeys;
static std::map<KeyHandle, PubKey> pubKeys;

View File

@@ -18,25 +18,24 @@ 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){
descriptor.reset(new int{ open(HID_DEV, O_RDWR | O_NONBLOCK | O_APPEND) }, [](int* fd) {
close(*fd);
delete fd;
});
@@ -48,9 +47,9 @@ 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){
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);
} };
@@ -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){
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){
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,9 +90,9 @@ shared_ptr<FILE> getHostAPDUStream()
return stream;
}
shared_ptr<FILE> getComDevStream()
{
static shared_ptr<FILE> stream{ fopen((cacheDirectory + "comdev.txt").c_str(), "wb"), [](FILE *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);
} };
@@ -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){
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,9 +118,10 @@ 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){
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);
} };
@@ -126,9 +132,9 @@ shared_ptr<FILE> getDevAPDUStream()
return stream;
}
FILE* initHTML(FILE *fPtr, const string &title)
{
fprintf(fPtr, "<html>\n"
FILE* initHTML(FILE* fPtr, const string& title) {
fprintf(fPtr,
"<html>\n"
"\t<head>\n"
"\t\t<title>%s</title>\n"
"\t\t<style>\n"
@@ -165,13 +171,13 @@ FILE* initHTML(FILE *fPtr, const string &title)
"\t\t</style>\n"
"\t</head>\n"
"\n"
"\t<body>", title.c_str());
"\t<body>",
title.c_str());
return fPtr;
}
void closeHTML(FILE *fPtr)
{
void closeHTML(FILE* fPtr) {
fprintf(fPtr, "\t</body>\n"
"</html>");
fclose(fPtr);

View File

@@ -17,9 +17,9 @@ 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();

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,18 +17,17 @@ 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()
{
shared_ptr<U2FMessage> U2FMessage::readNonBlock() {
const static size_t startSeq = (size_t)-1ull;
static size_t currSeq = startSeq;
static uint16_t messageSize;
@@ -38,16 +37,14 @@ shared_ptr<U2FMessage> U2FMessage::readNonBlock()
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,20 +154,20 @@ 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();
@@ -187,22 +190,21 @@ void U2FMessage::write()
err |= data.back();
#ifdef DEBUG_STREAMS
fprintf(dAS, "</td>\n"
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);
"\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,18 +18,16 @@ 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:
struct U2FMessage {
public:
uint32_t cid;
uint8_t cmd;
std::vector<uint8_t> data;
public:
public:
U2FMessage() = default;
U2FMessage(const uint32_t nCID, const uint8_t nCMD);
static std::shared_ptr<U2FMessage> readNonBlock();

View File

@@ -17,29 +17,25 @@ 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;
}
@@ -51,11 +47,9 @@ 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;
@@ -63,9 +57,8 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
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:
@@ -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;
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;
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:
struct U2F_CMD {
protected:
U2F_CMD() = default;
public:
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
}; // 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:
public:
U2F_Init_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
};

View File

@@ -18,65 +18,57 @@ 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" };
}
@@ -89,48 +81,36 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
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,7 +121,8 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
#ifdef DEBUG_STREAMS
auto hAS = getHostAPDUStream().get();
fprintf(hAS, "<table>\n"
fprintf(hAS,
"<table>\n"
"\t\t\t<thead>\n"
"\t\t\t\t<tr>\n"
"\t\t\t\t\t<th>CLA</th>\n"
@@ -160,23 +141,24 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const U2FMessage& uMsg)
"\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);
"\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"
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);
"\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 },
const map<uint8_t, bool> U2F_Msg_CMD::usesData = { { U2F_REG, true },
{ U2F_AUTH, true },
{ U2F_VER, false }
};
{ 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,11 +20,10 @@ 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
{
struct U2F_Msg_CMD : U2F_CMD {
uint8_t cla;
uint8_t ins;
uint8_t p1;
@@ -34,13 +33,12 @@ struct U2F_Msg_CMD : U2F_CMD
const static std::map<uint8_t, bool> usesData;
protected:
protected:
static uint32_t getLe(const uint32_t byteCount, std::vector<uint8_t> bytes);
U2F_Msg_CMD() = default;
public:
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:
public:
U2F_Ping_CMD(const U2FMessage& uMsg);
virtual void respond(const uint32_t channelID) const override;
};

View File

@@ -17,55 +17,51 @@ 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() + 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::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;
@@ -78,12 +74,12 @@ void U2F_Register_APDU::respond(const uint32_t channelID) const
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;
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;
};

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);
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,17 +1,15 @@
#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];
// 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)
{
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);
@@ -20,19 +18,16 @@ void terminateHandler()
}
#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;
}

View File

@@ -11,7 +11,7 @@ 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
@@ -49,7 +49,7 @@ typedef struct {
#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 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
@@ -124,4 +124,3 @@ typedef struct {
#endif
#endif // __U2FHID_H_INCLUDED__