core/cmd_interface/cerberus_protocol_master_commands.c (712 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include "attestation_cmd_interface.h" #include "cerberus_protocol_master_commands.h" #include "cerberus_protocol_optional_commands.h" #include "cerberus_protocol_required_commands.h" #include "common/certificate.h" #include "common/common_math.h" #include "common/unused.h" #include "manifest/cfm/cfm_manager.h" #include "manifest/pcd/pcd_manager.h" /** * Get CFM interface for a specified CFM location. * * @param manager The cfm managing responsible for cfm. * @param region The cfm region to query. 0 for active, 1 for pending. * @param cfm Output for the CFM * * @return 0 if the operation was successful or an error code. */ int cerberus_protocol_get_curr_cfm (const struct cfm_manager *manager, uint8_t region, const struct cfm **cfm) { if (manager == NULL) { return CMD_HANDLER_UNSUPPORTED_COMMAND; } if (region == 0) { *cfm = manager->get_active_cfm (manager); } else if (region == 1) { *cfm = manager->get_pending_cfm (manager); } else { return CMD_HANDLER_OUT_OF_RANGE; } return 0; } /** * Release a cfm instance. * * @param manager The cfm manager releasing the cfm. * @param cfm The cfm to release. */ static void cerberus_protocol_free_cfm (const struct cfm_manager *manager, const struct cfm *cfm) { if (manager != NULL) { manager->free_cfm (manager, cfm); } } /** * Release a PCD instance. * * @param manager The PCD manager releasing the PCD. * @param pcd The PCD to release. */ static void cerberus_protocol_free_pcd (const struct pcd_manager *manager, const struct pcd *pcd) { if (manager != NULL) { manager->free_pcd (manager, pcd); } } /** * Populate the Cerberus protocol header segment of a Cerberus Protocol request * * @param header Buffer to fill with Cerberus Protocol header * @param command Command ID to utilize in header */ static void cerberus_protocol_populate_cerberus_protocol_header ( struct cerberus_protocol_header *header, uint8_t command) { header->msg_type = MCTP_BASE_PROTOCOL_MSG_TYPE_VENDOR_DEF; header->integrity_check = 0; header->pci_vendor_id = CERBERUS_PROTOCOL_MSFT_PCI_VID; header->reserved1 = 0; header->crypt = 0; header->reserved2 = 0; header->rq = 0; header->command = command; } /** * Construct get device capabilities request. * * @param device_mgr Device manager instance to utilize. * @param buf The buffer containing the generated request. * @param buf_len Maximum size of buffer. * * @return Length of the generated request if the request was successfully constructed or an * error code. */ int cerberus_protocol_generate_get_device_capabilities_request (struct device_manager *device_mgr, uint8_t *buf, size_t buf_len) { struct cerberus_protocol_device_capabilities *rq = (struct cerberus_protocol_device_capabilities*) buf; int status; if ((device_mgr == NULL) || (rq == NULL)) { return CMD_HANDLER_INVALID_ARGUMENT; } if (buf_len < (sizeof (struct cerberus_protocol_device_capabilities))) { return CMD_HANDLER_BUF_TOO_SMALL; } cerberus_protocol_populate_cerberus_protocol_header (&rq->header, CERBERUS_PROTOCOL_GET_DEVICE_CAPABILITIES); status = device_manager_get_device_capabilities_request (device_mgr, &rq->capabilities); if (status != 0) { return status; } return sizeof (struct cerberus_protocol_device_capabilities); } /** * Construct get certificate digest request. * * @param slot_num Slot number to request. * @param key_alg Key exchange algorithm to request. * @param buf Output buffer for the generated request data. * @param buf_len Maximum size of buffer. * * @return Length of the generated request data if the request was successfully constructed or * an error code. */ int cerberus_protocol_generate_get_certificate_digest_request (uint8_t slot_num, uint8_t key_alg, uint8_t *buf, size_t buf_len) { struct cerberus_protocol_get_certificate_digest *rq = (struct cerberus_protocol_get_certificate_digest*) buf; if (rq == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } if (buf_len < sizeof (struct cerberus_protocol_get_certificate_digest)) { return CMD_HANDLER_BUF_TOO_SMALL; } if ((slot_num > ATTESTATION_MAX_SLOT_NUM) || (key_alg >= NUM_ATTESTATION_KEY_EXCHANGE_ALGORITHMS)) { return CMD_HANDLER_OUT_OF_RANGE; } cerberus_protocol_populate_cerberus_protocol_header (&rq->header, CERBERUS_PROTOCOL_GET_DIGEST); rq->slot_num = slot_num; rq->key_alg = key_alg; return (sizeof (struct cerberus_protocol_get_certificate_digest)); } /** * Construct get certificate request. * * @param slot_num Slot number to request. * @param cert_num Certificate number to request. * @param buf Output buffer for the generated request data. * @param buf_len Maximum size of buffer. * @param offset Offset from start of certificate in bytes to request * @param length Number of bytes to read back, 0 for max payload length * * @return Length of the generated request data if the request was successfully constructed or * an error code. */ int cerberus_protocol_generate_get_certificate_request (uint8_t slot_num, uint8_t cert_num, uint8_t *buf, size_t buf_len, uint16_t offset, uint16_t length) { struct cerberus_protocol_get_certificate *rq = (struct cerberus_protocol_get_certificate*) buf; if (rq == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } if (buf_len < sizeof (struct cerberus_protocol_get_certificate)) { return CMD_HANDLER_BUF_TOO_SMALL; } if (slot_num > ATTESTATION_MAX_SLOT_NUM) { return CMD_HANDLER_OUT_OF_RANGE; } cerberus_protocol_populate_cerberus_protocol_header (&rq->header, CERBERUS_PROTOCOL_GET_CERTIFICATE); rq->slot_num = slot_num; rq->cert_num = cert_num; rq->offset = offset; rq->length = length; return (sizeof (struct cerberus_protocol_get_certificate)); } /** * Construct challenge request. * * @param rng RNG engine to utilize. * @param eid EID of target device in attestation challenge request. * @param slot_num Requested slot number for target device to utilize. * @param buf Output buffer for the generated request data. * @param buf_len Maximum size of buffer. * * @return Length of the generated request data if the request was successfully constructed or * an error code. */ int cerberus_protocol_generate_challenge_request (const struct rng_engine *rng, uint8_t eid, uint8_t slot_num, uint8_t *buf, size_t buf_len) { struct cerberus_protocol_challenge *rq = (struct cerberus_protocol_challenge*) buf; int status; UNUSED (eid); if ((rng == NULL) || (rq == NULL)) { return CMD_HANDLER_INVALID_ARGUMENT; } if (buf_len < sizeof (struct cerberus_protocol_challenge)) { return CMD_HANDLER_BUF_TOO_SMALL; } if (slot_num > ATTESTATION_MAX_SLOT_NUM) { return CMD_HANDLER_OUT_OF_RANGE; } memset (rq, 0, sizeof (struct cerberus_protocol_challenge)); cerberus_protocol_populate_cerberus_protocol_header (&rq->header, CERBERUS_PROTOCOL_ATTESTATION_CHALLENGE); rq->challenge.slot_num = slot_num; status = rng->generate_random_buffer (rng, sizeof (rq->challenge.nonce), rq->challenge.nonce); if (status == 0) { return sizeof (struct cerberus_protocol_challenge); } else { return status; } } /** * Process manifest update init request * * @param manifest_interface Interface to handle manifest update commands * @param request Manifest update request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_manifest_update_init ( const struct manifest_cmd_interface *manifest_interface, struct cmd_interface_msg *request) { /* Just use the CFM structures since they are the same for all manifests. */ struct cerberus_protocol_prepare_cfm_update *rq = (struct cerberus_protocol_prepare_cfm_update*) request->data; if (request->length != sizeof (struct cerberus_protocol_prepare_cfm_update)) { return CMD_HANDLER_BAD_LENGTH; } if (manifest_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_COMMAND; } request->length = 0; return manifest_interface->prepare_manifest (manifest_interface, rq->total_size); } /** * Process manifest update request * * @param manifest_interface Interface to handle manifest update commands * @param request Manifest update request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_manifest_update ( const struct manifest_cmd_interface *manifest_interface, struct cmd_interface_msg *request) { /* Just use the CFM structures since they are the same for all manifests. */ struct cerberus_protocol_cfm_update *rq = (struct cerberus_protocol_cfm_update*) request->data; int status; if (request->length < sizeof (struct cerberus_protocol_cfm_update)) { return CMD_HANDLER_BAD_LENGTH; } if (manifest_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_COMMAND; } status = manifest_interface->store_manifest (manifest_interface, &rq->payload, cerberus_protocol_cfm_update_length (request)); request->length = 0; return status; } /** * Process manifest update complete request * * @param manifest_interface Interface to handle manifest update commands * @param request Manifest update complete request to process * @param delayed_activation_allowed Boolean indicating whether delayed activation is allowed * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_manifest_update_complete ( const struct manifest_cmd_interface *manifest_interface, struct cmd_interface_msg *request, bool delayed_activation_allowed) { /* Just use the CFM structures since they are the same for all manifests. */ struct cerberus_protocol_complete_cfm_update *rq = (struct cerberus_protocol_complete_cfm_update*) request->data; if (request->length != (sizeof (struct cerberus_protocol_complete_pcd_update) + delayed_activation_allowed)) { return CMD_HANDLER_BAD_LENGTH; } if (manifest_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_COMMAND; } request->length = 0; if (delayed_activation_allowed) { return manifest_interface->finish_manifest (manifest_interface, rq->activation); } else { return manifest_interface->finish_manifest (manifest_interface, true); } } /** * Process a request to initialize a CFM update. * * @param cfm_interface Command interface for CFM processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_cfm_update_init (const struct manifest_cmd_interface *cfm_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update_init (cfm_interface, request); } /** * Process a request to write CFM update data. * * @param cfm_interface Command interface for CFM processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_cfm_update (const struct manifest_cmd_interface *cfm_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update (cfm_interface, request); } /** * Process a request to complete a CFM update. * * @param cfm_interface Command interface for CFM processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_cfm_update_complete (const struct manifest_cmd_interface *cfm_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update_complete (cfm_interface, request, true); } /** * Process manifest ID version * * @param manifest manifest to query * @param request manifest version ID request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_manifest_id_version (const struct manifest *manifest, struct cmd_interface_msg *request) { /* Just use the CFM structures since they are the same for all manifests. */ struct cerberus_protocol_get_cfm_id_version_response *rsp = (struct cerberus_protocol_get_cfm_id_version_response*) request->data; int status = 0; if (manifest != NULL) { status = manifest->get_id (manifest, &rsp->version); if (status != 0) { return status; } rsp->valid = 1; } else { rsp->valid = 0; rsp->version = 0; } request->length = sizeof (struct cerberus_protocol_get_cfm_id_version_response); return status; } /** * Process manifest ID platform * * @param manifest manifest to query * @param request manifest platform ID request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_manifest_id_platform (const struct manifest *manifest, struct cmd_interface_msg *request) { /* Just use the CFM structures since the same same for all manifests. */ struct cerberus_protocol_get_cfm_id_platform_response *rsp = (struct cerberus_protocol_get_cfm_id_platform_response*) request->data; char *platform_id = (char*) &rsp->platform; size_t platform_id_len; int status = 0; if (manifest != NULL) { status = manifest->get_platform_id (manifest, &platform_id, CERBERUS_PROTOCOL_MAX_CFM_ID_PLATFORM (request)); if (status != 0) { return status; } rsp->valid = 1; platform_id_len = strlen (platform_id) + 1; } else { rsp->valid = 0; rsp->platform = '\0'; platform_id_len = 1; } request->length = cerberus_protocol_get_cfm_id_platform_response_length (platform_id_len); return status; } /** * Process CFM ID version * * @param cfm CFM to query * @param request CFM platform ID request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_get_cfm_id_version (const struct cfm *cfm, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_id_version (&cfm->base, request); } /** * Process CFM ID platform * * @param cfm CFM to query * @param request CFM version ID request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_get_cfm_id_platform (const struct cfm *cfm, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_id_platform (&cfm->base, request); } /** * Process CFM ID request * * @param cfm_mgr CFM manager instance to utilize * @param request CFM ID request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_cfm_id (const struct cfm_manager *cfm_mgr, struct cmd_interface_msg *request) { struct cerberus_protocol_get_cfm_id *rq = (struct cerberus_protocol_get_cfm_id*) request->data; const struct cfm *curr_cfm = NULL; int status = 0; int id; if (request->length == (sizeof (struct cerberus_protocol_get_cfm_id) - sizeof (rq->id))) { rq->id = 0; } else if (request->length != sizeof (struct cerberus_protocol_get_cfm_id)) { return CMD_HANDLER_BAD_LENGTH; } id = rq->id; if (id > 1) { return CMD_HANDLER_OUT_OF_RANGE; } status = cerberus_protocol_get_curr_cfm (cfm_mgr, rq->region, &curr_cfm); /* When there's no valid CFM manager, return a success with response indicating no valid * manifest. */ if ((status != 0) && (status != CMD_HANDLER_UNSUPPORTED_COMMAND)) { return status; } if (id == 0) { status = cerberus_protocol_get_cfm_id_version (curr_cfm, request); } else { status = cerberus_protocol_get_cfm_id_platform (curr_cfm, request); } cerberus_protocol_free_cfm (cfm_mgr, curr_cfm); return status; } /** * Process CFM component IDs request * * @param cfm_mgr CFM manager instance to utilize * @param request CFM component IDs request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_cfm_component_ids (const struct cfm_manager *cfm_mgr, struct cmd_interface_msg *request) { struct cerberus_protocol_get_cfm_component_ids *rq = (struct cerberus_protocol_get_cfm_component_ids*) request->data; struct cerberus_protocol_get_cfm_component_ids_response *rsp = (struct cerberus_protocol_get_cfm_component_ids_response*) request->data; const struct cfm *curr_cfm = NULL; uint32_t offset; size_t length; int status = 0; if (request->length != sizeof (struct cerberus_protocol_get_cfm_component_ids)) { return CMD_HANDLER_BAD_LENGTH; } if (cfm_mgr == NULL) { rsp->valid = 0; rsp->version = 0; request->length = cerberus_protocol_get_cfm_component_ids_response_length (0); return status; } status = cerberus_protocol_get_curr_cfm (cfm_mgr, rq->region, &curr_cfm); if (status != 0) { return status; } if (curr_cfm != NULL) { offset = rq->offset; rsp->valid = 1; status = curr_cfm->base.get_id (&curr_cfm->base, &rsp->version); if (status != 0) { goto exit; } length = CERBERUS_PROTOCOL_MAX_COMPONENT_IDS (request); status = curr_cfm->buffer_supported_components (curr_cfm, offset, length, cerberus_protocol_cfm_component_ids (rsp)); if (ROT_IS_ERROR (status)) { goto exit; } request->length = cerberus_protocol_get_cfm_component_ids_response_length (status); status = 0; } else { rsp->valid = 0; rsp->version = 0; request->length = cerberus_protocol_get_cfm_component_ids_response_length (0); } exit: cerberus_protocol_free_cfm (cfm_mgr, curr_cfm); return status; } /** * Process a request to initialize a PCD update. * * @param pcd_interface Command interface for PCD processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_pcd_update_init (const struct manifest_cmd_interface *pcd_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update_init (pcd_interface, request); } /** * Process a request to write PCD update data. * * @param pcd_interface Command interface for PCD processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_pcd_update (const struct manifest_cmd_interface *pcd_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update (pcd_interface, request); } /** * Process a request to complete a PCD update. * * @param pcd_interface Command interface for PCD processing * @param request Request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_pcd_update_complete (const struct manifest_cmd_interface *pcd_interface, struct cmd_interface_msg *request) { return cerberus_protocol_manifest_update_complete (pcd_interface, request, false); } /** * Process PCD platform ID request * * @param pcd PCD instance to utilize * @param request Get PCD platform ID request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_get_pcd_platform_id (const struct pcd *pcd, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_id_platform (&pcd->base, request); } /** * Process PCD version ID request * * @param pcd PCD instance to utilize * @param request Get PCD version ID request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_get_pcd_version_id (const struct pcd *pcd, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_id_version (&pcd->base, request); } /** * Process PCD ID request * * @param pcd_mgr PCD manager instance to utilize * @param request Get PCD ID request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_pcd_id (const struct pcd_manager *pcd_mgr, struct cmd_interface_msg *request) { struct cerberus_protocol_get_pcd_id *rq = (struct cerberus_protocol_get_pcd_id*) request->data; const struct pcd *curr_pcd = NULL; int status; if (request->length == (sizeof (struct cerberus_protocol_get_pcd_id) - sizeof (rq->id))) { rq->id = 0; } else if (request->length != sizeof (struct cerberus_protocol_get_pcd_id)) { return CMD_HANDLER_BAD_LENGTH; } if (rq->id > 1) { return CMD_HANDLER_OUT_OF_RANGE; } /* When there's no valid PCD manager, return a success * with response indicating no valid manifest */ if (pcd_mgr != NULL) { curr_pcd = pcd_mgr->get_active_pcd (pcd_mgr); } if (rq->id == 0) { status = cerberus_protocol_get_pcd_version_id (curr_pcd, request); } else { status = cerberus_protocol_get_pcd_platform_id (curr_pcd, request); } cerberus_protocol_free_pcd (pcd_mgr, curr_pcd); return status; } /** * Process PCD component IDs request * * @param pcd_mgr PCD manager instance to utilize * @param request PCD component IDs request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_pcd_component_ids (const struct pcd_manager *pcd_mgr, struct cmd_interface_msg *request) { struct cerberus_protocol_get_pcd_component_ids *rq = (struct cerberus_protocol_get_pcd_component_ids*) request->data; struct cerberus_protocol_get_pcd_component_ids_response *rsp = (struct cerberus_protocol_get_pcd_component_ids_response*) request->data; const struct pcd *curr_pcd = NULL; uint32_t offset; size_t length; int status = 0; if (request->length != sizeof (struct cerberus_protocol_get_pcd_component_ids)) { return CMD_HANDLER_BAD_LENGTH; } if (pcd_mgr == NULL) { rsp->valid = 0; rsp->version = 0; request->length = cerberus_protocol_get_pcd_component_ids_response_length (0); return status; } curr_pcd = pcd_mgr->get_active_pcd (pcd_mgr); if (curr_pcd != NULL) { offset = rq->offset; rsp->valid = 1; status = curr_pcd->base.get_id (&curr_pcd->base, &rsp->version); if (status != 0) { goto exit; } length = CERBERUS_PROTOCOL_MAX_PCD_COMPONENT_IDS (request); status = curr_pcd->buffer_supported_components (curr_pcd, offset, length, cerberus_protocol_pcd_component_ids (rsp)); if (ROT_IS_ERROR (status)) { goto exit; } request->length = cerberus_protocol_get_pcd_component_ids_response_length (status); status = 0; } else { rsp->valid = 0; rsp->version = 0; request->length = cerberus_protocol_get_pcd_component_ids_response_length (0); } exit: cerberus_protocol_free_pcd (pcd_mgr, curr_pcd); return status; } /** * Process a FW update status request * * @param control Firmware update control instance to query * @param rsp Status response message to update * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_fw_update_status (const struct firmware_update_control *control, struct cerberus_protocol_update_status_response *rsp) { if (control == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } rsp->update_status = control->get_status (control); return 0; } /** * Process PFM update status request * * @param pfm_cmd List of PFM command interfaces for all available ports. * @param num_ports Number of available ports. * @param request PFM update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_pfm_update_status (const struct manifest_cmd_interface *pfm_cmd[], uint8_t num_ports, struct cmd_interface_msg *request) { struct cerberus_protocol_update_status *rq = (struct cerberus_protocol_update_status*) request->data; struct cerberus_protocol_update_status_response *rsp = (struct cerberus_protocol_update_status_response*) request->data; if (rq->port_id >= num_ports) { return CMD_HANDLER_OUT_OF_RANGE; } if (pfm_cmd[rq->port_id] == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } rsp->update_status = pfm_cmd[rq->port_id]->get_status (pfm_cmd[rq->port_id]); return 0; } /** * Process manifest update status request * * @param manifest_interface Interface to handle manifest update commands * @param request Manifest update status request to process * * @return 0 if request processing completed successfully or an error code. */ static int cerberus_protocol_get_manifest_update_status ( const struct manifest_cmd_interface *manifest_interface, struct cmd_interface_msg *request) { struct cerberus_protocol_update_status_response *rsp = (struct cerberus_protocol_update_status_response*) request->data; if (manifest_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } rsp->update_status = manifest_interface->get_status (manifest_interface); return 0; } /** * Process CFM update status request * * @param cfm_interface CFM command interface * @param request CFM update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_cfm_update_status (const struct manifest_cmd_interface *cfm_interface, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_update_status (cfm_interface, request); } /** * Process PCD update status request * * @param pcd_interface PCD command interface * @param request PCD update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_pcd_update_status (const struct manifest_cmd_interface *pcd_interface, struct cmd_interface_msg *request) { return cerberus_protocol_get_manifest_update_status (pcd_interface, request); } /** * Process a request for host verification actions on reset. * * @param host List of host processors for all available ports * @param num_ports Number of available ports * @param request Host verification actions request to process * * @return Response length if request processing completed successfully or an error code. */ int cerberus_protocol_get_host_next_verification_status (struct host_processor *host[], uint8_t num_ports, struct cmd_interface_msg *request) { struct cerberus_protocol_update_status *rq = (struct cerberus_protocol_update_status*) request->data; struct cerberus_protocol_update_status_response *rsp = (struct cerberus_protocol_update_status_response*) request->data; int status; if (rq->port_id >= num_ports) { return CMD_HANDLER_OUT_OF_RANGE; } if ((host == NULL) || (host[rq->port_id] == NULL)) { return CMD_HANDLER_UNSUPPORTED_INDEX; } status = host[rq->port_id]->get_next_reset_verification_actions (host[rq->port_id]); if (ROT_IS_ERROR (status)) { return status; } rsp->update_status = (uint32_t) status; return 0; } /** * Process recovery image get update status request * * @param recovery_0 The recovery image command interface instance for port 0. * @param recovery_1 The recovery image command interface instance for port 1. * @param request Recovery image update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_recovery_image_update_status ( const struct recovery_image_cmd_interface *recovery_0, const struct recovery_image_cmd_interface *recovery_1, struct cmd_interface_msg *request) { struct cerberus_protocol_update_status *rq = (struct cerberus_protocol_update_status*) request->data; struct cerberus_protocol_update_status_response *rsp = (struct cerberus_protocol_update_status_response*) request->data; const struct recovery_image_cmd_interface *curr_recovery_interface; if (rq->port_id > 1) { return CMD_HANDLER_OUT_OF_RANGE; } curr_recovery_interface = cerberus_protocol_get_recovery_image_cmd_interface (recovery_0, recovery_1, rq->port_id); if (curr_recovery_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } rsp->update_status = curr_recovery_interface->get_status (curr_recovery_interface); return 0; } /** * Process a reset configuration update status request * * @param background Background command processing instance to query * @param rsp Status response message to update * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_reset_config_status (const struct cmd_background *background, struct cerberus_protocol_update_status_response *rsp) { #ifdef CMD_ENABLE_RESET_CONFIG if (background == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } rsp->update_status = background->get_authorized_operation_status (background); return 0; #else UNUSED (background); UNUSED (rsp); return CMD_HANDLER_UNSUPPORTED_COMMAND; #endif } /** * Process update status request * * @param control Firmware update control instance to query * @param num_ports Number of available ports * @param pfm_cmd List of PFM command interfaces for all available ports * @param cfm CFM command interface * @param pcd PCD command interface * @param host List of host processors for all available ports * @param recovery_0 The recovery image command interface instance for port 0. * @param recovery_1 The recovery image command interface instance for port 1. * @param background Command background instance to query * @param request Update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_update_status (const struct firmware_update_control *control, uint8_t num_ports, const struct manifest_cmd_interface *pfm_cmd[], const struct manifest_cmd_interface *cfm, const struct manifest_cmd_interface *pcd, struct host_processor *host[], const struct recovery_image_cmd_interface *recovery_0, const struct recovery_image_cmd_interface *recovery_1, const struct cmd_background *background, struct cmd_interface_msg *request) { struct cerberus_protocol_update_status *req = (struct cerberus_protocol_update_status*) request->data; struct cerberus_protocol_update_status_response *rsp = (struct cerberus_protocol_update_status_response*) request->data; int status; if (request->length != sizeof (struct cerberus_protocol_update_status)) { return CMD_HANDLER_BAD_LENGTH; } switch (req->update_type) { case CERBERUS_PROTOCOL_FW_UPDATE_STATUS: status = cerberus_protocol_get_fw_update_status (control, rsp); break; case CERBERUS_PROTOCOL_PFM_UPDATE_STATUS: status = cerberus_protocol_get_pfm_update_status (pfm_cmd, num_ports, request); break; case CERBERUS_PROTOCOL_CFM_UPDATE_STATUS: status = cerberus_protocol_get_manifest_update_status (cfm, request); break; case CERBERUS_PROTOCOL_PCD_UPDATE_STATUS: status = cerberus_protocol_get_manifest_update_status (pcd, request); break; case CERBERUS_PROTOCOL_HOST_FW_NEXT_RESET: status = cerberus_protocol_get_host_next_verification_status (host, num_ports, request); break; case CERBERUS_PROTOCOL_RECOVERY_IMAGE_UPDATE_STATUS: status = cerberus_protocol_get_recovery_image_update_status (recovery_0, recovery_1, request); break; case CERBERUS_PROTOCOL_CONFIG_RESET_STATUS: status = cerberus_protocol_get_reset_config_status (background, rsp); break; default: return CMD_HANDLER_UNSUPPORTED_INDEX; } if (status == 0) { cmd_interface_msg_set_message_payload_length (request, sizeof (struct cerberus_protocol_update_status_response)); } return status; } /** * Process an extended FW update status request * * @param control Firmware update control instance to query * @param rsp Status response message to update * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_extended_fw_update_status (const struct firmware_update_control *control, struct cerberus_protocol_extended_update_status_response *rsp) { rsp->update_status = control->get_status (control); rsp->remaining_len = control->get_remaining_len (control); return 0; } /** * Process recovery image extended get update status request. * * @param manager_0 The recovery image manager instance for port 0. * @param manager_1 The recovery image manager instance for port 1. * @param cmd_0 The recovery image command interface instance for port 0. * @param cmd_1 The recovery image command interface instance for port 1. * @param port The port to query. * @param update_status Output buffer to store the update status. * @param rem_len Output buffer for the remaining update bytes. * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_extended_recovery_image_update_status ( struct recovery_image_manager *manager_0, struct recovery_image_manager *manager_1, const struct recovery_image_cmd_interface *cmd_0, const struct recovery_image_cmd_interface *cmd_1, uint8_t port, uint32_t *update_status, uint32_t *rem_len) { const struct recovery_image_cmd_interface *cmd_interface; struct recovery_image_manager *recovery_manager; struct flash_updater *updating; if (port > 1) { return CMD_HANDLER_OUT_OF_RANGE; } recovery_manager = cerberus_protocol_get_recovery_image_manager (manager_0, manager_1, port); if (recovery_manager == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } cmd_interface = cerberus_protocol_get_recovery_image_cmd_interface (cmd_0, cmd_1, port); if (cmd_interface == NULL) { return CMD_HANDLER_UNSUPPORTED_INDEX; } *update_status = cmd_interface->get_status (cmd_interface); updating = recovery_manager->get_flash_update_manager (recovery_manager); *rem_len = flash_updater_get_remaining_bytes (updating); return 0; } /** * Process extended update status request * * @param control Firmware update control instance to utilize * @param recovery_manager_0 The recovery image manager instance for port 0. * @param recovery_manager_1 The recovery image manager instance for port 1. * @param recovery_cmd_0 The recovery image command interface instance for port 0. * @param recovery_cmd_1 The recovery image command interface instance for port 1. * @param request Expected update status request to process * * @return 0 if request processing completed successfully or an error code. */ int cerberus_protocol_get_extended_update_status (const struct firmware_update_control *control, struct recovery_image_manager *recovery_manager_0, struct recovery_image_manager *recovery_manager_1, const struct recovery_image_cmd_interface *recovery_cmd_0, const struct recovery_image_cmd_interface *recovery_cmd_1, struct cmd_interface_msg *request) { struct cerberus_protocol_extended_update_status *rq = (struct cerberus_protocol_extended_update_status*) request->data; struct cerberus_protocol_extended_update_status_response *rsp = (struct cerberus_protocol_extended_update_status_response*) request->data; int status; if (request->length != sizeof (struct cerberus_protocol_extended_update_status)) { return CMD_HANDLER_BAD_LENGTH; } switch (rq->update_type) { case CERBERUS_PROTOCOL_FW_UPDATE_STATUS: status = cerberus_protocol_get_extended_fw_update_status (control, rsp); break; case CERBERUS_PROTOCOL_RECOVERY_IMAGE_UPDATE_STATUS: status = cerberus_protocol_get_extended_recovery_image_update_status (recovery_manager_0, recovery_manager_1, recovery_cmd_0, recovery_cmd_1, rq->port_id, &rsp->update_status, &rsp->remaining_len); break; default: return CMD_HANDLER_UNSUPPORTED_INDEX; } if (status == 0) { request->length = sizeof (struct cerberus_protocol_extended_update_status_response); } return status; } /** * Process certificate digest response. This function only ensures the response is valid per * Cerberus protocol response definition, the certificate digest is not validated or stored. * * @param response Certificate digest response to process * * @return 0 if response processed successfully or an error code. */ int cerberus_protocol_process_certificate_digest_response (struct cmd_interface_msg *response) { struct cerberus_protocol_get_certificate_digest_response *rsp = (struct cerberus_protocol_get_certificate_digest_response*) response->data; if (response->length <= sizeof (struct cerberus_protocol_get_certificate_digest_response)) { return CMD_HANDLER_BAD_LENGTH; } if (response->length != cerberus_protocol_get_certificate_digest_response_length (rsp)) { return CMD_HANDLER_BAD_LENGTH; } return 0; } /** * Process certificate response message. This function only ensures the response is valid per * Cerberus protocol response definition, the certificate is not validated or stored. * * @param response Certificate response to process * * @return 0 if response processed successfully or an error code. */ int cerberus_protocol_process_certificate_response (struct cmd_interface_msg *response) { struct cerberus_protocol_get_certificate_response *rsp = (struct cerberus_protocol_get_certificate_response*) response->data; if (response->length <= sizeof (struct cerberus_protocol_get_certificate_response)) { return CMD_HANDLER_BAD_LENGTH; } if (rsp->slot_num > ATTESTATION_MAX_SLOT_NUM) { return CMD_HANDLER_UNSUPPORTED_INDEX; } return 0; } /** * Process challenge response message. This function only ensures the response is valid per * Cerberus protocol response definition, the challenge is not validated. * * @param response Challenge response to process * * @return Completion status, 0 if success or an error code. */ int cerberus_protocol_process_challenge_response (struct cmd_interface_msg *response) { struct cerberus_protocol_challenge_response *rsp = (struct cerberus_protocol_challenge_response*) response->data; if ((response->length <= sizeof (struct cerberus_protocol_challenge_response)) || (response->length <= cerberus_protocol_challenge_response_length (rsp))) { return CMD_HANDLER_BAD_LENGTH; } if (rsp->challenge.slot_num > ATTESTATION_MAX_SLOT_NUM) { return CMD_HANDLER_UNSUPPORTED_INDEX; } if (rsp->challenge.reserved != 0) { return CMD_HANDLER_RSVD_NOT_ZERO; } return 0; } /** * Process get device capabilities response. * * @param device_mgr Device manager instance to utilize * @param response Capabilities response to process * * @return Completion status, 0 if success or an error code. */ int cerberus_protocol_process_device_capabilities_response (struct device_manager *device_mgr, struct cmd_interface_msg *response) { struct cerberus_protocol_device_capabilities_response *rsp = (struct cerberus_protocol_device_capabilities_response*) response->data; int device_num; if (response->length != sizeof (struct cerberus_protocol_device_capabilities_response)) { return CMD_HANDLER_BAD_LENGTH; } if ((rsp->capabilities.request.reserved1 != 0) || (rsp->capabilities.request.reserved2 != 0) || (rsp->capabilities.request.reserved3 != 0)) { return CMD_HANDLER_RSVD_NOT_ZERO; } device_num = device_manager_get_device_num (device_mgr, response->source_eid); if (ROT_IS_ERROR (device_num)) { return device_num; } return device_manager_update_device_capabilities (device_mgr, device_num, &rsp->capabilities); }