blob: 0a5199dad5e168c3663db145e30b6ed2a7333dea [file] [log] [blame]
/* Copyright 2019,2020 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include <ex_sss.h>
#include <ex_sss_boot.h>
#include <fsl_sss_se05x_apis.h>
#include <nxLog_App.h>
#include <se05x_APDU.h>
#include <se05x_const.h>
#include <se05x_ecc_curves.h>
#include <se05x_ecc_curves_values.h>
#include <se05x_tlv.h>
#include <string.h>
#include <nxEnsure.h>
#include "ex_sss_auth.h"
#include "global_platf.h"
#include "smCom.h"
static ex_sss_boot_ctx_t gex_sss_get_info_ctx;
#define EX_SSS_BOOT_PCONTEXT (&gex_sss_get_info_ctx)
#define EX_SSS_BOOT_DO_ERASE 0
#define EX_SSS_BOOT_EXPOSE_ARGC_ARGV 1
#define EX_SSS_BOOT_SKIP_SELECT_APPLET 1
#define SEMS_LITE_AGENT_CHANNEL_1 0x01
#define SEMS_LITE_GETDATA_UUID_TAG 0xFE
#include <ex_sss_main_inc.h>
static sss_status_t JCOP4_GetDataIdentify(void *conn_ctx);
static sss_status_t JCOP4_GetCPLCData(void *conn_ctx);
static sss_status_t SemsLite_Applet_Identify(void *conn_ctx);
static sss_status_t Iot_Applet_Identify(sss_se05x_session_t *pSession, int getUid);
static sss_status_t sems_lite_session_open(void *conn_ctx);
static sss_status_t iot_applet_session_open(ex_sss_boot_ctx_t *pCtx);
sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
sss_se05x_session_t *pSession = (sss_se05x_session_t *)&pCtx->session;
status = sems_lite_session_open(pSession->s_ctx.conn_ctx);
if (status == kStatus_SSS_Success) {
/* Get UID from semslite */
status = SemsLite_Applet_Identify(pSession->s_ctx.conn_ctx);
if (status != kStatus_SSS_Success) {
goto cleanup;
}
status = iot_applet_session_open(pCtx);
if (status != kStatus_SSS_Success) {
LOG_I("No IoT applet found");
}
else {
/* Get applet version and config details */
status = Iot_Applet_Identify(pSession, 0);
if (status != kStatus_SSS_Success) {
goto cleanup;
}
}
}
else {
LOG_W("No SemsLite Applet Available. ");
/* Try connecting to iot applet */
status = iot_applet_session_open(pCtx);
if (status != kStatus_SSS_Success) {
LOG_I("Error in iot applet session open");
goto cleanup;
}
/* Get UID, applet version and config details */
status = Iot_Applet_Identify(pSession, 1);
if (status != kStatus_SSS_Success) {
goto cleanup;
}
}
status = JCOP4_GetDataIdentify(pSession->s_ctx.conn_ctx);
if (status != kStatus_SSS_Success)
goto cleanup;
status = JCOP4_GetCPLCData(pSession->s_ctx.conn_ctx);
if (status != kStatus_SSS_Success)
goto cleanup;
status = kStatus_SSS_Success;
cleanup:
return status;
}
static sss_status_t iot_applet_session_open(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
const char *portName;
ex_sss_session_close(pCtx);
status = ex_sss_boot_connectstring(gex_sss_argc, gex_sss_argv, &portName);
if (kStatus_SSS_Success != status) {
LOG_E("ex_sss_boot_connectstring Failed");
goto cleanup;
}
pCtx->se05x_open_ctx.skip_select_applet = 0;
status = ex_sss_boot_open(pCtx, portName);
if (kStatus_SSS_Success != status) {
LOG_E("ex_sss_session_open Failed");
goto cleanup;
}
status = kStatus_SSS_Success;
cleanup:
return status;
}
static sss_status_t sems_lite_session_open(void *conn_ctx)
{
sss_status_t status = kStatus_SSS_Fail;
U32 ret = 0;
smStatus_t retStatus = SM_NOT_OK;
#ifdef SEMS_LITE_AGENT_CHANNEL_1
const uint8_t openCmd[] = {0x00, 0x70, 0x00, 0x00, 0x01};
U16 openCmdLen = sizeof(openCmd);
#endif
/* clang-format off */
const uint8_t selectCmd[] = {
#ifdef SEMS_LITE_AGENT_CHANNEL_1
0x01, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00,
#else
0x00, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00,
#endif
0x03, 0x96, 0x54, 0x53, 0x00, 0x00, 0x00, 0x01,
0x03, 0x30, 0x00, 0x00, 0x00, 0x00,
};
/* clang-format on */
U16 selectCmdLen = sizeof(selectCmd);
uint8_t resp[128] = {0x00};
U32 respLen = sizeof(resp);
ENSURE_OR_GO_EXIT(conn_ctx != NULL);
#ifdef SEMS_LITE_AGENT_CHANNEL_1
ret = smCom_TransceiveRaw(conn_ctx, (uint8_t *)openCmd, openCmdLen, resp, &respLen);
ENSURE_OR_GO_EXIT(ret == SM_OK);
#endif
respLen = sizeof(resp);
ret = smCom_TransceiveRaw(conn_ctx, (uint8_t *)selectCmd, selectCmdLen, resp, &respLen);
ENSURE_OR_GO_EXIT(ret == SM_OK);
retStatus = (resp[respLen - 2] << 8) | (resp[respLen - 1]);
if (retStatus != SM_OK) {
goto exit;
}
status = kStatus_SSS_Success;
exit:
return status;
}
#define CHECK_FEATURE_PRESENT(AppletConfig, ITEM) \
if (((kSE05x_AppletConfig_##ITEM) == ((AppletConfig) & (kSE05x_AppletConfig_##ITEM)))) { \
LOG_I("With " #ITEM); \
} \
else { \
LOG_I("WithOut " #ITEM); \
}
static sss_status_t sems_lite_verify_GetDataResponse(uint8_t tag_P2, uint8_t *pRspBuf, U32 *pRspBufLen)
{
sss_status_t sss_stat = kStatus_SSS_Fail;
size_t getDataRspLen = 0;
smStatus_t retStatus = SM_NOT_OK;
if (*pRspBufLen > 2) {
getDataRspLen = *pRspBufLen;
retStatus = (pRspBuf[getDataRspLen - 2] << 8) | (pRspBuf[getDataRspLen - 1]);
if (retStatus == SM_OK) {
if (pRspBuf[0] == tag_P2) {
if (pRspBuf[1] > 0) {
*pRspBufLen = pRspBuf[1];
memmove(pRspBuf, pRspBuf + 2, pRspBuf[1]);
sss_stat = kStatus_SSS_Success;
}
else {
memset(pRspBuf, 0, *pRspBufLen);
*pRspBufLen = 0;
}
}
}
}
return sss_stat;
}
static sss_status_t SemsLite_Applet_Identify(void *conn_ctx)
{
sss_status_t status = kStatus_SSS_Fail;
U32 ret = 0;
uint8_t uid[64];
U32 uidLen = sizeof(uid);
uint8_t tag_P1 = 0x00;
uint8_t tag_P2 = SEMS_LITE_GETDATA_UUID_TAG;
uint8_t getDataCmd[32] = {
0x80, // CLA '80' / '00' GlobalPlatform / ISO / IEC
0xCA, // INS 'CA' GET DATA(IDENTIFY)
0x00, // P1 '00' High order tag value
0x00, // P2 - proprietary data coming from respective function
0x00, // Lc is Le'00' Case 2 command
};
U16 getDataCmdLen = 5;
getDataCmd[2] = tag_P1;
getDataCmd[3] = tag_P2;
#ifdef SEMS_LITE_AGENT_CHANNEL_1
getDataCmd[0] = getDataCmd[0] | SEMS_LITE_AGENT_CHANNEL_1;
#endif
ret = smCom_TransceiveRaw(conn_ctx, (uint8_t *)getDataCmd, getDataCmdLen, uid, &uidLen);
if (ret != SM_OK) {
LOG_E("Could not get requested Data!!!");
goto cleanup;
}
if (kStatus_SSS_Success != sems_lite_verify_GetDataResponse(SEMS_LITE_GETDATA_UUID_TAG, uid, &uidLen)) {
goto cleanup;
}
LOG_W("#####################################################");
LOG_AU8_I(uid, uidLen);
status = kStatus_SSS_Success;
cleanup:
return status;
}
static sss_status_t Iot_Applet_Identify(sss_se05x_session_t *pSession, int getUid)
{
sss_status_t status = kStatus_SSS_Fail;
smStatus_t sw_status;
SE05x_Result_t result = kSE05x_Result_NA;
uint8_t uid[SE050_MODULE_UNIQUE_ID_LEN];
size_t uidLen = sizeof(uid);
uint8_t applet_version[7];
size_t applet_versionLen = sizeof(applet_version);
if (getUid == 1) {
sw_status = Se05x_API_CheckObjectExists(&pSession->s_ctx, kSE05x_AppletResID_UNIQUE_ID, &result);
if (SM_OK != sw_status) {
LOG_E("Failed Se05x_API_CheckObjectExists");
goto cleanup;
}
sw_status =
Se05x_API_ReadObject(&pSession->s_ctx, kSE05x_AppletResID_UNIQUE_ID, 0, (uint16_t)uidLen, uid, &uidLen);
if (SM_OK != sw_status) {
LOG_E("Failed Se05x_API_CheckObjectExists");
goto cleanup;
}
LOG_W("#####################################################");
LOG_AU8_I(uid, uidLen);
}
// VersionInfo is a 7 - byte value consisting of :
// - 1 - byte Major applet version
// - 1 - byte Minor applet version
// - 1 - byte patch applet version
// - 2 - byte AppletConfig, indicating the supported applet features
// - 2-byte Secure Box version: major version (MSB) concatenated with minor version (LSB).
sw_status = Se05x_API_GetVersion(&pSession->s_ctx, applet_version, &applet_versionLen);
if (SM_OK != sw_status) {
LOG_E("Failed Se05x_API_GetVersion");
goto cleanup;
}
LOG_W("#####################################################");
LOG_I("Applet Major = %d", applet_version[0]);
LOG_I("Applet Minor = %d", applet_version[1]);
LOG_I("Applet patch = %d", applet_version[2]);
LOG_I("AppletConfig = %02X%02X", applet_version[3], applet_version[4]);
{
U16 AppletConfig = applet_version[3] << 8 | applet_version[4];
CHECK_FEATURE_PRESENT(AppletConfig, ECDAA);
CHECK_FEATURE_PRESENT(AppletConfig, ECDSA_ECDH_ECDHE);
CHECK_FEATURE_PRESENT(AppletConfig, EDDSA);
CHECK_FEATURE_PRESENT(AppletConfig, DH_MONT);
CHECK_FEATURE_PRESENT(AppletConfig, HMAC);
CHECK_FEATURE_PRESENT(AppletConfig, RSA_PLAIN);
CHECK_FEATURE_PRESENT(AppletConfig, RSA_CRT);
CHECK_FEATURE_PRESENT(AppletConfig, AES);
CHECK_FEATURE_PRESENT(AppletConfig, DES);
CHECK_FEATURE_PRESENT(AppletConfig, PBKDF);
CHECK_FEATURE_PRESENT(AppletConfig, TLS);
CHECK_FEATURE_PRESENT(AppletConfig, MIFARE);
CHECK_FEATURE_PRESENT(AppletConfig, I2CM);
}
LOG_I("Internal = %02X%02X", applet_version[5], applet_version[6]);
status = kStatus_SSS_Success;
cleanup:
return status;
}
/* Execute and decode GET DATA IDENTIFY as specified for SE05x JCOP
*
* @warn After this call, the applet is deselected and applet commands won't work.
* The applet session needs to be re-established
* (select applet, establish optional session, like in the sss_session_open()
*/
static sss_status_t JCOP4_GetDataIdentify(void *conn_ctx)
{
sss_status_t status = kStatus_SSS_Fail;
smStatus_t rxStatus;
char jcop_platform_id[17] = {0};
/* Must be packed */
typedef struct
{
//0xFE Tag value - proprietary data Only present if class byte is 0x80
uint8_t vTag_value_proprietary_data;
//0x49 / 0x45 Length of following data Only present if class byte is 0x80
uint8_t vLength_of_following_data;
//0xDF28 Tag card identification data Only present if class byte is 0x80
uint8_t vTag_card_identification_data[0x02];
//0x46 Length of card identification data Only present if class byte is 0x80
uint8_t vLength_of_card_identification_data;
//0x01 Tag configuration ID Identifies the configuration content
uint8_t vTag_configuration_ID;
uint8_t vLength_configuration_ID; //0x0C Length configuration ID
uint8_t vConfiguration_ID[0x0C]; //var Configuration ID
uint8_t vTag_patch_ID; //0x02 Tag patch ID Identifies the patch level
uint8_t vLength_patch_ID; //0x08 Length patch ID
uint8_t vPatch_ID[0x08]; //var Patch ID
//0x03 Tag platform build ID1 Identifies the JCOP platform
uint8_t vTag_platform_build_ID1;
uint8_t vLength_platform_build_ID; //0x18 Length platform build ID
uint8_t vPlatform_build_ID[0x18]; //var Platform build ID
uint8_t vTag_FIPS_mode; //0x052 Tag FIPS mode FIPS mode active
uint8_t vLength_FIPS_mode; //0x01 Length FIPS mode
//var FIPS mode 0x00 - FIPS mode not active, 0x01 - FIPS mode active
uint8_t vFIPS_mode;
//uint8_t vTag_modules_enabled; //0x06 Tag modules enabled Lists enabled and disabled modules
//uint8_t vLength_modules_enabled; //0x02 Length modules enabled Big endian format
//uint8_t vBit_mask_of_enabled_modules[0x02]; //var Bit mask of enabled modules See Table 5.3
//0x07 Tag pre-perso state Lists pre-perso state
uint8_t vTag_pre_perso_state;
//0x01 Length pre-perso state
uint8_t vLength_pre_perso_state;
//var Bit mask of pre-perso state bit0 = 1 = config module available,
// bit1 = 1 = transport state is active.
// Unused bits are set to 0x0.
uint8_t vBit_mask_of_pre_perso_state;
uint8_t vTag_ROM_ID; //'08' Tag ROM ID Indentifies the ROM content
uint8_t vLength_ROM_ID; //'08' Length ROM ID Normal ending
uint8_t vROM_ID[0x08]; //var ROM ID
uint8_t vStatus_Word_SW_[0x02]; //9000h Status Word (SW)
} identifyRsp_t;
const uint8_t cmd[] = {
0x80, // CLA '80' / '00' GlobalPlatform / ISO / IEC
0xCA, // INS 'CA' GET DATA(IDENTIFY)
0x00, // P1 '00' High order tag value
0xFE, // P2 'FE' Low order tag value - proprietary data
0x02, // Lc '02' Length of data field
0xDF,
0x28, // Data 'DF28' Card identification data
0x00 // Le '00' Length of response data
};
identifyRsp_t identifyRsp = {0};
U32 prspLen = sizeof(identifyRsp_t);
U16 dummyResponse16 = sizeof(identifyRsp_t);
/* Select card manager / ISD
* (ReUsing same dummy buffers) */
rxStatus = GP_Select(conn_ctx, (uint8_t *)&identifyRsp /* dummy */, 0, (uint8_t *)&identifyRsp, &dummyResponse16);
if (rxStatus != SM_OK) {
LOG_E("Could not select ISD.");
goto cleanup;
}
rxStatus = smCom_TransceiveRaw(conn_ctx, (uint8_t *)cmd, sizeof(cmd), (uint8_t *)&identifyRsp, &prspLen);
if (rxStatus == SM_OK && prspLen == sizeof(identifyRsp)) {
LOG_W("#####################################################");
LOG_I("%s = 0x%02X", "Tag value - proprietary data 0xFE", identifyRsp.vTag_value_proprietary_data);
LOG_I("%s = 0x%02X", "Length of following data 0x45", identifyRsp.vLength_of_following_data);
LOG_MAU8_I("Tag card identification data",
identifyRsp.vTag_card_identification_data,
sizeof(identifyRsp.vTag_card_identification_data));
LOG_I("%s = 0x%02X",
"Length of card identification data", // 0x46
identifyRsp.vLength_of_card_identification_data);
LOG_I("%s = 0x%02X", "Tag configuration ID (Must be 0x01)", identifyRsp.vTag_configuration_ID);
LOG_D("%s = 0x%02X", "Length configuration ID 0x0C", identifyRsp.vLength_configuration_ID);
LOG_MAU8_I("Configuration ID", identifyRsp.vConfiguration_ID, sizeof(identifyRsp.vConfiguration_ID));
//Third and fourth Byte of vConfiguration_ID is the OEF ID
LOG_MAU8_I("OEF ID", &identifyRsp.vConfiguration_ID[2], 2);
LOG_I("%s = 0x%02X", "Tag patch ID (Must be 0x02)", identifyRsp.vTag_patch_ID);
LOG_D("%s = 0x%02X", "Length patch ID 0x08", identifyRsp.vLength_patch_ID);
LOG_MAU8_I("Patch ID", identifyRsp.vPatch_ID, sizeof(identifyRsp.vPatch_ID));
LOG_I("%s = 0x%02X", "Tag platform build ID1 (Must be 0x03)", identifyRsp.vTag_platform_build_ID1);
LOG_D("%s = 0x%02X", "Length platform build ID 0x18", identifyRsp.vLength_platform_build_ID);
LOG_MAU8_I("Platform build ID", identifyRsp.vPlatform_build_ID, sizeof(identifyRsp.vPlatform_build_ID));
memcpy(jcop_platform_id, identifyRsp.vPlatform_build_ID, 16);
LOG_I("%s = %s", "JCOP Platform ID", jcop_platform_id);
LOG_I("%s = 0x%02X", "Tag FIPS mode (Must be 0x05)", identifyRsp.vTag_FIPS_mode);
LOG_D("%s = 0x%02X", "Length FIPS mode 0x01", identifyRsp.vLength_FIPS_mode);
LOG_I("%s = 0x%02X", "FIPS mode var", identifyRsp.vFIPS_mode);
//LOG_I("%s = 0x%02X", "Tag modules enabled 0x06", identifyRsp.vTag_modules_enabled);
//LOG_I("%s = 0x%02X", "Length modules enabled 0x02", identifyRsp.vLength_modules_enabled);
//LOG_MAU8_I("Bit mask of enabled modules", identifyRsp.vBit_mask_of_enabled_modules, sizeof(identifyRsp.vBit_mask_of_enabled_modules));
LOG_I("%s = 0x%02X", "Tag pre-perso state (Must be 0x07)", identifyRsp.vTag_pre_perso_state);
LOG_D("%s = 0x%02X", "Length pre-perso state 0x01", identifyRsp.vLength_pre_perso_state);
LOG_I("%s = 0x%02X", "Bit mask of pre-perso state var", identifyRsp.vBit_mask_of_pre_perso_state);
LOG_I("%s = 0x%02X", "Tag ROM ID (Must be 0x08)", identifyRsp.vTag_ROM_ID);
LOG_D("%s = 0x%02X", "Length ROM ID 0x08", identifyRsp.vLength_ROM_ID);
LOG_MAU8_I("ROM ID", identifyRsp.vROM_ID, sizeof(identifyRsp.vROM_ID));
LOG_MAU8_I("Status Word (SW)", identifyRsp.vStatus_Word_SW_, sizeof(identifyRsp.vStatus_Word_SW_));
}
else {
LOG_E("Error in retreiving the JCOP Identifier. Response is as follows");
LOG_AU8_E((uint8_t *)&identifyRsp, sizeof(identifyRsp));
goto cleanup;
}
status = kStatus_SSS_Success;
cleanup:
if (kStatus_SSS_Success == status) {
LOG_I("se05x_GetInfoPlainApplet Example Success !!!...");
}
else {
LOG_E("se05x_GetInfoPlainApplet Example Failed !!!...");
}
return status;
}
/* See 5.1.1.2 Get CPLC data
* This command returns the Card Production Life Cycle (CPLC) data. The APDU can be sent without prior authentication.
*
*
* The Card Production Life Cycle data as defined in VISA GlobalPlatform Card Specification 2.1.1 are coded in 42
* bytes. The CPLC format and the default values are shown below
*
*/
static sss_status_t JCOP4_GetCPLCData(void *conn_ctx)
{
sss_status_t status = kStatus_SSS_Fail;
smStatus_t rxStatus;
/* Must be packed */
typedef struct
{
uint8_t p9F7F[2];
uint8_t pLen[1]; // = 2A
uint8_t IC_fabricator[2]; // 2 '4790' NXP
uint8_t IC_type1[2]; // 2 'D321' NXP
uint8_t Operating_system_identifier[2]; // 2 '47' SS NXP
uint8_t Operating_system_release_date[2]; // 2 SS SS NXP
uint8_t Operating_system_release_level[2]; // 2 <Mask ID> <Patch ID> NXP
uint8_t IC_fabrication_date[2]; // tt NXP
uint8_t IC_Serial_number[4]; // 4 nnnb NXP
uint8_t IC_Batch_identifier[2]; // 2 bb NXP
uint8_t IC_module_fabricator[2]; // 2 '00' '00' Customer
uint8_t IC_module_packaging_date[2]; // 2 '00' '00' Customer
uint8_t ICC_manufacturer[2]; // 2 '00' '00' Customer
uint8_t IC_embedding_date[2]; // 2 '00' '00' Customer
uint8_t IC_OS_initializer[2]; // 2 WX Customer
uint8_t IC_OS_initialization_date[2]; // 2 YN Customer
uint8_t IC_OS_initialization_equipment[4]; // ID 4 NNNN Customer
uint8_t IC_personalizer[2]; // 2 '00' '00' Customer
uint8_t IC_personalization_date[2]; // 2 '00' '00' Customer
uint8_t IC_personalization_equipment_ID[4]; // 4 '00'. . . '00' Customer
uint8_t SW[2];
} cplcRsp_t;
const uint8_t cmd[] = {
0x80, // CLA '80' / '00' GlobalPlatform / ISO / IEC
0xCA, // INS
0x9F, // P1
0x7F, // P2
0x00, // Lc
};
cplcRsp_t cplc_data = {{0}};
U32 cplc_data_len = sizeof(cplcRsp_t);
SSS_ASSERT(sizeof(cplcRsp_t) == 47);
rxStatus = smCom_TransceiveRaw(conn_ctx, (uint8_t *)cmd, sizeof(cmd), (uint8_t *)&cplc_data, &cplc_data_len);
if (rxStatus == SM_OK && cplc_data_len == sizeof(cplc_data)) {
LOG_W("#####################################################");
LOG_AU8_I(cplc_data.IC_fabricator, sizeof(cplc_data.IC_fabricator));
LOG_AU8_I(cplc_data.IC_type1, sizeof(cplc_data.IC_type1));
LOG_AU8_I(cplc_data.Operating_system_identifier, sizeof(cplc_data.Operating_system_identifier));
LOG_AU8_I(cplc_data.Operating_system_release_date, sizeof(cplc_data.Operating_system_release_date));
LOG_AU8_I(cplc_data.Operating_system_release_level, sizeof(cplc_data.Operating_system_release_level));
LOG_AU8_I(cplc_data.IC_fabrication_date, sizeof(cplc_data.IC_fabrication_date));
LOG_AU8_I(cplc_data.IC_Serial_number, sizeof(cplc_data.IC_Serial_number));
LOG_AU8_I(cplc_data.IC_Batch_identifier, sizeof(cplc_data.IC_Batch_identifier));
LOG_AU8_I(cplc_data.IC_module_fabricator, sizeof(cplc_data.IC_module_fabricator));
LOG_AU8_I(cplc_data.IC_module_packaging_date, sizeof(cplc_data.IC_module_packaging_date));
LOG_AU8_I(cplc_data.ICC_manufacturer, sizeof(cplc_data.ICC_manufacturer));
LOG_AU8_I(cplc_data.IC_embedding_date, sizeof(cplc_data.IC_embedding_date));
LOG_AU8_I(cplc_data.IC_OS_initializer, sizeof(cplc_data.IC_OS_initializer));
LOG_AU8_I(cplc_data.IC_OS_initialization_date, sizeof(cplc_data.IC_OS_initialization_date));
LOG_AU8_I(cplc_data.IC_OS_initialization_equipment, sizeof(cplc_data.IC_OS_initialization_equipment));
LOG_AU8_I(cplc_data.IC_personalizer, sizeof(cplc_data.IC_personalizer));
LOG_AU8_I(cplc_data.IC_personalization_date, sizeof(cplc_data.IC_personalization_date));
LOG_AU8_I(cplc_data.IC_personalization_equipment_ID, sizeof(cplc_data.IC_personalization_equipment_ID));
LOG_AU8_I(cplc_data.SW, sizeof(cplc_data.SW));
}
else {
LOG_E("Error in retreiving the CPLC Data. Response is as follows");
LOG_AU8_E((uint8_t *)&cplc_data, sizeof(cplc_data));
goto cleanup;
}
status = kStatus_SSS_Success;
cleanup:
return status;
}