/** @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 **/ #include "SpdmSecurityLibInternal.h" /** Measure and log an EFI variable, and extend the measurement result into a specific PCR. @param[in] PcrIndex PCR Index. @param[in] EventType Event type. @param[in] VarName A Null-terminated string that is the name of the vendor's variable. @param[in] VendorGuid A unique identifier for the vendor. @param[in] VarData The content of the variable data. @param[in] VarSize The size of the variable data. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS EFIAPI MeasureVariable ( IN UINT32 PcrIndex, IN UINT32 EventType, IN CHAR16 *VarName, IN EFI_GUID *VendorGuid, IN VOID *VarData, IN UINTN VarSize ) { EFI_STATUS Status; UINTN VarNameLength; UEFI_VARIABLE_DATA *VarLog; UINT32 VarLogSize; if (!(((VarSize == 0) && (VarData == NULL)) || ((VarSize != 0) && (VarData != NULL)))) { ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); return EFI_INVALID_PARAMETER; } VarNameLength = StrLen (VarName); VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); VarLog = (UEFI_VARIABLE_DATA *)AllocateZeroPool (VarLogSize); if (VarLog == NULL) { return EFI_OUT_OF_RESOURCES; } CopyMem (&VarLog->VariableName, VendorGuid, sizeof (VarLog->VariableName)); VarLog->UnicodeNameLength = VarNameLength; VarLog->VariableDataLength = VarSize; CopyMem ( VarLog->UnicodeName, VarName, VarNameLength * sizeof (*VarName) ); if (VarSize != 0) { CopyMem ( (CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData, VarSize ); } DEBUG ((DEBUG_INFO, "VariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PcrIndex, (UINTN)EventType)); DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); Status = TpmMeasureAndLogData ( PcrIndex, EventType, VarLog, VarLogSize, VarLog, VarLogSize ); FreePool (VarLog); return Status; } /** Extend Certicate and auth state to NV Index and measure trust anchor to PCR. @param[in] SpdmDeviceContext The SPDM context for the device. @param[in] AuthState The auth state of this deice. @param[in] CertChainSize The size of cert chain. @param[in] CertChain A pointer to a destination buffer to store the certificate chain. @param[in] TrustAnchor A buffer to hold the trust_anchor which is used to validate the peer certificate, if not NULL. @param[in] TrustAnchorSize A buffer to hold the trust_anchor_size, if not NULL.. @param[in] SlotId The number of slot for the certificate chain. @param[out] SecurityState A pointer to the security state of the requester. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS ExtendCertificate ( IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext, IN UINT8 AuthState, IN UINTN CertChainSize, IN UINT8 *CertChain, IN VOID *TrustAnchor, IN UINTN TrustAnchorSize, IN UINT8 SlotId, OUT EDKII_DEVICE_SECURITY_STATE *SecurityState ) { VOID *EventLog; UINT32 EventLogSize; UINT8 *EventLogPtr; TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT *NvIndexInstance; TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2 *EventData2; TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN *TcgSpdmCertChain; VOID *DeviceContext; UINTN DeviceContextSize; EFI_STATUS Status; UINTN DevicePathSize; UINT32 BaseHashAlgo; UINTN DataSize; VOID *SpdmContext; SPDM_DATA_PARAMETER Parameter; EFI_SIGNATURE_DATA *SignatureData; UINTN SignatureDataSize; SpdmContext = SpdmDeviceContext->SpdmContext; EventLog = NULL; ZeroMem (&Parameter, sizeof (Parameter)); Parameter.location = SpdmDataLocationConnection; DataSize = sizeof (BaseHashAlgo); Status = SpdmGetData (SpdmContext, SpdmDataBaseHashAlgo, &Parameter, &BaseHashAlgo, &DataSize); ASSERT_EFI_ERROR (Status); DeviceContextSize = GetDeviceMeasurementContextSize (SpdmDeviceContext); DevicePathSize = GetDevicePathSize (SpdmDeviceContext->DevicePath); switch (AuthState) { case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_SUCCESS: case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_AUTH: case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_BINDING: EventLogSize = (UINT32)(sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT) + sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2) + sizeof (UINT64) + DevicePathSize + sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN) + CertChainSize + DeviceContextSize); EventLog = AllocatePool (EventLogSize); if (EventLog == NULL) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE; return EFI_OUT_OF_RESOURCES; } EventLogPtr = EventLog; NvIndexInstance = (VOID *)EventLogPtr; CopyMem (NvIndexInstance->Signature, TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE)); NvIndexInstance->Version = TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT_VERSION; ZeroMem (NvIndexInstance->Reserved, sizeof (NvIndexInstance->Reserved)); EventLogPtr += sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT); EventData2 = (VOID *)EventLogPtr; CopyMem (EventData2->Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE_2, sizeof (EventData2->Signature)); EventData2->Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION_2; EventData2->AuthState = AuthState; EventData2->Reserved = 0; EventData2->Length = (UINT32)EventLogSize; EventData2->DeviceType = GetSpdmDeviceType (SpdmDeviceContext); EventData2->SubHeaderType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_SUB_HEADER_TYPE_SPDM_CERT_CHAIN; EventData2->SubHeaderLength = (UINT32)(sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN) + CertChainSize); EventData2->SubHeaderUID = SpdmDeviceContext->DeviceUID; EventLogPtr = (VOID *)(EventData2 + 1); *(UINT64 *)EventLogPtr = (UINT64)DevicePathSize; EventLogPtr += sizeof (UINT64); CopyMem (EventLogPtr, SpdmDeviceContext->DevicePath, DevicePathSize); EventLogPtr += DevicePathSize; TcgSpdmCertChain = (VOID *)EventLogPtr; TcgSpdmCertChain->SpdmVersion = SpdmDeviceContext->SpdmVersion; TcgSpdmCertChain->SpdmSlotId = SlotId; TcgSpdmCertChain->Reserved = 0; TcgSpdmCertChain->SpdmHashAlgo = BaseHashAlgo; EventLogPtr += sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN); CopyMem (EventLogPtr, CertChain, CertChainSize); EventLogPtr += CertChainSize; if (DeviceContextSize != 0) { DeviceContext = (VOID *)EventLogPtr; Status = CreateDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize); if (Status != EFI_SUCCESS) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; Status = EFI_DEVICE_ERROR; goto Exit; } } Status = TpmMeasureAndLogData ( TCG_NV_EXTEND_INDEX_FOR_INSTANCE, EV_NO_ACTION, EventLog, EventLogSize, EventLog, EventLogSize ); if (EFI_ERROR (Status)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR; } DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Instance) - %r\n", Status)); break; case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID: EventLogSize = (UINT32)(sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT) + sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2) + sizeof (UINT64) + DevicePathSize + sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN) + DeviceContextSize); EventLog = AllocatePool (EventLogSize); if (EventLog == NULL) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE; return EFI_OUT_OF_RESOURCES; } EventLogPtr = EventLog; NvIndexInstance = (VOID *)EventLogPtr; CopyMem (NvIndexInstance->Signature, TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE)); NvIndexInstance->Version = TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT_VERSION; ZeroMem (NvIndexInstance->Reserved, sizeof (NvIndexInstance->Reserved)); EventLogPtr += sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT); EventData2 = (VOID *)EventLogPtr; CopyMem (EventData2->Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE_2, sizeof (EventData2->Signature)); EventData2->Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION_2; EventData2->AuthState = AuthState; EventData2->Reserved = 0; EventData2->Length = (UINT32)EventLogSize; EventData2->DeviceType = GetSpdmDeviceType (SpdmDeviceContext); EventData2->SubHeaderType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_SUB_HEADER_TYPE_SPDM_CERT_CHAIN; EventData2->SubHeaderLength = sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN); EventData2->SubHeaderUID = SpdmDeviceContext->DeviceUID; EventLogPtr = (VOID *)(EventData2 + 1); *(UINT64 *)EventLogPtr = (UINT64)DevicePathSize; EventLogPtr += sizeof (UINT64); CopyMem (EventLogPtr, SpdmDeviceContext->DevicePath, DevicePathSize); EventLogPtr += DevicePathSize; TcgSpdmCertChain = (VOID *)EventLogPtr; TcgSpdmCertChain->SpdmVersion = SpdmDeviceContext->SpdmVersion; TcgSpdmCertChain->SpdmSlotId = SlotId; TcgSpdmCertChain->Reserved = 0; TcgSpdmCertChain->SpdmHashAlgo = BaseHashAlgo; EventLogPtr += sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN); if (DeviceContextSize != 0) { DeviceContext = (VOID *)EventLogPtr; Status = CreateDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize); if (Status != EFI_SUCCESS) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; Status = EFI_DEVICE_ERROR; goto Exit; } } Status = TpmMeasureAndLogData ( TCG_NV_EXTEND_INDEX_FOR_INSTANCE, EV_NO_ACTION, EventLog, EventLogSize, EventLog, EventLogSize ); if (EFI_ERROR (Status)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR; } DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Instance) - %r\n", Status)); goto Exit; case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_NO_SIG: case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_SPDM: EventLogSize = (UINT32)(sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT) + sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2) + sizeof (UINT64) + DevicePathSize + DeviceContextSize); EventLog = AllocatePool (EventLogSize); if (EventLog == NULL) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE; return EFI_OUT_OF_RESOURCES; } EventLogPtr = EventLog; NvIndexInstance = (VOID *)EventLogPtr; CopyMem (NvIndexInstance->Signature, TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_INSTANCE_SIGNATURE)); NvIndexInstance->Version = TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT_VERSION; ZeroMem (NvIndexInstance->Reserved, sizeof (NvIndexInstance->Reserved)); EventLogPtr += sizeof (TCG_NV_INDEX_INSTANCE_EVENT_LOG_STRUCT); EventData2 = (VOID *)EventLogPtr; CopyMem (EventData2->Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE_2, sizeof (EventData2->Signature)); EventData2->Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION_2; EventData2->AuthState = AuthState; EventData2->Reserved = 0; EventData2->Length = (UINT32)EventLogSize; EventData2->DeviceType = GetSpdmDeviceType (SpdmDeviceContext); EventData2->SubHeaderType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_SUB_HEADER_TYPE_SPDM_CERT_CHAIN; EventData2->SubHeaderLength = 0; EventData2->SubHeaderUID = SpdmDeviceContext->DeviceUID; EventLogPtr = (VOID *)(EventData2 + 1); *(UINT64 *)EventLogPtr = (UINT64)DevicePathSize; EventLogPtr += sizeof (UINT64); CopyMem (EventLogPtr, SpdmDeviceContext->DevicePath, DevicePathSize); EventLogPtr += DevicePathSize; if (DeviceContextSize != 0) { DeviceContext = (VOID *)EventLogPtr; Status = CreateDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize); if (Status != EFI_SUCCESS) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; Status = EFI_DEVICE_ERROR; goto Exit; } } Status = TpmMeasureAndLogData ( TCG_NV_EXTEND_INDEX_FOR_INSTANCE, EV_NO_ACTION, EventLog, EventLogSize, EventLog, EventLogSize ); if (EFI_ERROR (Status)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR; } DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Instance) - %r\n", Status)); goto Exit; default: SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_UNSUPPORTED; return EFI_UNSUPPORTED; } if ((TrustAnchor != NULL) && (TrustAnchorSize != 0)) { SignatureDataSize = sizeof (EFI_GUID) + TrustAnchorSize; SignatureData = AllocateZeroPool (SignatureDataSize); if (SignatureData == NULL) { ASSERT (SignatureData != NULL); SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE; Status = EFI_OUT_OF_RESOURCES; goto Exit; } CopyGuid (&SignatureData->SignatureOwner, &gEfiCallerIdGuid); CopyMem ( (UINT8 *)SignatureData + sizeof (EFI_GUID), TrustAnchor, TrustAnchorSize ); MeasureVariable ( PCR_INDEX_FOR_SIGNATURE_DB, EV_EFI_SPDM_DEVICE_AUTHORITY, EFI_DEVICE_SECURITY_DATABASE, &gEfiDeviceSignatureDatabaseGuid, SignatureData, SignatureDataSize ); FreePool (SignatureData); } Exit: if (EventLog != NULL) { FreePool (EventLog); } return Status; } /** Measure and log Auth state and Requester and responder Nonce into NV Index. @param[in] SpdmDeviceContext The SPDM context for the device. @param[in] AuthState The auth state of this deice. @param[in] RequesterNonce A buffer to hold the requester nonce (32 bytes), if not NULL. @param[in] ResponderNonce A buffer to hold the responder nonce (32 bytes), if not NULL. @param[out] SecurityState A pointer to the security state of the requester. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS ExtendAuthentication ( IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext, IN UINT8 AuthState, IN UINT8 *RequesterNonce, IN UINT8 *ResponderNonce, OUT EDKII_DEVICE_SECURITY_STATE *SecurityState ) { EFI_STATUS Status; { TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_SPDM_CHALLENGE DynamicEventLogSpdmChallengeEvent; TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_SPDM_CHALLENGE_AUTH DynamicEventLogSpdmChallengeAuthEvent; CopyMem (DynamicEventLogSpdmChallengeEvent.Header.Signature, TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE)); DynamicEventLogSpdmChallengeEvent.Header.Version = TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_VERSION; ZeroMem (DynamicEventLogSpdmChallengeEvent.Header.Reserved, sizeof (DynamicEventLogSpdmChallengeEvent.Header.Reserved)); DynamicEventLogSpdmChallengeEvent.Header.Uid = SpdmDeviceContext->DeviceUID; DynamicEventLogSpdmChallengeEvent.DescriptionSize = sizeof (TCG_SPDM_CHALLENGE_DESCRIPTION); CopyMem (DynamicEventLogSpdmChallengeEvent.Description, TCG_SPDM_CHALLENGE_DESCRIPTION, sizeof (TCG_SPDM_CHALLENGE_DESCRIPTION)); DynamicEventLogSpdmChallengeEvent.DataSize = SPDM_NONCE_SIZE; CopyMem (DynamicEventLogSpdmChallengeEvent.Data, RequesterNonce, SPDM_NONCE_SIZE); Status = TpmMeasureAndLogData ( TCG_NV_EXTEND_INDEX_FOR_DYNAMIC, EV_NO_ACTION, &DynamicEventLogSpdmChallengeEvent, sizeof (DynamicEventLogSpdmChallengeEvent), &DynamicEventLogSpdmChallengeEvent, sizeof (DynamicEventLogSpdmChallengeEvent) ); if (EFI_ERROR (Status)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR; } DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Dynamic) - %r\n", Status)); CopyMem (DynamicEventLogSpdmChallengeAuthEvent.Header.Signature, TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE)); DynamicEventLogSpdmChallengeAuthEvent.Header.Version = TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_VERSION; ZeroMem (DynamicEventLogSpdmChallengeAuthEvent.Header.Reserved, sizeof (DynamicEventLogSpdmChallengeAuthEvent.Header.Reserved)); DynamicEventLogSpdmChallengeAuthEvent.Header.Uid = SpdmDeviceContext->DeviceUID; DynamicEventLogSpdmChallengeAuthEvent.DescriptionSize = sizeof (TCG_SPDM_CHALLENGE_AUTH_DESCRIPTION); CopyMem (DynamicEventLogSpdmChallengeAuthEvent.Description, TCG_SPDM_CHALLENGE_AUTH_DESCRIPTION, sizeof (TCG_SPDM_CHALLENGE_AUTH_DESCRIPTION)); DynamicEventLogSpdmChallengeAuthEvent.DataSize = SPDM_NONCE_SIZE; CopyMem (DynamicEventLogSpdmChallengeAuthEvent.Data, ResponderNonce, SPDM_NONCE_SIZE); Status = TpmMeasureAndLogData ( TCG_NV_EXTEND_INDEX_FOR_DYNAMIC, EV_NO_ACTION, &DynamicEventLogSpdmChallengeAuthEvent, sizeof (DynamicEventLogSpdmChallengeAuthEvent), &DynamicEventLogSpdmChallengeAuthEvent, sizeof (DynamicEventLogSpdmChallengeAuthEvent) ); if (EFI_ERROR (Status)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR; } DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Dynamic) - %r\n", Status)); } return Status; } /** This function gets SPDM digest and certificates. @param[in] SpdmDeviceContext The SPDM context for the device. @param[out] AuthState The auth state of the devices. @param[out] ValidSlotId The number of slot for the certificate chain. @param[out] SecurityState The security state of the requester. @param[out] IsValidCertChain The validity of the certificate chain. @param[out] RootCertMatch The authority of the certificate chain. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS EFIAPI DoDeviceCertificate ( IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext, OUT UINT8 *AuthState, OUT UINT8 *ValidSlotId, OUT EDKII_DEVICE_SECURITY_STATE *SecurityState, OUT BOOLEAN *IsValidCertChain, OUT BOOLEAN *RootCertMatch ) { EFI_STATUS Status; SPDM_RETURN SpdmReturn; VOID *SpdmContext; UINT32 CapabilityFlags; UINTN DataSize; SPDM_DATA_PARAMETER Parameter; UINT8 SlotMask; UINT8 TotalDigestBuffer[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT]; UINTN CertChainSize; UINT8 CertChain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; VOID *TrustAnchor; UINTN TrustAnchorSize; UINT8 SlotId; SpdmContext = SpdmDeviceContext->SpdmContext; ZeroMem (&Parameter, sizeof (Parameter)); Parameter.location = SpdmDataLocationConnection; DataSize = sizeof (CapabilityFlags); SpdmReturn = SpdmGetData (SpdmContext, SpdmDataCapabilityFlags, &Parameter, &CapabilityFlags, &DataSize); if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; return EFI_DEVICE_ERROR; } *IsValidCertChain = FALSE; *RootCertMatch = FALSE; CertChainSize = sizeof (CertChain); ZeroMem (CertChain, sizeof (CertChain)); TrustAnchor = NULL; TrustAnchorSize = 0; // // Init *ValidSlotId to invalid slot_id // *ValidSlotId = SPDM_MAX_SLOT_COUNT; if ((CapabilityFlags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP) == 0) { *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_NO_SIG; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_NO_CAPABILITIES; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, 0, NULL, NULL, 0, 0, SecurityState); return Status; } else { ZeroMem (TotalDigestBuffer, sizeof (TotalDigestBuffer)); SpdmReturn = SpdmGetDigest (SpdmContext, NULL, &SlotMask, TotalDigestBuffer); if ((LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) || ((SlotMask & 0x01) == 0)) { *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_CERTIFIACTE_FAILURE; SlotId = 0; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, 0, NULL, NULL, 0, SlotId, SecurityState); return Status; } for (SlotId = 0; SlotId < SPDM_MAX_SLOT_COUNT; SlotId++) { if (((SlotMask >> SlotId) & 0x01) == 0) { continue; } CertChainSize = sizeof (CertChain); ZeroMem (CertChain, sizeof (CertChain)); SpdmReturn = SpdmGetCertificateEx (SpdmContext, NULL, SlotId, &CertChainSize, CertChain, (CONST VOID **)&TrustAnchor, &TrustAnchorSize); if (LIBSPDM_STATUS_IS_SUCCESS (SpdmReturn)) { *IsValidCertChain = TRUE; break; } else if (SpdmReturn == LIBSPDM_STATUS_VERIF_FAIL) { *IsValidCertChain = FALSE; *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_CERTIFIACTE_FAILURE; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, 0, NULL, NULL, 0, SlotId, SecurityState); } else if (SpdmReturn == LIBSPDM_STATUS_VERIF_NO_AUTHORITY) { *IsValidCertChain = TRUE; *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_AUTH; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_CERTIFIACTE_FAILURE; *ValidSlotId = SlotId; } } if ((SlotId >= SPDM_MAX_SLOT_COUNT) && (*ValidSlotId == SPDM_MAX_SLOT_COUNT)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; return EFI_DEVICE_ERROR; } if (TrustAnchor != NULL) { *RootCertMatch = TRUE; *ValidSlotId = SlotId; } else { *ValidSlotId = 0; } DEBUG ((DEBUG_INFO, "SpdmGetCertificateEx - SpdmReturn %p, TrustAnchorSize 0x%x, RootCertMatch %d\n", SpdmReturn, TrustAnchorSize, *RootCertMatch)); return EFI_SUCCESS; } } /** This function does authentication. @param[in] SpdmDeviceContext The SPDM context for the device. @param[out] AuthState The auth state of the devices. @param[in] ValidSlotId The number of slot for the certificate chain. @param[in] IsValidCertChain Indicate the validity of CertChain @param[in] RootCertMatch Indicate the match or mismatch for Rootcert @param[out] SecurityState The security state of the requester. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_OUT_OF_RESOURCES Out of memory. @retval EFI_DEVICE_ERROR The operation was unsuccessful. **/ EFI_STATUS EFIAPI DoDeviceAuthentication ( IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext, OUT UINT8 *AuthState, IN UINT8 ValidSlotId, IN BOOLEAN IsValidCertChain, IN BOOLEAN RootCertMatch, OUT EDKII_DEVICE_SECURITY_STATE *SecurityState ) { EFI_STATUS Status; SPDM_RETURN SpdmReturn; VOID *SpdmContext; UINT32 CapabilityFlags; UINTN DataSize; SPDM_DATA_PARAMETER Parameter; UINTN CertChainSize; UINT8 CertChain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; UINT8 RequesterNonce[SPDM_NONCE_SIZE]; UINT8 ResponderNonce[SPDM_NONCE_SIZE]; VOID *TrustAnchor; UINTN TrustAnchorSize; BOOLEAN IsValidChallengeAuthSig; SpdmContext = SpdmDeviceContext->SpdmContext; ZeroMem (&Parameter, sizeof (Parameter)); Parameter.location = SpdmDataLocationConnection; DataSize = sizeof (CapabilityFlags); SpdmReturn = SpdmGetData (SpdmContext, SpdmDataCapabilityFlags, &Parameter, &CapabilityFlags, &DataSize); if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) { SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR; return EFI_DEVICE_ERROR; } IsValidChallengeAuthSig = FALSE; // get the valid CertChain CertChainSize = sizeof (CertChain); ZeroMem (CertChain, sizeof (CertChain)); SpdmReturn = SpdmGetCertificateEx (SpdmContext, NULL, ValidSlotId, &CertChainSize, CertChain, (CONST VOID **)&TrustAnchor, &TrustAnchorSize); if ((!LIBSPDM_STATUS_IS_SUCCESS (SpdmReturn)) && (!(SpdmReturn == LIBSPDM_STATUS_VERIF_NO_AUTHORITY))) { return EFI_DEVICE_ERROR; } if ((CapabilityFlags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP) == 0) { *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_BINDING; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_NO_CAPABILITIES; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, CertChainSize, CertChain, NULL, 0, ValidSlotId, SecurityState); return Status; } else { ZeroMem (RequesterNonce, sizeof (RequesterNonce)); ZeroMem (ResponderNonce, sizeof (ResponderNonce)); SpdmReturn = SpdmChallengeEx (SpdmContext, NULL, ValidSlotId, SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, NULL, NULL, NULL, RequesterNonce, ResponderNonce, NULL, 0); if (SpdmReturn == LIBSPDM_STATUS_SUCCESS) { IsValidChallengeAuthSig = TRUE; } else if ((LIBSPDM_STATUS_IS_ERROR (SpdmReturn))) { IsValidChallengeAuthSig = FALSE; *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_CHALLENGE_FAILURE; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, 0, NULL, NULL, 0, ValidSlotId, SecurityState); return Status; } else { return EFI_DEVICE_ERROR; } if (IsValidCertChain && IsValidChallengeAuthSig && !RootCertMatch) { *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_NO_AUTH; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_NO_CERT_PROVISION; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, CertChainSize, CertChain, NULL, 0, ValidSlotId, SecurityState); } else if (IsValidCertChain && IsValidChallengeAuthSig && RootCertMatch) { *AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_SUCCESS; SecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_SUCCESS; Status = ExtendCertificate (SpdmDeviceContext, *AuthState, CertChainSize, CertChain, TrustAnchor, TrustAnchorSize, ValidSlotId, SecurityState); } Status = ExtendAuthentication (SpdmDeviceContext, *AuthState, RequesterNonce, ResponderNonce, SecurityState); } return Status; }