/** @file EDKII Device Security library for SPDM device. It follows the SPDM Specification. Copyright (c) 2024, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef SPDM_SECURITY_LIB_H_ #define SPDM_SECURITY_LIB_H_ #include #include /** * Send an SPDM transport layer message to a device. * * The message is an SPDM message with transport layer wrapper, * or a secured SPDM message with transport layer wrapper. * * For requester, the message is a transport layer SPDM request. * For responder, the message is a transport layer SPDM response. * * @param spdm_context A pointer to the SPDM context. * @param message_size size in bytes of the message data buffer. * @param message A pointer to a destination buffer to store the message. * The caller is responsible for having * either implicit or explicit ownership of the buffer. * The message pointer shall be inside of * [msg_buf_ptr, msg_buf_ptr + max_msg_size] from * acquired sender_buffer. * @param timeout The timeout, in 100ns units, to use for the execution * of the message. A timeout value of 0 * means that this function will wait indefinitely for the * message to execute. If timeout is greater * than zero, then this function will return RETURN_TIMEOUT if the * time required to execute the message is greater * than timeout. * * @retval RETURN_SUCCESS The SPDM message is sent successfully. * @retval RETURN_DEVICE_ERROR A device error occurs when the SPDM message is sent to the device. * @retval RETURN_INVALID_PARAMETER The message is NULL or the message_size is zero. * @retval RETURN_TIMEOUT A timeout occurred while waiting for the SPDM message * to execute. **/ typedef SPDM_RETURN (*SPDM_DEVICE_SEND_MESSAGE_FUNC)( IN VOID *SpdmContext, IN UINTN MessageSize, IN OUT CONST VOID *Message, IN UINT64 Timeout ); /** * Receive an SPDM transport layer message from a device. * * The message is an SPDM message with transport layer wrapper, * or a secured SPDM message with transport layer wrapper. * * For requester, the message is a transport layer SPDM response. * For responder, the message is a transport layer SPDM request. * * @param spdm_context A pointer to the SPDM context. * @param message_size size in bytes of the message data buffer. * @param message A pointer to a destination buffer to store the message. * The caller is responsible for having * either implicit or explicit ownership of the buffer. * On input, the message pointer shall be msg_buf_ptr from * acquired receiver_buffer. * On output, the message pointer shall be inside of * [msg_buf_ptr, msg_buf_ptr + max_msg_size] from * acquired receiver_buffer. * @param timeout The timeout, in 100ns units, to use for the execution * of the message. A timeout value of 0 * means that this function will wait indefinitely for the * message to execute. If timeout is greater * than zero, then this function will return RETURN_TIMEOUT if the * time required to execute the message is greater * than timeout. * * @retval RETURN_SUCCESS The SPDM message is received successfully. * @retval RETURN_DEVICE_ERROR A device error occurs when the SPDM message is received from the device. * @retval RETURN_INVALID_PARAMETER The message is NULL, message_size is NULL or * the *message_size is zero. * @retval RETURN_TIMEOUT A timeout occurred while waiting for the SPDM message * to execute. **/ typedef SPDM_RETURN (*SPDM_DEVICE_RECEIVE_MESSAGE_FUNC)( IN VOID *SpdmContext, IN OUT UINTN *MessageSize, IN OUT VOID **Message, IN UINT64 Timeout ); /** * Encode an SPDM or APP message to a transport layer message. * * For normal SPDM message, it adds the transport layer wrapper. * For secured SPDM message, it encrypts a secured message then adds the transport layer wrapper. * For secured APP message, it encrypts a secured message then adds the transport layer wrapper. * * The APP message is encoded to a secured message directly in SPDM session. * The APP message format is defined by the transport layer. * Take MCTP as example: APP message == MCTP header (MCTP_MESSAGE_TYPE_SPDM) + SPDM message * * @param spdm_context A pointer to the SPDM context. * @param session_id Indicates if it is a secured message protected via SPDM session. * If session_id is NULL, it is a normal message. * If session_id is NOT NULL, it is a secured message. * @param is_app_message Indicates if it is an APP message or SPDM message. * @param is_requester Indicates if it is a requester message. * @param message_size size in bytes of the message data buffer. * @param message A pointer to a source buffer to store the message. * For normal message, it shall point to the acquired sender buffer. * For secured message, it shall point to the scratch buffer in spdm_context. * @param transport_message_size size in bytes of the transport message data buffer. * @param transport_message A pointer to a destination buffer to store the transport message. * On input, it shall be msg_buf_ptr from sender buffer. * On output, it will point to acquired sender buffer. * * @retval RETURN_SUCCESS The message is encoded successfully. * @retval RETURN_INVALID_PARAMETER The message is NULL or the message_size is zero. **/ typedef SPDM_RETURN (*SPDM_TRANSPORT_ENCODE_MESSAGE_FUNC)( IN VOID *SpdmContext, IN OUT CONST UINT32 *SessionId, IN BOOLEAN IsAppMessage, IN BOOLEAN IsRequester, IN UINTN MessageSize, IN OUT VOID *Message, IN OUT UINTN *TransportMessageSize, IN VOID **TransportMessage ); /** * Decode an SPDM or APP message from a transport layer message. * * For normal SPDM message, it removes the transport layer wrapper, * For secured SPDM message, it removes the transport layer wrapper, then decrypts and verifies a secured message. * For secured APP message, it removes the transport layer wrapper, then decrypts and verifies a secured message. * * The APP message is decoded from a secured message directly in SPDM session. * The APP message format is defined by the transport layer. * Take MCTP as example: APP message == MCTP header (MCTP_MESSAGE_TYPE_SPDM) + SPDM message * * @param spdm_context A pointer to the SPDM context. * @param session_id Indicates if it is a secured message protected via SPDM session. * If *session_id is NULL, it is a normal message. * If *session_id is NOT NULL, it is a secured message. * @param is_app_message Indicates if it is an APP message or SPDM message. * @param is_requester Indicates if it is a requester message. * @param transport_message_size size in bytes of the transport message data buffer. * @param transport_message A pointer to a source buffer to store the transport message. * For normal message or secured message, it shall point to acquired receiver buffer. * @param message_size size in bytes of the message data buffer. * @param message A pointer to a destination buffer to store the message. * On input, it shall point to the scratch buffer in spdm_context. * On output, for normal message, it will point to the original receiver buffer. * On output, for secured message, it will point to the scratch buffer in spdm_context. * * @retval RETURN_SUCCESS The message is decoded successfully. * @retval RETURN_INVALID_PARAMETER The message is NULL or the message_size is zero. * @retval RETURN_UNSUPPORTED The transport_message is unsupported. **/ typedef SPDM_RETURN (*SPDM_TRANSPORT_DECODE_MESSAGE_FUNC)( IN VOID *SpdmContext, IN OUT UINT32 **SessionId, IN BOOLEAN *IsAppMessage, IN BOOLEAN IsRequester, IN UINTN TransportMessageSize, IN OUT VOID *TransportMessage, IN OUT UINTN *MessageSize, IN OUT VOID **Message ); /** * Acquire a device sender buffer for transport layer message. * * The max_msg_size must be larger than * MAX (non-secure Transport Message Header Size + * SPDM_CAPABILITIES.DataTransferSize + * max alignment pad size (transport specific), * secure Transport Message Header Size + * sizeof(spdm_secured_message_a_data_header1_t) + * length of sequence_number (transport specific) + * sizeof(spdm_secured_message_a_data_header2_t) + * sizeof(spdm_secured_message_cipher_header_t) + * App Message Header Size (transport specific) + * SPDM_CAPABILITIES.DataTransferSize + * maximum random data size (transport specific) + * AEAD MAC size (16) + * max alignment pad size (transport specific)) * * For MCTP, * Transport Message Header Size = sizeof(mctp_message_header_t) * length of sequence_number = 2 * App Message Header Size = sizeof(mctp_message_header_t) * maximum random data size = MCTP_MAX_RANDOM_NUMBER_COUNT * max alignment pad size = 0 * For PCI_DOE, * Transport Message Header Size = sizeof(pci_doe_data_object_header_t) * length of sequence_number = 0 * App Message Header Size = 0 * maximum random data size = 0 * max alignment pad size = 3 * * @param context A pointer to the SPDM context. * @param max_msg_size size in bytes of the maximum size of sender buffer. * @param msg_buf_ptr A pointer to a sender buffer. * * @retval RETURN_SUCCESS The sender buffer is acquired. **/ typedef SPDM_RETURN (*SPDM_DEVICE_ACQUIRE_SENDER_BUFFER_FUNC)( IN VOID *SpdmContext, IN OUT VOID **MsgBufPtr ); /** * Release a device sender buffer for transport layer message. * * @param context A pointer to the SPDM context. * @param msg_buf_ptr A pointer to a sender buffer. * * @retval RETURN_SUCCESS The sender buffer is Released. **/ typedef VOID (*SPDM_DEVICE_RELEASE_SENDER_BUFFER_FUNC)( IN VOID *SpdmContext, IN CONST VOID *MsgBufPtr ); /** * Acquire a device receiver buffer for transport layer message. * * The max_msg_size must be larger than * MAX (non-secure Transport Message Header Size + * SPDM_CAPABILITIES.DataTransferSize + * max alignment pad size (transport specific), * secure Transport Message Header Size + * sizeof(spdm_secured_message_a_data_header1_t) + * length of sequence_number (transport specific) + * sizeof(spdm_secured_message_a_data_header2_t) + * sizeof(spdm_secured_message_cipher_header_t) + * App Message Header Size (transport specific) + * SPDM_CAPABILITIES.DataTransferSize + * maximum random data size (transport specific) + * AEAD MAC size (16) + * max alignment pad size (transport specific)) * * For MCTP, * Transport Message Header Size = sizeof(mctp_message_header_t) * length of sequence_number = 2 * App Message Header Size = sizeof(mctp_message_header_t) * maximum random data size = MCTP_MAX_RANDOM_NUMBER_COUNT * max alignment pad size = 0 * For PCI_DOE, * Transport Message Header Size = sizeof(pci_doe_data_object_header_t) * length of sequence_number = 0 * App Message Header Size = 0 * maximum random data size = 0 * max alignment pad size = 3 * * @param context A pointer to the SPDM context. * @param max_msg_size size in bytes of the maximum size of receiver buffer. * @param msg_buf_pt A pointer to a receiver buffer. * * @retval RETURN_SUCCESS The receiver buffer is acquired. **/ typedef SPDM_RETURN (*SPDM_DEVICE_ACQUIRE_RECEIVER_BUFFER_FUNC)( IN VOID *SpdmContext, IN OUT VOID **MsgBufPtr ); /** * Release a device receiver buffer for transport layer message. * * @param context A pointer to the SPDM context. * @param msg_buf_ptr A pointer to a receiver buffer. * * @retval RETURN_SUCCESS The receiver buffer is Released. **/ typedef VOID (*SPDM_DEVICE_RELEASE_RECEIVER_BUFFER_FUNC)( IN VOID *SpdmContext, IN CONST VOID *MsgBufPtr ); typedef struct { UINT32 Version; // // DeviceType is used to create TCG event log context_data. // DeviceHandle is used to create TCG event log device_path information. // EDKII_DEVICE_IDENTIFIER *DeviceId; // // TRUE means to use PCR 0 (code) / 1 (config). // FALSE means to use PCR 2 (code) / 3 (config). // BOOLEAN IsEmbeddedDevice; // // Below 9 APIs are used to send/receive SPDM request/response. // // The request flow is: // |<--- SenderBufferSize --->| // |<--- TransportRequestBufferSize --->| // |<---MaxHeaderSize--->|<-SpdmRequestBufferSize ->| // +--+------------------+==========================+----------------+--+ // | | Transport Header | SPDM Message | Transport Tail | | // +--+------------------+==========================+----------------+--+ // ^ ^ ^ // | | | SpdmRequestBuffer // | | TransportRequestBuffer // | SenderBuffer // // AcquireSenderBuffer (&SenderBuffer, &SenderBufferSize); // SpdmRequestBuffer = SenderBuffer + TransportHeaderSize; // /* build SPDM request in SpdmRequestBuffer */ // TransportEncodeMessage (SpdmRequestBuffer, SpdmRequestBufferSize, // &TransportRequestBuffer, &TransportRequestBufferSize); // SendMessage (TransportRequestBuffer, TransportRequestBufferSize); // ReleaseSenderBuffer (SenderBuffer); // // The response flow is: // |<--- ReceiverBufferSize --->| // |<--- TransportResponseBufferSize --->| // |<-SpdmResponseBufferSize->| // +--+------------------+==========================+----------------+--+ // | | Transport Header | SPDM Message | Transport Tail | | // +--+------------------+==========================+----------------+--+ // ^ ^ ^ // | | | SpdmResponseBuffer // | | TransportResponseBuffer // | ReceiverBuffer // // AcquireReceiverBuffer (&ReceiverBuffer, &ReceiverBufferSize); // TransportResponseBuffer = ReceiverBuffer; // ReceiveMessage (&TransportResponseBuffer, &TransportResponseBufferSize); // TransportDecodeMessage (TransportResponseBuffer, TransportResponseBufferSize, // &SpdmResponseBuffer, &SpdmResponseBufferSize); // /* process SPDM response in SpdmResponseBuffer */ // ReleaseReceiverBuffer (ReceiverBuffer); // // // API required by SpdmRegisterDeviceIoFunc in libspdm // It is used to send/receive transport message (SPDM + transport header). // SPDM_DEVICE_SEND_MESSAGE_FUNC SendMessage; SPDM_DEVICE_RECEIVE_MESSAGE_FUNC ReceiveMessage; // // API required by SpdmRegisterTransportLayerFunc in libspdm // It is used to add/remove transport header for SPDM. // SPDM_TRANSPORT_ENCODE_MESSAGE_FUNC TransportEncodeMessage; SPDM_TRANSPORT_DECODE_MESSAGE_FUNC TransportDecodeMessage; // // API required by SpdmRegisterDeviceBufferFunc in libspdm // It is used to get the sender/receiver buffer for transport message (SPDM + transport header). // The size MUST be big enough to send or receive one transport message (SPDM + transport header). // Tthe sender/receiver buffer MAY be overlapped. // SPDM_DEVICE_ACQUIRE_SENDER_BUFFER_FUNC AcquireSenderBuffer; SPDM_DEVICE_RELEASE_SENDER_BUFFER_FUNC ReleaseSenderBuffer; SPDM_DEVICE_ACQUIRE_RECEIVER_BUFFER_FUNC AcquireReceiverBuffer; SPDM_DEVICE_RELEASE_RECEIVER_BUFFER_FUNC ReleaseReceiverBuffer; // // Preferred Algorithm List for SPDM negotiation. // If it is none zero, it will be used directly. // If it is zero, then the SpdmSecurityLib will set the default value. // UINT32 BaseHashAlgo; UINT32 BaseAsymAlgo; // // transfer size // UINT32 MaxSpdmMsgSize; UINT32 TransportHeaderSize; UINT32 TransportTailSize; UINT32 SenderBufferSize; UINT32 ReceiverBufferSize; EFI_GUID *SpdmIoProtocolGuid; } EDKII_SPDM_DEVICE_INFO; /** This function will send SPDM VCA, GET_CERTIFICATE, CHALLENGE, GET_MEASUREMENT, The certificate and measurement will be extended to TPM PCR/NvIndex. **/ RETURN_STATUS EFIAPI SpdmDeviceAuthenticationAndMeasurement ( IN EDKII_SPDM_DEVICE_INFO *SpdmDeviceInfo, IN EDKII_DEVICE_SECURITY_POLICY *SecurityPolicy, OUT EDKII_DEVICE_SECURITY_STATE *SecurityState ); /** This function will get SpdmIoProtocol via Context. **/ VOID * EFIAPI SpdmGetIoProtocolViaSpdmContext ( IN VOID *SpdmContext ); /** Helper function to quickly determine whether device authentication boot is enabled. @retval TRUE device authentication boot is verifiably enabled. @retval FALSE device authentication boot is either disabled or an error prevented checking. **/ BOOLEAN EFIAPI IsDeviceAuthBootEnabled ( VOID ); #endif