/** @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