X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=SecurityPkg%2FLibrary%2FDxeImageVerificationLib%2FDxeImageVerificationLib.c;h=470a0d20efcafd7f9c7bc7ad8efeb686e0056c34;hb=5cd8be6079ea7e5638903b2f3da0f4c10ec7f1da;hp=1efb2f96cdcc22d4c3e5868c1866d63eac8f35a9;hpb=9e569700901857d0ba418ebdd30b8086b908688c;p=mirror_edk2.git diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index 1efb2f96cd..470a0d20ef 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -822,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; @@ -851,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)) { @@ -895,16 +897,13 @@ 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; } @@ -923,7 +922,8 @@ IsCertHashFoundInDatabase ( // // Hash of Certificate is found in forbidden database. // - IsFound = TRUE; + Status = EFI_SUCCESS; + *IsFound = TRUE; // // Return the revocation time. @@ -938,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; } /** @@ -1216,6 +1218,7 @@ IsForbiddenByDbx ( { EFI_STATUS Status; BOOLEAN IsForbidden; + BOOLEAN IsFound; UINT8 *Data; UINTN DataSize; EFI_SIGNATURE_LIST *CertList; @@ -1237,7 +1240,7 @@ IsForbiddenByDbx ( // // Variable Initialization // - IsForbidden = FALSE; + IsForbidden = TRUE; Data = NULL; CertList = NULL; CertData = NULL; @@ -1254,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); @@ -1344,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); @@ -1392,6 +1413,7 @@ IsAllowedByDb ( { EFI_STATUS Status; BOOLEAN VerifyStatus; + BOOLEAN IsFound; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *CertData; UINTN DataSize; @@ -1412,66 +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 // - DbxDataSize = 0; - 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. // @@ -1480,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: