blob: c00db25dc42a57a7520c41df108f45602fbbdae4 [file] [log] [blame]
/**
* @file ax_a71chEngine.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2017,2020 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* OpenSSL Engine for Embedded Secure Element (A71CH)
*
* This engine invokes the API of axHostSw/a71ch that wraps APDU communication
* with the A71CH secure element.
*
* The following operations are supported by this engine:
* - Random number generation
* - ECC sign
* - ECC verify
* - ECDH compute_key
*
* When dealing with an EC key argument whose a public key is used:
* - In case the key is a 'reference key' -> use the referenced public key
* - In case the public key is passed by value and it matches the value of a public key
* stored in the Secure Element -> delegate the operation to the Secure Element
* - If none of the two above cases apply; at compile time one can choose between two
* strategies:
* (1) return a fail
* (2) delegate the operation to the OpenSSL SW implementation
*
* When dealing with an EC key argument whose private key is used:
* - In case the key is a 'reference key' -> use the referenced private key
* - In case the above does not apply; at compile time one can choose between two
* strategies:
* (1) return a fail
* (2) delegate the operation to the OpenSSL SW implementation
*
* @note
* Compatible with:
* - OpenSSL 1.0.2
* - OpenSSL 1.1.0
*
*/
/*
* This file contains source code form OpenSSL distribution that is covered
* by the LICENSE-OpenSSL file to be found in the root of this source code
* distribution tree.
*/
#include "ax_embSeEngine.h"
#include "ax_cryptoIpc.h"
#include <openssl/bn.h>
// #include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <stdlib.h>
#if !defined(OPENSSL_SYS_MACOSX)
#include <malloc.h>
#endif
#include "ax_api.h"
#include "ax_embSeEngine_Internal.h"
#include "fsl_sscp_a71ch.h"
#include "sm_printf.h"
#include "nxLog_App.h"
#include "nxEnsure.h"
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
#ifdef OPENSSL_NO_DYNAMIC_ENGINE
#undef OPENSSL_NO_DYNAMIC_ENGINE
#endif
#endif
// <Conditionally activate features at compile time>
#define PRIVATE_KEY_HANDOVER_TO_SW
#define PUBLIC_KEY_HANDOVER_TO_SW
// </Conditionally activate features at compile time>
/* Define ECDH secret key size */
#define ECDH_MAX_LEN 32
#define EMBSE_MAX_ECC_PUBKEY_BUF (2*96 + 1) // Corresponds to 768 bit ECC key
/* Maximum Key Index supported by the A70CM SE */
#define EMBSE_A70CM_MAX_PUBLIC_KEY_INDEX 2
/* Logging related defines */
#define EMBSE_MAX_PRINT_BUF_SIZE (511)
#define LOG_FLOW_MASK 0x01
#define LOG_DBG_MASK 0x02
#define LOG_ERR_MASK 0x04
#define LOG_FLOW_ON 0x01
#define LOG_DBG_ON 0x02
#define LOG_ERR_ON 0x04
// Adjust to the required default log level.
static int EMBSE_LogControl = (LOG_ERR_ON | LOG_DBG_ON | LOG_FLOW_ON); // Full log
// static int EMBSE_LogControl = (LOG_ERR_ON); // Only Errors
static axKeyIdentifier_t eccSigningKeys[] = {
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_0},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_1},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_2},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_3}
};
static axKeyIdentifier_t eccVerifyKeys[] = {
{A71CH_SSI_PUBLIC_KEY, A71CH_PUBLIC_KEY_0},
{A71CH_SSI_PUBLIC_KEY, A71CH_PUBLIC_KEY_1},
{A71CH_SSI_PUBLIC_KEY, A71CH_PUBLIC_KEY_2}
};
static axKeyIdentifier_t eccDhStaticKeys[] = {
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_0},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_1},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_2},
{A71CH_SSI_KEY_PAIR, A71CH_KEY_PAIR_3}
};
// Locally used utility functions
static U16 getEcKeyReference(const EC_KEY *eckey, axKeyIdentifier_t *validKeys, int nKeys,
SST_Identifier_t *ident, SST_Index_t *idx);
static U16 axAdaptSize(U8* pOut, U16 expectedLen, const U8 *pIn, U16 actualLen);
static void EmbSe_Print(int flag, const char * format, ...);
static void EmbSe_PrintPayload(int flag, const U8 *pPayload, U16 nLength, const char *title);
static U16 EmbSe_A70Init(void);
/* engine name */
static const char *embSe_id = OPENSSL_ENGINE_EMBSE_ID;
static const char *embSe_name = "se hardware engine support";
/* Random Num Status, used when Get Rand Status is invoked */
unsigned short gRandStatus = 1;
const int Version1 = 1; //-> Release Version1.Version2.Version3
const int Version2 = 0;
const int Version3 = 1;
/* ecdsa_method struct definition from */
struct ecdsa_method
{
const char *name;
ECDSA_SIG *(*ecdsa_do_sign)(const unsigned char *dgst, int dgst_len,
const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey);
int (*ecdsa_sign_setup)(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
BIGNUM **r);
int (*ecdsa_do_verify)(const unsigned char *dgst, int dgst_len,
const ECDSA_SIG *sig, EC_KEY *eckey);
#if 0
int (*init)(EC_KEY *eckey);
int (*finish)(EC_KEY *eckey);
#endif
int flags;
char *app_data;
};
/* ecdh_method struct definition from ech_locl.h*/
struct ecdh_method
{
const char *name;
int (*compute_key)(void *key, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen));
#if 0
int (*init)(EC_KEY *eckey);
int (*finish)(EC_KEY *eckey);
#endif
int flags;
char *app_data;
};
/* Engine API Declaration */
static int EmbSe_Rand(unsigned char *buf, int num);
static int EmbSe_Rand_Status(void);
static ECDSA_SIG *EmbSe_ECDSA_Do_Sign(const unsigned char *dgst, int dgst_len,
const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey);
static int EmbSe_ECDSA_Sign_Setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
BIGNUM **r);
static int EmbSe_ECDSA_Do_Verify(const unsigned char *dgst, int dgst_len,
const ECDSA_SIG *sig, EC_KEY *eckey);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
static int EmbSe_Compute_Key(void *sh_secret,
size_t sec_len,
const EC_POINT *pub_key,
EC_KEY *ecdh,
void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen));
#else
static int EmbSe_Simple_Compute_Key(unsigned char **pout,
size_t *poutlen,
const EC_POINT *pub_key,
const EC_KEY *ecdh);
static int EmbSe_Simple_Key_gen(EC_KEY *key);
#endif
/* Fill in implemented Engine methods in respective data structures */
static RAND_METHOD EmbSe_RAND =
{
NULL, /* RAND_seed() */
EmbSe_Rand, /* RAND_bytes() */
NULL, /* RAND_cleanup() */
NULL, /* RAND_add() */
EmbSe_Rand, /* RAND_pseudo_rand() */
EmbSe_Rand_Status /* RAND_status() */
};
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
static ECDSA_METHOD EmbSe_ECDSA = {
"e2se_ecdsa",
*EmbSe_ECDSA_Do_Sign,
EmbSe_ECDSA_Sign_Setup,
EmbSe_ECDSA_Do_Verify,
0,
NULL
};
static ECDH_METHOD EmbSe_ECDH = {
"e2se_ecdh",
*EmbSe_Compute_Key,
0,
NULL
};
#else
// Renamed 'ossl_ecdsa_sign' from openssl-1.1.0j/crypto/ec/ecdsa_ossl.c
static int my_ossl_ecdsa_sign(int type, const unsigned char *dgst, int dlen,
unsigned char *sig, unsigned int *siglen,
const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey)
{
ECDSA_SIG *s;
int rv = 0;
ENSURE_OR_GO_EXIT(siglen != NULL);
RAND_seed(dgst, dlen);
s = ECDSA_do_sign_ex(dgst, dlen, kinv, r, eckey);
if (s == NULL) {
*siglen = 0;
return 0;
}
*siglen = i2d_ECDSA_SIG(s, &sig);
ECDSA_SIG_free(s);
rv = 1;
exit:
return rv;
}
// Renamed 'ossl_ecdsa_verify' from openssl-1.1.0j/crypto/ec/ecdsa_ossl.c
static int my_ossl_ecdsa_verify(int type, const unsigned char *dgst, int dgst_len,
const unsigned char *sigbuf, int sig_len, EC_KEY *eckey)
{
ECDSA_SIG *s;
const unsigned char *p = sigbuf;
unsigned char *der = NULL;
int derlen = -1;
int ret = -1;
s = ECDSA_SIG_new();
if (s == NULL)
return (ret);
if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL)
goto err;
/* Ensure signature uses DER and doesn't have trailing garbage */
derlen = i2d_ECDSA_SIG(s, &der);
if (derlen != sig_len || memcmp(sigbuf, der, derlen) != 0)
goto err;
ret = ECDSA_do_verify(dgst, dgst_len, s, eckey);
err:
OPENSSL_clear_free(der, derlen);
ECDSA_SIG_free(s);
return (ret);
}
static EC_KEY_METHOD *EmbSe_EC = NULL;
static EC_KEY_METHOD *EmbSe_EC_Default = NULL;
static int setup_ec_key_method(void) {
EmbSe_EC_Default = (EC_KEY_METHOD *)EC_KEY_get_default_method();
EmbSe_EC = EC_KEY_METHOD_new(NULL);
if (EmbSe_EC == NULL) {
return 0;
}
// NOTE: Equivalent of set_name does not exist for OpenSSL 1.1
// EC_KEY_METHOD_set_name(EmbSe_EC, "e2se_ecdsa");
EC_KEY_METHOD_set_sign(EmbSe_EC, my_ossl_ecdsa_sign, EmbSe_ECDSA_Sign_Setup, EmbSe_ECDSA_Do_Sign);
EC_KEY_METHOD_set_verify(EmbSe_EC, my_ossl_ecdsa_verify, EmbSe_ECDSA_Do_Verify);
EC_KEY_METHOD_set_compute_key(EmbSe_EC, EmbSe_Simple_Compute_Key);
EC_KEY_METHOD_set_keygen(EmbSe_EC, EmbSe_Simple_Key_gen);
return 1;
}
#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L)
#ifndef OPENSSL_NO_HW
/* The definitions for control commands specific to this engine */
#define EMBSE_LOG_LEVEL ENGINE_CMD_BASE
#define EMBSE_CMD_SO_PATH (ENGINE_CMD_BASE + 1)
static const ENGINE_CMD_DEFN embSe_cmd_defns[] = {
{EMBSE_LOG_LEVEL,
"LOG_LEVEL",
"Specifies the Log level (Error=0x04; Debug=0x02; Flow=0x01; Or'd combinations possible)",
ENGINE_CMD_FLAG_NUMERIC},
{EMBSE_CMD_SO_PATH,
"SO_PATH",
"Specifies the path to the 'e2se ssl' shared library (not implemented)",
ENGINE_CMD_FLAG_STRING},
{0, NULL, NULL, 0}
};
/* Engine API's for initialization and cleanup */
static int EmbSe_Destroy(ENGINE *e)
{
AX_UNUSED_ARG(e);
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Destroy(): Entry\n");
return 1;
}
/****** ENGINE API's *******/
static int EmbSe_Init(ENGINE *e)
{
U16 sw = 0;
AX_UNUSED_ARG(e);
/* Initialize the Engine Mutex */
CryptoIpc_MutexInit(AX_CI_TRUE);
sw = EmbSe_A70Init();
if (sw != SW_OK)
{
EmbSe_Print(LOG_ERR_ON, "Call to EmbSe_A70Init() failed with return code 0x%04X\n", sw);
return -1;
}
EmbSe_Print(LOG_FLOW_ON, "Version: %d.%d.%d\n", Version1, Version2, Version3);
#ifdef __gnu_linux__
mallopt(M_MMAP_THRESHOLD, 125);
#endif
/* Engine is ready to use */
return 1;
}
static int EmbSe_Finish(ENGINE *e)
{
AX_UNUSED_ARG(e);
SM_Close(NULL, SMCOM_CLOSE_MODE_STD);
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Finish(): Entry\n");
return 1;
}
static int EmbSe_Ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
{
AX_UNUSED_ARG(e);
/* Values of String Variables are received in p, while values of Numeric ones are in i */
switch(cmd)
{
case EMBSE_LOG_LEVEL:
EmbSe_Print(LOG_FLOW_ON, "Control Command EMBSE_LOG_LEVEL; requested log level = %ld\n", i);
if (i < 0x08)
{
EMBSE_LogControl = i & 0x07;
}
else
{
EmbSe_Print(LOG_DBG_ON, "Invalid Control Command value for EMBSE_LOG_LEVEL\n");
}
return 1;
case EMBSE_CMD_SO_PATH:
EmbSe_Print(LOG_ERR_ON, "Control command EMBSE_CMD_SO_PATH has not been implemented.\n");
return 0;
default:
break;
}
return 0;
}
/* This internal function is used by ENGINE_e2se() and possibly by the
* "dynamic" ENGINE support too */
static int bind_helper(ENGINE *e)
{
if (!ENGINE_set_id(e, embSe_id) ||
!ENGINE_set_name(e, embSe_name) ||
!ENGINE_set_destroy_function(e, &EmbSe_Destroy) ||
!ENGINE_set_init_function(e, &EmbSe_Init) ||
!ENGINE_set_finish_function(e, &EmbSe_Finish) ||
!ENGINE_set_ctrl_function(e, &EmbSe_Ctrl) ||
!ENGINE_set_cmd_defns(e, &embSe_cmd_defns[0]) ||
!ENGINE_set_RAND(e, &EmbSe_RAND) ||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
!ENGINE_set_ECDSA(e, &EmbSe_ECDSA) ||
!ENGINE_set_ECDH(e, &EmbSe_ECDH))
#else
!setup_ec_key_method() ||
!ENGINE_set_EC(e, EmbSe_EC))
#endif
{
return 0;
}
return 1;
}
#ifdef OPENSSL_NO_DYNAMIC_ENGINE
static ENGINE *EngineEmbSe(void)
{
ENGINE *ret = ENGINE_new();
if (!ret)
{
return NULL;
}
if (!bind_helper(ret))
{
ENGINE_free(ret);
return NULL;
}
return ret;
}
void EngineEmbSe_Load(void)
{
/* Copied from eng_[openssl|dyn].c */
ENGINE *toadd = EngineEmbSe();
if (!toadd) return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
EmbSe_Print(LOG_FLOW_ON, "EngineEmbSe_Load succeeded!\n");
}
#else
/* This stuff is needed if this ENGINE is being compiled into a self-contained
* shared-library. */
static int bind_fn(ENGINE *e, const char *id)
{
if (id && (strcmp(id, embSe_id) != 0))
return 0;
if (!bind_helper(e))
return 0;
return 1;
}
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
#endif /* OPENSSL_NO_DYNAMIC_ENGINE */
#endif /* !OPENSSL_NO_HW */
#define MAX_RND_CHUNK A71CH_SCP03_MAX_PAYLOAD_SIZE
/**
* Implementation of Engine API for Random Number Generation. Invokes Host API RND_GetRandom
* @param[in,out] buf buffer to store the generated Random Number
* @param[in] num number of random bytes requested
* @retval 0 upon failure
* @retval 1 upon success
*/
static int EmbSe_Rand(unsigned char *buf, int num)
{
U16 sw = ERR_GENERAL_ERROR;
int requested = 0;
int offset = 0;
int chunk = 0;
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Rand invoked requesting %d random bytes\n", num);
memset(buf,0,num);
CryptoIpc_MutexLock();
requested = num;
while (requested > 0)
{
if (requested > MAX_RND_CHUNK)
{
chunk = MAX_RND_CHUNK;
}
else
{
chunk = requested;
}
sw = A71_GetRandom (buf+offset, chunk);
if (sw != SW_OK) {
break;
}
offset += chunk;
requested -= chunk;
}
CryptoIpc_MutexUnlock();
gRandStatus = sw;
if (sw == SW_OK)
{
return 1;
}
else
{
EmbSe_Print(LOG_ERR_ON, "Call to RND_GetRandom failed with 0x%04X\n", sw);
return 0;
}
}
/**
* @function EmbSe_Rand_Status
* @description Engine API to return the status from invocation of RND_GetRandom()
* @param void
* @return value U16 of previous RND_GetRandom() API.
*/
static int EmbSe_Rand_Status(void)
{
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Rand_Status invoked\n");
return (int)gRandStatus;
}
// EmbSe RSA API's
/* Size of an SSL signature: MD5+SHA1 */
#define SSL_SIG_LENGTH 36
// EmbSE ECDSA Implementation
// --------------------------
static ECDSA_SIG *EmbSe_ECDSA_Do_Sign(const unsigned char *dgst, int dgst_len,
const BIGNUM *inv, const BIGNUM *rp, EC_KEY *eckey)
{
U8 sigDER[256];
U16 sigDERLen = sizeof(sigDER);
U16 sw;
ECDSA_SIG *pSig;
EC_KEY *dup_eckey = NULL;
U8 *pp;
SST_Identifier_t ident;
SST_Index_t idx;
U8 dgstBuf[32];
U16 dgstBufLen = sizeof(dgstBuf);
sw = getEcKeyReference(eckey, eccSigningKeys, sizeof(eccSigningKeys)/sizeof(axKeyIdentifier_t),
&ident, &idx);
if (sw == SW_OK)
{
EmbSe_Print(LOG_FLOW_ON, "ECC_Sign(ident=%d, idx=%d; dgstLen=%d)\n", ident, idx, dgst_len);
axAdaptSize(dgstBuf, dgstBufLen, dgst, dgst_len);
CryptoIpc_MutexLock();
sw = A71_EccSign(idx, (const U8*)dgstBuf, dgstBufLen, (U8*)sigDER, (U16*)&sigDERLen);
CryptoIpc_MutexUnlock();
if (sw != SW_OK)
{
EmbSe_Print(LOG_ERR_ON, "SE signature creation error: 0x%04X.\n", sw);
return NULL;
}
EmbSe_Print(LOG_FLOW_ON, "A71_EccSign called successfully: sigDERLen=%d\n", sigDERLen);
/* sig is DER encoded. Transform to ECDSA_SIG and return this */
pp = (U8*)sigDER;
pSig = ECDSA_SIG_new();
if (pSig == NULL)
{
EmbSe_Print(LOG_ERR_ON, "ECDSA_SIG_new call failed\n");
return NULL;
}
if (d2i_ECDSA_SIG((ECDSA_SIG**)&pSig, (const unsigned char**)&pp, sigDERLen) == NULL)
{
EmbSe_Print(LOG_ERR_ON, "d2i_ECDSA_SIG failed\n");
return NULL;
}
EmbSe_Print(LOG_FLOW_ON, "EmbSe_ECDSA_Do_Sign success.\n");
return pSig;
}
else if (sw == ERR_IDENT_IDX_RANGE)
{
EmbSe_Print(LOG_ERR_ON, "Reference Key with identifier or index out of range: 0x%04X.\n", sw);
return NULL;
}
else if (sw == ERR_NO_PRIVATE_KEY)
{
EmbSe_Print(LOG_ERR_ON, "Expecting private key (by value or reference): 0x%04X.\n", sw);
return NULL;
}
else if (sw == ERR_PATTERN_COMPARE_FAILED)
{
#ifdef PRIVATE_KEY_HANDOVER_TO_SW
// Invoke OpenSSL sign API if no valid key reference is detected
EmbSe_Print(LOG_FLOW_ON,"No matching key in A71CH. Invoking OpenSSL API: ECDSA_do_sign_ex.\n");
/* Create a duplicate key */
dup_eckey = EC_KEY_dup(eckey);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
/* Attach OpenSSL's SW method to duplicate key */
if (!ECDSA_set_method(dup_eckey, ECDSA_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL ECDSA_set_method failure..\n");
return NULL;
}
#else
/* Attach OpenSSL's SW method to duplicate key */
if (!EC_KEY_set_method(dup_eckey, EC_KEY_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL EC_KEY_set_method failure..\n");
return NULL;
}
#endif
/* Invoke OpenSSL's sign API and return result */
return ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, dup_eckey);
#else
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Sign expected a reference key: 0x%04X.\n", sw);
return NULL;
#endif
}
else
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Sign unexpected key type: 0x%04X.\n", sw);
return NULL;
}
}
static int EmbSe_ECDSA_Sign_Setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv,
BIGNUM **r)
{
return 1;
}
static int EmbSe_ECDSA_Do_Verify(const unsigned char *dgst, int dgst_len,
const ECDSA_SIG *sig, EC_KEY *eckey)
{
U16 sw;
U8 retval = 0;
int nRet = 0;
int i;
int flagHandleKey = AX_ENGINE_INVOKE_NOTHING;
EC_KEY *dup_eckey = NULL;
U8 *pSignatureDER, *pSigTmp;
U16 sigLen;
SST_Identifier_t ident;
SST_Index_t idx;
size_t pub_key_len;
const EC_POINT *pub_key_point;
U8 refPub[EMBSE_MAX_ECC_PUBKEY_BUF];
EmbSe_Print(LOG_FLOW_ON, "Invoking EmbSe_ECDSA_Do_Verify(..)\n");
if (!eckey)
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: No EC Key provided as input.\n");
return -1;
}
if (!sig)
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: No signature provided as input.\n");
return -1;
}
/* Convert ECDSA_SIG to DER and print */
sigLen = i2d_ECDSA_SIG((ECDSA_SIG*)sig, NULL);
if (sigLen != 0)
{
pSignatureDER = (U8*)OPENSSL_malloc(sigLen);
pSigTmp = pSignatureDER;
// The pointer passed as second argument will point past the end of the returned signature
// upon return. Which explains pointer copy operation before the call.
i2d_ECDSA_SIG((ECDSA_SIG*)sig, &pSigTmp);
}
else
{
EmbSe_Print(LOG_ERR_ON, "Call to i2d_ECDSA_SIG failed\n");
return -1;
}
EmbSe_Print(LOG_DBG_ON, "====>SIGNATURE (len=%d)\n", sigLen);
EmbSe_PrintPayload(LOG_DBG_ON, pSignatureDER, sigLen, "");
EmbSe_PrintPayload(LOG_DBG_ON, dgst, dgst_len, "====>DIGEST");
sw = getEcKeyReference(eckey, eccVerifyKeys, sizeof(eccVerifyKeys)/sizeof(axKeyIdentifier_t),
&ident, &idx);
if (sw == SW_OK)
{
flagHandleKey = AX_ENGINE_INVOKE_SE;
}
else if ( (sw == ERR_NO_PRIVATE_KEY) || (sw == ERR_PATTERN_COMPARE_FAILED) )
{
// Check whether the public key passed by value matches one of
// the provisioned public keys.
/* Extract public key */
pub_key_point = EC_KEY_get0_public_key(eckey);
if (!pub_key_point)
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: EC Key public key error.\n");
nRet = -1;
goto clean_mem_up;
}
pub_key_len = EC_POINT_point2oct(EC_KEY_get0_group(eckey), pub_key_point,
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
if ( (pub_key_len == 0) || (pub_key_len > sizeof(refPub)) )
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: Preparation to convert public key into byte array failed.\n");
nRet = -1;
goto clean_mem_up;
}
if ( EC_POINT_point2oct(EC_KEY_get0_group(eckey), pub_key_point,
POINT_CONVERSION_UNCOMPRESSED, refPub, pub_key_len, NULL) == 0 )
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: Pub key data extraction error.\n");
nRet = -1;
goto clean_mem_up;
}
EmbSe_PrintPayload(LOG_DBG_ON, refPub, (U16)pub_key_len, "PubKey (Verify)");
flagHandleKey = AX_ENGINE_INVOKE_OPENSSL_SW;
// The local data structure eccVerifyKeys must match the storage
// capability of the attached secure element.
// Failure to retrieve a key from the secure element will not be
// considered fatal (the value may not have been provisioned)
CryptoIpc_MutexLock();
for (i=0; i<(int)(sizeof(eccVerifyKeys)/sizeof(axKeyIdentifier_t)); i++)
{
U8 fetchedPubKey[65];
U16 fetchedPubKeyLen = sizeof(fetchedPubKey);
memset(fetchedPubKey, 0, fetchedPubKeyLen);
idx = eccVerifyKeys[i].idx;
EmbSe_Print(LOG_DBG_ON, "A71_GetEccPublicKey(0x%02X)\n", (SST_Index_t)idx);
sw = A71_GetEccPublicKey((SST_Index_t)idx, fetchedPubKey, &fetchedPubKeyLen);
if (sw == SW_OK)
{
if (memcmp(refPub, fetchedPubKey, sizeof(fetchedPubKey)) == 0)
{
// We have a match.
flagHandleKey = AX_ENGINE_INVOKE_SE;
EmbSe_Print(LOG_FLOW_ON, "EmbSe_ECDSA_Do_Verify: Found matching public key at index 0x%02X\n", idx);
break;
}
}
}
CryptoIpc_MutexUnlock();
}
else
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: No matching/valid public key\n");
nRet = -1;
goto clean_mem_up;
}
if (flagHandleKey == AX_ENGINE_INVOKE_SE)
{
U8 dgstBuf[32];
U16 dgstBufLen = sizeof(dgstBuf);
EmbSe_Print(LOG_FLOW_ON, "ECC_Verify(KeyIdent=%d, KeyIndex=%d, dgst_len=%d, sigLen=%d)\n",
ident, idx, dgst_len, sigLen);
axAdaptSize(dgstBuf, dgstBufLen, dgst, dgst_len);
CryptoIpc_MutexLock();
sw = A71_EccVerify(idx, dgstBuf, dgstBufLen, pSignatureDER, sigLen, (U8*)&retval);
CryptoIpc_MutexUnlock();
if (sw != SW_OK)
{
EmbSe_Print(LOG_ERR_ON, "A71_EccVerify returned with Error: 0x%04X\n", sw);
nRet = -1;
goto clean_mem_up;
}
else
{
if (retval == 1)
EmbSe_Print(LOG_FLOW_ON, "Verification PASS\n");
else
EmbSe_Print(LOG_FLOW_ON, "Verification FAIL\n");
}
nRet = (int)retval;
}
else if (flagHandleKey == AX_ENGINE_INVOKE_OPENSSL_SW)
{
#ifdef PUBLIC_KEY_HANDOVER_TO_SW
EmbSe_Print(LOG_FLOW_ON, "No matching key in A71CH. Invoking OpenSSL API: ECDSA_do_verify.\n");
/* Create a duplicate key */
dup_eckey = EC_KEY_dup(eckey);
if (dup_eckey == NULL)
{
EmbSe_Print(LOG_ERR_ON, "OpenSSL verify: Failed to duplicate key.\n");
nRet = -1;
goto clean_mem_up;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
/* Attach OpenSSL's SW methods to duplicate key */
if (!ECDSA_set_method(dup_eckey, ECDSA_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL ECDSA_set_method failure..\n");
nRet = -1;
EC_KEY_free(dup_eckey);
goto clean_mem_up;
}
#else
/* Attach OpenSSL's SW methods to duplicate key */
if (!EC_KEY_set_method(dup_eckey, EC_KEY_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL EC_KEY_set_method failure..\n");
nRet = -1;
EC_KEY_free(dup_eckey);
goto clean_mem_up;
}
#endif
/* Invoke OpenSSL verify and return result */
nRet = ECDSA_do_verify(dgst, dgst_len, sig, dup_eckey);
if (nRet == 1)
{
EmbSe_Print(LOG_FLOW_ON, "Verification by OpenSSL PASS\n");
}
else
{
EmbSe_Print(LOG_FLOW_ON, "Verification by OpenSSL FAIL (nRet=%d)\n", nRet);
}
EC_KEY_free(dup_eckey);
#else
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify expected a reference key or a matching stored public key.\n");
nRet = -1;
goto clean_mem_up;
#endif
}
else
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_ECDSA_Do_Verify: unexpected conditional branch (flagHandleKey=%d).\n", flagHandleKey);
nRet = -1;
goto clean_mem_up;
}
clean_mem_up:
OPENSSL_free(pSignatureDER);
return nRet;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
/**
* Engine API implementation for computing shared secret, based on local private key, remote public key and an
* optional KDF(Key Derivation Function).
*
* @param[out] sh_secret buffer that will contain the computed shared secret (raw value if KDF is NULL).
* @param[in] sec_len length of computed shared secret.
* @param[in] pub_key public key of remote entity.
* @param[in] ecdh reference to private key object of local entity.
* @param[in] (*KDF) reference to a function that implements Key Derivation Function (hash on raw secret)
*
* @param: (*KDF)in- Reference to buffer containing the generated shared secret.
* @param: (*KDF)inlen- Length of the input
* @param: (*KDF)out - Buffer that returns final output on running KDF
* @param: (*KDF)outlen - returns length of computed output on running KDF
* @return: On failure, returns -1; On success returns length of computed secret.
*/
static int EmbSe_Compute_Key(void *sh_secret,
size_t sec_len,
const EC_POINT *pub_key,
EC_KEY *ecdh,
void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen))
#else
static int EmbSe_Simple_Compute_Key(unsigned char **pout,
size_t *poutlen,
const EC_POINT *pub_key,
const EC_KEY *ecdh)
#endif
{
U16 sw;
U16 field_size_bits = 0;
const EC_GROUP *key_group = NULL;
U8 *pubKeyBuf = NULL;
U16 pubKeyBufLen = 0;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
int ret = -1;
#else
int ret = 0;
#endif
U8 *shSecBuf = NULL;
U16 shSecBufLen = 0;
SST_Identifier_t ident;
SST_Index_t idx;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Compute_Key invoked (ecdh)\n");
/* Requested secret length limit check */
if (sec_len > ECDH_MAX_LEN) {
EmbSe_Print(LOG_ERR_ON, "Requested secret too long. Try <= %d.\n", ECDH_MAX_LEN);
return ret;
}
#else
EmbSe_Print(LOG_FLOW_ON, "EmbSe_Simple_Compute_Key invoked (ecdh)\n");
#endif
/* Get the key group */
key_group = EC_KEY_get0_group(ecdh);
if (!key_group)
{
EmbSe_Print(LOG_ERR_ON, "Unable to extract ECDH key group.\n");
goto err;
}
else
{/* Calculate length of field element for the key group */
field_size_bits = (U16)EC_GROUP_get_degree(key_group);
if (!field_size_bits)
{
EmbSe_Print(LOG_ERR_ON, "Unable to extract ECDH key field length.\n");
goto err;
}
}
/* Extract Public Key Data */
/****************************/
// Check if pub key is on the curve group
if (!EC_POINT_is_on_curve(key_group, pub_key, NULL))
{
EmbSe_Print(LOG_ERR_ON, "ECDH Public key error(incompatible group).\n");
goto err;
}
// Get the size of public key -> pass NULL for buffer
pubKeyBufLen = (U16) EC_POINT_point2oct(key_group, pub_key, POINT_CONVERSION_UNCOMPRESSED,
NULL, pubKeyBufLen, NULL);
// Allocate memory for public key data & check allocation
pubKeyBuf = malloc(pubKeyBufLen * sizeof(U8));
if (!pubKeyBuf)
{
EmbSe_Print(LOG_ERR_ON, "malloc failure for ECDH public key data.\n");
goto err;
}
// Get public key data
if (!EC_POINT_point2oct(key_group, pub_key, POINT_CONVERSION_UNCOMPRESSED, pubKeyBuf, pubKeyBufLen, NULL))
{
EmbSe_Print(LOG_ERR_ON, "ECDH public key data error (EC_POINT_point2oct).\n");
goto err;
}
/* Secure Element Call (if applicable) */
/***************************************/
shSecBufLen = (U16)(field_size_bits+7)/8;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
shSecBuf = malloc(shSecBufLen * sizeof(U8));
#else
shSecBuf = OPENSSL_malloc(shSecBufLen * sizeof(U8));
#endif
sw = getEcKeyReference(ecdh, eccDhStaticKeys, sizeof(eccDhStaticKeys)/sizeof(axKeyIdentifier_t),
&ident, &idx);
if (sw == SW_OK)
{
EmbSe_Print(LOG_FLOW_ON, "A71_EcdhGetSharedSecret(idx=%d, pubKeyLen=%d, shSecBufLen=%d)\n",
idx, pubKeyBufLen, shSecBufLen);
CryptoIpc_MutexLock();
sw = A71_EcdhGetSharedSecret(idx, pubKeyBuf, pubKeyBufLen, shSecBuf, &shSecBufLen);
CryptoIpc_MutexUnlock();
if (sw == SW_OK)
{
EmbSe_Print(LOG_FLOW_ON, "A71CH: A71_EcdhGetSharedSecret OK: Status code 0x%04x\n", sw);
}
else
{
EmbSe_Print(LOG_ERR_ON, "A71CH: A71_EcdhGetSharedSecret Error: Status code 0x%04x\n", sw);
goto err;
}
}
else if (sw == ERR_IDENT_IDX_RANGE)
{
EmbSe_Print(LOG_ERR_ON, "Reference Key with identifier or index out of range: 0x%04X.\n", sw);
goto err;
}
else if (sw == ERR_NO_PRIVATE_KEY)
{
EmbSe_Print(LOG_ERR_ON, "Expecting private key (by value or reference): 0x%04X.\n", sw);
goto err;
}
else if (sw == ERR_PATTERN_COMPARE_FAILED)
{
#ifdef PRIVATE_KEY_HANDOVER_TO_SW
EC_KEY *dup_ecdh = NULL;
int ecdh_ret = -1;
// Delegate to OpenSSL SW implementation
EmbSe_Print(LOG_FLOW_ON,"No matching key in A71CH. Invoking OpenSSL API: ECDH_compute_key.\n");
/* Create a duplicate key */
dup_ecdh = EC_KEY_dup(ecdh);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
/* Attach OpenSSL's SW method to duplicate key */
if (!ECDH_set_method(dup_ecdh, ECDH_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL ECDH_set_method failure.\n");
goto err;
}
#else
/* Attach OpenSSL's SW method to duplicate key */
if (!EC_KEY_set_method(dup_ecdh, EC_KEY_OpenSSL())) {
EmbSe_Print(LOG_ERR_ON, "OpenSSL EC_KEY_set_method failure..\n");
goto err;
}
#endif
/* Invoke OpenSSL ECDH_compute_key and return result */
// int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
// void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen));
ecdh_ret = ECDH_compute_key(shSecBuf, shSecBufLen, pub_key, dup_ecdh, NULL);
EC_KEY_free(dup_ecdh);
if (0 < ecdh_ret)
{
EmbSe_Print(LOG_FLOW_ON, "ECDH_compute_key by OpenSSL PASS\n");
shSecBufLen = (U16)ecdh_ret;
}
else
{
EmbSe_Print(LOG_ERR_ON, "ECDH_compute_key by OpenSSL FAILS with %d.\n", ecdh_ret);
goto err;
}
#else
EmbSe_Print(LOG_ERR_ON, "EmbSe_Compute_Key expected a reference key: 0x%04X.\n", sw);
goto err;
#endif
}
else
{
EmbSe_Print(LOG_ERR_ON, "EmbSe_Compute_Key unexpected key type: 0x%04X.\n", sw);
goto err;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
/* Finally run the KDF, if provided */
memset(sh_secret, 0, shSecBufLen);
if (KDF != 0)
{
if (KDF(shSecBuf, shSecBufLen, sh_secret, &sec_len) == NULL)
{
EmbSe_Print(LOG_ERR_ON, "KDF failed.\n");
goto err;
}
ret = (int)sec_len;
}
else
{
/* When KDF=NULL, return raw secret, copy asked length */
if (sec_len > shSecBufLen)
{
sec_len = shSecBufLen;
}
memcpy(sh_secret, shSecBuf, sec_len);
ret = (int)sec_len;
}
#else
*pout = shSecBuf;
*poutlen = shSecBufLen;
ret = 1;
#endif
// Never print shared secret
// EmbSe_PrintPayload(LOG_DBG_ON, sh_secret, sec_len, "Shared Secret: ");
err:
/* Free all allocated memory */
if (pubKeyBuf)
free(pubKeyBuf);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
if (shSecBuf)
free(shSecBuf);
#endif
return ret;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
#else
static int EmbSe_Simple_Key_gen(EC_KEY *key)
{
int(*openssl_Key_gen_sw)(EC_KEY * key) = NULL;
EC_KEY_METHOD_get_keygen((EC_KEY_METHOD *)EmbSe_EC_Default, &openssl_Key_gen_sw);
return openssl_Key_gen_sw(key);
}
#endif
/* Support functions */
/**********************/
/**
* Initialize communication with Secure Element.
* Supporting function for Engine Init.
*
* @retval ::SW_OK Upon successful execution
*/
static U16 EmbSe_A70Init(void)
{
U16 connectStatus = 0;
U8 Atr[64];
U16 AtrLen = sizeof(Atr);
SmCommState_t commState;
sm_printf(DBGOUT, "Connect to A71CH. Chunksize at link layer = %d.\n", MAX_CHUNK_LENGTH_LINK);
#if defined(TDA8029_UART) || defined(SCI2C) || defined(PCSC)|| defined(T1oI2C)
connectStatus = SM_Connect(NULL, &commState, Atr, &AtrLen);
#elif defined(SMCOM_JRCP_V1) || defined(SMCOM_JRCP_V2)
// {
// if (CONF_modules_load_file(NULL, "rjct_server",
// CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0)
// {
// fprintf(stderr, "FATAL: error loading configuration file\n");
// ERR_print_errors_fp(stderr);
// }
// }
{
#ifdef SMCOM_JRCP_V2
commState.connType = kType_SE_Conn_Type_JRCP_V2;
#endif
#ifdef SMCOM_JRCP_V1
commState.connType = kType_SE_Conn_Type_JRCP_V1;
#endif
char *rjctServerAddress = NULL;
rjctServerAddress = getenv("RJCT_SERVER_ADDR");
if (rjctServerAddress == NULL) {
connectStatus = SM_RjctConnect(NULL, "127.0.0.1:8050", &commState, Atr, &AtrLen);
}
else {
char szConnect[256];
size_t connectLen = sizeof(szConnect);
char szColonPort[] = ":8050";
size_t colonPortLen = sizeof(szColonPort) + 1;
if (sizeof(rjctServerAddress) > (connectLen-colonPortLen)) {
sm_printf(DBGOUT, "Server address is too long: %s\n", rjctServerAddress);
return ERR_NO_VALID_IP_PORT_PATTERN;
}
else {
strcpy(szConnect, rjctServerAddress);
//strcat(szConnect, szColonPort);
sm_printf(DBGOUT, "Server address:port set to %s\n", szConnect);
connectStatus = SM_RjctConnect(NULL, szConnect, &commState, Atr, &AtrLen);
}
}
}
#else
#error "No communication channel defined"
#endif // TDA8029
if ( (connectStatus == ERR_CONNECT_LINK_FAILED) || (connectStatus == ERR_CONNECT_SELECT_FAILED) )
{
sm_printf(CONSOLE, "SM_Connect failed with status 0x%04X\n", connectStatus);
return connectStatus;
}
else if ( connectStatus == SMCOM_COM_FAILED )
{
sm_printf(CONSOLE, "SM_Connect failed with status 0x%04X (Could not open communication channel)\n", connectStatus);
return connectStatus;
}
else if ( connectStatus == SMCOM_PROTOCOL_FAILED)
{
sm_printf(CONSOLE, "SM_Connect failed with status 0x%04X (Could not establish communication protocol)\n", connectStatus);
return connectStatus;
}
else if ( connectStatus == ERR_NO_VALID_IP_PORT_PATTERN )
{
sm_printf(DBGOUT, "Pass the IP address and port number as arguments, e.g. \"127.0.0.1:8050\"!\n");
return connectStatus;
}
else
{
int i=0;
#if defined(SCI2C)
sm_printf(CONSOLE, "SCI2C_"); // To highlight the ATR format for SCI2C deviates from ISO7816-3
#elif defined(SPI)
sm_printf(CONSOLE, "SCSPI_");
#endif
if (AtrLen > 0)
{
sm_printf(CONSOLE, "ATR=0x");
for (i=0; i<AtrLen; i++) { sm_printf(CONSOLE, "%02X.", Atr[i]); }
sm_printf(CONSOLE, "\n");
}
#if defined(TDA8029_UART)
sm_printf(CONSOLE, "UART Baudrate Idx: 0x%02X\n", commState.param2);
sm_printf(CONSOLE, "T=1 TA1: 0x%02X\n", commState.param1);
#endif
sm_printf(CONSOLE, "HostLib Version : 0x%04X\n", commState.hostLibVersion);
if (connectStatus != SW_OK)
{
sm_printf(CONSOLE, "Select failed. SW = 0x%04X\n", connectStatus);
return connectStatus;
}
sm_printf(CONSOLE, "Applet Version : 0x%04X\n", commState.appletVersion);
sm_printf(CONSOLE, "SecureBox Version: 0x%04X\n", commState.sbVersion);
}
sm_printf(DBGOUT, "==========SELECT-DONE=========\n");
return SW_OK;
}
void EmbSe_Print(int flag, const char * format, ...)
{
unsigned char buffer[EMBSE_MAX_PRINT_BUF_SIZE + 1];
int active = 0;
va_list vArgs;
if ( (flag & EMBSE_LogControl & LOG_FLOW_MASK) == LOG_FLOW_ON ) {
active = 1;
printf("e2a71ch-flw: ");
}
else if ( (flag & EMBSE_LogControl & LOG_DBG_MASK) == LOG_DBG_ON ) {
active = 1;
printf("e2a71ch-dbg: ");
}
else if ( (flag & EMBSE_LogControl & LOG_ERR_MASK) == LOG_ERR_ON ) {
active = 1;
printf("e2a71ch-err: ");
}
if (active == 1)
{
va_start(vArgs, format);
vsnprintf((char *)buffer, EMBSE_MAX_PRINT_BUF_SIZE, (char const *)format, vArgs);
va_end(vArgs);
printf("%s", buffer);
}
return;
}
static void EmbSe_PrintPayload(int flag, const U8 *pPayload, U16 nLength, const char *title)
{
U16 i;
int active = 0;
if ( (flag & EMBSE_LogControl & LOG_FLOW_MASK) == LOG_FLOW_ON ) {
active = 1;
printf("e2a71ch-flw: %s", title);
}
else if ( (flag & EMBSE_LogControl & LOG_DBG_MASK) == LOG_DBG_ON ) {
active = 1;
printf("e2a71ch-dbg: %s", title);
}
else if ( (flag & EMBSE_LogControl & LOG_ERR_MASK) == LOG_ERR_ON ) {
active = 1;
printf("e2a71ch-err: %s", title);
}
if (active == 1)
{
for (i = 0; i < nLength; i++)
{
if (i % 16 == 0) { printf("\n"); }
printf("%02X ", pPayload[i]);
}
printf("\n");
}
}
/**
Return SW_OK when the ecKey passed as argument matches one of the valid
keys contained in the validKeys array. Upon successfull execution ident
and idx contain values that point to the appropriate key in the secure
element.
@return ERR_PATTERN_COMPARE_FAILED Not a reference key
@return ERR_IDENT_IDX_RANGE Refers to unsupported key type (aka. identifier) or index
@return ERR_NO_PRIVATE_KEY No private key present
*/
static U16 getEcKeyReference(const EC_KEY *eckey, axKeyIdentifier_t *validKeys, int nKeys,
SST_Identifier_t *ident, SST_Index_t *idx)
{
U16 sw = ERR_PATTERN_COMPARE_FAILED;
const BIGNUM *prv_key_bn;
U8 tmpBuf[EMBSE_MAX_ECC_PUBKEY_BUF];
U16 privKeylen = 0;
U8 Ident = 0;
U8 Index = 0;
U32 Coeff[2] = {0, 0};
int i = 0;
int j = 0;
ENSURE_OR_GO_EXIT(ident != NULL);
ENSURE_OR_GO_EXIT(idx != NULL);
// printf("Debug: getEcKeyReference: Possible matches = %d\n", nKeys);
/* Test for private key */
prv_key_bn = EC_KEY_get0_private_key(eckey);
if (prv_key_bn)
{
privKeylen = BN_bn2bin(prv_key_bn, tmpBuf);
/* get Ident and Index */
Ident = tmpBuf[privKeylen-2];
Index = tmpBuf[privKeylen-1];
/* Get double ID string */
for (j=0; j<2; j++)
{
for (i=3;i<7;i++)
{
Coeff[j] |= tmpBuf[privKeylen-i-(j*4)]<< 8*(i-3);
}
}
if ( ((unsigned int)Coeff[0] == (unsigned int)EMBSE_REFKEY_ID) &&
((unsigned int)Coeff[1] == (unsigned int)EMBSE_REFKEY_ID) )
{
sw = ERR_IDENT_IDX_RANGE;
// Look for matching key
for (i=0; i<nKeys; i++)
{
if ( (validKeys[i].ident == Ident) && (validKeys[i].idx == Index) )
{
// We have a match
*ident = validKeys[i].ident;
*idx = validKeys[i].idx;
sw = SW_OK;
break;
}
}
}
else
{
sw = ERR_PATTERN_COMPARE_FAILED;
}
}
else
{
sw = ERR_NO_PRIVATE_KEY;
}
exit:
return sw;
}
/**
* Either zero sign extend \p pIn so it becomes \p expectedLen byte long
* or truncate the right most byte.
* The caller must ensure \p expectedLen is bigger than \p actualLen
* @param[in,out] pOut
* @param[in] expectedLen Zero sign extend/truncate until this length.
* @param[in] pIn Array representation of big number, to be zero sign extended or truncated
* @param[in] actualLen Length of incoming array \p pIn
*
* @retval SW_OK In case of successfull execution
* @retval ERR_API_ERROR Requested adjustment would result in truncation
*/
static U16 axAdaptSize(U8* pOut, U16 expectedLen, const U8 *pIn, U16 actualLen)
{
U16 sw = SW_OK;
int numExtraByte = (int)expectedLen - (int)actualLen;
if (numExtraByte == 0) {
memcpy(pOut, pIn, actualLen);
}
else if (numExtraByte < 0) {
memcpy(pOut, pIn, expectedLen);
}
else {
memcpy(pOut + numExtraByte, pIn, actualLen);
memset(pOut, 0x00, numExtraByte);
}
return sw;
}