blob: c584c0a906786adfffb391b20d1c19bfdc638f64 [file] [log] [blame]
/*
* Copyright 2020 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "se05x_ImportExternalObjectPrepare.h"
#include <ex_sss_boot.h>
#include <fsl_sss_se05x_policy.h>
#include <nxEnsure.h>
#include <nxLog_App.h>
#include <nxScp03_Apis.h>
#include <nxScp03_Const.h>
#include <se05x_APDU.h>
#include <se05x_tlv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <smCom.h>
#include "fsl_sss_util_asn1_der.h"
#include "smCom.h"
static ex_sss_boot_ctx_t gex_sss_import_external_prepare;
uint8_t gTxBuffer[SE05X_MAX_BUF_SIZE_CMD];
size_t gTxBufferLen;
Se05xSession_t *pgSe05xSessionCtx;
#define EX_SSS_BOOT_PCONTEXT (&gex_sss_import_external_prepare)
#define EX_SSS_BOOT_DO_ERASE 0
#define EX_SSS_BOOT_EXPOSE_ARGC_ARGV 1
#define EX_SSS_BOOT_SKIP_SELECT_APPLET 1
#include <ex_sss_main_inc.h>
void usage()
{
LOG_W(
"\n\
Usage:\n\
se05x_ImportExternalObjectPrepare.exe \n\
-keyid <ECDSA auth object id>\n\
-file <Input ECDSA keypair file>");
return;
}
static sss_status_t parse_command_line_args(int argc, const char **argv);
static sss_status_t calculate_shared_secret(ex_sss_boot_ctx_t *pCtx);
static sss_status_t calculate_master_secret(ex_sss_boot_ctx_t *pCtx);
static sss_status_t nxECKey_HostLocal_CalculateSessionKeys(ex_sss_boot_ctx_t *pCtx);
static sss_status_t nxECKey_Calculate_Initial_Mac_Chaining_Value(ex_sss_boot_ctx_t *pCtx);
static sss_status_t read_se_ecka_and_store(ex_sss_boot_ctx_t *pCtx);
static sss_status_t generate_tee_ecka_and_export(ex_sss_boot_ctx_t *pCtx,
uint8_t *pk_tee_ecka,
size_t *pk_tee_ecka_len,
size_t *publicKeyLen,
uint16_t *outKeyIndex);
static sss_status_t store_ecdsa_key(ex_sss_boot_ctx_t *pCtx);
static sss_status_t create_internal_auth_data(ex_sss_boot_ctx_t *pCtx,
uint8_t *p_to_be_signed_buf,
size_t *to_be_signed_len,
uint8_t *pk_tee_ecka,
size_t publicKeyLen);
smStatus_t se05x_ImportExtObjTransformBuffer(Se05xSession_t *pwrite_apdubufferctx,
const tlvHeader_t *hdr,
uint8_t *cmdBuf,
size_t cmdBufLen,
uint8_t *rsp,
size_t *rspLen,
uint8_t hasle);
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);
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);
smStatus_t se05x_ImportExtObjDecryptResponse(
struct Se05xSession *pSessionCtx, size_t cmd_cmacLen, uint8_t *rsp, size_t *rspLength, uint8_t hasle);
sss_status_t ex_sss_entry(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status;
smStatus_t sm_status = SM_NOT_OK;
int argc = gex_sss_argc;
const char **argv = gex_sss_argv;
uint8_t pk_tee_ecka[256] = {0};
size_t pk_tee_ecka_len = sizeof(pk_tee_ecka);
size_t publicKeyLen;
uint16_t outKeyIndex;
uint8_t to_be_signed[200] = {0};
size_t to_be_signed_len = 0;
sss_digest_t digest_ctx;
uint8_t digest[32] = {0};
size_t digestLen = sizeof(digest);
sss_asymmetric_t asymm_ctx;
uint8_t signature[80] = {0};
size_t signatureLen = sizeof(signature);
uint8_t internal_auth_pk_tee_ecka_sig_tag[] = INTERNAL_AUTH_PK_TEE_ECKA_SIG_TAG;
uint8_t auth_data[256] = {0};
size_t auth_data_len = 0;
uint8_t auth_id[4] = {0};
NXSCP03_DynCtx_t dyn_ctx;
uint8_t EncryptedAPDU[100] = {0};
uint8_t EncryptedAPDUWithHeader[300] = {0};
size_t EncryptedAPDUWithHeaderLen = 0;
uint8_t mac[16] = {0};
size_t macLen;
sss_se05x_session_t *se05x_session = (sss_se05x_session_t *)&pCtx->session;
pgSe05xSessionCtx = &se05x_session->s_ctx;
/* Parse commandline arguments */
status = parse_command_line_args(argc, argv);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
for (int i = 0; i < 4; ++i)
auth_id[i] = ((uint8_t *)&ecdsa_auth_id)[3 - i];
sss_se05x_session_t se05xWriteBufferSession;
Se05xSession_t *pse05xWriteBufferSessionCtx = &se05xWriteBufferSession.s_ctx;
/* Read PK.SE.ECKA */
status = read_se_ecka_and_store(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Generate SK.TEE.ECKA and read PK.TEE.ECKA */
status = generate_tee_ecka_and_export(pCtx, pk_tee_ecka, &pk_tee_ecka_len, &publicKeyLen, &outKeyIndex);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Store ECDSA key in host */
status = store_ecdsa_key(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Create InternalAuth TLV to be signed by ECDSA key */
status = create_internal_auth_data(pCtx, to_be_signed, &to_be_signed_len, &pk_tee_ecka[outKeyIndex], publicKeyLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Sign InternalAuth data
* Data should be hashed and signed
* Signature algorithm should be kAlgorithm_SSS_ECDSA_SHA256
*/
status = sss_digest_context_init(&digest_ctx, &pCtx->host_session, kAlgorithm_SSS_SHA256, kMode_SSS_Digest);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_digest_one_go(&digest_ctx, to_be_signed, to_be_signed_len, digest, &digestLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
sss_digest_context_free(&digest_ctx);
status = sss_asymmetric_context_init(
&asymm_ctx, &pCtx->host_session, &hostECDSAkey_object, kAlgorithm_SSS_SHA256, kMode_SSS_Sign);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_asymmetric_sign_digest(&asymm_ctx, digest, digestLen, signature, &signatureLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
sss_asymmetric_context_free(&asymm_ctx);
/* Add signature to 0x5F37 tag */
memcpy(&auth_data[auth_data_len], to_be_signed, to_be_signed_len);
auth_data_len += to_be_signed_len;
memcpy(&auth_data[auth_data_len], internal_auth_pk_tee_ecka_sig_tag, sizeof(internal_auth_pk_tee_ecka_sig_tag));
auth_data_len += sizeof(internal_auth_pk_tee_ecka_sig_tag);
auth_data[auth_data_len++] = (uint8_t)signatureLen;
memcpy(&auth_data[auth_data_len], signature, signatureLen);
auth_data_len += signatureLen;
status = calculate_shared_secret(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = calculate_master_secret(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = nxECKey_HostLocal_CalculateSessionKeys(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = nxECKey_Calculate_Initial_Mac_Chaining_Value(pCtx);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
pse05xWriteBufferSessionCtx->authType = kSSS_AuthType_ECKey;
pse05xWriteBufferSessionCtx->pdynScp03Ctx = &dyn_ctx;
memcpy(&pse05xWriteBufferSessionCtx->pdynScp03Ctx->Enc, &enc_obj, sizeof(sss_object_t));
memcpy(&pse05xWriteBufferSessionCtx->pdynScp03Ctx->Mac, &mac_obj, sizeof(sss_object_t));
memcpy(&pse05xWriteBufferSessionCtx->pdynScp03Ctx->Rmac, &rmac_obj, sizeof(sss_object_t));
memcpy(pse05xWriteBufferSessionCtx->pdynScp03Ctx->MCV, iniMacChaining, 16);
memcpy(pse05xWriteBufferSessionCtx->pdynScp03Ctx->cCounter, commandCounter, 16);
pse05xWriteBufferSessionCtx->pdynScp03Ctx->authType = kSSS_AuthType_ECKey;
pse05xWriteBufferSessionCtx->pdynScp03Ctx->SecurityLevel = SECURITY_LEVEL;
/* doc:start:writesecureobjbuf */
/* 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);
/* doc:end:writesecureobjbuf */
/* Wrap WriteSecureObject APDU with FastSCP context */
memcpy(EncryptedAPDU, WriteSymmKeyAPDU, WriteSymmKeyAPDU_len);
status =
nxSCP03_Encrypt_CommandAPDU(pse05xWriteBufferSessionCtx->pdynScp03Ctx, EncryptedAPDU, &WriteSymmKeyAPDU_len);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Add header containing CLA INS P1 P2 */
EncryptedAPDUWithHeader[0] = 0x84; /* CLA */
EncryptedAPDUWithHeader[1] = 0x01; /* INS */
EncryptedAPDUWithHeader[2] = 0x03; /* P1 */
EncryptedAPDUWithHeader[3] = 0x00; /* P2 */
EncryptedAPDUWithHeader[4] = (uint8_t)WriteSymmKeyAPDU_len + 8 /* Length of mac added */;
memcpy(&EncryptedAPDUWithHeader[5], EncryptedAPDU, WriteSymmKeyAPDU_len);
EncryptedAPDUWithHeaderLen = WriteSymmKeyAPDU_len + 5;
/* Add MAC to the wrapped command */
status = nxpSCP03_CalculateMac_CommandAPDU(
pse05xWriteBufferSessionCtx->pdynScp03Ctx, EncryptedAPDUWithHeader, EncryptedAPDUWithHeaderLen, mac, &macLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
#if SSS_HAVE_SE05X_VER_GTE_06_00
/* Save MAC for RMAC calculation */
memcpy(ObjectMAC, mac, 16);
#endif
memcpy(&EncryptedAPDUWithHeader[EncryptedAPDUWithHeaderLen], mac, 8);
EncryptedAPDUWithHeaderLen += 8;
LOG_D("Restore MCV ");
#if SSS_HAVE_SE05X_VER_GTE_06_00
/* For 5.10 applet onwards Current MAC is MCV*/
memcpy(pse05xWriteBufferSessionCtx->pdynScp03Ctx->MCV, ObjectMAC, 16);
#else
/* Before 5.10 applet initial MAC is MCV*/
memcpy(pse05xWriteBufferSessionCtx->pdynScp03Ctx->MCV, iniMacChaining, 16);
#endif
pse05xWriteBufferSessionCtx->fp_TXn = &se05x_ImportExtObjTransformBuffer;
pse05xWriteBufferSessionCtx->fp_RawTXn = &se05x_ImportExtObjTransmitBuffer;
pse05xWriteBufferSessionCtx->fp_DeCrypt = &se05x_ImportExtObjDecryptResponse;
/* Create raw APDU for ImportExternalObject */
sm_status = Se05x_API_ImportExternalObject(pse05xWriteBufferSessionCtx,
auth_data,
auth_data_len,
auth_id,
sizeof(auth_id),
EncryptedAPDUWithHeader,
EncryptedAPDUWithHeaderLen);
status = (sm_status == SM_OK) ? kStatus_SSS_Success : kStatus_SSS_Fail;
exit:
if (kStatus_SSS_Success == status) {
LOG_I("se05x_ImportExternalObjectPrepare Example Success !!!...");
}
else {
LOG_E("se05x_ImportExternalObjectPrepare Example Failed !!!...");
}
return status;
}
static sss_status_t parse_command_line_args(int argc, const char **argv)
{
bool ecdsa_file_parameter_passed = false;
bool ecdsa_auth_id_passed = false;
for (int j = 1; j < argc; j++) {
if (strcmp(argv[j], "-file") == 0) {
ecdsa_file_parameter_passed = true;
j++;
const char *filename = argv[j];
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
LOG_E("Cannot open file");
return kStatus_SSS_Fail;
}
fread(hostEcdsakey, sizeof(hostEcdsakey), 1, fp);
fclose(fp);
}
else if (strcmp(argv[j], "-keyid") == 0) {
ecdsa_auth_id_passed = true;
j++;
ecdsa_auth_id = (uint32_t)strtoul(argv[j], NULL, 16);
}
}
if (!ecdsa_file_parameter_passed) {
LOG_E("ECDSA file parameter not passed");
usage();
return kStatus_SSS_Fail;
}
if (!ecdsa_auth_id_passed) {
LOG_E("ECDSA KeyID not passed");
usage();
return kStatus_SSS_Fail;
}
return kStatus_SSS_Success;
}
static sss_status_t calculate_shared_secret(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
sss_derive_key_t dervCtx;
size_t sharedSecBitLen = 0;
/* Derive shared secret using PK.SE.ECKA and SK.TEE.ECKA
* This will be stored in shsSecret object
*/
status = sss_key_object_init(&shsSecret, &pCtx->host_ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(
&shsSecret, __LINE__, kSSS_KeyPart_Default, kSSS_CipherType_AES, 32, kKeyObject_Mode_Transient);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_derive_key_context_init(
&dervCtx, &pCtx->host_session, &sk_tee_ecka_obj, kAlgorithm_SSS_ECDH, kMode_SSS_ComputeSharedSecret);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_derive_key_dh(&dervCtx, &se_ecka_pub_host_obj, &shsSecret);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_store_get_key(shsSecret.keyStore, &shsSecret, sharedSecret, &sharedSecretLen, &sharedSecBitLen);
LOG_D("sharedSecret");
LOG_AU8_D(sharedSecret, sharedSecretLen);
cleanup:
sss_derive_key_context_free(&dervCtx);
sss_key_object_free(&shsSecret);
return status;
}
static sss_status_t calculate_master_secret(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
sss_digest_t md;
/* Fixed DR.SE */
uint8_t dr_se[16] = {0};
size_t dr_se_len = sizeof(dr_se);
uint8_t derivationInput[100] = {0};
size_t derivationInputLen = 0;
#if SSS_HAVE_SE05X_VER_GTE_06_00 || SSS_HAVE_FIPS
const uint8_t kdf_counter[] = {0x00, 0x00, 0x00, 0x01};
memcpy(&derivationInput[derivationInputLen], kdf_counter, sizeof(kdf_counter));
derivationInputLen += sizeof(kdf_counter);
#endif
/* Calculate master secret using previously derived shared secret and dr.se (fixed) */
memcpy(&derivationInput[derivationInputLen], sharedSecret, sharedSecretLen);
derivationInputLen += sharedSecretLen;
memcpy(&derivationInput[derivationInputLen], dr_se, dr_se_len);
derivationInputLen += dr_se_len;
derivationInput[derivationInputLen++] = SCP_CONFIG;
derivationInput[derivationInputLen++] = SECURITY_LEVEL;
derivationInput[derivationInputLen++] = GPCS_KEY_TYPE_AES;
derivationInput[derivationInputLen++] = GPCS_KEY_LEN_AES;
status = sss_digest_context_init(&md, &pCtx->host_session, kAlgorithm_SSS_SHA256, kMode_SSS_Digest);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_digest_one_go(&md, derivationInput, derivationInputLen, masterSk, &masterSkLen);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
sss_digest_context_free(&md);
masterSkLen = 16;
LOG_MAU8_D("Master Secret", masterSk, masterSkLen);
/*Set the Master secret as AES Key*/
status = sss_key_object_init(&masterSec, &pCtx->host_ks);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(
&masterSec, __LINE__, kSSS_KeyPart_Default, kSSS_CipherType_AES, 32, kKeyObject_Mode_Persistent);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
status = sss_host_key_store_set_key(&pCtx->host_ks, &masterSec, masterSk, masterSkLen, masterSkLen * 8, NULL, 0);
ENSURE_OR_GO_CLEANUP(status == kStatus_SSS_Success);
LOG_I("master shared Secret !!!!");
LOG_AU8_I(masterSk, masterSkLen);
cleanup:
return status;
}
static sss_status_t nxECKey_HostLocal_CalculateSessionKeys(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
uint8_t ddA[128];
uint16_t ddALen = sizeof(ddA);
uint8_t sessionEncKey[16];
uint8_t sessionMacKey[16];
uint8_t sessionRmacKey[16];
uint32_t signatureLen = 16;
/* Generation and Creation of Session ENC SSS Key Object */
// Set the Derviation data
nxScp03_setDerivationData(
ddA, &ddALen, DATA_DERIVATION_SENC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, NULL, 0);
// Calculate the Session-ENC key
status = nxScp03_Generate_SessionKey(&masterSec, ddA, ddALen, sessionEncKey, &signatureLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
LOG_MAU8_I("sessionEncKey", sessionEncKey, 16);
// Set the Session-ENC key
status = sss_key_object_init(&enc_obj, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(
&enc_obj, __LINE__, kSSS_KeyPart_Default, kSSS_CipherType_AES, 32, kKeyObject_Mode_Persistent);
status = sss_key_store_set_key(&pCtx->host_ks, &enc_obj, sessionEncKey, 16, (16) * 8, NULL, 0);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Generation and Creation of Session MAC SSS Key Object */
// Set the Derviation data
nxScp03_setDerivationData(
ddA, &ddALen, DATA_DERIVATION_SMAC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, NULL, 0);
// Calculate the Session-MAC key
status = nxScp03_Generate_SessionKey(&masterSec, ddA, ddALen, sessionMacKey, &signatureLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
LOG_MAU8_I("sessionMacKey", sessionMacKey, 16);
// Set the Session-MAC key
status = sss_key_object_init(&mac_obj, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(
&mac_obj, __LINE__, kSSS_KeyPart_Default, kSSS_CipherType_AES, 32, kKeyObject_Mode_Persistent);
status = sss_host_key_store_set_key(&pCtx->host_ks, &mac_obj, sessionMacKey, 16, (16) * 8, NULL, 0);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Generation and Creation of Session RMAC SSS Key Object */
// Set the Derviation data
nxScp03_setDerivationData(
ddA, &ddALen, DATA_DERIVATION_SRMAC, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, NULL, 0);
// Calculate the Session-RMAC key
status = nxScp03_Generate_SessionKey(&masterSec, ddA, ddALen, sessionRmacKey, &signatureLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
LOG_MAU8_I("sessionRmacKey", sessionRmacKey, 16);
// Set the Session-RMAC key
status = sss_key_object_init(&rmac_obj, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(
&rmac_obj, __LINE__, kSSS_KeyPart_Default, kSSS_CipherType_AES, 32, kKeyObject_Mode_Persistent);
status = sss_host_key_store_set_key(&pCtx->host_ks, &rmac_obj, sessionRmacKey, 16, (16) * 8, NULL, 0);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
exit:
return status;
}
static sss_status_t nxECKey_Calculate_Initial_Mac_Chaining_Value(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
uint8_t ddA[128];
uint16_t ddALen = sizeof(ddA);
uint32_t signatureLen = 16;
// Set the Derviation data
nxScp03_setDerivationData(
ddA, &ddALen, DATA_DERIVATION_INITIAL_MCV, DATA_DERIVATION_L_128BIT, DATA_DERIVATION_KDF_CTR, NULL, 0);
// Calculate the Initial MCV value
status = nxScp03_Generate_SessionKey(&masterSec, ddA, ddALen, iniMacChaining, &signatureLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
LOG_MAU8_I("Initial MCV", iniMacChaining, 16);
// Set the Initial MCV value
exit:
return status;
}
/* doc:start:transformsapdubuf */
/* 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);
ret = pSe05xSession->fp_RawTXn(
pgSe05xSessionCtx->conn_ctx, NULL, kSSS_AuthType_None, hdr, cmdBuf, cmdBufLen, rsp, rspLen, hasle);
ENSURE_OR_GO_EXIT(ret == SM_OK);
ret = pSe05xSession->fp_DeCrypt(pSe05xSession, cmdBufLen, rsp, rspLen, hasle);
exit:
return ret;
}
/* doc:end:transformsapdubuf */
/* doc:start:decryptsresponsebuf */
/* 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;
}
/* doc:end:decryptsresponsebuf */
/* doc:start:transmitapdubuf */
/* 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)
{
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;
}
/* doc:end:transmitapdubuf */
/* doc:start:createapdubuf */
/* 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)
{
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;
}
/* doc:end:createapdubuf */
static sss_status_t read_se_ecka_and_store(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
size_t keyBitLen = 256;
status = sss_key_object_init(&se_ecka_pub_obj, &pCtx->ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_get_handle(&se_ecka_pub_obj, SE_ECKA_PUB_OBJID);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_store_get_key(&pCtx->ks, &se_ecka_pub_obj, se_ecka_pub, &se_ecka_pub_len, &keyBitLen);
LOG_D("SE ECKA Public Key");
LOG_AU8_D(se_ecka_pub, se_ecka_pub_len);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
/* Set PK.SE.ECKA in host */
status = sss_key_object_init(&se_ecka_pub_host_obj, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(&se_ecka_pub_host_obj,
__LINE__,
kSSS_KeyPart_Public,
kSSS_CipherType_EC_NIST_P,
256,
kKeyObject_Mode_Persistent);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status =
sss_key_store_set_key(&pCtx->host_ks, &se_ecka_pub_host_obj, se_ecka_pub, se_ecka_pub_len, keyBitLen, NULL, 0);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
exit:
return status;
}
static sss_status_t generate_tee_ecka_and_export(
ex_sss_boot_ctx_t *pCtx, uint8_t *pk_tee_ecka, size_t *pk_tee_ecka_len, size_t *publicKeyLen, uint16_t *outKeyIndex)
{
sss_status_t status = kStatus_SSS_Fail;
size_t keyBitLen = 256;
status = sss_key_object_init(&sk_tee_ecka_obj, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(&sk_tee_ecka_obj,
MAKE_TEST_ID(__LINE__),
kSSS_KeyPart_Pair,
kSSS_CipherType_EC_NIST_P,
sizeof(hostEcdsakey),
kKeyObject_Mode_Persistent);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_store_generate_key(&pCtx->host_ks, &sk_tee_ecka_obj, 256, NULL);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_store_get_key(&pCtx->host_ks, &sk_tee_ecka_obj, pk_tee_ecka, pk_tee_ecka_len, &keyBitLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
LOG_D("HOST ECKA Keypair");
LOG_AU8_D(pk_tee_ecka, *pk_tee_ecka_len);
status = sss_util_pkcs8_asn1_get_ec_public_key_index(pk_tee_ecka, *pk_tee_ecka_len, outKeyIndex, publicKeyLen);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
exit:
return status;
}
static sss_status_t store_ecdsa_key(ex_sss_boot_ctx_t *pCtx)
{
sss_status_t status = kStatus_SSS_Fail;
status = sss_key_object_init(&hostECDSAkey_object, &pCtx->host_ks);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status = sss_key_object_allocate_handle(&hostECDSAkey_object,
MAKE_TEST_ID(__LINE__),
kSSS_KeyPart_Pair,
kSSS_CipherType_EC_NIST_P,
sizeof(hostEcdsakey),
kKeyObject_Mode_Persistent);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
status =
sss_key_store_set_key(&pCtx->host_ks, &hostECDSAkey_object, hostEcdsakey, sizeof(hostEcdsakey), 256, NULL, 0);
ENSURE_OR_GO_EXIT(status == kStatus_SSS_Success);
exit:
return status;
}
static sss_status_t create_internal_auth_data(ex_sss_boot_ctx_t *pCtx,
uint8_t *p_to_be_signed_buf,
size_t *to_be_signed_len,
uint8_t *pk_tee_ecka,
size_t publicKeyLen)
{
sss_status_t status = kStatus_SSS_Success;
uint8_t internal_auth_pk_tee_ecka_tag[] = INTERNAL_AUTH_PK_TEE_ECKA_TAG;
size_t internal_auth_pk_tee_ecka_tag_size = sizeof(internal_auth_pk_tee_ecka_tag);
uint8_t eckey_fixed_params[] = ECKEY_PARAMS;
/* Copy fixed ECKey params of InternalAuthenticate */
memcpy(&p_to_be_signed_buf[*to_be_signed_len], eckey_fixed_params, sizeof(eckey_fixed_params));
(*to_be_signed_len) += sizeof(eckey_fixed_params);
/* Create 0x7F49 TLV */
memcpy(&p_to_be_signed_buf[*to_be_signed_len], internal_auth_pk_tee_ecka_tag, internal_auth_pk_tee_ecka_tag_size);
(*to_be_signed_len) += internal_auth_pk_tee_ecka_tag_size;
/* Length of value of 0x7F49 */
uint8_t *pinternal_auth_pk_tee_ecka_len = &p_to_be_signed_buf[(*to_be_signed_len)++];
p_to_be_signed_buf[(*to_be_signed_len)++] = 0xB0; /* PK.TEE.ECKA Tag */
p_to_be_signed_buf[(*to_be_signed_len)++] = (uint8_t)publicKeyLen; /* PK.TEE.ECKA Tag */
memcpy(&p_to_be_signed_buf[*to_be_signed_len], pk_tee_ecka, publicKeyLen);
(*to_be_signed_len) += publicKeyLen;
p_to_be_signed_buf[(*to_be_signed_len)++] = 0xF0; /* ECCurve identifier Tag */
p_to_be_signed_buf[(*to_be_signed_len)++] = 0x01; /* ECCurve identifier Length */
p_to_be_signed_buf[(*to_be_signed_len)++] = 0x03; /* ECCurve identifier Value */
*pinternal_auth_pk_tee_ecka_len =
(uint8_t)(publicKeyLen + 2 /* Tag & Length for 0xF0 */ + 3 /* TLV for ECCurve Identifier */);
return status;
}