# This external input must be validated carefully to avoid security issues such as\r
# buffer overflow or integer overflow.\r
#\r
-# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2019, 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
Pk/CryptRsaExt.c\r
Pk/CryptPkcs5Pbkdf2.c\r
Pk/CryptPkcs7Sign.c\r
- Pk/CryptPkcs7Verify.c\r
+ Pk/CryptPkcs7VerifyCommon.c\r
+ Pk/CryptPkcs7VerifyBase.c\r
Pk/CryptDh.c\r
Pk/CryptX509.c\r
Pk/CryptAuthenticode.c\r
#define OBJ_length(o) ((o)->length)\r
#endif\r
\r
+/**\r
+ Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
+ a new structure to wrap P7Data.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ UEFI Authenticated Variable is external input, so this function will do basic\r
+ check for PKCS#7 data structure.\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] 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
+WrapPkcs7Data (\r
+ IN CONST UINT8 *P7Data,\r
+ IN UINTN P7Length,\r
+ OUT BOOLEAN *WrapFlag,\r
+ OUT UINT8 **WrapData,\r
+ OUT UINTN *WrapDataSize\r
+ );\r
+\r
#endif\r
Pk/CryptRsaExtNull.c\r
Pk/CryptPkcs5Pbkdf2Null.c\r
Pk/CryptPkcs7SignNull.c\r
- Pk/CryptPkcs7Verify.c\r
+ Pk/CryptPkcs7VerifyCommon.c\r
+ Pk/CryptPkcs7VerifyBase.c\r
\r
Pk/CryptDhNull.c\r
Pk/CryptX509Null.c\r
+++ /dev/null
-/** @file\r
- PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
-\r
- Caution: This module requires additional review when modified.\r
- This library will have external input - signature (e.g. UEFI Authenticated\r
- Variable). It may by input in SMM mode.\r
- This external input must be validated carefully to avoid security issue like\r
- buffer overflow, integer overflow.\r
-\r
- WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated\r
- Variable and will do basic check for data structure.\r
-\r
-Copyright (c) 2009 - 2017, 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/x509v3.h>\r
-#include <openssl/pkcs7.h>\r
-\r
-UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };\r
-\r
-/**\r
- Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
- a new structure to wrap P7Data.\r
-\r
- Caution: This function may receive untrusted input.\r
- UEFI Authenticated Variable is external input, so this function will do basic\r
- check for PKCS#7 data structure.\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] 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
-WrapPkcs7Data (\r
- IN CONST UINT8 *P7Data,\r
- IN UINTN P7Length,\r
- OUT BOOLEAN *WrapFlag,\r
- OUT UINT8 **WrapData,\r
- OUT UINTN *WrapDataSize\r
- )\r
-{\r
- BOOLEAN Wrapped;\r
- UINT8 *SignedData;\r
-\r
- //\r
- // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
- //\r
- Wrapped = FALSE;\r
- if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {\r
- if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {\r
- if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {\r
- Wrapped = TRUE;\r
- }\r
- }\r
- }\r
-\r
- if (Wrapped) {\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
- *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
- SignedData[0] = 0x30;\r
- SignedData[1] = 0x82;\r
-\r
- //\r
- // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
- //\r
- SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);\r
- SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);\r
-\r
- //\r
- // Part3: 0x06, 0x09.\r
- //\r
- SignedData[4] = 0x06;\r
- SignedData[5] = 0x09;\r
-\r
- //\r
- // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.\r
- //\r
- CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));\r
-\r
- //\r
- // Part5: 0xA0, 0x82.\r
- //\r
- SignedData[15] = 0xA0;\r
- SignedData[16] = 0x82;\r
-\r
- //\r
- // Part6: Length2 = P7Length, in big endian.\r
- //\r
- SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);\r
- SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);\r
-\r
- //\r
- // Part7: P7Data.\r
- //\r
- CopyMem (SignedData + 19, P7Data, P7Length);\r
- }\r
-\r
- *WrapFlag = Wrapped;\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Pop single certificate from STACK_OF(X509).\r
-\r
- If X509Stack, Cert, or CertSize is NULL, then return FALSE.\r
-\r
- @param[in] X509Stack Pointer to a X509 stack object.\r
- @param[out] Cert Pointer to a X509 certificate.\r
- @param[out] CertSize Length of output X509 certificate in bytes.\r
-\r
- @retval TRUE The X509 stack pop succeeded.\r
- @retval FALSE The pop operation failed.\r
-\r
-**/\r
-BOOLEAN\r
-X509PopCertificate (\r
- IN VOID *X509Stack,\r
- OUT UINT8 **Cert,\r
- OUT UINTN *CertSize\r
- )\r
-{\r
- BIO *CertBio;\r
- X509 *X509Cert;\r
- STACK_OF(X509) *CertStack;\r
- BOOLEAN Status;\r
- INT32 Result;\r
- BUF_MEM *Ptr;\r
- INT32 Length;\r
- VOID *Buffer;\r
-\r
- Status = FALSE;\r
-\r
- if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {\r
- return Status;\r
- }\r
-\r
- CertStack = (STACK_OF(X509) *) X509Stack;\r
-\r
- X509Cert = sk_X509_pop (CertStack);\r
-\r
- if (X509Cert == NULL) {\r
- return Status;\r
- }\r
-\r
- Buffer = NULL;\r
-\r
- CertBio = BIO_new (BIO_s_mem ());\r
- if (CertBio == NULL) {\r
- return Status;\r
- }\r
-\r
- Result = i2d_X509_bio (CertBio, X509Cert);\r
- if (Result == 0) {\r
- goto _Exit;\r
- }\r
-\r
- BIO_get_mem_ptr (CertBio, &Ptr);\r
- Length = (INT32)(Ptr->length);\r
- if (Length <= 0) {\r
- goto _Exit;\r
- }\r
-\r
- Buffer = malloc (Length);\r
- if (Buffer == NULL) {\r
- goto _Exit;\r
- }\r
-\r
- Result = BIO_read (CertBio, Buffer, Length);\r
- if (Result != Length) {\r
- goto _Exit;\r
- }\r
-\r
- *Cert = Buffer;\r
- *CertSize = Length;\r
-\r
- Status = TRUE;\r
-\r
-_Exit:\r
-\r
- BIO_free (CertBio);\r
-\r
- if (!Status && (Buffer != NULL)) {\r
- free (Buffer);\r
- }\r
-\r
- return Status;\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
- Caution: This function may receive untrusted input.\r
- UEFI Authenticated Variable is external input, so this function will do basic\r
- check for PKCS#7 data structure.\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 responsibility to free the buffer with\r
- Pkcs7FreeSigners().\r
- This data structure is EFI_CERT_STACK type.\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 responsibility to free the buffer with\r
- Pkcs7FreeSigners().\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
- CONST 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
- 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] SignerChainCerts Pointer to the certificates list chained to signer's\r
- certificate. It's caller's responsibility to free the buffer\r
- with Pkcs7FreeSigners().\r
- This data structure is EFI_CERT_STACK type.\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
- responsibility to free the buffer with Pkcs7FreeSigners().\r
- This data structure is EFI_CERT_STACK type.\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) *CtxChain;\r
- STACK_OF(X509) *CtxUntrusted;\r
- X509 *CtxCert;\r
- STACK_OF(X509) *Signers;\r
- X509 *Signer;\r
- X509 *Cert;\r
- X509 *Issuer;\r
- X509_NAME *IssuerName;\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
- CertCtx = NULL;\r
- CtxChain = NULL;\r
- CtxCert = NULL;\r
- CtxUntrusted = NULL;\r
- Cert = NULL;\r
- SingleCert = NULL;\r
- CertBuf = NULL;\r
- OldBuf = NULL;\r
- Signers = NULL;\r
-\r
- ZeroMem (&CertCtx, sizeof (CertCtx));\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 signer'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
- CertCtx = X509_STORE_CTX_new ();\r
- if (CertCtx == NULL) {\r
- goto _Error;\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
- CtxChain = X509_STORE_CTX_get0_chain (CertCtx);\r
- CtxCert = X509_STORE_CTX_get0_cert (CertCtx);\r
- if (CtxChain == NULL) {\r
- if (((CtxChain = sk_X509_new_null ()) == NULL) ||\r
- (!sk_X509_push (CtxChain, CtxCert))) {\r
- goto _Error;\r
- }\r
- }\r
- CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);\r
- if (CtxUntrusted != NULL) {\r
- (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);\r
- }\r
-\r
- //\r
- // Build certificates stack chained from Signer's certificate.\r
- //\r
- Cert = Signer;\r
- for (; ;) {\r
- //\r
- // Self-Issue checking\r
- //\r
- Issuer = NULL;\r
- if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {\r
- if (X509_cmp (Issuer, Cert) == 0) {\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Found the issuer of the current certificate\r
- //\r
- if (CtxUntrusted != NULL) {\r
- Issuer = NULL;\r
- IssuerName = X509_get_issuer_name (Cert);\r
- Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);\r
- if (Issuer != NULL) {\r
- if (!sk_X509_push (CtxChain, Issuer)) {\r
- goto _Error;\r
- }\r
- (VOID)sk_X509_delete_ptr (CtxUntrusted, 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 (CtxChain != NULL) {\r
- BufferSize = sizeof (UINT8);\r
- CertBuf = NULL;\r
-\r
- for (Index = 0; ; Index++) {\r
- Status = X509PopCertificate (CtxChain, &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 (CtxUntrusted != NULL) {\r
- BufferSize = sizeof (UINT8);\r
- CertBuf = NULL;\r
-\r
- for (Index = 0; ; Index++) {\r
- Status = X509PopCertificate (CtxUntrusted, &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
- if (CertCtx != NULL) {\r
- X509_STORE_CTX_cleanup (CertCtx);\r
- X509_STORE_CTX_free (CertCtx);\r
- }\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 validity 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
- Caution: This function may receive untrusted input.\r
- UEFI Authenticated Variable is external input, so this function will do basic\r
- check for PKCS#7 data structure.\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 *DataBio;\r
- BOOLEAN Status;\r
- X509 *Cert;\r
- X509_STORE *CertStore;\r
- UINT8 *SignedData;\r
- CONST 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
- DataBio = NULL;\r
- Cert = NULL;\r
- CertStore = NULL;\r
-\r
- //\r
- // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
- //\r
- if (EVP_add_digest (EVP_md5 ()) == 0) {\r
- return FALSE;\r
- }\r
- if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
- return FALSE;\r
- }\r
- if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
- return FALSE;\r
- }\r
- if (EVP_add_digest (EVP_sha384 ()) == 0) {\r
- return FALSE;\r
- }\r
- if (EVP_add_digest (EVP_sha512 ()) == 0) {\r
- return FALSE;\r
- }\r
- if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {\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
-\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
- //\r
- // Read DER-encoded root certificate and Construct X509 Certificate\r
- //\r
- Temp = TrustedCert;\r
- Cert = d2i_X509 (NULL, &Temp, (long) CertLength);\r
- if (Cert == NULL) {\r
- goto _Exit;\r
- }\r
-\r
- //\r
- // Setup X509 Store for trusted certificate\r
- //\r
- CertStore = X509_STORE_new ();\r
- if (CertStore == NULL) {\r
- goto _Exit;\r
- }\r
- if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
- goto _Exit;\r
- }\r
-\r
- //\r
- // For generic PKCS#7 handling, InData may be NULL if the content is present\r
- // in PKCS#7 structure. So ignore NULL checking here.\r
- //\r
- DataBio = BIO_new (BIO_s_mem ());\r
- if (DataBio == NULL) {\r
- goto _Exit;\r
- }\r
-\r
- if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {\r
- goto _Exit;\r
- }\r
-\r
- //\r
- // Allow partial certificate chains, terminated by a non-self-signed but\r
- // still trusted intermediate certificate. Also disable time checks.\r
- //\r
- X509_STORE_set_flags (CertStore,\r
- X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);\r
-\r
- //\r
- // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and\r
- // doesn't support the extended key usage for Authenticode Code Signing.\r
- // Bypass the certificate purpose checking by enabling any purposes setting.\r
- //\r
- X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
-\r
- //\r
- // Verifies the PKCS#7 signedData structure\r
- //\r
- Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
-\r
-_Exit:\r
- //\r
- // Release Resources\r
- //\r
- BIO_free (DataBio);\r
- X509_free (Cert);\r
- X509_STORE_free (CertStore);\r
- PKCS7_free (Pkcs7);\r
-\r
- if (!Wrapped) {\r
- OPENSSL_free (SignedData);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Extracts the attached content from a PKCS#7 signed data if existed. The input signed\r
- data could be wrapped in a ContentInfo structure.\r
-\r
- If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,\r
- then return FALSE. If the P7Data is not correctly formatted, then return FALSE.\r
-\r
- Caution: This function may receive untrusted input. So this function will do\r
- basic check for PKCS#7 data structure.\r
-\r
- @param[in] P7Data Pointer to the PKCS#7 signed data to process.\r
- @param[in] P7Length Length of the PKCS#7 signed data in bytes.\r
- @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.\r
- It's caller's responsibility to free the buffer with FreePool().\r
- @param[out] ContentSize The size of the extracted content in bytes.\r
-\r
- @retval TRUE The P7Data was correctly formatted for processing.\r
- @retval FALSE The P7Data was not correctly formatted for processing.\r
-\r
-**/\r
-BOOLEAN\r
-EFIAPI\r
-Pkcs7GetAttachedContent (\r
- IN CONST UINT8 *P7Data,\r
- IN UINTN P7Length,\r
- OUT VOID **Content,\r
- OUT UINTN *ContentSize\r
- )\r
-{\r
- BOOLEAN Status;\r
- PKCS7 *Pkcs7;\r
- UINT8 *SignedData;\r
- UINTN SignedDataSize;\r
- BOOLEAN Wrapped;\r
- CONST UINT8 *Temp;\r
- ASN1_OCTET_STRING *OctStr;\r
-\r
- //\r
- // Check input parameter.\r
- //\r
- if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {\r
- return FALSE;\r
- }\r
-\r
- *Content = NULL;\r
- Pkcs7 = NULL;\r
- SignedData = NULL;\r
- OctStr = NULL;\r
-\r
- Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
- if (!Status || (SignedDataSize > INT_MAX)) {\r
- goto _Exit;\r
- }\r
-\r
- Status = FALSE;\r
-\r
- //\r
- // Decoding PKCS#7 SignedData\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
- // The type of Pkcs7 must be signedData\r
- //\r
- if (!PKCS7_type_is_signed (Pkcs7)) {\r
- goto _Exit;\r
- }\r
-\r
- //\r
- // Check for detached or attached content\r
- //\r
- if (PKCS7_get_detached (Pkcs7)) {\r
- //\r
- // No Content supplied for PKCS7 detached signedData\r
- //\r
- *Content = NULL;\r
- *ContentSize = 0;\r
- } else {\r
- //\r
- // Retrieve the attached content in PKCS7 signedData\r
- //\r
- OctStr = Pkcs7->d.sign->contents->d.data;\r
- if ((OctStr->length > 0) && (OctStr->data != NULL)) {\r
- *ContentSize = OctStr->length;\r
- *Content = AllocatePool (*ContentSize);\r
- if (*Content == NULL) {\r
- *ContentSize = 0;\r
- goto _Exit;\r
- }\r
- CopyMem (*Content, OctStr->data, *ContentSize);\r
- }\r
- }\r
- Status = TRUE;\r
-\r
-_Exit:\r
- //\r
- // Release Resources\r
- //\r
- PKCS7_free (Pkcs7);\r
-\r
- if (!Wrapped) {\r
- OPENSSL_free (SignedData);\r
- }\r
-\r
- return Status;\r
-}\r
--- /dev/null
+/** @file\r
+ Non-runtime specific implementation of PKCS#7 SignedData Verification Wrapper.\r
+\r
+Copyright (c) 2019, 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/x509v3.h>\r
+#include <openssl/pkcs7.h>\r
+\r
+/**\r
+ Extracts the attached content from a PKCS#7 signed data if existed. The input signed\r
+ data could be wrapped in a ContentInfo structure.\r
+\r
+ If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,\r
+ then return FALSE. If the P7Data is not correctly formatted, then return FALSE.\r
+\r
+ Caution: This function may receive untrusted input. So this function will do\r
+ basic check for PKCS#7 data structure.\r
+\r
+ @param[in] P7Data Pointer to the PKCS#7 signed data to process.\r
+ @param[in] P7Length Length of the PKCS#7 signed data in bytes.\r
+ @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.\r
+ It's caller's responsibility to free the buffer with FreePool().\r
+ @param[out] ContentSize The size of the extracted content in bytes.\r
+\r
+ @retval TRUE The P7Data was correctly formatted for processing.\r
+ @retval FALSE The P7Data was not correctly formatted for processing.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Pkcs7GetAttachedContent (\r
+ IN CONST UINT8 *P7Data,\r
+ IN UINTN P7Length,\r
+ OUT VOID **Content,\r
+ OUT UINTN *ContentSize\r
+ )\r
+{\r
+ BOOLEAN Status;\r
+ PKCS7 *Pkcs7;\r
+ UINT8 *SignedData;\r
+ UINTN SignedDataSize;\r
+ BOOLEAN Wrapped;\r
+ CONST UINT8 *Temp;\r
+ ASN1_OCTET_STRING *OctStr;\r
+\r
+ //\r
+ // Check input parameter.\r
+ //\r
+ if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {\r
+ return FALSE;\r
+ }\r
+\r
+ *Content = NULL;\r
+ Pkcs7 = NULL;\r
+ SignedData = NULL;\r
+ OctStr = NULL;\r
+\r
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
+ if (!Status || (SignedDataSize > INT_MAX)) {\r
+ goto _Exit;\r
+ }\r
+\r
+ Status = FALSE;\r
+\r
+ //\r
+ // Decoding PKCS#7 SignedData\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
+ // The type of Pkcs7 must be signedData\r
+ //\r
+ if (!PKCS7_type_is_signed (Pkcs7)) {\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Check for detached or attached content\r
+ //\r
+ if (PKCS7_get_detached (Pkcs7)) {\r
+ //\r
+ // No Content supplied for PKCS7 detached signedData\r
+ //\r
+ *Content = NULL;\r
+ *ContentSize = 0;\r
+ } else {\r
+ //\r
+ // Retrieve the attached content in PKCS7 signedData\r
+ //\r
+ OctStr = Pkcs7->d.sign->contents->d.data;\r
+ if ((OctStr->length > 0) && (OctStr->data != NULL)) {\r
+ *ContentSize = OctStr->length;\r
+ *Content = AllocatePool (*ContentSize);\r
+ if (*Content == NULL) {\r
+ *ContentSize = 0;\r
+ goto _Exit;\r
+ }\r
+ CopyMem (*Content, OctStr->data, *ContentSize);\r
+ }\r
+ }\r
+ Status = TRUE;\r
+\r
+_Exit:\r
+ //\r
+ // Release Resources\r
+ //\r
+ PKCS7_free (Pkcs7);\r
+\r
+ if (!Wrapped) {\r
+ OPENSSL_free (SignedData);\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
+\r
+ Caution: This module requires additional review when modified.\r
+ This library will have external input - signature (e.g. UEFI Authenticated\r
+ Variable). It may by input in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+\r
+ WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated\r
+ Variable and will do basic check for data structure.\r
+\r
+Copyright (c) 2009 - 2019, 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/x509v3.h>\r
+#include <openssl/pkcs7.h>\r
+\r
+UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };\r
+\r
+/**\r
+ Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
+ a new structure to wrap P7Data.\r
+\r
+ Caution: This function may receive untrusted input.\r
+ UEFI Authenticated Variable is external input, so this function will do basic\r
+ check for PKCS#7 data structure.\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] 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
+WrapPkcs7Data (\r
+ IN CONST UINT8 *P7Data,\r
+ IN UINTN P7Length,\r
+ OUT BOOLEAN *WrapFlag,\r
+ OUT UINT8 **WrapData,\r
+ OUT UINTN *WrapDataSize\r
+ )\r
+{\r
+ BOOLEAN Wrapped;\r
+ UINT8 *SignedData;\r
+\r
+ //\r
+ // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
+ //\r
+ Wrapped = FALSE;\r
+ if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {\r
+ if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {\r
+ if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {\r
+ Wrapped = TRUE;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Wrapped) {\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
+ *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
+ SignedData[0] = 0x30;\r
+ SignedData[1] = 0x82;\r
+\r
+ //\r
+ // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
+ //\r
+ SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);\r
+ SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);\r
+\r
+ //\r
+ // Part3: 0x06, 0x09.\r
+ //\r
+ SignedData[4] = 0x06;\r
+ SignedData[5] = 0x09;\r
+\r
+ //\r
+ // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.\r
+ //\r
+ CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));\r
+\r
+ //\r
+ // Part5: 0xA0, 0x82.\r
+ //\r
+ SignedData[15] = 0xA0;\r
+ SignedData[16] = 0x82;\r
+\r
+ //\r
+ // Part6: Length2 = P7Length, in big endian.\r
+ //\r
+ SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);\r
+ SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);\r
+\r
+ //\r
+ // Part7: P7Data.\r
+ //\r
+ CopyMem (SignedData + 19, P7Data, P7Length);\r
+ }\r
+\r
+ *WrapFlag = Wrapped;\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Pop single certificate from STACK_OF(X509).\r
+\r
+ If X509Stack, Cert, or CertSize is NULL, then return FALSE.\r
+\r
+ @param[in] X509Stack Pointer to a X509 stack object.\r
+ @param[out] Cert Pointer to a X509 certificate.\r
+ @param[out] CertSize Length of output X509 certificate in bytes.\r
+\r
+ @retval TRUE The X509 stack pop succeeded.\r
+ @retval FALSE The pop operation failed.\r
+\r
+**/\r
+BOOLEAN\r
+X509PopCertificate (\r
+ IN VOID *X509Stack,\r
+ OUT UINT8 **Cert,\r
+ OUT UINTN *CertSize\r
+ )\r
+{\r
+ BIO *CertBio;\r
+ X509 *X509Cert;\r
+ STACK_OF(X509) *CertStack;\r
+ BOOLEAN Status;\r
+ INT32 Result;\r
+ BUF_MEM *Ptr;\r
+ INT32 Length;\r
+ VOID *Buffer;\r
+\r
+ Status = FALSE;\r
+\r
+ if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {\r
+ return Status;\r
+ }\r
+\r
+ CertStack = (STACK_OF(X509) *) X509Stack;\r
+\r
+ X509Cert = sk_X509_pop (CertStack);\r
+\r
+ if (X509Cert == NULL) {\r
+ return Status;\r
+ }\r
+\r
+ Buffer = NULL;\r
+\r
+ CertBio = BIO_new (BIO_s_mem ());\r
+ if (CertBio == NULL) {\r
+ return Status;\r
+ }\r
+\r
+ Result = i2d_X509_bio (CertBio, X509Cert);\r
+ if (Result == 0) {\r
+ goto _Exit;\r
+ }\r
+\r
+ BIO_get_mem_ptr (CertBio, &Ptr);\r
+ Length = (INT32)(Ptr->length);\r
+ if (Length <= 0) {\r
+ goto _Exit;\r
+ }\r
+\r
+ Buffer = malloc (Length);\r
+ if (Buffer == NULL) {\r
+ goto _Exit;\r
+ }\r
+\r
+ Result = BIO_read (CertBio, Buffer, Length);\r
+ if (Result != Length) {\r
+ goto _Exit;\r
+ }\r
+\r
+ *Cert = Buffer;\r
+ *CertSize = Length;\r
+\r
+ Status = TRUE;\r
+\r
+_Exit:\r
+\r
+ BIO_free (CertBio);\r
+\r
+ if (!Status && (Buffer != NULL)) {\r
+ free (Buffer);\r
+ }\r
+\r
+ return Status;\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
+ Caution: This function may receive untrusted input.\r
+ UEFI Authenticated Variable is external input, so this function will do basic\r
+ check for PKCS#7 data structure.\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 responsibility to free the buffer with\r
+ Pkcs7FreeSigners().\r
+ This data structure is EFI_CERT_STACK type.\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 responsibility to free the buffer with\r
+ Pkcs7FreeSigners().\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
+ CONST 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
+ 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] SignerChainCerts Pointer to the certificates list chained to signer's\r
+ certificate. It's caller's responsibility to free the buffer\r
+ with Pkcs7FreeSigners().\r
+ This data structure is EFI_CERT_STACK type.\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
+ responsibility to free the buffer with Pkcs7FreeSigners().\r
+ This data structure is EFI_CERT_STACK type.\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) *CtxChain;\r
+ STACK_OF(X509) *CtxUntrusted;\r
+ X509 *CtxCert;\r
+ STACK_OF(X509) *Signers;\r
+ X509 *Signer;\r
+ X509 *Cert;\r
+ X509 *Issuer;\r
+ X509_NAME *IssuerName;\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
+ CertCtx = NULL;\r
+ CtxChain = NULL;\r
+ CtxCert = NULL;\r
+ CtxUntrusted = NULL;\r
+ Cert = NULL;\r
+ SingleCert = NULL;\r
+ CertBuf = NULL;\r
+ OldBuf = NULL;\r
+ Signers = NULL;\r
+\r
+ ZeroMem (&CertCtx, sizeof (CertCtx));\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 signer'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
+ CertCtx = X509_STORE_CTX_new ();\r
+ if (CertCtx == NULL) {\r
+ goto _Error;\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
+ CtxChain = X509_STORE_CTX_get0_chain (CertCtx);\r
+ CtxCert = X509_STORE_CTX_get0_cert (CertCtx);\r
+ if (CtxChain == NULL) {\r
+ if (((CtxChain = sk_X509_new_null ()) == NULL) ||\r
+ (!sk_X509_push (CtxChain, CtxCert))) {\r
+ goto _Error;\r
+ }\r
+ }\r
+ CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);\r
+ if (CtxUntrusted != NULL) {\r
+ (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);\r
+ }\r
+\r
+ //\r
+ // Build certificates stack chained from Signer's certificate.\r
+ //\r
+ Cert = Signer;\r
+ for (; ;) {\r
+ //\r
+ // Self-Issue checking\r
+ //\r
+ Issuer = NULL;\r
+ if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {\r
+ if (X509_cmp (Issuer, Cert) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Found the issuer of the current certificate\r
+ //\r
+ if (CtxUntrusted != NULL) {\r
+ Issuer = NULL;\r
+ IssuerName = X509_get_issuer_name (Cert);\r
+ Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);\r
+ if (Issuer != NULL) {\r
+ if (!sk_X509_push (CtxChain, Issuer)) {\r
+ goto _Error;\r
+ }\r
+ (VOID)sk_X509_delete_ptr (CtxUntrusted, 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 (CtxChain != NULL) {\r
+ BufferSize = sizeof (UINT8);\r
+ CertBuf = NULL;\r
+\r
+ for (Index = 0; ; Index++) {\r
+ Status = X509PopCertificate (CtxChain, &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 (CtxUntrusted != NULL) {\r
+ BufferSize = sizeof (UINT8);\r
+ CertBuf = NULL;\r
+\r
+ for (Index = 0; ; Index++) {\r
+ Status = X509PopCertificate (CtxUntrusted, &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
+ if (CertCtx != NULL) {\r
+ X509_STORE_CTX_cleanup (CertCtx);\r
+ X509_STORE_CTX_free (CertCtx);\r
+ }\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 validity 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
+ Caution: This function may receive untrusted input.\r
+ UEFI Authenticated Variable is external input, so this function will do basic\r
+ check for PKCS#7 data structure.\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 *DataBio;\r
+ BOOLEAN Status;\r
+ X509 *Cert;\r
+ X509_STORE *CertStore;\r
+ UINT8 *SignedData;\r
+ CONST 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
+ DataBio = NULL;\r
+ Cert = NULL;\r
+ CertStore = NULL;\r
+\r
+ //\r
+ // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
+ //\r
+ if (EVP_add_digest (EVP_md5 ()) == 0) {\r
+ return FALSE;\r
+ }\r
+ if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
+ return FALSE;\r
+ }\r
+ if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
+ return FALSE;\r
+ }\r
+ if (EVP_add_digest (EVP_sha384 ()) == 0) {\r
+ return FALSE;\r
+ }\r
+ if (EVP_add_digest (EVP_sha512 ()) == 0) {\r
+ return FALSE;\r
+ }\r
+ if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {\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
+\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
+ //\r
+ // Read DER-encoded root certificate and Construct X509 Certificate\r
+ //\r
+ Temp = TrustedCert;\r
+ Cert = d2i_X509 (NULL, &Temp, (long) CertLength);\r
+ if (Cert == NULL) {\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Setup X509 Store for trusted certificate\r
+ //\r
+ CertStore = X509_STORE_new ();\r
+ if (CertStore == NULL) {\r
+ goto _Exit;\r
+ }\r
+ if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // For generic PKCS#7 handling, InData may be NULL if the content is present\r
+ // in PKCS#7 structure. So ignore NULL checking here.\r
+ //\r
+ DataBio = BIO_new (BIO_s_mem ());\r
+ if (DataBio == NULL) {\r
+ goto _Exit;\r
+ }\r
+\r
+ if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Allow partial certificate chains, terminated by a non-self-signed but\r
+ // still trusted intermediate certificate. Also disable time checks.\r
+ //\r
+ X509_STORE_set_flags (CertStore,\r
+ X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);\r
+\r
+ //\r
+ // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and\r
+ // doesn't support the extended key usage for Authenticode Code Signing.\r
+ // Bypass the certificate purpose checking by enabling any purposes setting.\r
+ //\r
+ X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
+\r
+ //\r
+ // Verifies the PKCS#7 signedData structure\r
+ //\r
+ Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
+\r
+_Exit:\r
+ //\r
+ // Release Resources\r
+ //\r
+ BIO_free (DataBio);\r
+ X509_free (Cert);\r
+ X509_STORE_free (CertStore);\r
+ PKCS7_free (Pkcs7);\r
+\r
+ if (!Wrapped) {\r
+ OPENSSL_free (SignedData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ Runtime specific implementation of PKCS#7 SignedData Verification Wrapper.\r
+\r
+Copyright (c) 2019, 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
+/**\r
+ Extracts the attached content from a PKCS#7 signed data if existed. The input signed\r
+ data could be wrapped in a ContentInfo structure.\r
+\r
+ Return FALSE to indicate this interface is not supported.\r
+\r
+ @param[in] P7Data Pointer to the PKCS#7 signed data to process.\r
+ @param[in] P7Length Length of the PKCS#7 signed data in bytes.\r
+ @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.\r
+ It's caller's responsibility to free the buffer with FreePool().\r
+ @param[out] ContentSize The size of the extracted content in bytes.\r
+\r
+ @retval TRUE The P7Data was correctly formatted for processing.\r
+ @retval FALSE The P7Data was not correctly formatted for processing.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Pkcs7GetAttachedContent (\r
+ IN CONST UINT8 *P7Data,\r
+ IN UINTN P7Length,\r
+ OUT VOID **Content,\r
+ OUT UINTN *ContentSize\r
+ )\r
+{\r
+ ASSERT (FALSE);\r
+ return FALSE;\r
+}\r
+\r
# functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and\r
# authenticode signature verification functions are not supported in this instance.\r
#\r
-# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2009 - 2019, 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
Pk/CryptRsaExtNull.c\r
Pk/CryptPkcs5Pbkdf2Null.c\r
Pk/CryptPkcs7SignNull.c\r
- Pk/CryptPkcs7Verify.c\r
+ Pk/CryptPkcs7VerifyCommon.c\r
+ Pk/CryptPkcs7VerifyRuntime.c\r
Pk/CryptDhNull.c\r
Pk/CryptX509.c\r
Pk/CryptAuthenticodeNull.c\r
[LibraryClasses]\r
BaseLib\r
BaseMemoryLib\r
- MemoryAllocationLib\r
UefiBootServicesTableLib\r
UefiRuntimeServicesTableLib\r
DebugLib\r
# functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and\r
# authenticode signature verification functions are not supported in this instance.\r
#\r
-# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2010 - 2019, 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
Pk/CryptRsaExtNull.c\r
Pk/CryptPkcs5Pbkdf2.c\r
Pk/CryptPkcs7SignNull.c\r
- Pk/CryptPkcs7Verify.c\r
+ Pk/CryptPkcs7VerifyCommon.c\r
+ Pk/CryptPkcs7VerifyBase.c\r
Pk/CryptDhNull.c\r
Pk/CryptX509.c\r
Pk/CryptAuthenticodeNull.c\r