Fixes CodeQL alerts for CWE-457: https://cwe.mitre.org/data/definitions/457.html Checks the return value from `ASN1_get_object()` to verify values set by the function are valid. Note that the function returns literal `0x80`: `return (0x80);` That is used to check the return value is as the case in other areas of the code. Cc: Erich McMillan <emcmillan@microsoft.com> Cc: Guomin Jiang <guomin.jiang@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Michael Kubacki <mikuback@linux.microsoft.com> Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com> Co-authored-by: Erich McMillan <emcmillan@microsoft.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Jiewen Yao <Jiewen.yao@intel.com> Reviewed-by: Oliver Smith-Denny <osd@smith-denny.com>
		
			
				
	
	
		
			1963 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1963 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  X.509 Certificate Handler Wrapper Implementation over OpenSSL.
 | 
						|
 | 
						|
Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "InternalCryptLib.h"
 | 
						|
#include <openssl/x509.h>
 | 
						|
#include <openssl/x509v3.h>
 | 
						|
#include <crypto/asn1.h>
 | 
						|
#include <openssl/asn1.h>
 | 
						|
#include <openssl/rsa.h>
 | 
						|
 | 
						|
/* OID*/
 | 
						|
#define OID_EXT_KEY_USAGE      { 0x55, 0x1D, 0x25 }
 | 
						|
#define OID_BASIC_CONSTRAINTS  { 0x55, 0x1D, 0x13 }
 | 
						|
 | 
						|
static CONST UINT8  mOidExtKeyUsage[]      = OID_EXT_KEY_USAGE;
 | 
						|
static CONST UINT8  mOidBasicConstraints[] = OID_BASIC_CONSTRAINTS;
 | 
						|
 | 
						|
#define CRYPTO_ASN1_TAG_CLASS_MASK  0xC0
 | 
						|
#define CRYPTO_ASN1_TAG_PC_MASK     0x20
 | 
						|
#define CRYPTO_ASN1_TAG_VALUE_MASK  0x1F
 | 
						|
 | 
						|
/**
 | 
						|
  Construct a X509 object from DER-encoded certificate data.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If SingleX509Cert is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in]  Cert            Pointer to the DER-encoded certificate data.
 | 
						|
  @param[in]  CertSize        The size of certificate data in bytes.
 | 
						|
  @param[out] SingleX509Cert  The generated X509 object.
 | 
						|
 | 
						|
  @retval     TRUE            The X509 object generation succeeded.
 | 
						|
  @retval     FALSE           The operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509ConstructCertificate (
 | 
						|
  IN   CONST UINT8  *Cert,
 | 
						|
  IN   UINTN        CertSize,
 | 
						|
  OUT  UINT8        **SingleX509Cert
 | 
						|
  )
 | 
						|
{
 | 
						|
  X509         *X509Cert;
 | 
						|
  CONST UINT8  *Temp;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize > INT_MAX)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Temp     = Cert;
 | 
						|
  X509Cert = d2i_X509 (NULL, &Temp, (long)CertSize);
 | 
						|
  if (X509Cert == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  *SingleX509Cert = (UINT8 *)X509Cert;
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Construct a X509 stack object from a list of DER-encoded certificate data.
 | 
						|
 | 
						|
  If X509Stack is NULL, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.
 | 
						|
                              On output, pointer to the X509 stack object with new
 | 
						|
                              inserted X509 certificate.
 | 
						|
  @param[in]       Args       VA_LIST marker for the variable argument list.
 | 
						|
                              A list of DER-encoded single certificate data followed
 | 
						|
                              by certificate size. A NULL terminates the list. The
 | 
						|
                              pairs are the arguments to X509ConstructCertificate().
 | 
						|
 | 
						|
  @retval     TRUE            The X509 stack construction succeeded.
 | 
						|
  @retval     FALSE           The construction operation failed.
 | 
						|
  @retval     FALSE           This interface is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509ConstructCertificateStackV (
 | 
						|
  IN OUT  UINT8    **X509Stack,
 | 
						|
  IN      VA_LIST  Args
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8  *Cert;
 | 
						|
  UINTN  CertSize;
 | 
						|
  X509   *X509Cert;
 | 
						|
 | 
						|
  STACK_OF (X509)  *CertStack;
 | 
						|
  BOOLEAN  Status;
 | 
						|
  UINTN    Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if (X509Stack == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize X509 stack object.
 | 
						|
  //
 | 
						|
  CertStack = (STACK_OF (X509) *)(*X509Stack);
 | 
						|
  if (CertStack == NULL) {
 | 
						|
    CertStack = sk_X509_new_null ();
 | 
						|
    if (CertStack == NULL) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; ; Index++) {
 | 
						|
    //
 | 
						|
    // If Cert is NULL, then it is the end of the list.
 | 
						|
    //
 | 
						|
    Cert = VA_ARG (Args, UINT8 *);
 | 
						|
    if (Cert == NULL) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    CertSize = VA_ARG (Args, UINTN);
 | 
						|
    if (CertSize == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Construct X509 Object from the given DER-encoded certificate data.
 | 
						|
    //
 | 
						|
    X509Cert = NULL;
 | 
						|
    Status   = X509ConstructCertificate (
 | 
						|
                 (CONST UINT8 *)Cert,
 | 
						|
                 CertSize,
 | 
						|
                 (UINT8 **)&X509Cert
 | 
						|
                 );
 | 
						|
    if (!Status) {
 | 
						|
      if (X509Cert != NULL) {
 | 
						|
        X509_free (X509Cert);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Insert the new X509 object into X509 stack object.
 | 
						|
    //
 | 
						|
    sk_X509_push (CertStack, X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Status) {
 | 
						|
    sk_X509_pop_free (CertStack, X509_free);
 | 
						|
  } else {
 | 
						|
    *X509Stack = (UINT8 *)CertStack;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Construct a X509 stack object from a list of DER-encoded certificate data.
 | 
						|
 | 
						|
  If X509Stack is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.
 | 
						|
                              On output, pointer to the X509 stack object with new
 | 
						|
                              inserted X509 certificate.
 | 
						|
  @param           ...        A list of DER-encoded single certificate data followed
 | 
						|
                              by certificate size. A NULL terminates the list. The
 | 
						|
                              pairs are the arguments to X509ConstructCertificate().
 | 
						|
 | 
						|
  @retval     TRUE            The X509 stack construction succeeded.
 | 
						|
  @retval     FALSE           The construction operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509ConstructCertificateStack (
 | 
						|
  IN OUT  UINT8  **X509Stack,
 | 
						|
  ...
 | 
						|
  )
 | 
						|
{
 | 
						|
  VA_LIST  Args;
 | 
						|
  BOOLEAN  Result;
 | 
						|
 | 
						|
  VA_START (Args, X509Stack);
 | 
						|
  Result = X509ConstructCertificateStackV (X509Stack, Args);
 | 
						|
  VA_END (Args);
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Release the specified X509 object.
 | 
						|
 | 
						|
  If X509Cert is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in]  X509Cert  Pointer to the X509 object to be released.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
X509Free (
 | 
						|
  IN  VOID  *X509Cert
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if (X509Cert == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Free OpenSSL X509 object.
 | 
						|
  //
 | 
						|
  X509_free ((X509 *)X509Cert);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Release the specified X509 stack object.
 | 
						|
 | 
						|
  If X509Stack is NULL, then return FALSE.
 | 
						|
 | 
						|
  @param[in]  X509Stack  Pointer to the X509 stack object to be released.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
X509StackFree (
 | 
						|
  IN  VOID  *X509Stack
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if (X509Stack == NULL) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Free OpenSSL X509 stack object.
 | 
						|
  //
 | 
						|
  sk_X509_pop_free ((STACK_OF (X509) *) X509Stack, X509_free);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the subject bytes from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     CertSubject  Pointer to the retrieved certificate subject bytes.
 | 
						|
  @param[in, out] SubjectSize  The size in bytes of the CertSubject buffer on input,
 | 
						|
                               and the size of buffer returned CertSubject on output.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If SubjectSize is NULL, then return FALSE.
 | 
						|
 | 
						|
  @retval  TRUE   The certificate subject retrieved successfully.
 | 
						|
  @retval  FALSE  Invalid certificate, or the SubjectSize is too small for the result.
 | 
						|
                  The SubjectSize will be updated with the required size.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetSubjectName (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  OUT     UINT8        *CertSubject,
 | 
						|
  IN OUT  UINTN        *SubjectSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN    Status;
 | 
						|
  X509       *X509Cert;
 | 
						|
  X509_NAME  *X509Name;
 | 
						|
  UINTN      X509NameSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (SubjectSize == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  X509Name = X509_get_subject_name (X509Cert);
 | 
						|
  if (X509Name == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  X509NameSize = i2d_X509_NAME (X509Name, NULL);
 | 
						|
  if (*SubjectSize < X509NameSize) {
 | 
						|
    *SubjectSize = X509NameSize;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *SubjectSize = X509NameSize;
 | 
						|
  if (CertSubject != NULL) {
 | 
						|
    i2d_X509_NAME (X509Name, &CertSubject);
 | 
						|
    Status = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve a string from one X.509 certificate base on the Request_NID.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[in]      Request_NID      NID of string to obtain
 | 
						|
  @param[out]     CommonName       Buffer to contain the retrieved certificate common
 | 
						|
                                   name string (UTF8). At most CommonNameSize bytes will be
 | 
						|
                                   written and the string will be null terminated. May be
 | 
						|
                                   NULL in order to determine the size buffer needed.
 | 
						|
  @param[in,out]  CommonNameSize   The size in bytes of the CommonName buffer on input,
 | 
						|
                                   and the size of buffer returned CommonName on output.
 | 
						|
                                   If CommonName is NULL then the amount of space needed
 | 
						|
                                   in buffer (including the final null) is returned.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS           The certificate CommonName retrieved successfully.
 | 
						|
  @retval RETURN_INVALID_PARAMETER If Cert is NULL.
 | 
						|
                                   If CommonNameSize is NULL.
 | 
						|
                                   If CommonName is not NULL and *CommonNameSize is 0.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval RETURN_NOT_FOUND         If no NID Name entry exists.
 | 
						|
  @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size
 | 
						|
                                   (including the final null) is returned in the
 | 
						|
                                   CommonNameSize parameter.
 | 
						|
  @retval RETURN_UNSUPPORTED       The operation is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
InternalX509GetNIDName (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  IN      INT32        Request_NID,
 | 
						|
  OUT     CHAR8        *CommonName   OPTIONAL,
 | 
						|
  IN OUT  UINTN        *CommonNameSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS    ReturnStatus;
 | 
						|
  BOOLEAN          Status;
 | 
						|
  X509             *X509Cert;
 | 
						|
  X509_NAME        *X509Name;
 | 
						|
  INT32            Index;
 | 
						|
  INTN             Length;
 | 
						|
  X509_NAME_ENTRY  *Entry;
 | 
						|
  ASN1_STRING      *EntryData;
 | 
						|
  UINT8            *UTF8Name;
 | 
						|
 | 
						|
  ReturnStatus = RETURN_INVALID_PARAMETER;
 | 
						|
  UTF8Name     = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {
 | 
						|
    return ReturnStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((CommonName != NULL) && (*CommonNameSize == 0)) {
 | 
						|
    return ReturnStatus;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    //
 | 
						|
    // Invalid X.509 Certificate
 | 
						|
    //
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  X509Name = X509_get_subject_name (X509Cert);
 | 
						|
  if (X509Name == NULL) {
 | 
						|
    //
 | 
						|
    // Fail to retrieve subject name content
 | 
						|
    //
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrive the string from X.509 Subject base on the Request_NID
 | 
						|
  //
 | 
						|
  Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);
 | 
						|
  if (Index < 0) {
 | 
						|
    //
 | 
						|
    // No Request_NID name entry exists in X509_NAME object
 | 
						|
    //
 | 
						|
    *CommonNameSize = 0;
 | 
						|
    ReturnStatus    = RETURN_NOT_FOUND;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Entry = X509_NAME_get_entry (X509Name, Index);
 | 
						|
  if (Entry == NULL) {
 | 
						|
    //
 | 
						|
    // Fail to retrieve name entry data
 | 
						|
    //
 | 
						|
    *CommonNameSize = 0;
 | 
						|
    ReturnStatus    = RETURN_NOT_FOUND;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  EntryData = X509_NAME_ENTRY_get_data (Entry);
 | 
						|
 | 
						|
  Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);
 | 
						|
  if (Length < 0) {
 | 
						|
    //
 | 
						|
    // Fail to convert the Name string
 | 
						|
    //
 | 
						|
    *CommonNameSize = 0;
 | 
						|
    ReturnStatus    = RETURN_INVALID_PARAMETER;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CommonName == NULL) {
 | 
						|
    *CommonNameSize = Length + 1;
 | 
						|
    ReturnStatus    = RETURN_BUFFER_TOO_SMALL;
 | 
						|
  } else {
 | 
						|
    *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;
 | 
						|
    CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);
 | 
						|
    CommonName[*CommonNameSize - 1] = '\0';
 | 
						|
    ReturnStatus                    = RETURN_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (UTF8Name != NULL) {
 | 
						|
    OPENSSL_free (UTF8Name);
 | 
						|
  }
 | 
						|
 | 
						|
  return ReturnStatus;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the common name (CN) string from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     CommonName       Buffer to contain the retrieved certificate common
 | 
						|
                                   name string. At most CommonNameSize bytes will be
 | 
						|
                                   written and the string will be null terminated. May be
 | 
						|
                                   NULL in order to determine the size buffer needed.
 | 
						|
  @param[in,out]  CommonNameSize   The size in bytes of the CommonName buffer on input,
 | 
						|
                                   and the size of buffer returned CommonName on output.
 | 
						|
                                   If CommonName is NULL then the amount of space needed
 | 
						|
                                   in buffer (including the final null) is returned.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS           The certificate CommonName retrieved successfully.
 | 
						|
  @retval RETURN_INVALID_PARAMETER If Cert is NULL.
 | 
						|
                                   If CommonNameSize is NULL.
 | 
						|
                                   If CommonName is not NULL and *CommonNameSize is 0.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval RETURN_NOT_FOUND         If no CommonName entry exists.
 | 
						|
  @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size
 | 
						|
                                   (including the final null) is returned in the
 | 
						|
                                   CommonNameSize parameter.
 | 
						|
  @retval RETURN_UNSUPPORTED       The operation is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
X509GetCommonName (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  OUT     CHAR8        *CommonName   OPTIONAL,
 | 
						|
  IN OUT  UINTN        *CommonNameSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the organization name (O) string from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     NameBuffer       Buffer to contain the retrieved certificate organization
 | 
						|
                                   name string. At most NameBufferSize bytes will be
 | 
						|
                                   written and the string will be null terminated. May be
 | 
						|
                                   NULL in order to determine the size buffer needed.
 | 
						|
  @param[in,out]  NameBufferSize   The size in bytes of the Name buffer on input,
 | 
						|
                                   and the size of buffer returned Name on output.
 | 
						|
                                   If NameBuffer is NULL then the amount of space needed
 | 
						|
                                   in buffer (including the final null) is returned.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS           The certificate Organization Name retrieved successfully.
 | 
						|
  @retval RETURN_INVALID_PARAMETER If Cert is NULL.
 | 
						|
                                   If NameBufferSize is NULL.
 | 
						|
                                   If NameBuffer is not NULL and *CommonNameSize is 0.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval RETURN_NOT_FOUND         If no Organization Name entry exists.
 | 
						|
  @retval RETURN_BUFFER_TOO_SMALL  If the NameBuffer is NULL. The required buffer size
 | 
						|
                                   (including the final null) is returned in the
 | 
						|
                                   CommonNameSize parameter.
 | 
						|
  @retval RETURN_UNSUPPORTED       The operation is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
X509GetOrganizationName (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  OUT     CHAR8        *NameBuffer   OPTIONAL,
 | 
						|
  IN OUT  UINTN        *NameBufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the RSA Public Key from one DER-encoded X509 certificate.
 | 
						|
 | 
						|
  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]  CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out] RsaContext   Pointer to new-generated RSA context which contain the retrieved
 | 
						|
                           RSA public key component. Use RsaFree() function to free the
 | 
						|
                           resource.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If RsaContext is NULL, then return FALSE.
 | 
						|
 | 
						|
  @retval  TRUE   RSA Public Key was retrieved successfully.
 | 
						|
  @retval  FALSE  Fail to retrieve RSA public key from X509 certificate.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
RsaGetPublicKeyFromX509 (
 | 
						|
  IN   CONST UINT8  *Cert,
 | 
						|
  IN   UINTN        CertSize,
 | 
						|
  OUT  VOID         **RsaContext
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN   Status;
 | 
						|
  EVP_PKEY  *Pkey;
 | 
						|
  X509      *X509Cert;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (RsaContext == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Pkey     = NULL;
 | 
						|
  X509Cert = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve and check EVP_PKEY data from X509 Certificate.
 | 
						|
  //
 | 
						|
  Pkey = X509_get_pubkey (X509Cert);
 | 
						|
  if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Duplicate RSA Context from the retrieved EVP_PKEY.
 | 
						|
  //
 | 
						|
  if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {
 | 
						|
    Status = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pkey != NULL) {
 | 
						|
    EVP_PKEY_free (Pkey);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Verify one X509 certificate was issued by the trusted CA.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate to be verified.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[in]      CACert       Pointer to the DER-encoded trusted CA certificate.
 | 
						|
  @param[in]      CACertSize   Size of the CA Certificate in bytes.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If CACert is NULL, then return FALSE.
 | 
						|
 | 
						|
  @retval  TRUE   The certificate was issued by the trusted CA.
 | 
						|
  @retval  FALSE  Invalid certificate or the certificate was not issued by the given
 | 
						|
                  trusted CA.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509VerifyCert (
 | 
						|
  IN  CONST UINT8  *Cert,
 | 
						|
  IN  UINTN        CertSize,
 | 
						|
  IN  CONST UINT8  *CACert,
 | 
						|
  IN  UINTN        CACertSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN         Status;
 | 
						|
  X509            *X509Cert;
 | 
						|
  X509            *X509CACert;
 | 
						|
  X509_STORE      *CertStore;
 | 
						|
  X509_STORE_CTX  *CertCtx;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (CACert == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Status     = FALSE;
 | 
						|
  X509Cert   = NULL;
 | 
						|
  X509CACert = NULL;
 | 
						|
  CertStore  = NULL;
 | 
						|
  CertCtx    = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Register & Initialize necessary digest algorithms for certificate verification.
 | 
						|
  //
 | 
						|
  if (EVP_add_digest (EVP_md5 ()) == 0) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EVP_add_digest (EVP_sha1 ()) == 0) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EVP_add_digest (EVP_sha256 ()) == 0) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded certificate to be verified and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded root certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **)&X509CACert);
 | 
						|
  if ((X509CACert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set up X509 Store for trusted certificate.
 | 
						|
  //
 | 
						|
  CertStore = X509_STORE_new ();
 | 
						|
  if (CertStore == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!(X509_STORE_add_cert (CertStore, X509CACert))) {
 | 
						|
    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
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Set up X509_STORE_CTX for the subsequent verification operation.
 | 
						|
  //
 | 
						|
  CertCtx = X509_STORE_CTX_new ();
 | 
						|
  if (CertCtx == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // X509 Certificate Verification.
 | 
						|
  //
 | 
						|
  Status = (BOOLEAN)X509_verify_cert (CertCtx);
 | 
						|
  X509_STORE_CTX_cleanup (CertCtx);
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (X509CACert != NULL) {
 | 
						|
    X509_free (X509CACert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (CertStore != NULL) {
 | 
						|
    X509_STORE_free (CertStore);
 | 
						|
  }
 | 
						|
 | 
						|
  X509_STORE_CTX_free (CertCtx);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the TBSCertificate from one given X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the given DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     TBSCert      DER-Encoded To-Be-Signed certificate.
 | 
						|
  @param[out]     TBSCertSize  Size of the TBS certificate in bytes.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If TBSCert is NULL, then return FALSE.
 | 
						|
  If TBSCertSize is NULL, then return FALSE.
 | 
						|
 | 
						|
  @retval  TRUE   The TBSCertificate was retrieved successfully.
 | 
						|
  @retval  FALSE  Invalid X.509 certificate.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetTBSCert (
 | 
						|
  IN  CONST UINT8  *Cert,
 | 
						|
  IN  UINTN        CertSize,
 | 
						|
  OUT UINT8        **TBSCert,
 | 
						|
  OUT UINTN        *TBSCertSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST UINT8  *Temp;
 | 
						|
  UINT32       Asn1Tag;
 | 
						|
  UINT32       ObjClass;
 | 
						|
  UINTN        Length;
 | 
						|
  UINTN        Inf;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (TBSCert == NULL) ||
 | 
						|
      (TBSCertSize == NULL) || (CertSize > INT_MAX))
 | 
						|
  {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // An X.509 Certificate is: (defined in RFC3280)
 | 
						|
  //   Certificate  ::=  SEQUENCE  {
 | 
						|
  //     tbsCertificate       TBSCertificate,
 | 
						|
  //     signatureAlgorithm   AlgorithmIdentifier,
 | 
						|
  //     signature            BIT STRING }
 | 
						|
  //
 | 
						|
  // and
 | 
						|
  //
 | 
						|
  //  TBSCertificate  ::=  SEQUENCE  {
 | 
						|
  //    version         [0]  Version DEFAULT v1,
 | 
						|
  //    ...
 | 
						|
  //    }
 | 
						|
  //
 | 
						|
  // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
 | 
						|
  // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
 | 
						|
  //
 | 
						|
  Temp   = Cert;
 | 
						|
  Length = 0;
 | 
						|
  Inf    = ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);
 | 
						|
 | 
						|
  if (((Inf & 0x80) == 0x00) && (Asn1Tag != V_ASN1_SEQUENCE)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  *TBSCert = (UINT8 *)Temp;
 | 
						|
 | 
						|
  ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);
 | 
						|
  //
 | 
						|
  // Verify the parsed TBSCertificate is one correct SEQUENCE data.
 | 
						|
  //
 | 
						|
  if (((Inf & 0x80) == 0x00) && (Asn1Tag != V_ASN1_SEQUENCE)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  *TBSCertSize = Length + (Temp - *TBSCert);
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the EC Public Key from one DER-encoded X509 certificate.
 | 
						|
 | 
						|
  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]  CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
 | 
						|
                           EC public key component. Use EcFree() function to free the
 | 
						|
                           resource.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If EcContext is NULL, then return FALSE.
 | 
						|
 | 
						|
  @retval  TRUE   EC Public Key was retrieved successfully.
 | 
						|
  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
EcGetPublicKeyFromX509 (
 | 
						|
  IN   CONST UINT8  *Cert,
 | 
						|
  IN   UINTN        CertSize,
 | 
						|
  OUT  VOID         **EcContext
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN   Status;
 | 
						|
  EVP_PKEY  *Pkey;
 | 
						|
  X509      *X509Cert;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (EcContext == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Pkey     = NULL;
 | 
						|
  X509Cert = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve and check EVP_PKEY data from X509 Certificate.
 | 
						|
  //
 | 
						|
  Pkey = X509_get_pubkey (X509Cert);
 | 
						|
  if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_EC)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Duplicate EC Context from the retrieved EVP_PKEY.
 | 
						|
  //
 | 
						|
  if ((*EcContext = EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey))) != NULL) {
 | 
						|
    Status = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pkey != NULL) {
 | 
						|
    EVP_PKEY_free (Pkey);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the version from one X.509 certificate.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If CertSize is 0, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     Version      Pointer to the retrieved version integer.
 | 
						|
 | 
						|
  @retval TRUE           The certificate version retrieved successfully.
 | 
						|
  @retval FALSE          If  Cert is NULL or CertSize is Zero.
 | 
						|
  @retval FALSE          The operation is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetVersion (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  OUT     UINTN        *Version
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Status;
 | 
						|
  X509     *X509Cert;
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  Status   = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    //
 | 
						|
    // Invalid X.509 Certificate
 | 
						|
    //
 | 
						|
    Status = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status) {
 | 
						|
    *Version = X509_get_version (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the serialNumber from one X.509 certificate.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If CertSize is 0, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     SerialNumber  Pointer to the retrieved certificate SerialNumber bytes.
 | 
						|
  @param[in, out] SerialNumberSize  The size in bytes of the SerialNumber buffer on input,
 | 
						|
                               and the size of buffer returned SerialNumber on output.
 | 
						|
 | 
						|
  @retval TRUE                     The certificate serialNumber retrieved successfully.
 | 
						|
  @retval FALSE                    If Cert is NULL or CertSize is Zero.
 | 
						|
                                   If SerialNumberSize is NULL.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval FALSE                    If no SerialNumber exists.
 | 
						|
  @retval FALSE                    If the SerialNumber is NULL. The required buffer size
 | 
						|
                                   (including the final null) is returned in the
 | 
						|
                                   SerialNumberSize parameter.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetSerialNumber (
 | 
						|
  IN      CONST UINT8 *Cert,
 | 
						|
  IN      UINTN CertSize,
 | 
						|
  OUT     UINT8 *SerialNumber, OPTIONAL
 | 
						|
  IN OUT  UINTN         *SerialNumberSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN       Status;
 | 
						|
  X509          *X509Cert;
 | 
						|
  ASN1_INTEGER  *Asn1Integer;
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (SerialNumberSize == NULL)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    *SerialNumberSize = 0;
 | 
						|
    Status            = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  Asn1Integer = X509_get_serialNumber (X509Cert);
 | 
						|
  if (Asn1Integer == NULL) {
 | 
						|
    *SerialNumberSize = 0;
 | 
						|
    Status            = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (*SerialNumberSize < (UINTN)Asn1Integer->length) {
 | 
						|
    *SerialNumberSize = (UINTN)Asn1Integer->length;
 | 
						|
    Status            = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SerialNumber != NULL) {
 | 
						|
    CopyMem (SerialNumber, Asn1Integer->data, *SerialNumberSize);
 | 
						|
    Status = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  *SerialNumberSize = (UINTN)Asn1Integer->length;
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the issuer bytes from one X.509 certificate.
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If CertIssuerSize is NULL, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     CertIssuer  Pointer to the retrieved certificate subject bytes.
 | 
						|
  @param[in, out] CertIssuerSize  The size in bytes of the CertIssuer buffer on input,
 | 
						|
                               and the size of buffer returned CertSubject on output.
 | 
						|
 | 
						|
  @retval  TRUE   The certificate issuer retrieved successfully.
 | 
						|
  @retval  FALSE  Invalid certificate, or the CertIssuerSize is too small for the result.
 | 
						|
                  The CertIssuerSize will be updated with the required size.
 | 
						|
  @retval  FALSE  This interface is not supported.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetIssuerName (
 | 
						|
  IN      CONST UINT8  *Cert,
 | 
						|
  IN      UINTN        CertSize,
 | 
						|
  OUT     UINT8        *CertIssuer,
 | 
						|
  IN OUT  UINTN        *CertIssuerSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN    Status;
 | 
						|
  X509       *X509Cert;
 | 
						|
  X509_NAME  *X509Name;
 | 
						|
  UINTN      X509NameSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (CertIssuerSize == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  X509Name = X509_get_subject_name (X509Cert);
 | 
						|
  if (X509Name == NULL) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  X509NameSize = i2d_X509_NAME (X509Name, NULL);
 | 
						|
  if (*CertIssuerSize < X509NameSize) {
 | 
						|
    *CertIssuerSize = X509NameSize;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *CertIssuerSize = X509NameSize;
 | 
						|
  if (CertIssuer != NULL) {
 | 
						|
    i2d_X509_NAME (X509Name, &CertIssuer);
 | 
						|
    Status = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Signature Algorithm from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     Oid              Signature Algorithm Object identifier buffer.
 | 
						|
  @param[in,out]  OidSize          Signature Algorithm Object identifier buffer size
 | 
						|
 | 
						|
  @retval TRUE           The certificate Extension data retrieved successfully.
 | 
						|
  @retval FALSE                    If Cert is NULL.
 | 
						|
                                   If OidSize is NULL.
 | 
						|
                                   If Oid is not NULL and *OidSize is 0.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval FALSE                    If no SignatureType.
 | 
						|
  @retval FALSE                    If the Oid is NULL. The required buffer size
 | 
						|
                                   is returned in the OidSize.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetSignatureAlgorithm (
 | 
						|
  IN CONST UINT8 *Cert,
 | 
						|
  IN       UINTN CertSize,
 | 
						|
  OUT   UINT8 *Oid, OPTIONAL
 | 
						|
  IN OUT   UINTN       *OidSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN      Status;
 | 
						|
  X509         *X509Cert;
 | 
						|
  int          Nid;
 | 
						|
  ASN1_OBJECT  *Asn1Obj;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (OidSize == NULL) || (CertSize == 0)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  Status   = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  Nid = X509_get_signature_nid (X509Cert);
 | 
						|
  if (Nid == NID_undef) {
 | 
						|
    *OidSize = 0;
 | 
						|
    Status   = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Asn1Obj = OBJ_nid2obj (Nid);
 | 
						|
  if (Asn1Obj == NULL) {
 | 
						|
    *OidSize = 0;
 | 
						|
    Status   = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (*OidSize < (UINTN)Asn1Obj->length) {
 | 
						|
    *OidSize = Asn1Obj->length;
 | 
						|
    Status   = FALSE;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Oid != NULL) {
 | 
						|
    CopyMem (Oid, Asn1Obj->data, Asn1Obj->length);
 | 
						|
  }
 | 
						|
 | 
						|
  *OidSize = Asn1Obj->length;
 | 
						|
  Status   = TRUE;
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve Extension data from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[in]      Oid              Object identifier buffer
 | 
						|
  @param[in]      OidSize          Object identifier buffer size
 | 
						|
  @param[out]     ExtensionData    Extension bytes.
 | 
						|
  @param[in, out] ExtensionDataSize Extension bytes size.
 | 
						|
 | 
						|
  @retval TRUE                     The certificate Extension data retrieved successfully.
 | 
						|
  @retval FALSE                    If Cert is NULL.
 | 
						|
                                   If ExtensionDataSize is NULL.
 | 
						|
                                   If ExtensionData is not NULL and *ExtensionDataSize is 0.
 | 
						|
                                   If Certificate is invalid.
 | 
						|
  @retval FALSE                    If no Extension entry match Oid.
 | 
						|
  @retval FALSE                    If the ExtensionData is NULL. The required buffer size
 | 
						|
                                   is returned in the ExtensionDataSize parameter.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetExtensionData (
 | 
						|
  IN     CONST UINT8  *Cert,
 | 
						|
  IN     UINTN        CertSize,
 | 
						|
  IN     CONST UINT8  *Oid,
 | 
						|
  IN     UINTN        OidSize,
 | 
						|
  OUT UINT8           *ExtensionData,
 | 
						|
  IN OUT UINTN        *ExtensionDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Status;
 | 
						|
  INTN     i;
 | 
						|
  X509     *X509Cert;
 | 
						|
 | 
						|
  CONST STACK_OF (X509_EXTENSION) *Extensions;
 | 
						|
  ASN1_OBJECT        *Asn1Obj;
 | 
						|
  ASN1_OCTET_STRING  *Asn1Oct;
 | 
						|
  X509_EXTENSION     *Ext;
 | 
						|
  UINTN              ObjLength;
 | 
						|
  UINTN              OctLength;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (CertSize == 0) || (Oid == NULL) || (OidSize == 0) || (ExtensionDataSize == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  Status   = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    *ExtensionDataSize = 0;
 | 
						|
    goto Cleanup;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve Extensions from certificate object.
 | 
						|
  //
 | 
						|
  Extensions = X509_get0_extensions (X509Cert);
 | 
						|
  if (sk_X509_EXTENSION_num (Extensions) <= 0) {
 | 
						|
    *ExtensionDataSize = 0;
 | 
						|
    goto Cleanup;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Traverse Extensions
 | 
						|
  //
 | 
						|
  Status    = FALSE;
 | 
						|
  Asn1Oct   = NULL;
 | 
						|
  OctLength = 0;
 | 
						|
  for (i = 0; i < sk_X509_EXTENSION_num (Extensions); i++) {
 | 
						|
    Ext = sk_X509_EXTENSION_value (Extensions, (int)i);
 | 
						|
    if (Ext == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Asn1Obj = X509_EXTENSION_get_object (Ext);
 | 
						|
    if (Asn1Obj == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    Asn1Oct = X509_EXTENSION_get_data (Ext);
 | 
						|
    if (Asn1Oct == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    ObjLength = OBJ_length (Asn1Obj);
 | 
						|
    OctLength = ASN1_STRING_length (Asn1Oct);
 | 
						|
    if ((OidSize == ObjLength) && (CompareMem (OBJ_get0_data (Asn1Obj), Oid, OidSize) == 0)) {
 | 
						|
      //
 | 
						|
      // Extension Found
 | 
						|
      //
 | 
						|
      Status = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // reset to 0 if not found
 | 
						|
    //
 | 
						|
    OctLength = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Status) {
 | 
						|
    if (*ExtensionDataSize < OctLength) {
 | 
						|
      *ExtensionDataSize = OctLength;
 | 
						|
      Status             = FALSE;
 | 
						|
      goto Cleanup;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Asn1Oct != NULL) {
 | 
						|
      CopyMem (ExtensionData, ASN1_STRING_get0_data (Asn1Oct), OctLength);
 | 
						|
    }
 | 
						|
 | 
						|
    *ExtensionDataSize = OctLength;
 | 
						|
  } else {
 | 
						|
    *ExtensionDataSize = 0;
 | 
						|
  }
 | 
						|
 | 
						|
Cleanup:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Extended Key Usage from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     Usage            Key Usage bytes.
 | 
						|
  @param[in, out] UsageSize        Key Usage buffer sizs in bytes.
 | 
						|
 | 
						|
  @retval TRUE                     The Usage bytes retrieve successfully.
 | 
						|
  @retval FALSE                    If Cert is NULL.
 | 
						|
                                   If CertSize is NULL.
 | 
						|
                                   If Usage is not NULL and *UsageSize is 0.
 | 
						|
                                   If Cert is invalid.
 | 
						|
  @retval FALSE                    If the Usage is NULL. The required buffer size
 | 
						|
                                   is returned in the UsageSize parameter.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetExtendedKeyUsage (
 | 
						|
  IN     CONST UINT8  *Cert,
 | 
						|
  IN     UINTN        CertSize,
 | 
						|
  OUT UINT8           *Usage,
 | 
						|
  IN OUT UINTN        *UsageSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Status;
 | 
						|
 | 
						|
  Status = X509GetExtensionData (Cert, CertSize, mOidExtKeyUsage, sizeof (mOidExtKeyUsage), Usage, UsageSize);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Validity from one X.509 certificate
 | 
						|
 | 
						|
  If Cert is NULL, then return FALSE.
 | 
						|
  If CertIssuerSize is NULL, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize     Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     From         notBefore Pointer to DateTime object.
 | 
						|
  @param[in,out]  FromSize     notBefore DateTime object size.
 | 
						|
  @param[out]     To           notAfter Pointer to DateTime object.
 | 
						|
  @param[in,out]  ToSize       notAfter DateTime object size.
 | 
						|
 | 
						|
  Note: X509CompareDateTime to compare DateTime oject
 | 
						|
        x509SetDateTime to get a DateTime object from a DateTimeStr
 | 
						|
 | 
						|
  @retval  TRUE   The certificate Validity retrieved successfully.
 | 
						|
  @retval  FALSE  Invalid certificate, or Validity retrieve failed.
 | 
						|
  @retval  FALSE  This interface is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetValidity  (
 | 
						|
  IN     CONST UINT8  *Cert,
 | 
						|
  IN     UINTN        CertSize,
 | 
						|
  IN     UINT8        *From,
 | 
						|
  IN OUT UINTN        *FromSize,
 | 
						|
  IN     UINT8        *To,
 | 
						|
  IN OUT UINTN        *ToSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN          Status;
 | 
						|
  X509             *X509Cert;
 | 
						|
  CONST ASN1_TIME  *F;
 | 
						|
  CONST ASN1_TIME  *T;
 | 
						|
  UINTN            TSize;
 | 
						|
  UINTN            FSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (FromSize == NULL) || (ToSize == NULL) || (CertSize == 0)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  Status   = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve Validity from/to from certificate object.
 | 
						|
  //
 | 
						|
  F = X509_get0_notBefore (X509Cert);
 | 
						|
  T = X509_get0_notAfter (X509Cert);
 | 
						|
 | 
						|
  if ((F == NULL) || (T == NULL)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  FSize = sizeof (ASN1_TIME) + F->length;
 | 
						|
  if (*FromSize < FSize) {
 | 
						|
    *FromSize = FSize;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *FromSize = FSize;
 | 
						|
  if (From != NULL) {
 | 
						|
    CopyMem (From, F, sizeof (ASN1_TIME));
 | 
						|
    ((ASN1_TIME *)From)->data = From + sizeof (ASN1_TIME);
 | 
						|
    CopyMem (From + sizeof (ASN1_TIME), F->data, F->length);
 | 
						|
  }
 | 
						|
 | 
						|
  TSize = sizeof (ASN1_TIME) + T->length;
 | 
						|
  if (*ToSize < TSize) {
 | 
						|
    *ToSize = TSize;
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  *ToSize = TSize;
 | 
						|
  if (To != NULL) {
 | 
						|
    CopyMem (To, T, sizeof (ASN1_TIME));
 | 
						|
    ((ASN1_TIME *)To)->data = To + sizeof (ASN1_TIME);
 | 
						|
    CopyMem (To + sizeof (ASN1_TIME), T->data, T->length);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = TRUE;
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Format a DateTimeStr to DataTime object in DataTime Buffer
 | 
						|
 | 
						|
  If DateTimeStr is NULL, then return FALSE.
 | 
						|
  If DateTimeSize is NULL, then return FALSE.
 | 
						|
  If this interface is not supported, then return FALSE.
 | 
						|
 | 
						|
  @param[in]      DateTimeStr      DateTime string like YYYYMMDDhhmmssZ
 | 
						|
                                   Ref: https://www.w3.org/TR/NOTE-datetime
 | 
						|
                                   Z stand for UTC time
 | 
						|
  @param[out]     DateTime         Pointer to a DateTime object.
 | 
						|
  @param[in,out]  DateTimeSize     DateTime object buffer size.
 | 
						|
 | 
						|
  @retval TRUE                     The DateTime object create successfully.
 | 
						|
  @retval FALSE                    If DateTimeStr is NULL.
 | 
						|
                                   If DateTimeSize is NULL.
 | 
						|
                                   If DateTime is not NULL and *DateTimeSize is 0.
 | 
						|
                                   If Year Month Day Hour Minute Second combination is invalid datetime.
 | 
						|
  @retval FALSE                    If the DateTime is NULL. The required buffer size
 | 
						|
                                   (including the final null) is returned in the
 | 
						|
                                   DateTimeSize parameter.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509FormatDateTime (
 | 
						|
  IN  CONST  CHAR8  *DateTimeStr,
 | 
						|
  OUT VOID          *DateTime,
 | 
						|
  IN OUT UINTN      *DateTimeSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN    Status;
 | 
						|
  INT32      Ret;
 | 
						|
  ASN1_TIME  *Dt;
 | 
						|
  UINTN      DSize;
 | 
						|
 | 
						|
  Dt     = NULL;
 | 
						|
  Status = FALSE;
 | 
						|
 | 
						|
  Dt = ASN1_TIME_new ();
 | 
						|
  if (Dt == NULL) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto Cleanup;
 | 
						|
  }
 | 
						|
 | 
						|
  Ret = ASN1_TIME_set_string_X509 (Dt, DateTimeStr);
 | 
						|
  if (Ret != 1) {
 | 
						|
    Status = FALSE;
 | 
						|
    goto Cleanup;
 | 
						|
  }
 | 
						|
 | 
						|
  DSize = sizeof (ASN1_TIME) + Dt->length;
 | 
						|
  if (*DateTimeSize < DSize) {
 | 
						|
    *DateTimeSize = DSize;
 | 
						|
    Status        = FALSE;
 | 
						|
    goto Cleanup;
 | 
						|
  }
 | 
						|
 | 
						|
  *DateTimeSize = DSize;
 | 
						|
  if (DateTime != NULL) {
 | 
						|
    CopyMem (DateTime, Dt, sizeof (ASN1_TIME));
 | 
						|
    ((ASN1_TIME *)DateTime)->data = (UINT8 *)DateTime + sizeof (ASN1_TIME);
 | 
						|
    CopyMem ((UINT8 *)DateTime + sizeof (ASN1_TIME), Dt->data, Dt->length);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = TRUE;
 | 
						|
 | 
						|
Cleanup:
 | 
						|
  if (Dt != NULL) {
 | 
						|
    ASN1_TIME_free (Dt);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare DateTime1 object and DateTime2 object.
 | 
						|
 | 
						|
  If DateTime1 is NULL, then return -2.
 | 
						|
  If DateTime2 is NULL, then return -2.
 | 
						|
  If DateTime1 == DateTime2, then return 0
 | 
						|
  If DateTime1 > DateTime2, then return 1
 | 
						|
  If DateTime1 < DateTime2, then return -1
 | 
						|
 | 
						|
  @param[in]      DateTime1         Pointer to a DateTime Ojbect
 | 
						|
  @param[in]      DateTime2         Pointer to a DateTime Object
 | 
						|
 | 
						|
  @retval  0      If DateTime1 == DateTime2
 | 
						|
  @retval  1      If DateTime1 > DateTime2
 | 
						|
  @retval  -1     If DateTime1 < DateTime2
 | 
						|
**/
 | 
						|
INT32
 | 
						|
EFIAPI
 | 
						|
X509CompareDateTime (
 | 
						|
  IN CONST  VOID  *DateTime1,
 | 
						|
  IN CONST  VOID  *DateTime2
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (INT32)ASN1_TIME_compare (DateTime1, DateTime2);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Key Usage from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize         Size of the X509 certificate in bytes.
 | 
						|
  @param[out]     Usage            Key Usage (CRYPTO_X509_KU_*)
 | 
						|
 | 
						|
  @retval  TRUE   The certificate Key Usage retrieved successfully.
 | 
						|
  @retval  FALSE  Invalid certificate, or Usage is NULL
 | 
						|
  @retval  FALSE  This interface is not supported.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetKeyUsage (
 | 
						|
  IN    CONST UINT8  *Cert,
 | 
						|
  IN    UINTN        CertSize,
 | 
						|
  OUT   UINTN        *Usage
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Status;
 | 
						|
  X509     *X509Cert;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((Cert == NULL) || (Usage == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  X509Cert = NULL;
 | 
						|
  Status   = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read DER-encoded X509 Certificate and Construct X509 object.
 | 
						|
  //
 | 
						|
  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
 | 
						|
  if ((X509Cert == NULL) || (!Status)) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve subject name from certificate object.
 | 
						|
  //
 | 
						|
  *Usage = X509_get_key_usage (X509Cert);
 | 
						|
  if (*Usage == NID_undef) {
 | 
						|
    goto _Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = TRUE;
 | 
						|
 | 
						|
_Exit:
 | 
						|
  //
 | 
						|
  // Release Resources.
 | 
						|
  //
 | 
						|
  if (X509Cert != NULL) {
 | 
						|
    X509_free (X509Cert);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Verify one X509 certificate was issued by the trusted CA.
 | 
						|
  @param[in]      RootCert          Trusted Root Certificate buffer
 | 
						|
 | 
						|
  @param[in]      RootCertLength    Trusted Root Certificate buffer length
 | 
						|
  @param[in]      CertChain         One or more ASN.1 DER-encoded X.509 certificates
 | 
						|
                                    where the first certificate is signed by the Root
 | 
						|
                                    Certificate or is the Root Cerificate itself. and
 | 
						|
                                    subsequent cerificate is signed by the preceding
 | 
						|
                                    cerificate.
 | 
						|
  @param[in]      CertChainLength   Total length of the certificate chain, in bytes.
 | 
						|
 | 
						|
  @retval  TRUE   All cerificates was issued by the first certificate in X509Certchain.
 | 
						|
  @retval  FALSE  Invalid certificate or the certificate was not issued by the given
 | 
						|
                  trusted CA.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509VerifyCertChain (
 | 
						|
  IN CONST UINT8  *RootCert,
 | 
						|
  IN UINTN        RootCertLength,
 | 
						|
  IN CONST UINT8  *CertChain,
 | 
						|
  IN UINTN        CertChainLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  CONST UINT8  *TmpPtr;
 | 
						|
  UINTN        Length;
 | 
						|
  UINT32       Asn1Tag;
 | 
						|
  UINT32       ObjClass;
 | 
						|
  CONST UINT8  *CurrentCert;
 | 
						|
  UINTN        CurrentCertLen;
 | 
						|
  CONST UINT8  *PrecedingCert;
 | 
						|
  UINTN        PrecedingCertLen;
 | 
						|
  BOOLEAN      VerifyFlag;
 | 
						|
  INT32        Ret;
 | 
						|
 | 
						|
  PrecedingCert    = RootCert;
 | 
						|
  PrecedingCertLen = RootCertLength;
 | 
						|
 | 
						|
  CurrentCert    = CertChain;
 | 
						|
  Length         = 0;
 | 
						|
  CurrentCertLen = 0;
 | 
						|
 | 
						|
  VerifyFlag = FALSE;
 | 
						|
  while (TRUE) {
 | 
						|
    TmpPtr = CurrentCert;
 | 
						|
    Ret    = ASN1_get_object (
 | 
						|
               (CONST UINT8 **)&TmpPtr,
 | 
						|
               (long *)&Length,
 | 
						|
               (int *)&Asn1Tag,
 | 
						|
               (int *)&ObjClass,
 | 
						|
               (long)(CertChainLength + CertChain - TmpPtr)
 | 
						|
               );
 | 
						|
    if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Calculate CurrentCert length;
 | 
						|
    //
 | 
						|
    CurrentCertLen = TmpPtr - CurrentCert + Length;
 | 
						|
 | 
						|
    //
 | 
						|
    // Verify CurrentCert with preceding cert;
 | 
						|
    //
 | 
						|
    VerifyFlag = X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen);
 | 
						|
    if (VerifyFlag == FALSE) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // move Current cert to Preceding cert
 | 
						|
    //
 | 
						|
    PrecedingCertLen = CurrentCertLen;
 | 
						|
    PrecedingCert    = CurrentCert;
 | 
						|
 | 
						|
    //
 | 
						|
    // Move to next
 | 
						|
    //
 | 
						|
    CurrentCert = CurrentCert + CurrentCertLen;
 | 
						|
  }
 | 
						|
 | 
						|
  return VerifyFlag;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get one X509 certificate from CertChain.
 | 
						|
 | 
						|
  @param[in]      CertChain         One or more ASN.1 DER-encoded X.509 certificates
 | 
						|
                                    where the first certificate is signed by the Root
 | 
						|
                                    Certificate or is the Root Cerificate itself. and
 | 
						|
                                    subsequent cerificate is signed by the preceding
 | 
						|
                                    cerificate.
 | 
						|
  @param[in]      CertChainLength   Total length of the certificate chain, in bytes.
 | 
						|
 | 
						|
  @param[in]      CertIndex         Index of certificate.
 | 
						|
 | 
						|
  @param[out]     Cert              The certificate at the index of CertChain.
 | 
						|
  @param[out]     CertLength        The length certificate at the index of CertChain.
 | 
						|
 | 
						|
  @retval  TRUE   Success.
 | 
						|
  @retval  FALSE  Failed to get certificate from certificate chain.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetCertFromCertChain (
 | 
						|
  IN CONST UINT8   *CertChain,
 | 
						|
  IN UINTN         CertChainLength,
 | 
						|
  IN CONST INT32   CertIndex,
 | 
						|
  OUT CONST UINT8  **Cert,
 | 
						|
  OUT UINTN        *CertLength
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN        Asn1Len;
 | 
						|
  INT32        CurrentIndex;
 | 
						|
  UINTN        CurrentCertLen;
 | 
						|
  CONST UINT8  *CurrentCert;
 | 
						|
  CONST UINT8  *TmpPtr;
 | 
						|
  INT32        Ret;
 | 
						|
  UINT32       Asn1Tag;
 | 
						|
  UINT32       ObjClass;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if ((CertChain == NULL) || (Cert == NULL) ||
 | 
						|
      (CertIndex < -1) || (CertLength == NULL))
 | 
						|
  {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Asn1Len        = 0;
 | 
						|
  CurrentCertLen = 0;
 | 
						|
  CurrentCert    = CertChain;
 | 
						|
  CurrentIndex   = -1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Traverse the certificate chain
 | 
						|
  //
 | 
						|
  while (TRUE) {
 | 
						|
    TmpPtr = CurrentCert;
 | 
						|
 | 
						|
    // Get asn1 object and taglen
 | 
						|
    Ret = ASN1_get_object (
 | 
						|
            (CONST UINT8 **)&TmpPtr,
 | 
						|
            (long *)&Asn1Len,
 | 
						|
            (int *)&Asn1Tag,
 | 
						|
            (int *)&ObjClass,
 | 
						|
            (long)(CertChainLength + CertChain - TmpPtr)
 | 
						|
            );
 | 
						|
    if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Calculate CurrentCert length;
 | 
						|
    //
 | 
						|
    CurrentCertLen = TmpPtr - CurrentCert + Asn1Len;
 | 
						|
    CurrentIndex++;
 | 
						|
 | 
						|
    if (CurrentIndex == CertIndex) {
 | 
						|
      *Cert       = CurrentCert;
 | 
						|
      *CertLength = CurrentCertLen;
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Move to next
 | 
						|
    //
 | 
						|
    CurrentCert = CurrentCert + CurrentCertLen;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If CertIndex is -1, Return the last certificate
 | 
						|
  //
 | 
						|
  if ((CertIndex == -1) && (CurrentIndex >= 0)) {
 | 
						|
    *Cert       = CurrentCert - CurrentCertLen;
 | 
						|
    *CertLength = CurrentCertLen;
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the tag and length of the tag.
 | 
						|
 | 
						|
  @param Ptr      The position in the ASN.1 data
 | 
						|
  @param End      End of data
 | 
						|
  @param Length   The variable that will receive the length
 | 
						|
  @param Tag      The expected tag
 | 
						|
 | 
						|
  @retval      TRUE   Get tag successful
 | 
						|
  @retval      FALSe  Failed to get tag or tag not match
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
Asn1GetTag (
 | 
						|
  IN OUT UINT8    **Ptr,
 | 
						|
  IN CONST UINT8  *End,
 | 
						|
  OUT UINTN       *Length,
 | 
						|
  IN     UINT32   Tag
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   *PtrOld;
 | 
						|
  INT32   ObjTag;
 | 
						|
  INT32   ObjCls;
 | 
						|
  long    ObjLength;
 | 
						|
  UINT32  Inf;
 | 
						|
 | 
						|
  //
 | 
						|
  // Save Ptr position
 | 
						|
  //
 | 
						|
  PtrOld = *Ptr;
 | 
						|
 | 
						|
  Inf = ASN1_get_object ((CONST UINT8 **)Ptr, &ObjLength, &ObjTag, &ObjCls, (INT32)(End - (*Ptr)));
 | 
						|
  if (((Inf & 0x80) == 0x00) &&
 | 
						|
      (ObjTag == (INT32)(Tag & CRYPTO_ASN1_TAG_VALUE_MASK)) &&
 | 
						|
      (ObjCls == (INT32)(Tag & CRYPTO_ASN1_TAG_CLASS_MASK)))
 | 
						|
  {
 | 
						|
    *Length = (UINTN)ObjLength;
 | 
						|
    return TRUE;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // if doesn't match Tag, restore Ptr to origin Ptr
 | 
						|
    //
 | 
						|
    *Ptr = PtrOld;
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the basic constraints from one X.509 certificate.
 | 
						|
 | 
						|
  @param[in]      Cert                     Pointer to the DER-encoded X509 certificate.
 | 
						|
  @param[in]      CertSize                 size of the X509 certificate in bytes.
 | 
						|
  @param[out]     BasicConstraints         basic constraints bytes.
 | 
						|
  @param[in, out] BasicConstraintsSize     basic constraints buffer sizs in bytes.
 | 
						|
 | 
						|
  @retval TRUE                     The basic constraints retrieve successfully.
 | 
						|
  @retval FALSE                    If cert is NULL.
 | 
						|
                                   If cert_size is NULL.
 | 
						|
                                   If basic_constraints is not NULL and *basic_constraints_size is 0.
 | 
						|
                                   If cert is invalid.
 | 
						|
  @retval FALSE                    The required buffer size is small.
 | 
						|
                                   The return buffer size is basic_constraints_size parameter.
 | 
						|
  @retval FALSE                    If no Extension entry match oid.
 | 
						|
  @retval FALSE                    The operation is not supported.
 | 
						|
 **/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
X509GetExtendedBasicConstraints             (
 | 
						|
  CONST UINT8  *Cert,
 | 
						|
  UINTN        CertSize,
 | 
						|
  UINT8        *BasicConstraints,
 | 
						|
  UINTN        *BasicConstraintsSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Status;
 | 
						|
 | 
						|
  if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = X509GetExtensionData (
 | 
						|
             (UINT8 *)Cert,
 | 
						|
             CertSize,
 | 
						|
             mOidBasicConstraints,
 | 
						|
             sizeof (mOidBasicConstraints),
 | 
						|
             BasicConstraints,
 | 
						|
             BasicConstraintsSize
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |