#include <stdlib.h>
#include <string.h>
#include "atca_command.h"
#include "atca_devtypes.h"
#include "atca_config.h"
ATCA_STATUS atCheckMAC(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_CHECKMAC;
packet->txsize = CHECKMAC_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atCounter(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_COUNTER;
packet->txsize = COUNTER_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atDeriveKey(ATCACommand ca_cmd, ATCAPacket *packet, bool has_mac)
{
packet->opcode = ATCA_DERIVE_KEY;
if (has_mac)
{
packet->txsize = DERIVE_KEY_COUNT_LARGE;
}
else
{
packet->txsize = DERIVE_KEY_COUNT_SMALL;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atECDH(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_ECDH;
packet->txsize = ECDH_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atGenDig(ATCACommand ca_cmd, ATCAPacket *packet, bool is_no_mac_key)
{
packet->opcode = ATCA_GENDIG;
if (packet->param1 == GENDIG_ZONE_SHARED_NONCE) {
packet->txsize = GENDIG_COUNT + 32;
}
else if (is_no_mac_key)
{
packet->txsize = GENDIG_COUNT + 4; }
else
{
packet->txsize = GENDIG_COUNT;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atGenKey(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_GENKEY;
if (packet->param1 & GENKEY_MODE_PUBKEY_DIGEST)
{
packet->txsize = GENKEY_COUNT_DATA;
}
else
{
packet->txsize = GENKEY_COUNT;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atHMAC(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_HMAC;
packet->txsize = HMAC_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atInfo(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_INFO;
packet->txsize = INFO_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atLock(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_LOCK;
packet->txsize = LOCK_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atMAC(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_MAC;
if (!(packet->param1 & MAC_MODE_BLOCK2_TEMPKEY))
{
packet->txsize = MAC_COUNT_LONG;
}
else
{
packet->txsize = MAC_COUNT_SHORT;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atNonce(ATCACommand ca_cmd, ATCAPacket *packet)
{
uint8_t calc_mode = packet->param1 & NONCE_MODE_MASK;
packet->opcode = ATCA_NONCE;
if ((calc_mode == NONCE_MODE_SEED_UPDATE || calc_mode == NONCE_MODE_NO_SEED_UPDATE))
{
packet->txsize = NONCE_COUNT_SHORT;
}
else if (calc_mode == NONCE_MODE_PASSTHROUGH)
{
if ((packet->param1 & NONCE_MODE_INPUT_LEN_MASK) == NONCE_MODE_INPUT_LEN_64)
{
packet->txsize = NONCE_COUNT_LONG_64;
}
else
{
packet->txsize = NONCE_COUNT_LONG;
}
}
else
{
return ATCA_BAD_PARAM;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atPause(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_PAUSE;
packet->txsize = PAUSE_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atPrivWrite(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_PRIVWRITE;
packet->txsize = PRIVWRITE_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atRandom(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_RANDOM;
packet->txsize = RANDOM_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atRead(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_READ;
packet->txsize = READ_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atSecureBoot(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_SECUREBOOT;
packet->txsize = ATCA_CMD_SIZE_MIN;
switch (packet->param1 & SECUREBOOT_MODE_MASK)
{
case SECUREBOOT_MODE_FULL:
case SECUREBOOT_MODE_FULL_COPY:
packet->txsize += (SECUREBOOT_DIGEST_SIZE + SECUREBOOT_SIGNATURE_SIZE);
break;
case SECUREBOOT_MODE_FULL_STORE:
packet->txsize += SECUREBOOT_DIGEST_SIZE;
break;
default:
return ATCA_BAD_PARAM;
break;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atSHA(ATCACommand ca_cmd, ATCAPacket *packet, uint16_t write_context_size)
{
packet->opcode = ATCA_SHA;
switch (packet->param1 & SHA_MODE_MASK)
{
case SHA_MODE_SHA256_START: case SHA_MODE_HMAC_START:
case SHA_MODE_SHA256_PUBLIC:
packet->txsize = ATCA_CMD_SIZE_MIN;
break;
case SHA_MODE_SHA256_UPDATE: packet->txsize = ATCA_CMD_SIZE_MIN + packet->param2;
break;
case SHA_MODE_SHA256_END: case SHA_MODE_HMAC_END:
packet->txsize = ATCA_CMD_SIZE_MIN + packet->param2;
break;
case SHA_MODE_READ_CONTEXT:
packet->txsize = ATCA_CMD_SIZE_MIN;
break;
case SHA_MODE_WRITE_CONTEXT:
packet->txsize = ATCA_CMD_SIZE_MIN + write_context_size;
break;
default:
return ATCA_BAD_PARAM;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atSign(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_SIGN;
packet->txsize = SIGN_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atUpdateExtra(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_UPDATE_EXTRA;
packet->txsize = UPDATE_COUNT;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atVerify(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_VERIFY;
switch (packet->param1 & VERIFY_MODE_MASK)
{
case VERIFY_MODE_STORED:
packet->txsize = VERIFY_256_STORED_COUNT;
break;
case VERIFY_MODE_VALIDATE_EXTERNAL:
packet->txsize = VERIFY_256_EXTERNAL_COUNT;
break;
case VERIFY_MODE_EXTERNAL:
packet->txsize = VERIFY_256_EXTERNAL_COUNT;
break;
case VERIFY_MODE_VALIDATE:
case VERIFY_MODE_INVALIDATE:
packet->txsize = VERIFY_256_VALIDATE_COUNT;
break;
default:
return ATCA_BAD_PARAM;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atWrite(ATCACommand ca_cmd, ATCAPacket *packet, bool has_mac)
{
packet->opcode = ATCA_WRITE;
packet->txsize = 7;
if (packet->param1 & ATCA_ZONE_READWRITE_32)
{
packet->txsize += ATCA_BLOCK_SIZE;
}
else
{
packet->txsize += ATCA_WORD_SIZE;
}
if (has_mac)
{
packet->txsize += WRITE_MAC_SIZE;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atAES(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_AES;
packet->txsize = ATCA_CMD_SIZE_MIN;
if ((packet->param1 & AES_MODE_OP_MASK) == AES_MODE_GFM)
{
packet->txsize += ATCA_AES_GFM_SIZE;
}
else
{
packet->txsize += AES_DATA_SIZE;
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atSelfTest(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_SELFTEST;
packet->txsize = ATCA_CMD_SIZE_MIN;
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS atKDF(ATCACommand ca_cmd, ATCAPacket *packet)
{
packet->opcode = ATCA_KDF;
if ((packet->param1 & KDF_MODE_ALG_MASK) == KDF_MODE_ALG_AES)
{
packet->txsize = ATCA_CMD_SIZE_MIN + KDF_DETAILS_SIZE + AES_DATA_SIZE;
}
else
{
packet->txsize = ATCA_CMD_SIZE_MIN + KDF_DETAILS_SIZE + packet->data[3];
}
atCalcCrc(packet);
return ATCA_SUCCESS;
}
ATCA_STATUS initATCACommand(ATCADeviceType device_type, ATCACommand ca_cmd)
{
if (ca_cmd == NULL)
{
return ATCA_BAD_PARAM;
}
ca_cmd->dt = device_type;
ca_cmd->clock_divider = 0;
return ATCA_SUCCESS;
}
#ifndef ATCA_NO_HEAP
ATCACommand newATCACommand(ATCADeviceType device_type)
{
ATCACommand ca_cmd;
ATCA_STATUS status;
ca_cmd = (ATCACommand)malloc(sizeof(*ca_cmd));
status = initATCACommand(device_type, ca_cmd);
if (status != ATCA_SUCCESS)
{
free(ca_cmd);
ca_cmd = NULL;
return NULL;
}
return ca_cmd;
}
#endif
#ifndef ATCA_NO_HEAP
void deleteATCACommand(ATCACommand *ca_cmd)
{
if (ca_cmd == NULL)
{
return;
}
free(*ca_cmd);
*ca_cmd = NULL;
}
#endif
void atCRC(size_t length, const uint8_t *data, uint8_t *crc_le)
{
size_t counter;
uint16_t crc_register = 0;
uint16_t polynom = 0x8005;
uint8_t shift_register;
uint8_t data_bit, crc_bit;
for (counter = 0; counter < length; counter++)
{
for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1)
{
data_bit = (data[counter] & shift_register) ? 1 : 0;
crc_bit = crc_register >> 15;
crc_register <<= 1;
if (data_bit != crc_bit)
{
crc_register ^= polynom;
}
}
}
crc_le[0] = (uint8_t)(crc_register & 0x00FF);
crc_le[1] = (uint8_t)(crc_register >> 8);
}
void atCalcCrc(ATCAPacket *packet)
{
uint8_t length, *crc;
packet->param2 = ATCA_UINT16_HOST_TO_LE(packet->param2);
length = packet->txsize - ATCA_CRC_SIZE;
crc = &(packet->txsize) + length;
atCRC(length, &(packet->txsize), crc);
}
ATCA_STATUS atCheckCrc(const uint8_t *response)
{
uint8_t crc[ATCA_CRC_SIZE];
uint8_t count = response[ATCA_COUNT_IDX];
count -= ATCA_CRC_SIZE;
atCRC(count, response, crc);
return (crc[0] == response[count] && crc[1] == response[count + 1]) ? ATCA_SUCCESS : ATCA_RX_CRC_ERROR;
}
bool atIsSHAFamily(ATCADeviceType device_type)
{
switch (device_type)
{
case ATSHA204A:
case ATSHA206A:
case ATECC108A:
case ATECC508A:
case ATECC608A:
return true;
break;
default:
return false;
break;
}
}
bool atIsECCFamily(ATCADeviceType device_type)
{
switch (device_type)
{
case ATECC108A:
case ATECC508A:
case ATECC608A:
return true;
break;
default:
return false;
break;
}
}
ATCA_STATUS isATCAError(uint8_t *data)
{
if (data[0] == 0x04) {
switch (data[1])
{
case 0x00: return ATCA_SUCCESS;
case 0x01: return ATCA_CHECKMAC_VERIFY_FAILED;
break;
case 0x03: return ATCA_PARSE_ERROR;
break;
case 0x05: return ATCA_STATUS_ECC;
break;
case 0x07: return ATCA_STATUS_SELFTEST_ERROR;
break;
case 0x08: return ATCA_HEALTH_TEST_ERROR;
case 0x0f: return ATCA_EXECUTION_ERROR;
break;
case 0x11: return ATCA_WAKE_SUCCESS;
break;
case 0xff: return ATCA_STATUS_CRC;
break;
default:
return ATCA_GEN_FAIL;
break;
}
}
else
{
return ATCA_SUCCESS;
}
}