]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7.c
Add two new interfaces Pkcs7GetSigners and Pkcs7FreeSigners to BaseCryptLib.
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7.c
index 16176423237958d21f37f3009158765e8ea3a744..036412af5989650ebaf360f513e187fe3a07973d 100644 (file)
@@ -57,7 +57,7 @@ X509VerifyCb (
   //\r
   if ((Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) ||\r
       (Error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)) {\r
-    Obj = (X509_OBJECT *) OPENSSL_malloc (sizeof (X509_OBJECT));\r
+    Obj = (X509_OBJECT *) malloc (sizeof (X509_OBJECT));\r
     if (Obj == NULL) {\r
       return 0;\r
     }\r
@@ -224,7 +224,7 @@ Pkcs7Sign (
     goto _Exit;\r
   }\r
 \r
-  P7Data     = OPENSSL_malloc (P7DataSize);\r
+  P7Data     = malloc (P7DataSize);\r
   if (P7Data == NULL) {\r
     Status = FALSE;\r
     goto _Exit;\r
@@ -238,7 +238,7 @@ Pkcs7Sign (
   // is totally 19 bytes.\r
   //\r
   *SignedDataSize = P7DataSize - 19;\r
-  *SignedData     = OPENSSL_malloc (*SignedDataSize);\r
+  *SignedData     = malloc (*SignedDataSize);\r
   if (*SignedData == NULL) {\r
     Status = FALSE;\r
     OPENSSL_free (P7Data);\r
@@ -278,69 +278,35 @@ _Exit:
 }\r
 \r
 /**\r
-  Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:\r
-  Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
-  in a ContentInfo structure.\r
-\r
-  If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
-  If P7Length, CertLength or DataLength overflow, then return FAlSE.\r
+  Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
+  a new structure to wrap P7Data.\r
 \r
   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.\r
   @param[in]  P7Length     Length of the PKCS#7 message 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]  CertLength   Length of the trusted certificate in bytes.\r
-  @param[in]  InData       Pointer to the content to be verified.\r
-  @param[in]  DataLength   Length of InData in bytes.\r
-\r
-  @retval  TRUE  The specified PKCS#7 signed data is valid.\r
-  @retval  FALSE Invalid PKCS#7 signed data.\r
+  @param[out] WrapFlag     If TRUE P7Data is a ContentInfo structure, otherwise\r
+                           return FALSE.\r
+  @param[out] WrapData     If return status of this function is TRUE: \r
+                           1) when WrapFlag is TRUE, pointer to P7Data.\r
+                           2) when WrapFlag is FALSE, pointer to a new ContentInfo\r
+                           structure. It's caller's responsibility to free this\r
+                           buffer.\r
+  @param[out] WrapDataSize Length of ContentInfo structure in bytes.\r
+\r
+  @retval     TRUE         The operation is finished successfully.\r
+  @retval     FALSE        The operation is failed due to lack of resources.\r
 \r
 **/\r
 BOOLEAN\r
-EFIAPI\r
-Pkcs7Verify (\r
+WrapPkcs7Data (\r
   IN  CONST UINT8  *P7Data,\r
   IN  UINTN        P7Length,\r
-  IN  CONST UINT8  *TrustedCert,\r
-  IN  UINTN        CertLength,\r
-  IN  CONST UINT8  *InData,\r
-  IN  UINTN        DataLength\r
+  OUT BOOLEAN      *WrapFlag,\r
+  OUT UINT8        **WrapData,\r
+  OUT UINTN        *WrapDataSize\r
   )\r
 {\r
-  PKCS7       *Pkcs7;\r
-  BIO         *CertBio;\r
-  BIO         *DataBio;\r
-  BOOLEAN     Status;\r
-  X509        *Cert;\r
-  X509_STORE  *CertStore;\r
-  UINT8       *SignedData;\r
-  UINT8       *Temp;\r
-  UINTN       SignedDataSize;\r
-  BOOLEAN     Wrapped;\r
-\r
-  //\r
-  // Check input parameters.\r
-  //\r
-  if (P7Data == NULL || TrustedCert == NULL || InData == NULL || \r
-    P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {\r
-    return FALSE;\r
-  }\r
-  \r
-  Status    = FALSE;\r
-  Pkcs7     = NULL;\r
-  CertBio   = NULL;\r
-  DataBio   = NULL;\r
-  Cert      = NULL;\r
-  CertStore = NULL;\r
-\r
-  //\r
-  // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
-  //\r
-  EVP_add_digest (EVP_md5());\r
-  EVP_add_digest (EVP_sha1());\r
-  EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA);\r
-  EVP_add_digest (EVP_sha256());\r
+  BOOLEAN          Wrapped;\r
+  UINT8            *SignedData;\r
 \r
   //\r
   // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
@@ -355,18 +321,21 @@ Pkcs7Verify (
   }\r
 \r
   if (Wrapped) {\r
-    SignedData     = (UINT8 *) P7Data;\r
-    SignedDataSize = P7Length;\r
+    *WrapData     = (UINT8 *) P7Data;\r
+    *WrapDataSize = P7Length;\r
   } else {\r
     //\r
     // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.\r
     //\r
-    SignedDataSize = P7Length + 19;\r
-    SignedData     = OPENSSL_malloc (SignedDataSize);\r
-    if (SignedData == NULL) {\r
+    *WrapDataSize = P7Length + 19;\r
+    *WrapData     = malloc (*WrapDataSize);\r
+    if (*WrapData == NULL) {\r
+      *WrapFlag = Wrapped;\r
       return FALSE;\r
     }\r
 \r
+    SignedData = *WrapData;\r
+\r
     //\r
     // Part1: 0x30, 0x82.\r
     //\r
@@ -376,8 +345,8 @@ Pkcs7Verify (
     //\r
     // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
     //\r
-    SignedData[2] = (UINT8) (((UINT16) (SignedDataSize - 4)) >> 8);\r
-    SignedData[3] = (UINT8) (((UINT16) (SignedDataSize - 4)) & 0xff);\r
+    SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);\r
+    SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);\r
 \r
     //\r
     // Part3: 0x06, 0x09.\r
@@ -407,6 +376,279 @@ Pkcs7Verify (
     //\r
     CopyMem (SignedData + 19, P7Data, P7Length);\r
   }\r
+\r
+  *WrapFlag = Wrapped;\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
+  in a ContentInfo structure.\r
+\r
+  If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then\r
+  return FALSE. If P7Length overflow, then return FAlSE.\r
+\r
+  @param[in]  P7Data       Pointer to the PKCS#7 message to verify.\r
+  @param[in]  P7Length     Length of the PKCS#7 message in bytes.\r
+  @param[out] CertStack    Pointer to Signer's certificates retrieved from P7Data.\r
+                           It's caller's responsiblity to free the buffer.\r
+  @param[out] StackLength  Length of signer's certificates in bytes.\r
+  @param[out] TrustedCert  Pointer to a trusted certificate from Signer's certificates.\r
+                           It's caller's responsiblity to free the buffer.\r
+  @param[out] CertLength   Length of the trusted certificate in bytes.\r
+\r
+  @retval  TRUE            The operation is finished successfully.\r
+  @retval  FALSE           Error occurs during the operation.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Pkcs7GetSigners (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  OUT UINT8        **CertStack,\r
+  OUT UINTN        *StackLength,\r
+  OUT UINT8        **TrustedCert,\r
+  OUT UINTN        *CertLength\r
+  )\r
+{\r
+  PKCS7            *Pkcs7;\r
+  BOOLEAN          Status;\r
+  UINT8            *SignedData;\r
+  UINT8            *Temp;\r
+  UINTN            SignedDataSize;\r
+  BOOLEAN          Wrapped;\r
+  STACK_OF(X509)   *Stack;\r
+  UINT8            Index;\r
+  UINT8            *CertBuf;\r
+  UINT8            *OldBuf;\r
+  UINTN            BufferSize;\r
+  UINTN            OldSize;\r
+  UINT8            *SingleCert;\r
+  UINTN            SingleCertSize;\r
+\r
+  if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||\r
+      (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) {\r
+    return FALSE;\r
+  }\r
+  \r
+  Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
+  if (!Status) {\r
+    return Status;\r
+  }\r
+\r
+  Status     = FALSE;\r
+  Pkcs7      = NULL;\r
+  Stack      = NULL;\r
+  CertBuf    = NULL;\r
+  OldBuf     = NULL;\r
+  SingleCert = NULL;\r
+\r
+  //\r
+  // Retrieve PKCS#7 Data (DER encoding)\r
+  //\r
+  if (SignedDataSize > INT_MAX) {\r
+    goto _Exit;\r
+  }\r
+\r
+  Temp = SignedData;\r
+  Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);\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
+  Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY);\r
+  if (Stack == NULL) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Convert CertStack to buffer in following format:\r
+  // UINT8  CertNumber;\r
+  // UINT32 Cert1Length;\r
+  // UINT8  Cert1[];\r
+  // UINT32 Cert2Length;\r
+  // UINT8  Cert2[];\r
+  // ...\r
+  // UINT32 CertnLength;\r
+  // UINT8  Certn[];\r
+  //\r
+  BufferSize = sizeof (UINT8);\r
+  OldSize    = BufferSize;\r
+  \r
+  for (Index = 0; ; Index++) {\r
+    Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);\r
+    if (!Status) {\r
+      break;\r
+    }\r
+\r
+    OldSize    = BufferSize;\r
+    OldBuf     = CertBuf;\r
+    BufferSize = OldSize + SingleCertSize + sizeof (UINT32);\r
+    CertBuf    = malloc (BufferSize);\r
+\r
+    if (CertBuf == NULL) {\r
+      goto _Exit;\r
+    }\r
+\r
+    if (OldBuf != NULL) {\r
+      CopyMem (CertBuf, OldBuf, OldSize);\r
+      free (OldBuf);\r
+      OldBuf = NULL;\r
+    }\r
+\r
+    WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize);\r
+    CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);\r
+\r
+    free (SingleCert);\r
+    SingleCert = NULL;\r
+  }\r
+\r
+  if (CertBuf != NULL) {\r
+    //\r
+    // Update CertNumber.\r
+    //\r
+    CertBuf[0] = Index;\r
+\r
+    *CertLength = BufferSize - OldSize - sizeof (UINT32);\r
+    *TrustedCert = malloc (*CertLength);\r
+    if (*TrustedCert == NULL) {\r
+      goto _Exit;\r
+    }\r
+\r
+    CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);\r
+    *CertStack   = CertBuf;\r
+    *StackLength = BufferSize;\r
+    Status = TRUE;\r
+  } \r
+\r
+_Exit:\r
+  //\r
+  // Release Resources\r
+  //\r
+  if (!Wrapped) {\r
+    free (SignedData);\r
+  }\r
+\r
+  if (Pkcs7 != NULL) {\r
+    PKCS7_free (Pkcs7);\r
+  }\r
+\r
+  if (Stack != NULL) {\r
+    sk_X509_pop_free(Stack, X509_free);\r
+  }\r
+\r
+  if (SingleCert !=  NULL) {\r
+    free (SingleCert);\r
+  }\r
+\r
+  if (!Status && (CertBuf != NULL)) {\r
+    free (CertBuf);\r
+    *CertStack = NULL;\r
+  }\r
+\r
+  if (OldBuf != NULL) {\r
+    free (OldBuf);\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wrap function to use free() to free allocated memory for certificates.\r
+\r
+  @param[in]  Certs        Pointer to the certificates to be freed.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Pkcs7FreeSigners (\r
+  IN  UINT8        *Certs\r
+  )\r
+{\r
+  if (Certs == NULL) {\r
+    return;\r
+  }\r
+\r
+  free (Certs);\r
+}\r
+\r
+/**\r
+  Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
+  in a ContentInfo structure.\r
+\r
+  If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
+  If P7Length, CertLength or DataLength overflow, then return FAlSE.\r
+\r
+  @param[in]  P7Data       Pointer to the PKCS#7 message to verify.\r
+  @param[in]  P7Length     Length of the PKCS#7 message 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]  CertLength   Length of the trusted certificate in bytes.\r
+  @param[in]  InData       Pointer to the content to be verified.\r
+  @param[in]  DataLength   Length of InData in bytes.\r
+\r
+  @retval  TRUE  The specified PKCS#7 signed data is valid.\r
+  @retval  FALSE Invalid PKCS#7 signed data.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Pkcs7Verify (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  IN  CONST UINT8  *TrustedCert,\r
+  IN  UINTN        CertLength,\r
+  IN  CONST UINT8  *InData,\r
+  IN  UINTN        DataLength\r
+  )\r
+{\r
+  PKCS7       *Pkcs7;\r
+  BIO         *CertBio;\r
+  BIO         *DataBio;\r
+  BOOLEAN     Status;\r
+  X509        *Cert;\r
+  X509_STORE  *CertStore;\r
+  UINT8       *SignedData;\r
+  UINT8       *Temp;\r
+  UINTN       SignedDataSize;\r
+  BOOLEAN     Wrapped;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (P7Data == NULL || TrustedCert == NULL || InData == NULL || \r
+    P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {\r
+    return FALSE;\r
+  }\r
+  \r
+  Pkcs7     = NULL;\r
+  CertBio   = NULL;\r
+  DataBio   = NULL;\r
+  Cert      = NULL;\r
+  CertStore = NULL;\r
+\r
+  //\r
+  // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
+  //\r
+  EVP_add_digest (EVP_md5());\r
+  EVP_add_digest (EVP_sha1());\r
+  EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA);\r
+  EVP_add_digest (EVP_sha256());\r
+\r
+  Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
+  if (!Status) {\r
+    return Status;\r
+  }\r
   \r
   //\r
   // Retrieve PKCS#7 Data (DER encoding)\r