示例#1
0
/**
  The handler is used to do the authentication for FMP capsule based upon
  EFI_FIRMWARE_IMAGE_AUTHENTICATION.

  Caution: This function may receive untrusted input.

  This function assumes the caller AuthenticateFmpImage()
  already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION.

  @param[in]  Image                   Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
  @param[in]  ImageSize               Size of the authentication image in bytes.
  @param[in]  PublicKeyData           The public key data used to validate the signature.
  @param[in]  PublicKeyDataLength     The length of the public key data.

  @retval RETURN_SUCCESS            Authentication pass.
                                    The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
  @retval RETURN_SECURITY_VIOLATION Authentication fail.
                                    The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
  @retval RETURN_INVALID_PARAMETER  The image is in an invalid format.
                                    The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
  @retval RETURN_OUT_OF_RESOURCES   No Authentication handler associated with CertType.
                                    The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
**/
RETURN_STATUS
FmpAuthenticatedHandlerPkcs7 (
  IN EFI_FIRMWARE_IMAGE_AUTHENTICATION  *Image,
  IN UINTN                              ImageSize,
  IN CONST UINT8                        *PublicKeyData,
  IN UINTN                              PublicKeyDataLength
  )
{
  RETURN_STATUS                             Status;
  BOOLEAN                                   CryptoStatus;
  VOID                                      *P7Data;
  UINTN                                     P7Length;
  VOID                                      *TempBuffer;

  DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));

  P7Length = Image->AuthInfo.Hdr.dwLength - (OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData));
  P7Data = Image->AuthInfo.CertData;

  // It is a signature across the variable data and the Monotonic Count value.
  TempBuffer = AllocatePool(ImageSize - Image->AuthInfo.Hdr.dwLength);
  if (TempBuffer == NULL) {
    DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: TempBuffer == NULL\n"));
    Status = RETURN_OUT_OF_RESOURCES;
    goto Done;
  }

  CopyMem(
    TempBuffer,
    (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength,
    ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength
    );
  CopyMem(
    (UINT8 *)TempBuffer + ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength,
    &Image->MonotonicCount,
    sizeof(Image->MonotonicCount)
    );
  CryptoStatus = Pkcs7Verify(
                   P7Data,
                   P7Length,
                   PublicKeyData,
                   PublicKeyDataLength,
                   (UINT8 *)TempBuffer,
                   ImageSize - Image->AuthInfo.Hdr.dwLength
                   );
  FreePool(TempBuffer);
  if (!CryptoStatus) {
    //
    // If PKCS7 signature verification fails, AUTH tested failed bit is set.
    //
    DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: Pkcs7Verify() failed\n"));
    Status = RETURN_SECURITY_VIOLATION;
    goto Done;
  }
  DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7: PASS verification\n"));

  Status = RETURN_SUCCESS;

Done:
  return Status;
}
/**
  Verifies the validility of a PE/COFF Authenticode Signature as described in "Windows
  Authenticode Portable Executable Signature Format".

  If AuthData is NULL, then return FALSE.
  If ImageHash is NULL, then return FALSE.

  Caution: This function may receive untrusted input.
  PE/COFF Authenticode is external input, so this function will do basic check for
  Authenticode data structure.

  @param[in]  AuthData     Pointer to the Authenticode Signature retrieved from signed
                           PE/COFF image to be verified.
  @param[in]  DataSize     Size of the Authenticode Signature in bytes.
  @param[in]  TrustedCert  Pointer to a trusted/root certificate encoded in DER, which
                           is used for certificate chain verification.
  @param[in]  CertSize     Size of the trusted certificate in bytes.
  @param[in]  ImageHash    Pointer to the original image file hash value. The procudure
                           for calculating the image hash value is described in Authenticode
                           specification.
  @param[in]  HashSize     Size of Image hash value in bytes.

  @retval  TRUE   The specified Authenticode Signature is valid.
  @retval  FALSE  Invalid Authenticode Signature.

**/
BOOLEAN
EFIAPI
AuthenticodeVerify (
  IN  CONST UINT8  *AuthData,
  IN  UINTN        DataSize,
  IN  CONST UINT8  *TrustedCert,
  IN  UINTN        CertSize,
  IN  CONST UINT8  *ImageHash,
  IN  UINTN        HashSize
  )
{
  BOOLEAN      Status;
  PKCS7        *Pkcs7;
  CONST UINT8  *OrigAuthData;
  UINT8        *SpcIndirectDataContent;
  UINT8        Asn1Byte;
  UINTN        ContentSize;
  UINT8        *SpcIndirectDataOid;

  //
  // Check input parameters.
  //
  if ((AuthData == NULL) || (TrustedCert == NULL) || (ImageHash == NULL)) {
    return FALSE;
  }

  if ((DataSize > INT_MAX) || (CertSize > INT_MAX) || (HashSize > INT_MAX)) {
    return FALSE;
  }

  Status       = FALSE;
  Pkcs7        = NULL;
  OrigAuthData = AuthData;

  //
  // Retrieve & Parse PKCS#7 Data (DER encoding) from Authenticode Signature
  //
  Pkcs7 = d2i_PKCS7 (NULL, &AuthData, (int)DataSize);
  if (Pkcs7 == NULL) {
    goto _Exit;
  }

  //
  // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
  //
  if (!PKCS7_type_is_signed (Pkcs7)) {
    goto _Exit;
  }

  //
  // NOTE: OpenSSL PKCS7 Decoder didn't work for Authenticode-format signed data due to
  //       some authenticode-specific structure. Use opaque ASN.1 string to retrieve
  //       PKCS#7 ContentInfo here.
  //
  SpcIndirectDataOid = (UINT8 *)(Pkcs7->d.sign->contents->type->data);
  if (CompareMem (
        SpcIndirectDataOid,
        mSpcIndirectOidValue,
        sizeof (mSpcIndirectOidValue)
        ) != 0) {
    //
    // Un-matched SPC_INDIRECT_DATA_OBJID.
    //
    goto _Exit;
  }  


  SpcIndirectDataContent = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data);

  //
  // Retrieve the SEQUENCE data size from ASN.1-encoded SpcIndirectDataContent.
  //
  Asn1Byte = *(SpcIndirectDataContent + 1);

  if ((Asn1Byte & 0x80) == 0) {
    //
    // Short Form of Length Encoding
    //
    ContentSize = (UINTN) (Asn1Byte & 0x7F);
    //
    // Skip the SEQUENCE Tag;
    //
    SpcIndirectDataContent += 2;
  } else if ((Asn1Byte & 0x82) == 0x82) {
    //
    // Long Form of Length Encoding, only support two bytes.
    //
    ContentSize = (UINTN) (*(UINT8 *)(SpcIndirectDataContent + 2));
    ContentSize = (ContentSize << 8) + (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 3));
    //
    // Skip the SEQUENCE Tag;
    //
    SpcIndirectDataContent += 4;
  } else {
    goto _Exit;
  }

  //
  // Compare the original file hash value to the digest retrieve from SpcIndirectDataContent
  // defined in Authenticode
  // NOTE: Need to double-check HashLength here!
  //
  if (CompareMem (SpcIndirectDataContent + ContentSize - HashSize, ImageHash, HashSize) != 0) {
    //
    // Un-matched PE/COFF Hash Value
    //
    goto _Exit;
  }

  //
  // Verifies the PKCS#7 Signed Data in PE/COFF Authenticode Signature
  //
  Status = (BOOLEAN) Pkcs7Verify (OrigAuthData, DataSize, TrustedCert, CertSize, SpcIndirectDataContent, ContentSize);

_Exit:
  //
  // Release Resources
  //
  PKCS7_free (Pkcs7);

  return Status;
}
示例#3
0
/**
  Check whether the PKCS7 signedData is revoked by verifying with the revoked
  certificates database, and if the signedData is timestamped, the embedded timestamp
  couterSignature will be checked with the supplied timestamp database.

  @param[in]  SignedData      Pointer to buffer containing ASN.1 DER-encoded PKCS7
                              signature.
  @param[in]  SignedDataSize  The size of SignedData buffer in bytes.
  @param[in]  InData          Pointer to the buffer containing the raw message data
                              previously signed and to be verified.
  @param[in]  InDataSize      The size of InData buffer in bytes.
  @param[in]  RevokedDb       Pointer to a list of pointers to EFI_SIGNATURE_LIST
                              structure which contains list of X.509 certificates
                              of revoked signers and revoked content hashes.
  @param[in]  TimeStampDb     Pointer to a list of pointers to EFI_SIGNATURE_LIST
                              structures which is used to pass a list of X.509
                              certificates of trusted timestamp signers.

  @retval  EFI_SUCCESS             The PKCS7 signedData is revoked.
  @retval  EFI_SECURITY_VIOLATION  Fail to verify the signature in PKCS7 signedData.
  @retval  EFI_INVALID_PARAMETER   SignedData is NULL or SignedDataSize is zero.
                                   AllowedDb is NULL.
                                   Content is not NULL and ContentSize is NULL.
  @retval  EFI_NOT_FOUND           Content not found because InData is NULL and no
                                   content embedded in PKCS7 signedData.
  @retval  EFI_UNSUPPORTED         The PKCS7 signedData was not correctly formatted.

**/
EFI_STATUS
P7CheckRevocation (
  IN UINT8                *SignedData,
  IN UINTN                SignedDataSize,
  IN UINT8                *InData,
  IN UINTN                InDataSize,
  IN EFI_SIGNATURE_LIST   **RevokedDb,
  IN EFI_SIGNATURE_LIST   **TimeStampDb
  )
{
  EFI_STATUS          Status;
  EFI_SIGNATURE_LIST  *SigList;
  EFI_SIGNATURE_DATA  *SigData;
  UINT8               *RevokedCert;
  UINTN               RevokedCertSize;
  UINTN               Index;
  UINT8               *CertBuffer;
  UINTN               BufferLength;
  UINT8               *TrustedCert;
  UINTN               TrustedCertLength;
  UINT8               CertNumber;
  UINT8               *CertPtr;
  UINT8               *Cert;
  UINTN               CertSize;
  EFI_TIME            RevocationTime;

  Status          = EFI_UNSUPPORTED;
  SigData         = NULL;
  RevokedCert     = NULL;
  RevokedCertSize = 0;
  CertBuffer      = NULL;
  TrustedCert     = NULL;

  //
  // The signedData is revoked if the hash of content existed in RevokedDb
  //
  if (IsContentHashRevoked (InData, InDataSize, RevokedDb)) {
    Status = EFI_SUCCESS;
    goto _Exit;
  }

  //
  // Check if the signer's certificate can be found in Revoked database
  //
  for (Index = 0; ; Index++) {
    SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);

    //
    // The list is terminated by a NULL pointer.
    //
    if (SigList == NULL) {
      break;
    }

    //
    // Ignore any non-X509-format entry in the list.
    //
    if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
      continue;
    }

    SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
                                      SigList->SignatureHeaderSize);

    RevokedCert     = SigData->SignatureData;
    RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);

    //
    // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
    //
    if (Pkcs7Verify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InData, InDataSize)) {
      //
      // The signedData was verified by one entry in Revoked Database
      //
      Status = EFI_SUCCESS;
      break;
    }
  }

  if (!EFI_ERROR (Status)) {
    //
    // The signedData was revoked, since it was hit by RevokedDb
    //
    goto _Exit;
  }

  //
  // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
  //
  if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {
    goto _Exit;
  }

  Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
  if ((BufferLength == 0) || (CertBuffer == NULL)) {
    Status = EFI_SUCCESS;
    goto _Exit;
  }

  //
  // Check if any hash of certificates embedded in P7 data is in the revoked database.
  //
  CertNumber = (UINT8) (*CertBuffer);
  CertPtr    = CertBuffer + 1;
  for (Index = 0; Index < CertNumber; Index++) {
    //
    // Retrieve the Certificate data
    //
    CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);
    Cert     = (UINT8 *)CertPtr + sizeof (UINT32);

    if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {
      //
      // Check the timestamp signature and signing time to determine if p7 data can be trusted.
      //
      Status = EFI_SUCCESS;
      if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {
        //
        // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
        // occured prior to the time of certificate revocation.
        //
        Status = EFI_NOT_READY;
      }

      goto _Exit;
    }

    CertPtr = CertPtr + sizeof (UINT32) + CertSize;
  }

_Exit:
  Pkcs7FreeSigners (CertBuffer);
  Pkcs7FreeSigners (TrustedCert);

  return Status;
}
示例#4
0
/**
  Check whether the PKCS7 signedData can be verified by the trusted certificates
  database, and return the content of the signedData if requested.

  @param[in]  SignedData      Pointer to buffer containing ASN.1 DER-encoded PKCS7
                              signature.
  @param[in]  SignedDataSize  The size of SignedData buffer in bytes.
  @param[in]  InData          Pointer to the buffer containing the raw message data
                              previously signed and to be verified.
  @param[in]  InDataSize      The size of InData buffer in bytes.
  @param[in]  AllowedDb       Pointer to a list of pointers to EFI_SIGNATURE_LIST
                              structures which contains lists of X.509 certificates
                              of approved signers.

  @retval  EFI_SUCCESS             The PKCS7 signedData is trusted.
  @retval  EFI_SECURITY_VIOLATION  Fail to verify the signature in PKCS7 signedData.
  @retval  EFI_INVALID_PARAMETER   SignedData is NULL or SignedDataSize is zero.
                                   AllowedDb is NULL.
                                   Content is not NULL and ContentSize is NULL.
  @retval  EFI_NOT_FOUND           Content not found because InData is NULL and no
                                   content embedded in PKCS7 signedData.
  @retval  EFI_UNSUPPORTED         The PKCS7 signedData was not correctly formatted.
  @retval  EFI_BUFFER_TOO_SMALL    The size of buffer indicated by ContentSize is too
                                   small to hold the content. ContentSize updated to
                                   the required size.

**/
EFI_STATUS
P7CheckTrust (
  IN UINT8               *SignedData,
  IN UINTN               SignedDataSize,
  IN UINT8               *InData,
  IN UINTN               InDataSize,
  IN EFI_SIGNATURE_LIST  **AllowedDb
  )
{
  EFI_STATUS          Status;
  EFI_SIGNATURE_LIST  *SigList;
  EFI_SIGNATURE_DATA  *SigData;
  UINT8               *TrustCert;
  UINTN               TrustCertSize;
  UINTN               Index;

  Status        = EFI_SECURITY_VIOLATION;
  SigData       = NULL;
  TrustCert     = NULL;
  TrustCertSize = 0;

  if (AllowedDb == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Build Certificate Stack with all valid X509 certificates in the supplied
  // Signature List for PKCS7 Verification.
  //
  for (Index = 0; ; Index++) {
    SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);

    //
    // The list is terminated by a NULL pointer.
    //
    if (SigList == NULL) {
      break;
    }

    //
    // Ignore any non-X509-format entry in the list.
    //
    if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
      continue;
    }

    SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
                                      SigList->SignatureHeaderSize);

    TrustCert     = SigData->SignatureData;
    TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);

    //
    // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
    //
    if (Pkcs7Verify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InData, InDataSize)) {
      //
      // The SignedData was verified successfully by one entry in Trusted Database
      //
      Status = EFI_SUCCESS;
      break;
    }
  }

  return Status;
}
示例#5
0
/**
  Validate UEFI-OpenSSL PKCS#7 Signing & Verification Interfaces.

  @retval  EFI_SUCCESS  Validation succeeded.
  @retval  EFI_ABORTED  Validation failed.

**/
EFI_STATUS
ValidateCryptPkcs7 (
  VOID
  )
{
  BOOLEAN  Status;
  UINT8    *P7SignedData;
  UINTN    P7SignedDataSize;
  UINT8    *SignCert;

  P7SignedData = NULL;
  SignCert     = NULL;

  Print (L"\nUEFI-OpenSSL PKCS#7 Signing & Verification Testing: ");

  Print (L"\n- Create PKCS#7 signedData ...");

  //
  // Construct Signer Certificate from RAW data.
  //
  Status = X509ConstructCertificate (TestCert, sizeof (TestCert), (UINT8 **) &SignCert);
  if (!Status || SignCert == NULL) {
    Print (L"[Fail]");
    goto _Exit;
  } else {
    Print (L"[Pass]");
  }

  //
  // Create PKCS#7 signedData on Payload.
  // Note: Caller should release P7SignedData manually.
  //
  Status = Pkcs7Sign (
             TestKeyPem,
             sizeof (TestKeyPem),
             (CONST UINT8 *) PemPass,
             (UINT8 *) Payload,
             AsciiStrLen (Payload),
             SignCert,
             NULL,
             &P7SignedData,
             &P7SignedDataSize
             );
  if (!Status || P7SignedDataSize == 0) {
    Print (L"[Fail]");
    goto _Exit;
  } else {
    Print (L"[Pass]");
  }

  Print (L"\n- Verify PKCS#7 signedData ...");

  Status = Pkcs7Verify (
             P7SignedData,
             P7SignedDataSize,
             TestCACert,
             sizeof (TestCACert),
             (UINT8 *) Payload,
             AsciiStrLen (Payload)
             );
  if (!Status) {
    Print (L"[Fail]");
  } else {
    Print (L"[Pass]");
  }

_Exit:
  if (P7SignedData != NULL) {
    FreePool (P7SignedData);
  }
  if (SignCert != NULL) {
    X509Free (SignCert);
  }

  Print (L"\n");
  return EFI_SUCCESS;
}