Improved U2F APDU Message error handling.
This commit is contained in:
5
APDU.hpp
5
APDU.hpp
@@ -10,9 +10,8 @@ enum APDU : uint8_t
|
||||
enum APDU_STATUS : uint16_t
|
||||
{
|
||||
SW_NO_ERROR = 0x9000,
|
||||
SW_CONDITIONS_NOT_SATISFIED = 0x6985,
|
||||
SW_WRONG_DATA = 0x6A80,
|
||||
SW_WRONG_LENGTH = 0x6700,
|
||||
SW_CLA_NOT_SUPPORTED = 0x6E00,
|
||||
SW_CONDITIONS_NOT_SATISFIED = 0x6985,
|
||||
SW_COMMAND_NOT_ALLOWED = 0x6986,
|
||||
SW_INS_NOT_SUPPORTED = 0x6D00
|
||||
};
|
||||
|
||||
@@ -14,8 +14,16 @@ using namespace std;
|
||||
U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vector<uint8_t> &data)
|
||||
: U2F_Msg_CMD{ msg }
|
||||
{
|
||||
if (data.size() < 66)
|
||||
throw runtime_error{ "Invalid authentication request" };
|
||||
if (p2 != 0)
|
||||
{
|
||||
//Invalid U2F (APDU) parameter detected
|
||||
throw APDU_STATUS::SW_COMMAND_NOT_ALLOWED;
|
||||
}
|
||||
else if (data.size() < 66)
|
||||
{
|
||||
//Invalid authentication request
|
||||
throw APDU_STATUS::SW_WRONG_LENGTH;
|
||||
}
|
||||
|
||||
copy(data.begin() + 0, data.begin() + 32, challengeP.begin());
|
||||
copy(data.begin() + 32, data.begin() + 64, appParam.begin());
|
||||
@@ -27,20 +35,11 @@ U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vecto
|
||||
|
||||
void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
|
||||
{
|
||||
U2FMessage msg{};
|
||||
msg.cid = channelID;
|
||||
msg.cmd = U2FHID_MSG;
|
||||
auto statusCode = APDU_STATUS::SW_NO_ERROR;
|
||||
|
||||
auto &response = msg.data;
|
||||
|
||||
if (keyH.size() != sizeof(Storage::KeyHandle))
|
||||
{
|
||||
//Respond with error code - key handle is of wrong size
|
||||
cerr << "Invalid key handle length" << endl;
|
||||
statusCode = APDU_STATUS::SW_WRONG_DATA;
|
||||
response.insert(response.end(), FIELD_BE(statusCode));
|
||||
msg.write();
|
||||
this->error(channelID, APDU_STATUS::SW_WRONG_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,14 +49,19 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
|
||||
{
|
||||
//Respond with error code - key handle doesn't exist in storage
|
||||
cerr << "Invalid key handle" << endl;
|
||||
statusCode = APDU_STATUS::SW_WRONG_DATA;
|
||||
response.insert(response.end(), FIELD_BE(statusCode));
|
||||
msg.write();
|
||||
this->error(channelID, SW_WRONG_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
auto appMatches = (Storage::appParams.at(keyHB) == appParam);
|
||||
|
||||
U2FMessage msg{};
|
||||
msg.cid = channelID;
|
||||
msg.cmd = U2FHID_MSG;
|
||||
|
||||
auto &response = msg.data;
|
||||
APDU_STATUS statusCode = APDU_STATUS::SW_NO_ERROR;
|
||||
|
||||
switch (p1)
|
||||
{
|
||||
case ControlCode::CheckOnly:
|
||||
@@ -76,10 +80,8 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << "Unknown APDU command" << endl;
|
||||
statusCode = APDU_STATUS::SW_WRONG_DATA;
|
||||
response.insert(response.end(), FIELD_BE(statusCode));
|
||||
msg.write();
|
||||
cerr << "Unknown APDU authentication command" << endl;
|
||||
this->error(channelID, APDU_STATUS::SW_COMMAND_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,14 @@ shared_ptr<U2F_CMD> U2F_CMD::get(const shared_ptr<U2FMessage> uMsg)
|
||||
switch (uMsg->cmd)
|
||||
{
|
||||
case U2FHID_MSG:
|
||||
try
|
||||
{
|
||||
return U2F_Msg_CMD::generate(uMsg);
|
||||
}
|
||||
catch (runtime_error)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
case U2FHID_INIT:
|
||||
return make_shared<U2F_Init_CMD>(uMsg);
|
||||
default:
|
||||
|
||||
@@ -47,12 +47,22 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
|
||||
if (uMsg->cmd != U2FHID_MSG)
|
||||
throw runtime_error{ "Failed to get U2F Msg uMsg" };
|
||||
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;
|
||||
|
||||
cmd.cla = dat[0];
|
||||
|
||||
if (cmd.cla != 0)
|
||||
{
|
||||
U2F_Msg_CMD::error(uMsg->cid, APDU_STATUS::SW_COMMAND_NOT_ALLOWED);
|
||||
throw runtime_error{ "Invalid CLA value in U2F Message" };
|
||||
}
|
||||
|
||||
cmd.ins = dat[1];
|
||||
cmd.p1 = dat[2];
|
||||
cmd.p2 = dat[3];
|
||||
@@ -64,7 +74,10 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
|
||||
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
|
||||
{
|
||||
@@ -79,15 +92,31 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
|
||||
|
||||
endPtr = startPtr + cmd.lc;
|
||||
|
||||
try
|
||||
{
|
||||
cmd.le = getLe(data.end() - endPtr, vector<uint8_t>(endPtr, data.end()));
|
||||
}
|
||||
catch (runtime_error)
|
||||
{
|
||||
U2F_Msg_CMD::error(uMsg->cid, APDU_STATUS::SW_WRONG_LENGTH);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.lc = 0;
|
||||
endPtr = startPtr;
|
||||
|
||||
try
|
||||
{
|
||||
cmd.le = getLe(cBCount, data);
|
||||
}
|
||||
catch (runtime_error)
|
||||
{
|
||||
U2F_Msg_CMD::error(uMsg->cid, APDU_STATUS::SW_WRONG_LENGTH);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
const auto dBytes = vector<uint8_t>(startPtr, endPtr);
|
||||
|
||||
@@ -124,6 +153,8 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
|
||||
"\t\t</table>\n"
|
||||
"\t\t<br />", cmd.le);
|
||||
|
||||
try
|
||||
{
|
||||
switch (cmd.ins)
|
||||
{
|
||||
case APDU::U2F_REG:
|
||||
@@ -133,7 +164,14 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
|
||||
case APDU::U2F_VER:
|
||||
return make_shared<U2F_Version_APDU>(cmd);
|
||||
default:
|
||||
throw runtime_error{ "Unknown APDU command issued" };
|
||||
cerr << "Invalid command used" << endl;
|
||||
throw APDU_STATUS::SW_INS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
catch (const APDU_STATUS e)
|
||||
{
|
||||
U2F_Msg_CMD::error(uMsg->cid, e);
|
||||
throw runtime_error{ "APDU construction error" };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,14 @@ U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD &msg, const vector<uint8_
|
||||
: U2F_Msg_CMD{ msg }
|
||||
{
|
||||
if (data.size() != 64)
|
||||
throw runtime_error{ "Incorrect registration size" };
|
||||
{
|
||||
//Incorrect registration size
|
||||
throw APDU_STATUS::SW_WRONG_LENGTH;
|
||||
}
|
||||
else if (p1 != 0x00 || p2 != 0x00)
|
||||
{
|
||||
cerr << "Ins: " << static_cast<uint32_t>(ins) << ", p1: " << static_cast<uint32_t>(p1) << ", p2: " << static_cast<uint32_t>(p2) << endl;
|
||||
cerr << "Invalid APDU parameters detected" << endl;
|
||||
//Invalid U2F Message (APDU) parameters detected
|
||||
throw APDU_STATUS::SW_COMMAND_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
copy(data.data() + 0, data.data() + 32, challengeP.begin());
|
||||
@@ -30,7 +33,7 @@ U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD &msg, const vector<uint8_
|
||||
Storage::PrivKey privKey{};
|
||||
Storage::PubKey pubKey{};
|
||||
|
||||
//Unsure if necessary
|
||||
//First byte must be 0x04 for some reason
|
||||
pubKey[0] = 0x04;
|
||||
|
||||
uECC_make_key(pubKey.data() + 1, privKey.data(), uECC_secp256r1());
|
||||
|
||||
@@ -9,7 +9,11 @@ using namespace std;
|
||||
|
||||
U2F_Version_APDU::U2F_Version_APDU(const U2F_Msg_CMD &msg)
|
||||
{
|
||||
//Don't actually respond yet
|
||||
//Don't actually respond yet unless invalid
|
||||
if (msg.p1 != 0 || msg.p2 != 0)
|
||||
throw APDU_STATUS::SW_COMMAND_NOT_ALLOWED;
|
||||
else if (msg.data.size() != 0)
|
||||
throw APDU_STATUS::SW_WRONG_LENGTH;
|
||||
}
|
||||
|
||||
void U2F_Version_APDU::respond(const uint32_t channelID) const
|
||||
|
||||
Reference in New Issue
Block a user