Home | History | Annotate | Download | only in Pk
      1 /** @file
      2   X.509 Certificate Handler Wrapper Implementation over OpenSSL.
      3 
      4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "InternalCryptLib.h"
     16 #include <openssl/x509.h>
     17 #include <openssl/rsa.h>
     18 
     19 /**
     20   Construct a X509 object from DER-encoded certificate data.
     21 
     22   If Cert is NULL, then return FALSE.
     23   If SingleX509Cert is NULL, then return FALSE.
     24 
     25   @param[in]  Cert            Pointer to the DER-encoded certificate data.
     26   @param[in]  CertSize        The size of certificate data in bytes.
     27   @param[out] SingleX509Cert  The generated X509 object.
     28 
     29   @retval     TRUE            The X509 object generation succeeded.
     30   @retval     FALSE           The operation failed.
     31 
     32 **/
     33 BOOLEAN
     34 EFIAPI
     35 X509ConstructCertificate (
     36   IN   CONST UINT8  *Cert,
     37   IN   UINTN        CertSize,
     38   OUT  UINT8        **SingleX509Cert
     39   )
     40 {
     41   X509         *X509Cert;
     42   CONST UINT8  *Temp;
     43 
     44   //
     45   // Check input parameters.
     46   //
     47   if (Cert == NULL || SingleX509Cert == NULL || CertSize > INT_MAX) {
     48     return FALSE;
     49   }
     50 
     51   //
     52   // Read DER-encoded X509 Certificate and Construct X509 object.
     53   //
     54   Temp     = Cert;
     55   X509Cert = d2i_X509 (NULL, &Temp, (long) CertSize);
     56   if (X509Cert == NULL) {
     57     return FALSE;
     58   }
     59 
     60   *SingleX509Cert = (UINT8 *) X509Cert;
     61 
     62   return TRUE;
     63 }
     64 
     65 /**
     66   Construct a X509 stack object from a list of DER-encoded certificate data.
     67 
     68   If X509Stack is NULL, then return FALSE.
     69 
     70   @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.
     71                               On output, pointer to the X509 stack object with new
     72                               inserted X509 certificate.
     73   @param           ...        A list of DER-encoded single certificate data followed
     74                               by certificate size. A NULL terminates the list. The
     75                               pairs are the arguments to X509ConstructCertificate().
     76 
     77   @retval     TRUE            The X509 stack construction succeeded.
     78   @retval     FALSE           The construction operation failed.
     79 
     80 **/
     81 BOOLEAN
     82 EFIAPI
     83 X509ConstructCertificateStack (
     84   IN OUT  UINT8  **X509Stack,
     85   ...
     86   )
     87 {
     88   UINT8           *Cert;
     89   UINTN           CertSize;
     90   X509            *X509Cert;
     91   STACK_OF(X509)  *CertStack;
     92   BOOLEAN         Status;
     93   VA_LIST         Args;
     94   UINTN           Index;
     95 
     96   //
     97   // Check input parameters.
     98   //
     99   if (X509Stack == NULL) {
    100     return FALSE;
    101   }
    102 
    103   Status = FALSE;
    104 
    105   //
    106   // Initialize X509 stack object.
    107   //
    108   CertStack = (STACK_OF(X509) *) (*X509Stack);
    109   if (CertStack == NULL) {
    110     CertStack = sk_X509_new_null ();
    111     if (CertStack == NULL) {
    112       return Status;
    113     }
    114   }
    115 
    116   VA_START (Args, X509Stack);
    117 
    118   for (Index = 0; ; Index++) {
    119     //
    120     // If Cert is NULL, then it is the end of the list.
    121     //
    122     Cert = VA_ARG (Args, UINT8 *);
    123     if (Cert == NULL) {
    124       break;
    125     }
    126 
    127     CertSize = VA_ARG (Args, UINTN);
    128     if (CertSize == 0) {
    129       break;
    130     }
    131 
    132     //
    133     // Construct X509 Object from the given DER-encoded certificate data.
    134     //
    135     X509Cert = NULL;
    136     Status = X509ConstructCertificate (
    137                (CONST UINT8 *) Cert,
    138                CertSize,
    139                (UINT8 **) &X509Cert
    140                );
    141     if (!Status) {
    142       if (X509Cert != NULL) {
    143         X509_free (X509Cert);
    144       }
    145       break;
    146     }
    147 
    148     //
    149     // Insert the new X509 object into X509 stack object.
    150     //
    151     sk_X509_push (CertStack, X509Cert);
    152   }
    153 
    154   VA_END (Args);
    155 
    156   if (!Status) {
    157     sk_X509_pop_free (CertStack, X509_free);
    158   } else {
    159     *X509Stack = (UINT8 *) CertStack;
    160   }
    161 
    162   return Status;
    163 }
    164 
    165 /**
    166   Release the specified X509 object.
    167 
    168   If X509Cert is NULL, then return FALSE.
    169 
    170   @param[in]  X509Cert  Pointer to the X509 object to be released.
    171 
    172 **/
    173 VOID
    174 EFIAPI
    175 X509Free (
    176   IN  VOID  *X509Cert
    177   )
    178 {
    179   //
    180   // Check input parameters.
    181   //
    182   if (X509Cert == NULL) {
    183     return;
    184   }
    185 
    186   //
    187   // Free OpenSSL X509 object.
    188   //
    189   X509_free ((X509 *) X509Cert);
    190 }
    191 
    192 /**
    193   Release the specified X509 stack object.
    194 
    195   If X509Stack is NULL, then return FALSE.
    196 
    197   @param[in]  X509Stack  Pointer to the X509 stack object to be released.
    198 
    199 **/
    200 VOID
    201 EFIAPI
    202 X509StackFree (
    203   IN  VOID  *X509Stack
    204   )
    205 {
    206   //
    207   // Check input parameters.
    208   //
    209   if (X509Stack == NULL) {
    210     return;
    211   }
    212 
    213   //
    214   // Free OpenSSL X509 stack object.
    215   //
    216   sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free);
    217 }
    218 
    219 /**
    220   Retrieve the subject bytes from one X.509 certificate.
    221 
    222   @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
    223   @param[in]      CertSize     Size of the X509 certificate in bytes.
    224   @param[out]     CertSubject  Pointer to the retrieved certificate subject bytes.
    225   @param[in, out] SubjectSize  The size in bytes of the CertSubject buffer on input,
    226                                and the size of buffer returned CertSubject on output.
    227 
    228   If Cert is NULL, then return FALSE.
    229   If SubjectSize is NULL, then return FALSE.
    230 
    231   @retval  TRUE   The certificate subject retrieved successfully.
    232   @retval  FALSE  Invalid certificate, or the SubjectSize is too small for the result.
    233                   The SubjectSize will be updated with the required size.
    234 
    235 **/
    236 BOOLEAN
    237 EFIAPI
    238 X509GetSubjectName (
    239   IN      CONST UINT8  *Cert,
    240   IN      UINTN        CertSize,
    241   OUT     UINT8        *CertSubject,
    242   IN OUT  UINTN        *SubjectSize
    243   )
    244 {
    245   BOOLEAN    Status;
    246   X509       *X509Cert;
    247   X509_NAME  *X509Name;
    248   UINTN      X509NameSize;
    249 
    250   //
    251   // Check input parameters.
    252   //
    253   if (Cert == NULL || SubjectSize == NULL) {
    254     return FALSE;
    255   }
    256 
    257   X509Cert = NULL;
    258 
    259   //
    260   // Read DER-encoded X509 Certificate and Construct X509 object.
    261   //
    262   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
    263   if ((X509Cert == NULL) || (!Status)) {
    264     Status = FALSE;
    265     goto _Exit;
    266   }
    267 
    268   Status = FALSE;
    269 
    270   //
    271   // Retrieve subject name from certificate object.
    272   //
    273   X509Name = X509_get_subject_name (X509Cert);
    274   if (X509Name == NULL) {
    275     goto _Exit;
    276   }
    277 
    278   X509NameSize = i2d_X509_NAME(X509Name, NULL);
    279   if (*SubjectSize < X509NameSize) {
    280     *SubjectSize = X509NameSize;
    281     goto _Exit;
    282   }
    283   *SubjectSize = X509NameSize;
    284   if (CertSubject != NULL) {
    285     i2d_X509_NAME(X509Name, &CertSubject);
    286     Status = TRUE;
    287   }
    288 
    289 _Exit:
    290   //
    291   // Release Resources.
    292   //
    293   if (X509Cert != NULL) {
    294     X509_free (X509Cert);
    295   }
    296 
    297   return Status;
    298 }
    299 
    300 /**
    301   Retrieve the RSA Public Key from one DER-encoded X509 certificate.
    302 
    303   @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
    304   @param[in]  CertSize     Size of the X509 certificate in bytes.
    305   @param[out] RsaContext   Pointer to new-generated RSA context which contain the retrieved
    306                            RSA public key component. Use RsaFree() function to free the
    307                            resource.
    308 
    309   If Cert is NULL, then return FALSE.
    310   If RsaContext is NULL, then return FALSE.
    311 
    312   @retval  TRUE   RSA Public Key was retrieved successfully.
    313   @retval  FALSE  Fail to retrieve RSA public key from X509 certificate.
    314 
    315 **/
    316 BOOLEAN
    317 EFIAPI
    318 RsaGetPublicKeyFromX509 (
    319   IN   CONST UINT8  *Cert,
    320   IN   UINTN        CertSize,
    321   OUT  VOID         **RsaContext
    322   )
    323 {
    324   BOOLEAN   Status;
    325   EVP_PKEY  *Pkey;
    326   X509      *X509Cert;
    327 
    328   //
    329   // Check input parameters.
    330   //
    331   if (Cert == NULL || RsaContext == NULL) {
    332     return FALSE;
    333   }
    334 
    335   Pkey     = NULL;
    336   X509Cert = NULL;
    337 
    338   //
    339   // Read DER-encoded X509 Certificate and Construct X509 object.
    340   //
    341   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
    342   if ((X509Cert == NULL) || (!Status)) {
    343     Status = FALSE;
    344     goto _Exit;
    345   }
    346 
    347   Status = FALSE;
    348 
    349   //
    350   // Retrieve and check EVP_PKEY data from X509 Certificate.
    351   //
    352   Pkey = X509_get_pubkey (X509Cert);
    353   if ((Pkey == NULL) || (Pkey->type != EVP_PKEY_RSA)) {
    354     goto _Exit;
    355   }
    356 
    357   //
    358   // Duplicate RSA Context from the retrieved EVP_PKEY.
    359   //
    360   if ((*RsaContext = RSAPublicKey_dup (Pkey->pkey.rsa)) != NULL) {
    361     Status = TRUE;
    362   }
    363 
    364 _Exit:
    365   //
    366   // Release Resources.
    367   //
    368   if (X509Cert != NULL) {
    369     X509_free (X509Cert);
    370   }
    371 
    372   if (Pkey != NULL) {
    373     EVP_PKEY_free (Pkey);
    374   }
    375 
    376   return Status;
    377 }
    378 
    379 /**
    380   Verify one X509 certificate was issued by the trusted CA.
    381 
    382   @param[in]      Cert         Pointer to the DER-encoded X509 certificate to be verified.
    383   @param[in]      CertSize     Size of the X509 certificate in bytes.
    384   @param[in]      CACert       Pointer to the DER-encoded trusted CA certificate.
    385   @param[in]      CACertSize   Size of the CA Certificate in bytes.
    386 
    387   If Cert is NULL, then return FALSE.
    388   If CACert is NULL, then return FALSE.
    389 
    390   @retval  TRUE   The certificate was issued by the trusted CA.
    391   @retval  FALSE  Invalid certificate or the certificate was not issued by the given
    392                   trusted CA.
    393 
    394 **/
    395 BOOLEAN
    396 EFIAPI
    397 X509VerifyCert (
    398   IN  CONST UINT8  *Cert,
    399   IN  UINTN        CertSize,
    400   IN  CONST UINT8  *CACert,
    401   IN  UINTN        CACertSize
    402   )
    403 {
    404   BOOLEAN         Status;
    405   X509            *X509Cert;
    406   X509            *X509CACert;
    407   X509_STORE      *CertStore;
    408   X509_STORE_CTX  CertCtx;
    409 
    410   //
    411   // Check input parameters.
    412   //
    413   if (Cert == NULL || CACert == NULL) {
    414     return FALSE;
    415   }
    416 
    417   Status     = FALSE;
    418   X509Cert   = NULL;
    419   X509CACert = NULL;
    420   CertStore  = NULL;
    421 
    422   //
    423   // Register & Initialize necessary digest algorithms for certificate verification.
    424   //
    425   if (EVP_add_digest (EVP_md5 ()) == 0) {
    426     goto _Exit;
    427   }
    428   if (EVP_add_digest (EVP_sha1 ()) == 0) {
    429     goto _Exit;
    430   }
    431   if (EVP_add_digest (EVP_sha256 ()) == 0) {
    432     goto _Exit;
    433   }
    434 
    435   //
    436   // Read DER-encoded certificate to be verified and Construct X509 object.
    437   //
    438   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
    439   if ((X509Cert == NULL) || (!Status)) {
    440     Status = FALSE;
    441     goto _Exit;
    442   }
    443 
    444   //
    445   // Read DER-encoded root certificate and Construct X509 object.
    446   //
    447   Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert);
    448   if ((X509CACert == NULL) || (!Status)) {
    449     Status = FALSE;
    450     goto _Exit;
    451   }
    452 
    453   Status = FALSE;
    454 
    455   //
    456   // Set up X509 Store for trusted certificate.
    457   //
    458   CertStore = X509_STORE_new ();
    459   if (CertStore == NULL) {
    460     goto _Exit;
    461   }
    462   if (!(X509_STORE_add_cert (CertStore, X509CACert))) {
    463     goto _Exit;
    464   }
    465 
    466   //
    467   // Allow partial certificate chains, terminated by a non-self-signed but
    468   // still trusted intermediate certificate. Also disable time checks.
    469   //
    470   X509_STORE_set_flags (CertStore,
    471                         X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
    472 
    473   //
    474   // Set up X509_STORE_CTX for the subsequent verification operation.
    475   //
    476   if (!X509_STORE_CTX_init (&CertCtx, CertStore, X509Cert, NULL)) {
    477     goto _Exit;
    478   }
    479 
    480   //
    481   // X509 Certificate Verification.
    482   //
    483   Status = (BOOLEAN) X509_verify_cert (&CertCtx);
    484   X509_STORE_CTX_cleanup (&CertCtx);
    485 
    486 _Exit:
    487   //
    488   // Release Resources.
    489   //
    490   if (X509Cert != NULL) {
    491     X509_free (X509Cert);
    492   }
    493 
    494   if (X509CACert != NULL) {
    495     X509_free (X509CACert);
    496   }
    497 
    498   if (CertStore != NULL) {
    499     X509_STORE_free (CertStore);
    500   }
    501 
    502   return Status;
    503 }
    504 
    505 /**
    506   Retrieve the TBSCertificate from one given X.509 certificate.
    507 
    508   @param[in]      Cert         Pointer to the given DER-encoded X509 certificate.
    509   @param[in]      CertSize     Size of the X509 certificate in bytes.
    510   @param[out]     TBSCert      DER-Encoded To-Be-Signed certificate.
    511   @param[out]     TBSCertSize  Size of the TBS certificate in bytes.
    512 
    513   If Cert is NULL, then return FALSE.
    514   If TBSCert is NULL, then return FALSE.
    515   If TBSCertSize is NULL, then return FALSE.
    516 
    517   @retval  TRUE   The TBSCertificate was retrieved successfully.
    518   @retval  FALSE  Invalid X.509 certificate.
    519 
    520 **/
    521 BOOLEAN
    522 EFIAPI
    523 X509GetTBSCert (
    524   IN  CONST UINT8  *Cert,
    525   IN  UINTN        CertSize,
    526   OUT UINT8        **TBSCert,
    527   OUT UINTN        *TBSCertSize
    528   )
    529 {
    530   CONST UINT8  *Temp;
    531   INTN         Asn1Tag;
    532   INTN         ObjClass;
    533   UINTN        Length;
    534 
    535   //
    536   // Check input parameters.
    537   //
    538   if ((Cert == NULL) || (TBSCert == NULL) ||
    539       (TBSCertSize == NULL) || (CertSize > INT_MAX)) {
    540     return FALSE;
    541   }
    542 
    543   //
    544   // An X.509 Certificate is: (defined in RFC3280)
    545   //   Certificate  ::=  SEQUENCE  {
    546   //     tbsCertificate       TBSCertificate,
    547   //     signatureAlgorithm   AlgorithmIdentifier,
    548   //     signature            BIT STRING }
    549   //
    550   // and
    551   //
    552   //  TBSCertificate  ::=  SEQUENCE  {
    553   //    version         [0]  Version DEFAULT v1,
    554   //    ...
    555   //    }
    556   //
    557   // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
    558   // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
    559   //
    560   Temp = Cert;
    561   ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);
    562 
    563   if (Asn1Tag != V_ASN1_SEQUENCE) {
    564     return FALSE;
    565   }
    566 
    567   *TBSCert = (UINT8 *)Temp;
    568 
    569   ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);
    570   //
    571   // Verify the parsed TBSCertificate is one correct SEQUENCE data.
    572   //
    573   if (Asn1Tag != V_ASN1_SEQUENCE) {
    574     return FALSE;
    575   }
    576 
    577   *TBSCertSize = Length + (Temp - *TBSCert);
    578 
    579   return TRUE;
    580 }
    581