blob: cc56c5983adb1342f53253ebc9aaef4e69556db3 [file] [log] [blame]
/**
* @file tstHostCrypto.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2016,2020 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
* Module implementing host based crypto functionality used in example programs.
* This module relies on the availability of mbed TLS on the Host plaform.
* @par HISTORY
*
*/
/*******************************************************************
* project specific include files
*******************************************************************/
#ifndef MBEDTLS
# define MBEDTLS
#endif
#include "tstHostCrypto.h"
#include "tst_sm_util.h"
#include "sm_printf.h"
#include "string.h"
#include "mbedtls/aes.h"
#include "hkdf_mbedtls.h"
#include "mbedtls/error.h"
#include "mbedtls/pk.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/rsa.h"
#include "mbedtls/error.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/md.h"
#include "mbedtls/platform.h"
#include "assert.h"
#include "HostCryptoAPI.h"
#include "string.h" /* For size_t */
#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#include "fsl_trng.h"
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
#include "fsl_rnga.h"
#elif defined(FSL_FEATURE_SOC_LPC_RNG_COUNT) && (FSL_FEATURE_SOC_LPC_RNG_COUNT > 0)
#include "fsl_rng.h"
#endif
/*******************************************************************
* global variables and struct definitions
*******************************************************************/
int fast_aes_wrap(const uint8_t *kek, int n, const uint8_t *plain, uint8_t *cipher);
#if AX_EMBEDDED
static int HOSTCRYPTO_GetRandom(void *pCtx, unsigned char *output, size_t len);
#endif
static mbedtls_ecp_group_id curveType2GroupID (ECCCurve_t curveType) {
switch (curveType) {
case ECCCurve_NIST_P192:
return MBEDTLS_ECP_DP_SECP192R1;
case ECCCurve_NIST_P224:
return MBEDTLS_ECP_DP_SECP224R1;
case ECCCurve_NIST_P256:
return MBEDTLS_ECP_DP_SECP256R1;
case ECCCurve_BrainPoolP256r1:
return MBEDTLS_ECP_DP_BP256R1;
default:
assert(0);
}
return MBEDTLS_ECP_DP_NONE;
}
// TODO: Check on buffer size passed as argument
U16 HOSTCRYPTO_Sign(EC_KEY* pKey, U8* pInputData, U16 inputLength, U8* pSignature, U16* pSignatureLength, U8 signatureFormat)
{
#ifdef __FUNCTION__
sm_printf(CONSOLE, "Not Implemented => '" __FUNCTION__ "'.\n");
#endif
return 0;
}
U16 HOSTCRYPTO_ECC_ComputeSharedSecret(EC_KEY *pKey, U8 *pubKey, U16 pubKeyLen, U8 *pSharedSecretData, U16 *pSharedSecretDataLen)
{
int retval;
int keyLen = 0; // # byte
int sharedSecretLen; // # bits
int sharedSecretLen_Derived; // # bits
U16 nStatus = SW_OK;
mbedtls_mpi rawSharedData;
mbedtls_ecp_point ecp_point;
const mbedtls_ecp_curve_info *p_curve_info = NULL;
if (pKey == NULL) {
return ERR_NO_PRIVATE_KEY;
}
mbedtls_ecp_keypair * pEcCtx = mbedtls_pk_ec( *pKey );
mbedtls_ecp_point_init(&ecp_point);
mbedtls_mpi_init(&rawSharedData);
/* Compute the size of the shared secret */
p_curve_info = mbedtls_ecp_curve_info_from_grp_id(pEcCtx->grp.id);
keyLen = ((p_curve_info->bit_size + 7)) / 8;
sharedSecretLen = keyLen * 8;
if (keyLen > *pSharedSecretDataLen)
{
return ERR_BUF_TOO_SMALL;
}
// NOTE: alternative approach to get #byte shared secret (based upon bitsize of EC curve)
// (pEcCtx->grp.pbits + 7) / 8
// convert external public key data to POINT
// external public key curve == local curve
// data has leading 0x04 (uncompressed point representation)
retval = mbedtls_ecp_point_read_binary( &(pEcCtx->grp), &ecp_point,
pubKey, pubKeyLen );
if (retval != 0)
{
return ERR_GENERAL_ERROR;
}
/* Compute the shared secret, no KDF is applied */
retval = mbedtls_ecdh_compute_shared( &(pEcCtx->grp), &rawSharedData,
&ecp_point, &(pEcCtx->d),
NULL,
NULL );
if (retval != 0)
{
return ERR_GENERAL_ERROR;
}
mbedtls_ecp_point_free(&ecp_point);
sharedSecretLen_Derived = mbedtls_mpi_size( &(rawSharedData) );
if (sharedSecretLen_Derived > sharedSecretLen)
{
// Unclear what error would trigger this code.
mbedtls_mpi_free(&(rawSharedData));
return ERR_GENERAL_ERROR;
}
*pSharedSecretDataLen = keyLen;
retval = mbedtls_mpi_write_binary(&rawSharedData,pSharedSecretData, keyLen);
if (retval != 0)
{
return ERR_GENERAL_ERROR;
}
mbedtls_mpi_free(&(rawSharedData));
return nStatus;
}
/**
* Extract the public key - as a byte array in uncompress format - from an ECC key
* @param[in] pKey Reference to ECC key.
* @param[in,out] pPublicKeyData IN: Buffer to contain public key; OUT: Public key
* @param[out] pPublicKeyLen Length of public key \p pPublicKeyData retrieved
* @param[in] maxPublicKeyLen Size of buffer (\p pPublicKeyData) provided to contain public key
*/
U16 HOSTCRYPTO_GetPublicKey(EC_KEY *pKey, U8 *pPublicKeyData, U16 *pPublicKeyLen, U16 maxPublicKeyLen)
{
int res;
size_t keylen = 0;
mbedtls_ecp_keypair * pEcCtx;
if ( pKey == NULL) {
return ERR_CRYPTO_ENGINE_FAILED;
}
pEcCtx = mbedtls_pk_ec( *pKey );
res = mbedtls_ecp_check_pubkey( &(pEcCtx->grp), &(pEcCtx->Q) );
if ((res != 0) || (pPublicKeyData == NULL) || (pPublicKeyLen == NULL))
{
return ERR_CRYPTO_ENGINE_FAILED;
}
res = mbedtls_ecp_point_write_binary(&(pEcCtx->grp),&(pEcCtx->Q),MBEDTLS_ECP_PF_UNCOMPRESSED,&keylen,pPublicKeyData,maxPublicKeyLen);
*pPublicKeyLen = (U16)keylen;
if ((*pPublicKeyLen == 0) || (res != 0))
{
return ERR_CRYPTO_ENGINE_FAILED;
}
return SW_OK;
}
/**
* Extract the private key - as a byte array restored to nominal key size by sign extension - from an ECC key (in an mbed TLS specific format)
* @param[in] pKey Reference to ECC key.
* @param[in,out] pPrivateKeyData IN: Buffer to contain private key; OUT: Private key
* @param[out] pPrivateKeyLen Length of private key \p pPrivateKeyData retrieved
* @param[in] maxPrivateKeyLen Size of buffer (\p pPrivateKeyData) provided to contain private key
*/
U16 HOSTCRYPTO_GetPrivateKey(EC_KEY *pKey, U8 *pPrivateKeyData, U16 *pPrivateKeyLen, U16 maxPrivateKeyLen)
{
int significantBytes = 0;
int keyLen = 0;
U16 res = SW_OK;
U8 keyArray[256];
const mbedtls_ecp_curve_info *p_curve_info = NULL;
mbedtls_ecp_keypair * pEcCtx;
if ( pKey == NULL) {
return ERR_CRYPTO_ENGINE_FAILED;
}
pEcCtx = mbedtls_pk_ec( *pKey );
/*TODO check sign extension part */
res = mbedtls_ecp_check_privkey( &(pEcCtx->grp), &(pEcCtx->d));
if ((res != 0) || (pPrivateKeyData == NULL) || (pPrivateKeyLen == NULL))
{
return ERR_CRYPTO_ENGINE_FAILED;
}
significantBytes = mbedtls_mpi_size( &(pEcCtx->d) );
p_curve_info = mbedtls_ecp_curve_info_from_grp_id( pEcCtx->grp.id );
keyLen = ((p_curve_info->bit_size + 7))/8;
if (keyLen > maxPrivateKeyLen)
{
return ERR_BUF_TOO_SMALL;
}
res = mbedtls_mpi_write_binary(&(pEcCtx->d),keyArray,keyLen);
if (res == 0)
{
// Extend byte array with leading 0x00 byte in case private key had
// been truncated because the MSB were not significant
if (significantBytes > 0)
{
res = axZeroSignExtend(keyArray, (U16)significantBytes, (U16)keyLen);
if (res == SW_OK)
{
memcpy(pPrivateKeyData, keyArray, keyLen);
*pPrivateKeyLen = (U16)keyLen;
}
else
{
*pPrivateKeyLen = 0;
}
}
else
{
*pPrivateKeyLen = 0;
res = ERR_GENERAL_ERROR;
}
}
else
{
res = ERR_CRYPTO_ENGINE_FAILED;
}
return res;
}
void HOSTCRYPTO_FreeEccKey(EC_KEY** ppKey) {
if ( ppKey == NULL )
{
; /* Nothing to do */
}
else
{
if ( *ppKey != NULL)
{
mbedtls_pk_free(*ppKey);
free(*ppKey);
}
*ppKey = NULL;
}
}
/**
* Create an ECC key (in an mbedTLS specific format) on the requested curve
* @param[in] curveType E.g. ECCCurve_NIST_P256. Not all curves defined in ::ECCCurve_t are always supported
by the underlying mbed TLS crypto library.
* @param[out] ppKey Double indirection to EC_KEY data structure. In case *ppKey already points
to a key object, that object is freed first.
*/
U16 HOSTCRYPTO_GenerateEccKey(ECCCurve_t curveType, EC_KEY** ppKey)
{
int32_t ret = 0;
#if !AX_EMBEDDED
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
#endif
/*TODO check how to consume and destroy */
mbedtls_pk_context * pKey;
if ( ppKey != NULL && *ppKey != NULL )
{
HOSTCRYPTO_FreeEccKey(ppKey);
*ppKey = NULL;
}
pKey = (mbedtls_pk_context *)malloc(sizeof(*pKey));
mbedtls_pk_init( pKey );
#if !AX_EMBEDDED
mbedtls_ctr_drbg_init( &ctr_drbg );
mbedtls_entropy_init( &entropy );
ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
NULL,
0 );
#endif
if (ret == 0)
{
ret = mbedtls_pk_setup( pKey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY) );
if (ret == 0)
{
#if !AX_EMBEDDED
ret = mbedtls_ecp_gen_key( curveType2GroupID(curveType), mbedtls_pk_ec( *pKey ),
mbedtls_ctr_drbg_random, &ctr_drbg );
#else
ret = mbedtls_ecp_gen_key( curveType2GroupID(curveType), mbedtls_pk_ec( *pKey ),
&HOSTCRYPTO_GetRandom, NULL );
#endif
if (ret == 0)
{
*ppKey = pKey;
#if !AX_EMBEDDED
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
#endif
return SW_OK;
}
}
}
mbedtls_pk_free( pKey );
free(pKey);
if ( ppKey != NULL && *ppKey != NULL ) {
HOSTCRYPTO_FreeEccKey(ppKey);
*ppKey = NULL;
}
#if !AX_EMBEDDED
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
#endif
return ERR_CRYPTO_ENGINE_FAILED;
}
/**
* Create an mbed TLS specific key structure and fill it up with the ECC key material contained
* in the crypto library agnostic \p eccKc data structure. In case \p eccKc does not contain a
* private key, only the public part will be copied into the mbed TLS specific key structure.
*
* @param[out] eccRef Double indirection to EC_KEY data structure.
* In case *ppKey already points to a key object, that object is freed first.
* @param[in] eccKc Data structure containing ECC key material.
*/
U16 HOSTCRYPTO_EccCreateOpenSslEccFromComponents(EC_KEY **ppKey, eccKeyComponents_t *eccKc)
{
int ret;
mbedtls_pk_context * pKey;
if ( ppKey != NULL && *ppKey != NULL )
{
HOSTCRYPTO_FreeEccKey(ppKey);
*ppKey = NULL;
}
pKey = (mbedtls_pk_context *) malloc(sizeof(*pKey));
mbedtls_pk_init( pKey );
ret = mbedtls_pk_setup( pKey, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY) );
if (ret == 0)
{
mbedtls_ecp_keypair * pEcCtx = mbedtls_pk_ec( *pKey );
*ppKey = pKey; //mbedtls_pk_ec( *pKey );
ret = mbedtls_ecp_group_load( &(pEcCtx->grp), curveType2GroupID(eccKc->curve) );
if (ret == 0)
{
ret = mbedtls_ecp_point_read_binary( &(pEcCtx->grp), &(pEcCtx->Q),
eccKc->pub, eccKc->pubLen );
if (ret == 0)
{
ret = mbedtls_mpi_read_binary( &(pEcCtx->d), eccKc->priv, eccKc->privLen );
if (ret == 0)
{
return SW_OK;
}
}
}
}
/* Error */
free(pKey);
return ERR_CRYPTO_ENGINE_FAILED;
}
/**
* Key unwrapping according to RFC3394 (https://tools.ietf.org/html/rfc3394)
* \note Only tested with an 128 bits wrapKey.
* @param[in] wrapKey Secret key used to unwrap \p in with. Also called KEK (key encryption key)
* @param[in] wrapKeyLen Length in byte of wrapKey
* @param[in,out] out IN: buffer of at least \p outLen byte; OUT: unwrapped key
* @param[in,out] outLen IN: size of buffer \p out provided; OUT: actual length of unwrapped key
* @param[in] in Wrapped key to be unwrapped
* @param[in] inLen Length in byte of key to be unwrapped
*/
U16 HOSTCRYPTO_AesUnwrapKeyRFC3394(const U8 *wrapKey, U16 wrapKeyLen, U8 *out, U16 *outLen, const U8 *in, U16 inLen)
{
#ifdef __FUNCTION__
sm_printf(CONSOLE, "Not Implemented => '" __FUNCTION__ "'.\n");
#endif
return 0;
}
/**
* Key wrapping according to RFC3394 (https://tools.ietf.org/html/rfc3394)
* \note Only tested with an 128 bits wrapKey. When wrapping a 128 bit key (16 byte), the resulting
* wrapped key is 24 byte long.
* @param[in] wrapKey Secret key used to wrap \p in. Also called KEK (key encryption key)
* @param[in] wrapKeyLen Length in byte of wrapKey
* @param[in,out] out IN: buffer of at least \p outLen byte; OUT: wrapped key
* @param[in,out] outLen IN: size of buffer \p out provided; OUT: actual length of wrapped key
* @param[in] in Key to be wrapped
* @param[in] inLen Length in byte of key to be wrapped
*/
U16 HOSTCRYPTO_AesWrapKeyRFC3394(const U8 *wrapKey, U16 wrapKeyLen, U8 *out, U16 *outLen, const U8 *in, U16 inLen)
{
int retval = 0;
//mbedtls_aes_context *ctx = NULL;
//int keybits = wrapKeyLen * 8;
/*TODO Borrowed check license */
retval = fast_aes_wrap(wrapKey,((inLen * 8) >> 6),in,out);
return retval;
}
#ifdef TGT_A71CH
U16 HOSTCRYPTO_HkdfExpandSha256(const U8 *secret, U16 secretLen, const U8 *info, U16 infoLen, U8 *derivedData, U16 derivedDataLen)
{
U16 sw = SW_OK;
int ret;
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
ret = mbedtls_hkdf_expand(md,
secret, secretLen,
info, infoLen,
derivedData, derivedDataLen);
if (ret != 0)
{
sw = ERR_CRYPTO_ENGINE_FAILED;
}
return sw;
}
U16 HOSTCRYPTO_HkdfFullSha256(const U8 *salt, U16 saltLen, const U8 *secret, U16 secretLen, const U8 *info, U16 infoLen, U8 *derivedData, U16 derivedDataLen)
{
U16 sw = SW_OK;
int ret;
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
ret = mbedtls_hkdf(md,
salt, saltLen,
secret, secretLen,
info, infoLen,
derivedData, derivedDataLen);
if (ret != 0)
{
sw = ERR_CRYPTO_ENGINE_FAILED;
}
return sw;
}
// Implements the CreatePremasterSecret functionality of RFC4279
U16 HOSTCRYPTO_TlsPskCreatePremasterSecret(const U8 *secret, U16 secretLen, U8 *premasterSecret, U16 *premasterSecretLen)
{
U16 targetLen = 0;
// Ensure buffer premasterSecret is big enough
targetLen = 2 * 2 + 2 * secretLen;
if (*premasterSecretLen < targetLen)
{
return ERR_BUF_TOO_SMALL;
}
premasterSecret[0] = (U8)(secretLen >> 8);
premasterSecret[1] = (U8)secretLen;
memset(&premasterSecret[2], 0x00, secretLen);
premasterSecret[2+secretLen] = (U8)(secretLen >> 8);
premasterSecret[3+secretLen] = (U8)secretLen;
memcpy(&premasterSecret[4+secretLen], secret, secretLen);
*premasterSecretLen = targetLen;
return SW_OK;
}
// Implements the CreatePremasterSecret functionality of RFC5489
U16 HOSTCRYPTO_TlsEcdhPskCreatePremasterSecret(const U8 *ecdhSS, U16 ecdhSSLen, const U8 *secret, U16 secretLen, U8 *premasterSecret, U16 *premasterSecretLen)
{
U16 targetLen = 0;
// Ensure buffer premasterSecret is big enough
targetLen = 2 * 2 + ecdhSSLen + secretLen;
if (*premasterSecretLen < targetLen)
{
return ERR_BUF_TOO_SMALL;
}
premasterSecret[0] = (U8)(ecdhSSLen >> 8);
premasterSecret[1] = (U8)ecdhSSLen;
memcpy(&premasterSecret[2], ecdhSS, ecdhSSLen);
premasterSecret[2+ecdhSSLen] = (U8)(secretLen >> 8);
premasterSecret[3+ecdhSSLen] = (U8)secretLen;
memcpy(&premasterSecret[4+ecdhSSLen], secret, secretLen);
*premasterSecretLen = targetLen;
return SW_OK;
}
U16 HOSTCRYPTO_HmacSha256(const U8 *secret, U16 secretLen, const U8 *data, U16 dataLen, U8 *hmacData)
{
int ret;
U16 sw = SW_OK;
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
ret = mbedtls_md_hmac(md, secret, secretLen, data, dataLen, hmacData);
if (ret != 0)
{
sw = ERR_CRYPTO_ENGINE_FAILED;
}
return sw;
}
U16 HOSTCRYPTO_Tls1_2_P_Sha256(const U8 *secret, U16 secretLen, const U8 *seed, U16 seedLen, U8 *derivedData, U16 derivedDataLen)
{
unsigned int nPos = 0;
unsigned char hashed0[MBEDTLS_MD_MAX_SIZE];
unsigned char hashed1[MBEDTLS_MD_MAX_SIZE];
const mbedtls_md_info_t *p_mbedtls_md_info = NULL;
mbedtls_md_context_t ctx;
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
U16 bytesToCopy;
unsigned char digLen = 0;
p_mbedtls_md_info = mbedtls_md_info_from_type(md_type);
digLen = mbedtls_md_get_size( p_mbedtls_md_info );
mbedtls_md_init(&ctx);
if ((mbedtls_md_setup(&ctx, p_mbedtls_md_info , 1))) //use hmac
goto err;
// First compute A(1) = HMAC(secret, SEED)
if ((mbedtls_md_hmac_starts(&ctx, secret, secretLen)))
goto err;
if ((mbedtls_md_hmac_update(&ctx, (const unsigned char *) seed, seedLen)))
goto err;
if ((mbedtls_md_hmac_finish(&ctx, hashed0)))
goto err;
while (derivedDataLen)
{
// Now compute P(N) = HMAC(secret, A(N) | seed) # N > 0
if (mbedtls_md_hmac_reset(&ctx))
goto err;
if ((mbedtls_md_hmac_update(&ctx, (const unsigned char *) hashed0, digLen)))
goto err;
if ((mbedtls_md_hmac_update(&ctx, (const unsigned char *) seed, seedLen)))
goto err;
if ((mbedtls_md_hmac_finish(&ctx, hashed1 )))
goto err;
bytesToCopy = (derivedDataLen < digLen) ? derivedDataLen : (U16)digLen;
memcpy(&derivedData[nPos], hashed1, bytesToCopy);
derivedDataLen -= bytesToCopy;
nPos += bytesToCopy;
// Compute A(N+1) and store for next round
if (mbedtls_md_hmac_reset(&ctx))
goto err;
if ((mbedtls_md_hmac_update(&ctx, (const unsigned char *) hashed0, digLen)))
goto err;
if ((mbedtls_md_hmac_finish(&ctx, hashed0 )))
goto err;
}
mbedtls_md_free(&ctx);
return SW_OK;
err:
mbedtls_md_free(&ctx);
return ERR_CRYPTO_ENGINE_FAILED;
}
#endif // TGT_A71CH
#if AX_EMBEDDED
#include "mbedtls/entropy_poll.h"
int HOSTCRYPTO_GetRandom(void *pCtx, unsigned char *output, size_t len)
{
status_t result = kStatus_Success;
#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#ifndef TRNG0
#define TRNG0 TRNG
#endif
result = TRNG_GetRandomData(TRNG0, output, len);
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
result = RNGA_GetRandomData(RNG, (void *)output, len);
#elif defined(FSL_FEATURE_SOC_LPC_RNG_COUNT) && (FSL_FEATURE_SOC_LPC_RNG_COUNT > 0)
uint32_t rn;
size_t length;
int i;
length = len;
while (length > 0)
{
rn = RNG_GetRandomData();
if (length >= sizeof(uint32_t))
{
memcpy(output, &rn, sizeof(uint32_t));
length -= sizeof(uint32_t);
output += sizeof(uint32_t);
}
else
{
memcpy(output, &rn, length);
output += length;
len = 0U;
}
/* Discard next 32 random words for better entropy */
for (i = 0; i < 32; i++)
{
RNG_GetRandomData();
}
}
result = kStatus_Success;
#endif
if (result == kStatus_Success)
{
return 0;
}
else
{
return result;
}
}
#endif