core/crypto/ecdsa.c (414 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <string.h> #include "ecdsa.h" #include "signature_verification_ecc.h" #include "common/buffer_util.h" #include "common/common_math.h" /** * Instantiate an HMAC_DRBG per RFC 6979 that can be used for generating the k value needed for * ECDSA signatures in a deterministic way. * * @param drbg The ECDSA DRBG context to instantiate. This must be wiped using * ecdsa_deterministic_k_drbg_clear after the signing process has completed. * @param hash The hash engine to used for HMAC operations. * @param hmac_algo The HMAC algorithm that should be used by the DRBG. * @param message_digest Digest of the message that is being signed with ECDSA. This can be either * the raw digest of the message data or the truncated/padded version used during signature * generation. * @param digest_length Length of the message digest. * @param priv_key The private key being used to sign the message. * @param key_length Length of the private key. * * @return 0 if the ECDSA DRBG was instantiated successfully or an error code. */ int ecdsa_deterministic_k_drbg_instantiate (struct ecdsa_deterministic_k_drbg *drbg, const struct hash_engine *hash, enum hmac_hash hmac_algo, const uint8_t *message_digest, size_t digest_length, const uint8_t *priv_key, size_t key_length) { struct hmac_engine hmac; int hash_length; uint8_t internal_octet; int status; if ((drbg == NULL) || (hash == NULL) || (message_digest == NULL) || (priv_key == NULL)) { return ECDSA_INVALID_ARGUMENT; } hash_length = hash_hmac_get_hmac_length (hmac_algo); if (hash_length == HASH_ENGINE_UNKNOWN_HASH) { return hash_length; } /* Set the initial values for K (0's) and V (1's). */ memset (drbg->key, 0, sizeof (drbg->key)); memset (drbg->value, 1, sizeof (drbg->value)); drbg->first = true; drbg->hmac_algo = hmac_algo; for (internal_octet = 0; internal_octet < 2; internal_octet++) { /* Derive a new K from the private key and message digest. */ status = hash_hmac_init (&hmac, hash, hmac_algo, drbg->key, hash_length); if (status != 0) { goto erase_context; } status = hash_hmac_update (&hmac, drbg->value, hash_length); if (status != 0) { goto hmac_cancel; } status = hash_hmac_update (&hmac, &internal_octet, 1); if (status != 0) { goto hmac_cancel; } status = hash_hmac_update (&hmac, priv_key, key_length); if (status != 0) { goto hmac_cancel; } status = hash_hmac_update (&hmac, message_digest, digest_length); if (status != 0) { goto hmac_cancel; } status = hash_hmac_finish (&hmac, drbg->key, sizeof (drbg->key)); if (status != 0) { goto erase_context; } /* Derive the new V using the updated K. */ status = hash_generate_hmac (hash, drbg->key, hash_length, drbg->value, hash_length, hmac_algo, drbg->value, sizeof (drbg->value)); if (status != 0) { goto erase_context; } } return 0; hmac_cancel: hash_hmac_cancel (&hmac); erase_context: buffer_zeroize (drbg, sizeof (*drbg)); return status; } /** * Generate a k value that can be used for ECDSA signatures following the deterministic generation * algorithm specified in RFC 6979. ecdsa_instantiate_deterministic_k_drbg must be called prior to * generating any k values. * * No checking of the resultant value against curve order is done, nor is it proven to generate a * valid r value. It is up to the caller to ensure the generated k value is valid and call this * function again if a new k is needed. * * If this call fails, the DRBG is left in an indeterminate state. The DRBG context should be * cleared and reinstantiated for additional attempts to generate a k value. * * @param drbg The instantiated DRBG to use for k generation. The DRBG context will be updated, * allowing for multiple calls to be made if invalid k values are produced. * @param hash The hash engine to use for HMAC operations. * @param k Output for the k value generated by the DRBG. * @param k_length The number of bytes to generate for k. * * @return 0 if k was generated successfully or an error code. */ int ecdsa_deterministic_k_drbg_generate (struct ecdsa_deterministic_k_drbg *drbg, const struct hash_engine *hash, uint8_t *k, size_t k_length) { struct hmac_engine hmac; uint8_t zero = 0x00; int hash_length; uint8_t *pos = k; size_t remaining = k_length; int status; if ((drbg == NULL) || (hash == NULL) || (k == NULL)) { return ECDSA_INVALID_ARGUMENT; } hash_length = hash_hmac_get_hmac_length (drbg->hmac_algo); if (hash_length == HASH_ENGINE_UNKNOWN_HASH) { return hash_length; } if (!drbg->first) { /* For subsequent requests, new K and V values need to be calculated. */ status = hash_hmac_init (&hmac, hash, drbg->hmac_algo, drbg->key, hash_length); if (status != 0) { return status; } status = hash_hmac_update (&hmac, drbg->value, hash_length); if (status != 0) { hash_hmac_cancel (&hmac); return status; } status = hash_hmac_update (&hmac, &zero, 1); if (status != 0) { hash_hmac_cancel (&hmac); return status; } status = hash_hmac_finish (&hmac, drbg->key, sizeof (drbg->key)); if (status != 0) { return status; } status = hash_generate_hmac (hash, drbg->key, hash_length, drbg->value, hash_length, drbg->hmac_algo, drbg->value, sizeof (drbg->value)); if (status != 0) { return status; } } drbg->first = false; while (remaining > 0) { status = hash_generate_hmac (hash, drbg->key, hash_length, drbg->value, hash_length, drbg->hmac_algo, drbg->value, sizeof (drbg->value)); if (status != 0) { return status; } pos += buffer_copy (drbg->value, hash_length, NULL, &remaining, pos); } /* When the key length is not an even multiple of bytes, bits need to get dropped from the * generated data. Per the RFC, this would be the last bits in the array, meaning the entire * array needs to be right shifted. */ if (k_length == ECC_KEY_LENGTH_521) { common_math_right_shift_array (k, k_length, 7); } return 0; } /** * Erase the DRBG context used for ECDSA signature k generation. * * @param drbg The DRBG context to clear. */ void ecdsa_deterministic_k_drbg_clear (struct ecdsa_deterministic_k_drbg *drbg) { buffer_zeroize (drbg, sizeof (*drbg)); } /** * Generate an ECDSA signature for a specified message. * * @param ecc The ECC engine to use for signature generation. * @param hash The hash engine that will be used to calculate the message digest. * @param hash_algo Algorithm to use for message hashing. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC engine will use a default RNG. * @param priv_key DER encoded ECC private key to use for signing. * @param key_length Length of the ECC private key data. * @param message The raw message data that should be signed. * @param msg_length Length of the message. * @param signature Output buffer for the ECDSA signature. The signature will be DER encoded. * @param sig_length The length of the signature output buffer. * * @return The length of the signature or an error code. Use ROT_IS_ERROR to check the return * value. */ int ecdsa_sign_message (const struct ecc_engine *ecc, const struct hash_engine *hash, enum hash_type hash_algo, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, const uint8_t *message, size_t msg_length, uint8_t *signature, size_t sig_length) { int status; if ((ecc == NULL) || (hash == NULL) || (priv_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } status = hash_start_new_hash (hash, hash_algo); if (status != 0) { return status; } status = hash->update (hash, message, msg_length); if (status != 0) { hash->cancel (hash); return status; } return ecdsa_sign_hash_and_finish (ecc, hash, rng, priv_key, key_length, signature, sig_length); } /** * Generate an ECDSA signature for the calculated digest. * * @param ecc The ECC engine to use for signature generation. * @param digest The digest to sign. This will be zeroized upon return. * @param digest_length Length of the digest to sign. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC engine will use a default RNG. * @param priv_key DER encoded ECC private key to use for signing. * @param key_length Length of the ECC private key data. * @param signature Output buffer for the ECDSA signature. The signature will be DER encoded. * @param sig_length The length of the signature output buffer. * * @return The length of the signature or an error code. Use ROT_IS_ERROR to check the return * value. */ static int ecdsa_sign_digest (const struct ecc_engine *ecc, uint8_t digest[HASH_MAX_HASH_LEN], size_t digest_length, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, uint8_t *signature, size_t sig_length) { struct ecc_private_key sign_key; int status; status = ecc->init_key_pair (ecc, priv_key, key_length, &sign_key, NULL); if (status != 0) { goto exit; } status = ecc->sign (ecc, &sign_key, digest, digest_length, rng, signature, sig_length); ecc->release_key_pair (ecc, &sign_key, NULL); exit: buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } /** * Generate an ECDSA signature for an active hash context. * * The hash context will remain active after signature generation, allowing additional updates to be * made. Not all hash implementations support this type of behavior, so it should only be used in * scenarios which require it. Most scenarios should use ecdsa_sign_hash_and_finish instead. * * @param ecc The ECC engine to use for signature generation. * @param hash The hash engine that contains the active context to sign. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC engine will use a default RNG. * @param priv_key DER encoded ECC private key to use for signing. * @param key_length Length of the ECC private key. * @param signature Output buffer for the ECDSA signature. The signature will be DER encoded. * @param sig_length The length of the signature output buffer. * * @return The length of the signature or an error code. Use ROT_IS_ERROR to check the return * value. */ int ecdsa_sign_hash (const struct ecc_engine *ecc, const struct hash_engine *hash, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, uint8_t *signature, size_t sig_length) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if ((ecc == NULL) || (hash == NULL) || (priv_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } status = hash->get_hash (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } return ecdsa_sign_digest (ecc, digest, digest_length, rng, priv_key, key_length, signature, sig_length); } /** * Generate an ECDSA signature for an active hash context. * * The hash context will be finished as part of signature generation. No additional updates can be * made to the hash context, regardless of whether the signature generation was successful or not. * * @param ecc The ECC engine to use for signature generation. * @param hash The hash engine that contains the active context to sign. The active context will * always be terminated upon returning from this call. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC engine will use a default RNG. * @param priv_key DER encoded ECC private key to use for signing. * @param key_length Length of the ECC private key. * @param signature Output buffer for the ECDSA signature. The signature will be DER encoded. * @param sig_length The length of the signature output buffer. * * @return The length of the signature or an error code. Use ROT_IS_ERROR to check the return * value. */ int ecdsa_sign_hash_and_finish (const struct ecc_engine *ecc, const struct hash_engine *hash, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, uint8_t *signature, size_t sig_length) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if (hash == NULL) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } if ((ecc == NULL) || (priv_key == NULL) || (signature == NULL)) { status = ECDSA_INVALID_ARGUMENT; goto hash_cancel; } status = hash->finish (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); goto hash_cancel; } return ecdsa_sign_digest (ecc, digest, digest_length, rng, priv_key, key_length, signature, sig_length); hash_cancel: hash->cancel (hash); return status; } /** * Verify a specified message with an ECDSA signature. * * @param ecc The ECC engine to use for ECDSA signature verification. * @param hash The hash engine that will be used to calculate the message digest. * @param hash_algo Algorithm to use for message hashing. * @param message The raw message data that should be verified. * @param msg_length Length of the message. * @param pub_key A DER encoded ECC public key to use for verification. Providing a private key is * also supported, though verification will use only the public portion of the key pair. * @param key_length Length of the DER encoded ECC key. * @param signature The DER encoded ECDSA signature for the message data. * @param sig_length Length of the ECDSA signature. * * @return 0 if the message was verified successfully or an error code. */ int ecdsa_verify_message (const struct ecc_engine *ecc, const struct hash_engine *hash, enum hash_type hash_algo, const uint8_t *message, size_t msg_length, const uint8_t *pub_key, size_t key_length, const uint8_t *signature, size_t sig_length) { struct signature_verification_ecc_state sig_verify_state; struct signature_verification_ecc sig_verify; int status; status = signature_verification_ecc_init (&sig_verify, &sig_verify_state, ecc, pub_key, key_length); if (status != 0) { return status; } status = signature_verification_verify_message (&sig_verify.base, hash, hash_algo, message, msg_length, NULL, 0, signature, sig_length); signature_verification_ecc_release (&sig_verify); return status; } /** * Verify an active hash context with an ECDSA signature. * * The hash context will remain active after signature verification, allowing additional updates to * be made. Not all hash implementations support this type of behavior, so it should only be used * in scenarios which require it. Most scenarios should use ecdsa_verify_hash_and_finish instead. * * @param ecc The ECC engine to use for ECDSA signature verification. * @param hash The hash engine that contains the active context to verify. * @param pub_key A DER encoded ECC public key to use for verification. Providing a private key is * also supported, though verification will use only the public portion of the key pair. * @param key_length Length of the DER encoded ECC key. * @param signature The DER encoded ECDSA signature for the hash context. * @param sig_length Length of the ECDSA signature. * * @return 0 if the hash was verified successfully or an error code. */ int ecdsa_verify_hash (const struct ecc_engine *ecc, const struct hash_engine *hash, const uint8_t *pub_key, size_t key_length, const uint8_t *signature, size_t sig_length) { struct signature_verification_ecc_state sig_verify_state; struct signature_verification_ecc sig_verify; int status; status = signature_verification_ecc_init (&sig_verify, &sig_verify_state, ecc, pub_key, key_length); if (status != 0) { return status; } status = signature_verification_verify_hash (&sig_verify.base, hash, NULL, 0, signature, sig_length); signature_verification_ecc_release (&sig_verify); return status; } /** * Verify an active hash context with an ECDSA signature. * * The hash context will be finished as part of signature verification. No additional updates can * be made to the hash context, regardless of whether the signature verification was successful or * not. * * @param ecc The ECC engine to use for ECDSA signature verification. * @param hash The hash engine that contains the active context to verify. * @param pub_key A DER encoded ECC public key to use for verification. Providing a private key is * also supported, though verification will use only the public portion of the key pair. * @param key_length Length of the DER encoded ECC key. * @param signature The DER encoded ECDSA signature for the hash context. * @param sig_length Length of the ECDSA signature. * * @return 0 if the hash was verified successfully or an error code. */ int ecdsa_verify_hash_and_finish (const struct ecc_engine *ecc, const struct hash_engine *hash, const uint8_t *pub_key, size_t key_length, const uint8_t *signature, size_t sig_length) { struct signature_verification_ecc_state sig_verify_state; struct signature_verification_ecc sig_verify; int status; status = signature_verification_ecc_init (&sig_verify, &sig_verify_state, ecc, pub_key, key_length); if (status != 0) { return status; } status = signature_verification_verify_hash_and_finish (&sig_verify.base, hash, NULL, 0, signature, sig_length); signature_verification_ecc_release (&sig_verify); return status; } /** * Generate an ECDSA signature for a specified message using an ECC hardware implementation. * * @param ecc_hw The ECC hardware instance to use for signature generation. * @param hash The hash engine that will be used to calculate the message digest. * @param hash_algo Algorithm to use for message hashing. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC hardware instance will use a default RNG, if one is * available. * @param priv_key Raw ECC private key to use for signing. * @param key_length Length of the ECC private key. This will determine the curve to use. * @param message The raw message data that should be signed. * @param msg_length Length of the message. * @param signature Output buffer for the ECDSA signature. * * @return 0 if the signature was generated successfully or an error code. */ int ecdsa_ecc_hw_sign_message (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, enum hash_type hash_algo, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, const uint8_t *message, size_t msg_length, struct ecc_ecdsa_signature *signature) { int status; if ((ecc_hw == NULL) || (hash == NULL) || (priv_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } status = hash_start_new_hash (hash, hash_algo); if (status != 0) { return status; } status = hash->update (hash, message, msg_length); if (status != 0) { hash->cancel (hash); return status; } return ecdsa_ecc_hw_sign_hash_and_finish (ecc_hw, hash, rng, priv_key, key_length, signature); } /** * Generate an ECDSA signature for the calculated digest using an ECC hardware implementation. * * @param ecc_hw The ECC hardware instance to use for signature generation. * @param digest The digest to sign. This will be zeroized upon return. * @param digest_length Length of the digest to sign. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC hardware instance will use a default RNG, if one is * available. * @param priv_key Raw ECC private key to use for signing. * @param key_length Length of the ECC private key. This will determine the curve to use. * @param signature Output buffer for the ECDSA signature. * * @return 0 if the signature was generated successfully or an error code. */ static int ecdsa_ecc_hw_sign_digest (const struct ecc_hw *ecc_hw, uint8_t digest[HASH_MAX_HASH_LEN], size_t digest_length, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, struct ecc_ecdsa_signature *signature) { int status; status = ecc_hw->ecdsa_sign (ecc_hw, priv_key, key_length, digest, digest_length, rng, signature); buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } /** * Generate an ECDSA signature for an active hash context using an ECC hardware implementation. * * The hash context will remain active after signature generation, allowing additional updates to be * made. Not all hash implementations support this type of behavior, so it should only be used in * scenarios which require it. Most scenarios should use ecdsa_ecc_hw_sign_hash_and_finish instead. * * @param ecc_hw The ECC hardware instance to use for signature generation. * @param hash The hash engine that contains the active context to sign. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC hardware instance will use a default RNG, if one is * available. * @param priv_key Raw ECC private key to use for signing. * @param key_length Length of the ECC private key. This will determine the curve to use. * @param signature Output buffer for the ECDSA signature. * * @return 0 if the signature was generated successfully or an error code. */ int ecdsa_ecc_hw_sign_hash (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, struct ecc_ecdsa_signature *signature) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if ((ecc_hw == NULL) || (hash == NULL) || (priv_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } status = hash->get_hash (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } return ecdsa_ecc_hw_sign_digest (ecc_hw, digest, digest_length, rng, priv_key, key_length, signature); } /** * Generate an ECDSA signature for an active hash context using an ECC hardware implementation. * * The hash context will be finished as part of signature generation. No additional updates can be * made to the hash context, regardless of whether the signature generation was successful or not. * * @param ecc_hw The ECC hardware instance to use for signature generation. * @param hash The hash engine that contains the active context to sign. The active context will * always be terminated upon returning from this call. * @param rng The random number generator that will be used to generate the random 'r' value in the * signature. If this is null, the ECC hardware instance will use a default RNG, if one is * available. * @param priv_key Raw ECC private key to use for signing. * @param key_length Length of the ECC private key. This will determine the curve to use. * @param signature Output buffer for the ECDSA signature. * * @return 0 if the signature was generated successfully or an error code. */ int ecdsa_ecc_hw_sign_hash_and_finish (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, const struct rng_engine *rng, const uint8_t *priv_key, size_t key_length, struct ecc_ecdsa_signature *signature) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if (hash == NULL) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } if ((ecc_hw == NULL) || (priv_key == NULL) || (signature == NULL)) { status = ECDSA_INVALID_ARGUMENT; goto hash_cancel; } status = hash->finish (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); goto hash_cancel; } return ecdsa_ecc_hw_sign_digest (ecc_hw, digest, digest_length, rng, priv_key, key_length, signature); hash_cancel: hash->cancel (hash); return status; } /** * Verify a specified message with an ECDSA signature using an ECC hardware implementation. * * @param ecc_hw The ECC hardware instance to use for signature verification. * @param hash The hash engine that will be used to calculate the message digest. * @param hash_algo Algorithm to use for message hashing. * @param message The raw message data that should be verified. * @param msg_length Length of the message. * @param pub_key Public key to use for verification. The key length will determine the curve to * use. * @param signature The ECDSA signature for the message data. * * @return 0 if the message was verified successfully or an error code. */ int ecdsa_ecc_hw_verify_message (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, enum hash_type hash_algo, const uint8_t *message, size_t msg_length, const struct ecc_point_public_key *pub_key, const struct ecc_ecdsa_signature *signature) { int status; if ((ecc_hw == NULL) || (hash == NULL) || (pub_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } status = hash_start_new_hash (hash, hash_algo); if (status != 0) { return status; } status = hash->update (hash, message, msg_length); if (status != 0) { hash->cancel (hash); return status; } return ecdsa_ecc_hw_verify_hash_and_finish (ecc_hw, hash, pub_key, signature); } /** * Verify a calculated digest against the provided ECDSA signature using an ECC hardware * implementation. * * @param ecc_hw The ECC hardware instance to use for signature verification. * @param digest The digest to verify. This will be zeroized upon return. * @param digest_length Length of the digest to verify. * @param pub_key Public key to use for verification. The key length will determine the curve to * use. * @param signature The ECDSA signature for the digest. * * @return 0 if the digest was verified successfully or an error code. */ static int ecdsa_ecc_hw_verify_digest (const struct ecc_hw *ecc_hw, uint8_t digest[HASH_MAX_HASH_LEN], size_t digest_length, const struct ecc_point_public_key *pub_key, const struct ecc_ecdsa_signature *signature) { int status; status = ecc_hw->ecdsa_verify (ecc_hw, pub_key, signature, digest, digest_length); buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } /** * Verify an active hash context with an ECDSA signature using an ECC hardware implementation. * * The hash context will remain active after signature verification, allowing additional updates to * be made. Not all hash implementations support this type of behavior, so it should only be used * in scenarios which require it. Most scenarios should use ecdsa_ecc_hw_verify_hash_and_finish * instead. * * @param ecc_hw The ECC hardware instance to use for signature verification. * @param hash The hash engine that contains the active context to verify. * @param pub_key Public key to use for verification. The key length will determine the curve to * use. * @param signature The ECDSA signature for the hash context. * * @return 0 if the hash was verified successfully or an error code. */ int ecdsa_ecc_hw_verify_hash (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, const struct ecc_point_public_key *pub_key, const struct ecc_ecdsa_signature *signature) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if ((ecc_hw == NULL) || (hash == NULL) || (pub_key == NULL) || (signature == NULL)) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } status = hash->get_hash (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); return status; } return ecdsa_ecc_hw_verify_digest (ecc_hw, digest, digest_length, pub_key, signature); } /** * Verify an active hash context with an ECDSA signature using an ECC hardware implementation. * * The hash context will be finished as part of signature verification. No additional updates can * be made to the hash context, regardless of whether the signature verification was successful or * not. * * @param ecc_hw The ECC hardware instance to use for signature verification. * @param hash The hash engine that contains the active context to verify. The active context will * always be terminated upon returning from this call. * @param pub_key Public key to use for verification. The key length will determine the curve to * use. * @param signature The ECDSA signature for the hash context. * * @return 0 if the hash was verified successfully or an error code. */ int ecdsa_ecc_hw_verify_hash_and_finish (const struct ecc_hw *ecc_hw, const struct hash_engine *hash, const struct ecc_point_public_key *pub_key, const struct ecc_ecdsa_signature *signature) { uint8_t digest[HASH_MAX_HASH_LEN] = {0}; size_t digest_length; int status; if (hash == NULL) { return ECDSA_INVALID_ARGUMENT; } digest_length = hash_get_active_hash_length (hash); if (digest_length == 0) { return ECDSA_NO_ACTVE_HASH; } if ((ecc_hw == NULL) || (pub_key == NULL) || (signature == NULL)) { status = ECDSA_INVALID_ARGUMENT; goto hash_cancel; } status = hash->finish (hash, digest, sizeof (digest)); if (status != 0) { buffer_zeroize (digest, HASH_MAX_HASH_LEN); goto hash_cancel; } return ecdsa_ecc_hw_verify_digest (ecc_hw, digest, digest_length, pub_key, signature); hash_cancel: hash->cancel (hash); return status; }