5.7.11. Import External Object Prepare¶
Import External Object command allows the user to import
an external object wrapped with a secure ECKey_Auth
context. A session is not required to execute this command,
the ECKey_Auth
parameters are provided with the wrapped
WriteSecureObject command. The applet will use ECKey_Auth
parameters and derive session keys to unwrap the command
and execute it. ImportExternalObject
command works in its
own session. It will open an ECKey
session, write the secure
object and close the session.
In this example, we prepare a complete raw APDU to be sent
to SE05x. A WriteSecureObject
command needs to be prepared
which will be wrapped and sent as a part of ImportExternalObject
command. For an example we are preparing WriteSymmKey
command as :
/* Symmetric Key */
/* clang-format off */
uint8_t keyValue[] = {0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x31};
/* clang-format on */
/* API to create buffer */
pse05xWriteBufferSessionCtx->fp_TXn = &se05x_ImportExtObjCreateAPDU;
int index = 0;
sm_status = Se05x_API_WriteSymmKey(pse05xWriteBufferSessionCtx,
NULL,
SE05x_MaxAttemps_NA,
__LINE__,
SE05x_KeyID_KEK_NONE,
keyValue,
sizeof(keyValue),
kSE05x_INS_NA,
kSE05x_SymmKeyType_AES);
if (sm_status != SM_OK) {
LOG_E("Failed to create buffer");
status = kStatus_SSS_Fail;
goto exit;
}
/* WriteSecureObject API will prepare complete APDU.
* We need to skip initial CLA INS P1 P2 and use just the TLVs
*
* The length is determined by the first length byte. If it
* is 0x00, the next two bytes are the length, otherwise that
* byte is the length.
*
* Determine the length here and accordingly determine the TLV.
*/
if (gTxBuffer[4] == 0x00) {
WriteSymmKeyAPDU_len = ((gTxBuffer[5] << 8) && 0xFF00) | ((gTxBuffer[6]) && 0xFF);
index = 7;
}
else {
WriteSymmKeyAPDU_len = gTxBuffer[4];
index = 5;
}
if (WriteSymmKeyAPDU_len > sizeof(WriteSymmKeyAPDU)) {
LOG_E("Insufficient buffer");
status = kStatus_SSS_Fail;
goto exit;
}
memcpy(WriteSymmKeyAPDU, &gTxBuffer[index], WriteSymmKeyAPDU_len);
/* This API creates an APDU buffer of the object stores it to the global buffer */
smStatus_t se05x_ImportExtObjCreateAPDU(Se05xSession_t *pwrite_apdubufferctx,
const tlvHeader_t *hdr,
uint8_t *cmdBuf,
size_t cmdBufLen,
uint8_t *rsp,
size_t *rspLen,
uint8_t hasle)
{
AX_UNUSED_ARG(pwrite_apdubufferctx);
AX_UNUSED_ARG(rsp);
AX_UNUSED_ARG(rspLen);
memset(gTxBuffer, 0, sizeof(gTxBuffer));
size_t i = 0;
memcpy(&gTxBuffer[i], hdr, sizeof(*hdr));
smStatus_t ret = SM_OK;
i += sizeof(*hdr);
if (cmdBufLen > 0) {
// The Lc field must be extended in case the length does not fit
// into a single byte (Note, while the standard would allow to
// encode 0x100 as 0x00 in the Lc field, nobody who is sane in his mind
// would actually do that).
if ((cmdBufLen < 0xFF) && !hasle) {
gTxBuffer[i++] = (uint8_t)cmdBufLen;
}
else {
gTxBuffer[i++] = 0x00;
gTxBuffer[i++] = 0xFFu & (cmdBufLen >> 8);
gTxBuffer[i++] = 0xFFu & (cmdBufLen);
}
memcpy(&gTxBuffer[i], cmdBuf, cmdBufLen);
i += cmdBufLen;
}
if (hasle) {
gTxBuffer[i++] = 0x00;
gTxBuffer[i++] = 0x00;
}
ret = SM_OK;
gTxBufferLen = i;
LOG_AU8_I(gTxBuffer, gTxBufferLen);
return ret;
}
/* This API transforms buffer to APDU and internally calls transmit and Decrypt */
smStatus_t se05x_ImportExtObjTransformBuffer(Se05xSession_t *pSe05xSession,
const tlvHeader_t *hdr,
uint8_t *cmdBuf,
size_t cmdBufLen,
uint8_t *rsp,
size_t *rspLen,
uint8_t hasle)
{
memset(gTxBuffer, 0, sizeof(gTxBuffer));
size_t i = 0;
memcpy(&gTxBuffer[i], hdr, sizeof(*hdr));
smStatus_t ret = SM_NOT_OK;
i += sizeof(*hdr);
if (cmdBufLen > 0) {
// The Lc field must be extended in case the length does not fit
// into a single byte (Note, while the standard would allow to
// encode 0x100 as 0x00 in the Lc field, nobody who is sane in his mind
// would actually do that).
if ((cmdBufLen < 0xFF) && !hasle) {
gTxBuffer[i++] = (uint8_t)cmdBufLen;
}
else {
gTxBuffer[i++] = 0x00;
gTxBuffer[i++] = 0xFFu & (cmdBufLen >> 8);
gTxBuffer[i++] = 0xFFu & (cmdBufLen);
}
ENSURE_OR_GO_EXIT(cmdBufLen <= sizeof(gTxBuffer) - i);
memcpy(&gTxBuffer[i], cmdBuf, cmdBufLen);
i += cmdBufLen;
}
if (hasle) {
gTxBuffer[i++] = 0x00;
gTxBuffer[i++] = 0x00;
}
gTxBufferLen = i;
LOG_D("Here is the buffer of Object needs to be Import");
LOG_AU8_D(gTxBuffer, gTxBufferLen);
if (pSe05xSession->fp_RawTXn) {
ret = pSe05xSession->fp_RawTXn(
pgSe05xSessionCtx->conn_ctx, NULL, kSSS_AuthType_None, hdr, cmdBuf, cmdBufLen, rsp, rspLen, hasle);
ENSURE_OR_GO_EXIT(ret == SM_OK);
}
if (pSe05xSession->fp_DeCrypt) {
ret = pSe05xSession->fp_DeCrypt(pSe05xSession, cmdBufLen, rsp, rspLen, hasle);
}
exit:
return ret;
}
/* This API transmit the buffer in default session */
static smStatus_t se05x_ImportExtObjTransmitBuffer(void *conn_ctx,
struct _sss_se05x_tunnel_context *pChannelCtx,
SE_AuthType_t currAuth,
const tlvHeader_t *hdr,
uint8_t *cmdBuf,
size_t cmdBufLen,
uint8_t *rsp,
size_t *rspLen,
uint8_t hasle)
{
AX_UNUSED_ARG(pChannelCtx);
AX_UNUSED_ARG(currAuth);
uint8_t txBuf[SE05X_MAX_BUF_SIZE_CMD] = {0};
size_t i = 0;
memcpy(&txBuf[i], hdr, sizeof(*hdr));
smStatus_t ret = SM_NOT_OK;
i += sizeof(*hdr);
if (cmdBufLen > 0) {
// The Lc field must be extended in case the length does not fit
// into a single byte (Note, while the standard would allow to
// encode 0x100 as 0x00 in the Lc field, nobody who is sane in his mind
// would actually do that).
if ((cmdBufLen < 0xFF) && !hasle) {
txBuf[i++] = (uint8_t)cmdBufLen;
}
else {
txBuf[i++] = 0x00;
txBuf[i++] = 0xFFu & (cmdBufLen >> 8);
txBuf[i++] = 0xFFu & (cmdBufLen);
}
memcpy(&txBuf[i], cmdBuf, cmdBufLen);
i += cmdBufLen;
}
else {
if (cmdBufLen == 0) {
txBuf[i++] = 0x00;
}
}
if (hasle) {
txBuf[i++] = 0x00;
txBuf[i++] = 0x00;
}
uint32_t U32rspLen = (uint32_t)*rspLen;
ret = (smStatus_t)smCom_TransceiveRaw(conn_ctx, txBuf, (U16)i, rsp, &U32rspLen);
*rspLen = U32rspLen;
return ret;
}
/* This API decrypts the response buffer */
smStatus_t se05x_ImportExtObjDecryptResponse(
struct Se05xSession *pSessionCtx, size_t cmd_cmacLen, uint8_t *rsp, size_t *rspLength, uint8_t hasle)
{
U16 rv = SM_NOT_OK;
if (*rspLength >= 2) {
rv = rsp[(*rspLength) - 2] << 8 | rsp[(*rspLength) - 1];
if ((rv == SM_OK) && (pSessionCtx->pdynScp03Ctx != NULL)) {
#if SSS_HAVE_SCP_SCP03_SSS
rv = nxpSCP03_Decrypt_ResponseAPDU(pSessionCtx->pdynScp03Ctx, cmd_cmacLen, rsp, rspLength, hasle);
#else
LOG_W("Decrypting without SSS_HAVE_SCP_SCP03_SSS");
rv = SM_NOT_OK;
#endif
}
#if SSS_HAVE_SCP_SCP03_SSS
else { /*Counter to be increament only in case of authentication is all kind of SCP
and response is not 9000 */
if ((rv != SM_OK) && (pSessionCtx->pdynScp03Ctx != NULL)) {
if (((pSessionCtx->pdynScp03Ctx->authType == kSSS_AuthType_AESKey) ||
(pSessionCtx->pdynScp03Ctx->authType == kSSS_AuthType_ECKey)) ||
((pSessionCtx->pdynScp03Ctx->authType == kSSS_AuthType_SCP03) && (cmd_cmacLen - 8) > 0)) {
nxpSCP03_Inc_CommandCounter(pSessionCtx->pdynScp03Ctx);
}
}
}
#endif
}
else {
rv = SM_NOT_OK;
}
return rv;
}
You can call any of the WriteSecureObject
API with your data
and create the buffer.
5.7.11.1. Building¶
Build the project with the following configurations.
se05x_ImportExternalObjectPrepare
Project = se05x_ImportExternalObjectPrepare
SCP=SCP03_SSS
SE05x_Auth=ECKey
5.7.11.2. How to use¶
Generate the raw APDU file by running the executable. Run se05x_ImportExternalObjectPrepare as
se05x_ImportExternalObjectPrepare.exe -keyid 0x7DA00003 -file eckey_ecdsa.der <portName>
where,
keyid is the authentication keyId at which ECDSA public key is stored.
file is the input ECDSA keypair file (in binary format)
portName is the name of the port over which to connect (COMPORT in case running over VCOM)