]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptX509.c
index 75337ed32bbc21ed0034078e79e0ba96980c6b41..2333157e0d17e13d3ae7f1146e73d691c68a5d2f 100644 (file)
@@ -1,21 +1,29 @@
 /** @file\r
   X.509 Certificate Handler Wrapper Implementation over OpenSSL.\r
 \r
-Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "InternalCryptLib.h"\r
 #include <openssl/x509.h>\r
+#include <openssl/x509v3.h>\r
+#include <crypto/asn1.h>\r
+#include <openssl/asn1.h>\r
 #include <openssl/rsa.h>\r
 \r
+/* OID*/\r
+#define OID_EXT_KEY_USAGE      { 0x55, 0x1D, 0x25 }\r
+#define OID_BASIC_CONSTRAINTS  { 0x55, 0x1D, 0x13 }\r
+\r
+static CONST UINT8  mOidExtKeyUsage[]      = OID_EXT_KEY_USAGE;\r
+static CONST UINT8  mOidBasicConstraints[] = OID_BASIC_CONSTRAINTS;\r
+\r
+#define CRYPTO_ASN1_TAG_CLASS_MASK  0xC0\r
+#define CRYPTO_ASN1_TAG_PC_MASK     0x20\r
+#define CRYPTO_ASN1_TAG_VALUE_MASK  0x1F\r
+\r
 /**\r
   Construct a X509 object from DER-encoded certificate data.\r
 \r
@@ -44,7 +52,7 @@ X509ConstructCertificate (
   //\r
   // Check input parameters.\r
   //\r
-  if (Cert == NULL || SingleX509Cert == NULL || CertSize > INT_MAX) {\r
+  if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize > INT_MAX)) {\r
     return FALSE;\r
   }\r
 \r
@@ -52,12 +60,12 @@ X509ConstructCertificate (
   // Read DER-encoded X509 Certificate and Construct X509 object.\r
   //\r
   Temp     = Cert;\r
-  X509Cert = d2i_X509 (NULL, &Temp, (long) CertSize);\r
+  X509Cert = d2i_X509 (NULL, &Temp, (long)CertSize);\r
   if (X509Cert == NULL) {\r
     return FALSE;\r
   }\r
 \r
-  *SingleX509Cert = (UINT8 *) X509Cert;\r
+  *SingleX509Cert = (UINT8 *)X509Cert;\r
 \r
   return TRUE;\r
 }\r
@@ -66,32 +74,35 @@ X509ConstructCertificate (
   Construct a X509 stack object from a list of DER-encoded certificate data.\r
 \r
   If X509Stack is NULL, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
 \r
   @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.\r
                               On output, pointer to the X509 stack object with new\r
                               inserted X509 certificate.\r
-  @param           ...        A list of DER-encoded single certificate data followed\r
+  @param[in]       Args       VA_LIST marker for the variable argument list.\r
+                              A list of DER-encoded single certificate data followed\r
                               by certificate size. A NULL terminates the list. The\r
                               pairs are the arguments to X509ConstructCertificate().\r
 \r
   @retval     TRUE            The X509 stack construction succeeded.\r
   @retval     FALSE           The construction operation failed.\r
+  @retval     FALSE           This interface is not supported.\r
 \r
 **/\r
 BOOLEAN\r
 EFIAPI\r
-X509ConstructCertificateStack (\r
-  IN OUT  UINT8  **X509Stack,\r
-  ...\r
+X509ConstructCertificateStackV (\r
+  IN OUT  UINT8    **X509Stack,\r
+  IN      VA_LIST  Args\r
   )\r
 {\r
-  UINT8           *Cert;\r
-  UINTN           CertSize;\r
-  X509            *X509Cert;\r
-  STACK_OF(X509)  *CertStack;\r
-  BOOLEAN         Status;\r
-  VA_LIST         Args;\r
-  UINTN           Index;\r
+  UINT8  *Cert;\r
+  UINTN  CertSize;\r
+  X509   *X509Cert;\r
+\r
+  STACK_OF (X509)  *CertStack;\r
+  BOOLEAN  Status;\r
+  UINTN    Index;\r
 \r
   //\r
   // Check input parameters.\r
@@ -105,7 +116,7 @@ X509ConstructCertificateStack (
   //\r
   // Initialize X509 stack object.\r
   //\r
-  CertStack = (STACK_OF(X509) *) (*X509Stack);\r
+  CertStack = (STACK_OF (X509) *)(*X509Stack);\r
   if (CertStack == NULL) {\r
     CertStack = sk_X509_new_null ();\r
     if (CertStack == NULL) {\r
@@ -113,8 +124,6 @@ X509ConstructCertificateStack (
     }\r
   }\r
 \r
-  VA_START (Args, X509Stack);\r
-\r
   for (Index = 0; ; Index++) {\r
     //\r
     // If Cert is NULL, then it is the end of the list.\r
@@ -133,15 +142,16 @@ X509ConstructCertificateStack (
     // Construct X509 Object from the given DER-encoded certificate data.\r
     //\r
     X509Cert = NULL;\r
-    Status = X509ConstructCertificate (\r
-               (CONST UINT8 *) Cert,\r
-               CertSize,\r
-               (UINT8 **) &X509Cert\r
-               );\r
+    Status   = X509ConstructCertificate (\r
+                 (CONST UINT8 *)Cert,\r
+                 CertSize,\r
+                 (UINT8 **)&X509Cert\r
+                 );\r
     if (!Status) {\r
       if (X509Cert != NULL) {\r
         X509_free (X509Cert);\r
       }\r
+\r
       break;\r
     }\r
 \r
@@ -151,17 +161,47 @@ X509ConstructCertificateStack (
     sk_X509_push (CertStack, X509Cert);\r
   }\r
 \r
-  VA_END (Args);\r
-\r
   if (!Status) {\r
     sk_X509_pop_free (CertStack, X509_free);\r
   } else {\r
-    *X509Stack = (UINT8 *) CertStack;\r
+    *X509Stack = (UINT8 *)CertStack;\r
   }\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Construct a X509 stack object from a list of DER-encoded certificate data.\r
+\r
+  If X509Stack is NULL, then return FALSE.\r
+\r
+  @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.\r
+                              On output, pointer to the X509 stack object with new\r
+                              inserted X509 certificate.\r
+  @param           ...        A list of DER-encoded single certificate data followed\r
+                              by certificate size. A NULL terminates the list. The\r
+                              pairs are the arguments to X509ConstructCertificate().\r
+\r
+  @retval     TRUE            The X509 stack construction succeeded.\r
+  @retval     FALSE           The construction operation failed.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509ConstructCertificateStack (\r
+  IN OUT  UINT8  **X509Stack,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST  Args;\r
+  BOOLEAN  Result;\r
+\r
+  VA_START (Args, X509Stack);\r
+  Result = X509ConstructCertificateStackV (X509Stack, Args);\r
+  VA_END (Args);\r
+  return Result;\r
+}\r
+\r
 /**\r
   Release the specified X509 object.\r
 \r
@@ -186,7 +226,7 @@ X509Free (
   //\r
   // Free OpenSSL X509 object.\r
   //\r
-  X509_free ((X509 *) X509Cert);\r
+  X509_free ((X509 *)X509Cert);\r
 }\r
 \r
 /**\r
@@ -213,7 +253,7 @@ X509StackFree (
   //\r
   // Free OpenSSL X509 stack object.\r
   //\r
-  sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free);\r
+  sk_X509_pop_free ((STACK_OF (X509) *) X509Stack, X509_free);\r
 }\r
 \r
 /**\r
@@ -250,7 +290,7 @@ X509GetSubjectName (
   //\r
   // Check input parameters.\r
   //\r
-  if (Cert == NULL || SubjectSize == NULL) {\r
+  if ((Cert == NULL) || (SubjectSize == NULL)) {\r
     return FALSE;\r
   }\r
 \r
@@ -259,7 +299,7 @@ X509GetSubjectName (
   //\r
   // Read DER-encoded X509 Certificate and Construct X509 object.\r
   //\r
-  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
   if ((X509Cert == NULL) || (!Status)) {\r
     Status = FALSE;\r
     goto _Exit;\r
@@ -275,14 +315,15 @@ X509GetSubjectName (
     goto _Exit;\r
   }\r
 \r
-  X509NameSize = i2d_X509_NAME(X509Name, NULL);\r
+  X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
   if (*SubjectSize < X509NameSize) {\r
     *SubjectSize = X509NameSize;\r
     goto _Exit;\r
   }\r
+\r
   *SubjectSize = X509NameSize;\r
   if (CertSubject != NULL) {\r
-    i2d_X509_NAME(X509Name, &CertSubject);\r
+    i2d_X509_NAME (X509Name, &CertSubject);\r
     Status = TRUE;\r
   }\r
 \r
@@ -298,10 +339,11 @@ _Exit:
 }\r
 \r
 /**\r
-  Retrieve the common name (CN) string from one X.509 certificate.\r
+  Retrieve a string from one X.509 certificate base on the Request_NID.\r
 \r
   @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
   @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[in]      Request_NID      NID of string to obtain\r
   @param[out]     CommonName       Buffer to contain the retrieved certificate common\r
                                    name string (UTF8). At most CommonNameSize bytes will be\r
                                    written and the string will be null terminated. May be\r
@@ -316,19 +358,20 @@ _Exit:
                                    If CommonNameSize is NULL.\r
                                    If CommonName is not NULL and *CommonNameSize is 0.\r
                                    If Certificate is invalid.\r
-  @retval RETURN_NOT_FOUND         If no CommonName entry exists.\r
+  @retval RETURN_NOT_FOUND         If no NID Name entry exists.\r
   @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size\r
                                    (including the final null) is returned in the\r
                                    CommonNameSize parameter.\r
   @retval RETURN_UNSUPPORTED       The operation is not supported.\r
 \r
 **/\r
+STATIC\r
 RETURN_STATUS\r
-EFIAPI\r
-X509GetCommonName (\r
+InternalX509GetNIDName (\r
   IN      CONST UINT8  *Cert,\r
   IN      UINTN        CertSize,\r
-  OUT     CHAR8        *CommonName,  OPTIONAL\r
+  IN      INT32        Request_NID,\r
+  OUT     CHAR8        *CommonName   OPTIONAL,\r
   IN OUT  UINTN        *CommonNameSize\r
   )\r
 {\r
@@ -351,6 +394,7 @@ X509GetCommonName (
   if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {\r
     return ReturnStatus;\r
   }\r
+\r
   if ((CommonName != NULL) && (*CommonNameSize == 0)) {\r
     return ReturnStatus;\r
   }\r
@@ -359,7 +403,7 @@ X509GetCommonName (
   //\r
   // Read DER-encoded X509 Certificate and Construct X509 object.\r
   //\r
-  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
   if ((X509Cert == NULL) || (!Status)) {\r
     //\r
     // Invalid X.509 Certificate\r
@@ -381,12 +425,12 @@ X509GetCommonName (
   }\r
 \r
   //\r
-  // Retrieve the CommonName information from X.509 Subject\r
+  // Retrive the string from X.509 Subject base on the Request_NID\r
   //\r
-  Index = X509_NAME_get_index_by_NID (X509Name, NID_commonName, -1);\r
+  Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);\r
   if (Index < 0) {\r
     //\r
-    // No CommonName entry exists in X509_NAME object\r
+    // No Request_NID name entry exists in X509_NAME object\r
     //\r
     *CommonNameSize = 0;\r
     ReturnStatus    = RETURN_NOT_FOUND;\r
@@ -408,7 +452,7 @@ X509GetCommonName (
   Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);\r
   if (Length < 0) {\r
     //\r
-    // Fail to convert the commonName string\r
+    // Fail to convert the Name string\r
     //\r
     *CommonNameSize = 0;\r
     ReturnStatus    = RETURN_INVALID_PARAMETER;\r
@@ -417,12 +461,12 @@ X509GetCommonName (
 \r
   if (CommonName == NULL) {\r
     *CommonNameSize = Length + 1;\r
-    ReturnStatus = RETURN_BUFFER_TOO_SMALL;\r
+    ReturnStatus    = RETURN_BUFFER_TOO_SMALL;\r
   } else {\r
     *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;\r
     CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);\r
     CommonName[*CommonNameSize - 1] = '\0';\r
-    ReturnStatus = RETURN_SUCCESS;\r
+    ReturnStatus                    = RETURN_SUCCESS;\r
   }\r
 \r
 _Exit:\r
@@ -432,6 +476,7 @@ _Exit:
   if (X509Cert != NULL) {\r
     X509_free (X509Cert);\r
   }\r
+\r
   if (UTF8Name != NULL) {\r
     OPENSSL_free (UTF8Name);\r
   }\r
@@ -439,6 +484,82 @@ _Exit:
   return ReturnStatus;\r
 }\r
 \r
+/**\r
+  Retrieve the common name (CN) string from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[out]     CommonName       Buffer to contain the retrieved certificate common\r
+                                   name string. At most CommonNameSize bytes will be\r
+                                   written and the string will be null terminated. May be\r
+                                   NULL in order to determine the size buffer needed.\r
+  @param[in,out]  CommonNameSize   The size in bytes of the CommonName buffer on input,\r
+                                   and the size of buffer returned CommonName on output.\r
+                                   If CommonName is NULL then the amount of space needed\r
+                                   in buffer (including the final null) is returned.\r
+\r
+  @retval RETURN_SUCCESS           The certificate CommonName retrieved successfully.\r
+  @retval RETURN_INVALID_PARAMETER If Cert is NULL.\r
+                                   If CommonNameSize is NULL.\r
+                                   If CommonName is not NULL and *CommonNameSize is 0.\r
+                                   If Certificate is invalid.\r
+  @retval RETURN_NOT_FOUND         If no CommonName entry exists.\r
+  @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size\r
+                                   (including the final null) is returned in the\r
+                                   CommonNameSize parameter.\r
+  @retval RETURN_UNSUPPORTED       The operation is not supported.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+X509GetCommonName (\r
+  IN      CONST UINT8  *Cert,\r
+  IN      UINTN        CertSize,\r
+  OUT     CHAR8        *CommonName   OPTIONAL,\r
+  IN OUT  UINTN        *CommonNameSize\r
+  )\r
+{\r
+  return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize);\r
+}\r
+\r
+/**\r
+  Retrieve the organization name (O) string from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[out]     NameBuffer       Buffer to contain the retrieved certificate organization\r
+                                   name string. At most NameBufferSize bytes will be\r
+                                   written and the string will be null terminated. May be\r
+                                   NULL in order to determine the size buffer needed.\r
+  @param[in,out]  NameBufferSize   The size in bytes of the Name buffer on input,\r
+                                   and the size of buffer returned Name on output.\r
+                                   If NameBuffer is NULL then the amount of space needed\r
+                                   in buffer (including the final null) is returned.\r
+\r
+  @retval RETURN_SUCCESS           The certificate Organization Name retrieved successfully.\r
+  @retval RETURN_INVALID_PARAMETER If Cert is NULL.\r
+                                   If NameBufferSize is NULL.\r
+                                   If NameBuffer is not NULL and *CommonNameSize is 0.\r
+                                   If Certificate is invalid.\r
+  @retval RETURN_NOT_FOUND         If no Organization Name entry exists.\r
+  @retval RETURN_BUFFER_TOO_SMALL  If the NameBuffer is NULL. The required buffer size\r
+                                   (including the final null) is returned in the\r
+                                   CommonNameSize parameter.\r
+  @retval RETURN_UNSUPPORTED       The operation is not supported.\r
+\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+X509GetOrganizationName (\r
+  IN      CONST UINT8  *Cert,\r
+  IN      UINTN        CertSize,\r
+  OUT     CHAR8        *NameBuffer   OPTIONAL,\r
+  IN OUT  UINTN        *NameBufferSize\r
+  )\r
+{\r
+  return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);\r
+}\r
+\r
 /**\r
   Retrieve the RSA Public Key from one DER-encoded X509 certificate.\r
 \r
@@ -470,7 +591,7 @@ RsaGetPublicKeyFromX509 (
   //\r
   // Check input parameters.\r
   //\r
-  if (Cert == NULL || RsaContext == NULL) {\r
+  if ((Cert == NULL) || (RsaContext == NULL)) {\r
     return FALSE;\r
   }\r
 \r
@@ -480,7 +601,7 @@ RsaGetPublicKeyFromX509 (
   //\r
   // Read DER-encoded X509 Certificate and Construct X509 object.\r
   //\r
-  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
   if ((X509Cert == NULL) || (!Status)) {\r
     Status = FALSE;\r
     goto _Exit;\r
@@ -552,7 +673,7 @@ X509VerifyCert (
   //\r
   // Check input parameters.\r
   //\r
-  if (Cert == NULL || CACert == NULL) {\r
+  if ((Cert == NULL) || (CACert == NULL)) {\r
     return FALSE;\r
   }\r
 \r
@@ -568,9 +689,11 @@ X509VerifyCert (
   if (EVP_add_digest (EVP_md5 ()) == 0) {\r
     goto _Exit;\r
   }\r
+\r
   if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
     goto _Exit;\r
   }\r
+\r
   if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
     goto _Exit;\r
   }\r
@@ -578,7 +701,7 @@ X509VerifyCert (
   //\r
   // Read DER-encoded certificate to be verified and Construct X509 object.\r
   //\r
-  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
   if ((X509Cert == NULL) || (!Status)) {\r
     Status = FALSE;\r
     goto _Exit;\r
@@ -587,7 +710,7 @@ X509VerifyCert (
   //\r
   // Read DER-encoded root certificate and Construct X509 object.\r
   //\r
-  Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert);\r
+  Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **)&X509CACert);\r
   if ((X509CACert == NULL) || (!Status)) {\r
     Status = FALSE;\r
     goto _Exit;\r
@@ -602,6 +725,7 @@ X509VerifyCert (
   if (CertStore == NULL) {\r
     goto _Exit;\r
   }\r
+\r
   if (!(X509_STORE_add_cert (CertStore, X509CACert))) {\r
     goto _Exit;\r
   }\r
@@ -610,8 +734,10 @@ X509VerifyCert (
   // Allow partial certificate chains, terminated by a non-self-signed but\r
   // still trusted intermediate certificate. Also disable time checks.\r
   //\r
-  X509_STORE_set_flags (CertStore,\r
-                        X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);\r
+  X509_STORE_set_flags (\r
+    CertStore,\r
+    X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME\r
+    );\r
 \r
   //\r
   // Set up X509_STORE_CTX for the subsequent verification operation.\r
@@ -620,6 +746,7 @@ X509VerifyCert (
   if (CertCtx == NULL) {\r
     goto _Exit;\r
   }\r
+\r
   if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {\r
     goto _Exit;\r
   }\r
@@ -627,7 +754,7 @@ X509VerifyCert (
   //\r
   // X509 Certificate Verification.\r
   //\r
-  Status = (BOOLEAN) X509_verify_cert (CertCtx);\r
+  Status = (BOOLEAN)X509_verify_cert (CertCtx);\r
   X509_STORE_CTX_cleanup (CertCtx);\r
 \r
 _Exit:\r
@@ -685,7 +812,8 @@ X509GetTBSCert (
   // Check input parameters.\r
   //\r
   if ((Cert == NULL) || (TBSCert == NULL) ||\r
-      (TBSCertSize == NULL) || (CertSize > INT_MAX)) {\r
+      (TBSCertSize == NULL) || (CertSize > INT_MAX))\r
+  {\r
     return FALSE;\r
   }\r
 \r
@@ -728,3 +856,1104 @@ X509GetTBSCert (
 \r
   return TRUE;\r
 }\r
+\r
+/**\r
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.\r
+\r
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.\r
+  @param[in]  CertSize     Size of the X509 certificate in bytes.\r
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved\r
+                           EC public key component. Use EcFree() function to free the\r
+                           resource.\r
+\r
+  If Cert is NULL, then return FALSE.\r
+  If EcContext is NULL, then return FALSE.\r
+\r
+  @retval  TRUE   EC Public Key was retrieved successfully.\r
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EcGetPublicKeyFromX509 (\r
+  IN   CONST UINT8  *Cert,\r
+  IN   UINTN        CertSize,\r
+  OUT  VOID         **EcContext\r
+  )\r
+{\r
+  BOOLEAN   Status;\r
+  EVP_PKEY  *Pkey;\r
+  X509      *X509Cert;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (EcContext == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Pkey     = NULL;\r
+  X509Cert = NULL;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    Status = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  Status = FALSE;\r
+\r
+  //\r
+  // Retrieve and check EVP_PKEY data from X509 Certificate.\r
+  //\r
+  Pkey = X509_get_pubkey (X509Cert);\r
+  if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_EC)) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Duplicate EC Context from the retrieved EVP_PKEY.\r
+  //\r
+  if ((*EcContext = EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey))) != NULL) {\r
+    Status = TRUE;\r
+  }\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  if (Pkey != NULL) {\r
+    EVP_PKEY_free (Pkey);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the version from one X.509 certificate.\r
+\r
+  If Cert is NULL, then return FALSE.\r
+  If CertSize is 0, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
+\r
+  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize     Size of the X509 certificate in bytes.\r
+  @param[out]     Version      Pointer to the retrieved version integer.\r
+\r
+  @retval TRUE           The certificate version retrieved successfully.\r
+  @retval FALSE          If  Cert is NULL or CertSize is Zero.\r
+  @retval FALSE          The operation is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetVersion (\r
+  IN      CONST UINT8  *Cert,\r
+  IN      UINTN        CertSize,\r
+  OUT     UINTN        *Version\r
+  )\r
+{\r
+  BOOLEAN  Status;\r
+  X509     *X509Cert;\r
+\r
+  X509Cert = NULL;\r
+  Status   = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    //\r
+    // Invalid X.509 Certificate\r
+    //\r
+    Status = FALSE;\r
+  }\r
+\r
+  if (Status) {\r
+    *Version = X509_get_version (X509Cert);\r
+  }\r
+\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the serialNumber from one X.509 certificate.\r
+\r
+  If Cert is NULL, then return FALSE.\r
+  If CertSize is 0, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
+\r
+  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize     Size of the X509 certificate in bytes.\r
+  @param[out]     SerialNumber  Pointer to the retrieved certificate SerialNumber bytes.\r
+  @param[in, out] SerialNumberSize  The size in bytes of the SerialNumber buffer on input,\r
+                               and the size of buffer returned SerialNumber on output.\r
+\r
+  @retval TRUE                     The certificate serialNumber retrieved successfully.\r
+  @retval FALSE                    If Cert is NULL or CertSize is Zero.\r
+                                   If SerialNumberSize is NULL.\r
+                                   If Certificate is invalid.\r
+  @retval FALSE                    If no SerialNumber exists.\r
+  @retval FALSE                    If the SerialNumber is NULL. The required buffer size\r
+                                   (including the final null) is returned in the\r
+                                   SerialNumberSize parameter.\r
+  @retval FALSE                    The operation is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetSerialNumber (\r
+  IN      CONST UINT8 *Cert,\r
+  IN      UINTN CertSize,\r
+  OUT     UINT8 *SerialNumber, OPTIONAL\r
+  IN OUT  UINTN         *SerialNumberSize\r
+  )\r
+{\r
+  BOOLEAN       Status;\r
+  X509          *X509Cert;\r
+  ASN1_INTEGER  *Asn1Integer;\r
+\r
+  Status = FALSE;\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (SerialNumberSize == NULL)) {\r
+    return Status;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    *SerialNumberSize = 0;\r
+    Status            = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Retrieve subject name from certificate object.\r
+  //\r
+  Asn1Integer = X509_get_serialNumber (X509Cert);\r
+  if (Asn1Integer == NULL) {\r
+    *SerialNumberSize = 0;\r
+    Status            = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  if (*SerialNumberSize < (UINTN)Asn1Integer->length) {\r
+    *SerialNumberSize = (UINTN)Asn1Integer->length;\r
+    Status            = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  if (SerialNumber != NULL) {\r
+    CopyMem (SerialNumber, Asn1Integer->data, *SerialNumberSize);\r
+    Status = TRUE;\r
+  }\r
+\r
+  *SerialNumberSize = (UINTN)Asn1Integer->length;\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the issuer bytes from one X.509 certificate.\r
+\r
+  If Cert is NULL, then return FALSE.\r
+  If CertIssuerSize is NULL, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
+\r
+  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize     Size of the X509 certificate in bytes.\r
+  @param[out]     CertIssuer  Pointer to the retrieved certificate subject bytes.\r
+  @param[in, out] CertIssuerSize  The size in bytes of the CertIssuer buffer on input,\r
+                               and the size of buffer returned CertSubject on output.\r
+\r
+  @retval  TRUE   The certificate issuer retrieved successfully.\r
+  @retval  FALSE  Invalid certificate, or the CertIssuerSize is too small for the result.\r
+                  The CertIssuerSize will be updated with the required size.\r
+  @retval  FALSE  This interface is not supported.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetIssuerName (\r
+  IN      CONST UINT8  *Cert,\r
+  IN      UINTN        CertSize,\r
+  OUT     UINT8        *CertIssuer,\r
+  IN OUT  UINTN        *CertIssuerSize\r
+  )\r
+{\r
+  BOOLEAN    Status;\r
+  X509       *X509Cert;\r
+  X509_NAME  *X509Name;\r
+  UINTN      X509NameSize;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (CertIssuerSize == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    Status = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  Status = FALSE;\r
+\r
+  //\r
+  // Retrieve subject name from certificate object.\r
+  //\r
+  X509Name = X509_get_subject_name (X509Cert);\r
+  if (X509Name == NULL) {\r
+    goto _Exit;\r
+  }\r
+\r
+  X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
+  if (*CertIssuerSize < X509NameSize) {\r
+    *CertIssuerSize = X509NameSize;\r
+    goto _Exit;\r
+  }\r
+\r
+  *CertIssuerSize = X509NameSize;\r
+  if (CertIssuer != NULL) {\r
+    i2d_X509_NAME (X509Name, &CertIssuer);\r
+    Status = TRUE;\r
+  }\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the Signature Algorithm from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[out]     Oid              Signature Algorithm Object identifier buffer.\r
+  @param[in,out]  OidSize          Signature Algorithm Object identifier buffer size\r
+\r
+  @retval TRUE           The certificate Extension data retrieved successfully.\r
+  @retval FALSE                    If Cert is NULL.\r
+                                   If OidSize is NULL.\r
+                                   If Oid is not NULL and *OidSize is 0.\r
+                                   If Certificate is invalid.\r
+  @retval FALSE                    If no SignatureType.\r
+  @retval FALSE                    If the Oid is NULL. The required buffer size\r
+                                   is returned in the OidSize.\r
+  @retval FALSE                    The operation is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetSignatureAlgorithm (\r
+  IN CONST UINT8 *Cert,\r
+  IN       UINTN CertSize,\r
+  OUT   UINT8 *Oid, OPTIONAL\r
+  IN OUT   UINTN       *OidSize\r
+  )\r
+{\r
+  BOOLEAN      Status;\r
+  X509         *X509Cert;\r
+  int          Nid;\r
+  ASN1_OBJECT  *Asn1Obj;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (OidSize == NULL) || (CertSize == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+  Status   = FALSE;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    Status = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Retrieve subject name from certificate object.\r
+  //\r
+  Nid = X509_get_signature_nid (X509Cert);\r
+  if (Nid == NID_undef) {\r
+    *OidSize = 0;\r
+    Status   = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  Asn1Obj = OBJ_nid2obj (Nid);\r
+  if (Asn1Obj == NULL) {\r
+    *OidSize = 0;\r
+    Status   = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  if (*OidSize < (UINTN)Asn1Obj->length) {\r
+    *OidSize = Asn1Obj->length;\r
+    Status   = FALSE;\r
+    goto _Exit;\r
+  }\r
+\r
+  if (Oid != NULL) {\r
+    CopyMem (Oid, Asn1Obj->data, Asn1Obj->length);\r
+  }\r
+\r
+  *OidSize = Asn1Obj->length;\r
+  Status   = TRUE;\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve Extension data from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[in]      Oid              Object identifier buffer\r
+  @param[in]      OidSize          Object identifier buffer size\r
+  @param[out]     ExtensionData    Extension bytes.\r
+  @param[in, out] ExtensionDataSize Extension bytes size.\r
+\r
+  @retval TRUE                     The certificate Extension data retrieved successfully.\r
+  @retval FALSE                    If Cert is NULL.\r
+                                   If ExtensionDataSize is NULL.\r
+                                   If ExtensionData is not NULL and *ExtensionDataSize is 0.\r
+                                   If Certificate is invalid.\r
+  @retval FALSE                    If no Extension entry match Oid.\r
+  @retval FALSE                    If the ExtensionData is NULL. The required buffer size\r
+                                   is returned in the ExtensionDataSize parameter.\r
+  @retval FALSE                    The operation is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetExtensionData (\r
+  IN     CONST UINT8  *Cert,\r
+  IN     UINTN        CertSize,\r
+  IN     CONST UINT8  *Oid,\r
+  IN     UINTN        OidSize,\r
+  OUT UINT8           *ExtensionData,\r
+  IN OUT UINTN        *ExtensionDataSize\r
+  )\r
+{\r
+  BOOLEAN  Status;\r
+  INTN     i;\r
+  X509     *X509Cert;\r
+\r
+  CONST STACK_OF (X509_EXTENSION) *Extensions;\r
+  ASN1_OBJECT        *Asn1Obj;\r
+  ASN1_OCTET_STRING  *Asn1Oct;\r
+  X509_EXTENSION     *Ext;\r
+  UINTN              ObjLength;\r
+  UINTN              OctLength;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (CertSize == 0) || (Oid == NULL) || (OidSize == 0) || (ExtensionDataSize == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+  Status   = FALSE;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    *ExtensionDataSize = 0;\r
+    goto Cleanup;\r
+  }\r
+\r
+  //\r
+  // Retrieve Extensions from certificate object.\r
+  //\r
+  Extensions = X509_get0_extensions (X509Cert);\r
+  if (sk_X509_EXTENSION_num (Extensions) <= 0) {\r
+    *ExtensionDataSize = 0;\r
+    goto Cleanup;\r
+  }\r
+\r
+  //\r
+  // Traverse Extensions\r
+  //\r
+  Status    = FALSE;\r
+  Asn1Oct   = NULL;\r
+  OctLength = 0;\r
+  for (i = 0; i < sk_X509_EXTENSION_num (Extensions); i++) {\r
+    Ext = sk_X509_EXTENSION_value (Extensions, (int)i);\r
+    if (Ext == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Asn1Obj = X509_EXTENSION_get_object (Ext);\r
+    if (Asn1Obj == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Asn1Oct = X509_EXTENSION_get_data (Ext);\r
+    if (Asn1Oct == NULL) {\r
+      continue;\r
+    }\r
+\r
+    ObjLength = OBJ_length (Asn1Obj);\r
+    OctLength = ASN1_STRING_length (Asn1Oct);\r
+    if ((OidSize == ObjLength) && (CompareMem (OBJ_get0_data (Asn1Obj), Oid, OidSize) == 0)) {\r
+      //\r
+      // Extension Found\r
+      //\r
+      Status = TRUE;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // reset to 0 if not found\r
+    //\r
+    OctLength = 0;\r
+  }\r
+\r
+  if (Status) {\r
+    if (*ExtensionDataSize < OctLength) {\r
+      *ExtensionDataSize = OctLength;\r
+      Status             = FALSE;\r
+      goto Cleanup;\r
+    }\r
+\r
+    if (Asn1Oct != NULL) {\r
+      CopyMem (ExtensionData, ASN1_STRING_get0_data (Asn1Oct), OctLength);\r
+    }\r
+\r
+    *ExtensionDataSize = OctLength;\r
+  } else {\r
+    *ExtensionDataSize = 0;\r
+  }\r
+\r
+Cleanup:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the Extended Key Usage from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[out]     Usage            Key Usage bytes.\r
+  @param[in, out] UsageSize        Key Usage buffer sizs in bytes.\r
+\r
+  @retval TRUE                     The Usage bytes retrieve successfully.\r
+  @retval FALSE                    If Cert is NULL.\r
+                                   If CertSize is NULL.\r
+                                   If Usage is not NULL and *UsageSize is 0.\r
+                                   If Cert is invalid.\r
+  @retval FALSE                    If the Usage is NULL. The required buffer size\r
+                                   is returned in the UsageSize parameter.\r
+  @retval FALSE                    The operation is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetExtendedKeyUsage (\r
+  IN     CONST UINT8  *Cert,\r
+  IN     UINTN        CertSize,\r
+  OUT UINT8           *Usage,\r
+  IN OUT UINTN        *UsageSize\r
+  )\r
+{\r
+  BOOLEAN  Status;\r
+\r
+  Status = X509GetExtensionData (Cert, CertSize, mOidExtKeyUsage, sizeof (mOidExtKeyUsage), Usage, UsageSize);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrieve the Validity from one X.509 certificate\r
+\r
+  If Cert is NULL, then return FALSE.\r
+  If CertIssuerSize is NULL, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
+\r
+  @param[in]      Cert         Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize     Size of the X509 certificate in bytes.\r
+  @param[out]     From         notBefore Pointer to DateTime object.\r
+  @param[in,out]  FromSize     notBefore DateTime object size.\r
+  @param[out]     To           notAfter Pointer to DateTime object.\r
+  @param[in,out]  ToSize       notAfter DateTime object size.\r
+\r
+  Note: X509CompareDateTime to compare DateTime oject\r
+        x509SetDateTime to get a DateTime object from a DateTimeStr\r
+\r
+  @retval  TRUE   The certificate Validity retrieved successfully.\r
+  @retval  FALSE  Invalid certificate, or Validity retrieve failed.\r
+  @retval  FALSE  This interface is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetValidity  (\r
+  IN     CONST UINT8  *Cert,\r
+  IN     UINTN        CertSize,\r
+  IN     UINT8        *From,\r
+  IN OUT UINTN        *FromSize,\r
+  IN     UINT8        *To,\r
+  IN OUT UINTN        *ToSize\r
+  )\r
+{\r
+  BOOLEAN          Status;\r
+  X509             *X509Cert;\r
+  CONST ASN1_TIME  *F;\r
+  CONST ASN1_TIME  *T;\r
+  UINTN            TSize;\r
+  UINTN            FSize;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (FromSize == NULL) || (ToSize == NULL) || (CertSize == 0)) {\r
+    return FALSE;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+  Status   = FALSE;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Retrieve Validity from/to from certificate object.\r
+  //\r
+  F = X509_get0_notBefore (X509Cert);\r
+  T = X509_get0_notAfter (X509Cert);\r
+\r
+  if ((F == NULL) || (T == NULL)) {\r
+    goto _Exit;\r
+  }\r
+\r
+  FSize = sizeof (ASN1_TIME) + F->length;\r
+  if (*FromSize < FSize) {\r
+    *FromSize = FSize;\r
+    goto _Exit;\r
+  }\r
+\r
+  *FromSize = FSize;\r
+  if (From != NULL) {\r
+    CopyMem (From, F, sizeof (ASN1_TIME));\r
+    ((ASN1_TIME *)From)->data = From + sizeof (ASN1_TIME);\r
+    CopyMem (From + sizeof (ASN1_TIME), F->data, F->length);\r
+  }\r
+\r
+  TSize = sizeof (ASN1_TIME) + T->length;\r
+  if (*ToSize < TSize) {\r
+    *ToSize = TSize;\r
+    goto _Exit;\r
+  }\r
+\r
+  *ToSize = TSize;\r
+  if (To != NULL) {\r
+    CopyMem (To, T, sizeof (ASN1_TIME));\r
+    ((ASN1_TIME *)To)->data = To + sizeof (ASN1_TIME);\r
+    CopyMem (To + sizeof (ASN1_TIME), T->data, T->length);\r
+  }\r
+\r
+  Status = TRUE;\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Format a DateTimeStr to DataTime object in DataTime Buffer\r
+\r
+  If DateTimeStr is NULL, then return FALSE.\r
+  If DateTimeSize is NULL, then return FALSE.\r
+  If this interface is not supported, then return FALSE.\r
+\r
+  @param[in]      DateTimeStr      DateTime string like YYYYMMDDhhmmssZ\r
+                                   Ref: https://www.w3.org/TR/NOTE-datetime\r
+                                   Z stand for UTC time\r
+  @param[out]     DateTime         Pointer to a DateTime object.\r
+  @param[in,out]  DateTimeSize     DateTime object buffer size.\r
+\r
+  @retval TRUE                     The DateTime object create successfully.\r
+  @retval FALSE                    If DateTimeStr is NULL.\r
+                                   If DateTimeSize is NULL.\r
+                                   If DateTime is not NULL and *DateTimeSize is 0.\r
+                                   If Year Month Day Hour Minute Second combination is invalid datetime.\r
+  @retval FALSE                    If the DateTime is NULL. The required buffer size\r
+                                   (including the final null) is returned in the\r
+                                   DateTimeSize parameter.\r
+  @retval FALSE                    The operation is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509FormatDateTime (\r
+  IN  CONST  CHAR8  *DateTimeStr,\r
+  OUT VOID          *DateTime,\r
+  IN OUT UINTN      *DateTimeSize\r
+  )\r
+{\r
+  BOOLEAN    Status;\r
+  INT32      Ret;\r
+  ASN1_TIME  *Dt;\r
+  UINTN      DSize;\r
+\r
+  Dt     = NULL;\r
+  Status = FALSE;\r
+\r
+  Dt = ASN1_TIME_new ();\r
+  if (Dt == NULL) {\r
+    Status = FALSE;\r
+    goto Cleanup;\r
+  }\r
+\r
+  Ret = ASN1_TIME_set_string_X509 (Dt, DateTimeStr);\r
+  if (Ret != 1) {\r
+    Status = FALSE;\r
+    goto Cleanup;\r
+  }\r
+\r
+  DSize = sizeof (ASN1_TIME) + Dt->length;\r
+  if (*DateTimeSize < DSize) {\r
+    *DateTimeSize = DSize;\r
+    Status        = FALSE;\r
+    goto Cleanup;\r
+  }\r
+\r
+  *DateTimeSize = DSize;\r
+  if (DateTime != NULL) {\r
+    CopyMem (DateTime, Dt, sizeof (ASN1_TIME));\r
+    ((ASN1_TIME *)DateTime)->data = (UINT8 *)DateTime + sizeof (ASN1_TIME);\r
+    CopyMem ((UINT8 *)DateTime + sizeof (ASN1_TIME), Dt->data, Dt->length);\r
+  }\r
+\r
+  Status = TRUE;\r
+\r
+Cleanup:\r
+  if (Dt != NULL) {\r
+    ASN1_TIME_free (Dt);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Compare DateTime1 object and DateTime2 object.\r
+\r
+  If DateTime1 is NULL, then return -2.\r
+  If DateTime2 is NULL, then return -2.\r
+  If DateTime1 == DateTime2, then return 0\r
+  If DateTime1 > DateTime2, then return 1\r
+  If DateTime1 < DateTime2, then return -1\r
+\r
+  @param[in]      DateTime1         Pointer to a DateTime Ojbect\r
+  @param[in]      DateTime2         Pointer to a DateTime Object\r
+\r
+  @retval  0      If DateTime1 == DateTime2\r
+  @retval  1      If DateTime1 > DateTime2\r
+  @retval  -1     If DateTime1 < DateTime2\r
+**/\r
+INT32\r
+EFIAPI\r
+X509CompareDateTime (\r
+  IN CONST  VOID  *DateTime1,\r
+  IN CONST  VOID  *DateTime2\r
+  )\r
+{\r
+  return (INT32)ASN1_TIME_compare (DateTime1, DateTime2);\r
+}\r
+\r
+/**\r
+  Retrieve the Key Usage from one X.509 certificate.\r
+\r
+  @param[in]      Cert             Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize         Size of the X509 certificate in bytes.\r
+  @param[out]     Usage            Key Usage (CRYPTO_X509_KU_*)\r
+\r
+  @retval  TRUE   The certificate Key Usage retrieved successfully.\r
+  @retval  FALSE  Invalid certificate, or Usage is NULL\r
+  @retval  FALSE  This interface is not supported.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetKeyUsage (\r
+  IN    CONST UINT8  *Cert,\r
+  IN    UINTN        CertSize,\r
+  OUT   UINTN        *Usage\r
+  )\r
+{\r
+  BOOLEAN  Status;\r
+  X509     *X509Cert;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((Cert == NULL) || (Usage == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  X509Cert = NULL;\r
+  Status   = FALSE;\r
+\r
+  //\r
+  // Read DER-encoded X509 Certificate and Construct X509 object.\r
+  //\r
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
+  if ((X509Cert == NULL) || (!Status)) {\r
+    goto _Exit;\r
+  }\r
+\r
+  //\r
+  // Retrieve subject name from certificate object.\r
+  //\r
+  *Usage = X509_get_key_usage (X509Cert);\r
+  if (*Usage == NID_undef) {\r
+    goto _Exit;\r
+  }\r
+\r
+  Status = TRUE;\r
+\r
+_Exit:\r
+  //\r
+  // Release Resources.\r
+  //\r
+  if (X509Cert != NULL) {\r
+    X509_free (X509Cert);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Verify one X509 certificate was issued by the trusted CA.\r
+  @param[in]      RootCert          Trusted Root Certificate buffer\r
+\r
+  @param[in]      RootCertLength    Trusted Root Certificate buffer length\r
+  @param[in]      CertChain         One or more ASN.1 DER-encoded X.509 certificates\r
+                                    where the first certificate is signed by the Root\r
+                                    Certificate or is the Root Cerificate itself. and\r
+                                    subsequent cerificate is signed by the preceding\r
+                                    cerificate.\r
+  @param[in]      CertChainLength   Total length of the certificate chain, in bytes.\r
+\r
+  @retval  TRUE   All cerificates was issued by the first certificate in X509Certchain.\r
+  @retval  FALSE  Invalid certificate or the certificate was not issued by the given\r
+                  trusted CA.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509VerifyCertChain (\r
+  IN CONST UINT8  *RootCert,\r
+  IN UINTN        RootCertLength,\r
+  IN CONST UINT8  *CertChain,\r
+  IN UINTN        CertChainLength\r
+  )\r
+{\r
+  CONST UINT8  *TmpPtr;\r
+  UINTN        Length;\r
+  UINT32       Asn1Tag;\r
+  UINT32       ObjClass;\r
+  CONST UINT8  *CurrentCert;\r
+  UINTN        CurrentCertLen;\r
+  CONST UINT8  *PrecedingCert;\r
+  UINTN        PrecedingCertLen;\r
+  BOOLEAN      VerifyFlag;\r
+  INT32        Ret;\r
+\r
+  PrecedingCert    = RootCert;\r
+  PrecedingCertLen = RootCertLength;\r
+\r
+  CurrentCert    = CertChain;\r
+  Length         = 0;\r
+  CurrentCertLen = 0;\r
+\r
+  VerifyFlag = FALSE;\r
+  while (TRUE) {\r
+    TmpPtr = CurrentCert;\r
+    Ret    = ASN1_get_object (\r
+               (CONST UINT8 **)&TmpPtr,\r
+               (long *)&Length,\r
+               (int *)&Asn1Tag,\r
+               (int *)&ObjClass,\r
+               (long)(CertChainLength + CertChain - TmpPtr)\r
+               );\r
+    if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Calculate CurrentCert length;\r
+    //\r
+    CurrentCertLen = TmpPtr - CurrentCert + Length;\r
+\r
+    //\r
+    // Verify CurrentCert with preceding cert;\r
+    //\r
+    VerifyFlag = X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen);\r
+    if (VerifyFlag == FALSE) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // move Current cert to Preceding cert\r
+    //\r
+    PrecedingCertLen = CurrentCertLen;\r
+    PrecedingCert    = CurrentCert;\r
+\r
+    //\r
+    // Move to next\r
+    //\r
+    CurrentCert = CurrentCert + CurrentCertLen;\r
+  }\r
+\r
+  return VerifyFlag;\r
+}\r
+\r
+/**\r
+  Get one X509 certificate from CertChain.\r
+\r
+  @param[in]      CertChain         One or more ASN.1 DER-encoded X.509 certificates\r
+                                    where the first certificate is signed by the Root\r
+                                    Certificate or is the Root Cerificate itself. and\r
+                                    subsequent cerificate is signed by the preceding\r
+                                    cerificate.\r
+  @param[in]      CertChainLength   Total length of the certificate chain, in bytes.\r
+\r
+  @param[in]      CertIndex         Index of certificate.\r
+\r
+  @param[out]     Cert              The certificate at the index of CertChain.\r
+  @param[out]     CertLength        The length certificate at the index of CertChain.\r
+\r
+  @retval  TRUE   Success.\r
+  @retval  FALSE  Failed to get certificate from certificate chain.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetCertFromCertChain (\r
+  IN CONST UINT8   *CertChain,\r
+  IN UINTN         CertChainLength,\r
+  IN CONST INT32   CertIndex,\r
+  OUT CONST UINT8  **Cert,\r
+  OUT UINTN        *CertLength\r
+  )\r
+{\r
+  UINTN        Asn1Len;\r
+  INT32        CurrentIndex;\r
+  UINTN        CurrentCertLen;\r
+  CONST UINT8  *CurrentCert;\r
+  CONST UINT8  *TmpPtr;\r
+  INT32        Ret;\r
+  UINT32       Asn1Tag;\r
+  UINT32       ObjClass;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if ((CertChain == NULL) || (Cert == NULL) ||\r
+      (CertIndex < -1) || (CertLength == NULL))\r
+  {\r
+    return FALSE;\r
+  }\r
+\r
+  Asn1Len        = 0;\r
+  CurrentCertLen = 0;\r
+  CurrentCert    = CertChain;\r
+  CurrentIndex   = -1;\r
+\r
+  //\r
+  // Traverse the certificate chain\r
+  //\r
+  while (TRUE) {\r
+    TmpPtr = CurrentCert;\r
+\r
+    // Get asn1 object and taglen\r
+    Ret = ASN1_get_object (\r
+            (CONST UINT8 **)&TmpPtr,\r
+            (long *)&Asn1Len,\r
+            (int *)&Asn1Tag,\r
+            (int *)&ObjClass,\r
+            (long)(CertChainLength + CertChain - TmpPtr)\r
+            );\r
+    if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Calculate CurrentCert length;\r
+    //\r
+    CurrentCertLen = TmpPtr - CurrentCert + Asn1Len;\r
+    CurrentIndex++;\r
+\r
+    if (CurrentIndex == CertIndex) {\r
+      *Cert       = CurrentCert;\r
+      *CertLength = CurrentCertLen;\r
+      return TRUE;\r
+    }\r
+\r
+    //\r
+    // Move to next\r
+    //\r
+    CurrentCert = CurrentCert + CurrentCertLen;\r
+  }\r
+\r
+  //\r
+  // If CertIndex is -1, Return the last certificate\r
+  //\r
+  if ((CertIndex == -1) && (CurrentIndex >= 0)) {\r
+    *Cert       = CurrentCert - CurrentCertLen;\r
+    *CertLength = CurrentCertLen;\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Retrieve the tag and length of the tag.\r
+\r
+  @param Ptr      The position in the ASN.1 data\r
+  @param End      End of data\r
+  @param Length   The variable that will receive the length\r
+  @param Tag      The expected tag\r
+\r
+  @retval      TRUE   Get tag successful\r
+  @retval      FALSe  Failed to get tag or tag not match\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+Asn1GetTag (\r
+  IN OUT UINT8    **Ptr,\r
+  IN CONST UINT8  *End,\r
+  OUT UINTN       *Length,\r
+  IN     UINT32   Tag\r
+  )\r
+{\r
+  UINT8  *PtrOld;\r
+  INT32  ObjTag;\r
+  INT32  ObjCls;\r
+  long   ObjLength;\r
+\r
+  //\r
+  // Save Ptr position\r
+  //\r
+  PtrOld = *Ptr;\r
+\r
+  ASN1_get_object ((CONST UINT8 **)Ptr, &ObjLength, &ObjTag, &ObjCls, (INT32)(End - (*Ptr)));\r
+  if ((ObjTag == (INT32)(Tag & CRYPTO_ASN1_TAG_VALUE_MASK)) &&\r
+      (ObjCls == (INT32)(Tag & CRYPTO_ASN1_TAG_CLASS_MASK)))\r
+  {\r
+    *Length = (UINTN)ObjLength;\r
+    return TRUE;\r
+  } else {\r
+    //\r
+    // if doesn't match Tag, restore Ptr to origin Ptr\r
+    //\r
+    *Ptr = PtrOld;\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+/**\r
+  Retrieve the basic constraints from one X.509 certificate.\r
+\r
+  @param[in]      Cert                     Pointer to the DER-encoded X509 certificate.\r
+  @param[in]      CertSize                 size of the X509 certificate in bytes.\r
+  @param[out]     BasicConstraints         basic constraints bytes.\r
+  @param[in, out] BasicConstraintsSize     basic constraints buffer sizs in bytes.\r
+\r
+  @retval TRUE                     The basic constraints retrieve successfully.\r
+  @retval FALSE                    If cert is NULL.\r
+                                   If cert_size is NULL.\r
+                                   If basic_constraints is not NULL and *basic_constraints_size is 0.\r
+                                   If cert is invalid.\r
+  @retval FALSE                    The required buffer size is small.\r
+                                   The return buffer size is basic_constraints_size parameter.\r
+  @retval FALSE                    If no Extension entry match oid.\r
+  @retval FALSE                    The operation is not supported.\r
+ **/\r
+BOOLEAN\r
+EFIAPI\r
+X509GetExtendedBasicConstraints             (\r
+  CONST UINT8  *Cert,\r
+  UINTN        CertSize,\r
+  UINT8        *BasicConstraints,\r
+  UINTN        *BasicConstraintsSize\r
+  )\r
+{\r
+  BOOLEAN  Status;\r
+\r
+  if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {\r
+    return FALSE;\r
+  }\r
+\r
+  Status = X509GetExtensionData (\r
+             (UINT8 *)Cert,\r
+             CertSize,\r
+             mOidBasicConstraints,\r
+             sizeof (mOidBasicConstraints),\r
+             BasicConstraints,\r
+             BasicConstraintsSize\r
+             );\r
+\r
+  return Status;\r
+}\r