#include "U2F_Msg_CMD.hpp" #include "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 #include "Streams.hpp" using namespace std; uint32_t U2F_Msg_CMD::getLe(const uint32_t byteCount, vector bytes) { if (byteCount > 3) throw runtime_error{ "Too much data for command" }; if (byteCount != 0) { //Le must be length of data in bytes 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 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 if (bytes[0] != 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]); } } else return 0; } shared_ptr U2F_Msg_CMD::get() { const auto message = U2FMessage::read(); if (message.cmd != U2FHID_MSG) throw runtime_error{ "Failed to get U2F Msg message" }; U2F_Msg_CMD cmd{}; auto &dat = message.data; cmd.cla = dat[0]; cmd.ins = dat[1]; cmd.p1 = dat[2]; cmd.p2 = dat[3]; const uint32_t cBCount = dat.size() - 4; vector data{ dat.begin() + 4, dat.end() }; auto startPtr = data.begin(), endPtr = data.end(); if (usesData.at(cmd.ins) || data.size() > 3) { //clog << "First bytes are: " << static_cast(data[0]) << " " << static_cast(data[1]) << " " << static_cast(data[2]) << endl; if (cBCount == 0) throw runtime_error{ "Invalid command - should have attached data" }; if (data[0] != 0) //1 byte length { cmd.lc = data[0]; startPtr++; } else { cmd.lc = (data[1] << 8) + data[2]; startPtr += 3; } endPtr = startPtr + cmd.lc; cmd.le = getLe(data.end() - endPtr, vector(endPtr, data.end())); } else { cmd.lc = 0; endPtr = startPtr; cmd.le = getLe(cBCount, data); } const auto dBytes = vector(startPtr, endPtr); auto hAS = getHostAPDUStream().get(); fprintf(hAS, "\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\n" "\t\t\t\n" "\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\t\n" "\t\t\t\t\n" "\t\t\t\n" "\t\t
CLAINSP1P2LcDataLe
0x%02X0x%02X%u%u%3u", cmd.cla, cmd.ins, cmd.p1, cmd.p2, cmd.lc); for (auto b : dBytes) fprintf(hAS, "%3u ", b); fprintf(hAS, "%5u
\n" "\t\t
", cmd.le); switch (cmd.ins) { case APDU::U2F_REG: return make_shared(cmd, dBytes); case APDU::U2F_AUTH: return make_shared(cmd, dBytes); case APDU::U2F_VER: return make_shared(cmd); default: throw runtime_error{ "Unknown APDU command issued" }; } } void U2F_Msg_CMD::respond(){}; const map U2F_Msg_CMD::usesData = { { U2F_REG, true }, { U2F_AUTH, true }, { U2F_VER, false } };