core/manifest/cfm/cfm_manager.c (210 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 "cfm_manager.h" #include "manifest/manifest_logging.h" /** * Add an observer to be notified of CFM management events. An observer can only be added to the * list once. The order in which observers are notified is not guaranteed to be the same as the * order in which they were added. * * @param manager The manager to register with. * @param observer The observer to add. * * @return 0 if the observer was added for notifications or an error code. */ int cfm_manager_add_observer (const struct cfm_manager *manager, const struct cfm_observer *observer) { if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return observable_add_observer (&manager->state->observable, (void*) observer); } /** * Remove an observer so it will no longer be notified of CFM management events. * * @param manager The manager to update. * @param observer The observer to remove. * * @return 0 if the observer was removed from future notifications or an error code. */ int cfm_manager_remove_observer (const struct cfm_manager *manager, const struct cfm_observer *observer) { if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } return observable_remove_observer (&manager->state->observable, (void*) observer); } /** * Initialize the base CFM manager. * * @param manager The manager to initialize. * @param state Variable context for the CFM manager. This must be uninitialized. * @param hash The hash engine to generate measurement data. * * @return 0 if the CFM manager was initialized successfully or an error code. */ int cfm_manager_init (struct cfm_manager *manager, struct cfm_manager_state *state, const struct hash_engine *hash) { int status; memset (manager, 0, sizeof (struct cfm_manager)); status = manifest_manager_init (&manager->base, hash); if (status != 0) { return status; } manager->state = state; return cfm_manager_init_state (manager); } /** * Initialize only the variable state for a base CFM manager. The rest of the manager is assumed to * have already been initialized. * * This would generally be used with a statically initialized instance. * * @param manager The manager that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int cfm_manager_init_state (const struct cfm_manager *manager) { if (manager->state == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } memset (manager->state, 0, sizeof (*manager->state)); return observable_init (&manager->state->observable); } /** * Release the resources used by base CFM manager. * * @param manager The manager to release. */ void cfm_manager_release (const struct cfm_manager *manager) { if (manager) { observable_release (&manager->state->observable); } } /** * Notify all observers of an event for a CFM. The CFM will be released to the manager upon * completion. * * @param manager The manager generating the event. * @param cfm The CFM the event is for. * @param callback_offset The offset in the observer structure for the notification to call. */ static void cfm_manager_notify_observers (const struct cfm_manager *manager, const struct cfm *cfm, size_t callback_offset) { if (!cfm) { /* No CFM so no event notification. */ return; } observable_notify_observers_with_ptr (&manager->state->observable, callback_offset, (void*) cfm); manager->free_cfm (manager, cfm); } /** * Notify observers that a new CFM has been verified and is now pending. * * @param manager The manager generating the event. */ void cfm_manager_on_cfm_verified (const struct cfm_manager *manager) { if (manager == NULL) { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_MANIFEST, MANIFEST_LOGGING_CFM_VERIFIED_EVENT_FAIL, MANIFEST_MANAGER_INVALID_ARGUMENT, 0); return; } cfm_manager_notify_observers (manager, manager->get_pending_cfm (manager), offsetof (struct cfm_observer, on_cfm_verified)); } /** * Notify observers that a new CFM has been activated. * * @param manager The manager generating the event. */ void cfm_manager_on_cfm_activated (const struct cfm_manager *manager) { if (manager == NULL) { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_MANIFEST, MANIFEST_LOGGING_CFM_ACTIVATED_EVENT_FAIL, MANIFEST_MANAGER_INVALID_ARGUMENT, 0); return; } cfm_manager_notify_observers (manager, manager->get_active_cfm (manager), offsetof (struct cfm_observer, on_cfm_activated)); } /** * Notify observers that the active CFM has been cleared. * * @param manager The manager generating the event. */ void cfm_manager_on_clear_active (const struct cfm_manager *manager) { if (manager == NULL) { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_MANIFEST, MANIFEST_LOGGING_CFM_CLEAR_ACTIVE_EVENT_FAIL, MANIFEST_MANAGER_INVALID_ARGUMENT, 0); return; } observable_notify_observers (&manager->state->observable, offsetof (struct cfm_observer, on_clear_active)); } /** * Notify observers that a CFM activation request has been received. * * @param manager The manager generating the event. */ void cfm_manager_on_cfm_activation_request (const struct cfm_manager *manager) { if (manager == NULL) { debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_MANIFEST, MANIFEST_LOGGING_CFM_ACTIVATION_REQUEST_FAIL, MANIFEST_MANAGER_INVALID_ARGUMENT, 0); return; } observable_notify_observers (&manager->state->observable, offsetof (struct cfm_observer, on_cfm_activation_request)); } /** * Get the data used for CFM ID measurement. * * @param manager The CFM manager to query * @param offset The offset to read data from * @param buffer The output buffer to be filled with measured data * @param length Maximum length of the buffer. Updated with actual length * @param total_len Total length of CFM ID measurement * *@return length of the measured data if successfully retrieved or an error code. */ int cfm_manager_get_id_measured_data (const struct cfm_manager *manager, size_t offset, uint8_t *buffer, size_t length, uint32_t *total_len) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_get_id_measured_data (NULL, offset, buffer, length, total_len); } else { status = manifest_manager_get_id_measured_data (&active->base, offset, buffer, length, total_len); manager->free_cfm (manager, active); } return status; } /** * Update a hash context with the data used for the CFM ID measurement. * * @param manager The CFM manager to query. * @param hash Hash engine to update. * * @return 0 if the hash was updated successfully or an error code. */ int cfm_manager_hash_id_measured_data (const struct cfm_manager *manager, const struct hash_engine *hash) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_hash_id_measured_data (NULL, hash); } else { status = manifest_manager_hash_id_measured_data (&active->base, hash); manager->free_cfm (manager, active); } return status; } /** * Get the data used for CFM platform ID measurement. * * @param manager The CFM manager to query * @param offset The offset to read data from * @param buffer The output buffer to be filled with measured data * @param length Maximum length of the buffer * @param total_len Total length of manifest platform ID measurement * * @return Length of the measured data if successfully retrieved or an error code. */ int cfm_manager_get_platform_id_measured_data (const struct cfm_manager *manager, size_t offset, uint8_t *buffer, size_t length, uint32_t *total_len) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_get_platform_id_measured_data (NULL, offset, buffer, length, total_len); } else { status = manifest_manager_get_platform_id_measured_data (&active->base, offset, buffer, length, total_len); manager->free_cfm (manager, active); } return status; } /** * Update a hash context with the data used for the CFM platform ID measurement. * * @param manager The CFM manager to query. * @param hash Hash engine to update. * * @return 0 if the hash was updated successfully or an error code. */ int cfm_manager_hash_platform_id_measured_data (const struct cfm_manager *manager, const struct hash_engine *hash) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_hash_platform_id_measured_data (NULL, hash); } else { status = manifest_manager_hash_platform_id_measured_data (&active->base, hash); manager->free_cfm (manager, active); } return status; } /** * Get the data used for CFM measurement. * * @param manager The CFM manager to query * @param offset The offset to read data from * @param buffer The output buffer to be filled with measured data * @param length Maximum length of the buffer * @param total_len Total length of measured data * * @return Length of the measured data if successfully retrieved or an error code. */ int cfm_manager_get_cfm_measured_data (const struct cfm_manager *manager, size_t offset, uint8_t *buffer, size_t length, uint32_t *total_len) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_get_manifest_measured_data (&manager->base, NULL, offset, buffer, length, total_len); } else { status = manifest_manager_get_manifest_measured_data (&manager->base, &active->base, offset, buffer, length, total_len); manager->free_cfm (manager, active); } return status; } /** * Update a hash context with the data used for the CFM measurement. * * NOTE: When using this function to hash the CFM measurement, it must be guaranteed that the hash * context used by the CFM manager be different from the one passed into this function as an * argument. * * @param manager The CFM manager to query. * @param hash Hash engine to update. This must be different from the hash engine contained in the * CFM manager. * * @return 0 if the hash was updated successfully or an error code. */ int cfm_manager_hash_cfm_measured_data (const struct cfm_manager *manager, const struct hash_engine *hash) { int status; const struct cfm *active; if (manager == NULL) { return MANIFEST_MANAGER_INVALID_ARGUMENT; } active = manager->get_active_cfm (manager); if (active == NULL) { status = manifest_manager_hash_manifest_measured_data (&manager->base, NULL, hash); } else { status = manifest_manager_hash_manifest_measured_data (&manager->base, &active->base, hash); manager->free_cfm (manager, active); } return status; }