summaryrefslogtreecommitdiffstats
path: root/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c')
-rw-r--r--SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c481
1 files changed, 481 insertions, 0 deletions
diff --git a/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c b/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c
new file mode 100644
index 0000000000..d61aa01698
--- /dev/null
+++ b/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmConnectionInit.c
@@ -0,0 +1,481 @@
+/** @file
+ EDKII Device Security library for SPDM device.
+ It follows the SPDM Specification.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SpdmSecurityLibInternal.h"
+
+LIST_ENTRY mSpdmDeviceContextList = INITIALIZE_LIST_HEAD_VARIABLE (mSpdmDeviceContextList);
+
+#define CONNECTUIN_FAILURE_GET_SPDM_UID_FAILED "Fail to get Spdm Uid"
+#define CONNECTUIN_FAILURE_STGNATURE_DB_FUL_STRING "The Signature database devdb is full"
+
+/**
+ record Spdm Io protocol into the context list.
+
+ @param[in] SpdmDeviceContext The SPDM context of the device.
+
+**/
+VOID
+RecordSpdmDeviceContextInList (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext
+ )
+{
+ SPDM_DEVICE_CONTEXT_INSTANCE *NewSpdmDeviceContext;
+ LIST_ENTRY *SpdmDeviceContextList;
+
+ SpdmDeviceContextList = &mSpdmDeviceContextList;
+
+ NewSpdmDeviceContext = AllocateZeroPool (sizeof (*NewSpdmDeviceContext));
+ if (NewSpdmDeviceContext == NULL) {
+ ASSERT (NewSpdmDeviceContext != NULL);
+ return;
+ }
+
+ NewSpdmDeviceContext->Signature = SPDM_DEVICE_CONTEXT_INSTANCE_SIGNATURE;
+ NewSpdmDeviceContext->SpdmDeviceContext = SpdmDeviceContext;
+
+ InsertTailList (SpdmDeviceContextList, &NewSpdmDeviceContext->Link);
+}
+
+/**
+ get Spdm Io protocol from Context list via spdm context.
+
+ @param[in] SpdmContext The SPDM context of the requester.
+
+ return a pointer to the Spdm Io protocol.
+
+**/
+VOID *
+EFIAPI
+GetSpdmIoProtocolViaSpdmContext (
+ IN VOID *SpdmContext
+ )
+{
+ LIST_ENTRY *Link;
+ SPDM_DEVICE_CONTEXT_INSTANCE *CurrentSpdmDeviceContext;
+ LIST_ENTRY *SpdmDeviceContextList;
+
+ SpdmDeviceContextList = &mSpdmDeviceContextList;
+
+ Link = GetFirstNode (SpdmDeviceContextList);
+ while (!IsNull (SpdmDeviceContextList, Link)) {
+ CurrentSpdmDeviceContext = SPDM_DEVICE_CONTEXT_INSTANCE_FROM_LINK (Link);
+
+ if (CurrentSpdmDeviceContext->SpdmDeviceContext->SpdmContext == SpdmContext) {
+ return CurrentSpdmDeviceContext->SpdmDeviceContext->SpdmIoProtocol;
+ }
+
+ Link = GetNextNode (SpdmDeviceContextList, Link);
+ }
+
+ return NULL;
+}
+
+/**
+ creates and returns Spdm Uid from the volatile variable.
+
+ @param[in] SpdmUid A pointer to Spdm Uid.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+GetSpdmUid (
+ UINT64 *SpdmUid
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarSize;
+ UINT64 Uid;
+
+ VarSize = sizeof (*SpdmUid);
+ Status = gRT->GetVariable (
+ L"SpdmUid",
+ &gEfiDeviceSecuritySpdmUidGuid,
+ NULL,
+ &VarSize,
+ &Uid
+ );
+ if (Status == EFI_NOT_FOUND) {
+ Uid = 0;
+ } else if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *SpdmUid = Uid++;
+ Status = gRT->SetVariable (
+ L"SpdmUid",
+ &gEfiDeviceSecuritySpdmUidGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Uid),
+ &Uid
+ );
+
+ return Status;
+}
+
+/**
+ Record and log the connection failure string to PCR1.
+
+ @param[in] FailureString The failure string.
+ @param[in] StringLen The length of the string.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+RecordConnectionFailureStatus (
+ IN CHAR8 *FailureString,
+ IN UINT32 StringLen
+ )
+{
+ EFI_STATUS Status;
+
+ Status = TpmMeasureAndLogData (
+ 1,
+ EV_PLATFORM_CONFIG_FLAGS,
+ FailureString,
+ StringLen,
+ FailureString,
+ StringLen
+ );
+ DEBUG ((DEBUG_INFO, "RecordConnectionFailureStatus %r\n", Status));
+ return Status;
+}
+
+/**
+ This function creates the spdm device context and init connection to the
+ responder with the device info.
+
+ @param[in] SpdmDeviceInfo A pointer to device info.
+ @param[out] SecurityState A pointer to the security state of the requester.
+
+ @return the spdm device conext after the init connection succeeds.
+
+**/
+SPDM_DEVICE_CONTEXT *
+EFIAPI
+CreateSpdmDeviceContext (
+ IN EDKII_SPDM_DEVICE_INFO *SpdmDeviceInfo,
+ OUT EDKII_DEVICE_SECURITY_STATE *SecurityState
+ )
+{
+ SPDM_DEVICE_CONTEXT *SpdmDeviceContext;
+ VOID *SpdmContext;
+ UINTN SpdmContextSize;
+ VOID *ScratchBuffer;
+ UINTN ScratchBufferSize;
+ EFI_STATUS Status;
+ SPDM_RETURN SpdmReturn;
+ EFI_SIGNATURE_LIST *DbList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ UINTN Index;
+ UINTN SiglistHeaderSize;
+ UINTN DbSize;
+ VOID *Data;
+ UINTN DataSize;
+ SPDM_DATA_PARAMETER Parameter;
+ UINT8 Data8;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT8 AuthState;
+
+ SpdmDeviceContext = AllocateZeroPool (sizeof (*SpdmDeviceContext));
+ if (SpdmDeviceContext == NULL) {
+ ASSERT (SpdmDeviceContext != NULL);
+ return NULL;
+ }
+
+ SpdmDeviceContext->Signature = SPDM_DEVICE_CONTEXT_SIGNATURE;
+ CopyMem (&SpdmDeviceContext->DeviceId, SpdmDeviceInfo->DeviceId, sizeof (EDKII_DEVICE_IDENTIFIER));
+ SpdmDeviceContext->IsEmbeddedDevice = SpdmDeviceInfo->IsEmbeddedDevice;
+
+ SpdmContextSize = SpdmGetContextSize ();
+ SpdmContext = AllocateZeroPool (SpdmContextSize);
+ if (SpdmContext == NULL) {
+ ASSERT (SpdmContext != NULL);
+ goto Error;
+ }
+
+ SpdmReturn = SpdmInitContext (SpdmContext);
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ goto Error;
+ }
+
+ SpdmRegisterDeviceIoFunc (
+ SpdmContext,
+ SpdmDeviceInfo->SendMessage,
+ SpdmDeviceInfo->ReceiveMessage
+ );
+ SpdmRegisterTransportLayerFunc (
+ SpdmContext,
+ SpdmDeviceInfo->MaxSpdmMsgSize,
+ SpdmDeviceInfo->TransportHeaderSize,
+ SpdmDeviceInfo->TransportTailSize,
+ SpdmDeviceInfo->TransportEncodeMessage,
+ SpdmDeviceInfo->TransportDecodeMessage
+ );
+
+ SpdmRegisterDeviceBufferFunc (
+ SpdmContext,
+ SpdmDeviceInfo->SenderBufferSize,
+ SpdmDeviceInfo->ReceiverBufferSize,
+ SpdmDeviceInfo->AcquireSenderBuffer,
+ SpdmDeviceInfo->ReleaseSenderBuffer,
+ SpdmDeviceInfo->AcquireReceiverBuffer,
+ SpdmDeviceInfo->ReleaseReceiverBuffer
+ );
+
+ ScratchBufferSize = SpdmGetSizeofRequiredScratchBuffer (SpdmContext);
+ ScratchBuffer = AllocateZeroPool (ScratchBufferSize);
+ if (ScratchBuffer == NULL) {
+ ASSERT (ScratchBuffer != NULL);
+ goto Error;
+ }
+
+ SpdmSetScratchBuffer (SpdmContext, ScratchBuffer, ScratchBufferSize);
+
+ SpdmDeviceContext->SpdmContextSize = SpdmContextSize;
+ SpdmDeviceContext->SpdmContext = SpdmContext;
+ SpdmDeviceContext->ScratchBufferSize = ScratchBufferSize;
+ SpdmDeviceContext->ScratchBuffer = ScratchBuffer;
+
+ Status = gBS->HandleProtocol (
+ SpdmDeviceContext->DeviceId.DeviceHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&SpdmDeviceContext->DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate - DevicePath - %r\n", Status));
+ goto Error;
+ }
+
+ Status = gBS->HandleProtocol (
+ SpdmDeviceContext->DeviceId.DeviceHandle,
+ &SpdmDeviceContext->DeviceId.DeviceType,
+ (VOID **)&SpdmDeviceContext->DeviceIo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate - DeviceIo - %r\n", Status));
+ // This is optional, only check known device type later.
+ }
+
+ if (SpdmDeviceInfo->SpdmIoProtocolGuid != NULL) {
+ Status = gBS->HandleProtocol (
+ SpdmDeviceContext->DeviceId.DeviceHandle,
+ SpdmDeviceInfo->SpdmIoProtocolGuid,
+ (VOID **)&SpdmDeviceContext->SpdmIoProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate - SpdmIoProtocol - %r\n", Status));
+ goto Error;
+ }
+ }
+
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid)) {
+ if (SpdmDeviceContext->DeviceIo == NULL) {
+ DEBUG ((DEBUG_ERROR, "Locate - PciIo - %r\n", Status));
+ goto Error;
+ }
+ }
+
+ Status = GetSpdmUid (&SpdmDeviceContext->DeviceUID);
+ if (EFI_ERROR (Status)) {
+ Status = RecordConnectionFailureStatus (
+ CONNECTUIN_FAILURE_GET_SPDM_UID_FAILED,
+ sizeof (CONNECTUIN_FAILURE_GET_SPDM_UID_FAILED)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "Fail to get UID - %r\n", Status));
+ goto Error;
+ }
+
+ RecordSpdmDeviceContextInList (SpdmDeviceContext);
+
+ Status = GetVariable2 (
+ EFI_DEVICE_SECURITY_DATABASE,
+ &gEfiDeviceSignatureDatabaseGuid,
+ (VOID **)&SpdmDeviceContext->SignatureList,
+ &SpdmDeviceContext->SignatureListSize
+ );
+ if ((!EFI_ERROR (Status)) && (SpdmDeviceContext->SignatureList != NULL)) {
+ DbList = SpdmDeviceContext->SignatureList;
+ DbSize = SpdmDeviceContext->SignatureListSize;
+ while ((DbSize > 0) && (SpdmDeviceContext->SignatureListSize >= DbList->SignatureListSize)) {
+ if (DbList->SignatureListSize == 0) {
+ break;
+ }
+
+ if ( (!CompareGuid (&DbList->SignatureType, &gEfiCertX509Guid))
+ || (DbList->SignatureHeaderSize != 0)
+ || (DbList->SignatureSize < sizeof (EFI_SIGNATURE_DATA)))
+ {
+ DbSize -= DbList->SignatureListSize;
+ DbList = (EFI_SIGNATURE_LIST *)((UINT8 *)DbList + DbList->SignatureListSize);
+ continue;
+ }
+
+ SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbList->SignatureHeaderSize;
+ Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)DbList + SiglistHeaderSize);
+ CertCount = (DbList->SignatureListSize - SiglistHeaderSize) / DbList->SignatureSize;
+
+ for (Index = 0; Index < CertCount; Index++) {
+ Data = Cert->SignatureData;
+ DataSize = DbList->SignatureSize - sizeof (EFI_GUID);
+
+ ZeroMem (&Parameter, sizeof (Parameter));
+ Parameter.location = SpdmDataLocationLocal;
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataPeerPublicRootCert, &Parameter, Data, DataSize);
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ if (SpdmReturn == LIBSPDM_STATUS_BUFFER_FULL) {
+ Status = RecordConnectionFailureStatus (
+ CONNECTUIN_FAILURE_STGNATURE_DB_FUL_STRING,
+ sizeof (CONNECTUIN_FAILURE_STGNATURE_DB_FUL_STRING)
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ ASSERT (FALSE);
+ }
+
+ goto Error;
+ }
+
+ Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + DbList->SignatureSize);
+ }
+
+ DbSize -= DbList->SignatureListSize;
+ DbList = (EFI_SIGNATURE_LIST *)((UINT8 *)DbList + DbList->SignatureListSize);
+ }
+ }
+
+ Data8 = 0;
+ ZeroMem (&Parameter, sizeof (Parameter));
+ Parameter.location = SpdmDataLocationLocal;
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataCapabilityCTExponent, &Parameter, &Data8, sizeof (Data8));
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ ASSERT (FALSE);
+ goto Error;
+ }
+
+ Data32 = 0;
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataCapabilityFlags, &Parameter, &Data32, sizeof (Data32));
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ ASSERT (FALSE);
+ goto Error;
+ }
+
+ Data8 = SPDM_MEASUREMENT_SPECIFICATION_DMTF;
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataMeasurementSpec, &Parameter, &Data8, sizeof (Data8));
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ ASSERT (FALSE);
+ goto Error;
+ }
+
+ if (SpdmDeviceInfo->BaseAsymAlgo != 0) {
+ Data32 = SpdmDeviceInfo->BaseAsymAlgo;
+ } else {
+ Data32 = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048 |
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 |
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096 |
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256 |
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384 |
+ SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521;
+ }
+
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataBaseAsymAlgo, &Parameter, &Data32, sizeof (Data32));
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ ASSERT (FALSE);
+ goto Error;
+ }
+
+ if (SpdmDeviceInfo->BaseHashAlgo != 0) {
+ Data32 = SpdmDeviceInfo->BaseHashAlgo;
+ } else {
+ Data32 = SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256 |
+ SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384 |
+ SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_512;
+ }
+
+ SpdmReturn = SpdmSetData (SpdmContext, SpdmDataBaseHashAlgo, &Parameter, &Data32, sizeof (Data32));
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ ASSERT (FALSE);
+ goto Error;
+ }
+
+ SpdmReturn = SpdmInitConnection (SpdmContext, FALSE);
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ DEBUG ((DEBUG_ERROR, "SpdmInitConnection - %p\n", SpdmReturn));
+
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_SPDM;
+ SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_NO_CAPABILITIES;
+ Status = ExtendCertificate (SpdmDeviceContext, AuthState, 0, NULL, NULL, 0, 0, SecurityState);
+ if (Status != EFI_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "ExtendCertificate AUTH_STATE_NO_SPDM failed\n"));
+ }
+
+ goto Error;
+ }
+
+ ZeroMem (&Parameter, sizeof (Parameter));
+ Parameter.location = SpdmDataLocationConnection;
+ DataSize = sizeof (Data16);
+ SpdmReturn = SpdmGetData (SpdmContext, SpdmDataSpdmVersion, &Parameter, &Data16, &DataSize);
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ DEBUG ((DEBUG_ERROR, "SpdmGetData - %p\n", SpdmReturn));
+ goto Error;
+ }
+
+ SpdmDeviceContext->SpdmVersion = (Data16 >> SPDM_VERSION_NUMBER_SHIFT_BIT);
+
+ return SpdmDeviceContext;
+Error:
+ DestroySpdmDeviceContext (SpdmDeviceContext);
+ return NULL;
+}
+
+/**
+ This function destories the spdm device context.
+
+ @param[in] SpdmDeviceContext A pointer to device info.
+
+**/
+VOID
+EFIAPI
+DestroySpdmDeviceContext (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext
+ )
+{
+ // need zero memory in case of secret in memory.
+ if (SpdmDeviceContext->SpdmContext != NULL) {
+ ZeroMem (SpdmDeviceContext->SpdmContext, SpdmDeviceContext->SpdmContextSize);
+ FreePool (SpdmDeviceContext->SpdmContext);
+ }
+
+ if (SpdmDeviceContext->ScratchBuffer != NULL) {
+ ZeroMem (SpdmDeviceContext->ScratchBuffer, SpdmDeviceContext->ScratchBufferSize);
+ FreePool (SpdmDeviceContext->ScratchBuffer);
+ }
+
+ if (SpdmDeviceContext->SignatureList != NULL) {
+ ZeroMem (SpdmDeviceContext->SignatureList, SpdmDeviceContext->SignatureListSize);
+ FreePool (SpdmDeviceContext->SignatureList);
+ }
+
+ FreePool (SpdmDeviceContext);
+}