/** * @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