123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910 |
- /** @file
- PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.
- Caution: This module requires additional review when modified.
- This library will have external input - signature (e.g. UEFI Authenticated
- Variable). It may by input in SMM mode.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
- WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated
- Variable and will do basic check for data structure.
- Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "InternalCryptLib.h"
- #include <openssl/objects.h>
- #include <openssl/x509.h>
- #include <openssl/x509v3.h>
- #include <openssl/pkcs7.h>
- UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
- /**
- Check input P7Data is a wrapped ContentInfo structure or not. If not construct
- a new structure to wrap P7Data.
- Caution: This function may receive untrusted input.
- UEFI Authenticated Variable is external input, so this function will do basic
- check for PKCS#7 data structure.
- @param[in] P7Data Pointer to the PKCS#7 message to verify.
- @param[in] P7Length Length of the PKCS#7 message in bytes.
- @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise
- return FALSE.
- @param[out] WrapData If return status of this function is TRUE:
- 1) when WrapFlag is TRUE, pointer to P7Data.
- 2) when WrapFlag is FALSE, pointer to a new ContentInfo
- structure. It's caller's responsibility to free this
- buffer.
- @param[out] WrapDataSize Length of ContentInfo structure in bytes.
- @retval TRUE The operation is finished successfully.
- @retval FALSE The operation is failed due to lack of resources.
- **/
- BOOLEAN
- WrapPkcs7Data (
- IN CONST UINT8 *P7Data,
- IN UINTN P7Length,
- OUT BOOLEAN *WrapFlag,
- OUT UINT8 **WrapData,
- OUT UINTN *WrapDataSize
- )
- {
- BOOLEAN Wrapped;
- UINT8 *SignedData;
- //
- // Check whether input P7Data is a wrapped ContentInfo structure or not.
- //
- Wrapped = FALSE;
- if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {
- if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {
- if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {
- Wrapped = TRUE;
- }
- }
- }
- if (Wrapped) {
- *WrapData = (UINT8 *) P7Data;
- *WrapDataSize = P7Length;
- } else {
- //
- // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.
- //
- *WrapDataSize = P7Length + 19;
- *WrapData = malloc (*WrapDataSize);
- if (*WrapData == NULL) {
- *WrapFlag = Wrapped;
- return FALSE;
- }
- SignedData = *WrapData;
- //
- // Part1: 0x30, 0x82.
- //
- SignedData[0] = 0x30;
- SignedData[1] = 0x82;
- //
- // Part2: Length1 = P7Length + 19 - 4, in big endian.
- //
- SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);
- SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);
- //
- // Part3: 0x06, 0x09.
- //
- SignedData[4] = 0x06;
- SignedData[5] = 0x09;
- //
- // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.
- //
- CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));
- //
- // Part5: 0xA0, 0x82.
- //
- SignedData[15] = 0xA0;
- SignedData[16] = 0x82;
- //
- // Part6: Length2 = P7Length, in big endian.
- //
- SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);
- SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);
- //
- // Part7: P7Data.
- //
- CopyMem (SignedData + 19, P7Data, P7Length);
- }
- *WrapFlag = Wrapped;
- return TRUE;
- }
- /**
- Pop single certificate from STACK_OF(X509).
- If X509Stack, Cert, or CertSize is NULL, then return FALSE.
- @param[in] X509Stack Pointer to a X509 stack object.
- @param[out] Cert Pointer to a X509 certificate.
- @param[out] CertSize Length of output X509 certificate in bytes.
- @retval TRUE The X509 stack pop succeeded.
- @retval FALSE The pop operation failed.
- **/
- BOOLEAN
- X509PopCertificate (
- IN VOID *X509Stack,
- OUT UINT8 **Cert,
- OUT UINTN *CertSize
- )
- {
- BIO *CertBio;
- X509 *X509Cert;
- STACK_OF(X509) *CertStack;
- BOOLEAN Status;
- INT32 Result;
- BUF_MEM *Ptr;
- INT32 Length;
- VOID *Buffer;
- Status = FALSE;
- if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {
- return Status;
- }
- CertStack = (STACK_OF(X509) *) X509Stack;
- X509Cert = sk_X509_pop (CertStack);
- if (X509Cert == NULL) {
- return Status;
- }
- Buffer = NULL;
- CertBio = BIO_new (BIO_s_mem ());
- if (CertBio == NULL) {
- return Status;
- }
- Result = i2d_X509_bio (CertBio, X509Cert);
- if (Result == 0) {
- goto _Exit;
- }
- BIO_get_mem_ptr (CertBio, &Ptr);
- Length = (INT32)(Ptr->length);
- if (Length <= 0) {
- goto _Exit;
- }
- Buffer = malloc (Length);
- if (Buffer == NULL) {
- goto _Exit;
- }
- Result = BIO_read (CertBio, Buffer, Length);
- if (Result != Length) {
- goto _Exit;
- }
- *Cert = Buffer;
- *CertSize = Length;
- Status = TRUE;
- _Exit:
- BIO_free (CertBio);
- if (!Status && (Buffer != NULL)) {
- free (Buffer);
- }
- return Status;
- }
- /**
- Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:
- Cryptographic Message Syntax Standard". The input signed data could be wrapped
- in a ContentInfo structure.
- If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then
- return FALSE. If P7Length overflow, then return FALSE.
- Caution: This function may receive untrusted input.
- UEFI Authenticated Variable is external input, so this function will do basic
- check for PKCS#7 data structure.
- @param[in] P7Data Pointer to the PKCS#7 message to verify.
- @param[in] P7Length Length of the PKCS#7 message in bytes.
- @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.
- It's caller's responsibility to free the buffer with
- Pkcs7FreeSigners().
- This data structure is EFI_CERT_STACK type.
- @param[out] StackLength Length of signer's certificates in bytes.
- @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.
- It's caller's responsibility to free the buffer with
- Pkcs7FreeSigners().
- @param[out] CertLength Length of the trusted certificate in bytes.
- @retval TRUE The operation is finished successfully.
- @retval FALSE Error occurs during the operation.
- **/
- BOOLEAN
- EFIAPI
- Pkcs7GetSigners (
- IN CONST UINT8 *P7Data,
- IN UINTN P7Length,
- OUT UINT8 **CertStack,
- OUT UINTN *StackLength,
- OUT UINT8 **TrustedCert,
- OUT UINTN *CertLength
- )
- {
- PKCS7 *Pkcs7;
- BOOLEAN Status;
- UINT8 *SignedData;
- CONST UINT8 *Temp;
- UINTN SignedDataSize;
- BOOLEAN Wrapped;
- STACK_OF(X509) *Stack;
- UINT8 Index;
- UINT8 *CertBuf;
- UINT8 *OldBuf;
- UINTN BufferSize;
- UINTN OldSize;
- UINT8 *SingleCert;
- UINTN SingleCertSize;
- if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||
- (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) {
- return FALSE;
- }
- Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
- if (!Status) {
- return Status;
- }
- Status = FALSE;
- Pkcs7 = NULL;
- Stack = NULL;
- CertBuf = NULL;
- OldBuf = NULL;
- SingleCert = NULL;
- //
- // Retrieve PKCS#7 Data (DER encoding)
- //
- if (SignedDataSize > INT_MAX) {
- goto _Exit;
- }
- Temp = SignedData;
- Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
- if (Pkcs7 == NULL) {
- goto _Exit;
- }
- //
- // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
- //
- if (!PKCS7_type_is_signed (Pkcs7)) {
- goto _Exit;
- }
- Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY);
- if (Stack == NULL) {
- goto _Exit;
- }
- //
- // Convert CertStack to buffer in following format:
- // UINT8 CertNumber;
- // UINT32 Cert1Length;
- // UINT8 Cert1[];
- // UINT32 Cert2Length;
- // UINT8 Cert2[];
- // ...
- // UINT32 CertnLength;
- // UINT8 Certn[];
- //
- BufferSize = sizeof (UINT8);
- OldSize = BufferSize;
- for (Index = 0; ; Index++) {
- Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);
- if (!Status) {
- break;
- }
- OldSize = BufferSize;
- OldBuf = CertBuf;
- BufferSize = OldSize + SingleCertSize + sizeof (UINT32);
- CertBuf = malloc (BufferSize);
- if (CertBuf == NULL) {
- goto _Exit;
- }
- if (OldBuf != NULL) {
- CopyMem (CertBuf, OldBuf, OldSize);
- free (OldBuf);
- OldBuf = NULL;
- }
- WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize);
- CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);
- free (SingleCert);
- SingleCert = NULL;
- }
- if (CertBuf != NULL) {
- //
- // Update CertNumber.
- //
- CertBuf[0] = Index;
- *CertLength = BufferSize - OldSize - sizeof (UINT32);
- *TrustedCert = malloc (*CertLength);
- if (*TrustedCert == NULL) {
- goto _Exit;
- }
- CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);
- *CertStack = CertBuf;
- *StackLength = BufferSize;
- Status = TRUE;
- }
- _Exit:
- //
- // Release Resources
- //
- if (!Wrapped) {
- free (SignedData);
- }
- if (Pkcs7 != NULL) {
- PKCS7_free (Pkcs7);
- }
- if (Stack != NULL) {
- sk_X509_pop_free(Stack, X509_free);
- }
- if (SingleCert != NULL) {
- free (SingleCert);
- }
- if (!Status && (CertBuf != NULL)) {
- free (CertBuf);
- *CertStack = NULL;
- }
- if (OldBuf != NULL) {
- free (OldBuf);
- }
- return Status;
- }
- /**
- Wrap function to use free() to free allocated memory for certificates.
- @param[in] Certs Pointer to the certificates to be freed.
- **/
- VOID
- EFIAPI
- Pkcs7FreeSigners (
- IN UINT8 *Certs
- )
- {
- if (Certs == NULL) {
- return;
- }
- free (Certs);
- }
- /**
- 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] SignerChainCerts Pointer to the certificates list chained to signer's
- certificate. It's caller's responsibility to free the buffer
- with Pkcs7FreeSigners().
- This data structure is EFI_CERT_STACK type.
- @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
- responsibility to free the buffer with Pkcs7FreeSigners().
- This data structure is EFI_CERT_STACK type.
- @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) *CtxChain;
- STACK_OF(X509) *CtxUntrusted;
- X509 *CtxCert;
- STACK_OF(X509) *Signers;
- X509 *Signer;
- X509 *Cert;
- X509 *Issuer;
- X509_NAME *IssuerName;
- UINT8 *CertBuf;
- UINT8 *OldBuf;
- UINTN BufferSize;
- UINTN OldSize;
- UINT8 *SingleCert;
- UINTN CertSize;
- //
- // Initializations
- //
- Status = FALSE;
- NewP7Data = NULL;
- Pkcs7 = NULL;
- CertCtx = NULL;
- CtxChain = NULL;
- CtxCert = NULL;
- CtxUntrusted = NULL;
- Cert = NULL;
- SingleCert = NULL;
- CertBuf = NULL;
- OldBuf = NULL;
- Signers = NULL;
- ZeroMem (&CertCtx, sizeof (CertCtx));
- //
- // 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: Only one signer case will be handled in this function, which means SignerInfos
- // should include only one signer'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);
- CertCtx = X509_STORE_CTX_new ();
- if (CertCtx == NULL) {
- goto _Error;
- }
- if (!X509_STORE_CTX_init (CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {
- goto _Error;
- }
- //
- // Initialize Chained & Untrusted stack
- //
- CtxChain = X509_STORE_CTX_get0_chain (CertCtx);
- CtxCert = X509_STORE_CTX_get0_cert (CertCtx);
- if (CtxChain == NULL) {
- if (((CtxChain = sk_X509_new_null ()) == NULL) ||
- (!sk_X509_push (CtxChain, CtxCert))) {
- goto _Error;
- }
- }
- CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);
- if (CtxUntrusted != NULL) {
- (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);
- }
- //
- // Build certificates stack chained from Signer's certificate.
- //
- Cert = Signer;
- for (; ;) {
- //
- // Self-Issue checking
- //
- Issuer = NULL;
- if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {
- if (X509_cmp (Issuer, Cert) == 0) {
- break;
- }
- }
- //
- // Found the issuer of the current certificate
- //
- if (CtxUntrusted != NULL) {
- Issuer = NULL;
- IssuerName = X509_get_issuer_name (Cert);
- Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);
- if (Issuer != NULL) {
- if (!sk_X509_push (CtxChain, Issuer)) {
- goto _Error;
- }
- (VOID)sk_X509_delete_ptr (CtxUntrusted, 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 (CtxChain != NULL) {
- BufferSize = sizeof (UINT8);
- CertBuf = NULL;
- for (Index = 0; ; Index++) {
- Status = X509PopCertificate (CtxChain, &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 (CtxUntrusted != NULL) {
- BufferSize = sizeof (UINT8);
- CertBuf = NULL;
- for (Index = 0; ; Index++) {
- Status = X509PopCertificate (CtxUntrusted, &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);
- if (CertCtx != NULL) {
- X509_STORE_CTX_cleanup (CertCtx);
- X509_STORE_CTX_free (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 validity 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.
- If P7Data, TrustedCert or InData is NULL, then return FALSE.
- If P7Length, CertLength or DataLength overflow, then return FALSE.
- Caution: This function may receive untrusted input.
- UEFI Authenticated Variable is external input, so this function will do basic
- check for PKCS#7 data structure.
- @param[in] P7Data Pointer to the PKCS#7 message to verify.
- @param[in] P7Length Length of the PKCS#7 message in bytes.
- @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
- is used for certificate chain verification.
- @param[in] CertLength Length of the trusted certificate in bytes.
- @param[in] InData Pointer to the content to be verified.
- @param[in] DataLength Length of InData in bytes.
- @retval TRUE The specified PKCS#7 signed data is valid.
- @retval FALSE Invalid PKCS#7 signed data.
- **/
- BOOLEAN
- EFIAPI
- Pkcs7Verify (
- IN CONST UINT8 *P7Data,
- IN UINTN P7Length,
- IN CONST UINT8 *TrustedCert,
- IN UINTN CertLength,
- IN CONST UINT8 *InData,
- IN UINTN DataLength
- )
- {
- PKCS7 *Pkcs7;
- BIO *DataBio;
- BOOLEAN Status;
- X509 *Cert;
- X509_STORE *CertStore;
- UINT8 *SignedData;
- CONST UINT8 *Temp;
- UINTN SignedDataSize;
- BOOLEAN Wrapped;
- //
- // Check input parameters.
- //
- if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||
- P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {
- return FALSE;
- }
- Pkcs7 = NULL;
- DataBio = NULL;
- Cert = NULL;
- CertStore = NULL;
- //
- // Register & Initialize necessary digest algorithms for PKCS#7 Handling
- //
- if (EVP_add_digest (EVP_md5 ()) == 0) {
- return FALSE;
- }
- if (EVP_add_digest (EVP_sha1 ()) == 0) {
- return FALSE;
- }
- if (EVP_add_digest (EVP_sha256 ()) == 0) {
- return FALSE;
- }
- if (EVP_add_digest (EVP_sha384 ()) == 0) {
- return FALSE;
- }
- if (EVP_add_digest (EVP_sha512 ()) == 0) {
- return FALSE;
- }
- if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
- return FALSE;
- }
- Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
- if (!Status) {
- return Status;
- }
- Status = FALSE;
- //
- // Retrieve PKCS#7 Data (DER encoding)
- //
- if (SignedDataSize > INT_MAX) {
- goto _Exit;
- }
- Temp = SignedData;
- Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
- if (Pkcs7 == NULL) {
- goto _Exit;
- }
- //
- // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
- //
- if (!PKCS7_type_is_signed (Pkcs7)) {
- goto _Exit;
- }
- //
- // Read DER-encoded root certificate and Construct X509 Certificate
- //
- Temp = TrustedCert;
- Cert = d2i_X509 (NULL, &Temp, (long) CertLength);
- if (Cert == NULL) {
- goto _Exit;
- }
- //
- // Setup X509 Store for trusted certificate
- //
- CertStore = X509_STORE_new ();
- if (CertStore == NULL) {
- goto _Exit;
- }
- if (!(X509_STORE_add_cert (CertStore, Cert))) {
- goto _Exit;
- }
- //
- // For generic PKCS#7 handling, InData may be NULL if the content is present
- // in PKCS#7 structure. So ignore NULL checking here.
- //
- DataBio = BIO_new (BIO_s_mem ());
- if (DataBio == NULL) {
- goto _Exit;
- }
- if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {
- goto _Exit;
- }
- //
- // Allow partial certificate chains, terminated by a non-self-signed but
- // still trusted intermediate certificate. Also disable time checks.
- //
- X509_STORE_set_flags (CertStore,
- X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
- //
- // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and
- // doesn't support the extended key usage for Authenticode Code Signing.
- // Bypass the certificate purpose checking by enabling any purposes setting.
- //
- X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
- //
- // Verifies the PKCS#7 signedData structure
- //
- Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);
- _Exit:
- //
- // Release Resources
- //
- BIO_free (DataBio);
- X509_free (Cert);
- X509_STORE_free (CertStore);
- PKCS7_free (Pkcs7);
- if (!Wrapped) {
- OPENSSL_free (SignedData);
- }
- return Status;
- }
|