X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=SecurityPkg%2FLibrary%2FDxeImageVerificationLib%2FDxeImageVerificationLib.c;h=470a0d20efcafd7f9c7bc7ad8efeb686e0056c34;hb=5cd8be6079ea7e5638903b2f3da0f4c10ec7f1da;hp=5f09a66bc9cea32581c52fc0fe192500e21f2bde;hpb=f891b052c5ec13c1032fb9d340d5262ac1a7e7e1;p=mirror_edk2.git diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index 5f09a66bc9..470a0d20ef 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -704,7 +704,7 @@ GetImageExeInfoTableSize ( @param[in] Name Input a null-terminated, user-friendly name. @param[in] DevicePath Input device path pointer. @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure. - @param[in] SignatureSize Size of signature. + @param[in] SignatureSize Size of signature. Must be zero if Signature is NULL. **/ VOID @@ -761,6 +761,7 @@ AddImageExeInfo ( // // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align // + ASSERT (Signature != NULL || SignatureSize == 0); NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize; NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize); @@ -821,22 +822,23 @@ AddImageExeInfo ( @param[in] SignatureList Pointer to the Signature List in forbidden database. @param[in] SignatureListSize Size of Signature List. @param[out] RevocationTime Return the time that the certificate was revoked. + @param[out] IsFound Search result. Only valid if EFI_SUCCESS returned. - @return TRUE The certificate hash is found in the forbidden database. - @return FALSE The certificate hash is not found in the forbidden database. + @retval EFI_SUCCESS Finished the search without any error. + @retval Others Error occurred in the search of database. **/ -BOOLEAN +EFI_STATUS IsCertHashFoundInDatabase ( IN UINT8 *Certificate, IN UINTN CertSize, IN EFI_SIGNATURE_LIST *SignatureList, IN UINTN SignatureListSize, - OUT EFI_TIME *RevocationTime + OUT EFI_TIME *RevocationTime, + OUT BOOLEAN *IsFound ) { - BOOLEAN IsFound; - BOOLEAN Status; + EFI_STATUS Status; EFI_SIGNATURE_LIST *DbxList; UINTN DbxSize; EFI_SIGNATURE_DATA *CertHash; @@ -850,21 +852,22 @@ IsCertHashFoundInDatabase ( UINT8 *TBSCert; UINTN TBSCertSize; - IsFound = FALSE; + Status = EFI_ABORTED; + *IsFound = FALSE; DbxList = SignatureList; DbxSize = SignatureListSize; HashCtx = NULL; HashAlg = HASHALG_MAX; if ((RevocationTime == NULL) || (DbxList == NULL)) { - return FALSE; + return EFI_INVALID_PARAMETER; } // // Retrieve the TBSCertificate from the X.509 Certificate. // if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) { - return FALSE; + return Status; } while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) { @@ -894,19 +897,19 @@ IsCertHashFoundInDatabase ( if (HashCtx == NULL) { goto Done; } - Status = mHash[HashAlg].HashInit (HashCtx); - if (!Status) { + if (!mHash[HashAlg].HashInit (HashCtx)) { goto Done; } - Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize); - if (!Status) { + if (!mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize)) { goto Done; } - Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest); - if (!Status) { + if (!mHash[HashAlg].HashFinal (HashCtx, CertDigest)) { goto Done; } + FreePool (HashCtx); + HashCtx = NULL; + SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize; CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize); CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize; @@ -919,7 +922,8 @@ IsCertHashFoundInDatabase ( // // Hash of Certificate is found in forbidden database. // - IsFound = TRUE; + Status = EFI_SUCCESS; + *IsFound = TRUE; // // Return the revocation time. @@ -934,12 +938,14 @@ IsCertHashFoundInDatabase ( DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize); } + Status = EFI_SUCCESS; + Done: if (HashCtx != NULL) { FreePool (HashCtx); } - return IsFound; + return Status; } /** @@ -1212,6 +1218,7 @@ IsForbiddenByDbx ( { EFI_STATUS Status; BOOLEAN IsForbidden; + BOOLEAN IsFound; UINT8 *Data; UINTN DataSize; EFI_SIGNATURE_LIST *CertList; @@ -1233,7 +1240,7 @@ IsForbiddenByDbx ( // // Variable Initialization // - IsForbidden = FALSE; + IsForbidden = TRUE; Data = NULL; CertList = NULL; CertData = NULL; @@ -1250,7 +1257,14 @@ IsForbiddenByDbx ( // DataSize = 0; Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + ASSERT (EFI_ERROR (Status)); if (Status != EFI_BUFFER_TOO_SMALL) { + if (Status == EFI_NOT_FOUND) { + // + // Evidently not in dbx if the database doesn't exist. + // + IsForbidden = FALSE; + } return IsForbidden; } Data = (UINT8 *) AllocateZeroPool (DataSize); @@ -1322,7 +1336,7 @@ IsForbiddenByDbx ( // UINT8 Certn[]; // Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength); - if ((BufferLength == 0) || (CertBuffer == NULL)) { + if ((BufferLength == 0) || (CertBuffer == NULL) || (*CertBuffer) == 0) { IsForbidden = TRUE; goto Done; } @@ -1340,24 +1354,35 @@ IsForbiddenByDbx ( // CertPtr = CertPtr + sizeof (UINT32) + CertSize; - if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) { + Status = IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime, &IsFound); + if (EFI_ERROR (Status)) { // - // Check the timestamp signature and signing time to determine if the image can be trusted. + // Error in searching dbx. Consider it as 'found'. RevocationTime might + // not be valid in such situation. // IsForbidden = TRUE; + } else if (IsFound) { + // + // Found Cert in dbx successfully. Check the timestamp signature and + // signing time to determine if the image can be trusted. + // if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) { IsForbidden = FALSE; // // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT // continue; + } else { + IsForbidden = TRUE; + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n")); + goto Done; } - DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n")); - goto Done; } } + IsForbidden = FALSE; + Done: if (Data != NULL) { FreePool (Data); @@ -1388,6 +1413,7 @@ IsAllowedByDb ( { EFI_STATUS Status; BOOLEAN VerifyStatus; + BOOLEAN IsFound; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *CertData; UINTN DataSize; @@ -1408,65 +1434,100 @@ IsAllowedByDb ( RootCertSize = 0; VerifyStatus = FALSE; + // + // Fetch 'db' content. If 'db' doesn't exist or encounters problem to get the + // data, return not-allowed-by-db (FALSE). + // DataSize = 0; Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); - if (Status == EFI_BUFFER_TOO_SMALL) { - Data = (UINT8 *) AllocateZeroPool (DataSize); - if (Data == NULL) { - return VerifyStatus; + ASSERT (EFI_ERROR (Status)); + if (Status != EFI_BUFFER_TOO_SMALL) { + return VerifyStatus; + } + + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + return VerifyStatus; + } + + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Fetch 'dbx' content. If 'dbx' doesn't exist, continue to check 'db'. + // If any other errors occured, no need to check 'db' but just return + // not-allowed-by-db (FALSE) to avoid bypass. + // + DbxDataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL); + ASSERT (EFI_ERROR (Status)); + if (Status != EFI_BUFFER_TOO_SMALL) { + if (Status != EFI_NOT_FOUND) { + goto Done; + } + // + // 'dbx' does not exist. Continue to check 'db'. + // + } else { + // + // 'dbx' exists. Get its content. + // + DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize); + if (DbxData == NULL) { + goto Done; } - Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data); + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData); if (EFI_ERROR (Status)) { goto Done; } + } - // - // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data. - // - CertList = (EFI_SIGNATURE_LIST *) Data; - while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { - if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { - CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); - CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + // + // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; - for (Index = 0; Index < CertCount; Index++) { - // - // Iterate each Signature Data Node within this CertList for verify. - // - RootCert = CertData->SignatureData; - RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); + for (Index = 0; Index < CertCount; Index++) { + // + // Iterate each Signature Data Node within this CertList for verify. + // + RootCert = CertData->SignatureData; + RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); + // + // Call AuthenticodeVerify library to Verify Authenticode struct. + // + VerifyStatus = AuthenticodeVerify ( + AuthData, + AuthDataSize, + RootCert, + RootCertSize, + mImageDigest, + mImageDigestSize + ); + if (VerifyStatus) { // - // Call AuthenticodeVerify library to Verify Authenticode struct. + // The image is signed and its signature is found in 'db'. // - VerifyStatus = AuthenticodeVerify ( - AuthData, - AuthDataSize, - RootCert, - RootCertSize, - mImageDigest, - mImageDigestSize - ); - if (VerifyStatus) { + if (DbxData != NULL) { // // Here We still need to check if this RootCert's Hash is revoked // - Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL); - if (Status == EFI_BUFFER_TOO_SMALL) { - goto Done; - } - DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize); - if (DbxData == NULL) { - goto Done; - } - - Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData); + Status = IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime, &IsFound); if (EFI_ERROR (Status)) { - goto Done; - } - - if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) { + // + // Error in searching dbx. Consider it as 'found'. RevocationTime might + // not be valid in such situation. + // + VerifyStatus = FALSE; + } else if (IsFound) { // // Check the timestamp signature and signing time to determine if the RootCert can be trusted. // @@ -1475,17 +1536,23 @@ IsAllowedByDb ( DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n")); } } - - goto Done; } - CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize); + // + // There's no 'dbx' to check revocation time against (must-be pass), + // or, there's revocation time found in 'dbx' and checked againt 'dbt' + // (maybe pass or fail, depending on timestamp compare result). Either + // way the verification job has been completed at this point. + // + goto Done; } - } - DataSize -= CertList->SignatureListSize; - CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize); + } } + + DataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } Done: @@ -1547,7 +1614,8 @@ Done: execution table. @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not authenticate, and the platform policy dictates that the DXE - Foundation many not use File. + Foundation may not use File. The image has + been added to the file execution table. **/ EFI_STATUS @@ -1560,7 +1628,6 @@ DxeImageVerificationHandler ( IN BOOLEAN BootPolicy ) { - EFI_STATUS Status; EFI_IMAGE_DOS_HEADER *DosHdr; BOOLEAN IsVerified; EFI_SIGNATURE_LIST *SignatureList; @@ -1588,7 +1655,6 @@ DxeImageVerificationHandler ( SecDataDir = NULL; PkcsCertData = NULL; Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; - Status = EFI_ACCESS_DENIED; IsVerified = FALSE; @@ -1657,7 +1723,7 @@ DxeImageVerificationHandler ( // Read the Dos header. // if (FileBuffer == NULL) { - return EFI_INVALID_PARAMETER; + return EFI_ACCESS_DENIED; } mImageBase = (UINT8 *) FileBuffer; @@ -1676,7 +1742,7 @@ DxeImageVerificationHandler ( // The information can't be got from the invalid PeImage // DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n")); - goto Done; + goto Failed; } DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase; @@ -1698,7 +1764,7 @@ DxeImageVerificationHandler ( // It is not a valid Pe/Coff file. // DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n")); - goto Done; + goto Failed; } if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { @@ -1729,7 +1795,7 @@ DxeImageVerificationHandler ( // if (!HashPeImage (HASHALG_SHA256)) { DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr)); - goto Done; + goto Failed; } if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) { @@ -1737,7 +1803,7 @@ DxeImageVerificationHandler ( // Image Hash is in forbidden database (DBX). // DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr)); - goto Done; + goto Failed; } if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) { @@ -1751,7 +1817,7 @@ DxeImageVerificationHandler ( // Image Hash is not found in both forbidden and allowed database. // DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr)); - goto Done; + goto Failed; } // @@ -1853,7 +1919,6 @@ DxeImageVerificationHandler ( if (IsVerified) { return EFI_SUCCESS; } - Status = EFI_ACCESS_DENIED; if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) { // // Get image hash value as signature of executable. @@ -1861,7 +1926,8 @@ DxeImageVerificationHandler ( SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize; SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize); if (SignatureList == NULL) { - goto Done; + SignatureListSize = 0; + goto Failed; } SignatureList->SignatureHeaderSize = 0; SignatureList->SignatureListSize = (UINT32) SignatureListSize; @@ -1871,25 +1937,26 @@ DxeImageVerificationHandler ( CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize); } -Done: - if (Status != EFI_SUCCESS) { - // - // Policy decides to defer or reject the image; add its information in image executable information table. - // - NameStr = ConvertDevicePathToText (File, FALSE, TRUE); - AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize); - if (NameStr != NULL) { - DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr)); - FreePool(NameStr); - } - Status = EFI_SECURITY_VIOLATION; +Failed: + // + // Policy decides to defer or reject the image; add its information in image + // executable information table in either case. + // + NameStr = ConvertDevicePathToText (File, FALSE, TRUE); + AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize); + if (NameStr != NULL) { + DEBUG ((DEBUG_INFO, "The image doesn't pass verification: %s\n", NameStr)); + FreePool(NameStr); } if (SignatureList != NULL) { FreePool (SignatureList); } - return Status; + if (Policy == DEFER_EXECUTE_ON_SECURITY_VIOLATION) { + return EFI_SECURITY_VIOLATION; + } + return EFI_ACCESS_DENIED; } /**