From 2bc9c3225da1fbbfab5dd2a4f23224988367d0c4 Mon Sep 17 00:00:00 2001 From: Michael Kuc Date: Sat, 23 Jun 2018 08:09:41 +0000 Subject: [PATCH] Initial commit. --- deleteme | Bin 0 -> 92128 bytes init.txt | Bin 0 -> 64 bytes monitor.cpp | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++ u2f.hpp | 127 +++++++++++++++++++++ 4 files changed, 440 insertions(+) create mode 100755 deleteme create mode 100644 init.txt create mode 100644 monitor.cpp create mode 100644 u2f.hpp diff --git a/deleteme b/deleteme new file mode 100755 index 0000000000000000000000000000000000000000..e67696216103d2d77c8224f2a5ae063d5bc21aa5 GIT binary patch literal 92128 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

=w?L%pT@1kCLpvWB8pQj?gGM~^ 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

;fX0fs_(#5`y||XtUPf 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 +#include +#include +#include +#include +#include +#include +#include "u2f.hpp" + +using namespace std; + +const constexpr uint16_t packetSize = 32; + +struct Packet +{ + uint32_t cid; + + protected: + Packet() = default; + virtual void writePacket(); + + public: + static shared_ptr getPacket(); + virtual ~Packet() = default; +}; + + +struct InitPacket : Packet +{ + uint8_t cmd; + uint8_t bcnth; + uint8_t bcntl; + array data{}; + + public: + InitPacket() = default; + static shared_ptr getPacket(const uint32_t rCID, const uint8_t rCMD); + void writePacket() override; +}; + +struct ContPacket : Packet +{ + uint8_t seq; + array data{}; + + public: + ContPacket() = default; + static shared_ptr getPacket(const uint32_t rCID, const uint8_t rSeq); + void writePacket() override; +}; + +shared_ptr getStream() +{ + static shared_ptr stream{ fopen("/dev/hidg0", "rwb"), [](FILE *f){ + fclose(f); + } }; + + if (!stream) + clog << "Stream is unavailable" << endl; + + return stream; +} + +vector readBytes(const size_t count) +{ + vector bytes(count); + + const auto readByteCount = fread(bytes.data(), 1, count, getStream().get()); + + clog << "Read " << readByteCount << " bytes" << endl; + + if (readByteCount != count) + throw runtime_error{ "Failed to read sufficient bytes" }; + + return bytes; +} + +shared_ptr InitPacket::getPacket(const uint32_t rCID, const uint8_t rCMD) +{ + auto p = make_shared(); + p->cid = rCID; + p->cmd = rCMD; + p->bcnth = readBytes(1)[0]; + p->bcntl = readBytes(1)[0]; + /*uint16_t pLen = p->bcnth; + p->bcnth <<= 8; + p->bcnth += p->bcntl; + */ + + const auto dataBytes = readBytes(p->data.size()); + copy(dataBytes.begin(), dataBytes.end(), p->data.data()); + + return p; +} + +shared_ptr ContPacket::getPacket(const uint32_t rCID, const uint8_t rSeq) +{ + auto p = make_shared(); + p->cid = rCID; + p->seq = rSeq; + + const auto dataBytes = readBytes(p->data.size()); + copy(dataBytes.begin(), dataBytes.end(), p->data.data()); + + return p; +} + +shared_ptr Packet::getPacket() +{ + clog << "Making generic packet" << endl; + const uint32_t cid = *reinterpret_cast(readBytes(4).data()); + clog << "Grabbed cid" << endl; + uint8_t b = readBytes(1)[0]; + + clog << "b: " << static_cast(b) << endl; + + if (b && TYPE_MASK) + { + //Init packet + return InitPacket::getPacket(cid, b); + } + else + { + //Cont packet + return ContPacket::getPacket(cid, b); + } +} + +void Packet::writePacket() +{ + fwrite(&cid, 4, 1, getStream().get()); +} + +void InitPacket::writePacket() +{ + Packet::writePacket(); + auto stream = getStream().get(); + + fwrite(&cmd, 1, 1, stream); + fwrite(&bcnth, 1, 1, stream); + fwrite(&bcntl, 1, 1, stream); + fwrite(data.data(), data.size(), 1, stream); +} + +void ContPacket::writePacket() +{ + Packet::writePacket(); + auto stream = getStream().get(); + + fwrite(&seq, 1, 1, stream); + fwrite(data.data(), data.size(), 1, stream); +} + +struct U2FMessage +{ + uint32_t cid; + uint8_t cmd; + vector data; + + static U2FMessage read() + { + auto fPack = dynamic_pointer_cast(Packet::getPacket()); + + if (!fPack) + throw runtime_error{ "Failed to receive Init packet" }; + + const uint16_t messageSize = ((static_cast(fPack->bcnth) << 8u) + fPack->bcntl); + + clog << "Message has size: " << messageSize << endl; + + const uint16_t copyByteCount = min(static_cast(fPack->data.size()), messageSize); + + U2FMessage message{ fPack-> cid, fPack->cmd }; + message.data.assign(fPack->data.begin(), fPack->data.begin() + copyByteCount); + + uint8_t currSeq = 0; + + while (message.data.size() < messageSize) + { + auto newPack = dynamic_pointer_cast(Packet::getPacket()); + + if (!newPack) + throw runtime_error{ "Failed to receive Cont packet" }; + else if (newPack->seq != currSeq) + throw runtime_error{ "Packet out of sequence" }; + + const uint16_t remainingBytes = messageSize - message.data.size(); + const uint16_t copyBytes = min(static_cast(newPack->data.size()), remainingBytes); + message.data.insert(message.data.end(), newPack->data.begin(), newPack->data.begin() + copyBytes); + + currSeq++; + } + + return message; + } + + void write() + { + const uint16_t bytesToWrite = this->data.size(); + uint16_t bytesWritten = 0; + + { + const uint8_t bcnth = bytesToWrite >> 8; + const uint8_t bcntl = bytesToWrite - (bcnth << 8); + + InitPacket p{}; + p.cid = cid; + p.cmd = cmd; + p.bcnth = bcnth; + p.bcntl = bcntl; + + { + uint16_t initialByteCount = min(static_cast(p.data.size()), static_cast(bytesToWrite - bytesWritten)); + copy(data.begin(), data.begin() + initialByteCount, p.data.begin()); + bytesWritten += initialByteCount; + } + + p.writePacket(); + } + + uint8_t seq = 0; + + while (bytesWritten != bytesToWrite) + { + ContPacket p{}; + p.cid = cid; + p.seq = seq; + uint16_t newByteCount = min(static_cast(p.data.size()), static_cast(bytesToWrite - bytesWritten)); + copy(data.begin() + bytesWritten, data.begin() + bytesWritten + newByteCount, p.data.begin()); + p.writePacket(); + seq++; + } + } +}; + +struct U2F_CMD +{ + protected: + U2F_CMD() = default; + + public: + ~U2F_CMD() = default; +}; //For polymorphic type casting + +struct U2F_Init_CMD : U2F_CMD +{ + uint64_t nonce; + + public: + static U2F_Init_CMD get() + { + const auto message = U2FMessage::read(); + + if (message.cmd != U2FHID_INIT) + throw runtime_error{ "Failed to get U2F Init message" }; + else if (message.data.size() != INIT_NONCE_SIZE) + throw runtime_error{ "Init nonce is incorrect size" }; + + U2F_Init_CMD cmd; + cmd.nonce = *reinterpret_cast(message.data.data()); + + return cmd; + } +}; + +#define FIELD(name) reinterpret_cast(&name), (reinterpret_cast(&name) + sizeof(name)) + +struct U2F_Init_Response : U2F_CMD +{ + uint32_t cid; + uint64_t nonce; + uint8_t protocolVer; + uint8_t majorDevVer; + uint8_t minorDevVer; + uint8_t buildDevVer; + uint8_t capabilities; + + void write() + { + U2FMessage m{}; + m.cid = CID_BROADCAST; + m.cmd = U2FHID_INIT; + + m.data.insert(m.data.begin() + 0, FIELD(nonce)); + m.data.insert(m.data.begin() + 8, FIELD(cid)); + m.data.insert(m.data.begin() + 12, FIELD(protocolVer)); + m.data.insert(m.data.begin() + 13, FIELD(majorDevVer)); + m.data.insert(m.data.begin() + 14, FIELD(minorDevVer)); + m.data.insert(m.data.begin() + 15, FIELD(buildDevVer)); + m.data.insert(m.data.begin() + 16, FIELD(capabilities)); + } +}; + + +int main() +{ + auto initFrame = U2F_Init_CMD::get(); + U2F_Init_Response resp{}; + + resp.cid = 0xF1D0F1D0; + resp.nonce = initFrame.nonce; + resp.protocolVer = 2; + resp.majorDevVer = 0; + resp.minorDevVer = 0; + resp.buildDevVer = 0; + resp.capabilities = CAPFLAG_WINK; + + resp.write(); + U2FMessage m = m.read(); + + for (const auto d : m.data) + cout << static_cast(d) << endl; +} diff --git a/u2f.hpp b/u2f.hpp new file mode 100644 index 0000000..97744d9 --- /dev/null +++ b/u2f.hpp @@ -0,0 +1,127 @@ +// Common U2F HID transport header - Proposed Standard +// 2014-10-09 +// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com + +#ifndef __U2FHID_H_INCLUDED__ +#define __U2FHID_H_INCLUDED__ + +#ifdef _MSC_VER // Windows +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// Size of HID reports + +#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 TYPE_MASK 0x80 // Frame type mask +#define TYPE_INIT 0x80 // Initial frame identifier +#define TYPE_CONT 0x00 // Continuation frame identifier + +typedef struct { + uint32_t cid; // Channel identifier + union { + uint8_t type; // Frame type - b7 defines type + struct { + uint8_t cmd; // Command - b7 set + uint8_t bcnth; // Message byte count - high part + uint8_t bcntl; // Message byte count - low part + uint8_t data[HID_RPT_SIZE - 7]; // Data payload + } init; + struct { + uint8_t seq; // Sequence number - b7 cleared + uint8_t data[HID_RPT_SIZE - 5]; // Data payload + } cont; + }; +} U2FHID_FRAME; + +#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) + +// 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 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_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 + +typedef struct { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce +} U2FHID_INIT_REQ; + +typedef struct { + uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce + uint32_t cid; // Channel identifier + uint8_t versionInterface; // Interface version + uint8_t versionMajor; // Major version number + uint8_t versionMinor; // Minor version number + uint8_t versionBuild; // Build version number + uint8_t capFlags; // Capabilities flags +} U2FHID_INIT_RESP; + +// U2FHID_SYNC command defines + +typedef struct { + uint8_t nonce; // Client application nonce +} U2FHID_SYNC_REQ; + +typedef struct { + 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 + +#ifdef __cplusplus +} +#endif + +#endif // __U2FHID_H_INCLUDED__ +