Added authorisation.
This commit is contained in:
20
Channel.cpp
20
Channel.cpp
@@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include "u2f.hpp"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <android/log.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -33,7 +34,7 @@ uint32_t Channel::getCID() const {
|
||||
return cid;
|
||||
}
|
||||
|
||||
void Channel::handle(const U2FMessage& uMsg) {
|
||||
bool Channel::handle(const U2FMessage& uMsg, AuthorisationLevel auth) {
|
||||
if (uMsg.cmd == U2FHID_INIT)
|
||||
this->initState = ChannelInitState::Initialised;
|
||||
else if (uMsg.cid != this->cid)
|
||||
@@ -46,8 +47,21 @@ void Channel::handle(const U2FMessage& uMsg) {
|
||||
|
||||
auto cmd = U2F_CMD::get(uMsg);
|
||||
|
||||
if (cmd)
|
||||
return cmd->respond(this->cid);
|
||||
if (!cmd)
|
||||
return true;
|
||||
|
||||
if (cmd->requiresAuthorisation()) {
|
||||
if (auth == AuthorisationLevel::Unspecified) {
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "U2FDevice",
|
||||
"Action requires authorisation; seeking authorisation");
|
||||
return false;
|
||||
}
|
||||
else if (auth == AuthorisationLevel::Unauthorised)
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "U2FDevice", "Action requires authorisation; authorisation not granted");
|
||||
}
|
||||
|
||||
cmd->respond(this->cid, auth == AuthorisationLevel::Authorised);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Channel::init(const ChannelInitState newInitState) {
|
||||
|
||||
@@ -25,6 +25,8 @@ enum class ChannelInitState { Unitialised, Initialised };
|
||||
|
||||
enum class ChannelLockedState { Locked, Unlocked };
|
||||
|
||||
enum class AuthorisationLevel { Unspecified, Unauthorised, Authorised };
|
||||
|
||||
class Channel {
|
||||
protected:
|
||||
uint32_t cid;
|
||||
@@ -33,7 +35,10 @@ protected:
|
||||
|
||||
public:
|
||||
Channel(const uint32_t channelID);
|
||||
void handle(const U2FMessage& uMsg);
|
||||
|
||||
// Returns false if requires authorisation check
|
||||
// True otherwise
|
||||
bool handle(const U2FMessage& uMsg, AuthorisationLevel auth);
|
||||
|
||||
uint32_t getCID() const;
|
||||
void init(const ChannelInitState newInitState);
|
||||
|
||||
@@ -32,10 +32,10 @@ void Controller::handleTransaction() {
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
handleTransaction(*msg);
|
||||
handleTransaction(*msg, AuthorisationLevel::Unspecified);
|
||||
}
|
||||
|
||||
void Controller::handleTransaction(const U2FMessage& msg) {
|
||||
bool Controller::handleTransaction(const U2FMessage& msg, AuthorisationLevel auth) {
|
||||
try {
|
||||
if (channels.size() != 0 &&
|
||||
chrono::duration_cast<chrono::seconds>(chrono::system_clock::now() - lastMessage) <
|
||||
@@ -60,7 +60,7 @@ void Controller::handleTransaction(const U2FMessage& msg) {
|
||||
}
|
||||
} else if (channels.find(opChannelID) == channels.end()) {
|
||||
U2FMessage::error(opChannelID, ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MSGS
|
||||
@@ -68,7 +68,7 @@ void Controller::handleTransaction(const U2FMessage& msg) {
|
||||
clog << "cid: " << msg.cid << ", cmd: " << static_cast<unsigned int>(msg.cmd) << endl;
|
||||
#endif
|
||||
|
||||
channels.at(opChannelID).handle(msg);
|
||||
return channels.at(opChannelID).handle(msg, auth);
|
||||
}
|
||||
|
||||
uint32_t Controller::nextChannel() {
|
||||
|
||||
@@ -31,6 +31,9 @@ public:
|
||||
Controller(const uint32_t startChannel = 1);
|
||||
|
||||
void handleTransaction();
|
||||
void handleTransaction(const U2FMessage& msg);
|
||||
|
||||
// Returns false if required authentication
|
||||
// Returns true otherwise
|
||||
bool handleTransaction(const U2FMessage& msg, AuthorisationLevel auth);
|
||||
uint32_t nextChannel();
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ 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 {
|
||||
void U2F_Authenticate_APDU::respond(const uint32_t channelID, bool hasAuthorisation) const {
|
||||
if (keyH.size() != sizeof(Storage::KeyHandle)) {
|
||||
// Respond with error code - key handle is of wrong size
|
||||
cerr << "Invalid key handle length" << endl;
|
||||
@@ -71,6 +71,8 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t presence;
|
||||
|
||||
switch (p1) {
|
||||
case ControlCode::CheckOnly:
|
||||
this->error(channelID, APDU_STATUS::SW_CONDITIONS_NOT_SATISFIED);
|
||||
@@ -98,7 +100,7 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const {
|
||||
auto& keyCount = Storage::keyCounts[keyHB];
|
||||
keyCount++;
|
||||
|
||||
response.push_back(0x01);
|
||||
response.push_back(hasAuthorisation ? 1u : 0u);
|
||||
response.insert(response.end(), FIELD_BE(keyCount));
|
||||
|
||||
Digest digest;
|
||||
@@ -110,7 +112,7 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const {
|
||||
|
||||
mbedtls_sha256_update(&shaContext, reinterpret_cast<const uint8_t*>(appParam.data()),
|
||||
sizeof(appParam));
|
||||
uint8_t userPresence{ 1u };
|
||||
uint8_t userPresence = hasAuthorisation ? 1u : 0u;
|
||||
mbedtls_sha256_update(&shaContext, &userPresence, 1);
|
||||
const auto beCounter = beEncode(keyCount);
|
||||
mbedtls_sha256_update(&shaContext, beCounter.data(), beCounter.size());
|
||||
@@ -128,3 +130,7 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const {
|
||||
|
||||
msg.write();
|
||||
}
|
||||
|
||||
bool U2F_Authenticate_APDU::requiresAuthorisation() const {
|
||||
return p1 == ControlCode::EnforcePresenceSign;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ struct U2F_Authenticate_APDU : U2F_Msg_CMD {
|
||||
public:
|
||||
U2F_Authenticate_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data);
|
||||
|
||||
virtual void respond(const uint32_t channelID) const override;
|
||||
bool requiresAuthorisation() const override;
|
||||
virtual void respond(const uint32_t channelID, bool hasAuthorisation) const override;
|
||||
|
||||
enum ControlCode {
|
||||
CheckOnly = 0x07,
|
||||
|
||||
@@ -42,3 +42,7 @@ shared_ptr<U2F_CMD> U2F_CMD::get(const U2FMessage& uMsg) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool U2F_CMD::requiresAuthorisation() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ protected:
|
||||
|
||||
public:
|
||||
virtual ~U2F_CMD() = default;
|
||||
virtual bool requiresAuthorisation() const;
|
||||
static std::shared_ptr<U2F_CMD> get(const U2FMessage& uMsg);
|
||||
virtual void respond(const uint32_t channelID) const = 0;
|
||||
virtual void respond(const uint32_t channelID, bool hasAuthorisation) const = 0;
|
||||
}; // For polymorphic type casting
|
||||
|
||||
@@ -37,7 +37,7 @@ 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, bool) const {
|
||||
U2FMessage msg{};
|
||||
msg.cid = CID_BROADCAST;
|
||||
msg.cmd = U2FHID_INIT;
|
||||
|
||||
@@ -27,5 +27,5 @@ struct U2F_Init_CMD : U2F_CMD {
|
||||
|
||||
public:
|
||||
U2F_Init_CMD(const U2FMessage& uMsg);
|
||||
virtual void respond(const uint32_t channelID) const override;
|
||||
virtual void respond(const uint32_t channelID, bool) const override;
|
||||
};
|
||||
|
||||
@@ -194,6 +194,6 @@ 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, bool) const {
|
||||
U2F_Msg_CMD::error(channelID, static_cast<uint16_t>(APDU_STATUS::SW_INS_NOT_SUPPORTED));
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct U2F_Msg_CMD : U2F_CMD {
|
||||
struct U2F_Msg_CMD : public U2F_CMD {
|
||||
uint8_t cla;
|
||||
uint8_t ins;
|
||||
uint8_t p1;
|
||||
@@ -36,9 +36,10 @@ struct U2F_Msg_CMD : U2F_CMD {
|
||||
protected:
|
||||
static uint32_t getLe(const uint32_t byteCount, std::vector<uint8_t> bytes);
|
||||
U2F_Msg_CMD() = default;
|
||||
virtual ~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;
|
||||
void respond(const uint32_t channelID, bool hasAuthorisation) const;
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ U2F_Ping_CMD::U2F_Ping_CMD(const U2FMessage& uMsg) : nonce{ uMsg.data } {
|
||||
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, bool) const {
|
||||
U2FMessage msg{};
|
||||
msg.cid = channelID;
|
||||
msg.cmd = U2FHID_PING;
|
||||
|
||||
@@ -27,5 +27,5 @@ struct U2F_Ping_CMD : U2F_CMD {
|
||||
|
||||
public:
|
||||
U2F_Ping_CMD(const U2FMessage& uMsg);
|
||||
virtual void respond(const uint32_t channelID) const override;
|
||||
virtual void respond(const uint32_t channelID, bool) const override;
|
||||
};
|
||||
|
||||
@@ -61,7 +61,13 @@ U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD& msg, const vector<uint8_
|
||||
Storage::keyCounts[this->keyH] = 0;
|
||||
}
|
||||
|
||||
void U2F_Register_APDU::respond(const uint32_t channelID) const {
|
||||
void U2F_Register_APDU::respond(const uint32_t channelID, bool hasAuthorisation) const {
|
||||
if (!hasAuthorisation) {
|
||||
error(channelID, APDU_STATUS::SW_CONDITIONS_NOT_SATISFIED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
U2FMessage m{};
|
||||
m.cid = channelID;
|
||||
m.cmd = U2FHID_MSG;
|
||||
@@ -118,3 +124,7 @@ void U2F_Register_APDU::respond(const uint32_t channelID) const {
|
||||
|
||||
m.write();
|
||||
}
|
||||
|
||||
bool U2F_Register_APDU::requiresAuthorisation() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ struct U2F_Register_APDU : U2F_Msg_CMD {
|
||||
|
||||
public:
|
||||
U2F_Register_APDU(const U2F_Msg_CMD& msg, const std::vector<uint8_t>& data);
|
||||
virtual ~U2F_Register_APDU() = default;
|
||||
|
||||
void respond(const uint32_t channelID) const override;
|
||||
bool requiresAuthorisation() const override;
|
||||
void respond(const uint32_t channelID, bool hasAuthorisation) const override;
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ U2F_Version_APDU::U2F_Version_APDU(const U2F_Msg_CMD& msg, const std::vector<uin
|
||||
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, bool) const {
|
||||
char ver[]{ 'U', '2', 'F', '_', 'V', '2' };
|
||||
U2FMessage m{};
|
||||
|
||||
|
||||
@@ -22,5 +22,5 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
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;
|
||||
void respond(const uint32_t channelID, bool) const override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user