/** @file\r
- Implement image verification services for secure boot service in UEFI2.3.1.\r
+ Implement image verification services for secure boot service\r
\r
Caution: This file requires additional review when modified.\r
This library will have external input - PE/COFF image.\r
DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r
untrusted PE/COFF image and validate its data structure within this image buffer before use.\r
\r
-Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
}\r
\r
/**\r
- Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
+ Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
PE/COFF Specification 8.0 Appendix A\r
\r
Caution: This function may receive untrusted input.\r
}\r
\r
/**\r
- Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of\r
+ Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r
Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r
8.0 Appendix A\r
\r
}\r
\r
DevicePathSize = GetDevicePathSize (DevicePath);\r
- NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) - sizeof (EFI_SIGNATURE_LIST) + NameStringLen + DevicePathSize + SignatureSize;\r
+ NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
if (NewImageExeInfoTable == NULL) {\r
return ;\r
UINT8 CertDigest[MAX_DIGEST_SIZE];\r
UINT8 *DbxCertHash;\r
UINTN SiglistHeaderSize;\r
+ UINT8 *TBSCert;\r
+ UINTN TBSCertSize;\r
\r
IsFound = FALSE;\r
DbxList = SignatureList;\r
HashCtx = NULL;\r
HashAlg = HASHALG_MAX;\r
\r
- ASSERT (RevocationTime != NULL);\r
- ASSERT (DbxList != NULL);\r
+ if ((RevocationTime == NULL) || (DbxList == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Retrieve the TBSCertificate from the X.509 Certificate.\r
+ //\r
+ if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {\r
+ return FALSE;\r
+ }\r
\r
while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {\r
//\r
}\r
\r
//\r
- // Calculate the hash value of current db certificate for comparision.\r
+ // Calculate the hash value of current TBSCertificate for comparision.\r
//\r
if (mHash[HashAlg].GetContextSize == NULL) {\r
goto Done;\r
if (!Status) {\r
goto Done;\r
}\r
- Status = mHash[HashAlg].HashUpdate (HashCtx, Certificate, CertSize);\r
+ Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);\r
if (!Status) {\r
goto Done;\r
}\r
BOOLEAN IsForbidden;\r
UINT8 *Data;\r
UINTN DataSize;\r
+ EFI_SIGNATURE_LIST *CertList;\r
+ UINTN CertListSize;\r
+ EFI_SIGNATURE_DATA *CertData;\r
+ UINT8 *RootCert;\r
+ UINTN RootCertSize;\r
+ UINTN CertCount;\r
UINTN Index;\r
UINT8 *CertBuffer;\r
UINTN BufferLength;\r
//\r
IsForbidden = FALSE;\r
Data = NULL;\r
+ CertList = NULL;\r
+ CertData = NULL;\r
+ RootCert = NULL;\r
+ RootCertSize = 0;\r
Cert = NULL;\r
CertBuffer = NULL;\r
BufferLength = 0;\r
return IsForbidden;\r
}\r
\r
+ //\r
+ // Verify image signature with RAW X509 certificates in DBX database.\r
+ // If passed, the image will be forbidden.\r
+ //\r
+ CertList = (EFI_SIGNATURE_LIST *) Data;\r
+ CertListSize = DataSize;\r
+ while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {\r
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+\r
+ for (Index = 0; Index < CertCount; Index++) {\r
+ //\r
+ // Iterate each Signature Data Node within this CertList for verify.\r
+ //\r
+ RootCert = CertData->SignatureData;\r
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r
+\r
+ //\r
+ // Call AuthenticodeVerify library to Verify Authenticode struct.\r
+ //\r
+ IsForbidden = AuthenticodeVerify (\r
+ AuthData,\r
+ AuthDataSize,\r
+ RootCert,\r
+ RootCertSize,\r
+ mImageDigest,\r
+ mImageDigestSize\r
+ );\r
+ if (IsForbidden) {\r
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);\r
+ goto Done;\r
+ }\r
+\r
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);\r
+ }\r
+ }\r
+\r
+ CertListSize -= CertList->SignatureListSize;\r
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+ }\r
+\r
+ //\r
+ // Check X.509 Certificate Hash & Possible Timestamp.\r
+ //\r
+\r
//\r
// Retrieve the certificate stack from AuthData\r
// The output CertStack format will be:\r
}\r
\r
//\r
- // Check if any certificates in AuthData is in the forbidden database.\r
+ // Check if any hash of certificates embedded in AuthData is in the forbidden database.\r
//\r
CertNumber = (UINT8) (*CertBuffer);\r
CertPtr = CertBuffer + 1;\r
for (Index = 0; Index < CertNumber; Index++) {\r
CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);\r
Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r
- if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Cert, &gEfiCertX509Guid, CertSize)) {\r
- //\r
- // Raw certificate in dbx means the image signed by the certificate is forbidden.\r
- //\r
- IsForbidden = TRUE;\r
- goto Done;\r
- }\r
\r
if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {\r
//\r
UINTN RootCertSize;\r
UINTN Index;\r
UINTN CertCount;\r
+ UINTN DbxDataSize;\r
+ UINT8 *DbxData;\r
+ EFI_TIME RevocationTime;\r
\r
Data = NULL;\r
CertList = NULL;\r
Cert = NULL;\r
RootCert = NULL;\r
+ DbxData = NULL;\r
RootCertSize = 0;\r
VerifyStatus = FALSE;\r
\r
mImageDigestSize\r
);\r
if (VerifyStatus) {\r
- SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+ //\r
+ // Here We still need to check if this RootCert's Hash is revoked\r
+ //\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ goto Done;\r
+ }\r
+ DbxData = (UINT8 *) AllocateZeroPool (DataSize);\r
+ if (DbxData == NULL) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {\r
+ //\r
+ // Check the timestamp signature and signing time to determine if the image can be trusted.\r
+ //\r
+ VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r
+ }\r
+\r
goto Done;\r
}\r
\r
}\r
\r
Done:\r
+ if (VerifyStatus) {\r
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r
+ }\r
+\r
if (Data != NULL) {\r
FreePool (Data);\r
}\r
+ if (DbxData != NULL) {\r
+ FreePool (DbxData);\r
+ }\r
\r
return VerifyStatus;\r
}\r