| /* |
| * 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; |
| } |