/** @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" | |
/** | |
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; | |
} |