key/aziot-keys/aziot-keys.h (156 lines of code) (raw):

/** * Copyright (c) Microsoft. All rights reserved. * * This header specifies the API used for libaziot-keys. This library is used to create and load keys by the Azure IoT Keys Service. * * * # API conventions * * All functions return an `unsigned int` to indicate success or failure. See the [`AZIOT_KEYS_RC`] type's docs for details about these constants. * * The only function exported by this library is [`aziot_keys_get_function_list`]. Call this function to get the version of the API * that this library exports, as well as the function pointers to the key operations. See its docs for more details. * * All calls to [`aziot_keys_get_function_list`] or any function in [`AZIOT_KEYS_FUNCTION_LIST`] are serialized, ie a function will not be called * while another function is running. However, it is not guaranteed that all function calls will be made from the same operating system thread. * Thus, implementations do not need to worry about locking to prevent concurrent access, but should also not store data in thread-local storage. */ #include <stdint.h> /** * Return code of a function. This is a transparent wrapper around a `std::os::raw::c_uint` (`unsigned int`). * * One of the `AZIOT_KEYS_RC_ERR_*` constants. */ typedef unsigned int AZIOT_KEYS_RC; /** * Represents the version of the API exported by this library. */ typedef unsigned int AZIOT_KEYS_VERSION; /** * The base struct of all of function lists. */ typedef struct AZIOT_KEYS_FUNCTION_LIST { /** * The version of the API represented in this function list. * * The specific subtype of `AZIOT_KEYS_FUNCTION_LIST` can be determined by inspecting this value. */ AZIOT_KEYS_VERSION version; } AZIOT_KEYS_FUNCTION_LIST; /** * The mechanism used with `sign` / `verify`. * * One of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. */ typedef unsigned int AZIOT_KEYS_SIGN_MECHANISM; /** * Used with `sign` / `verify` with the [`AZIOT_KEYS_SIGN_MECHANISM_DERIVED`] mechanism. */ typedef struct AZIOT_KEYS_SIGN_DERIVED_PARAMETERS { /** * The data used to derive the new key. */ const unsigned char *derivation_data; /** * The length of the `derivation_data` buffer. */ uintptr_t derivation_data_len; /** * The signature mechanism to use with the derived key. * * One of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. */ AZIOT_KEYS_SIGN_MECHANISM mechanism; /** * The parameters of the signature mechanism specified by `mechanism`. */ const void *parameters; } AZIOT_KEYS_SIGN_DERIVED_PARAMETERS; /** * Used with `encrypt` / `decrypt` with the [`AZIOT_KEYS_ENCRYPT_MECHANISM_AEAD`] mechanism. */ typedef struct AZIOT_KEYS_ENCRYPT_AEAD_PARAMETERS { /** * The IV. */ const unsigned char *iv; /** * The length of the `iv` buffer. */ uintptr_t iv_len; /** * The AAD. */ const unsigned char *aad; /** * The length of the `aad` buffer. */ uintptr_t aad_len; } AZIOT_KEYS_ENCRYPT_AEAD_PARAMETERS; /** * The mechanism used with `encrypt` / `decrypt`. * * One of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. */ typedef unsigned int AZIOT_KEYS_ENCRYPT_MECHANISM; /** * Used with `encrypt` / `decrypt` with the [`AZIOT_KEYS_ENCRYPT_MECHANISM_DERIVED`] mechanism. */ typedef struct AZIOT_KEYS_ENCRYPT_DERIVED_PARAMETERS { /** * The data used to derive the new key. */ const unsigned char *derivation_data; /** * The length of the `derivation_data` buffer. */ uintptr_t derivation_data_len; /** * The encryption mechanism to use with the derived key. * * One of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. */ AZIOT_KEYS_ENCRYPT_MECHANISM mechanism; /** * The parameters of the encryption mechanism specified by `mechanism`. */ const void *parameters; } AZIOT_KEYS_ENCRYPT_DERIVED_PARAMETERS; /** * Used as the parameter type with `get_key_pair_parameter`. * * One of the `AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_*` constants. */ typedef unsigned int AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE; /** * The usage of key being created with `create_key_if_not_exists` or * being imported with `import_key`. * * This is a bitflag type, so its values can be combined. But note that not all combinations of flags * are valid. */ typedef unsigned int AZIOT_KEYS_KEY_USAGE; /** * The specific implementation of [`AZIOT_KEYS_FUNCTION_LIST`] for API version 2.0.0.0 */ typedef struct AZIOT_KEYS_FUNCTION_LIST_2_0_0_0 { /** * The value of `base.version` must be [`AZIOT_KEYS_VERSION_2_0_0_0`]. */ struct AZIOT_KEYS_FUNCTION_LIST base; /** * Set a parameter on this library. * * `name` must not be `NULL`. * `value` may be `NULL`. * * The caller may free the name string after this method returns. If the implementation needs to hold on to it, it must make a copy. * * The interpretation of names and values depends on the implementation. A special case is for names that start with `preloaded_key:`, * such as `preloaded_key:foo`. This defines a user-provided association of the key ID "foo" with the location specified by `value`. * Any call that uses the key with ID "foo" must use the location specified by `value`. Note that this does not mean the key already exists * at that location; but it does mean that `create_key_if_not_exists` (for example) must create the key at that location and not any other. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `name` is `NULL`. * - `name` is not recognized by this implementation, or invalid in some other way. * - `value` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*set_parameter)(const char *name, const char *value); /** * Create or load a key pair identified by the specified `id`. * * - If a key pair with that ID exists and can be loaded, it will be left as-is. * - If a key pair with that ID does not exist, a new key will be created. It will be saved such that it can be looked up later using that same ID. * * `preferred_algorithms` dictates the caller's preference for the key algorithm. It is a string with components separated by COLON U+003A `:`, * where each component specifies the name of an algorithm and will be attempted by the implementation in that order. * The valid components are `"ec-p256"` for secp256r1, `"rsa-2048"` for 2048-bit RSA, `"rsa-4096"` for 4096-bit RSA, and `"*"` which indicates * any algorithm of the implementation's choice. For example, the caller might use `"ec-p256:rsa-2048:*"` to indicate that it would like * the implementation to use secp256r1, else RSA-2048 if that fails, else any other algorithm of the implementation's choice if that also fails. * * If an implementation does not recognize a particular component as an algorithm, or is unable to use the algorithm to generate a key pair, * it must ignore that component and try the next one. If no components are left, the implementation returns an error. * The implementation is allowed to be unable to generate a key pair regardless of which algorithms are specified; this is true even if * the wildcard algorithm is specified. * * If `preferred_algorithms` is `NULL`, it must be interpreted the same as if it was `"*"`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - `preferred_algorithms` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*create_key_pair_if_not_exists)(const char *id, const char *preferred_algorithms); /** * Load an existing key pair identified by the specified `id`. * * This validates that a key pair with the given ID exists and can be loaded. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*load_key_pair)(const char *id); /** * Get the value of a parameter of the key pair identified by the specified `id`. * * `type_` must be set to one of the `AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_*` constants. * * `value` is an output byte buffer allocated by the caller to store the parameter value. * The caller sets `value_len` to the address of the length of the buffer. * The implementation populates `value` with the parameter value and sets `value_len` to the number of bytes it wrote to `value`. * * It is allowed for the caller to call the function with `value` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the parameter value, sets that in `value_len` and returns. * * The format of the data stored in `value` is determined by the `type_`. See the documentation of those constants for details. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key pair specified by `id` does not exist. * - `type_` is not a valid parameter type for the key pair specified by `id`. * - `value` is insufficiently large to hold the parameter value. * - `value_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*get_key_pair_parameter)(const char *id, AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE type_, unsigned char *value, uintptr_t *value_len); /** * Create or load a key identified by the specified `id`. * * - If a key with that ID exists and can be loaded, it will be left as-is. * - If a key with that ID does not exist, a new random key will be created. * It will be saved such that it can be looked up later using that same ID. * * `usage` specifies what the key will be used for. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*create_key_if_not_exists)(const char *id, AZIOT_KEYS_KEY_USAGE usage); /** * Load an existing key identified by the specified `id`. * * This validates that a key with the given ID exists and can be loaded. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key specified by `id` does not exist. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*load_key)(const char *id); /** * Import a symmetric key with the given `id`. * * It will be saved such that it can be looked up later using that same ID. * * If a key with that ID already exists, the existing key will be overwritten. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - `bytes` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*import_key)(const char *id, const uint8_t *bytes, uintptr_t bytes_len, AZIOT_KEYS_KEY_USAGE usage); /** * Derive a key with a given base key using some derivation data, and return the derived key. * * The derivation process used by this function must be identical to * the derivation process used by `encrypt` with the `AZIOT_KEYS_ENCRYPT_MECHANISM_DERIVED` mechanism and * the derivation process used by `sign` with the `AZIOT_KEYS_SIGN_MECHANISM_DERIVED` mechanism. * * `base_id` is the ID of the key that will be used to derive the new key. The key must have been created / imported * with the [`crate::AZIOT_KEYS_KEY_USAGE_DERIVE`] usage. * * `derivation_data` is a byte buffer containing the data that used for the derivation. * The caller sets `derivation_data_len` to the length of the buffer. * * `derived_key` is an output byte buffer allocated by the caller to store the derived key. * The caller sets `derived_key_len` to the address of the length of the buffer. * The implementation populates `derived_key` with the parameter derived_key and sets `derived_key_len` to the number of bytes it wrote to `derived_key`. * * It is allowed for the caller to call the function with `derived_key` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the derived key, sets that in `derived_key_len` and returns. * * The new key is not persisted by the implementation, only returned in `derived_key`. * If the caller wishes to persist it, they can import it with `import_key`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `base_id` is `NULL`. * - `base_id` is invalid. * - The key specified by `base_id` does not exist. * - `derivation_data` is `NULL`. * - `derived_key` is insufficiently large to hold the parameter value. * - `derived_key_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*derive_key)(const char *base_id, const uint8_t *derivation_data, uintptr_t derivation_data_len, unsigned char *derived_key, uintptr_t *derived_key_len); /** * Sign the given digest using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `digest` is a byte buffer containing the data that must be signed. * The caller sets `digest_len` to the length of the buffer. * * `signature` is an output byte buffer allocated by the caller to store the signature. * The caller sets `signature_len` to the address of the length of the buffer. * The implementation populates `signature` with the signature and sets `signature_len` to the number of bytes it wrote to `signature`. * * It is allowed for the caller to call the function with `signature` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the signature, sets that in `signature_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid signature mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `digest` is `NULL`. * - `signature` is insufficiently large to hold the signature. * - `signature_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*sign)(const char *id, AZIOT_KEYS_SIGN_MECHANISM mechanism, const void *parameters, const unsigned char *digest, uintptr_t digest_len, unsigned char *signature, uintptr_t *signature_len); /** * Verify the signature of the given digest using the key or key pair (but see note below) identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `digest` is a byte buffer containing the data that must be signed. * The caller sets `digest_len` to the length of the buffer. * * `signature` is a byte buffer containing the signature that the caller expects the data to have. * The caller sets `signature_len` to the length of the buffer. * * `ok` is an output parameter that stores whether the signature could be verified or not. * If the function is able to compute the signature of the data, it sets `ok` and returns `AZIOT_KEYS_RC_OK`. * `ok` is set to 0 if the signature is invalid and non-zero if the signature is valid. * The value stored in `ok` is only meaningful if the function returns `AZIOT_KEYS_RC_OK`, otherwise it must be ignored. * * Note: The implementation is not required to support verification with key pairs, ie `AZIOT_KEYS_SIGN_MECHANISM_ECDSA`. * The caller can do the verification themselves with the public parameters of the EC key as obtained via `get_key_pair_parameter`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid signature mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `digest` is `NULL`. * - `signature` is `NULL`. * - `ok` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*verify)(const char *id, AZIOT_KEYS_SIGN_MECHANISM mechanism, const void *parameters, const unsigned char *digest, uintptr_t digest_len, const unsigned char *signature, uintptr_t signature_len, int *ok); /** * Encrypt the given plaintext using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `plaintext` is a byte buffer containing the data that must be encrypted. * The caller sets `plaintext_len` to the length of the buffer. * * `ciphertext` is an output byte buffer allocated by the caller to store the encrypted data. * The caller sets `ciphertext_len` to the address of the length of the buffer. * The implementation populates `ciphertext` with the ciphertext and sets `ciphertext_len` to the number of bytes it wrote to `ciphertext`. * * It is allowed for the caller to call the function with `ciphertext` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the ciphertext, sets that in `ciphertext_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid encryption mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `plaintext` is `NULL`. * - `ciphertext` is insufficiently large to hold the ciphertext. * - `ciphertext_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*encrypt)(const char *id, AZIOT_KEYS_ENCRYPT_MECHANISM mechanism, const void *parameters, const unsigned char *plaintext, uintptr_t plaintext_len, unsigned char *ciphertext, uintptr_t *ciphertext_len); /** * Decrypt the given plaintext using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `ciphertext` is a byte buffer containing the data that must be signed. * The caller sets `ciphertext_len` to the length of the buffer. * * `plaintext` is an output byte buffer allocated by the caller to store the decrypted data. * The caller sets `plaintext_len` to the address of the length of the buffer. * The implementation populates `plaintext` with the plaintext and sets `plaintext_len` to the number of bytes it wrote to `plaintext`. * * It is allowed for the caller to call the function with `plaintext` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the plaintext, sets that in `plaintext_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid encryption mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `ciphertext` is `NULL`. * - `plaintext` is insufficiently large to hold the ciphertext. * - `plaintext_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*decrypt)(const char *id, AZIOT_KEYS_ENCRYPT_MECHANISM mechanism, const void *parameters, const unsigned char *ciphertext, uintptr_t ciphertext_len, unsigned char *plaintext, uintptr_t *plaintext_len); } AZIOT_KEYS_FUNCTION_LIST_2_0_0_0; /** * The specific implementation of [`AZIOT_KEYS_FUNCTION_LIST`] for API version 2.1.0.0 */ typedef struct AZIOT_KEYS_FUNCTION_LIST_2_1_0_0 { /** * The value of `base.version` must be [`AZIOT_KEYS_VERSION_2_1_0_0`]. */ struct AZIOT_KEYS_FUNCTION_LIST base; /** * Set a parameter on this library. * * `name` must not be `NULL`. * `value` may be `NULL`. * * The caller may free the name string after this method returns. If the implementation needs to hold on to it, it must make a copy. * * The interpretation of names and values depends on the implementation. A special case is for names that start with `preloaded_key:`, * such as `preloaded_key:foo`. This defines a user-provided association of the key ID "foo" with the location specified by `value`. * Any call that uses the key with ID "foo" must use the location specified by `value`. Note that this does not mean the key already exists * at that location; but it does mean that `create_key_if_not_exists` (for example) must create the key at that location and not any other. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `name` is `NULL`. * - `name` is not recognized by this implementation, or invalid in some other way. * - `value` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*set_parameter)(const char *name, const char *value); /** * Create or load a key pair identified by the specified `id`. * * - If a key pair with that ID exists and can be loaded, it will be left as-is. * - If a key pair with that ID does not exist, a new key will be created. It will be saved such that it can be looked up later using that same ID. * * `preferred_algorithms` dictates the caller's preference for the key algorithm. It is a string with components separated by COLON U+003A `:`, * where each component specifies the name of an algorithm and will be attempted by the implementation in that order. * The valid components are `"ec-p256"` for secp256r1, `"rsa-2048"` for 2048-bit RSA, `"rsa-4096"` for 4096-bit RSA, and `"*"` which indicates * any algorithm of the implementation's choice. For example, the caller might use `"ec-p256:rsa-2048:*"` to indicate that it would like * the implementation to use secp256r1, else RSA-2048 if that fails, else any other algorithm of the implementation's choice if that also fails. * * If an implementation does not recognize a particular component as an algorithm, or is unable to use the algorithm to generate a key pair, * it must ignore that component and try the next one. If no components are left, the implementation returns an error. * The implementation is allowed to be unable to generate a key pair regardless of which algorithms are specified; this is true even if * the wildcard algorithm is specified. * * If `preferred_algorithms` is `NULL`, it must be interpreted the same as if it was `"*"`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - `preferred_algorithms` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*create_key_pair_if_not_exists)(const char *id, const char *preferred_algorithms); /** * Move an existing key pair to another `id`. * * This function replaces any existing key and the destination `id`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - either `from` or `to` is `NULL`. * - either `from` or `to` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*move_key_pair)(const char *from, const char *to); /** * Load an existing key pair identified by the specified `id`. * * This validates that a key pair with the given ID exists and can be loaded. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*load_key_pair)(const char *id); /** * Get the value of a parameter of the key pair identified by the specified `id`. * * `type_` must be set to one of the `AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_*` constants. * * `value` is an output byte buffer allocated by the caller to store the parameter value. * The caller sets `value_len` to the address of the length of the buffer. * The implementation populates `value` with the parameter value and sets `value_len` to the number of bytes it wrote to `value`. * * It is allowed for the caller to call the function with `value` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the parameter value, sets that in `value_len` and returns. * * The format of the data stored in `value` is determined by the `type_`. See the documentation of those constants for details. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key pair specified by `id` does not exist. * - `type_` is not a valid parameter type for the key pair specified by `id`. * - `value` is insufficiently large to hold the parameter value. * - `value_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*get_key_pair_parameter)(const char *id, AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE type_, unsigned char *value, uintptr_t *value_len); /** * Delete an existing key pair identified by the specified `id`. * * This function succeeds if a key with the specified ID doesn't already exist. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*delete_key_pair)(const char *id); /** * Create or load a key identified by the specified `id`. * * - If a key with that ID exists and can be loaded, it will be left as-is. * - If a key with that ID does not exist, a new random key will be created. * It will be saved such that it can be looked up later using that same ID. * * `usage` specifies what the key will be used for. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*create_key_if_not_exists)(const char *id, AZIOT_KEYS_KEY_USAGE usage); /** * Load an existing key identified by the specified `id`. * * This validates that a key with the given ID exists and can be loaded. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key specified by `id` does not exist. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*load_key)(const char *id); /** * Import a symmetric key with the given `id`. * * It will be saved such that it can be looked up later using that same ID. * * If a key with that ID already exists, the existing key will be overwritten. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - `bytes` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*import_key)(const char *id, const uint8_t *bytes, uintptr_t bytes_len, AZIOT_KEYS_KEY_USAGE usage); /** * Delete an existing key identified by the specified `id`. * * This function succeeds if a key with the specified ID doesn't already exist. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*delete_key)(const char *id); /** * Derive a key with a given base key using some derivation data, and return the derived key. * * The derivation process used by this function must be identical to * the derivation process used by `encrypt` with the `AZIOT_KEYS_ENCRYPT_MECHANISM_DERIVED` mechanism and * the derivation process used by `sign` with the `AZIOT_KEYS_SIGN_MECHANISM_DERIVED` mechanism. * * `base_id` is the ID of the key that will be used to derive the new key. The key must have been created / imported * with the [`crate::AZIOT_KEYS_KEY_USAGE_DERIVE`] usage. * * `derivation_data` is a byte buffer containing the data that used for the derivation. * The caller sets `derivation_data_len` to the length of the buffer. * * `derived_key` is an output byte buffer allocated by the caller to store the derived key. * The caller sets `derived_key_len` to the address of the length of the buffer. * The implementation populates `derived_key` with the parameter derived_key and sets `derived_key_len` to the number of bytes it wrote to `derived_key`. * * It is allowed for the caller to call the function with `derived_key` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the derived key, sets that in `derived_key_len` and returns. * * The new key is not persisted by the implementation, only returned in `derived_key`. * If the caller wishes to persist it, they can import it with `import_key`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `base_id` is `NULL`. * - `base_id` is invalid. * - The key specified by `base_id` does not exist. * - `derivation_data` is `NULL`. * - `derived_key` is insufficiently large to hold the parameter value. * - `derived_key_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*derive_key)(const char *base_id, const uint8_t *derivation_data, uintptr_t derivation_data_len, unsigned char *derived_key, uintptr_t *derived_key_len); /** * Sign the given digest using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `digest` is a byte buffer containing the data that must be signed. * The caller sets `digest_len` to the length of the buffer. * * `signature` is an output byte buffer allocated by the caller to store the signature. * The caller sets `signature_len` to the address of the length of the buffer. * The implementation populates `signature` with the signature and sets `signature_len` to the number of bytes it wrote to `signature`. * * It is allowed for the caller to call the function with `signature` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the signature, sets that in `signature_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid signature mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `digest` is `NULL`. * - `signature` is insufficiently large to hold the signature. * - `signature_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*sign)(const char *id, AZIOT_KEYS_SIGN_MECHANISM mechanism, const void *parameters, const unsigned char *digest, uintptr_t digest_len, unsigned char *signature, uintptr_t *signature_len); /** * Verify the signature of the given digest using the key or key pair (but see note below) identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_SIGN_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `digest` is a byte buffer containing the data that must be signed. * The caller sets `digest_len` to the length of the buffer. * * `signature` is a byte buffer containing the signature that the caller expects the data to have. * The caller sets `signature_len` to the length of the buffer. * * `ok` is an output parameter that stores whether the signature could be verified or not. * If the function is able to compute the signature of the data, it sets `ok` and returns `AZIOT_KEYS_RC_OK`. * `ok` is set to 0 if the signature is invalid and non-zero if the signature is valid. * The value stored in `ok` is only meaningful if the function returns `AZIOT_KEYS_RC_OK`, otherwise it must be ignored. * * Note: The implementation is not required to support verification with key pairs, ie `AZIOT_KEYS_SIGN_MECHANISM_ECDSA`. * The caller can do the verification themselves with the public parameters of the EC key as obtained via `get_key_pair_parameter`. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid signature mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `digest` is `NULL`. * - `signature` is `NULL`. * - `ok` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*verify)(const char *id, AZIOT_KEYS_SIGN_MECHANISM mechanism, const void *parameters, const unsigned char *digest, uintptr_t digest_len, const unsigned char *signature, uintptr_t signature_len, int *ok); /** * Encrypt the given plaintext using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `plaintext` is a byte buffer containing the data that must be encrypted. * The caller sets `plaintext_len` to the length of the buffer. * * `ciphertext` is an output byte buffer allocated by the caller to store the encrypted data. * The caller sets `ciphertext_len` to the address of the length of the buffer. * The implementation populates `ciphertext` with the ciphertext and sets `ciphertext_len` to the number of bytes it wrote to `ciphertext`. * * It is allowed for the caller to call the function with `ciphertext` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the ciphertext, sets that in `ciphertext_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid encryption mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `plaintext` is `NULL`. * - `ciphertext` is insufficiently large to hold the ciphertext. * - `ciphertext_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*encrypt)(const char *id, AZIOT_KEYS_ENCRYPT_MECHANISM mechanism, const void *parameters, const unsigned char *plaintext, uintptr_t plaintext_len, unsigned char *ciphertext, uintptr_t *ciphertext_len); /** * Decrypt the given plaintext using the key or key pair identified by the specified `id`. * * `mechanism` must be set to one of the `AZIOT_KEYS_ENCRYPT_MECHANISM_*` constants. * `parameters` must be set according to the `mechanism`, as documented on the constants. * * `ciphertext` is a byte buffer containing the data that must be signed. * The caller sets `ciphertext_len` to the length of the buffer. * * `plaintext` is an output byte buffer allocated by the caller to store the decrypted data. * The caller sets `plaintext_len` to the address of the length of the buffer. * The implementation populates `plaintext` with the plaintext and sets `plaintext_len` to the number of bytes it wrote to `plaintext`. * * It is allowed for the caller to call the function with `plaintext` set to `NULL`. In this case the implementation calculates * an upper bound for how many bytes will be needed to store the plaintext, sets that in `plaintext_len` and returns. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `id` is `NULL`. * - `id` is invalid. * - The key or key pair specified by `id` does not exist. * - `mechanism` is not a valid encryption mechanism for the key or key pair specified by `id`. * - `parameters` is invalid. * - `ciphertext` is `NULL`. * - `plaintext` is insufficiently large to hold the ciphertext. * - `plaintext_len` is `NULL`. * * - `AZIOT_KEYS_RC_ERR_EXTERNAL` */ AZIOT_KEYS_RC (*decrypt)(const char *id, AZIOT_KEYS_ENCRYPT_MECHANISM mechanism, const void *parameters, const unsigned char *ciphertext, uintptr_t ciphertext_len, unsigned char *plaintext, uintptr_t *plaintext_len); } AZIOT_KEYS_FUNCTION_LIST_2_1_0_0; /** * The algorithm of a key pair, as returned by `get_key_pair_parameter`. * * One of the `AZIOT_KEYS_KEY_PAIR_PARAMETER_ALGORITHM_*` constants. */ typedef unsigned int AZIOT_KEYS_KEY_PAIR_PARAMETER_ALGORITHM; /** * The operation succeeded. */ #define AZIOT_KEYS_RC_OK 0 /** * The operation failed because a parameter has an invalid value. */ #define AZIOT_KEYS_RC_ERR_INVALID_PARAMETER 1 /** * The library encountered an error with an external resource, such as an I/O error or RPC error. */ #define AZIOT_KEYS_RC_ERR_EXTERNAL 2 /** * Used as the parameter type with `get_key_pair_parameter` to get the key algorithm. * * The value returned by `get_key_pair_parameter` will be one of the `AZIOT_KEYS_KEY_PAIR_PARAMETER_ALGORITHM_*` constants. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_ALGORITHM 1 /** * Used as the parameter type with `get_key_pair_parameter` to get the curve OID of an EC key. * * The value returned by `get_key_pair_parameter` will be a byte buffer containing a DER-encoded OID. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_EC_CURVE_OID 2 /** * Used as the parameter type with `get_key_pair_parameter` to get the point of an EC key. * * The value returned by `get_key_pair_parameter` will be a byte buffer containing a DER-encoded octet string in RFC 5490 format. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_EC_POINT 3 /** * Used as the parameter type with `get_key_pair_parameter` to get the modulus of an RSA key. * * The value returned by `get_key_pair_parameter` will be a byte buffer holding a big-endian bignum. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_RSA_MODULUS 4 /** * Used as the parameter type with `get_key_pair_parameter` to get the exponent of an RSA key. * * The value returned by `get_key_pair_parameter` will be a byte buffer holding a big-endian bignum. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_TYPE_RSA_EXPONENT 5 /** * The key pair is an EC key. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_ALGORITHM_EC 1 /** * The key pair is an RSA key. */ #define AZIOT_KEYS_KEY_PAIR_PARAMETER_ALGORITHM_RSA 2 /** * The key can be used for deriving other keys. * * Cannot be combined with [`AZIOT_KEYS_KEY_USAGE_ENCRYPT`] */ #define AZIOT_KEYS_KEY_USAGE_DERIVE 1 /** * The key can be used for encryption. * * Cannot be combined with [`AZIOT_KEYS_KEY_USAGE_DERIVE`] or [`AZIOT_KEYS_KEY_USAGE_SIGN`] */ #define AZIOT_KEYS_KEY_USAGE_ENCRYPT 16 /** * The key can be used for signing. * * Cannot be combined with [`AZIOT_KEYS_KEY_USAGE_ENCRYPT`] */ #define AZIOT_KEYS_KEY_USAGE_SIGN AZIOT_KEYS_KEY_USAGE_DERIVE /** * Used with `sign` / `verify` to sign / verify using ECDSA. * * The `parameters` parameter of `sign` / `verify` is unused and ignored. */ #define AZIOT_KEYS_SIGN_MECHANISM_ECDSA 1 /** * Used with `sign` / `verify` to sign / verify using HMAC-SHA256. * * The `parameters` parameter of `sign` / `verify` is unused and ignored. */ #define AZIOT_KEYS_SIGN_MECHANISM_HMAC_SHA256 2 /** * Used with `sign` / `verify` to sign / verify using a derived key. * * The `id` parameter of `sign` / `verify` is set to the ID of the base key. * The `parameters` parameter of `sign` / `verify` must be set to an `AZIOT_KEYS_SIGN_DERIVED_PARAMETERS` value. */ #define AZIOT_KEYS_SIGN_MECHANISM_DERIVED 3 /** * Used with `encrypt` / `decrypt` to encrypt / decrypt using an AEAD mechanism, like AES-GCM. * * The exact AEAD algorithm used is left to the implementation and need not always be the same. * The caller must not make any assumptions about the format of the ciphertext. * * The `parameters` parameter of `encrypt` / `decrypt` must be set to an `AZIOT_KEYS_ENCRYPT_AEAD_PARAMETERS` value. */ #define AZIOT_KEYS_ENCRYPT_MECHANISM_AEAD 1 /** * Used with `encrypt` / `decrypt` to encrypt / decrypt using RSA with PKCS1 padding. * * The `parameters` parameter of `encrypt` / `decrypt` is unused and ignored. */ #define AZIOT_KEYS_ENCRYPT_MECHANISM_RSA_PKCS1 2 /** * Used with `encrypt` / `decrypt` to encrypt / decrypt using RSA with no padding. Padding will have been performed by the caller. * * The `parameters` parameter of `encrypt` / `decrypt` is unused and ignored. */ #define AZIOT_KEYS_ENCRYPT_MECHANISM_RSA_NO_PADDING 3 /** * Used with `encrypt` / `decrypt` to encrypt / decrypt using a derived key. * * The `id` parameter of `encrypt` / `decrypt` is set to the ID of the base key. * The `parameters` parameter of `encrypt` / `decrypt` must be set to an `AZIOT_KEYS_ENCRYPT_DERIVED_PARAMETERS` value. */ #define AZIOT_KEYS_ENCRYPT_MECHANISM_DERIVED 4 /** * Version 2.0.0.0 */ #define AZIOT_KEYS_VERSION_2_0_0_0 33554432 /** * Version 2.1.0.0 */ #define AZIOT_KEYS_VERSION_2_1_0_0 33619968 /** * Get the list of functions for operations corresponding to the specified version. * * Implementations can use this function for initialization, since it is guaranteed to be called before any operations. * However it is not an error to call this function multiple times, for the same or different version, * so implementations must ensure they only run their initialization once. * * The pointer returned from this function must not be freed by the caller, and its contents must not be mutated. * * # Errors * * - `AZIOT_KEYS_RC_ERR_INVALID_PARAMETER`: * - `version` is not recognized by this implementation. * - `pfunction_list` is `NULL`. */ AZIOT_KEYS_RC aziot_keys_get_function_list(AZIOT_KEYS_VERSION version, const struct AZIOT_KEYS_FUNCTION_LIST **pfunction_list);