Home | History | Annotate | Download | only in Pk
      1 /** @file
      2   PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.
      3 
      4   Caution: This module requires additional review when modified.
      5   This library will have external input - signature (e.g. UEFI Authenticated
      6   Variable). It may by input in SMM mode.
      7   This external input must be validated carefully to avoid security issue like
      8   buffer overflow, integer overflow.
      9 
     10   WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated
     11   Variable and will do basic check for data structure.
     12 
     13 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
     14 This program and the accompanying materials
     15 are licensed and made available under the terms and conditions of the BSD License
     16 which accompanies this distribution.  The full text of the license may be found at
     17 http://opensource.org/licenses/bsd-license.php
     18 
     19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     21 
     22 **/
     23 
     24 #include "InternalCryptLib.h"
     25 
     26 #include <openssl/objects.h>
     27 #include <openssl/x509.h>
     28 #include <openssl/x509v3.h>
     29 #include <openssl/pkcs7.h>
     30 
     31 UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };
     32 
     33 /**
     34   Check input P7Data is a wrapped ContentInfo structure or not. If not construct
     35   a new structure to wrap P7Data.
     36 
     37   Caution: This function may receive untrusted input.
     38   UEFI Authenticated Variable is external input, so this function will do basic
     39   check for PKCS#7 data structure.
     40 
     41   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.
     42   @param[in]  P7Length     Length of the PKCS#7 message in bytes.
     43   @param[out] WrapFlag     If TRUE P7Data is a ContentInfo structure, otherwise
     44                            return FALSE.
     45   @param[out] WrapData     If return status of this function is TRUE:
     46                            1) when WrapFlag is TRUE, pointer to P7Data.
     47                            2) when WrapFlag is FALSE, pointer to a new ContentInfo
     48                            structure. It's caller's responsibility to free this
     49                            buffer.
     50   @param[out] WrapDataSize Length of ContentInfo structure in bytes.
     51 
     52   @retval     TRUE         The operation is finished successfully.
     53   @retval     FALSE        The operation is failed due to lack of resources.
     54 
     55 **/
     56 BOOLEAN
     57 WrapPkcs7Data (
     58   IN  CONST UINT8  *P7Data,
     59   IN  UINTN        P7Length,
     60   OUT BOOLEAN      *WrapFlag,
     61   OUT UINT8        **WrapData,
     62   OUT UINTN        *WrapDataSize
     63   )
     64 {
     65   BOOLEAN          Wrapped;
     66   UINT8            *SignedData;
     67 
     68   //
     69   // Check whether input P7Data is a wrapped ContentInfo structure or not.
     70   //
     71   Wrapped = FALSE;
     72   if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {
     73     if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {
     74       if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {
     75         Wrapped = TRUE;
     76       }
     77     }
     78   }
     79 
     80   if (Wrapped) {
     81     *WrapData     = (UINT8 *) P7Data;
     82     *WrapDataSize = P7Length;
     83   } else {
     84     //
     85     // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.
     86     //
     87     *WrapDataSize = P7Length + 19;
     88     *WrapData     = malloc (*WrapDataSize);
     89     if (*WrapData == NULL) {
     90       *WrapFlag = Wrapped;
     91       return FALSE;
     92     }
     93 
     94     SignedData = *WrapData;
     95 
     96     //
     97     // Part1: 0x30, 0x82.
     98     //
     99     SignedData[0] = 0x30;
    100     SignedData[1] = 0x82;
    101 
    102     //
    103     // Part2: Length1 = P7Length + 19 - 4, in big endian.
    104     //
    105     SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8);
    106     SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff);
    107 
    108     //
    109     // Part3: 0x06, 0x09.
    110     //
    111     SignedData[4] = 0x06;
    112     SignedData[5] = 0x09;
    113 
    114     //
    115     // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.
    116     //
    117     CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));
    118 
    119     //
    120     // Part5: 0xA0, 0x82.
    121     //
    122     SignedData[15] = 0xA0;
    123     SignedData[16] = 0x82;
    124 
    125     //
    126     // Part6: Length2 = P7Length, in big endian.
    127     //
    128     SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8);
    129     SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff);
    130 
    131     //
    132     // Part7: P7Data.
    133     //
    134     CopyMem (SignedData + 19, P7Data, P7Length);
    135   }
    136 
    137   *WrapFlag = Wrapped;
    138   return TRUE;
    139 }
    140 
    141 /**
    142   Pop single certificate from STACK_OF(X509).
    143 
    144   If X509Stack, Cert, or CertSize is NULL, then return FALSE.
    145 
    146   @param[in]  X509Stack       Pointer to a X509 stack object.
    147   @param[out] Cert            Pointer to a X509 certificate.
    148   @param[out] CertSize        Length of output X509 certificate in bytes.
    149 
    150   @retval     TRUE            The X509 stack pop succeeded.
    151   @retval     FALSE           The pop operation failed.
    152 
    153 **/
    154 BOOLEAN
    155 X509PopCertificate (
    156   IN  VOID  *X509Stack,
    157   OUT UINT8 **Cert,
    158   OUT UINTN *CertSize
    159   )
    160 {
    161   BIO             *CertBio;
    162   X509            *X509Cert;
    163   STACK_OF(X509)  *CertStack;
    164   BOOLEAN         Status;
    165   INT32           Result;
    166   INT32           Length;
    167   VOID            *Buffer;
    168 
    169   Status = FALSE;
    170 
    171   if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {
    172     return Status;
    173   }
    174 
    175   CertStack = (STACK_OF(X509) *) X509Stack;
    176 
    177   X509Cert = sk_X509_pop (CertStack);
    178 
    179   if (X509Cert == NULL) {
    180     return Status;
    181   }
    182 
    183   Buffer = NULL;
    184 
    185   CertBio = BIO_new (BIO_s_mem ());
    186   if (CertBio == NULL) {
    187     return Status;
    188   }
    189 
    190   Result = i2d_X509_bio (CertBio, X509Cert);
    191   if (Result == 0) {
    192     goto _Exit;
    193   }
    194 
    195   Length = (INT32)(((BUF_MEM *) CertBio->ptr)->length);
    196   if (Length <= 0) {
    197     goto _Exit;
    198   }
    199 
    200   Buffer = malloc (Length);
    201   if (Buffer == NULL) {
    202     goto _Exit;
    203   }
    204 
    205   Result = BIO_read (CertBio, Buffer, Length);
    206   if (Result != Length) {
    207     goto _Exit;
    208   }
    209 
    210   *Cert     = Buffer;
    211   *CertSize = Length;
    212 
    213   Status = TRUE;
    214 
    215 _Exit:
    216 
    217   BIO_free (CertBio);
    218 
    219   if (!Status && (Buffer != NULL)) {
    220     free (Buffer);
    221   }
    222 
    223   return Status;
    224 }
    225 
    226 /**
    227   Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:
    228   Cryptographic Message Syntax Standard". The input signed data could be wrapped
    229   in a ContentInfo structure.
    230 
    231   If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then
    232   return FALSE. If P7Length overflow, then return FAlSE.
    233 
    234   Caution: This function may receive untrusted input.
    235   UEFI Authenticated Variable is external input, so this function will do basic
    236   check for PKCS#7 data structure.
    237 
    238   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.
    239   @param[in]  P7Length     Length of the PKCS#7 message in bytes.
    240   @param[out] CertStack    Pointer to Signer's certificates retrieved from P7Data.
    241                            It's caller's responsiblity to free the buffer.
    242   @param[out] StackLength  Length of signer's certificates in bytes.
    243   @param[out] TrustedCert  Pointer to a trusted certificate from Signer's certificates.
    244                            It's caller's responsiblity to free the buffer.
    245   @param[out] CertLength   Length of the trusted certificate in bytes.
    246 
    247   @retval  TRUE            The operation is finished successfully.
    248   @retval  FALSE           Error occurs during the operation.
    249 
    250 **/
    251 BOOLEAN
    252 EFIAPI
    253 Pkcs7GetSigners (
    254   IN  CONST UINT8  *P7Data,
    255   IN  UINTN        P7Length,
    256   OUT UINT8        **CertStack,
    257   OUT UINTN        *StackLength,
    258   OUT UINT8        **TrustedCert,
    259   OUT UINTN        *CertLength
    260   )
    261 {
    262   PKCS7            *Pkcs7;
    263   BOOLEAN          Status;
    264   UINT8            *SignedData;
    265   CONST UINT8      *Temp;
    266   UINTN            SignedDataSize;
    267   BOOLEAN          Wrapped;
    268   STACK_OF(X509)   *Stack;
    269   UINT8            Index;
    270   UINT8            *CertBuf;
    271   UINT8            *OldBuf;
    272   UINTN            BufferSize;
    273   UINTN            OldSize;
    274   UINT8            *SingleCert;
    275   UINTN            SingleCertSize;
    276 
    277   if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||
    278       (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) {
    279     return FALSE;
    280   }
    281 
    282   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
    283   if (!Status) {
    284     return Status;
    285   }
    286 
    287   Status     = FALSE;
    288   Pkcs7      = NULL;
    289   Stack      = NULL;
    290   CertBuf    = NULL;
    291   OldBuf     = NULL;
    292   SingleCert = NULL;
    293 
    294   //
    295   // Retrieve PKCS#7 Data (DER encoding)
    296   //
    297   if (SignedDataSize > INT_MAX) {
    298     goto _Exit;
    299   }
    300 
    301   Temp = SignedData;
    302   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
    303   if (Pkcs7 == NULL) {
    304     goto _Exit;
    305   }
    306 
    307   //
    308   // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
    309   //
    310   if (!PKCS7_type_is_signed (Pkcs7)) {
    311     goto _Exit;
    312   }
    313 
    314   Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY);
    315   if (Stack == NULL) {
    316     goto _Exit;
    317   }
    318 
    319   //
    320   // Convert CertStack to buffer in following format:
    321   // UINT8  CertNumber;
    322   // UINT32 Cert1Length;
    323   // UINT8  Cert1[];
    324   // UINT32 Cert2Length;
    325   // UINT8  Cert2[];
    326   // ...
    327   // UINT32 CertnLength;
    328   // UINT8  Certn[];
    329   //
    330   BufferSize = sizeof (UINT8);
    331   OldSize    = BufferSize;
    332 
    333   for (Index = 0; ; Index++) {
    334     Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);
    335     if (!Status) {
    336       break;
    337     }
    338 
    339     OldSize    = BufferSize;
    340     OldBuf     = CertBuf;
    341     BufferSize = OldSize + SingleCertSize + sizeof (UINT32);
    342     CertBuf    = malloc (BufferSize);
    343 
    344     if (CertBuf == NULL) {
    345       goto _Exit;
    346     }
    347 
    348     if (OldBuf != NULL) {
    349       CopyMem (CertBuf, OldBuf, OldSize);
    350       free (OldBuf);
    351       OldBuf = NULL;
    352     }
    353 
    354     WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize);
    355     CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);
    356 
    357     free (SingleCert);
    358     SingleCert = NULL;
    359   }
    360 
    361   if (CertBuf != NULL) {
    362     //
    363     // Update CertNumber.
    364     //
    365     CertBuf[0] = Index;
    366 
    367     *CertLength = BufferSize - OldSize - sizeof (UINT32);
    368     *TrustedCert = malloc (*CertLength);
    369     if (*TrustedCert == NULL) {
    370       goto _Exit;
    371     }
    372 
    373     CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);
    374     *CertStack   = CertBuf;
    375     *StackLength = BufferSize;
    376     Status = TRUE;
    377   }
    378 
    379 _Exit:
    380   //
    381   // Release Resources
    382   //
    383   if (!Wrapped) {
    384     free (SignedData);
    385   }
    386 
    387   if (Pkcs7 != NULL) {
    388     PKCS7_free (Pkcs7);
    389   }
    390 
    391   if (Stack != NULL) {
    392     sk_X509_pop_free(Stack, X509_free);
    393   }
    394 
    395   if (SingleCert !=  NULL) {
    396     free (SingleCert);
    397   }
    398 
    399   if (!Status && (CertBuf != NULL)) {
    400     free (CertBuf);
    401     *CertStack = NULL;
    402   }
    403 
    404   if (OldBuf != NULL) {
    405     free (OldBuf);
    406   }
    407 
    408   return Status;
    409 }
    410 
    411 /**
    412   Wrap function to use free() to free allocated memory for certificates.
    413 
    414   @param[in]  Certs        Pointer to the certificates to be freed.
    415 
    416 **/
    417 VOID
    418 EFIAPI
    419 Pkcs7FreeSigners (
    420   IN  UINT8        *Certs
    421   )
    422 {
    423   if (Certs == NULL) {
    424     return;
    425   }
    426 
    427   free (Certs);
    428 }
    429 
    430 /**
    431   Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:
    432   Cryptographic Message Syntax Standard", and outputs two certificate lists chained and
    433   unchained to the signer's certificates.
    434   The input signed data could be wrapped in a ContentInfo structure.
    435 
    436   @param[in]  P7Data            Pointer to the PKCS#7 message.
    437   @param[in]  P7Length          Length of the PKCS#7 message in bytes.
    438   @param[out] SignerChainCerts  Pointer to the certificates list chained to signer's
    439                                 certificate. It's caller's responsiblity to free the buffer.
    440   @param[out] ChainLength       Length of the chained certificates list buffer in bytes.
    441   @param[out] UnchainCerts      Pointer to the unchained certificates lists. It's caller's
    442                                 responsiblity to free the buffer.
    443   @param[out] UnchainLength     Length of the unchained certificates list buffer in bytes.
    444 
    445   @retval  TRUE         The operation is finished successfully.
    446   @retval  FALSE        Error occurs during the operation.
    447 
    448 **/
    449 BOOLEAN
    450 EFIAPI
    451 Pkcs7GetCertificatesList (
    452   IN  CONST UINT8  *P7Data,
    453   IN  UINTN        P7Length,
    454   OUT UINT8        **SignerChainCerts,
    455   OUT UINTN        *ChainLength,
    456   OUT UINT8        **UnchainCerts,
    457   OUT UINTN        *UnchainLength
    458   )
    459 {
    460   BOOLEAN          Status;
    461   UINT8            *NewP7Data;
    462   UINTN            NewP7Length;
    463   BOOLEAN          Wrapped;
    464   UINT8            Index;
    465   PKCS7            *Pkcs7;
    466   X509_STORE_CTX   CertCtx;
    467   STACK_OF(X509)   *Signers;
    468   X509             *Signer;
    469   X509             *Cert;
    470   X509             *TempCert;
    471   X509             *Issuer;
    472   UINT8            *CertBuf;
    473   UINT8            *OldBuf;
    474   UINTN            BufferSize;
    475   UINTN            OldSize;
    476   UINT8            *SingleCert;
    477   UINTN            CertSize;
    478 
    479   //
    480   // Initializations
    481   //
    482   Status         = FALSE;
    483   NewP7Data      = NULL;
    484   Pkcs7          = NULL;
    485   Cert           = NULL;
    486   TempCert       = NULL;
    487   SingleCert     = NULL;
    488   CertBuf        = NULL;
    489   OldBuf         = NULL;
    490   Signers        = NULL;
    491 
    492   //
    493   // Parameter Checking
    494   //
    495   if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||
    496       (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) {
    497     return Status;
    498   }
    499 
    500   *SignerChainCerts = NULL;
    501   *ChainLength      = 0;
    502   *UnchainCerts     = NULL;
    503   *UnchainLength    = 0;
    504 
    505   //
    506   // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.
    507   //
    508   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);
    509   if (!Status || (NewP7Length > INT_MAX)) {
    510     goto _Error;
    511   }
    512 
    513   //
    514   // Decodes PKCS#7 SignedData
    515   //
    516   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length);
    517   if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {
    518     goto _Error;
    519   }
    520 
    521   //
    522   // Obtains Signer's Certificate from PKCS#7 data
    523   // NOTE: Only one signer case will be handled in this function, which means SignerInfos
    524   //       should include only one signer's certificate.
    525   //
    526   Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);
    527   if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {
    528     goto _Error;
    529   }
    530   Signer = sk_X509_value (Signers, 0);
    531 
    532   if (!X509_STORE_CTX_init (&CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {
    533     goto _Error;
    534   }
    535   //
    536   // Initialize Chained & Untrusted stack
    537   //
    538   if (CertCtx.chain == NULL) {
    539     if (((CertCtx.chain = sk_X509_new_null ()) == NULL) ||
    540         (!sk_X509_push (CertCtx.chain, CertCtx.cert))) {
    541       goto _Error;
    542     }
    543   }
    544   (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Signer);
    545 
    546   //
    547   // Build certificates stack chained from Signer's certificate.
    548   //
    549   Cert = Signer;
    550   for (; ;) {
    551     //
    552     // Self-Issue checking
    553     //
    554     if (CertCtx.check_issued (&CertCtx, Cert, Cert)) {
    555       break;
    556     }
    557 
    558     //
    559     // Found the issuer of the current certificate
    560     //
    561     if (CertCtx.untrusted != NULL) {
    562       Issuer = NULL;
    563       for (Index = 0; Index < sk_X509_num (CertCtx.untrusted); Index++) {
    564         TempCert = sk_X509_value (CertCtx.untrusted, Index);
    565         if (CertCtx.check_issued (&CertCtx, Cert, TempCert)) {
    566           Issuer = TempCert;
    567           break;
    568         }
    569       }
    570       if (Issuer != NULL) {
    571         if (!sk_X509_push (CertCtx.chain, Issuer)) {
    572           goto _Error;
    573         }
    574         (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Issuer);
    575 
    576         Cert = Issuer;
    577         continue;
    578       }
    579     }
    580 
    581     break;
    582   }
    583 
    584   //
    585   // Converts Chained and Untrusted Certificate to Certificate Buffer in following format:
    586   //      UINT8  CertNumber;
    587   //      UINT32 Cert1Length;
    588   //      UINT8  Cert1[];
    589   //      UINT32 Cert2Length;
    590   //      UINT8  Cert2[];
    591   //      ...
    592   //      UINT32 CertnLength;
    593   //      UINT8  Certn[];
    594   //
    595 
    596   if (CertCtx.chain != NULL) {
    597     BufferSize = sizeof (UINT8);
    598     OldSize    = BufferSize;
    599     CertBuf    = NULL;
    600 
    601     for (Index = 0; ; Index++) {
    602       Status = X509PopCertificate (CertCtx.chain, &SingleCert, &CertSize);
    603       if (!Status) {
    604         break;
    605       }
    606 
    607       OldSize    = BufferSize;
    608       OldBuf     = CertBuf;
    609       BufferSize = OldSize + CertSize + sizeof (UINT32);
    610       CertBuf    = malloc (BufferSize);
    611 
    612       if (CertBuf == NULL) {
    613         Status = FALSE;
    614         goto _Error;
    615       }
    616       if (OldBuf != NULL) {
    617         CopyMem (CertBuf, OldBuf, OldSize);
    618         free (OldBuf);
    619         OldBuf = NULL;
    620       }
    621 
    622       WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
    623       CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
    624 
    625       free (SingleCert);
    626       SingleCert = NULL;
    627     }
    628 
    629     if (CertBuf != NULL) {
    630       //
    631       // Update CertNumber.
    632       //
    633       CertBuf[0] = Index;
    634 
    635       *SignerChainCerts = CertBuf;
    636       *ChainLength      = BufferSize;
    637     }
    638   }
    639 
    640   if (CertCtx.untrusted != NULL) {
    641     BufferSize = sizeof (UINT8);
    642     OldSize    = BufferSize;
    643     CertBuf    = NULL;
    644 
    645     for (Index = 0; ; Index++) {
    646       Status = X509PopCertificate (CertCtx.untrusted, &SingleCert, &CertSize);
    647       if (!Status) {
    648         break;
    649       }
    650 
    651       OldSize    = BufferSize;
    652       OldBuf     = CertBuf;
    653       BufferSize = OldSize + CertSize + sizeof (UINT32);
    654       CertBuf    = malloc (BufferSize);
    655 
    656       if (CertBuf == NULL) {
    657         Status = FALSE;
    658         goto _Error;
    659       }
    660       if (OldBuf != NULL) {
    661         CopyMem (CertBuf, OldBuf, OldSize);
    662         free (OldBuf);
    663         OldBuf = NULL;
    664       }
    665 
    666       WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
    667       CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
    668 
    669       free (SingleCert);
    670       SingleCert = NULL;
    671     }
    672 
    673     if (CertBuf != NULL) {
    674       //
    675       // Update CertNumber.
    676       //
    677       CertBuf[0] = Index;
    678 
    679       *UnchainCerts  = CertBuf;
    680       *UnchainLength = BufferSize;
    681     }
    682   }
    683 
    684   Status = TRUE;
    685 
    686 _Error:
    687   //
    688   // Release Resources.
    689   //
    690   if (!Wrapped && (NewP7Data != NULL)) {
    691     free (NewP7Data);
    692   }
    693 
    694   if (Pkcs7 != NULL) {
    695     PKCS7_free (Pkcs7);
    696   }
    697   sk_X509_free (Signers);
    698 
    699   X509_STORE_CTX_cleanup (&CertCtx);
    700 
    701   if (SingleCert != NULL) {
    702     free (SingleCert);
    703   }
    704 
    705   if (OldBuf != NULL) {
    706     free (OldBuf);
    707   }
    708 
    709   if (!Status && (CertBuf != NULL)) {
    710     free (CertBuf);
    711     *SignerChainCerts = NULL;
    712     *UnchainCerts     = NULL;
    713   }
    714 
    715   return Status;
    716 }
    717 
    718 /**
    719   Verifies the validility of a PKCS#7 signed data as described in "PKCS #7:
    720   Cryptographic Message Syntax Standard". The input signed data could be wrapped
    721   in a ContentInfo structure.
    722 
    723   If P7Data, TrustedCert or InData is NULL, then return FALSE.
    724   If P7Length, CertLength or DataLength overflow, then return FAlSE.
    725 
    726   Caution: This function may receive untrusted input.
    727   UEFI Authenticated Variable is external input, so this function will do basic
    728   check for PKCS#7 data structure.
    729 
    730   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.
    731   @param[in]  P7Length     Length of the PKCS#7 message in bytes.
    732   @param[in]  TrustedCert  Pointer to a trusted/root certificate encoded in DER, which
    733                            is used for certificate chain verification.
    734   @param[in]  CertLength   Length of the trusted certificate in bytes.
    735   @param[in]  InData       Pointer to the content to be verified.
    736   @param[in]  DataLength   Length of InData in bytes.
    737 
    738   @retval  TRUE  The specified PKCS#7 signed data is valid.
    739   @retval  FALSE Invalid PKCS#7 signed data.
    740 
    741 **/
    742 BOOLEAN
    743 EFIAPI
    744 Pkcs7Verify (
    745   IN  CONST UINT8  *P7Data,
    746   IN  UINTN        P7Length,
    747   IN  CONST UINT8  *TrustedCert,
    748   IN  UINTN        CertLength,
    749   IN  CONST UINT8  *InData,
    750   IN  UINTN        DataLength
    751   )
    752 {
    753   PKCS7       *Pkcs7;
    754   BIO         *DataBio;
    755   BOOLEAN     Status;
    756   X509        *Cert;
    757   X509_STORE  *CertStore;
    758   UINT8       *SignedData;
    759   CONST UINT8 *Temp;
    760   UINTN       SignedDataSize;
    761   BOOLEAN     Wrapped;
    762 
    763   //
    764   // Check input parameters.
    765   //
    766   if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||
    767     P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {
    768     return FALSE;
    769   }
    770 
    771   Pkcs7     = NULL;
    772   DataBio   = NULL;
    773   Cert      = NULL;
    774   CertStore = NULL;
    775 
    776   //
    777   // Register & Initialize necessary digest algorithms for PKCS#7 Handling
    778   //
    779   if (EVP_add_digest (EVP_md5 ()) == 0) {
    780     return FALSE;
    781   }
    782   if (EVP_add_digest (EVP_sha1 ()) == 0) {
    783     return FALSE;
    784   }
    785   if (EVP_add_digest (EVP_sha256 ()) == 0) {
    786     return FALSE;
    787   }
    788   if (EVP_add_digest (EVP_sha384 ()) == 0) {
    789     return FALSE;
    790   }
    791   if (EVP_add_digest (EVP_sha512 ()) == 0) {
    792     return FALSE;
    793   }
    794   if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
    795     return FALSE;
    796   }
    797 
    798   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
    799   if (!Status) {
    800     return Status;
    801   }
    802 
    803   Status = FALSE;
    804 
    805   //
    806   // Retrieve PKCS#7 Data (DER encoding)
    807   //
    808   if (SignedDataSize > INT_MAX) {
    809     goto _Exit;
    810   }
    811 
    812   Temp = SignedData;
    813   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
    814   if (Pkcs7 == NULL) {
    815     goto _Exit;
    816   }
    817 
    818   //
    819   // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
    820   //
    821   if (!PKCS7_type_is_signed (Pkcs7)) {
    822     goto _Exit;
    823   }
    824 
    825   //
    826   // Read DER-encoded root certificate and Construct X509 Certificate
    827   //
    828   Temp = TrustedCert;
    829   Cert = d2i_X509 (NULL, &Temp, (long) CertLength);
    830   if (Cert == NULL) {
    831     goto _Exit;
    832   }
    833 
    834   //
    835   // Setup X509 Store for trusted certificate
    836   //
    837   CertStore = X509_STORE_new ();
    838   if (CertStore == NULL) {
    839     goto _Exit;
    840   }
    841   if (!(X509_STORE_add_cert (CertStore, Cert))) {
    842     goto _Exit;
    843   }
    844 
    845   //
    846   // For generic PKCS#7 handling, InData may be NULL if the content is present
    847   // in PKCS#7 structure. So ignore NULL checking here.
    848   //
    849   DataBio = BIO_new (BIO_s_mem ());
    850   if (DataBio == NULL) {
    851     goto _Exit;
    852   }
    853 
    854   if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {
    855     goto _Exit;
    856   }
    857 
    858   //
    859   // Allow partial certificate chains, terminated by a non-self-signed but
    860   // still trusted intermediate certificate. Also disable time checks.
    861   //
    862   X509_STORE_set_flags (CertStore,
    863                         X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
    864 
    865   //
    866   // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and
    867   // doesn't support the extended key usage for Authenticode Code Signing.
    868   // Bypass the certificate purpose checking by enabling any purposes setting.
    869   //
    870   X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
    871 
    872   //
    873   // Verifies the PKCS#7 signedData structure
    874   //
    875   Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);
    876 
    877 _Exit:
    878   //
    879   // Release Resources
    880   //
    881   BIO_free (DataBio);
    882   X509_free (Cert);
    883   X509_STORE_free (CertStore);
    884   PKCS7_free (Pkcs7);
    885 
    886   if (!Wrapped) {
    887     OPENSSL_free (SignedData);
    888   }
    889 
    890   return Status;
    891 }
    892 
    893 /**
    894   Extracts the attached content from a PKCS#7 signed data if existed. The input signed
    895   data could be wrapped in a ContentInfo structure.
    896 
    897   If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,
    898   then return FAlSE. If the P7Data is not correctly formatted, then return FALSE.
    899 
    900   Caution: This function may receive untrusted input. So this function will do
    901            basic check for PKCS#7 data structure.
    902 
    903   @param[in]   P7Data       Pointer to the PKCS#7 signed data to process.
    904   @param[in]   P7Length     Length of the PKCS#7 signed data in bytes.
    905   @param[out]  Content      Pointer to the extracted content from the PKCS#7 signedData.
    906                             It's caller's responsiblity to free the buffer.
    907   @param[out]  ContentSize  The size of the extracted content in bytes.
    908 
    909   @retval     TRUE          The P7Data was correctly formatted for processing.
    910   @retval     FALSE         The P7Data was not correctly formatted for processing.
    911 
    912 */
    913 BOOLEAN
    914 EFIAPI
    915 Pkcs7GetAttachedContent (
    916   IN  CONST UINT8  *P7Data,
    917   IN  UINTN        P7Length,
    918   OUT VOID         **Content,
    919   OUT UINTN        *ContentSize
    920   )
    921 {
    922   BOOLEAN            Status;
    923   PKCS7              *Pkcs7;
    924   UINT8              *SignedData;
    925   UINTN              SignedDataSize;
    926   BOOLEAN            Wrapped;
    927   CONST UINT8        *Temp;
    928   ASN1_OCTET_STRING  *OctStr;
    929 
    930   //
    931   // Check input parameter.
    932   //
    933   if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {
    934     return FALSE;
    935   }
    936 
    937   *Content   = NULL;
    938   Pkcs7      = NULL;
    939   SignedData = NULL;
    940   OctStr     = NULL;
    941 
    942   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
    943   if (!Status || (SignedDataSize > INT_MAX)) {
    944     goto _Exit;
    945   }
    946 
    947   Status = FALSE;
    948 
    949   //
    950   // Decoding PKCS#7 SignedData
    951   //
    952   Temp  = SignedData;
    953   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);
    954   if (Pkcs7 == NULL) {
    955     goto _Exit;
    956   }
    957 
    958   //
    959   // The type of Pkcs7 must be signedData
    960   //
    961   if (!PKCS7_type_is_signed (Pkcs7)) {
    962     goto _Exit;
    963   }
    964 
    965   //
    966   // Check for detached or attached content
    967   //
    968   if (PKCS7_get_detached (Pkcs7)) {
    969     //
    970     // No Content supplied for PKCS7 detached signedData
    971     //
    972     *Content     = NULL;
    973     *ContentSize = 0;
    974   } else {
    975     //
    976     // Retrieve the attached content in PKCS7 signedData
    977     //
    978     OctStr = Pkcs7->d.sign->contents->d.data;
    979     if ((OctStr->length > 0) && (OctStr->data != NULL)) {
    980       *ContentSize = OctStr->length;
    981       *Content     = malloc (*ContentSize);
    982       if (*Content == NULL) {
    983         *ContentSize = 0;
    984         goto _Exit;
    985       }
    986       CopyMem (*Content, OctStr->data, *ContentSize);
    987     }
    988   }
    989   Status = TRUE;
    990 
    991 _Exit:
    992   //
    993   // Release Resources
    994   //
    995   PKCS7_free (Pkcs7);
    996 
    997   if (!Wrapped) {
    998     OPENSSL_free (SignedData);
    999   }
   1000 
   1001   return Status;
   1002 }
   1003