/** @file\r
X.509 Certificate Handler Wrapper Implementation over OpenSSL.\r
\r
-Copyright (c) 2010 - 2015, 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
// 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
// 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
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
+\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
//\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
}\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
// 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
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
X509Free (\r
IN VOID *X509Cert\r
)\r
-{ \r
+{\r
//\r
// Check input parameters.\r
//\r
if (X509Cert == NULL) {\r
return;\r
}\r
- \r
+\r
//\r
// Free OpenSSL X509 object.\r
//\r
- X509_free ((X509 *) X509Cert);\r
+ X509_free ((X509 *)X509Cert);\r
}\r
\r
/**\r
if (X509Stack == NULL) {\r
return;\r
}\r
- \r
+\r
//\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
BOOLEAN Status;\r
X509 *X509Cert;\r
X509_NAME *X509Name;\r
+ UINTN X509NameSize;\r
\r
//\r
// Check input parameters.\r
//\r
- if (Cert == NULL || SubjectSize == NULL) {\r
+ if ((Cert == NULL) || (SubjectSize == NULL)) {\r
return FALSE;\r
}\r
\r
//\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
goto _Exit;\r
}\r
\r
- if (*SubjectSize < (UINTN) X509Name->bytes->length) {\r
- *SubjectSize = (UINTN) X509Name->bytes->length;\r
+ X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
+ if (*SubjectSize < X509NameSize) {\r
+ *SubjectSize = X509NameSize;\r
goto _Exit;\r
}\r
- *SubjectSize = (UINTN) X509Name->bytes->length;\r
+\r
+ *SubjectSize = X509NameSize;\r
if (CertSubject != NULL) {\r
- CopyMem (CertSubject, (UINT8 *) X509Name->bytes->data, *SubjectSize);\r
+ i2d_X509_NAME (X509Name, &CertSubject);\r
Status = TRUE;\r
}\r
\r
return Status;\r
}\r
\r
+/**\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
+ 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 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
+InternalX509GetNIDName (\r
+ IN CONST UINT8 *Cert,\r
+ IN UINTN CertSize,\r
+ IN INT32 Request_NID,\r
+ OUT CHAR8 *CommonName OPTIONAL,\r
+ IN OUT UINTN *CommonNameSize\r
+ )\r
+{\r
+ RETURN_STATUS ReturnStatus;\r
+ BOOLEAN Status;\r
+ X509 *X509Cert;\r
+ X509_NAME *X509Name;\r
+ INT32 Index;\r
+ INTN Length;\r
+ X509_NAME_ENTRY *Entry;\r
+ ASN1_STRING *EntryData;\r
+ UINT8 *UTF8Name;\r
+\r
+ ReturnStatus = RETURN_INVALID_PARAMETER;\r
+ UTF8Name = NULL;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {\r
+ return ReturnStatus;\r
+ }\r
+\r
+ if ((CommonName != NULL) && (*CommonNameSize == 0)) {\r
+ return ReturnStatus;\r
+ }\r
+\r
+ X509Cert = NULL;\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
+ //\r
+ // Invalid X.509 Certificate\r
+ //\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
+ //\r
+ // Fail to retrieve subject name content\r
+ //\r
+ goto _Exit;\r
+ }\r
+\r
+ //\r
+ // Retrive the string from X.509 Subject base on the Request_NID\r
+ //\r
+ Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);\r
+ if (Index < 0) {\r
+ //\r
+ // No Request_NID name entry exists in X509_NAME object\r
+ //\r
+ *CommonNameSize = 0;\r
+ ReturnStatus = RETURN_NOT_FOUND;\r
+ goto _Exit;\r
+ }\r
+\r
+ Entry = X509_NAME_get_entry (X509Name, Index);\r
+ if (Entry == NULL) {\r
+ //\r
+ // Fail to retrieve name entry data\r
+ //\r
+ *CommonNameSize = 0;\r
+ ReturnStatus = RETURN_NOT_FOUND;\r
+ goto _Exit;\r
+ }\r
+\r
+ EntryData = X509_NAME_ENTRY_get_data (Entry);\r
+\r
+ Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);\r
+ if (Length < 0) {\r
+ //\r
+ // Fail to convert the Name string\r
+ //\r
+ *CommonNameSize = 0;\r
+ ReturnStatus = RETURN_INVALID_PARAMETER;\r
+ goto _Exit;\r
+ }\r
+\r
+ if (CommonName == NULL) {\r
+ *CommonNameSize = Length + 1;\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
+ }\r
+\r
+_Exit:\r
+ //\r
+ // Release Resources.\r
+ //\r
+ if (X509Cert != NULL) {\r
+ X509_free (X509Cert);\r
+ }\r
+\r
+ if (UTF8Name != NULL) {\r
+ OPENSSL_free (UTF8Name);\r
+ }\r
+\r
+ 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
BOOLEAN Status;\r
EVP_PKEY *Pkey;\r
X509 *X509Cert;\r
- \r
+\r
//\r
// Check input parameters.\r
//\r
- if (Cert == NULL || RsaContext == NULL) {\r
+ if ((Cert == NULL) || (RsaContext == NULL)) {\r
return FALSE;\r
}\r
\r
//\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
// Retrieve and check EVP_PKEY data from X509 Certificate.\r
//\r
Pkey = X509_get_pubkey (X509Cert);\r
- if ((Pkey == NULL) || (Pkey->type != EVP_PKEY_RSA)) {\r
+ if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {\r
goto _Exit;\r
}\r
\r
//\r
// Duplicate RSA Context from the retrieved EVP_PKEY.\r
//\r
- if ((*RsaContext = RSAPublicKey_dup (Pkey->pkey.rsa)) != NULL) {\r
+ if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {\r
Status = TRUE;\r
}\r
\r
\r
if (Pkey != NULL) {\r
EVP_PKEY_free (Pkey);\r
- } \r
+ }\r
\r
return Status;\r
}\r
X509 *X509Cert;\r
X509 *X509CACert;\r
X509_STORE *CertStore;\r
- X509_STORE_CTX CertCtx;\r
- \r
+ X509_STORE_CTX *CertCtx;\r
+\r
//\r
// Check input parameters.\r
//\r
- if (Cert == NULL || CACert == NULL) {\r
+ if ((Cert == NULL) || (CACert == NULL)) {\r
return FALSE;\r
}\r
\r
X509Cert = NULL;\r
X509CACert = NULL;\r
CertStore = NULL;\r
+ CertCtx = NULL;\r
\r
//\r
// Register & Initialize necessary digest algorithms for certificate verification.\r
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
//\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
//\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
if (CertStore == NULL) {\r
goto _Exit;\r
}\r
+\r
if (!(X509_STORE_add_cert (CertStore, X509CACert))) {\r
goto _Exit;\r
}\r
\r
+ //\r
+ // 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 (\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
//\r
- if (!X509_STORE_CTX_init (&CertCtx, CertStore, X509Cert, NULL)) {\r
+ CertCtx = X509_STORE_CTX_new ();\r
+ if (CertCtx == NULL) {\r
+ goto _Exit;\r
+ }\r
+\r
+ if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {\r
goto _Exit;\r
}\r
\r
//\r
// X509 Certificate Verification.\r
//\r
- Status = (BOOLEAN) X509_verify_cert (&CertCtx);\r
- X509_STORE_CTX_cleanup (&CertCtx);\r
+ Status = (BOOLEAN)X509_verify_cert (CertCtx);\r
+ X509_STORE_CTX_cleanup (CertCtx);\r
\r
_Exit:\r
//\r
if (CertStore != NULL) {\r
X509_STORE_free (CertStore);\r
}\r
- \r
+\r
+ X509_STORE_CTX_free (CertCtx);\r
+\r
return Status;\r
}\r
\r
)\r
{\r
CONST UINT8 *Temp;\r
- INTN Asn1Tag;\r
- INTN ObjClass;\r
+ UINT32 Asn1Tag;\r
+ UINT32 ObjClass;\r
UINTN Length;\r
\r
//\r
// 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
// So we can just ASN1-parse the x.509 DER-encoded data. If we strip\r
// the first SEQUENCE, the second SEQUENCE is the TBSCertificate.\r
//\r
- Temp = Cert;\r
+ Temp = Cert;\r
+ Length = 0;\r
ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);\r
\r
if (Asn1Tag != V_ASN1_SEQUENCE) {\r
}\r
\r
*TBSCertSize = Length + (Temp - *TBSCert);\r
- \r
+\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