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 - 2016, 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 responsibility 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 responsibility 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 responsibility 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                                 responsibility 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   ZeroMem (&CertCtx, sizeof (CertCtx));
    493 
    494   //
    495   // Parameter Checking
    496   //
    497   if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||
    498       (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) {
    499     return Status;
    500   }
    501 
    502   *SignerChainCerts = NULL;
    503   *ChainLength      = 0;
    504   *UnchainCerts     = NULL;
    505   *UnchainLength    = 0;
    506 
    507   //
    508   // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.
    509   //
    510   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);
    511   if (!Status || (NewP7Length > INT_MAX)) {
    512     goto _Error;
    513   }
    514 
    515   //
    516   // Decodes PKCS#7 SignedData
    517   //
    518   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length);
    519   if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {
    520     goto _Error;
    521   }
    522 
    523   //
    524   // Obtains Signer's Certificate from PKCS#7 data
    525   // NOTE: Only one signer case will be handled in this function, which means SignerInfos
    526   //       should include only one signer's certificate.
    527   //
    528   Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);
    529   if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {
    530     goto _Error;
    531   }
    532   Signer = sk_X509_value (Signers, 0);
    533 
    534   if (!X509_STORE_CTX_init (&CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {
    535     goto _Error;
    536   }
    537   //
    538   // Initialize Chained & Untrusted stack
    539   //
    540   if (CertCtx.chain == NULL) {
    541     if (((CertCtx.chain = sk_X509_new_null ()) == NULL) ||
    542         (!sk_X509_push (CertCtx.chain, CertCtx.cert))) {
    543       goto _Error;
    544     }
    545   }
    546   (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Signer);
    547 
    548   //
    549   // Build certificates stack chained from Signer's certificate.
    550   //
    551   Cert = Signer;
    552   for (; ;) {
    553     //
    554     // Self-Issue checking
    555     //
    556     if (CertCtx.check_issued (&CertCtx, Cert, Cert)) {
    557       break;
    558     }
    559 
    560     //
    561     // Found the issuer of the current certificate
    562     //
    563     if (CertCtx.untrusted != NULL) {
    564       Issuer = NULL;
    565       for (Index = 0; Index < sk_X509_num (CertCtx.untrusted); Index++) {
    566         TempCert = sk_X509_value (CertCtx.untrusted, Index);
    567         if (CertCtx.check_issued (&CertCtx, Cert, TempCert)) {
    568           Issuer = TempCert;
    569           break;
    570         }
    571       }
    572       if (Issuer != NULL) {
    573         if (!sk_X509_push (CertCtx.chain, Issuer)) {
    574           goto _Error;
    575         }
    576         (VOID)sk_X509_delete_ptr (CertCtx.untrusted, Issuer);
    577 
    578         Cert = Issuer;
    579         continue;
    580       }
    581     }
    582 
    583     break;
    584   }
    585 
    586   //
    587   // Converts Chained and Untrusted Certificate to Certificate Buffer in following format:
    588   //      UINT8  CertNumber;
    589   //      UINT32 Cert1Length;
    590   //      UINT8  Cert1[];
    591   //      UINT32 Cert2Length;
    592   //      UINT8  Cert2[];
    593   //      ...
    594   //      UINT32 CertnLength;
    595   //      UINT8  Certn[];
    596   //
    597 
    598   if (CertCtx.chain != NULL) {
    599     BufferSize = sizeof (UINT8);
    600     OldSize    = BufferSize;
    601     CertBuf    = NULL;
    602 
    603     for (Index = 0; ; Index++) {
    604       Status = X509PopCertificate (CertCtx.chain, &SingleCert, &CertSize);
    605       if (!Status) {
    606         break;
    607       }
    608 
    609       OldSize    = BufferSize;
    610       OldBuf     = CertBuf;
    611       BufferSize = OldSize + CertSize + sizeof (UINT32);
    612       CertBuf    = malloc (BufferSize);
    613 
    614       if (CertBuf == NULL) {
    615         Status = FALSE;
    616         goto _Error;
    617       }
    618       if (OldBuf != NULL) {
    619         CopyMem (CertBuf, OldBuf, OldSize);
    620         free (OldBuf);
    621         OldBuf = NULL;
    622       }
    623 
    624       WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
    625       CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
    626 
    627       free (SingleCert);
    628       SingleCert = NULL;
    629     }
    630 
    631     if (CertBuf != NULL) {
    632       //
    633       // Update CertNumber.
    634       //
    635       CertBuf[0] = Index;
    636 
    637       *SignerChainCerts = CertBuf;
    638       *ChainLength      = BufferSize;
    639     }
    640   }
    641 
    642   if (CertCtx.untrusted != NULL) {
    643     BufferSize = sizeof (UINT8);
    644     OldSize    = BufferSize;
    645     CertBuf    = NULL;
    646 
    647     for (Index = 0; ; Index++) {
    648       Status = X509PopCertificate (CertCtx.untrusted, &SingleCert, &CertSize);
    649       if (!Status) {
    650         break;
    651       }
    652 
    653       OldSize    = BufferSize;
    654       OldBuf     = CertBuf;
    655       BufferSize = OldSize + CertSize + sizeof (UINT32);
    656       CertBuf    = malloc (BufferSize);
    657 
    658       if (CertBuf == NULL) {
    659         Status = FALSE;
    660         goto _Error;
    661       }
    662       if (OldBuf != NULL) {
    663         CopyMem (CertBuf, OldBuf, OldSize);
    664         free (OldBuf);
    665         OldBuf = NULL;
    666       }
    667 
    668       WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
    669       CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
    670 
    671       free (SingleCert);
    672       SingleCert = NULL;
    673     }
    674 
    675     if (CertBuf != NULL) {
    676       //
    677       // Update CertNumber.
    678       //
    679       CertBuf[0] = Index;
    680 
    681       *UnchainCerts  = CertBuf;
    682       *UnchainLength = BufferSize;
    683     }
    684   }
    685 
    686   Status = TRUE;
    687 
    688 _Error:
    689   //
    690   // Release Resources.
    691   //
    692   if (!Wrapped && (NewP7Data != NULL)) {
    693     free (NewP7Data);
    694   }
    695 
    696   if (Pkcs7 != NULL) {
    697     PKCS7_free (Pkcs7);
    698   }
    699   sk_X509_free (Signers);
    700 
    701   X509_STORE_CTX_cleanup (&CertCtx);
    702 
    703   if (SingleCert != NULL) {
    704     free (SingleCert);
    705   }
    706 
    707   if (OldBuf != NULL) {
    708     free (OldBuf);
    709   }
    710 
    711   if (!Status && (CertBuf != NULL)) {
    712     free (CertBuf);
    713     *SignerChainCerts = NULL;
    714     *UnchainCerts     = NULL;
    715   }
    716 
    717   return Status;
    718 }
    719 
    720 /**
    721   Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:
    722   Cryptographic Message Syntax Standard". The input signed data could be wrapped
    723   in a ContentInfo structure.
    724 
    725   If P7Data, TrustedCert or InData is NULL, then return FALSE.
    726   If P7Length, CertLength or DataLength overflow, then return FALSE.
    727 
    728   Caution: This function may receive untrusted input.
    729   UEFI Authenticated Variable is external input, so this function will do basic
    730   check for PKCS#7 data structure.
    731 
    732   @param[in]  P7Data       Pointer to the PKCS#7 message to verify.
    733   @param[in]  P7Length     Length of the PKCS#7 message in bytes.
    734   @param[in]  TrustedCert  Pointer to a trusted/root certificate encoded in DER, which
    735                            is used for certificate chain verification.
    736   @param[in]  CertLength   Length of the trusted certificate in bytes.
    737   @param[in]  InData       Pointer to the content to be verified.
    738   @param[in]  DataLength   Length of InData in bytes.
    739 
    740   @retval  TRUE  The specified PKCS#7 signed data is valid.
    741   @retval  FALSE Invalid PKCS#7 signed data.
    742 
    743 **/
    744 BOOLEAN
    745 EFIAPI
    746 Pkcs7Verify (
    747   IN  CONST UINT8  *P7Data,
    748   IN  UINTN        P7Length,
    749   IN  CONST UINT8  *TrustedCert,
    750   IN  UINTN        CertLength,
    751   IN  CONST UINT8  *InData,
    752   IN  UINTN        DataLength
    753   )
    754 {
    755   PKCS7       *Pkcs7;
    756   BIO         *DataBio;
    757   BOOLEAN     Status;
    758   X509        *Cert;
    759   X509_STORE  *CertStore;
    760   UINT8       *SignedData;
    761   CONST UINT8 *Temp;
    762   UINTN       SignedDataSize;
    763   BOOLEAN     Wrapped;
    764 
    765   //
    766   // Check input parameters.
    767   //
    768   if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||
    769     P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {
    770     return FALSE;
    771   }
    772 
    773   Pkcs7     = NULL;
    774   DataBio   = NULL;
    775   Cert      = NULL;
    776   CertStore = NULL;
    777 
    778   //
    779   // Register & Initialize necessary digest algorithms for PKCS#7 Handling
    780   //
    781   if (EVP_add_digest (EVP_md5 ()) == 0) {
    782     return FALSE;
    783   }
    784   if (EVP_add_digest (EVP_sha1 ()) == 0) {
    785     return FALSE;
    786   }
    787   if (EVP_add_digest (EVP_sha256 ()) == 0) {
    788     return FALSE;
    789   }
    790   if (EVP_add_digest (EVP_sha384 ()) == 0) {
    791     return FALSE;
    792   }
    793   if (EVP_add_digest (EVP_sha512 ()) == 0) {
    794     return FALSE;
    795   }
    796   if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
    797     return FALSE;
    798   }
    799 
    800   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
    801   if (!Status) {
    802     return Status;
    803   }
    804 
    805   Status = FALSE;
    806 
    807   //
    808   // Retrieve PKCS#7 Data (DER encoding)
    809   //
    810   if (SignedDataSize > INT_MAX) {
    811     goto _Exit;
    812   }
    813 
    814   Temp = SignedData;
    815   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
    816   if (Pkcs7 == NULL) {
    817     goto _Exit;
    818   }
    819 
    820   //
    821   // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
    822   //
    823   if (!PKCS7_type_is_signed (Pkcs7)) {
    824     goto _Exit;
    825   }
    826 
    827   //
    828   // Read DER-encoded root certificate and Construct X509 Certificate
    829   //
    830   Temp = TrustedCert;
    831   Cert = d2i_X509 (NULL, &Temp, (long) CertLength);
    832   if (Cert == NULL) {
    833     goto _Exit;
    834   }
    835 
    836   //
    837   // Setup X509 Store for trusted certificate
    838   //
    839   CertStore = X509_STORE_new ();
    840   if (CertStore == NULL) {
    841     goto _Exit;
    842   }
    843   if (!(X509_STORE_add_cert (CertStore, Cert))) {
    844     goto _Exit;
    845   }
    846 
    847   //
    848   // For generic PKCS#7 handling, InData may be NULL if the content is present
    849   // in PKCS#7 structure. So ignore NULL checking here.
    850   //
    851   DataBio = BIO_new (BIO_s_mem ());
    852   if (DataBio == NULL) {
    853     goto _Exit;
    854   }
    855 
    856   if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {
    857     goto _Exit;
    858   }
    859 
    860   //
    861   // Allow partial certificate chains, terminated by a non-self-signed but
    862   // still trusted intermediate certificate. Also disable time checks.
    863   //
    864   X509_STORE_set_flags (CertStore,
    865                         X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
    866 
    867   //
    868   // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and
    869   // doesn't support the extended key usage for Authenticode Code Signing.
    870   // Bypass the certificate purpose checking by enabling any purposes setting.
    871   //
    872   X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
    873 
    874   //
    875   // Verifies the PKCS#7 signedData structure
    876   //
    877   Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);
    878 
    879 _Exit:
    880   //
    881   // Release Resources
    882   //
    883   BIO_free (DataBio);
    884   X509_free (Cert);
    885   X509_STORE_free (CertStore);
    886   PKCS7_free (Pkcs7);
    887 
    888   if (!Wrapped) {
    889     OPENSSL_free (SignedData);
    890   }
    891 
    892   return Status;
    893 }
    894 
    895 /**
    896   Extracts the attached content from a PKCS#7 signed data if existed. The input signed
    897   data could be wrapped in a ContentInfo structure.
    898 
    899   If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,
    900   then return FALSE. If the P7Data is not correctly formatted, then return FALSE.
    901 
    902   Caution: This function may receive untrusted input. So this function will do
    903            basic check for PKCS#7 data structure.
    904 
    905   @param[in]   P7Data       Pointer to the PKCS#7 signed data to process.
    906   @param[in]   P7Length     Length of the PKCS#7 signed data in bytes.
    907   @param[out]  Content      Pointer to the extracted content from the PKCS#7 signedData.
    908                             It's caller's responsibility to free the buffer.
    909   @param[out]  ContentSize  The size of the extracted content in bytes.
    910 
    911   @retval     TRUE          The P7Data was correctly formatted for processing.
    912   @retval     FALSE         The P7Data was not correctly formatted for processing.
    913 
    914 */
    915 BOOLEAN
    916 EFIAPI
    917 Pkcs7GetAttachedContent (
    918   IN  CONST UINT8  *P7Data,
    919   IN  UINTN        P7Length,
    920   OUT VOID         **Content,
    921   OUT UINTN        *ContentSize
    922   )
    923 {
    924   BOOLEAN            Status;
    925   PKCS7              *Pkcs7;
    926   UINT8              *SignedData;
    927   UINTN              SignedDataSize;
    928   BOOLEAN            Wrapped;
    929   CONST UINT8        *Temp;
    930   ASN1_OCTET_STRING  *OctStr;
    931 
    932   //
    933   // Check input parameter.
    934   //
    935   if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {
    936     return FALSE;
    937   }
    938 
    939   *Content   = NULL;
    940   Pkcs7      = NULL;
    941   SignedData = NULL;
    942   OctStr     = NULL;
    943 
    944   Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
    945   if (!Status || (SignedDataSize > INT_MAX)) {
    946     goto _Exit;
    947   }
    948 
    949   Status = FALSE;
    950 
    951   //
    952   // Decoding PKCS#7 SignedData
    953   //
    954   Temp  = SignedData;
    955   Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);
    956   if (Pkcs7 == NULL) {
    957     goto _Exit;
    958   }
    959 
    960   //
    961   // The type of Pkcs7 must be signedData
    962   //
    963   if (!PKCS7_type_is_signed (Pkcs7)) {
    964     goto _Exit;
    965   }
    966 
    967   //
    968   // Check for detached or attached content
    969   //
    970   if (PKCS7_get_detached (Pkcs7)) {
    971     //
    972     // No Content supplied for PKCS7 detached signedData
    973     //
    974     *Content     = NULL;
    975     *ContentSize = 0;
    976   } else {
    977     //
    978     // Retrieve the attached content in PKCS7 signedData
    979     //
    980     OctStr = Pkcs7->d.sign->contents->d.data;
    981     if ((OctStr->length > 0) && (OctStr->data != NULL)) {
    982       *ContentSize = OctStr->length;
    983       *Content     = malloc (*ContentSize);
    984       if (*Content == NULL) {
    985         *ContentSize = 0;
    986         goto _Exit;
    987       }
    988       CopyMem (*Content, OctStr->data, *ContentSize);
    989     }
    990   }
    991   Status = TRUE;
    992 
    993 _Exit:
    994   //
    995   // Release Resources
    996   //
    997   PKCS7_free (Pkcs7);
    998 
    999   if (!Wrapped) {
   1000     OPENSSL_free (SignedData);
   1001   }
   1002 
   1003   return Status;
   1004 }
   1005