]> git.proxmox.com Git - mirror_edk2.git/commitdiff
CryptoPkg: Add one new API (Pkcs7GetCertificatesList) for certs retrieving.
authorQin Long <qin.long@intel.com>
Thu, 5 Nov 2015 08:50:39 +0000 (08:50 +0000)
committerqlong <qlong@Edk2>
Thu, 5 Nov 2015 08:50:39 +0000 (08:50 +0000)
Adding one new API (Pkcs7GetCertificatesList) to retrieve and sort all
embedded certificates from Pkcs7 signedData. This new API will provide
the support for UEFI 2.5 Secure-Boot AuditMode feature.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Qin Long <qin.long@intel.com>
Reviewed-by: Chao Zhang <chao.b.zhang@intel.com>
Reviewed-by: Ting Ye <ting.ye@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18729 6f19259b-4bc3-4df7-8a09-765794883524

CryptoPkg/Include/Library/BaseCryptLib.h
CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c
CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c

index 95b75c92b8f5c976af7dbf2ed04118177f97a823..390e302f98c84f38eaa1d62e3cdcfd88035ed14f 100644 (file)
@@ -1984,6 +1984,36 @@ Pkcs7FreeSigners (
   IN  UINT8        *Certs\r
   );\r
 \r
+/**\r
+  Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
+  unchained to the signer's certificates.\r
+  The input signed data could be wrapped in a ContentInfo structure.\r
+\r
+  @param[in]  P7Data            Pointer to the PKCS#7 message.\r
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.\r
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to signer's\r
+                                certificate. It's caller's responsiblity to free the buffer.\r
+  @param[out] ChainLength       Length of the chained certificates list buffer in bytes.\r
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. It's caller's\r
+                                responsiblity to free the buffer.\r
+  @param[out] UnchainLength     Length of the unchained certificates list buffer 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
+Pkcs7GetCertificatesList (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  OUT UINT8        **SignerChainCerts,\r
+  OUT UINTN        *ChainLength,\r
+  OUT UINT8        **UnchainCerts,\r
+  OUT UINTN        *UnchainLength\r
+  );\r
+\r
 /**\r
   Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message\r
   Syntax Standard, version 1.5". This interface is only intended to be used for\r
index fafcf1ba85361c98592e7e304a581a77b9ecee0e..242ba10bbf0e31f5946aee8673d792e4152ddcbd 100644 (file)
@@ -427,6 +427,294 @@ Pkcs7FreeSigners (
   free (Certs);\r
 }\r
 \r
+/**\r
+  Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
+  unchained to the signer's certificates.\r
+  The input signed data could be wrapped in a ContentInfo structure.\r
+\r
+  @param[in]  P7Data            Pointer to the PKCS#7 message.\r
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.\r
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to signer's\r
+                                certificate. It's caller's responsiblity to free the buffer.\r
+  @param[out] ChainLength       Length of the chained certificates list buffer in bytes.\r
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. It's caller's\r
+                                responsiblity to free the buffer.\r
+  @param[out] UnchainLength     Length of the unchained certificates list buffer 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
+Pkcs7GetCertificatesList (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  OUT UINT8        **SignerChainCerts,\r
+  OUT UINTN        *ChainLength,\r
+  OUT UINT8        **UnchainCerts,\r
+  OUT UINTN        *UnchainLength\r
+  )\r
+{\r
+  BOOLEAN          Status;\r
+  UINT8            *NewP7Data;\r
+  UINTN            NewP7Length;\r
+  BOOLEAN          Wrapped;\r
+  UINT8            Index;\r
+  PKCS7            *Pkcs7;\r
+  X509_STORE_CTX   CertCtx;\r
+  STACK_OF(X509)   *Signers;\r
+  X509             *Signer;\r
+  X509             *Cert;\r
+  X509             *TempCert;\r
+  X509             *Issuer;\r
+  UINT8            *CertBuf;\r
+  UINT8            *OldBuf;\r
+  UINTN            BufferSize;\r
+  UINTN            OldSize;\r
+  UINT8            *SingleCert;\r
+  UINTN            CertSize;\r
+\r
+  //\r
+  // Initializations\r
+  //\r
+  Status         = FALSE;\r
+  NewP7Data      = NULL;\r
+  Pkcs7          = NULL;\r
+  Cert           = NULL;\r
+  TempCert       = NULL;\r
+  SingleCert     = NULL;\r
+  CertBuf        = NULL;\r
+  OldBuf         = NULL;\r
+  Signers        = NULL;\r
+\r
+  //\r
+  // Parameter Checking\r
+  //\r
+  if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||\r
+      (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) {\r
+    return Status;\r
+  }\r
+\r
+  *SignerChainCerts = NULL;\r
+  *ChainLength      = 0;\r
+  *UnchainCerts     = NULL;\r
+  *UnchainLength    = 0;\r
+\r
+  //\r
+  // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.\r
+  //\r
+  Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);\r
+  if (!Status || (NewP7Length > INT_MAX)) {\r
+    goto _Error;\r
+  }\r
+\r
+  //\r
+  // Decodes PKCS#7 SignedData\r
+  //\r
+  Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length);\r
+  if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {\r
+    goto _Error;\r
+  }\r
+\r
+  //\r
+  // Obtains Signer's Certificate from PKCS#7 data\r
+  // NOTE: Only one signer case will be handled in this function, which means SignerInfos\r
+  //       should include only one singer's certificate.\r
+  //\r
+  Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);\r
+  if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {\r
+    goto _Error;\r
+  }\r
+  Signer = sk_X509_value (Signers, 0);\r
+\r
+  if (!X509_STORE_CTX_init (&CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {\r
+    goto _Error;\r
+  }\r
+  //\r
+  // Initialize Chained & Untrusted stack\r
+  //\r
+  if (CertCtx.chain == NULL) {\r
+    if (((CertCtx.chain = sk_X509_new_null ()) == NULL) ||\r
+        (!sk_X509_push (CertCtx.chain, CertCtx.cert))) {\r
+      goto _Error;\r
+    }\r
+  }\r
+  sk_X509_delete_ptr (CertCtx.untrusted, Signer);\r
+\r
+  //\r
+  // Build certificates stack chained from Signer's certificate.\r
+  //\r
+  Cert = Signer;\r
+  for (; ;) {\r
+    //\r
+    // Self-Issue checking\r
+    //\r
+    if (CertCtx.check_issued (&CertCtx, Cert, Cert)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Found the issuer of the current certificate\r
+    //\r
+    if (CertCtx.untrusted != NULL) {\r
+      Issuer = NULL;\r
+      for (Index = 0; Index < sk_X509_num (CertCtx.untrusted); Index++) {\r
+        TempCert = sk_X509_value (CertCtx.untrusted, Index);\r
+        if (CertCtx.check_issued (&CertCtx, Cert, TempCert)) {\r
+          Issuer = TempCert;\r
+          break;\r
+        }\r
+      }\r
+      if (Issuer != NULL) {\r
+        if (!sk_X509_push (CertCtx.chain, Issuer)) {\r
+          goto _Error;\r
+        }\r
+        sk_X509_delete_ptr (CertCtx.untrusted, Issuer);\r
+\r
+        Cert = Issuer;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Converts Chained and Untrusted Certificate to Certificate 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
+\r
+  if (CertCtx.chain != NULL) {\r
+    BufferSize = sizeof (UINT8);\r
+    OldSize    = BufferSize;\r
+    CertBuf    = NULL;\r
+\r
+    for (Index = 0; ; Index++) {\r
+      Status = X509PopCertificate (CertCtx.chain, &SingleCert, &CertSize);\r
+      if (!Status) {\r
+        break;\r
+      }\r
+\r
+      OldSize    = BufferSize;\r
+      OldBuf     = CertBuf;\r
+      BufferSize = OldSize + CertSize + sizeof (UINT32);\r
+      CertBuf    = malloc (BufferSize);\r
+\r
+      if (CertBuf == NULL) {\r
+        Status = FALSE;\r
+        goto _Error;\r
+      }\r
+      if (OldBuf != NULL) {\r
+        CopyMem (CertBuf, OldBuf, OldSize);\r
+        free (OldBuf);\r
+        OldBuf = NULL;\r
+      }\r
+\r
+      WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);\r
+      CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
+\r
+      free (SingleCert);\r
+      SingleCert = NULL;\r
+    }\r
+\r
+    if (CertBuf != NULL) {\r
+      //\r
+      // Update CertNumber.\r
+      //\r
+      CertBuf[0] = Index;\r
+\r
+      *SignerChainCerts = CertBuf;\r
+      *ChainLength      = BufferSize;\r
+    }\r
+  }\r
+\r
+  if (CertCtx.untrusted != NULL) {\r
+    BufferSize = sizeof (UINT8);\r
+    OldSize    = BufferSize;\r
+    CertBuf    = NULL;\r
+\r
+    for (Index = 0; ; Index++) {\r
+      Status = X509PopCertificate (CertCtx.untrusted, &SingleCert, &CertSize);\r
+      if (!Status) {\r
+        break;\r
+      }\r
+\r
+      OldSize    = BufferSize;\r
+      OldBuf     = CertBuf;\r
+      BufferSize = OldSize + CertSize + sizeof (UINT32);\r
+      CertBuf    = malloc (BufferSize);\r
+\r
+      if (CertBuf == NULL) {\r
+        Status = FALSE;\r
+        goto _Error;\r
+      }\r
+      if (OldBuf != NULL) {\r
+        CopyMem (CertBuf, OldBuf, OldSize);\r
+        free (OldBuf);\r
+        OldBuf = NULL;\r
+      }\r
+\r
+      WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);\r
+      CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
+\r
+      free (SingleCert);\r
+      SingleCert = NULL;\r
+    }\r
+\r
+    if (CertBuf != NULL) {\r
+      //\r
+      // Update CertNumber.\r
+      //\r
+      CertBuf[0] = Index;\r
+\r
+      *UnchainCerts  = CertBuf;\r
+      *UnchainLength = BufferSize;\r
+    }\r
+  }\r
+\r
+  Status = TRUE;\r
+\r
+_Error:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (!Wrapped && (NewP7Data != NULL)) {\r
+    free (NewP7Data);\r
+  }\r
+\r
+  if (Pkcs7 != NULL) {\r
+    PKCS7_free (Pkcs7);\r
+  }\r
+  sk_X509_free (Signers);\r
+\r
+  X509_STORE_CTX_cleanup (&CertCtx);\r
+\r
+  if (SingleCert != NULL) {\r
+    free (SingleCert);\r
+  }\r
+\r
+  if (OldBuf != NULL) {\r
+    free (OldBuf);\r
+  }\r
+\r
+  if (!Status && (CertBuf != NULL)) {\r
+    free (CertBuf);\r
+    *SignerChainCerts = NULL;\r
+    *UnchainCerts     = NULL;\r
+  }\r
+\r
+  return Status;\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
index 09b92c7f159bcccae0b05211bc9b8fd8d8107f82..b9affe4275037073ea0437ee6f1a10e7901e8833 100644 (file)
@@ -66,6 +66,40 @@ Pkcs7FreeSigners (
   ASSERT (FALSE);\r
 }\r
 \r
+/**\r
+  Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
+  unchained to the signer's certificates.\r
+  The input signed data could be wrapped in a ContentInfo structure.\r
+\r
+  @param[in]  P7Data            Pointer to the PKCS#7 message.\r
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.\r
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to signer's\r
+                                certificate. It's caller's responsiblity to free the buffer.\r
+  @param[out] ChainLength       Length of the chained certificates list buffer in bytes.\r
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. It's caller's\r
+                                responsiblity to free the buffer.\r
+  @param[out] UnchainLength     Length of the unchained certificates list buffer 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
+Pkcs7GetCertificatesList (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  OUT UINT8        **SignerChainCerts,\r
+  OUT UINTN        *ChainLength,\r
+  OUT UINT8        **UnchainCerts,\r
+  OUT UINTN        *UnchainLength\r
+  )\r
+{\r
+  ASSERT (FALSE);\r
+  return FALSE;\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
index 09b92c7f159bcccae0b05211bc9b8fd8d8107f82..b9affe4275037073ea0437ee6f1a10e7901e8833 100644 (file)
@@ -66,6 +66,40 @@ Pkcs7FreeSigners (
   ASSERT (FALSE);\r
 }\r
 \r
+/**\r
+  Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
+  Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
+  unchained to the signer's certificates.\r
+  The input signed data could be wrapped in a ContentInfo structure.\r
+\r
+  @param[in]  P7Data            Pointer to the PKCS#7 message.\r
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.\r
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to signer's\r
+                                certificate. It's caller's responsiblity to free the buffer.\r
+  @param[out] ChainLength       Length of the chained certificates list buffer in bytes.\r
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. It's caller's\r
+                                responsiblity to free the buffer.\r
+  @param[out] UnchainLength     Length of the unchained certificates list buffer 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
+Pkcs7GetCertificatesList (\r
+  IN  CONST UINT8  *P7Data,\r
+  IN  UINTN        P7Length,\r
+  OUT UINT8        **SignerChainCerts,\r
+  OUT UINTN        *ChainLength,\r
+  OUT UINT8        **UnchainCerts,\r
+  OUT UINTN        *UnchainLength\r
+  )\r
+{\r
+  ASSERT (FALSE);\r
+  return FALSE;\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