core/cmd_interface/cmd_interface_system.c (372 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <math.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include "cerberus_protocol.h" #include "cerberus_protocol_debug_commands.h" #include "cerberus_protocol_diagnostic_commands.h" #include "cerberus_protocol_master_commands.h" #include "cerberus_protocol_optional_commands.h" #include "cerberus_protocol_required_commands.h" #include "cmd_interface.h" #include "cmd_interface_system.h" #include "cmd_logging.h" #include "common/unused.h" int cmd_interface_system_process_request (const struct cmd_interface *intf, struct cmd_interface_msg *request) { const struct cmd_interface_system *interface = (const struct cmd_interface_system*) intf; uint8_t command_id; uint8_t command_set; int status; status = cmd_interface_process_cerberus_protocol_message (&interface->base, request, &command_id, &command_set, true, true); if (status != 0) { return status; } switch (command_id) { case CERBERUS_PROTOCOL_GET_FW_VERSION: status = cerberus_protocol_get_fw_version (interface->fw_version, request); break; case CERBERUS_PROTOCOL_GET_DIGEST: status = cerberus_protocol_get_certificate_digest (interface->attestation, interface->base.session, request); break; case CERBERUS_PROTOCOL_GET_CERTIFICATE: status = cerberus_protocol_get_certificate (interface->attestation, request); break; case CERBERUS_PROTOCOL_ATTESTATION_CHALLENGE: status = cerberus_protocol_get_challenge_response (interface->attestation, interface->base.session, request); break; case CERBERUS_PROTOCOL_GET_LOG_INFO: status = cerberus_protocol_get_log_info (interface->pcr_store, request); break; case CERBERUS_PROTOCOL_READ_LOG: status = cerberus_protocol_log_read (interface->pcr_store, interface->hash, request); break; case CERBERUS_PROTOCOL_CLEAR_LOG: status = cerberus_protocol_log_clear (interface->background, request); break; case CERBERUS_PROTOCOL_GET_PFM_ID: { const struct pfm_manager *pfm_mgr[2] = { interface->pfm_manager_0, interface->pfm_manager_1 }; status = cerberus_protocol_get_pfm_id (pfm_mgr, 2, request); break; } case CERBERUS_PROTOCOL_GET_PFM_SUPPORTED_FW: { const struct pfm_manager *pfm_mgr[2] = { interface->pfm_manager_0, interface->pfm_manager_1 }; status = cerberus_protocol_get_pfm_fw (pfm_mgr, 2, request); break; } case CERBERUS_PROTOCOL_INIT_PFM_UPDATE: { const struct manifest_cmd_interface *pfm_cmd[2] = {interface->pfm_0, interface->pfm_1}; status = cerberus_protocol_pfm_update_init (pfm_cmd, 2, request); break; } case CERBERUS_PROTOCOL_PFM_UPDATE: { const struct manifest_cmd_interface *pfm_cmd[2] = {interface->pfm_0, interface->pfm_1}; status = cerberus_protocol_pfm_update (pfm_cmd, 2, request); break; } case CERBERUS_PROTOCOL_COMPLETE_PFM_UPDATE: { const struct manifest_cmd_interface *pfm_cmd[2] = {interface->pfm_0, interface->pfm_1}; status = cerberus_protocol_pfm_update_complete (pfm_cmd, 2, request); break; } case CERBERUS_PROTOCOL_GET_CFM_ID: status = cerberus_protocol_get_cfm_id (interface->cfm_manager, request); break; case CERBERUS_PROTOCOL_INIT_CFM_UPDATE: status = cerberus_protocol_cfm_update_init (interface->cfm, request); break; case CERBERUS_PROTOCOL_CFM_UPDATE: status = cerberus_protocol_cfm_update (interface->cfm, request); break; case CERBERUS_PROTOCOL_COMPLETE_CFM_UPDATE: status = cerberus_protocol_cfm_update_complete (interface->cfm, request); break; case CERBERUS_PROTOCOL_GET_PCD_ID: status = cerberus_protocol_get_pcd_id (interface->pcd_manager, request); break; case CERBERUS_PROTOCOL_INIT_PCD_UPDATE: status = cerberus_protocol_pcd_update_init (interface->pcd, request); break; case CERBERUS_PROTOCOL_PCD_UPDATE: status = cerberus_protocol_pcd_update (interface->pcd, request); break; case CERBERUS_PROTOCOL_COMPLETE_PCD_UPDATE: status = cerberus_protocol_pcd_update_complete (interface->pcd, request); break; case CERBERUS_PROTOCOL_GET_PCD_SUPPORTED_COMPONENT_IDS: status = cerberus_protocol_get_pcd_component_ids (interface->pcd_manager, request); break; case CERBERUS_PROTOCOL_GET_CFM_SUPPORTED_COMPONENT_IDS: status = cerberus_protocol_get_cfm_component_ids (interface->cfm_manager, request); break; case CERBERUS_PROTOCOL_INIT_FW_UPDATE: status = cerberus_protocol_fw_update_init (interface->control, request); break; case CERBERUS_PROTOCOL_FW_UPDATE: status = cerberus_protocol_fw_update (interface->control, request); break; case CERBERUS_PROTOCOL_COMPLETE_FW_UPDATE: status = cerberus_protocol_fw_update_start (interface->control, request); break; case CERBERUS_PROTOCOL_GET_UPDATE_STATUS: { const struct manifest_cmd_interface *pfm_cmd[2] = {interface->pfm_0, interface->pfm_1}; struct host_processor *host[2] = {interface->host_0, interface->host_1}; status = cerberus_protocol_get_update_status (interface->control, 2, pfm_cmd, interface->cfm, interface->pcd, host, interface->recovery_cmd_0, interface->recovery_cmd_1, interface->background, request); break; } case CERBERUS_PROTOCOL_GET_EXT_UPDATE_STATUS: status = cerberus_protocol_get_extended_update_status (interface->control, interface->recovery_manager_0, interface->recovery_manager_1, interface->recovery_cmd_0, interface->recovery_cmd_1, request); break; case CERBERUS_PROTOCOL_GET_DEVICE_CAPABILITIES: status = cerberus_protocol_get_device_capabilities (interface->device_manager, request); break; case CERBERUS_PROTOCOL_RESET_COUNTER: status = cerberus_protocol_reset_counter (interface->cmd_device, request); break; case CERBERUS_PROTOCOL_UNSEAL_MESSAGE: status = cerberus_protocol_unseal_message (interface->background, request); break; case CERBERUS_PROTOCOL_UNSEAL_MESSAGE_RESULT: status = cerberus_protocol_unseal_message_result (interface->background, request); break; case CERBERUS_PROTOCOL_EXPORT_CSR: status = cerberus_protocol_export_csr (interface->riot, request); break; case CERBERUS_PROTOCOL_IMPORT_CA_SIGNED_CERT: status = cerberus_protocol_import_ca_signed_cert (interface->riot, interface->background, request); break; case CERBERUS_PROTOCOL_GET_SIGNED_CERT_STATE: status = cerberus_protocol_get_signed_cert_state (interface->background, request); break; case CERBERUS_PROTOCOL_RESET_CONFIG: status = cerberus_protocol_reset_config (interface->auth, interface->background, request); break; case CERBERUS_PROTOCOL_PREPARE_RECOVERY_IMAGE: status = cerberus_protocol_prepare_recovery_image (interface->recovery_cmd_0, interface->recovery_cmd_1, request); break; case CERBERUS_PROTOCOL_UPDATE_RECOVERY_IMAGE: status = cerberus_protocol_update_recovery_image (interface->recovery_cmd_0, interface->recovery_cmd_1, request); break; case CERBERUS_PROTOCOL_ACTIVATE_RECOVERY_IMAGE: status = cerberus_protocol_activate_recovery_image (interface->recovery_cmd_0, interface->recovery_cmd_1, request); break; case CERBERUS_PROTOCOL_GET_RECOVERY_IMAGE_VERSION: status = cerberus_protocol_get_recovery_image_id (interface->recovery_manager_0, interface->recovery_manager_1, request); break; case CERBERUS_PROTOCOL_GET_HOST_STATE: status = cerberus_protocol_get_host_reset_status (interface->host_0_ctrl, interface->host_1_ctrl, request); break; case CERBERUS_PROTOCOL_GET_DEVICE_INFO: status = cerberus_protocol_get_device_info (interface->cmd_device, request); break; case CERBERUS_PROTOCOL_GET_DEVICE_ID: status = cerberus_protocol_get_device_id (&interface->device_id, request); break; case CERBERUS_PROTOCOL_GET_ATTESTATION_DATA: status = cerberus_protocol_get_attestation_data (interface->pcr_store, request); break; case CERBERUS_PROTOCOL_GET_ATTESTATION_SUMMARY: status = cerberus_protocol_get_attestation_summary (interface->device_manager, request); break; #ifdef CMD_ENABLE_HEAP_STATS case CERBERUS_PROTOCOL_DIAG_HEAP_USAGE: return cerberus_protocol_heap_stats (interface->cmd_device, request); #endif #ifdef CMD_SUPPORT_ENCRYPTED_SESSIONS case CERBERUS_PROTOCOL_EXCHANGE_KEYS: status = cerberus_protocol_key_exchange (interface->base.session, request, request->is_encrypted); break; case CERBERUS_PROTOCOL_SESSION_SYNC: status = cerberus_protocol_session_sync (interface->base.session, request, request->is_encrypted); break; #endif #ifdef CMD_SUPPORT_DEBUG_COMMANDS case CERBERUS_PROTOCOL_DEBUG_GET_ATTESTATION_STATE: status = cerberus_protocol_get_attestation_state (interface->device_manager, request); break; case CERBERUS_PROTOCOL_DEBUG_FILL_LOG: status = cerberus_protocol_debug_fill_log (interface->background, request); break; #endif default: return CMD_HANDLER_UNKNOWN_REQUEST; } if (status == 0) { status = cmd_interface_prepare_response (&interface->base, request); } return status; } int cmd_interface_system_process_response (const struct cmd_interface *intf, struct cmd_interface_msg *response) { struct cmd_interface_system *interface = (struct cmd_interface_system*) intf; uint8_t command_id; uint8_t command_set; int status; status = cmd_interface_process_cerberus_protocol_message (&interface->base, response, &command_id, &command_set, true, true); if (status != 0) { return status; } switch (command_id) { #ifdef ATTESTATION_SUPPORT_CERBERUS_CHALLENGE case CERBERUS_PROTOCOL_GET_DIGEST: status = cerberus_protocol_process_certificate_digest_response (response); if (status != 0) { return status; } else { return observable_notify_observers_with_ptr (&interface->observable, offsetof (struct cerberus_protocol_observer, on_get_digest_response), response); } case CERBERUS_PROTOCOL_GET_CERTIFICATE: status = cerberus_protocol_process_certificate_response (response); if (status != 0) { return status; } else { return observable_notify_observers_with_ptr (&interface->observable, offsetof (struct cerberus_protocol_observer, on_get_certificate_response), response); } case CERBERUS_PROTOCOL_ATTESTATION_CHALLENGE: status = cerberus_protocol_process_challenge_response (response); if (status != 0) { return status; } else { return observable_notify_observers_with_ptr (&interface->observable, offsetof (struct cerberus_protocol_observer, on_challenge_response), response); } case CERBERUS_PROTOCOL_GET_DEVICE_CAPABILITIES: status = cerberus_protocol_process_device_capabilities_response (interface->device_manager, response); if (status != 0) { return status; } else { return observable_notify_observers_with_ptr (&interface->observable, offsetof (struct cerberus_protocol_observer, on_device_capabilities), response); } #endif case CERBERUS_PROTOCOL_ERROR: return cerberus_protocol_process_error_response (response); default: return CMD_HANDLER_UNKNOWN_RESPONSE; } } /** * Initialize System command interface instance * * @param intf The System command interface instance to initialize * @param control The FW update control instance to use * @param pfm_0 Command interface to PFM for port 0 * @param pfm_1 Command interface to PFM for port 1 * @param cfm Command interface to CFM * @param pcd Command interface to PCD * @param pfm_manager_0 PFM manager for port 0 * @param pfm_manager_1 PFM manager for port 1 * @param cfm_manager CFM manager * @param pcd_manager PCD manager * @param attestation Attestation responder instance to utilize * @param device_manager Device manager * @param store PCR storage * @param hash Hash engine to to use for PCR operations * @param background Context for executing long-running operations in the background. * @param host_0 Host interface for port 0 * @param host_1 Host interface for port 1 * @param fw_version The FW version strings * @param riot RIoT keys manager * @param auth Handler for authorizing protected commands * @param host_0_ctrl The host control instance for port 0 * @param host_1_ctrl The host control instance for port 1 * @param recovery_cmd_0 Command interface to a recovery image for port 0 * @param recovery_cmd_1 Command interface to a recovery image for port 1 * @param recovery_manager_0 Recovery image manager for port 0 * @param recovery_manager_1 Recovery image manager for port 1 * @param cmd_device Device command handler instance * @param vendor_id Device vendor ID * @param device_id Device ID * @param subsystem_vid Subsystem vendor ID * @param subsystem_id Subsystem ID * @param session Session manager for channel encryption * * @return Initialization status, 0 if success or an error code. */ int cmd_interface_system_init (struct cmd_interface_system *intf, const struct firmware_update_control *control, const struct manifest_cmd_interface *pfm_0, const struct manifest_cmd_interface *pfm_1, const struct manifest_cmd_interface *cfm, const struct manifest_cmd_interface *pcd, const struct pfm_manager *pfm_manager_0, const struct pfm_manager *pfm_manager_1, const struct cfm_manager *cfm_manager, const struct pcd_manager *pcd_manager, struct attestation_responder *attestation, struct device_manager *device_manager, struct pcr_store *store, const struct hash_engine *hash, const struct cmd_background *background, struct host_processor *host_0, struct host_processor *host_1, const struct cmd_interface_fw_version *fw_version, const struct riot_key_manager *riot, const struct cmd_authorization *auth, const struct host_control *host_ctrl_0, const struct host_control *host_ctrl_1, const struct recovery_image_cmd_interface *recovery_cmd_0, const struct recovery_image_cmd_interface *recovery_cmd_1, struct recovery_image_manager *recovery_manager_0, struct recovery_image_manager *recovery_manager_1, const struct cmd_device *cmd_device, uint16_t vendor_id, uint16_t device_id, uint16_t subsystem_vid, uint16_t subsystem_id, struct session_manager *session) { int status; if ((intf == NULL) || (control == NULL) || (store == NULL) || (background == NULL) || (riot == NULL) || (auth == NULL) || (attestation == NULL) || (hash == NULL) || (device_manager == NULL) || (fw_version == NULL) || (cmd_device == NULL)) { return CMD_HANDLER_INVALID_ARGUMENT; } memset (intf, 0, sizeof (struct cmd_interface_system)); status = observable_init (&intf->observable); if (status != 0) { return status; } intf->control = control; intf->pfm_0 = pfm_0; intf->pfm_1 = pfm_1; intf->cfm = cfm; intf->pcd = pcd; intf->pfm_manager_0 = pfm_manager_0; intf->pfm_manager_1 = pfm_manager_1; intf->cfm_manager = cfm_manager; intf->pcd_manager = pcd_manager; intf->host_0 = host_0; intf->host_1 = host_1; intf->pcr_store = store; intf->riot = riot; intf->background = background; intf->auth = auth; intf->attestation = attestation; intf->hash = hash; intf->host_0_ctrl = host_ctrl_0; intf->host_1_ctrl = host_ctrl_1; intf->device_manager = device_manager; intf->recovery_cmd_0 = recovery_cmd_0; intf->recovery_cmd_1 = recovery_cmd_1; intf->recovery_manager_0 = recovery_manager_0; intf->recovery_manager_1 = recovery_manager_1; intf->fw_version = fw_version; intf->cmd_device = cmd_device; intf->device_id.vendor_id = vendor_id; intf->device_id.device_id = device_id; intf->device_id.subsystem_vid = subsystem_vid; intf->device_id.subsystem_id = subsystem_id; intf->base.process_request = cmd_interface_system_process_request; #ifdef CMD_ENABLE_ISSUE_REQUEST intf->base.process_response = cmd_interface_system_process_response; #endif #if CMD_SUPPORT_ENCRYPTED_SESSIONS intf->base.session = session; #else UNUSED (session); #endif return 0; } /** * Deinitialize System command interface instance * * @param intf The System command interface instance to deinitialize */ void cmd_interface_system_deinit (struct cmd_interface_system *intf) { if (intf != NULL) { observable_release (&intf->observable); } } /** * Add an observer for system notifications. * * @param system The system instance to register with. * @param observer The observer to add. * * @return 0 if the observer was successfully added or an error code. */ int cmd_interface_system_add_cerberus_protocol_observer (struct cmd_interface_system *intf, const struct cerberus_protocol_observer *observer) { if (intf == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } return observable_add_observer (&intf->observable, (void*) observer); } /** * Remove an observer from system notifications. * * @param system The system instance to deregister from. * @param observer The observer to remove. * * @return 0 if the observer was successfully removed or an error code. */ int cmd_interface_system_remove_cerberus_protocol_observer (struct cmd_interface_system *intf, const struct cerberus_protocol_observer *observer) { if (intf == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } return observable_remove_observer (&intf->observable, (void*) observer); }