core/crypto/ecc.h (101 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#ifndef ECC_H_
#define ECC_H_
#include <stddef.h>
#include <stdint.h>
#include "crypto/rng.h"
#include "status/rot_status.h"
/* Private key lengths */
#define ECC_KEY_LENGTH_256 (256 / 8)
#define ECC_KEY_LENGTH_384 (384 / 8)
#define ECC_KEY_LENGTH_521 (528 / 8)
/* Configurable ECC parameters. Defaults can be overridden in platform_config.h. */
#include "platform_config.h"
#ifndef ECC_MAX_KEY_LENGTH
#define ECC_MAX_KEY_LENGTH ECC_KEY_LENGTH_521
#endif
#if ECC_MAX_KEY_LENGTH < ECC_KEY_LENGTH_256
#error "ECC must at least have support for 256-bit keys."
#endif
/**
* An ECC private key. A key instance is only usable by the engine that initialized it.
*/
struct ecc_private_key {
void *context; /**< The implementation context for the private key. */
};
/**
* An ECC public key. A key instance is only usable by the engine that initialized it.
*/
struct ecc_public_key {
void *context; /**< The implementation context for the public key. */
};
#pragma pack(push,1)
/**
* Defines a structure to hold the raw value (i.e. not ASN.1/DER encoded) for an ECC private key.
* No curve information is stored. The curve is implied based on the key length.
*/
struct ecc_raw_private_key {
uint8_t d[ECC_MAX_KEY_LENGTH]; /**< The integer used as the private key. */
size_t key_length; /**< Length of the private key. */
};
/**
* Defines a structure to hold the X and Y values for a point on a curve that represents an ECC
* public key. No curve information is stored. The curve is implied based on the key length.
*/
struct ecc_point_public_key {
uint8_t x[ECC_MAX_KEY_LENGTH]; /**< X coordinate for the ECC public key. */
uint8_t y[ECC_MAX_KEY_LENGTH]; /**< Y coordinate for the ECC public key. */
size_t key_length; /**< Length of each coordinate in the public key. */
};
/**
* Defines a structure to hold the raw r and s values (i.e. not ASN.1/DER encoded) for an ECDSA
* signature. These values are expected to match the private key length and have the MSBs padded
* with 0's when necessary.
*/
struct ecc_ecdsa_signature {
uint8_t r[ECC_MAX_KEY_LENGTH]; /**< r value for the ECDSA signature. */
uint8_t s[ECC_MAX_KEY_LENGTH]; /**< s value for the ECDSA signature. */
size_t length; /**< Length of each integer in the ECDSA signature. */
};
#pragma pack(pop)
/**
* A platform-independent API for generating and using ECC key pairs. ECC engine instances are not
* guaranteed to be thread-safe.
*/
struct ecc_engine {
/**
* Initialize an ECC key pair to be used by the ECC engine.
*
* @param engine The ECC engine to use for key initialization.
* @param key The private key to use for key initialization. This must be a DER encoded private
* key. It can contain more bytes that specified in the DER encoding, which will be ignored.
* Some implementations only provide oracle access to private keys. In these cases, the DER
* encoded data would be some identifier for the private key.
* @param key_length The length of the private key data.
* @param priv_key Output for the initialized private key. This can be null to skip private key
* initialization.
* @param pub_key Output for the initialized public key. This can be null to skip public key
* initialization.
*
* @return 0 if the key pair was successfully initialized or an error code.
*/
int (*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);
/**
* Initialize an ECC public key to be used by the ECC engine.
*
* @param engine The ECC engine to use for key initialization.
* @param key The public key to use for key initialization. This must be a DER encoded public
* key. It can contain more bytes that specified in the DER encoding, which will be ignored.
* @param key_length The length of the public key data.
* @param pub_key Output for the initialized public key.
*
* @return 0 if the public key was successfully initialized or an error code.
*/
int (*init_public_key) (const struct ecc_engine *engine, const uint8_t *key, size_t key_length,
struct ecc_public_key *pub_key);
#ifdef ECC_ENABLE_GENERATE_KEY_PAIR
/**
* Generate an ECC key pair using a specified value for the private key. The length of the
* specified private key determines the ECC curve to use for key pair generation.
* - ECC_KEY_LENGTH_256 -> NIST P-256
* - ECC_KEY_LENGTH_384 -> NIST P-384
* - ECC_KEY_LENGTH_521 -> NIST P-521
*
* @param engine The ECC engine to use to generate the key pair.
* @param priv The private value to use for key generation.
* @param key_length The length of the private key.
* @param priv_key Output for the generated private key. This can be null to skip private key
* generation.
* @param pub_key Output for the generated public key. This can be null to skip public key
* generation.
*
* @return 0 if the key pair was successfully generated or an error code.
*/
int (*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);
/**
* Generate a random ECC key pair. The desired length of the key determines the ECC curve to
* use for key pair generation.
* - ECC_KEY_LENGTH_256 -> NIST P-256
* - ECC_KEY_LENGTH_384 -> NIST P-384
* - ECC_KEY_LENGTH_521 -> NIST P-521
*
* @param engine The ECC engine to use to generate the key pair.
* @param key_length The length of the key that should be generated.
* @param priv_key Output for the generated private key. This can be null to skip private key
* generation.
* @param pub_key Output for the generated public key. This can be null to skip public key
* generation.
*
* @return 0 if the key pair was successfully generated or an error code.
*/
int (*generate_key_pair) (const struct ecc_engine *engine, size_t key_length,
struct ecc_private_key *priv_key, struct ecc_public_key *pub_key);
#endif
/**
* Release ECC keys. The memory for released keys will be zeroed.
*
* @param engine The ECC engine used to generated the keys.
* @param priv_key The private key to release. This can be null to not release a private key.
* @param pub_key The public key to release. This can be null to not release a public key.
*/
void (*release_key_pair) (const struct ecc_engine *engine, struct ecc_private_key *priv_key,
struct ecc_public_key *pub_key);
/**
* Get the maximum length for a ECDSA signature generated using a given key.
*
* @param engine The ECC engine to query.
* @param key The private key that would be used for the signature.
*
* @return The maximum number of signature bytes or an error code. Use ROT_IS_ERROR to check
* the return value.
*/
int (*get_signature_max_length) (const struct ecc_engine *engine,
const struct ecc_private_key *key);
#ifdef ECC_ENABLE_GENERATE_KEY_PAIR
/**
* Encode an ECC private key in DER format.
*
* @param engine The ECC engine used to generate the key.
* @param key The private key to encode to DER.
* @param der Output buffer for the DER encoded private key. This is a dynamically allocated
* buffer, and it is the responsibility of the caller to free it. This will return null in the
* case of an error. Some implementations only provide oracle access to private keys. In these
* cases, the DER encoded data will not be an ECC private key, but rather an encoded identifier
* for the private key. This type of encoded data is not portable across implementations, but
* can be used to load keys in different instances of the same type.
* @param length Output for the length of the DER key.
*
* @return 0 if the key was successfully encoded or an error code.
*/
int (*get_private_key_der) (const struct ecc_engine *engine, const struct ecc_private_key *key,
uint8_t **der, size_t *length);
/**
* Encode an ECC public key in DER format.
*
* @param engine The ECC engine used to generate the key.
* @param key The public key to encode to DER.
* @param der Output buffer for the DER encoded public key. This is a dynamically allocated
* buffer, and it is the responsibility of the caller to free it. This will return null in the
* case of an error.
* @param length Output for the length of the DER key.
*
* @return 0 if the key was successfully encoded or an error code.
*/
int (*get_public_key_der) (const struct ecc_engine *engine, const struct ecc_public_key *key,
uint8_t **der, size_t *length);
#endif
/**
* Create an ECDSA signature for a SHA2 digest.
*
* @param engine The ECC engine to use to sign the digest.
* @param key The private key to sign with.
* @param digest The digest to use to generate the signature.
* @param length The length of the digest.
* @param rng An optional random number generator to use for generating the random 'r' value in
* the signature. If this is null, the ECC instance will use an internally managed RNG for this
* operation.
* @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 (*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);
/**
* Verify an ECDSA signature against a SHA2 digest.
*
* @param engine The ECC engine to use for signature verification.
* @param key The public key to verify the signature with.
* @param digest The digest to use for signature verification.
* @param length The length of the digest.
* @param signature The ECDSA signature to verify. The signature must be DER encoded. As long
* as the encoded length is correct, the buffer can be padded with extra data and not cause a
* verification failure.
* @param sig_length The length of the signature.
*
* @return 0 if the signature matches the digest or an error code.
*/
int (*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);
#ifdef ECC_ENABLE_ECDH
/**
* Get the maximum length for an ECDH shared secret generated using a given key.
*
* @param engine The ECC engine to query.
* @param key The private key that would be used to generate the secret.
*
* @return The maximum number of bytes in the secret or an error code. Use ROT_IS_ERROR to
* check the return value.
*/
int (*get_shared_secret_max_length) (const struct ecc_engine *engine,
const struct ecc_private_key *key);
/**
* Generate the ECDH shared secret for a pair of keys.
*
* @param engine The ECC engine to use to generate the secret.
* @param priv_key The private key to use to generate the secret.
* @param pub_key The public key to use to generate the secret.
* @param secret Output buffer to hold the generated secret. This is the raw data generated by
* ECDH which can be fed into additional key derivation functions, as appropriate.
* @param length The length of the secret buffer.
*
* @return The length of the shared secret or an error code. Use ROT_IS_ERROR to check the
* return value.
*/
int (*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);
#endif
};
#define ECC_ENGINE_ERROR(code) ROT_ERROR (ROT_MODULE_ECC_ENGINE, code)
/**
* Error codes that can be generated by an ECC engine.
*/
enum {
ECC_ENGINE_INVALID_ARGUMENT = ECC_ENGINE_ERROR (0x00), /**< Input parameter is null or not valid. */
ECC_ENGINE_NO_MEMORY = ECC_ENGINE_ERROR (0x01), /**< Memory allocation failed. */
ECC_ENGINE_KEY_PAIR_FAILED = ECC_ENGINE_ERROR (0x02), /**< Failed to initialize a key pair from DER data. */
ECC_ENGINE_PUBLIC_KEY_FAILED = ECC_ENGINE_ERROR (0x03), /**< Failed to initialize a public key from DER data. */
ECC_ENGINE_DERIVED_KEY_FAILED = ECC_ENGINE_ERROR (0x04), /**< Failed to generate a deterministic key pair. */
ECC_ENGINE_GENERATE_KEY_FAILED = ECC_ENGINE_ERROR (0x05), /**< Failed to generate a random key pair. */
ECC_ENGINE_PRIVATE_KEY_DER_FAILED = ECC_ENGINE_ERROR (0x06), /**< The private key was not encoded to DER. */
ECC_ENGINE_PUBLIC_KEY_DER_FAILED = ECC_ENGINE_ERROR (0x07), /**< The public key was not encoded to DER. */
ECC_ENGINE_SIGN_FAILED = ECC_ENGINE_ERROR (0x08), /**< The ECDSA signature was not generated. */
ECC_ENGINE_VERIFY_FAILED = ECC_ENGINE_ERROR (0x09), /**< A error unrelated to signature checking caused verification to fail. */
ECC_ENGINE_SHARED_SECRET_FAILED = ECC_ENGINE_ERROR (0x0a), /**< The ECDH secret was not generated. */
ECC_ENGINE_NOT_EC_KEY = ECC_ENGINE_ERROR (0x0b), /**< Key data does not contain an EC key. */
ECC_ENGINE_NOT_PRIVATE_KEY = ECC_ENGINE_ERROR (0x0c), /**< The key is not a private key. */
ECC_ENGINE_NOT_PUBLIC_KEY = ECC_ENGINE_ERROR (0x0d), /**< The key is not a public key. */
ECC_ENGINE_SIG_BUFFER_TOO_SMALL = ECC_ENGINE_ERROR (0x0e), /**< There is not enough buffer space to store the signature. */
ECC_ENGINE_SECRET_BUFFER_TOO_SMALL = ECC_ENGINE_ERROR (0x0f), /**< There is not enough buffer space to store the ECDH secret. */
ECC_ENGINE_BAD_SIGNATURE = ECC_ENGINE_ERROR (0x10), /**< ECDSA signature verification failed. */
ECC_ENGINE_HW_NOT_INIT = ECC_ENGINE_ERROR (0x11), /**< The ECC hardware has not been initialized. */
ECC_ENGINE_SIG_LENGTH_FAILED = ECC_ENGINE_ERROR (0x12), /**< Failed to get the maximum signature length. */
ECC_ENGINE_SECRET_LENGTH_FAILED = ECC_ENGINE_ERROR (0x13), /**< Failed to get the maximum shared secret length. */
ECC_ENGINE_UNSUPPORTED_KEY_LENGTH = ECC_ENGINE_ERROR (0x14), /**< The ECC key length is not supported by the implementation. */
ECC_ENGINE_UNSUPPORTED_HASH_TYPE = ECC_ENGINE_ERROR (0x15), /**< The hash algorithm for a signature digest is not supported by the implementation. */
ECC_ENGINE_SELF_TEST_FAILED = ECC_ENGINE_ERROR (0x16), /**< An internal self-test of the ECC engine failed. */
ECC_ENGINE_UNSUPPORTED_OPERATION = ECC_ENGINE_ERROR (0x17), /**< The requested operation is not supported by the implementation. */
ECC_ENGINE_INCOMPATIBLE_DIGEST = ECC_ENGINE_ERROR (0x18), /**< The specified digest cannot be used for a signing operation. */
};
#endif /* ECC_H_ */