core/keystore/ephemeral_key_manager.c (130 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <stdlib.h> #include <string.h> #include "common/type_cast.h" #include "common/unused.h" #include "keystore/ephemeral_key_manager.h" #include "keystore/keystore_logging.h" /** * It will schedule/set the thread execution timeout for the next execution cycle * * @param key_manager The pointer of ephemeral_key_manager. */ static void ephemeral_key_manager_schedule_next_execute ( const struct ephemeral_key_manager *key_manager) { if (platform_init_timeout (key_manager->period_ms, &key_manager->state->next) == 0) { key_manager->state->next_valid = true; } else { key_manager->state->next_valid = false; } } const platform_clock* ephemeral_key_manager_get_next_execution ( const struct periodic_task_handler *handler) { const struct ephemeral_key_manager *key_manager = TO_DERIVED_TYPE (handler, const struct ephemeral_key_manager, base); if (key_manager->state->next_valid) { return &key_manager->state->next; } else { /* Do not wait to call execute again. */ return NULL; } } void ephemeral_key_manager_execute (const struct periodic_task_handler *handler) { const struct ephemeral_key_manager *key_manager = TO_DERIVED_TYPE (handler, const struct ephemeral_key_manager, base); size_t key_length = 0; int status; if (key_manager->key_cache->is_error_state (key_manager->key_cache) == false) { if (key_manager->key_cache->is_initialized (key_manager->key_cache) == false) { status = key_manager->key_cache->initialize_cache (key_manager->key_cache); if (status != 0) { /* Failed to initialize the key cache - Create debug log entry */ debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_KEYSTORE, KEYSTORE_LOGGING_CACHE_INIT_FAIL, status, 0); /* Task should execute after some delay */ ephemeral_key_manager_schedule_next_execute (key_manager); } else { /* Schedule the next execution immediately since a key cache needs to be checked */ key_manager->state->next_valid = false; } } else { if (key_manager->key_cache->is_full (key_manager->key_cache) == false) { /* The cache is not full, so generate a new key pair and add it to the cache. */ status = key_manager->key_gen->generate_key (key_manager->key_gen, key_manager->key_size, key_manager->key, key_manager->key_buf_size, &key_length); if (status == 0) { status = key_manager->key_cache->add (key_manager->key_cache, key_manager->key, key_length); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_KEYSTORE, KEYSTORE_LOGGING_EPHEMERAL_KEY_ADD_FAIL, key_length, status); } } else { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_KEYSTORE, KEYSTORE_LOGGING_EPHEMERAL_KEY_GENERATION_FAIL, key_manager->key_size, status); } /* Schedule the next execution immediately since another key may need to be * generated and stored. */ key_manager->state->next_valid = false; } else { /* The cache is full. Wait some time before executing again. */ ephemeral_key_manager_schedule_next_execute (key_manager); } } } else { /* Task should execute after some delay */ ephemeral_key_manager_schedule_next_execute (key_manager); } } /** * Initialize an instance of the ephemeral key manager object * * @param key_manager Key manager instance to initialize. * @param state Variable context for the key manager. This must be uninitialized. * @param key_cache The key cache to use for storing and retrieving generated key pairs. * @param key_gen A generator for ephemeral key pairs. * @param period_ms The time between task execution cycles while the cache is full. The task will * run without delay while the cache is not full. * @param key_size Length of the private key, in bits, that should be generated. * @param key A pointer to a buffer to use as temporary storage for the generated key pair. * @param key_buf_size Size of the key buffer. * * @return 0 if completed successfully or an error code. */ int ephemeral_key_manager_init (struct ephemeral_key_manager *key_manager, struct ephemeral_key_manager_state *state, const struct key_cache *key_cache, const struct ephemeral_key_generation *key_gen, uint32_t period_ms, size_t key_size, uint8_t *key, size_t key_buf_size) { if ((key_manager == NULL) || (key_cache == NULL) || (key_gen == NULL) || (state == NULL) || (key == NULL)) { return EPHEMERAL_KEY_MANAGER_INVALID_ARGUMENT; } memset (key_manager, 0, sizeof (*key_manager)); key_manager->base.prepare = NULL; key_manager->base.get_next_execution = ephemeral_key_manager_get_next_execution; key_manager->base.execute = ephemeral_key_manager_execute; key_manager->state = state; key_manager->key_cache = key_cache; key_manager->key_gen = key_gen; key_manager->period_ms = period_ms; key_manager->key_size = key_size; key_manager->key = key; key_manager->key_buf_size = key_buf_size; return ephemeral_key_manager_init_state (key_manager); } /** * Initialize the state information for the ephemeral key manager. * * @param key_manager The key manager containing the state to initialize. * * @return 0 if the ephemeral key manager was successfully initialized or an error code. */ int ephemeral_key_manager_init_state (const struct ephemeral_key_manager *key_manager) { if ((key_manager == NULL) || (key_manager->state == NULL) || (key_manager->key_cache == NULL) || (key_manager->key_gen == NULL)) { return EPHEMERAL_KEY_MANAGER_INVALID_ARGUMENT; } memset (key_manager->state, 0, sizeof (struct ephemeral_key_manager_state)); return 0; } /** * Release a key manager instance. * * @param key_manager The key manager to release. */ void ephemeral_key_manager_release (const struct ephemeral_key_manager *key_manager) { UNUSED (key_manager); } /** * Retrieve a pre-generated ephemeral key from the cache for the specified requestor ID. * * @param key_manager The ephemeral key manager to query. * @param requestor_id The ID of the requestor for the key. * @param key Output for the key data. * @param key_buf_size Length of the output key buffer. * @param length Output for the length of the key data. * * @return 0 if the key was successfully retrieved or an error code. */ int ephemeral_key_manager_get_key (const struct ephemeral_key_manager *key_manager, uint16_t requestor_id, uint8_t *key, size_t key_buf_size, size_t *length) { int status; if ((key_manager == NULL) || (key == NULL) || (length == NULL)) { return EPHEMERAL_KEY_MANAGER_INVALID_ARGUMENT; } status = key_manager->key_cache->remove (key_manager->key_cache, requestor_id, key, key_buf_size, length); return status; } /** * Retrieve the ephemeral key for the specified key size supported * * @param key_manager The ephemeral key manager to query. * * @return supported key length */ size_t ephemeral_key_manager_get_key_size (const struct ephemeral_key_manager *key_manager) { if (key_manager == NULL) { return EPHEMERAL_KEY_MANAGER_INVALID_ARGUMENT; } /* Return the key type */ return key_manager->key_size; }