summaryrefslogtreecommitdiff
path: root/CryptoPkg
diff options
context:
space:
mode:
authorWenxing Hou <wenxing.hou@intel.com>2024-03-12 19:40:02 +0800
committerLiming Gao <gaoliming@byosoft.com.cn>2024-05-27 17:24:30 +0800
commit40fa5cf2995e9de6c9853945428f407f208be1e1 (patch)
tree25be06dd996a30d4fb0c009caa182ed34a536386 /CryptoPkg
parentf44cc28972e1b3a66469a88c7dc7a658e7995e90 (diff)
downloadedk2-40fa5cf2995e9de6c9853945428f407f208be1e1.zip
edk2-40fa5cf2995e9de6c9853945428f407f208be1e1.tar.gz
edk2-40fa5cf2995e9de6c9853945428f407f208be1e1.tar.bz2
CryptoPkg: Add X509 functions based on Mbedtls
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177 X.509 Certificate Handler Wrapper Implementation over MbedTLS. Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Yi Li <yi1.li@intel.com> Signed-off-by: Wenxing Hou <wenxing.hou@intel.com> Reviewed-by: Yi Li <yi1.li@intel.com> Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
Diffstat (limited to 'CryptoPkg')
-rw-r--r--CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c1940
1 files changed, 1940 insertions, 0 deletions
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
new file mode 100644
index 0000000..84b67c8
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
@@ -0,0 +1,1940 @@
+/** @file
+ X.509 Certificate Handler Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/rsa.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecdsa.h>
+
+///
+/// OID
+///
+STATIC CONST UINT8 OID_commonName[] = {
+ 0x55, 0x04, 0x03
+};
+STATIC CONST UINT8 OID_organizationName[] = {
+ 0x55, 0x04, 0x0A
+};
+STATIC CONST UINT8 OID_extKeyUsage[] = {
+ 0x55, 0x1D, 0x25
+};
+STATIC CONST UINT8 OID_BasicConstraints[] = {
+ 0x55, 0x1D, 0x13
+};
+
+/* Profile for backward compatibility. Allows RSA 1024, unlike the default
+ profile. */
+STATIC mbedtls_x509_crt_profile gCompatProfile =
+{
+ /* Hashes from SHA-256 and above. Note that this selection
+ * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA256) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA384) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA512),
+ 0xFFFFFFF, /* Any PK alg */
+
+ /* Curves at or above 128-bit security level. Note that this selection
+ * should be aligned with ssl_preset_default_curves in ssl_tls.c. */
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP521R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP512R1) |
+ 0,
+ 1024,
+};
+
+/**
+ Construct a X509 object from DER-encoded certificate data.
+
+ If Cert is NULL, then return FALSE.
+ If SingleX509Cert is NULL, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded certificate data.
+ @param[in] CertSize The size of certificate data in bytes.
+ @param[out] SingleX509Cert The generated X509 object.
+
+ @retval TRUE The X509 object generation succeeded.
+ @retval FALSE The operation failed.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificate (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **SingleX509Cert
+ )
+{
+ mbedtls_x509_crt *MbedTlsCert;
+ INT32 Ret;
+
+ if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize == 0)) {
+ return FALSE;
+ }
+
+ MbedTlsCert = AllocateZeroPool (sizeof (mbedtls_x509_crt));
+ if (MbedTlsCert == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (MbedTlsCert);
+
+ *SingleX509Cert = (UINT8 *)(VOID *)MbedTlsCert;
+ Ret = mbedtls_x509_crt_parse_der (MbedTlsCert, Cert, CertSize);
+ if (Ret == 0) {
+ return TRUE;
+ } else {
+ mbedtls_x509_crt_free (MbedTlsCert);
+ FreePool (MbedTlsCert);
+ return FALSE;
+ }
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ If X509Stack is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param[in] Args VA_LIST marker for the variable argument list.
+ A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval TRUE The X509 stack construction succeeded.
+ @retval FALSE The construction operation failed.
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStackV (
+ IN OUT UINT8 **X509Stack,
+ IN VA_LIST Args
+ )
+{
+ UINT8 *Cert;
+ UINTN CertSize;
+ INT32 Index;
+ INT32 Ret;
+ mbedtls_x509_crt *Crt;
+
+ if (X509Stack == NULL) {
+ return FALSE;
+ }
+
+ Ret = 0;
+ Crt = NULL;
+ if (*X509Stack == NULL) {
+ Crt = AllocateZeroPool (sizeof (mbedtls_x509_crt));
+ if (Crt == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (Crt);
+ *X509Stack = (UINT8 *)Crt;
+ }
+
+ for (Index = 0; ; Index++) {
+ //
+ // If Cert is NULL, then it is the end of the list.
+ //
+ Cert = VA_ARG (Args, UINT8 *);
+ if (Cert == NULL) {
+ break;
+ }
+
+ CertSize = VA_ARG (Args, UINTN);
+ if (CertSize == 0) {
+ break;
+ }
+
+ Ret = mbedtls_x509_crt_parse_der ((mbedtls_x509_crt *)*X509Stack, Cert, CertSize);
+
+ if (Ret != 0) {
+ break;
+ }
+ }
+
+ if (Ret == 0) {
+ return TRUE;
+ } else {
+ if (Crt != NULL) {
+ mbedtls_x509_crt_free (Crt);
+ FreePool (Crt);
+ *X509Stack = NULL;
+ }
+
+ return FALSE;
+ }
+}
+
+/**
+ Construct a X509 stack object from a list of DER-encoded certificate data.
+
+ If X509Stack is NULL, then return FALSE.
+
+ @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
+ On output, pointer to the X509 stack object with new
+ inserted X509 certificate.
+ @param ... A list of DER-encoded single certificate data followed
+ by certificate size. A NULL terminates the list. The
+ pairs are the arguments to X509ConstructCertificate().
+
+ @retval TRUE The X509 stack construction succeeded.
+ @retval FALSE The construction operation failed.
+
+**/
+BOOLEAN
+EFIAPI
+X509ConstructCertificateStack (
+ IN OUT UINT8 **X509Stack,
+ ...
+ )
+{
+ VA_LIST Args;
+ BOOLEAN Result;
+
+ VA_START (Args, X509Stack);
+ Result = X509ConstructCertificateStackV (X509Stack, Args);
+ VA_END (Args);
+ return Result;
+}
+
+/**
+ Release the specified X509 object.
+
+ If X509Cert is NULL, then return FALSE.
+
+ @param[in] X509Cert Pointer to the X509 object to be released.
+
+**/
+VOID
+EFIAPI
+X509Free (
+ IN VOID *X509Cert
+ )
+{
+ if (X509Cert != NULL) {
+ mbedtls_x509_crt_free (X509Cert);
+ FreePool (X509Cert);
+ }
+}
+
+/**
+ Release the specified X509 stack object.
+
+ If X509Stack is NULL, then return FALSE.
+
+ @param[in] X509Stack Pointer to the X509 stack object to be released.
+
+**/
+VOID
+EFIAPI
+X509StackFree (
+ IN VOID *X509Stack
+ )
+{
+ if (X509Stack == NULL) {
+ return;
+ }
+
+ mbedtls_x509_crt_free (X509Stack);
+}
+
+/**
+ Retrieve the tag and length of the tag.
+
+ @param Ptr The position in the ASN.1 data
+ @param End End of data
+ @param Length The variable that will receive the length
+ @param Tag The expected tag
+
+ @retval TRUE Get tag successful
+ @retval FALSe Failed to get tag or tag not match
+**/
+BOOLEAN
+EFIAPI
+Asn1GetTag (
+ IN OUT UINT8 **Ptr,
+ IN CONST UINT8 *End,
+ OUT UINTN *Length,
+ IN UINT32 Tag
+ )
+{
+ if (mbedtls_asn1_get_tag (Ptr, End, Length, (INT32)Tag) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Retrieve the subject bytes from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CertSubject Pointer to the retrieved certificate subject bytes.
+ @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input,
+ and the size of buffer returned CertSubject on output.
+
+ If Cert is NULL, then return FALSE.
+ If SubjectSize is NULL, then return FALSE.
+
+ @retval TRUE The certificate subject retrieved successfully.
+ @retval FALSE Invalid certificate, or the SubjectSize is too small for the result.
+ The SubjectSize will be updated with the required size.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetSubjectName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *CertSubject,
+ IN OUT UINTN *SubjectSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (CertSubject != NULL) {
+ CopyMem (CertSubject, Crt.subject_raw.p, Crt.subject_raw.len);
+ }
+
+ *SubjectSize = Crt.subject_raw.len;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return Ret == 0;
+}
+
+/**
+ Retrieve a string from one X.509 certificate base on the Request_NID.
+
+ @param[in] Name mbedtls_x509_name
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @param[in,out] CommonName Buffer to contain the retrieved certificate common
+ name string (UTF8). At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no NID Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetNIDName (
+ IN mbedtls_x509_name *Name,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ IN OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ CONST mbedtls_asn1_named_data *data;
+
+ data = mbedtls_asn1_find_named_data (Name, Oid, OidSize);
+ if (data != NULL) {
+ if (*CommonNameSize <= data->val.len) {
+ *CommonNameSize = data->val.len + 1;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+
+ if (CommonName != NULL) {
+ CopyMem (CommonName, data->val.p, data->val.len);
+ CommonName[data->val.len] = '\0';
+ }
+
+ *CommonNameSize = data->val.len + 1;
+ return RETURN_SUCCESS;
+ } else {
+ return RETURN_NOT_FOUND;
+ }
+}
+
+/**
+ Get X509 SubjectNIDName by OID.
+
+ @param[in] Cert certificate
+ @param[in] CertSize certificate size.
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @param[in,out] CommonName Buffer to contain the retrieved certificate common
+ name string (UTF8). At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no NID Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetSubjectNIDName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ IN OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ mbedtls_x509_name *Name;
+ RETURN_STATUS ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Name = &(Crt.subject);
+ ReturnStatus = InternalX509GetNIDName (Name, Oid, OidSize, CommonName, CommonNameSize);
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Get X509 IssuerNIDName by OID.
+
+ @param[in] Cert certificate
+ @param[in] CertSize certificate size.
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @param[out] CommonName Buffer to contain the retrieved certificate common
+ name string (UTF8). At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no NID Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetIssuerNIDName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ mbedtls_x509_name *Name;
+ RETURN_STATUS ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Name = &(Crt.issuer);
+ ReturnStatus = InternalX509GetNIDName (Name, Oid, OidSize, CommonName, CommonNameSize);
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the common name (CN) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CommonName Buffer to contain the retrieved certificate common
+ name string. At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no CommonName entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetCommonName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ return InternalX509GetSubjectNIDName (Cert, CertSize, (CHAR8 *)OID_commonName, sizeof (OID_commonName), CommonName, CommonNameSize);
+}
+
+/**
+ Retrieve the organization name (O) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] NameBuffer Buffer to contain the retrieved certificate organization
+ name string. At most NameBufferSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,
+ and the size of buffer returned Name on output.
+ If NameBuffer is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate Organization Name retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If NameBufferSize is NULL.
+ If NameBuffer is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no Organization Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetOrganizationName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *NameBuffer OPTIONAL,
+ IN OUT UINTN *NameBufferSize
+ )
+{
+ return InternalX509GetSubjectNIDName (Cert, CertSize, (CHAR8 *)OID_organizationName, sizeof (OID_organizationName), NameBuffer, NameBufferSize);
+}
+
+/**
+ Retrieve the RSA Public Key from one DER-encoded X509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved
+ RSA public key component. Use RsaFree() function to free the
+ resource.
+
+ If Cert is NULL, then return FALSE.
+ If RsaContext is NULL, then return FALSE.
+
+ @retval TRUE RSA Public Key was retrieved successfully.
+ @retval FALSE Fail to retrieve RSA public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+RsaGetPublicKeyFromX509 (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT VOID **RsaContext
+ )
+{
+ mbedtls_x509_crt Crt;
+ mbedtls_rsa_context *Rsa;
+ INT32 Ret;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ if (mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize) != 0) {
+ return FALSE;
+ }
+
+ if (mbedtls_pk_get_type (&Crt.pk) != MBEDTLS_PK_RSA) {
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ Ret = mbedtls_rsa_copy (Rsa, mbedtls_pk_rsa (Crt.pk));
+ if (Ret != 0) {
+ RsaFree (Rsa);
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ *RsaContext = Rsa;
+ return TRUE;
+}
+
+/**
+ Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] EcContext Pointer to new-generated EC DSA context which contain the retrieved
+ EC public key component. Use EcFree() function to free the
+ resource.
+
+ If Cert is NULL, then return FALSE.
+ If EcContext is NULL, then return FALSE.
+
+ @retval TRUE EC Public Key was retrieved successfully.
+ @retval FALSE Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT VOID **EcContext
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Verify one X509 certificate was issued by the trusted CA.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] CACert Pointer to the DER-encoded trusted CA certificate.
+ @param[in] CACertSize Size of the CA Certificate in bytes.
+
+ If Cert is NULL, then return FALSE.
+ If CACert is NULL, then return FALSE.
+
+ @retval TRUE The certificate was issued by the trusted CA.
+ @retval FALSE Invalid certificate or the certificate was not issued by the given
+ trusted CA.
+
+**/
+BOOLEAN
+EFIAPI
+X509VerifyCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *CACert,
+ IN UINTN CACertSize
+ )
+{
+ INT32 Ret;
+ mbedtls_x509_crt Ca;
+ mbedtls_x509_crt End;
+ UINT32 VFlag;
+ mbedtls_x509_crt_profile Profile;
+
+ if ((Cert == NULL) || (CACert == NULL)) {
+ return FALSE;
+ }
+
+ VFlag = 0;
+ CopyMem (&Profile, &gCompatProfile, sizeof (mbedtls_x509_crt_profile));
+
+ mbedtls_x509_crt_init (&Ca);
+ mbedtls_x509_crt_init (&End);
+
+ Ret = mbedtls_x509_crt_parse_der (&Ca, CACert, CACertSize);
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_crt_parse_der (&End, Cert, CertSize);
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_crt_verify_with_profile (&End, &Ca, NULL, &Profile, NULL, &VFlag, NULL, NULL);
+ }
+
+ mbedtls_x509_crt_free (&Ca);
+ mbedtls_x509_crt_free (&End);
+
+ return Ret == 0;
+}
+
+/**
+ Verify one X509 certificate was issued by the trusted CA.
+
+ @param[in] RootCert Trusted Root Certificate buffer
+ @param[in] RootCertLength Trusted Root Certificate buffer length
+ @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
+ where the first certificate is signed by the Root
+ Certificate or is the Root Cerificate itself. and
+ subsequent cerificate is signed by the preceding
+ cerificate.
+ @param[in] CertChainLength Total length of the certificate chain, in bytes.
+
+ @retval TRUE All cerificates was issued by the first certificate in X509Certchain.
+ @retval FALSE Invalid certificate or the certificate was not issued by the given
+ trusted CA.
+**/
+BOOLEAN
+EFIAPI
+X509VerifyCertChain (
+ IN CONST UINT8 *RootCert,
+ IN UINTN RootCertLength,
+ IN CONST UINT8 *CertChain,
+ IN UINTN CertChainLength
+ )
+{
+ UINTN Asn1Len;
+ UINTN PrecedingCertLen;
+ CONST UINT8 *PrecedingCert;
+ UINTN CurrentCertLen;
+ CONST UINT8 *CurrentCert;
+ CONST UINT8 *TmpPtr;
+ UINT32 Ret;
+ BOOLEAN VerifyFlag;
+
+ VerifyFlag = FALSE;
+ PrecedingCert = RootCert;
+ PrecedingCertLen = RootCertLength;
+
+ CurrentCert = CertChain;
+
+ //
+ // Get Current certificate from Certificates buffer and Verify with preciding cert
+ //
+ do {
+ TmpPtr = CurrentCert;
+ Ret = mbedtls_asn1_get_tag ((UINT8 **)&TmpPtr, CertChain + CertChainLength, &Asn1Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ break;
+ }
+
+ CurrentCertLen = Asn1Len + (TmpPtr - CurrentCert);
+
+ if (!X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen)) {
+ VerifyFlag = FALSE;
+ break;
+ } else {
+ VerifyFlag = TRUE;
+ }
+
+ //
+ // Save preceding certificate
+ //
+ PrecedingCert = CurrentCert;
+ PrecedingCertLen = CurrentCertLen;
+
+ //
+ // Move current certificate to next;
+ //
+ CurrentCert = CurrentCert + CurrentCertLen;
+ } while (1);
+
+ return VerifyFlag;
+}
+
+/**
+ Get one X509 certificate from CertChain.
+
+ @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
+ where the first certificate is signed by the Root
+ Certificate or is the Root Cerificate itself. and
+ subsequent cerificate is signed by the preceding
+ cerificate.
+ @param[in] CertChainLength Total length of the certificate chain, in bytes.
+
+ @param[in] CertIndex Index of certificate.
+
+ @param[out] Cert The certificate at the index of CertChain.
+ @param[out] CertLength The length certificate at the index of CertChain.
+
+ @retval TRUE Success.
+ @retval FALSE Failed to get certificate from certificate chain.
+**/
+BOOLEAN
+EFIAPI
+X509GetCertFromCertChain (
+ IN CONST UINT8 *CertChain,
+ IN UINTN CertChainLength,
+ IN CONST INT32 CertIndex,
+ OUT CONST UINT8 **Cert,
+ OUT UINTN *CertLength
+ )
+{
+ UINTN Asn1Len;
+ INT32 CurrentIndex;
+ UINTN CurrentCertLen;
+ CONST UINT8 *CurrentCert;
+ CONST UINT8 *TmpPtr;
+ INT32 Ret;
+
+ //
+ // Check input parameters.
+ //
+ if ((CertChain == NULL) || (Cert == NULL) ||
+ (CertIndex < -1) || (CertLength == NULL))
+ {
+ return FALSE;
+ }
+
+ CurrentCert = CertChain;
+ CurrentIndex = -1;
+
+ //
+ // Traverse the certificate chain
+ //
+ while (TRUE) {
+ //
+ // Get asn1 tag len
+ //
+ TmpPtr = CurrentCert;
+ Ret = mbedtls_asn1_get_tag ((UINT8 **)&TmpPtr, CertChain + CertChainLength, &Asn1Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ break;
+ }
+
+ CurrentCertLen = Asn1Len + (TmpPtr - CurrentCert);
+ CurrentIndex++;
+
+ if (CurrentIndex == CertIndex) {
+ *Cert = CurrentCert;
+ *CertLength = CurrentCertLen;
+ return TRUE;
+ }
+
+ //
+ // Move to next
+ //
+ CurrentCert = CurrentCert + CurrentCertLen;
+ }
+
+ //
+ // If CertIndex is -1, Return the last certificate
+ //
+ if ((CertIndex == -1) && (CurrentIndex >= 0)) {
+ *Cert = CurrentCert - CurrentCertLen;
+ *CertLength = CurrentCertLen;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Retrieve the TBSCertificate from one given X.509 certificate.
+
+ @param[in] Cert Pointer to the given DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] TBSCert DER-Encoded To-Be-Signed certificate.
+ @param[out] TBSCertSize Size of the TBS certificate in bytes.
+
+ If Cert is NULL, then return FALSE.
+ If TBSCert is NULL, then return FALSE.
+ If TBSCertSize is NULL, then return FALSE.
+
+ @retval TRUE The TBSCertificate was retrieved successfully.
+ @retval FALSE Invalid X.509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetTBSCert (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 **TBSCert,
+ OUT UINTN *TBSCertSize
+ )
+{
+ UINTN Length;
+ UINTN Ret;
+ UINT8 *Ptr;
+ CONST UINT8 *Temp;
+ CONST UINT8 *End;
+
+ //
+ // Check input parameters.
+ //
+ if ((Cert == NULL) || (TBSCert == NULL) ||
+ (TBSCertSize == NULL) || (CertSize > INT_MAX))
+ {
+ return FALSE;
+ }
+
+ //
+ // An X.509 Certificate is: (defined in RFC3280)
+ // Certificate ::= SEQUENCE {
+ // tbsCertificate TBSCertificate,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING }
+ //
+ // and
+ //
+ // TBSCertificate ::= SEQUENCE {
+ // version [0] Version DEFAULT v1,
+ // ...
+ // }
+ //
+ // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
+ // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
+ //
+
+ Length = 0;
+
+ Ptr = (UINT8 *)Cert;
+ End = Cert + CertSize;
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &Length, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ Temp = Ptr;
+ End = Ptr + Length;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &Length, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ *TBSCert = (UINT8 *)Temp;
+ *TBSCertSize = Length + (Ptr - Temp);
+
+ return TRUE;
+}
+
+/**
+ Retrieve the version from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertSize is 0, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] Version Pointer to the retrieved version integer.
+
+ @retval TRUE The certificate version retrieved successfully.
+ @retval FALSE If Cert is NULL or CertSize is Zero.
+ @retval FALSE The operation is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetVersion (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINTN *Version
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ *Version = Crt.version - 1;
+ ReturnStatus = TRUE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the serialNumber from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertSize is 0, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] SerialNumber Pointer to the retrieved certificate SerialNumber bytes.
+ @param[in, out] SerialNumberSize The size in bytes of the SerialNumber buffer on input,
+ and the size of buffer returned SerialNumber on output.
+
+ @retval TRUE The certificate serialNumber retrieved successfully.
+ @retval FALSE If Cert is NULL or CertSize is Zero.
+ If SerialNumberSize is NULL.
+ If Certificate is invalid.
+ @retval FALSE If no SerialNumber exists.
+ @retval FALSE If the SerialNumber is NULL. The required buffer size
+ (including the final null) is returned in the
+ SerialNumberSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetSerialNumber (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *SerialNumber OPTIONAL,
+ IN OUT UINTN *SerialNumberSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*SerialNumberSize <= Crt.serial.len) {
+ *SerialNumberSize = Crt.serial.len + 1;
+ ReturnStatus = FALSE;
+ goto Cleanup;
+ }
+
+ if (SerialNumber != NULL) {
+ CopyMem (SerialNumber, Crt.serial.p, Crt.serial.len);
+ SerialNumber[Crt.serial.len] = '\0';
+ }
+
+ *SerialNumberSize = Crt.serial.len + 1;
+ ReturnStatus = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the issuer bytes from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertIssuerSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CertIssuer Pointer to the retrieved certificate subject bytes.
+ @param[in, out] CertIssuerSize The size in bytes of the CertIssuer buffer on input,
+ and the size of buffer returned CertSubject on output.
+
+ @retval TRUE The certificate issuer retrieved successfully.
+ @retval FALSE Invalid certificate, or the CertIssuerSize is too small for the result.
+ The CertIssuerSize will be updated with the required size.
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetIssuerName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *CertIssuer,
+ IN OUT UINTN *CertIssuerSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*CertIssuerSize < Crt.serial.len) {
+ *CertIssuerSize = Crt.serial.len;
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ if (CertIssuer != NULL) {
+ CopyMem (CertIssuer, Crt.serial.p, Crt.serial.len);
+ }
+
+ *CertIssuerSize = Crt.serial.len;
+ Status = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the issuer common name (CN) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CommonName Buffer to contain the retrieved certificate issuer common
+ name string. At most CommonNameSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
+ and the size of buffer returned CommonName on output.
+ If CommonName is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate Issuer CommonName retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If CommonNameSize is NULL.
+ If CommonName is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no CommonName entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetIssuerCommonName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ return InternalX509GetIssuerNIDName (Cert, CertSize, (CHAR8 *)OID_commonName, sizeof (OID_commonName), CommonName, CommonNameSize);
+}
+
+/**
+ Retrieve the issuer organization name (O) string from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] NameBuffer Buffer to contain the retrieved certificate issuer organization
+ name string. At most NameBufferSize bytes will be
+ written and the string will be null terminated. May be
+ NULL in order to determine the size buffer needed.
+ @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,
+ and the size of buffer returned Name on output.
+ If NameBuffer is NULL then the amount of space needed
+ in buffer (including the final null) is returned.
+
+ @retval RETURN_SUCCESS The certificate issuer Organization Name retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If NameBufferSize is NULL.
+ If NameBuffer is not NULL and *CommonNameSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no Organization Name entry exists.
+ @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size
+ (including the final null) is returned in the
+ CommonNameSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+
+**/
+RETURN_STATUS
+EFIAPI
+X509GetIssuerOrganizationName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *NameBuffer OPTIONAL,
+ IN OUT UINTN *NameBufferSize
+ )
+{
+ return InternalX509GetIssuerNIDName (Cert, CertSize, (CHAR8 *)OID_organizationName, sizeof (OID_organizationName), NameBuffer, NameBufferSize);
+}
+
+/**
+ Retrieve the Signature Algorithm from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] Oid Signature Algorithm Object identifier buffer.
+ @param[in,out] OidSize Signature Algorithm Object identifier buffer size
+
+ @retval TRUE The certificate Extension data retrieved successfully.
+ @retval FALSE If Cert is NULL.
+ If OidSize is NULL.
+ If Oid is not NULL and *OidSize is 0.
+ If Certificate is invalid.
+ @retval FALSE If no SignatureType.
+ @retval FALSE If the Oid is NULL. The required buffer size
+ is returned in the OidSize.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetSignatureAlgorithm (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *Oid OPTIONAL,
+ IN OUT UINTN *OidSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if ((Cert == NULL) || (CertSize == 0) || (OidSize == NULL)) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*OidSize < Crt.sig_oid.len) {
+ *OidSize = Crt.serial.len;
+ ReturnStatus = FALSE;
+ goto Cleanup;
+ }
+
+ if (Oid != NULL) {
+ CopyMem (Oid, Crt.sig_oid.p, Crt.sig_oid.len);
+ }
+
+ *OidSize = Crt.sig_oid.len;
+ ReturnStatus = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Find first Extension data match with given OID
+
+ @param[in] Start Pointer to the DER-encoded Extensions Data
+ @param[in] End Extensions Data size in bytes
+ @param[in ] Oid OID for match
+ @param[in ] OidSize OID size in bytes
+ @param[out] FindExtensionData output matched extension data.
+ @param[out] FindExtensionDataLen matched extension data size.
+
+ **/
+STATIC
+RETURN_STATUS
+InternalX509FindExtensionData (
+ UINT8 *Start,
+ UINT8 *End,
+ CONST UINT8 *Oid,
+ UINTN OidSize,
+ UINT8 **FindExtensionData,
+ UINTN *FindExtensionDataLen
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ExtensionPtr;
+ size_t ObjLen;
+ INT32 Ret;
+ RETURN_STATUS ReturnStatus;
+ size_t FindExtensionLen;
+ size_t HeaderLen;
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ Ptr = Start;
+
+ Ret = 0;
+
+ while (TRUE) {
+ /*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ */
+ ExtensionPtr = Ptr;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret == 0) {
+ HeaderLen = (size_t)(Ptr - ExtensionPtr);
+ FindExtensionLen = ObjLen;
+ // Get Object Identifier
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID);
+ } else {
+ break;
+ }
+
+ if ((Ret == 0) && (CompareMem (Ptr, Oid, OidSize) == 0)) {
+ Ptr += ObjLen;
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_BOOLEAN);
+ if (Ret == 0) {
+ Ptr += ObjLen;
+ }
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING);
+ } else {
+ Ret = 1;
+ }
+
+ if (Ret == 0) {
+ *FindExtensionData = Ptr;
+ *FindExtensionDataLen = ObjLen;
+ ReturnStatus = RETURN_SUCCESS;
+ break;
+ }
+
+ // move to next
+ Ptr = ExtensionPtr + HeaderLen + FindExtensionLen;
+ Ret = 0;
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve Extension data from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] Oid Object identifier buffer
+ @param[in] OidSize Object identifier buffer size
+ @param[out] ExtensionData Extension bytes.
+ @param[in, out] ExtensionDataSize Extension bytes size.
+
+ @retval TRUE The certificate Extension data retrieved successfully.
+ @retval FALSE If Cert is NULL.
+ If ExtensionDataSize is NULL.
+ If ExtensionData is not NULL and *ExtensionDataSize is 0.
+ If Certificate is invalid.
+ @retval FALSE If no Extension entry match Oid.
+ @retval FALSE If the ExtensionData is NULL. The required buffer size
+ is returned in the ExtensionDataSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetExtensionData (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *Oid,
+ IN UINTN OidSize,
+ OUT UINT8 *ExtensionData,
+ IN OUT UINTN *ExtensionDataSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ RETURN_STATUS ReturnStatus;
+ BOOLEAN Status;
+ UINT8 *Ptr;
+ UINT8 *End;
+ size_t ObjLen;
+
+ if ((Cert == NULL) ||
+ (CertSize == 0) ||
+ (Oid == NULL) ||
+ (OidSize == 0) ||
+ (ExtensionDataSize == NULL))
+ {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Ptr = Crt.v3_ext.p;
+ End = Crt.v3_ext.p + Crt.v3_ext.len;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ }
+
+ if (Ret == 0) {
+ ReturnStatus = InternalX509FindExtensionData (Ptr, End, Oid, OidSize, &Ptr, &ObjLen);
+ }
+
+ if (ReturnStatus == RETURN_SUCCESS) {
+ if (*ExtensionDataSize < ObjLen) {
+ *ExtensionDataSize = ObjLen;
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ if (Oid != NULL) {
+ CopyMem (ExtensionData, Ptr, ObjLen);
+ }
+
+ *ExtensionDataSize = ObjLen;
+ Status = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Validity from one X.509 certificate
+
+ If Cert is NULL, then return FALSE.
+ If CertIssuerSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] From notBefore Pointer to DateTime object.
+ @param[in,out] FromSize notBefore DateTime object size.
+ @param[in] To notAfter Pointer to DateTime object.
+ @param[in,out] ToSize notAfter DateTime object size.
+
+ Note: X509CompareDateTime to compare DateTime oject
+ x509SetDateTime to get a DateTime object from a DateTimeStr
+
+ @retval TRUE The certificate Validity retrieved successfully.
+ @retval FALSE Invalid certificate, or Validity retrieve failed.
+ @retval FALSE This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetValidity (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN UINT8 *From,
+ IN OUT UINTN *FromSize,
+ IN UINT8 *To,
+ IN OUT UINTN *ToSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+ UINTN TSize;
+ UINTN FSize;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ FSize = sizeof (mbedtls_x509_time);
+ if (*FromSize < FSize) {
+ *FromSize = FSize;
+ goto _Exit;
+ }
+
+ *FromSize = FSize;
+ if (From != NULL) {
+ CopyMem (From, &(Crt.valid_from), FSize);
+ }
+
+ TSize = sizeof (mbedtls_x509_time);
+ if (*ToSize < TSize) {
+ *ToSize = TSize;
+ goto _Exit;
+ }
+
+ *ToSize = TSize;
+ if (To != NULL) {
+ CopyMem (To, &(Crt.valid_to), sizeof (mbedtls_x509_time));
+ }
+
+ Status = TRUE;
+ }
+
+_Exit:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Key Usage from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] Usage Key Usage (CRYPTO_X509_KU_*)
+
+ @retval TRUE The certificate Key Usage retrieved successfully.
+ @retval FALSE Invalid certificate, or Usage is NULL
+ @retval FALSE This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetKeyUsage (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINTN *Usage
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ *Usage = Crt.key_usage;
+ Status = TRUE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Extended Key Usage from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] Usage Key Usage bytes.
+ @param[in, out] UsageSize Key Usage buffer sizs in bytes.
+
+ @retval TRUE The Usage bytes retrieve successfully.
+ @retval FALSE If Cert is NULL.
+ If CertSize is NULL.
+ If Usage is not NULL and *UsageSize is 0.
+ If Cert is invalid.
+ @retval FALSE If the Usage is NULL. The required buffer size
+ is returned in the UsageSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetExtendedKeyUsage (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *Usage,
+ IN OUT UINTN *UsageSize
+ )
+{
+ BOOLEAN ReturnStatus;
+
+ if ((Cert == NULL) || (CertSize == 0) || (UsageSize == NULL)) {
+ return FALSE;
+ }
+
+ ReturnStatus = X509GetExtensionData ((UINT8 *)Cert, CertSize, (UINT8 *)OID_extKeyUsage, sizeof (OID_extKeyUsage), Usage, UsageSize);
+
+ return ReturnStatus;
+}
+
+/**
+ Compare DateTime1 object and DateTime2 object time.
+
+ @param[in] Before Pointer to a DateTime Ojbect
+ @param[in] After Pointer to a DateTime Object
+
+ @retval 0 If DateTime1 <= DateTime2
+ @retval 1 If DateTime1 > DateTime2
+**/
+STATIC
+INTN
+InternalX509CheckTime (
+ CONST mbedtls_x509_time *Before,
+ CONST mbedtls_x509_time *After
+ )
+{
+ if (Before->year > After->year) {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon > After->mon))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day > After->day))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour > After->hour))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour == After->hour) &&
+ (Before->min > After->min))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour == After->hour) &&
+ (Before->min == After->min) &&
+ (Before->sec > After->sec))
+ {
+ return (1);
+ }
+
+ return (0);
+}
+
+/**
+ change string to int.
+
+ @param[in] PStart Pointer to a string Start
+ @param[in] PEnd Pointer to a string End
+
+ @return number
+**/
+STATIC
+INT32
+InternalAtoI (
+ CHAR8 *PStart,
+ CHAR8 *PEnd
+ )
+{
+ CHAR8 *Ptr;
+ INT32 Knum;
+
+ Knum = 0;
+ Ptr = PStart;
+
+ while (Ptr < PEnd) {
+ ///
+ /// k = k * 2^3 + k * 2^1 = k * 8 + k * 2 = k * 10
+ ///
+ Knum = (Knum << 3) + (Knum << 1) + (*Ptr) - '0';
+ Ptr++;
+ }
+
+ return Knum;
+}
+
+/**
+ Format a DateTime object into DataTime Buffer
+
+ If DateTimeStr is NULL, then return FALSE.
+ If DateTimeSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ
+ Ref: https://www.w3.org/TR/NOTE-datetime
+ Z stand for UTC time
+ @param[in,out] DateTime Pointer to a DateTime object.
+ @param[in,out] DateTimeSize DateTime object buffer size.
+
+ @retval RETURN_SUCCESS The DateTime object create successfully.
+ @retval RETURN_INVALID_PARAMETER If DateTimeStr is NULL.
+ If DateTimeSize is NULL.
+ If DateTime is not NULL and *DateTimeSize is 0.
+ If Year Month Day Hour Minute Second combination is invalid datetime.
+ @retval RETURN_BUFFER_TOO_SMALL If the DateTime is NULL. The required buffer size
+ (including the final null) is returned in the
+ DateTimeSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+**/
+RETURN_STATUS
+EFIAPI
+X509SetDateTime (
+ CHAR8 *DateTimeStr,
+ IN OUT VOID *DateTime,
+ IN OUT UINTN *DateTimeSize
+ )
+{
+ mbedtls_x509_time Dt;
+
+ INT32 Year;
+ INT32 Month;
+ INT32 Day;
+ INT32 Hour;
+ INT32 Minute;
+ INT32 Second;
+ RETURN_STATUS ReturnStatus;
+ CHAR8 *Ptr;
+
+ Ptr = DateTimeStr;
+
+ Year = InternalAtoI (Ptr, Ptr + 4);
+ Ptr += 4;
+ Month = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Day = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Hour = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Minute = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Second = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Dt.year = (int)Year;
+ Dt.mon = (int)Month;
+ Dt.day = (int)Day;
+ Dt.hour = (int)Hour;
+ Dt.min = (int)Minute;
+ Dt.sec = (int)Second;
+
+ if (*DateTimeSize < sizeof (mbedtls_x509_time)) {
+ *DateTimeSize = sizeof (mbedtls_x509_time);
+ ReturnStatus = RETURN_BUFFER_TOO_SMALL;
+ goto Cleanup;
+ }
+
+ if (DateTime != NULL) {
+ CopyMem (DateTime, &Dt, sizeof (mbedtls_x509_time));
+ }
+
+ *DateTimeSize = sizeof (mbedtls_x509_time);
+ ReturnStatus = RETURN_SUCCESS;
+Cleanup:
+ return ReturnStatus;
+}
+
+/**
+ Compare DateTime1 object and DateTime2 object.
+
+ If DateTime1 is NULL, then return -2.
+ If DateTime2 is NULL, then return -2.
+ If DateTime1 == DateTime2, then return 0
+ If DateTime1 > DateTime2, then return 1
+ If DateTime1 < DateTime2, then return -1
+
+ @param[in] DateTime1 Pointer to a DateTime Ojbect
+ @param[in] DateTime2 Pointer to a DateTime Object
+
+ @retval 0 If DateTime1 == DateTime2
+ @retval 1 If DateTime1 > DateTime2
+ @retval -1 If DateTime1 < DateTime2
+**/
+INT32
+EFIAPI
+X509CompareDateTime (
+ IN CONST VOID *DateTime1,
+ IN CONST VOID *DateTime2
+ )
+{
+ if ((DateTime1 == NULL) || (DateTime2 == NULL)) {
+ return -2;
+ }
+
+ if (CompareMem (DateTime2, DateTime1, sizeof (mbedtls_x509_time)) == 0) {
+ return 0;
+ }
+
+ if (InternalX509CheckTime ((mbedtls_x509_time *)DateTime1, (mbedtls_x509_time *)DateTime2) == 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ Retrieve the basic constraints from one X.509 certificate.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize size of the X509 certificate in bytes.
+ @param[out] BasicConstraints basic constraints bytes.
+ @param[in, out] BasicConstraintsSize basic constraints buffer sizs in bytes.
+
+ @retval TRUE The basic constraints retrieve successfully.
+ @retval FALSE If cert is NULL.
+ If cert_size is NULL.
+ If basic_constraints is not NULL and *basic_constraints_size is 0.
+ If cert is invalid.
+ @retval FALSE The required buffer size is small.
+ The return buffer size is basic_constraints_size parameter.
+ @retval FALSE If no Extension entry match oid.
+ @retval FALSE The operation is not supported.
+ **/
+BOOLEAN
+EFIAPI
+X509GetExtendedBasicConstraints (
+ CONST UINT8 *Cert,
+ UINTN CertSize,
+ UINT8 *BasicConstraints,
+ UINTN *BasicConstraintsSize
+ )
+{
+ BOOLEAN Status;
+
+ if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {
+ return FALSE;
+ }
+
+ Status = X509GetExtensionData (
+ (UINT8 *)Cert,
+ CertSize,
+ OID_BasicConstraints,
+ sizeof (OID_BasicConstraints),
+ BasicConstraints,
+ BasicConstraintsSize
+ );
+
+ return Status;
+}
+
+/**
+ Format a DateTimeStr to DataTime object in DataTime Buffer
+
+ If DateTimeStr is NULL, then return FALSE.
+ If DateTimeSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ
+ Ref: https://www.w3.org/TR/NOTE-datetime
+ Z stand for UTC time
+ @param[out] DateTime Pointer to a DateTime object.
+ @param[in,out] DateTimeSize DateTime object buffer size.
+
+ @retval TRUE The DateTime object create successfully.
+ @retval FALSE If DateTimeStr is NULL.
+ If DateTimeSize is NULL.
+ If DateTime is not NULL and *DateTimeSize is 0.
+ If Year Month Day Hour Minute Second combination is invalid datetime.
+ @retval FALSE If the DateTime is NULL. The required buffer size
+ (including the final null) is returned in the
+ DateTimeSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509FormatDateTime (
+ IN CONST CHAR8 *DateTimeStr,
+ OUT VOID *DateTime,
+ IN OUT UINTN *DateTimeSize
+ )
+{
+ mbedtls_x509_time *Tm;
+
+ if (*DateTimeSize < sizeof (mbedtls_x509_time)) {
+ return FALSE;
+ }
+
+ if (DateTime == NULL) {
+ return FALSE;
+ }
+
+ Tm = (mbedtls_x509_time *)DateTime;
+
+ Tm->year = (DateTimeStr[0] + '0') * 1000 + (DateTimeStr[1] + '0') * 100 +
+ (DateTimeStr[2] + '0') * 10 + (DateTimeStr[3] + '0') * 1;
+
+ Tm->mon = (DateTimeStr[4] + '0') * 10 + (DateTimeStr[5] + '0') * 1;
+
+ Tm->day = (DateTimeStr[6] + '0') * 10 + (DateTimeStr[7] + '0') * 1;
+
+ Tm->hour = (DateTimeStr[8] + '0') * 10 + (DateTimeStr[9] + '0') * 1;
+
+ Tm->min = (DateTimeStr[10] + '0') * 10 + (DateTimeStr[11] + '0') * 1;
+
+ Tm->sec = (DateTimeStr[12] + '0') * 10 + (DateTimeStr[13] + '0') * 1;
+
+ return TRUE;
+}