Improved U2F APDU Message error handling.

This commit is contained in:
2018-08-10 13:13:38 +00:00
parent 5d1d0ccb63
commit 2ced303d3a
6 changed files with 94 additions and 41 deletions

View File

@@ -9,10 +9,9 @@ enum APDU : uint8_t
enum APDU_STATUS : uint16_t enum APDU_STATUS : uint16_t
{ {
SW_NO_ERROR = 0x9000, SW_NO_ERROR = 0x9000,
SW_WRONG_DATA = 0x6A80,
SW_CONDITIONS_NOT_SATISFIED = 0x6985, SW_CONDITIONS_NOT_SATISFIED = 0x6985,
SW_WRONG_DATA = 0x6A80, SW_COMMAND_NOT_ALLOWED = 0x6986,
SW_WRONG_LENGTH = 0x6700, SW_INS_NOT_SUPPORTED = 0x6D00
SW_CLA_NOT_SUPPORTED = 0x6E00,
SW_INS_NOT_SUPPORTED = 0x6D00
}; };

View File

@@ -14,8 +14,16 @@ using namespace std;
U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vector<uint8_t> &data) U2F_Authenticate_APDU::U2F_Authenticate_APDU(const U2F_Msg_CMD &msg, const vector<uint8_t> &data)
: U2F_Msg_CMD{ msg } : U2F_Msg_CMD{ msg }
{ {
if (data.size() < 66) if (p2 != 0)
throw runtime_error{ "Invalid authentication request" }; {
//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() + 0, data.begin() + 32, challengeP.begin());
copy(data.begin() + 32, data.begin() + 64, appParam.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 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)) if (keyH.size() != sizeof(Storage::KeyHandle))
{ {
//Respond with error code - key handle is of wrong size //Respond with error code - key handle is of wrong size
cerr << "Invalid key handle length" << endl; cerr << "Invalid key handle length" << endl;
statusCode = APDU_STATUS::SW_WRONG_DATA; this->error(channelID, APDU_STATUS::SW_WRONG_DATA);
response.insert(response.end(), FIELD_BE(statusCode));
msg.write();
return; 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 //Respond with error code - key handle doesn't exist in storage
cerr << "Invalid key handle" << endl; cerr << "Invalid key handle" << endl;
statusCode = APDU_STATUS::SW_WRONG_DATA; this->error(channelID, SW_WRONG_DATA);
response.insert(response.end(), FIELD_BE(statusCode));
msg.write();
return; return;
} }
auto appMatches = (Storage::appParams.at(keyHB) == appParam); 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) switch (p1)
{ {
case ControlCode::CheckOnly: case ControlCode::CheckOnly:
@@ -76,10 +80,8 @@ void U2F_Authenticate_APDU::respond(const uint32_t channelID) const
break; break;
default: default:
cerr << "Unknown APDU command" << endl; cerr << "Unknown APDU authentication command" << endl;
statusCode = APDU_STATUS::SW_WRONG_DATA; this->error(channelID, APDU_STATUS::SW_COMMAND_NOT_ALLOWED);
response.insert(response.end(), FIELD_BE(statusCode));
msg.write();
return; return;
} }

View File

@@ -10,7 +10,14 @@ shared_ptr<U2F_CMD> U2F_CMD::get(const shared_ptr<U2FMessage> uMsg)
switch (uMsg->cmd) switch (uMsg->cmd)
{ {
case U2FHID_MSG: case U2FHID_MSG:
return U2F_Msg_CMD::generate(uMsg); try
{
return U2F_Msg_CMD::generate(uMsg);
}
catch (runtime_error)
{
return {};
}
case U2FHID_INIT: case U2FHID_INIT:
return make_shared<U2F_Init_CMD>(uMsg); return make_shared<U2F_Init_CMD>(uMsg);
default: default:

View File

@@ -47,12 +47,22 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
if (uMsg->cmd != U2FHID_MSG) if (uMsg->cmd != U2FHID_MSG)
throw runtime_error{ "Failed to get U2F Msg uMsg" }; 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" }; throw runtime_error{ "Msg data is incorrect size" };
}
U2F_Msg_CMD cmd; U2F_Msg_CMD cmd;
auto &dat = uMsg->data; auto &dat = uMsg->data;
cmd.cla = dat[0]; 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.ins = dat[1];
cmd.p1 = dat[2]; cmd.p1 = dat[2];
cmd.p2 = dat[3]; 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 (usesData.at(cmd.ins) || data.size() > 3)
{ {
if (cBCount == 0) if (cBCount == 0)
{
U2F_Msg_CMD::error(uMsg->cid, APDU_STATUS::SW_WRONG_LENGTH);
throw runtime_error{ "Invalid command - should have attached data" }; throw runtime_error{ "Invalid command - should have attached data" };
}
if (data[0] != 0) //1 byte length if (data[0] != 0) //1 byte length
{ {
@@ -79,14 +92,30 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
endPtr = startPtr + cmd.lc; endPtr = startPtr + cmd.lc;
cmd.le = getLe(data.end() - endPtr, vector<uint8_t>(endPtr, data.end())); 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 else
{ {
cmd.lc = 0; cmd.lc = 0;
endPtr = startPtr; endPtr = startPtr;
cmd.le = getLe(cBCount, data); 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); const auto dBytes = vector<uint8_t>(startPtr, endPtr);
@@ -124,16 +153,25 @@ shared_ptr<U2F_Msg_CMD> U2F_Msg_CMD::generate(const shared_ptr<U2FMessage> uMsg)
"\t\t</table>\n" "\t\t</table>\n"
"\t\t<br />", cmd.le); "\t\t<br />", cmd.le);
switch (cmd.ins) try
{ {
case APDU::U2F_REG: switch (cmd.ins)
return make_shared<U2F_Register_APDU>(cmd, dBytes); {
case APDU::U2F_AUTH: case APDU::U2F_REG:
return make_shared<U2F_Authenticate_APDU>(cmd, dBytes); return make_shared<U2F_Register_APDU>(cmd, dBytes);
case APDU::U2F_VER: case APDU::U2F_AUTH:
return make_shared<U2F_Version_APDU>(cmd); return make_shared<U2F_Authenticate_APDU>(cmd, dBytes);
default: case APDU::U2F_VER:
throw runtime_error{ "Unknown APDU command issued" }; return make_shared<U2F_Version_APDU>(cmd);
default:
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" };
} }
} }

View File

@@ -16,11 +16,14 @@ U2F_Register_APDU::U2F_Register_APDU(const U2F_Msg_CMD &msg, const vector<uint8_
: U2F_Msg_CMD{ msg } : U2F_Msg_CMD{ msg }
{ {
if (data.size() != 64) 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) 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; //Invalid U2F Message (APDU) parameters detected
cerr << "Invalid APDU parameters detected" << endl; throw APDU_STATUS::SW_COMMAND_NOT_ALLOWED;
} }
copy(data.data() + 0, data.data() + 32, challengeP.begin()); 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::PrivKey privKey{};
Storage::PubKey pubKey{}; Storage::PubKey pubKey{};
//Unsure if necessary //First byte must be 0x04 for some reason
pubKey[0] = 0x04; pubKey[0] = 0x04;
uECC_make_key(pubKey.data() + 1, privKey.data(), uECC_secp256r1()); uECC_make_key(pubKey.data() + 1, privKey.data(), uECC_secp256r1());

View File

@@ -9,7 +9,11 @@ using namespace std;
U2F_Version_APDU::U2F_Version_APDU(const U2F_Msg_CMD &msg) 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 void U2F_Version_APDU::respond(const uint32_t channelID) const