]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c
Add new interfaces to support PKCS7#7 signed data and authenticode signature. Update...
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptAuthenticode.c
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c
new file mode 100644 (file)
index 0000000..5f93e4a
--- /dev/null
@@ -0,0 +1,143 @@
+/** @file\r
+  Authenticode Portable Executable Signature Verification over OpenSSL.\r
+\r
+Copyright (c) 2011, 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
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalCryptLib.h"\r
+\r
+#include <openssl/objects.h>\r
+#include <openssl/x509.h>\r
+#include <openssl/pkcs7.h>\r
+\r
+\r
+/**\r
+  Verifies the validility of a PE/COFF Authenticode Signature as described in "Windows\r
+  Authenticode Portable Executable Signature Format".\r
+\r
+  If AuthData is NULL, then ASSERT().\r
+  If ImageHash is NULL, then ASSERT().\r
+\r
+  @param[in]  AuthData     Pointer to the Authenticode Signature retrieved from signed\r
+                           PE/COFF image to be verified.\r
+  @param[in]  DataSize     Size of the Authenticode Signature in bytes.\r
+  @param[in]  TrustedCert  Pointer to a trusted/root certificate encoded in DER, which\r
+                           is used for certificate chain verification.\r
+  @param[in]  CertSize     Size of the trusted certificate in bytes.\r
+  @param[in]  ImageHash    Pointer to the original image file hash value. The procudure\r
+                           for calculating the image hash value is described in Authenticode\r
+                           specification.\r
+  @param[in]  HashSize     Size of Image hash value in bytes.\r
+\r
+  @retval  TRUE   The specified Authenticode Signature is valid.\r
+  @retval  FALSE  Invalid Authenticode Signature.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+AuthenticodeVerify (\r
+  IN  CONST UINT8  *AuthData,\r
+  IN  UINTN        DataSize,\r
+  IN  CONST UINT8  *TrustedCert,\r
+  IN  UINTN        CertSize,\r
+  IN  CONST UINT8  *ImageHash,\r
+  IN  UINTN        HashSize\r
+  )\r
+{\r
+  BOOLEAN      Status;\r
+  PKCS7        *Pkcs7;\r
+  CONST UINT8  *OrigAuthData;\r
+  UINT8        *SpcIndirectDataContent;\r
+  UINT8        Asn1Byte;\r
+  UINTN        ContentSize;\r
+\r
+  //\r
+  // ASSERT if Authenticode Signature Data or PE Image Hash is NULL\r
+  //\r
+  ASSERT (AuthData  != NULL);\r
+  ASSERT (ImageHash != NULL);\r
+\r
+  Status       = FALSE;\r
+  Pkcs7        = NULL;\r
+  OrigAuthData = AuthData;\r
+\r
+  //\r
+  // Retrieve & Parse PKCS#7 Data (DER encoding) from Authenticode Signature\r
+  //\r
+  Pkcs7 = d2i_PKCS7 (NULL, &AuthData, (int)DataSize);\r
+  if (Pkcs7 == NULL) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
+  //\r
+  if (!PKCS7_type_is_signed (Pkcs7)) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // NOTE: OpenSSL PKCS7 Decoder didn't work for Authenticode-format signed data due to\r
+  //       some authenticode-specific structure. Use opaque ASN.1 string to retrieve\r
+  //       PKCS#7 ContentInfo here.\r
+  //\r
+  SpcIndirectDataContent = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data);\r
+\r
+  //\r
+  // Retrieve the SEQUENCE data size from ASN.1-encoded SpcIndirectDataContent.\r
+  //\r
+  Asn1Byte = *(SpcIndirectDataContent + 1);\r
+  if ((Asn1Byte & 0x80) == 0) {\r
+    //\r
+    // Short Form of Length Encoding\r
+    //\r
+    ContentSize = (UINTN) (Asn1Byte & 0x7F);\r
+    //\r
+    // Skip the SEQUENCE Tag;\r
+    //\r
+    SpcIndirectDataContent += 2;\r
+  } else {\r
+    //\r
+    // Long Form of Length Encoding (Assume Only two bytes here)\r
+    //\r
+    ContentSize  = (UINTN) (*(SpcIndirectDataContent + 2));\r
+    ContentSize = (ContentSize << 8) + (UINTN)(*(SpcIndirectDataContent + 3));\r
+    //\r
+    // Skip the SEQUENCE Tag;\r
+    //\r
+    SpcIndirectDataContent += 4;\r
+  }\r
+\r
+  //\r
+  // Compare the original file hash value to the digest retrieve from SpcIndirectDataContent\r
+  // defined in Authenticode\r
+  // NOTE: Need to double-check HashLength here!\r
+  //\r
+  if (CompareMem (SpcIndirectDataContent + ContentSize - HashSize, ImageHash, HashSize) != 0) {\r
+    //\r
+    // Un-matched PE/COFF Hash Value\r
+    //\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Verifies the PKCS#7 Signed Data in PE/COFF Authenticode Signature\r
+  //\r
+  Status = (BOOLEAN) Pkcs7Verify (OrigAuthData, DataSize, TrustedCert, CertSize, SpcIndirectDataContent, ContentSize);\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources\r
+  //\r
+  PKCS7_free (Pkcs7);\r
+\r
+  return Status;\r
+}\r