2 X.509 Certificate Handler Wrapper Implementation over OpenSSL.
4 Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "InternalCryptLib.h"
10 #include <openssl/x509.h>
11 #include <openssl/x509v3.h>
12 #include <crypto/asn1.h>
13 #include <openssl/asn1.h>
14 #include <openssl/rsa.h>
17 #define OID_EXT_KEY_USAGE { 0x55, 0x1D, 0x25 }
18 #define OID_BASIC_CONSTRAINTS { 0x55, 0x1D, 0x13 }
20 static CONST UINT8 mOidExtKeyUsage
[] = OID_EXT_KEY_USAGE
;
21 static CONST UINT8 mOidBasicConstraints
[] = OID_BASIC_CONSTRAINTS
;
23 #define CRYPTO_ASN1_TAG_CLASS_MASK 0xC0
24 #define CRYPTO_ASN1_TAG_PC_MASK 0x20
25 #define CRYPTO_ASN1_TAG_VALUE_MASK 0x1F
28 Construct a X509 object from DER-encoded certificate data.
30 If Cert is NULL, then return FALSE.
31 If SingleX509Cert is NULL, then return FALSE.
33 @param[in] Cert Pointer to the DER-encoded certificate data.
34 @param[in] CertSize The size of certificate data in bytes.
35 @param[out] SingleX509Cert The generated X509 object.
37 @retval TRUE The X509 object generation succeeded.
38 @retval FALSE The operation failed.
43 X509ConstructCertificate (
46 OUT UINT8
**SingleX509Cert
53 // Check input parameters.
55 if ((Cert
== NULL
) || (SingleX509Cert
== NULL
) || (CertSize
> INT_MAX
)) {
60 // Read DER-encoded X509 Certificate and Construct X509 object.
63 X509Cert
= d2i_X509 (NULL
, &Temp
, (long)CertSize
);
64 if (X509Cert
== NULL
) {
68 *SingleX509Cert
= (UINT8
*)X509Cert
;
74 Construct a X509 stack object from a list of DER-encoded certificate data.
76 If X509Stack is NULL, then return FALSE.
77 If this interface is not supported, then return FALSE.
79 @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
80 On output, pointer to the X509 stack object with new
81 inserted X509 certificate.
82 @param[in] Args VA_LIST marker for the variable argument list.
83 A list of DER-encoded single certificate data followed
84 by certificate size. A NULL terminates the list. The
85 pairs are the arguments to X509ConstructCertificate().
87 @retval TRUE The X509 stack construction succeeded.
88 @retval FALSE The construction operation failed.
89 @retval FALSE This interface is not supported.
94 X509ConstructCertificateStackV (
95 IN OUT UINT8
**X509Stack
,
103 STACK_OF (X509
) *CertStack
;
108 // Check input parameters.
110 if (X509Stack
== NULL
) {
117 // Initialize X509 stack object.
119 CertStack
= (STACK_OF (X509
) *)(*X509Stack
);
120 if (CertStack
== NULL
) {
121 CertStack
= sk_X509_new_null ();
122 if (CertStack
== NULL
) {
127 for (Index
= 0; ; Index
++) {
129 // If Cert is NULL, then it is the end of the list.
131 Cert
= VA_ARG (Args
, UINT8
*);
136 CertSize
= VA_ARG (Args
, UINTN
);
142 // Construct X509 Object from the given DER-encoded certificate data.
145 Status
= X509ConstructCertificate (
151 if (X509Cert
!= NULL
) {
152 X509_free (X509Cert
);
159 // Insert the new X509 object into X509 stack object.
161 sk_X509_push (CertStack
, X509Cert
);
165 sk_X509_pop_free (CertStack
, X509_free
);
167 *X509Stack
= (UINT8
*)CertStack
;
174 Construct a X509 stack object from a list of DER-encoded certificate data.
176 If X509Stack is NULL, then return FALSE.
178 @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.
179 On output, pointer to the X509 stack object with new
180 inserted X509 certificate.
181 @param ... A list of DER-encoded single certificate data followed
182 by certificate size. A NULL terminates the list. The
183 pairs are the arguments to X509ConstructCertificate().
185 @retval TRUE The X509 stack construction succeeded.
186 @retval FALSE The construction operation failed.
191 X509ConstructCertificateStack (
192 IN OUT UINT8
**X509Stack
,
199 VA_START (Args
, X509Stack
);
200 Result
= X509ConstructCertificateStackV (X509Stack
, Args
);
206 Release the specified X509 object.
208 If X509Cert is NULL, then return FALSE.
210 @param[in] X509Cert Pointer to the X509 object to be released.
220 // Check input parameters.
222 if (X509Cert
== NULL
) {
227 // Free OpenSSL X509 object.
229 X509_free ((X509
*)X509Cert
);
233 Release the specified X509 stack object.
235 If X509Stack is NULL, then return FALSE.
237 @param[in] X509Stack Pointer to the X509 stack object to be released.
247 // Check input parameters.
249 if (X509Stack
== NULL
) {
254 // Free OpenSSL X509 stack object.
256 sk_X509_pop_free ((STACK_OF (X509
) *) X509Stack
, X509_free
);
260 Retrieve the subject bytes from one X.509 certificate.
262 @param[in] Cert Pointer to the DER-encoded X509 certificate.
263 @param[in] CertSize Size of the X509 certificate in bytes.
264 @param[out] CertSubject Pointer to the retrieved certificate subject bytes.
265 @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input,
266 and the size of buffer returned CertSubject on output.
268 If Cert is NULL, then return FALSE.
269 If SubjectSize is NULL, then return FALSE.
271 @retval TRUE The certificate subject retrieved successfully.
272 @retval FALSE Invalid certificate, or the SubjectSize is too small for the result.
273 The SubjectSize will be updated with the required size.
279 IN CONST UINT8
*Cert
,
281 OUT UINT8
*CertSubject
,
282 IN OUT UINTN
*SubjectSize
291 // Check input parameters.
293 if ((Cert
== NULL
) || (SubjectSize
== NULL
)) {
300 // Read DER-encoded X509 Certificate and Construct X509 object.
302 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
303 if ((X509Cert
== NULL
) || (!Status
)) {
311 // Retrieve subject name from certificate object.
313 X509Name
= X509_get_subject_name (X509Cert
);
314 if (X509Name
== NULL
) {
318 X509NameSize
= i2d_X509_NAME (X509Name
, NULL
);
319 if (*SubjectSize
< X509NameSize
) {
320 *SubjectSize
= X509NameSize
;
324 *SubjectSize
= X509NameSize
;
325 if (CertSubject
!= NULL
) {
326 i2d_X509_NAME (X509Name
, &CertSubject
);
332 // Release Resources.
334 if (X509Cert
!= NULL
) {
335 X509_free (X509Cert
);
342 Retrieve a string from one X.509 certificate base on the Request_NID.
344 @param[in] Cert Pointer to the DER-encoded X509 certificate.
345 @param[in] CertSize Size of the X509 certificate in bytes.
346 @param[in] Request_NID NID of string to obtain
347 @param[out] CommonName Buffer to contain the retrieved certificate common
348 name string (UTF8). At most CommonNameSize bytes will be
349 written and the string will be null terminated. May be
350 NULL in order to determine the size buffer needed.
351 @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
352 and the size of buffer returned CommonName on output.
353 If CommonName is NULL then the amount of space needed
354 in buffer (including the final null) is returned.
356 @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
357 @retval RETURN_INVALID_PARAMETER If Cert is NULL.
358 If CommonNameSize is NULL.
359 If CommonName is not NULL and *CommonNameSize is 0.
360 If Certificate is invalid.
361 @retval RETURN_NOT_FOUND If no NID Name entry exists.
362 @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
363 (including the final null) is returned in the
364 CommonNameSize parameter.
365 @retval RETURN_UNSUPPORTED The operation is not supported.
370 InternalX509GetNIDName (
371 IN CONST UINT8
*Cert
,
373 IN INT32 Request_NID
,
374 OUT CHAR8
*CommonName OPTIONAL
,
375 IN OUT UINTN
*CommonNameSize
378 RETURN_STATUS ReturnStatus
;
384 X509_NAME_ENTRY
*Entry
;
385 ASN1_STRING
*EntryData
;
388 ReturnStatus
= RETURN_INVALID_PARAMETER
;
392 // Check input parameters.
394 if ((Cert
== NULL
) || (CertSize
> INT_MAX
) || (CommonNameSize
== NULL
)) {
398 if ((CommonName
!= NULL
) && (*CommonNameSize
== 0)) {
404 // Read DER-encoded X509 Certificate and Construct X509 object.
406 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
407 if ((X509Cert
== NULL
) || (!Status
)) {
409 // Invalid X.509 Certificate
417 // Retrieve subject name from certificate object.
419 X509Name
= X509_get_subject_name (X509Cert
);
420 if (X509Name
== NULL
) {
422 // Fail to retrieve subject name content
428 // Retrive the string from X.509 Subject base on the Request_NID
430 Index
= X509_NAME_get_index_by_NID (X509Name
, Request_NID
, -1);
433 // No Request_NID name entry exists in X509_NAME object
436 ReturnStatus
= RETURN_NOT_FOUND
;
440 Entry
= X509_NAME_get_entry (X509Name
, Index
);
443 // Fail to retrieve name entry data
446 ReturnStatus
= RETURN_NOT_FOUND
;
450 EntryData
= X509_NAME_ENTRY_get_data (Entry
);
452 Length
= ASN1_STRING_to_UTF8 (&UTF8Name
, EntryData
);
455 // Fail to convert the Name string
458 ReturnStatus
= RETURN_INVALID_PARAMETER
;
462 if (CommonName
== NULL
) {
463 *CommonNameSize
= Length
+ 1;
464 ReturnStatus
= RETURN_BUFFER_TOO_SMALL
;
466 *CommonNameSize
= MIN ((UINTN
)Length
, *CommonNameSize
- 1) + 1;
467 CopyMem (CommonName
, UTF8Name
, *CommonNameSize
- 1);
468 CommonName
[*CommonNameSize
- 1] = '\0';
469 ReturnStatus
= RETURN_SUCCESS
;
474 // Release Resources.
476 if (X509Cert
!= NULL
) {
477 X509_free (X509Cert
);
480 if (UTF8Name
!= NULL
) {
481 OPENSSL_free (UTF8Name
);
488 Retrieve the common name (CN) string from one X.509 certificate.
490 @param[in] Cert Pointer to the DER-encoded X509 certificate.
491 @param[in] CertSize Size of the X509 certificate in bytes.
492 @param[out] CommonName Buffer to contain the retrieved certificate common
493 name string. At most CommonNameSize bytes will be
494 written and the string will be null terminated. May be
495 NULL in order to determine the size buffer needed.
496 @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,
497 and the size of buffer returned CommonName on output.
498 If CommonName is NULL then the amount of space needed
499 in buffer (including the final null) is returned.
501 @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.
502 @retval RETURN_INVALID_PARAMETER If Cert is NULL.
503 If CommonNameSize is NULL.
504 If CommonName is not NULL and *CommonNameSize is 0.
505 If Certificate is invalid.
506 @retval RETURN_NOT_FOUND If no CommonName entry exists.
507 @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size
508 (including the final null) is returned in the
509 CommonNameSize parameter.
510 @retval RETURN_UNSUPPORTED The operation is not supported.
516 IN CONST UINT8
*Cert
,
518 OUT CHAR8
*CommonName OPTIONAL
,
519 IN OUT UINTN
*CommonNameSize
522 return InternalX509GetNIDName (Cert
, CertSize
, NID_commonName
, CommonName
, CommonNameSize
);
526 Retrieve the organization name (O) string from one X.509 certificate.
528 @param[in] Cert Pointer to the DER-encoded X509 certificate.
529 @param[in] CertSize Size of the X509 certificate in bytes.
530 @param[out] NameBuffer Buffer to contain the retrieved certificate organization
531 name string. At most NameBufferSize bytes will be
532 written and the string will be null terminated. May be
533 NULL in order to determine the size buffer needed.
534 @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,
535 and the size of buffer returned Name on output.
536 If NameBuffer is NULL then the amount of space needed
537 in buffer (including the final null) is returned.
539 @retval RETURN_SUCCESS The certificate Organization Name retrieved successfully.
540 @retval RETURN_INVALID_PARAMETER If Cert is NULL.
541 If NameBufferSize is NULL.
542 If NameBuffer is not NULL and *CommonNameSize is 0.
543 If Certificate is invalid.
544 @retval RETURN_NOT_FOUND If no Organization Name entry exists.
545 @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size
546 (including the final null) is returned in the
547 CommonNameSize parameter.
548 @retval RETURN_UNSUPPORTED The operation is not supported.
553 X509GetOrganizationName (
554 IN CONST UINT8
*Cert
,
556 OUT CHAR8
*NameBuffer OPTIONAL
,
557 IN OUT UINTN
*NameBufferSize
560 return InternalX509GetNIDName (Cert
, CertSize
, NID_organizationName
, NameBuffer
, NameBufferSize
);
564 Retrieve the RSA Public Key from one DER-encoded X509 certificate.
566 @param[in] Cert Pointer to the DER-encoded X509 certificate.
567 @param[in] CertSize Size of the X509 certificate in bytes.
568 @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved
569 RSA public key component. Use RsaFree() function to free the
572 If Cert is NULL, then return FALSE.
573 If RsaContext is NULL, then return FALSE.
575 @retval TRUE RSA Public Key was retrieved successfully.
576 @retval FALSE Fail to retrieve RSA public key from X509 certificate.
581 RsaGetPublicKeyFromX509 (
582 IN CONST UINT8
*Cert
,
584 OUT VOID
**RsaContext
592 // Check input parameters.
594 if ((Cert
== NULL
) || (RsaContext
== NULL
)) {
602 // Read DER-encoded X509 Certificate and Construct X509 object.
604 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
605 if ((X509Cert
== NULL
) || (!Status
)) {
613 // Retrieve and check EVP_PKEY data from X509 Certificate.
615 Pkey
= X509_get_pubkey (X509Cert
);
616 if ((Pkey
== NULL
) || (EVP_PKEY_id (Pkey
) != EVP_PKEY_RSA
)) {
621 // Duplicate RSA Context from the retrieved EVP_PKEY.
623 if ((*RsaContext
= RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey
))) != NULL
) {
629 // Release Resources.
631 if (X509Cert
!= NULL
) {
632 X509_free (X509Cert
);
636 EVP_PKEY_free (Pkey
);
643 Verify one X509 certificate was issued by the trusted CA.
645 @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified.
646 @param[in] CertSize Size of the X509 certificate in bytes.
647 @param[in] CACert Pointer to the DER-encoded trusted CA certificate.
648 @param[in] CACertSize Size of the CA Certificate in bytes.
650 If Cert is NULL, then return FALSE.
651 If CACert is NULL, then return FALSE.
653 @retval TRUE The certificate was issued by the trusted CA.
654 @retval FALSE Invalid certificate or the certificate was not issued by the given
661 IN CONST UINT8
*Cert
,
663 IN CONST UINT8
*CACert
,
670 X509_STORE
*CertStore
;
671 X509_STORE_CTX
*CertCtx
;
674 // Check input parameters.
676 if ((Cert
== NULL
) || (CACert
== NULL
)) {
687 // Register & Initialize necessary digest algorithms for certificate verification.
689 if (EVP_add_digest (EVP_md5 ()) == 0) {
693 if (EVP_add_digest (EVP_sha1 ()) == 0) {
697 if (EVP_add_digest (EVP_sha256 ()) == 0) {
702 // Read DER-encoded certificate to be verified and Construct X509 object.
704 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
705 if ((X509Cert
== NULL
) || (!Status
)) {
711 // Read DER-encoded root certificate and Construct X509 object.
713 Status
= X509ConstructCertificate (CACert
, CACertSize
, (UINT8
**)&X509CACert
);
714 if ((X509CACert
== NULL
) || (!Status
)) {
722 // Set up X509 Store for trusted certificate.
724 CertStore
= X509_STORE_new ();
725 if (CertStore
== NULL
) {
729 if (!(X509_STORE_add_cert (CertStore
, X509CACert
))) {
734 // Allow partial certificate chains, terminated by a non-self-signed but
735 // still trusted intermediate certificate. Also disable time checks.
737 X509_STORE_set_flags (
739 X509_V_FLAG_PARTIAL_CHAIN
| X509_V_FLAG_NO_CHECK_TIME
743 // Set up X509_STORE_CTX for the subsequent verification operation.
745 CertCtx
= X509_STORE_CTX_new ();
746 if (CertCtx
== NULL
) {
750 if (!X509_STORE_CTX_init (CertCtx
, CertStore
, X509Cert
, NULL
)) {
755 // X509 Certificate Verification.
757 Status
= (BOOLEAN
)X509_verify_cert (CertCtx
);
758 X509_STORE_CTX_cleanup (CertCtx
);
762 // Release Resources.
764 if (X509Cert
!= NULL
) {
765 X509_free (X509Cert
);
768 if (X509CACert
!= NULL
) {
769 X509_free (X509CACert
);
772 if (CertStore
!= NULL
) {
773 X509_STORE_free (CertStore
);
776 X509_STORE_CTX_free (CertCtx
);
782 Retrieve the TBSCertificate from one given X.509 certificate.
784 @param[in] Cert Pointer to the given DER-encoded X509 certificate.
785 @param[in] CertSize Size of the X509 certificate in bytes.
786 @param[out] TBSCert DER-Encoded To-Be-Signed certificate.
787 @param[out] TBSCertSize Size of the TBS certificate in bytes.
789 If Cert is NULL, then return FALSE.
790 If TBSCert is NULL, then return FALSE.
791 If TBSCertSize is NULL, then return FALSE.
793 @retval TRUE The TBSCertificate was retrieved successfully.
794 @retval FALSE Invalid X.509 certificate.
800 IN CONST UINT8
*Cert
,
803 OUT UINTN
*TBSCertSize
812 // Check input parameters.
814 if ((Cert
== NULL
) || (TBSCert
== NULL
) ||
815 (TBSCertSize
== NULL
) || (CertSize
> INT_MAX
))
821 // An X.509 Certificate is: (defined in RFC3280)
822 // Certificate ::= SEQUENCE {
823 // tbsCertificate TBSCertificate,
824 // signatureAlgorithm AlgorithmIdentifier,
825 // signature BIT STRING }
829 // TBSCertificate ::= SEQUENCE {
830 // version [0] Version DEFAULT v1,
834 // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
835 // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
839 ASN1_get_object (&Temp
, (long *)&Length
, (int *)&Asn1Tag
, (int *)&ObjClass
, (long)CertSize
);
841 if (Asn1Tag
!= V_ASN1_SEQUENCE
) {
845 *TBSCert
= (UINT8
*)Temp
;
847 ASN1_get_object (&Temp
, (long *)&Length
, (int *)&Asn1Tag
, (int *)&ObjClass
, (long)Length
);
849 // Verify the parsed TBSCertificate is one correct SEQUENCE data.
851 if (Asn1Tag
!= V_ASN1_SEQUENCE
) {
855 *TBSCertSize
= Length
+ (Temp
- *TBSCert
);
861 Retrieve the EC Public Key from one DER-encoded X509 certificate.
863 @param[in] Cert Pointer to the DER-encoded X509 certificate.
864 @param[in] CertSize Size of the X509 certificate in bytes.
865 @param[out] EcContext Pointer to new-generated EC DSA context which contain the retrieved
866 EC public key component. Use EcFree() function to free the
869 If Cert is NULL, then return FALSE.
870 If EcContext is NULL, then return FALSE.
872 @retval TRUE EC Public Key was retrieved successfully.
873 @retval FALSE Fail to retrieve EC public key from X509 certificate.
878 EcGetPublicKeyFromX509 (
879 IN CONST UINT8
*Cert
,
884 #if FixedPcdGetBool (PcdOpensslEcEnabled)
890 // Check input parameters.
892 if ((Cert
== NULL
) || (EcContext
== NULL
)) {
900 // Read DER-encoded X509 Certificate and Construct X509 object.
902 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
903 if ((X509Cert
== NULL
) || (!Status
)) {
911 // Retrieve and check EVP_PKEY data from X509 Certificate.
913 Pkey
= X509_get_pubkey (X509Cert
);
914 if ((Pkey
== NULL
) || (EVP_PKEY_id (Pkey
) != EVP_PKEY_EC
)) {
919 // Duplicate EC Context from the retrieved EVP_PKEY.
921 if ((*EcContext
= EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey
))) != NULL
) {
927 // Release Resources.
929 if (X509Cert
!= NULL
) {
930 X509_free (X509Cert
);
934 EVP_PKEY_free (Pkey
);
944 Retrieve the version from one X.509 certificate.
946 If Cert is NULL, then return FALSE.
947 If CertSize is 0, then return FALSE.
948 If this interface is not supported, then return FALSE.
950 @param[in] Cert Pointer to the DER-encoded X509 certificate.
951 @param[in] CertSize Size of the X509 certificate in bytes.
952 @param[out] Version Pointer to the retrieved version integer.
954 @retval TRUE The certificate version retrieved successfully.
955 @retval FALSE If Cert is NULL or CertSize is Zero.
956 @retval FALSE The operation is not supported.
962 IN CONST UINT8
*Cert
,
971 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
972 if ((X509Cert
== NULL
) || (!Status
)) {
974 // Invalid X.509 Certificate
980 *Version
= X509_get_version (X509Cert
);
983 if (X509Cert
!= NULL
) {
984 X509_free (X509Cert
);
991 Retrieve the serialNumber from one X.509 certificate.
993 If Cert is NULL, then return FALSE.
994 If CertSize is 0, then return FALSE.
995 If this interface is not supported, then return FALSE.
997 @param[in] Cert Pointer to the DER-encoded X509 certificate.
998 @param[in] CertSize Size of the X509 certificate in bytes.
999 @param[out] SerialNumber Pointer to the retrieved certificate SerialNumber bytes.
1000 @param[in, out] SerialNumberSize The size in bytes of the SerialNumber buffer on input,
1001 and the size of buffer returned SerialNumber on output.
1003 @retval TRUE The certificate serialNumber retrieved successfully.
1004 @retval FALSE If Cert is NULL or CertSize is Zero.
1005 If SerialNumberSize is NULL.
1006 If Certificate is invalid.
1007 @retval FALSE If no SerialNumber exists.
1008 @retval FALSE If the SerialNumber is NULL. The required buffer size
1009 (including the final null) is returned in the
1010 SerialNumberSize parameter.
1011 @retval FALSE The operation is not supported.
1015 X509GetSerialNumber (
1016 IN CONST UINT8
*Cert
,
1018 OUT UINT8
*SerialNumber
, OPTIONAL
1019 IN OUT UINTN
*SerialNumberSize
1024 ASN1_INTEGER
*Asn1Integer
;
1028 // Check input parameters.
1030 if ((Cert
== NULL
) || (SerialNumberSize
== NULL
)) {
1037 // Read DER-encoded X509 Certificate and Construct X509 object.
1039 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1040 if ((X509Cert
== NULL
) || (!Status
)) {
1041 *SerialNumberSize
= 0;
1047 // Retrieve subject name from certificate object.
1049 Asn1Integer
= X509_get_serialNumber (X509Cert
);
1050 if (Asn1Integer
== NULL
) {
1051 *SerialNumberSize
= 0;
1056 if (*SerialNumberSize
< (UINTN
)Asn1Integer
->length
) {
1057 *SerialNumberSize
= (UINTN
)Asn1Integer
->length
;
1062 if (SerialNumber
!= NULL
) {
1063 CopyMem (SerialNumber
, Asn1Integer
->data
, *SerialNumberSize
);
1067 *SerialNumberSize
= (UINTN
)Asn1Integer
->length
;
1071 // Release Resources.
1073 if (X509Cert
!= NULL
) {
1074 X509_free (X509Cert
);
1081 Retrieve the issuer bytes from one X.509 certificate.
1083 If Cert is NULL, then return FALSE.
1084 If CertIssuerSize is NULL, then return FALSE.
1085 If this interface is not supported, then return FALSE.
1087 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1088 @param[in] CertSize Size of the X509 certificate in bytes.
1089 @param[out] CertIssuer Pointer to the retrieved certificate subject bytes.
1090 @param[in, out] CertIssuerSize The size in bytes of the CertIssuer buffer on input,
1091 and the size of buffer returned CertSubject on output.
1093 @retval TRUE The certificate issuer retrieved successfully.
1094 @retval FALSE Invalid certificate, or the CertIssuerSize is too small for the result.
1095 The CertIssuerSize will be updated with the required size.
1096 @retval FALSE This interface is not supported.
1102 IN CONST UINT8
*Cert
,
1104 OUT UINT8
*CertIssuer
,
1105 IN OUT UINTN
*CertIssuerSize
1110 X509_NAME
*X509Name
;
1114 // Check input parameters.
1116 if ((Cert
== NULL
) || (CertIssuerSize
== NULL
)) {
1123 // Read DER-encoded X509 Certificate and Construct X509 object.
1125 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1126 if ((X509Cert
== NULL
) || (!Status
)) {
1134 // Retrieve subject name from certificate object.
1136 X509Name
= X509_get_subject_name (X509Cert
);
1137 if (X509Name
== NULL
) {
1141 X509NameSize
= i2d_X509_NAME (X509Name
, NULL
);
1142 if (*CertIssuerSize
< X509NameSize
) {
1143 *CertIssuerSize
= X509NameSize
;
1147 *CertIssuerSize
= X509NameSize
;
1148 if (CertIssuer
!= NULL
) {
1149 i2d_X509_NAME (X509Name
, &CertIssuer
);
1155 // Release Resources.
1157 if (X509Cert
!= NULL
) {
1158 X509_free (X509Cert
);
1165 Retrieve the Signature Algorithm from one X.509 certificate.
1167 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1168 @param[in] CertSize Size of the X509 certificate in bytes.
1169 @param[out] Oid Signature Algorithm Object identifier buffer.
1170 @param[in,out] OidSize Signature Algorithm Object identifier buffer size
1172 @retval TRUE The certificate Extension data retrieved successfully.
1173 @retval FALSE If Cert is NULL.
1175 If Oid is not NULL and *OidSize is 0.
1176 If Certificate is invalid.
1177 @retval FALSE If no SignatureType.
1178 @retval FALSE If the Oid is NULL. The required buffer size
1179 is returned in the OidSize.
1180 @retval FALSE The operation is not supported.
1184 X509GetSignatureAlgorithm (
1185 IN CONST UINT8
*Cert
,
1187 OUT UINT8
*Oid
, OPTIONAL
1188 IN OUT UINTN
*OidSize
1194 ASN1_OBJECT
*Asn1Obj
;
1197 // Check input parameters.
1199 if ((Cert
== NULL
) || (OidSize
== NULL
) || (CertSize
== 0)) {
1207 // Read DER-encoded X509 Certificate and Construct X509 object.
1209 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1210 if ((X509Cert
== NULL
) || (!Status
)) {
1216 // Retrieve subject name from certificate object.
1218 Nid
= X509_get_signature_nid (X509Cert
);
1219 if (Nid
== NID_undef
) {
1225 Asn1Obj
= OBJ_nid2obj (Nid
);
1226 if (Asn1Obj
== NULL
) {
1232 if (*OidSize
< (UINTN
)Asn1Obj
->length
) {
1233 *OidSize
= Asn1Obj
->length
;
1239 CopyMem (Oid
, Asn1Obj
->data
, Asn1Obj
->length
);
1242 *OidSize
= Asn1Obj
->length
;
1247 // Release Resources.
1249 if (X509Cert
!= NULL
) {
1250 X509_free (X509Cert
);
1257 Retrieve Extension data from one X.509 certificate.
1259 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1260 @param[in] CertSize Size of the X509 certificate in bytes.
1261 @param[in] Oid Object identifier buffer
1262 @param[in] OidSize Object identifier buffer size
1263 @param[out] ExtensionData Extension bytes.
1264 @param[in, out] ExtensionDataSize Extension bytes size.
1266 @retval TRUE The certificate Extension data retrieved successfully.
1267 @retval FALSE If Cert is NULL.
1268 If ExtensionDataSize is NULL.
1269 If ExtensionData is not NULL and *ExtensionDataSize is 0.
1270 If Certificate is invalid.
1271 @retval FALSE If no Extension entry match Oid.
1272 @retval FALSE If the ExtensionData is NULL. The required buffer size
1273 is returned in the ExtensionDataSize parameter.
1274 @retval FALSE The operation is not supported.
1278 X509GetExtensionData (
1279 IN CONST UINT8
*Cert
,
1281 IN CONST UINT8
*Oid
,
1283 OUT UINT8
*ExtensionData
,
1284 IN OUT UINTN
*ExtensionDataSize
1291 CONST
STACK_OF (X509_EXTENSION
) *Extensions
;
1292 ASN1_OBJECT
*Asn1Obj
;
1293 ASN1_OCTET_STRING
*Asn1Oct
;
1294 X509_EXTENSION
*Ext
;
1299 // Check input parameters.
1301 if ((Cert
== NULL
) || (CertSize
== 0) || (Oid
== NULL
) || (OidSize
== 0) || (ExtensionDataSize
== NULL
)) {
1309 // Read DER-encoded X509 Certificate and Construct X509 object.
1311 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1312 if ((X509Cert
== NULL
) || (!Status
)) {
1313 *ExtensionDataSize
= 0;
1318 // Retrieve Extensions from certificate object.
1320 Extensions
= X509_get0_extensions (X509Cert
);
1321 if (sk_X509_EXTENSION_num (Extensions
) <= 0) {
1322 *ExtensionDataSize
= 0;
1327 // Traverse Extensions
1332 for (i
= 0; i
< sk_X509_EXTENSION_num (Extensions
); i
++) {
1333 Ext
= sk_X509_EXTENSION_value (Extensions
, (int)i
);
1338 Asn1Obj
= X509_EXTENSION_get_object (Ext
);
1339 if (Asn1Obj
== NULL
) {
1343 Asn1Oct
= X509_EXTENSION_get_data (Ext
);
1344 if (Asn1Oct
== NULL
) {
1348 ObjLength
= OBJ_length (Asn1Obj
);
1349 OctLength
= ASN1_STRING_length (Asn1Oct
);
1350 if ((OidSize
== ObjLength
) && (CompareMem (OBJ_get0_data (Asn1Obj
), Oid
, OidSize
) == 0)) {
1359 // reset to 0 if not found
1365 if (*ExtensionDataSize
< OctLength
) {
1366 *ExtensionDataSize
= OctLength
;
1371 if (Asn1Oct
!= NULL
) {
1372 CopyMem (ExtensionData
, ASN1_STRING_get0_data (Asn1Oct
), OctLength
);
1375 *ExtensionDataSize
= OctLength
;
1377 *ExtensionDataSize
= 0;
1382 // Release Resources.
1384 if (X509Cert
!= NULL
) {
1385 X509_free (X509Cert
);
1392 Retrieve the Extended Key Usage from one X.509 certificate.
1394 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1395 @param[in] CertSize Size of the X509 certificate in bytes.
1396 @param[out] Usage Key Usage bytes.
1397 @param[in, out] UsageSize Key Usage buffer sizs in bytes.
1399 @retval TRUE The Usage bytes retrieve successfully.
1400 @retval FALSE If Cert is NULL.
1401 If CertSize is NULL.
1402 If Usage is not NULL and *UsageSize is 0.
1404 @retval FALSE If the Usage is NULL. The required buffer size
1405 is returned in the UsageSize parameter.
1406 @retval FALSE The operation is not supported.
1410 X509GetExtendedKeyUsage (
1411 IN CONST UINT8
*Cert
,
1414 IN OUT UINTN
*UsageSize
1419 Status
= X509GetExtensionData (Cert
, CertSize
, mOidExtKeyUsage
, sizeof (mOidExtKeyUsage
), Usage
, UsageSize
);
1424 Retrieve the Validity from one X.509 certificate
1426 If Cert is NULL, then return FALSE.
1427 If CertIssuerSize is NULL, then return FALSE.
1428 If this interface is not supported, then return FALSE.
1430 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1431 @param[in] CertSize Size of the X509 certificate in bytes.
1432 @param[out] From notBefore Pointer to DateTime object.
1433 @param[in,out] FromSize notBefore DateTime object size.
1434 @param[out] To notAfter Pointer to DateTime object.
1435 @param[in,out] ToSize notAfter DateTime object size.
1437 Note: X509CompareDateTime to compare DateTime oject
1438 x509SetDateTime to get a DateTime object from a DateTimeStr
1440 @retval TRUE The certificate Validity retrieved successfully.
1441 @retval FALSE Invalid certificate, or Validity retrieve failed.
1442 @retval FALSE This interface is not supported.
1447 IN CONST UINT8
*Cert
,
1450 IN OUT UINTN
*FromSize
,
1452 IN OUT UINTN
*ToSize
1463 // Check input parameters.
1465 if ((Cert
== NULL
) || (FromSize
== NULL
) || (ToSize
== NULL
) || (CertSize
== 0)) {
1473 // Read DER-encoded X509 Certificate and Construct X509 object.
1475 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1476 if ((X509Cert
== NULL
) || (!Status
)) {
1481 // Retrieve Validity from/to from certificate object.
1483 F
= X509_get0_notBefore (X509Cert
);
1484 T
= X509_get0_notAfter (X509Cert
);
1486 if ((F
== NULL
) || (T
== NULL
)) {
1490 FSize
= sizeof (ASN1_TIME
) + F
->length
;
1491 if (*FromSize
< FSize
) {
1498 CopyMem (From
, F
, sizeof (ASN1_TIME
));
1499 ((ASN1_TIME
*)From
)->data
= From
+ sizeof (ASN1_TIME
);
1500 CopyMem (From
+ sizeof (ASN1_TIME
), F
->data
, F
->length
);
1503 TSize
= sizeof (ASN1_TIME
) + T
->length
;
1504 if (*ToSize
< TSize
) {
1511 CopyMem (To
, T
, sizeof (ASN1_TIME
));
1512 ((ASN1_TIME
*)To
)->data
= To
+ sizeof (ASN1_TIME
);
1513 CopyMem (To
+ sizeof (ASN1_TIME
), T
->data
, T
->length
);
1520 // Release Resources.
1522 if (X509Cert
!= NULL
) {
1523 X509_free (X509Cert
);
1530 Format a DateTimeStr to DataTime object in DataTime Buffer
1532 If DateTimeStr is NULL, then return FALSE.
1533 If DateTimeSize is NULL, then return FALSE.
1534 If this interface is not supported, then return FALSE.
1536 @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ
1537 Ref: https://www.w3.org/TR/NOTE-datetime
1538 Z stand for UTC time
1539 @param[out] DateTime Pointer to a DateTime object.
1540 @param[in,out] DateTimeSize DateTime object buffer size.
1542 @retval TRUE The DateTime object create successfully.
1543 @retval FALSE If DateTimeStr is NULL.
1544 If DateTimeSize is NULL.
1545 If DateTime is not NULL and *DateTimeSize is 0.
1546 If Year Month Day Hour Minute Second combination is invalid datetime.
1547 @retval FALSE If the DateTime is NULL. The required buffer size
1548 (including the final null) is returned in the
1549 DateTimeSize parameter.
1550 @retval FALSE The operation is not supported.
1554 X509FormatDateTime (
1555 IN CONST CHAR8
*DateTimeStr
,
1557 IN OUT UINTN
*DateTimeSize
1568 Dt
= ASN1_TIME_new ();
1574 Ret
= ASN1_TIME_set_string_X509 (Dt
, DateTimeStr
);
1580 DSize
= sizeof (ASN1_TIME
) + Dt
->length
;
1581 if (*DateTimeSize
< DSize
) {
1582 *DateTimeSize
= DSize
;
1587 *DateTimeSize
= DSize
;
1588 if (DateTime
!= NULL
) {
1589 CopyMem (DateTime
, Dt
, sizeof (ASN1_TIME
));
1590 ((ASN1_TIME
*)DateTime
)->data
= (UINT8
*)DateTime
+ sizeof (ASN1_TIME
);
1591 CopyMem ((UINT8
*)DateTime
+ sizeof (ASN1_TIME
), Dt
->data
, Dt
->length
);
1598 ASN1_TIME_free (Dt
);
1605 Compare DateTime1 object and DateTime2 object.
1607 If DateTime1 is NULL, then return -2.
1608 If DateTime2 is NULL, then return -2.
1609 If DateTime1 == DateTime2, then return 0
1610 If DateTime1 > DateTime2, then return 1
1611 If DateTime1 < DateTime2, then return -1
1613 @param[in] DateTime1 Pointer to a DateTime Ojbect
1614 @param[in] DateTime2 Pointer to a DateTime Object
1616 @retval 0 If DateTime1 == DateTime2
1617 @retval 1 If DateTime1 > DateTime2
1618 @retval -1 If DateTime1 < DateTime2
1622 X509CompareDateTime (
1623 IN CONST VOID
*DateTime1
,
1624 IN CONST VOID
*DateTime2
1627 return (INT32
)ASN1_TIME_compare (DateTime1
, DateTime2
);
1631 Retrieve the Key Usage from one X.509 certificate.
1633 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1634 @param[in] CertSize Size of the X509 certificate in bytes.
1635 @param[out] Usage Key Usage (CRYPTO_X509_KU_*)
1637 @retval TRUE The certificate Key Usage retrieved successfully.
1638 @retval FALSE Invalid certificate, or Usage is NULL
1639 @retval FALSE This interface is not supported.
1644 IN CONST UINT8
*Cert
,
1653 // Check input parameters.
1655 if ((Cert
== NULL
) || (Usage
== NULL
)) {
1663 // Read DER-encoded X509 Certificate and Construct X509 object.
1665 Status
= X509ConstructCertificate (Cert
, CertSize
, (UINT8
**)&X509Cert
);
1666 if ((X509Cert
== NULL
) || (!Status
)) {
1671 // Retrieve subject name from certificate object.
1673 *Usage
= X509_get_key_usage (X509Cert
);
1674 if (*Usage
== NID_undef
) {
1682 // Release Resources.
1684 if (X509Cert
!= NULL
) {
1685 X509_free (X509Cert
);
1692 Verify one X509 certificate was issued by the trusted CA.
1693 @param[in] RootCert Trusted Root Certificate buffer
1695 @param[in] RootCertLength Trusted Root Certificate buffer length
1696 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
1697 where the first certificate is signed by the Root
1698 Certificate or is the Root Cerificate itself. and
1699 subsequent cerificate is signed by the preceding
1701 @param[in] CertChainLength Total length of the certificate chain, in bytes.
1703 @retval TRUE All cerificates was issued by the first certificate in X509Certchain.
1704 @retval FALSE Invalid certificate or the certificate was not issued by the given
1709 X509VerifyCertChain (
1710 IN CONST UINT8
*RootCert
,
1711 IN UINTN RootCertLength
,
1712 IN CONST UINT8
*CertChain
,
1713 IN UINTN CertChainLength
1716 CONST UINT8
*TmpPtr
;
1720 CONST UINT8
*CurrentCert
;
1721 UINTN CurrentCertLen
;
1722 CONST UINT8
*PrecedingCert
;
1723 UINTN PrecedingCertLen
;
1727 PrecedingCert
= RootCert
;
1728 PrecedingCertLen
= RootCertLength
;
1730 CurrentCert
= CertChain
;
1736 TmpPtr
= CurrentCert
;
1737 Ret
= ASN1_get_object (
1738 (CONST UINT8
**)&TmpPtr
,
1742 (long)(CertChainLength
+ CertChain
- TmpPtr
)
1744 if ((Asn1Tag
!= V_ASN1_SEQUENCE
) || (Ret
== 0x80)) {
1749 // Calculate CurrentCert length;
1751 CurrentCertLen
= TmpPtr
- CurrentCert
+ Length
;
1754 // Verify CurrentCert with preceding cert;
1756 VerifyFlag
= X509VerifyCert (CurrentCert
, CurrentCertLen
, PrecedingCert
, PrecedingCertLen
);
1757 if (VerifyFlag
== FALSE
) {
1762 // move Current cert to Preceding cert
1764 PrecedingCertLen
= CurrentCertLen
;
1765 PrecedingCert
= CurrentCert
;
1770 CurrentCert
= CurrentCert
+ CurrentCertLen
;
1777 Get one X509 certificate from CertChain.
1779 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
1780 where the first certificate is signed by the Root
1781 Certificate or is the Root Cerificate itself. and
1782 subsequent cerificate is signed by the preceding
1784 @param[in] CertChainLength Total length of the certificate chain, in bytes.
1786 @param[in] CertIndex Index of certificate.
1788 @param[out] Cert The certificate at the index of CertChain.
1789 @param[out] CertLength The length certificate at the index of CertChain.
1791 @retval TRUE Success.
1792 @retval FALSE Failed to get certificate from certificate chain.
1796 X509GetCertFromCertChain (
1797 IN CONST UINT8
*CertChain
,
1798 IN UINTN CertChainLength
,
1799 IN CONST INT32 CertIndex
,
1800 OUT CONST UINT8
**Cert
,
1801 OUT UINTN
*CertLength
1806 UINTN CurrentCertLen
;
1807 CONST UINT8
*CurrentCert
;
1808 CONST UINT8
*TmpPtr
;
1814 // Check input parameters.
1816 if ((CertChain
== NULL
) || (Cert
== NULL
) ||
1817 (CertIndex
< -1) || (CertLength
== NULL
))
1824 CurrentCert
= CertChain
;
1828 // Traverse the certificate chain
1831 TmpPtr
= CurrentCert
;
1833 // Get asn1 object and taglen
1834 Ret
= ASN1_get_object (
1835 (CONST UINT8
**)&TmpPtr
,
1839 (long)(CertChainLength
+ CertChain
- TmpPtr
)
1841 if ((Asn1Tag
!= V_ASN1_SEQUENCE
) || (Ret
== 0x80)) {
1846 // Calculate CurrentCert length;
1848 CurrentCertLen
= TmpPtr
- CurrentCert
+ Asn1Len
;
1851 if (CurrentIndex
== CertIndex
) {
1852 *Cert
= CurrentCert
;
1853 *CertLength
= CurrentCertLen
;
1860 CurrentCert
= CurrentCert
+ CurrentCertLen
;
1864 // If CertIndex is -1, Return the last certificate
1866 if ((CertIndex
== -1) && (CurrentIndex
>= 0)) {
1867 *Cert
= CurrentCert
- CurrentCertLen
;
1868 *CertLength
= CurrentCertLen
;
1876 Retrieve the tag and length of the tag.
1878 @param Ptr The position in the ASN.1 data
1879 @param End End of data
1880 @param Length The variable that will receive the length
1881 @param Tag The expected tag
1883 @retval TRUE Get tag successful
1884 @retval FALSe Failed to get tag or tag not match
1890 IN CONST UINT8
*End
,
1901 // Save Ptr position
1905 ASN1_get_object ((CONST UINT8
**)Ptr
, &ObjLength
, &ObjTag
, &ObjCls
, (INT32
)(End
- (*Ptr
)));
1906 if ((ObjTag
== (INT32
)(Tag
& CRYPTO_ASN1_TAG_VALUE_MASK
)) &&
1907 (ObjCls
== (INT32
)(Tag
& CRYPTO_ASN1_TAG_CLASS_MASK
)))
1909 *Length
= (UINTN
)ObjLength
;
1913 // if doesn't match Tag, restore Ptr to origin Ptr
1921 Retrieve the basic constraints from one X.509 certificate.
1923 @param[in] Cert Pointer to the DER-encoded X509 certificate.
1924 @param[in] CertSize size of the X509 certificate in bytes.
1925 @param[out] BasicConstraints basic constraints bytes.
1926 @param[in, out] BasicConstraintsSize basic constraints buffer sizs in bytes.
1928 @retval TRUE The basic constraints retrieve successfully.
1929 @retval FALSE If cert is NULL.
1930 If cert_size is NULL.
1931 If basic_constraints is not NULL and *basic_constraints_size is 0.
1933 @retval FALSE The required buffer size is small.
1934 The return buffer size is basic_constraints_size parameter.
1935 @retval FALSE If no Extension entry match oid.
1936 @retval FALSE The operation is not supported.
1940 X509GetExtendedBasicConstraints (
1943 UINT8
*BasicConstraints
,
1944 UINTN
*BasicConstraintsSize
1949 if ((Cert
== NULL
) || (CertSize
== 0) || (BasicConstraintsSize
== NULL
)) {
1953 Status
= X509GetExtensionData (
1956 mOidBasicConstraints
,
1957 sizeof (mOidBasicConstraints
),
1959 BasicConstraintsSize