#include "bee2/core/apdu.h"
#include "bee2/core/mem.h"
#include "bee2/core/util.h"
#define apduCmdSizeof(cmd) (sizeof(apdu_cmd_t) + (cmd)->cdf_len)
bool_t apduCmdIsValid(const apdu_cmd_t* cmd)
{
return memIsValid(cmd, sizeof(apdu_cmd_t)) &&
cmd->cdf_len < 65536 &&
memIsValid(cmd->cdf, cmd->cdf_len) &&
cmd->rdf_len <= 65536;
}
size_t apduCmdEnc(octet apdu[], const apdu_cmd_t* cmd)
{
size_t count;
ASSERT(apduCmdIsValid(cmd));
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 4, cmd, apduCmdSizeof(cmd)));
apdu[0] = cmd->cla, apdu[1] = cmd->ins;
apdu[2] = cmd->p1, apdu[3] = cmd->p2;
apdu += 4;
}
count = 4;
if (cmd->cdf_len == 0)
count += 0 + cmd->cdf_len;
else if (cmd->cdf_len < 256 && cmd->rdf_len <= 256)
{
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 1, cmd, apduCmdSizeof(cmd)));
apdu[0] = (octet)cmd->cdf_len;
memCopy(apdu + 1, cmd->cdf, cmd->cdf_len);
apdu += 1 + cmd->cdf_len;
}
count += 1 + cmd->cdf_len;
}
else
{
ASSERT(cmd->cdf_len < 65536);
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 3, cmd, apduCmdSizeof(cmd)));
apdu[0] = 0;
apdu[1] = (octet)(cmd->cdf_len / 256);
apdu[2] = (octet)cmd->cdf_len;
memCopy(apdu + 3, cmd->cdf, cmd->cdf_len);
apdu += 3 + cmd->cdf_len;
}
count += 3 + cmd->cdf_len;
}
if (cmd->rdf_len == 0)
count += 0;
else if (cmd->rdf_len <= 256 && cmd->cdf_len < 256)
{
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 1, cmd, apduCmdSizeof(cmd)));
apdu[0] = (octet)cmd->rdf_len;
}
count += 1;
}
else if (cmd->cdf_len)
{
ASSERT(256 <= cmd->cdf_len || 256 < cmd->rdf_len);
ASSERT(cmd->rdf_len <= 65536);
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 2, cmd, apduCmdSizeof(cmd)));
apdu[0] = (octet)(cmd->rdf_len / 256);
apdu[1] = (octet)cmd->rdf_len;
}
count += 2;
}
else
{
ASSERT(256 < cmd->rdf_len && cmd->rdf_len <= 65536);
if (apdu)
{
ASSERT(memIsDisjoint2(apdu, 3, cmd, apduCmdSizeof(cmd)));
apdu[0] = 0;
apdu[1] = (octet)(cmd->rdf_len / 256);
apdu[2] = (octet)cmd->rdf_len;
}
count += 3;
}
return count;
}
size_t apduCmdDec(apdu_cmd_t* cmd, const octet apdu[], size_t count)
{
size_t cdf_len_len;
size_t cdf_len;
size_t rdf_len;
ASSERT(memIsValid(apdu, count));
ASSERT(memIsNullOrValid(cmd, sizeof(apdu_cmd_t)));
if (count < 4)
return SIZE_MAX;
if (cmd)
{
ASSERT(memIsDisjoint2(cmd, sizeof(apdu_cmd_t), apdu, count));
memSetZero(cmd, sizeof(apdu_cmd_t));
cmd->cla = apdu[0], cmd->ins = apdu[1];
cmd->p1 = apdu[2], cmd->p2 = apdu[3];
}
apdu += 4, count -= 4;
if (count == 0 || count == 1 || count == 3 && apdu[0] == 0)
cdf_len_len = 0, cdf_len = 0;
else
{
ASSERT(count > 1);
if (apdu[0])
cdf_len_len = 1, cdf_len = apdu[0];
else
{
if (count < 3)
return SIZE_MAX;
cdf_len_len = 3;
cdf_len = apdu[1], cdf_len *= 256, cdf_len += apdu[2];
}
apdu += cdf_len_len, count -= cdf_len_len;
}
if (cdf_len > count)
return SIZE_MAX;
if (cmd)
memCopy(cmd->cdf, apdu, cdf_len);
apdu += cdf_len, count -= cdf_len;
switch (count)
{
case 0:
rdf_len = 0;
break;
case 1:
rdf_len = apdu[0];
if (rdf_len == 0)
rdf_len = 256;
if (cdf_len_len == 3)
return SIZE_MAX;
break;
case 2:
rdf_len = apdu[0], rdf_len *= 256, rdf_len += apdu[1];
if (rdf_len == 0)
rdf_len = 65536;
if (cdf_len_len <= 1 || cdf_len < 256 && rdf_len <= 256)
return SIZE_MAX;
break;
case 3:
rdf_len = apdu[1], rdf_len *= 256, rdf_len += apdu[2];
if (rdf_len == 0)
rdf_len = 65536;
if (apdu[0] != 0 || cdf_len_len != 0 || rdf_len <= 256)
return SIZE_MAX;
break;
default:
return SIZE_MAX;
}
if (cmd)
cmd->cdf_len = cdf_len, cmd->rdf_len = rdf_len;
return sizeof(apdu_cmd_t) + cdf_len;
}
bool_t apduRespIsValid(const apdu_resp_t* resp)
{
return memIsValid(resp, sizeof(apdu_resp_t)) &&
resp->rdf_len <= 65536 &&
memIsValid(resp->rdf, resp->rdf_len);
}
size_t apduRespEnc(octet apdu[], const apdu_resp_t* resp)
{
ASSERT(apduRespIsValid(resp));
if (apdu)
{
ASSERT(memIsValid(apdu, resp->rdf_len + 2));
memCopy(apdu, resp->rdf, resp->rdf_len);
apdu[resp->rdf_len] = resp->sw1, apdu[resp->rdf_len + 1] = resp->sw2;
}
return resp->rdf_len + 2;
}
size_t apduRespDec(apdu_resp_t* resp, const octet apdu[], size_t count)
{
ASSERT(memIsValid(apdu, count));
ASSERT(memIsNullOrValid(resp, sizeof(apdu_resp_t)));
if (count < 2)
return SIZE_MAX;
if (resp)
{
memSetZero(resp, sizeof(apdu_resp_t));
resp->sw1 = apdu[count - 2], resp->sw2 = apdu[count - 1];
resp->rdf_len = count - 2;
memCopy(resp->rdf, apdu, resp->rdf_len);
}
return sizeof(apdu_resp_t) + count - 2;
}