Suggest to add a note that this new API is for signed PE/COFF image only. Other 
parts are good to me.

Reviewed-by: Ye Ting <[email protected]> 

-----Original Message-----
From: edk2-devel [mailto:[email protected]] On Behalf Of Qin Long
Sent: Tuesday, November 03, 2015 2:38 PM
To: Ye, Ting; Zhang, Chao B
Cc: [email protected]
Subject: [edk2] [Patch] CryptoPkg: Add one new API (Pkcs7GetCertificatesList) 
for certs retrieving.

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 <[email protected]>
---
 CryptoPkg/Include/Library/BaseCryptLib.h           |  30 +++
 .../Library/BaseCryptLib/Pk/CryptPkcs7Verify.c     | 288 +++++++++++++++++++++
 .../Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c |  34 +++
 .../Pk/CryptPkcs7VerifyNull.c                      |  34 +++
 4 files changed, 386 insertions(+)

diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h 
b/CryptoPkg/Include/Library/BaseCryptLib.h
index 95b75c9..390e302 100644
--- a/CryptoPkg/Include/Library/BaseCryptLib.h
+++ b/CryptoPkg/Include/Library/BaseCryptLib.h
@@ -1985,6 +1985,36 @@ Pkcs7FreeSigners (
   );
 
 /**
+  Retrieves all embedded certificates from PKCS#7 signed data as described in 
"PKCS #7:
+  Cryptographic Message Syntax Standard", and outputs two certificate 
+ lists chained and  unchained to the signer's certificates.
+  The input signed data could be wrapped in a ContentInfo structure.
+
+  @param[in]  P7Data            Pointer to the PKCS#7 message.
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to 
signer's
+                                certificate. It's caller's responsiblity to 
free the buffer.
+  @param[out] ChainLength       Length of the chained certificates list buffer 
in bytes.
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. 
It's caller's
+                                responsiblity to free the buffer.
+  @param[out] UnchainLength     Length of the unchained certificates list 
buffer in bytes.
+
+  @retval  TRUE         The operation is finished successfully.
+  @retval  FALSE        Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+  IN  CONST UINT8  *P7Data,
+  IN  UINTN        P7Length,
+  OUT UINT8        **SignerChainCerts,
+  OUT UINTN        *ChainLength,
+  OUT UINT8        **UnchainCerts,
+  OUT UINTN        *UnchainLength
+  );
+
+/**
   Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
   Syntax Standard, version 1.5". This interface is only intended to be used for
   application to perform PKCS#7 functionality validation.
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c 
b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
index fafcf1b..541156e 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
@@ -428,6 +428,294 @@ Pkcs7FreeSigners (  }
 
 /**
+  Retrieves all embedded certificates from PKCS#7 signed data as described in 
"PKCS #7:
+  Cryptographic Message Syntax Standard", and outputs two certificate 
+ lists chained and  unchained to the signer's certificates.
+  The input signed data could be wrapped in a ContentInfo structure.
+
+  @param[in]  P7Data            Pointer to the PKCS#7 message.
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to 
signer's
+                                certificate. It's caller's responsiblity to 
free the buffer.
+  @param[out] ChainLength       Length of the chained certificates list buffer 
in bytes.
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. 
It's caller's
+                                responsiblity to free the buffer.
+  @param[out] UnchainLength     Length of the unchained certificates list 
buffer in bytes.
+
+  @retval  TRUE         The operation is finished successfully.
+  @retval  FALSE        Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+  IN  CONST UINT8  *P7Data,
+  IN  UINTN        P7Length,
+  OUT UINT8        **SignerChainCerts,
+  OUT UINTN        *ChainLength,
+  OUT UINT8        **UnchainCerts,
+  OUT UINTN        *UnchainLength
+  )
+{
+  BOOLEAN          Status;
+  UINT8            *NewP7Data;
+  UINTN            NewP7Length;
+  BOOLEAN          Wrapped;
+  UINT8            Index;
+  PKCS7            *Pkcs7;
+  X509_STORE_CTX   CertCtx;
+  STACK_OF(X509)   *Signers;
+  X509             *Signer;
+  X509             *Cert;
+  X509             *TempCert;
+  X509             *Issuer;
+  UINT8            *CertBuf;
+  UINT8            *OldBuf;
+  UINTN            BufferSize;
+  UINTN            OldSize;
+  UINT8            *SingleCert;
+  UINTN            CertSize;
+
+  //
+  // Initializations
+  //
+  Status         = FALSE;
+  NewP7Data      = NULL;
+  Pkcs7          = NULL;
+  Cert           = NULL;
+  TempCert       = NULL;
+  SingleCert     = NULL;
+  CertBuf        = NULL;
+  OldBuf         = NULL;
+  Signers        = NULL;
+
+  //
+  // Parameter Checking
+  //
+  if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) 
||
+      (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > 
INT_MAX)) {
+    return Status;
+  }
+
+  *SignerChainCerts = NULL;
+  *ChainLength      = 0;
+  *UnchainCerts     = NULL;
+  *UnchainLength    = 0;
+
+  //
+  // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.
+  //
+  Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, 
+ &NewP7Length);  if (!Status || (NewP7Length > INT_MAX)) {
+    goto _Error;
+  }
+
+  //
+  // Decodes PKCS#7 SignedData
+  //
+  Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) 
+ NewP7Length);  if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {
+    goto _Error;
+  }
+
+  //
+  // Obtains Signer's Certificate from PKCS#7 data  // NOTE: 
+ Authenticode supports only one signer. So SignerInfos should include
+  //       only one singer's certificate.
+  //
+  Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);  if 
+ ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {
+    goto _Error;
+  }
+  Signer = sk_X509_value (Signers, 0);
+
+  if (!X509_STORE_CTX_init (&CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {
+    goto _Error;
+  }
+  //
+  // Initialize Chained & Untrusted stack  //  if (CertCtx.chain == 
+ NULL) {
+    if (((CertCtx.chain = sk_X509_new_null ()) == NULL) ||
+        (!sk_X509_push (CertCtx.chain, CertCtx.cert))) {
+      goto _Error;
+    }
+  }
+  sk_X509_delete_ptr (CertCtx.untrusted, Signer);
+
+  //
+  // Build certificates stack chained from Signer's certificate.
+  //
+  Cert = Signer;
+  for (; ;) {
+    //
+    // Self-Issue checking
+    //
+    if (CertCtx.check_issued (&CertCtx, Cert, Cert)) {
+      break;
+    }
+
+    //
+    // Found the issuer of the current certificate
+    //
+    if (CertCtx.untrusted != NULL) {
+      Issuer = NULL;
+      for (Index = 0; Index < sk_X509_num (CertCtx.untrusted); Index++) {
+        TempCert = sk_X509_value (CertCtx.untrusted, Index);
+        if (CertCtx.check_issued (&CertCtx, Cert, TempCert)) {
+          Issuer = TempCert;
+          break;
+        }
+      }
+      if (Issuer != NULL) {
+        if (!sk_X509_push (CertCtx.chain, Issuer)) {
+          goto _Error;
+        }
+        sk_X509_delete_ptr (CertCtx.untrusted, Issuer);
+
+        Cert = Issuer;
+        continue;
+      }
+    }
+
+    break;
+  }
+
+  //
+  // Converts Chained and Untrusted Certificate to Certificate Buffer in 
following format:
+  //      UINT8  CertNumber;
+  //      UINT32 Cert1Length;
+  //      UINT8  Cert1[];
+  //      UINT32 Cert2Length;
+  //      UINT8  Cert2[];
+  //      ...
+  //      UINT32 CertnLength;
+  //      UINT8  Certn[];
+  //
+
+  if (CertCtx.chain != NULL) {
+    BufferSize = sizeof (UINT8);
+    OldSize    = BufferSize;
+    CertBuf    = NULL;
+
+    for (Index = 0; ; Index++) {
+      Status = X509PopCertificate (CertCtx.chain, &SingleCert, &CertSize);
+      if (!Status) {
+        break;
+      }
+
+      OldSize    = BufferSize;
+      OldBuf     = CertBuf;
+      BufferSize = OldSize + CertSize + sizeof (UINT32);
+      CertBuf    = malloc (BufferSize);
+
+      if (CertBuf == NULL) {
+        Status = FALSE;
+        goto _Error;
+      }
+      if (OldBuf != NULL) {
+        CopyMem (CertBuf, OldBuf, OldSize);
+        free (OldBuf);
+        OldBuf = NULL;
+      }
+
+      WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
+      CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, 
+ CertSize);
+
+      free (SingleCert);
+      SingleCert = NULL;
+    }
+
+    if (CertBuf != NULL) {
+      //
+      // Update CertNumber.
+      //
+      CertBuf[0] = Index;
+
+      *SignerChainCerts = CertBuf;
+      *ChainLength      = BufferSize;
+    }
+  }
+
+  if (CertCtx.untrusted != NULL) {
+    BufferSize = sizeof (UINT8);
+    OldSize    = BufferSize;
+    CertBuf    = NULL;
+
+    for (Index = 0; ; Index++) {
+      Status = X509PopCertificate (CertCtx.untrusted, &SingleCert, &CertSize);
+      if (!Status) {
+        break;
+      }
+
+      OldSize    = BufferSize;
+      OldBuf     = CertBuf;
+      BufferSize = OldSize + CertSize + sizeof (UINT32);
+      CertBuf    = malloc (BufferSize);
+
+      if (CertBuf == NULL) {
+        Status = FALSE;
+        goto _Error;
+      }
+      if (OldBuf != NULL) {
+        CopyMem (CertBuf, OldBuf, OldSize);
+        free (OldBuf);
+        OldBuf = NULL;
+      }
+
+      WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
+      CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, 
+ CertSize);
+
+      free (SingleCert);
+      SingleCert = NULL;
+    }
+
+    if (CertBuf != NULL) {
+      //
+      // Update CertNumber.
+      //
+      CertBuf[0] = Index;
+
+      *UnchainCerts  = CertBuf;
+      *UnchainLength = BufferSize;
+    }
+  }
+
+  Status = TRUE;
+
+_Error:
+  //
+  // Release Resources.
+  //
+  if (!Wrapped && (NewP7Data != NULL)) {
+    free (NewP7Data);
+  }
+
+  if (Pkcs7 != NULL) {
+    PKCS7_free (Pkcs7);
+  }
+  sk_X509_free (Signers);
+
+  X509_STORE_CTX_cleanup (&CertCtx);
+
+  if (SingleCert != NULL) {
+    free (SingleCert);
+  }
+
+  if (OldBuf != NULL) {
+    free (OldBuf);
+  }
+
+  if (!Status && (CertBuf != NULL)) {
+    free (CertBuf);
+    *SignerChainCerts = NULL;
+    *UnchainCerts     = NULL;
+  }
+
+  return Status;
+}
+
+/**
   Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:
   Cryptographic Message Syntax Standard". The input signed data could be 
wrapped
   in a ContentInfo structure.
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c 
b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c
index 09b92c7..b9affe4 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c
@@ -67,6 +67,40 @@ Pkcs7FreeSigners (
 }
 
 /**
+  Retrieves all embedded certificates from PKCS#7 signed data as described in 
"PKCS #7:
+  Cryptographic Message Syntax Standard", and outputs two certificate 
+ lists chained and  unchained to the signer's certificates.
+  The input signed data could be wrapped in a ContentInfo structure.
+
+  @param[in]  P7Data            Pointer to the PKCS#7 message.
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to 
signer's
+                                certificate. It's caller's responsiblity to 
free the buffer.
+  @param[out] ChainLength       Length of the chained certificates list buffer 
in bytes.
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. 
It's caller's
+                                responsiblity to free the buffer.
+  @param[out] UnchainLength     Length of the unchained certificates list 
buffer in bytes.
+
+  @retval  TRUE         The operation is finished successfully.
+  @retval  FALSE        Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+  IN  CONST UINT8  *P7Data,
+  IN  UINTN        P7Length,
+  OUT UINT8        **SignerChainCerts,
+  OUT UINTN        *ChainLength,
+  OUT UINT8        **UnchainCerts,
+  OUT UINTN        *UnchainLength
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
+
+/**
   Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:
   Cryptographic Message Syntax Standard". The input signed data could be 
wrapped
   in a ContentInfo structure.
diff --git 
a/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c 
b/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c
index 09b92c7..b9affe4 100644
--- 
a/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7VerifyNull.c
+++ b/CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/Pk/CryptPkcs7Ve
+++ rifyNull.c
@@ -67,6 +67,40 @@ Pkcs7FreeSigners (
 }
 
 /**
+  Retrieves all embedded certificates from PKCS#7 signed data as described in 
"PKCS #7:
+  Cryptographic Message Syntax Standard", and outputs two certificate 
+ lists chained and  unchained to the signer's certificates.
+  The input signed data could be wrapped in a ContentInfo structure.
+
+  @param[in]  P7Data            Pointer to the PKCS#7 message.
+  @param[in]  P7Length          Length of the PKCS#7 message in bytes.
+  @param[out] SingerChainCerts  Pointer to the certificates list chained to 
signer's
+                                certificate. It's caller's responsiblity to 
free the buffer.
+  @param[out] ChainLength       Length of the chained certificates list buffer 
in bytes.
+  @param[out] UnchainCerts      Pointer to the unchained certificates lists. 
It's caller's
+                                responsiblity to free the buffer.
+  @param[out] UnchainLength     Length of the unchained certificates list 
buffer in bytes.
+
+  @retval  TRUE         The operation is finished successfully.
+  @retval  FALSE        Error occurs during the operation.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs7GetCertificatesList (
+  IN  CONST UINT8  *P7Data,
+  IN  UINTN        P7Length,
+  OUT UINT8        **SignerChainCerts,
+  OUT UINTN        *ChainLength,
+  OUT UINT8        **UnchainCerts,
+  OUT UINTN        *UnchainLength
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
+
+/**
   Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:
   Cryptographic Message Syntax Standard". The input signed data could be 
wrapped
   in a ContentInfo structure.
--
2.5.1.windows.1

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to