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

@@ -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
};

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_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;
}

View File

@@ -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:

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)
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" };
}
}

View File

@@ -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());

View File

@@ -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