core/crypto/ecc_mbedtls.c (595 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stdbool.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include "ecc_mbedtls.h" #include "platform_api.h" #include "asn1/ecc_der_util.h" #include "common/unused.h" #include "crypto/crypto_logging.h" #include "crypto/hash.h" #include "crypto/rng_mbedtls.h" #include "mbedtls/bignum.h" #include "mbedtls/ecdh.h" #include "mbedtls/ecdsa.h" #include "mbedtls/ecp.h" #include "mbedtls/pk.h" /** * Get the mbedTLS ECC key pair instance for a public or private key instance. * * @return The mbedTLS ECC key pair. */ #define ecc_mbedtls_get_ec_key_pair(x) mbedtls_pk_ec (*((mbedtls_pk_context*) x->context)) /** * Allocate and initialize a context for an ECC key. * * @return The initialized key context or null. */ static mbedtls_pk_context* ecc_mbedtls_alloc_key_context () { mbedtls_pk_context *key = platform_malloc (sizeof (mbedtls_pk_context)); if (key != NULL) { mbedtls_pk_init (key); } return key; } /** * Zeroize an ECC key context and free the memory. * * @param context The context to free. */ static void ecc_mbedtls_free_key_context (void *context) { mbedtls_pk_free ((mbedtls_pk_context*) context); platform_free (context); } /** * Initialize a public key instance from a private key. * * @param key The private key instance to covert to a public key. * @param dup Flag indicating if a new key instance should be created for the public key. * @param error The error code for the operation. * * @return The public key instance or null if there was an error. */ static mbedtls_pk_context* ecc_mbedtls_convert_private_to_public (mbedtls_pk_context *key, bool dup, int *error) { mbedtls_pk_context *pub = key; mbedtls_ecp_keypair *priv_ec; mbedtls_ecp_keypair *pub_ec; uint8_t msg_code; int status; if (dup) { pub = ecc_mbedtls_alloc_key_context (); if (pub == NULL) { status = ECC_ENGINE_NO_MEMORY; goto error_alloc; } status = mbedtls_pk_setup (pub, mbedtls_pk_info_from_type (MBEDTLS_PK_ECKEY)); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_PK_INIT_EC; goto error_exit; } priv_ec = mbedtls_pk_ec (*key); pub_ec = mbedtls_pk_ec (*pub); status = mbedtls_ecp_group_copy (&pub_ec->grp, &priv_ec->grp); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_GROUP_COPY_EC; goto error_exit; } status = mbedtls_ecp_copy (&pub_ec->Q, &priv_ec->Q); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_COPY_EC; goto error_exit; } status = mbedtls_ecp_check_pub_priv (pub_ec, priv_ec); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_CHECK_PUB_PRV_EC; goto error_exit; } } else { pub_ec = mbedtls_pk_ec (*pub); mbedtls_mpi_free (&pub_ec->d); } *error = 0; return pub; error_exit: ecc_mbedtls_free_key_context (pub); *error = status; debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, msg_code, status, 0); error_alloc: return NULL; } int ecc_mbedtls_init_key_pair (const struct ecc_engine *engine, const uint8_t *key, size_t key_length, struct ecc_private_key *priv_key, struct ecc_public_key *pub_key) { mbedtls_pk_context *key_ctx; int status; if ((engine == NULL) || (key == NULL) || (key_length == 0)) { return ECC_ENGINE_INVALID_ARGUMENT; } if (!priv_key && !pub_key) { return 0; } if (priv_key) { memset (priv_key, 0, sizeof (struct ecc_private_key)); } if (pub_key) { memset (pub_key, 0, sizeof (struct ecc_public_key)); } key_ctx = ecc_mbedtls_alloc_key_context (); if (key_ctx == NULL) { return ECC_ENGINE_NO_MEMORY; } status = mbedtls_pk_parse_key (key_ctx, key, ecc_der_get_private_key_length (key, key_length), NULL, 0); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_PARSE_EC, status, 0); goto error; } if (mbedtls_pk_get_type (key_ctx) != MBEDTLS_PK_ECKEY) { status = ECC_ENGINE_NOT_EC_KEY; goto error; } if (pub_key) { pub_key->context = ecc_mbedtls_convert_private_to_public (key_ctx, (priv_key), &status); if (pub_key->context == NULL) { goto error; } } if (priv_key) { priv_key->context = key_ctx; } return 0; error: ecc_mbedtls_free_key_context (key_ctx); return status; } int ecc_mbedtls_init_public_key (const struct ecc_engine *engine, const uint8_t *key, size_t key_length, struct ecc_public_key *pub_key) { mbedtls_pk_context *key_ctx; int status; if ((engine == NULL) || (key == NULL) || (key_length == 0) || (pub_key == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } memset (pub_key, 0, sizeof (struct ecc_public_key)); key_ctx = ecc_mbedtls_alloc_key_context (); if (key_ctx == NULL) { return ECC_ENGINE_NO_MEMORY; } status = mbedtls_pk_parse_public_key (key_ctx, key, ecc_der_get_public_key_length (key, key_length)); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_PARSE_PUB_EC, status, 0); goto error; } if (mbedtls_pk_get_type (key_ctx) != MBEDTLS_PK_ECKEY) { status = ECC_ENGINE_NOT_EC_KEY; goto error; } pub_key->context = key_ctx; return 0; error: ecc_mbedtls_free_key_context (key_ctx); return status; } #ifdef ECC_ENABLE_GENERATE_KEY_PAIR int ecc_mbedtls_generate_derived_key_pair (const struct ecc_engine *engine, const uint8_t *priv, size_t key_length, struct ecc_private_key *priv_key, struct ecc_public_key *pub_key) { const struct ecc_engine_mbedtls *mbedtls = (const struct ecc_engine_mbedtls*) engine; mbedtls_pk_context *key_ctx; mbedtls_ecp_keypair *ec; mbedtls_ecp_group_id curve; uint8_t msg_code; int status; if ((mbedtls == NULL) || (priv == NULL) || (key_length == 0)) { return ECC_ENGINE_INVALID_ARGUMENT; } if (!priv_key && !pub_key) { return 0; } switch (key_length) { case ECC_KEY_LENGTH_256: curve = MBEDTLS_ECP_DP_SECP256R1; break; #if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_384 case ECC_KEY_LENGTH_384: curve = MBEDTLS_ECP_DP_SECP384R1; break; #if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_521 case ECC_KEY_LENGTH_521: curve = MBEDTLS_ECP_DP_SECP521R1; break; #endif #endif default: return ECC_ENGINE_UNSUPPORTED_KEY_LENGTH; } if (priv_key) { memset (priv_key, 0, sizeof (struct ecc_private_key)); } if (pub_key) { memset (pub_key, 0, sizeof (struct ecc_public_key)); } key_ctx = ecc_mbedtls_alloc_key_context (); if (key_ctx == NULL) { return ECC_ENGINE_NO_MEMORY; } status = mbedtls_pk_setup (key_ctx, mbedtls_pk_info_from_type (MBEDTLS_PK_ECKEY)); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_PK_INIT_EC; goto error_log; } ec = mbedtls_pk_ec (*key_ctx); status = mbedtls_ecp_group_load (&ec->grp, curve); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_GROUP_LOAD_EC; goto error_log; } status = mbedtls_mpi_read_binary (&ec->d, priv, key_length); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_MPI_READ_BIN_EC; goto error_log; } status = mbedtls_ecp_mul (&ec->grp, &ec->Q, &ec->d, &ec->grp.G, mbedtls_ctr_drbg_random, &mbedtls->state->ctr_drbg); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_MUL_EC; goto error_log; } status = mbedtls_ecp_check_privkey (&ec->grp, &ec->d); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_CHECK_PUB_PRV_EC; goto error_log; } if (pub_key) { pub_key->context = ecc_mbedtls_convert_private_to_public (key_ctx, (priv_key), &status); if (pub_key->context == NULL) { goto error; } } if (priv_key) { priv_key->context = key_ctx; } return 0; error_log: debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, msg_code, status, 0); error: ecc_mbedtls_free_key_context (key_ctx); return status; } int ecc_mbedtls_generate_key_pair (const struct ecc_engine *engine, size_t key_length, struct ecc_private_key *priv_key, struct ecc_public_key *pub_key) { const struct ecc_engine_mbedtls *mbedtls = (const struct ecc_engine_mbedtls*) engine; mbedtls_pk_context *key_ctx; mbedtls_ecp_keypair *ec; mbedtls_ecp_group_id curve; uint8_t msg_code; int status; if (mbedtls == NULL) { return ECC_ENGINE_INVALID_ARGUMENT; } if (!priv_key && !pub_key) { return 0; } switch (key_length) { case ECC_KEY_LENGTH_256: curve = MBEDTLS_ECP_DP_SECP256R1; break; #if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_384 case ECC_KEY_LENGTH_384: curve = MBEDTLS_ECP_DP_SECP384R1; break; #if ECC_MAX_KEY_LENGTH >= ECC_KEY_LENGTH_521 case ECC_KEY_LENGTH_521: curve = MBEDTLS_ECP_DP_SECP521R1; break; #endif #endif default: return ECC_ENGINE_UNSUPPORTED_KEY_LENGTH; } if (priv_key) { memset (priv_key, 0, sizeof (struct ecc_private_key)); } if (pub_key) { memset (pub_key, 0, sizeof (struct ecc_public_key)); } key_ctx = ecc_mbedtls_alloc_key_context (); if (key_ctx == NULL) { return ECC_ENGINE_NO_MEMORY; } status = mbedtls_pk_setup (key_ctx, mbedtls_pk_info_from_type (MBEDTLS_PK_ECKEY)); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_PK_INIT_EC; goto error_log; } ec = mbedtls_pk_ec (*key_ctx); status = mbedtls_ecp_gen_key (curve, ec, mbedtls_ctr_drbg_random, &mbedtls->state->ctr_drbg); if (status != 0) { msg_code = CRYPTO_LOG_MSG_MBEDTLS_ECP_GEN_KEY_EC; goto error_log; } if (pub_key) { pub_key->context = ecc_mbedtls_convert_private_to_public (key_ctx, (priv_key), &status); if (pub_key->context == NULL) { goto error; } } if (priv_key) { priv_key->context = key_ctx; } return 0; error_log: debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, msg_code, status, 0); error: ecc_mbedtls_free_key_context (key_ctx); return status; } #endif void ecc_mbedtls_release_key_pair (const struct ecc_engine *engine, struct ecc_private_key *priv_key, struct ecc_public_key *pub_key) { UNUSED (engine); if (priv_key) { ecc_mbedtls_free_key_context (priv_key->context); memset (priv_key, 0, sizeof (struct ecc_private_key)); } if (pub_key) { ecc_mbedtls_free_key_context (pub_key->context); memset (pub_key, 0, sizeof (struct ecc_public_key)); } } int ecc_mbedtls_get_signature_max_length (const struct ecc_engine *engine, const struct ecc_private_key *key) { size_t key_len; if ((engine == NULL) || (key == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } key_len = mbedtls_pk_get_len ((mbedtls_pk_context*) key->context); return (((key_len + 3) * 2) + ((key_len > 61) ? 1 : 2)); } #ifdef ECC_ENABLE_GENERATE_KEY_PAIR int ecc_mbedtls_get_private_key_der (const struct ecc_engine *engine, const struct ecc_private_key *key, uint8_t **der, size_t *length) { uint8_t tmp_der[29 + (3 * MBEDTLS_ECP_MAX_BYTES)]; int status; if (der == NULL) { return ECC_ENGINE_INVALID_ARGUMENT; } *der = NULL; if ((engine == NULL) || (key == NULL) || (length == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } if (ecc_mbedtls_get_ec_key_pair (key)->d.n == 0) { return ECC_ENGINE_NOT_PRIVATE_KEY; } status = mbedtls_pk_write_key_der ((mbedtls_pk_context*) key->context, tmp_der, sizeof (tmp_der)); if (status >= 0) { *der = platform_malloc (status); if (*der == NULL) { return ECC_ENGINE_NO_MEMORY; } memcpy (*der, &tmp_der[sizeof (tmp_der) - status], status); *length = status; status = 0; } else { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_WRITE_KEY_DER_EC, status, 0); } return status; } int ecc_mbedtls_get_public_key_der (const struct ecc_engine *engine, const struct ecc_public_key *key, uint8_t **der, size_t *length) { uint8_t tmp_der[30 + (2 * MBEDTLS_ECP_MAX_BYTES)]; int status; if (der == NULL) { return ECC_ENGINE_INVALID_ARGUMENT; } *der = NULL; if ((engine == NULL) || (key == NULL) || (length == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } if (ecc_mbedtls_get_ec_key_pair (key)->d.n != 0) { return ECC_ENGINE_NOT_PUBLIC_KEY; } status = mbedtls_pk_write_pubkey_der ((mbedtls_pk_context*) key->context, tmp_der, sizeof (tmp_der)); if (status >= 0) { *der = platform_malloc (status); if (*der == NULL) { return ECC_ENGINE_NO_MEMORY; } memcpy (*der, &tmp_der[sizeof (tmp_der) - status], status); *length = status; status = 0; } else { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_WRITE_PUBKEY_DER_EC, status, 0); } return status; } #endif int ecc_mbedtls_sign (const struct ecc_engine *engine, const struct ecc_private_key *key, const uint8_t *digest, size_t length, const struct rng_engine *rng, uint8_t *signature, size_t sig_length) { const struct ecc_engine_mbedtls *mbedtls = (const struct ecc_engine_mbedtls*) engine; mbedtls_ecp_keypair *ec; mbedtls_md_type_t hash_alg; int status; if ((mbedtls == NULL) || (key == NULL) || (digest == NULL) || (signature == NULL) || (length == 0)) { return ECC_ENGINE_INVALID_ARGUMENT; } if ((int) sig_length < ecc_mbedtls_get_signature_max_length (engine, key)) { return ECC_ENGINE_SIG_BUFFER_TOO_SMALL; } switch (length) { case SHA256_HASH_LENGTH: hash_alg = MBEDTLS_MD_SHA256; break; case SHA384_HASH_LENGTH: hash_alg = MBEDTLS_MD_SHA384; break; case SHA512_HASH_LENGTH: hash_alg = MBEDTLS_MD_SHA512; break; default: return ECC_ENGINE_UNSUPPORTED_HASH_TYPE; } ec = ecc_mbedtls_get_ec_key_pair (key); status = mbedtls_ecp_check_privkey (&ec->grp, &ec->d); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_ECP_CHECK_PUB_PRV_EC, status, 0); return status; } if (rng == NULL) { status = mbedtls_pk_sign ((mbedtls_pk_context*) key->context, hash_alg, digest, length, signature, &sig_length, mbedtls_ctr_drbg_random, &mbedtls->state->ctr_drbg); } else { #ifndef MBEDTLS_ECDSA_DETERMINISTIC status = mbedtls_pk_sign ((mbedtls_pk_context*) key->context, hash_alg, digest, length, signature, &sig_length, rng_mbedtls_rng_callback, (void*) rng); #else /* Cannot override the random number generation when deterministic ECDSA is enabled. */ status = ECC_ENGINE_UNSUPPORTED_OPERATION; #endif } if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_SIGN_EC, status, 0); } return (status == 0) ? (int) sig_length : status; } int ecc_mbedtls_verify (const struct ecc_engine *engine, const struct ecc_public_key *key, const uint8_t *digest, size_t length, const uint8_t *signature, size_t sig_length) { int status; if ((engine == NULL) || (key == NULL) || (digest == NULL) || (signature == NULL) || (length == 0) || (sig_length == 0)) { return ECC_ENGINE_INVALID_ARGUMENT; } status = mbedtls_pk_verify ((mbedtls_pk_context*) key->context, MBEDTLS_MD_NONE, digest, length, signature, ecc_der_get_ecdsa_signature_length (signature, sig_length)); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_PK_VERIFY_EC, status, 0); if ((status == MBEDTLS_ERR_MPI_ALLOC_FAILED) || (status == (MBEDTLS_ERR_MPI_ALLOC_FAILED + MBEDTLS_ERR_ECP_BAD_INPUT_DATA))) { return ECC_ENGINE_NO_MEMORY; } else { return ECC_ENGINE_BAD_SIGNATURE; } } return status; } #ifdef ECC_ENABLE_ECDH int ecc_mbedtls_get_shared_secret_max_length (const struct ecc_engine *engine, const struct ecc_private_key *key) { int status; if ((engine == NULL) || (key == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } status = mbedtls_pk_get_len ((mbedtls_pk_context*) key->context); if (status == 0) { return ECC_ENGINE_SECRET_LENGTH_FAILED; } return status; } int ecc_mbedtls_compute_shared_secret (const struct ecc_engine *engine, const struct ecc_private_key *priv_key, const struct ecc_public_key *pub_key, uint8_t *secret, size_t length) { const struct ecc_engine_mbedtls *mbedtls = (const struct ecc_engine_mbedtls*) engine; mbedtls_ecp_keypair *priv_ec; mbedtls_ecp_keypair *pub_ec; mbedtls_mpi out; size_t out_len; int secret_len; int status; if ((mbedtls == NULL) || (priv_key == NULL) || (pub_key == NULL) || (secret == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } secret_len = ecc_mbedtls_get_shared_secret_max_length (engine, priv_key); if (ROT_IS_ERROR (secret_len)) { return secret_len; } if (length < (size_t) secret_len) { return ECC_ENGINE_SECRET_BUFFER_TOO_SMALL; } priv_ec = ecc_mbedtls_get_ec_key_pair (priv_key); pub_ec = ecc_mbedtls_get_ec_key_pair (pub_key); mbedtls_mpi_init (&out); status = mbedtls_ecdh_compute_shared (&priv_ec->grp, &out, &pub_ec->Q, &priv_ec->d, mbedtls_ctr_drbg_random, &mbedtls->state->ctr_drbg); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_ECDH_COMPUTE_SHARED_SECRET_EC, status, 0); goto error; } out_len = mbedtls_mpi_size (&out); if (out_len > (size_t) secret_len) { status = ECC_ENGINE_SECRET_BUFFER_TOO_SMALL; goto error; } memset (secret, 0, length); mbedtls_mpi_write_binary (&out, &secret[secret_len - out_len], out_len); mbedtls_mpi_free (&out); return secret_len; error: mbedtls_mpi_free (&out); return status; } #endif /** * Initialize an instance for running ECC operations using mbedTLS. * * @param engine The ECC engine to initialize. * @param state Variable context for the ECC engine. This must be uninitialized. * * @return 0 if the engine was successfully initialized or an error code. */ int ecc_mbedtls_init (struct ecc_engine_mbedtls *engine, struct ecc_engine_mbedtls_state *state) { if (engine == NULL) { return ECC_ENGINE_INVALID_ARGUMENT; } memset (engine, 0, sizeof (struct ecc_engine_mbedtls)); engine->base.init_key_pair = ecc_mbedtls_init_key_pair; engine->base.init_public_key = ecc_mbedtls_init_public_key; #ifdef ECC_ENABLE_GENERATE_KEY_PAIR engine->base.generate_derived_key_pair = ecc_mbedtls_generate_derived_key_pair; engine->base.generate_key_pair = ecc_mbedtls_generate_key_pair; #endif engine->base.release_key_pair = ecc_mbedtls_release_key_pair; engine->base.get_signature_max_length = ecc_mbedtls_get_signature_max_length; #ifdef ECC_ENABLE_GENERATE_KEY_PAIR engine->base.get_private_key_der = ecc_mbedtls_get_private_key_der; engine->base.get_public_key_der = ecc_mbedtls_get_public_key_der; #endif engine->base.sign = ecc_mbedtls_sign; engine->base.verify = ecc_mbedtls_verify; #ifdef ECC_ENABLE_ECDH engine->base.get_shared_secret_max_length = ecc_mbedtls_get_shared_secret_max_length; engine->base.compute_shared_secret = ecc_mbedtls_compute_shared_secret; #endif engine->state = state; return ecc_mbedtls_init_state (engine); } /** * Initialize only the variable state of an mbedTLS ECC engine. The rest of the instance is assumed * to already have been initialized. * * This would generally be used with a statically initialized instance. * * @param engine The ECC engine that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int ecc_mbedtls_init_state (const struct ecc_engine_mbedtls *engine) { int status; if ((engine == NULL) || (engine->state == NULL)) { return ECC_ENGINE_INVALID_ARGUMENT; } memset (engine->state, 0, sizeof (*engine->state)); mbedtls_ctr_drbg_init (&engine->state->ctr_drbg); mbedtls_entropy_init (&engine->state->entropy); status = mbedtls_ctr_drbg_seed (&engine->state->ctr_drbg, mbedtls_entropy_func, &engine->state->entropy, NULL, 0); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_CTR_DRBG_SEED_EC, status, 0); goto exit; } return 0; exit: mbedtls_entropy_free (&engine->state->entropy); mbedtls_ctr_drbg_free (&engine->state->ctr_drbg); return status; } /** * Release an mbedTLS ECC engine. * * @param engine The ECC engine to release. */ void ecc_mbedtls_release (const struct ecc_engine_mbedtls *engine) { if (engine) { mbedtls_entropy_free (&engine->state->entropy); mbedtls_ctr_drbg_free (&engine->state->ctr_drbg); } }