1 /** @file
2   X.509 Certificate Handler Wrapper Implementation over OpenSSL.
3 
4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "InternalCryptLib.h"
10 #include <openssl/x509.h>
11 #include <openssl/rsa.h>
12 
13 /**
14   Construct a X509 object from DER-encoded certificate data.
15 
16   If Cert is NULL, then return FALSE.
17   If SingleX509Cert is NULL, then return FALSE.
18 
19   @param[in]  Cert            Pointer to the DER-encoded certificate data.
20   @param[in]  CertSize        The size of certificate data in bytes.
21   @param[out] SingleX509Cert  The generated X509 object.
22 
23   @retval     TRUE            The X509 object generation succeeded.
24   @retval     FALSE           The operation failed.
25 
26 **/
27 BOOLEAN
28 EFIAPI
X509ConstructCertificate(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT UINT8 ** SingleX509Cert)29 X509ConstructCertificate (
30   IN   CONST UINT8  *Cert,
31   IN   UINTN        CertSize,
32   OUT  UINT8        **SingleX509Cert
33   )
34 {
35   X509         *X509Cert;
36   CONST UINT8  *Temp;
37 
38   //
39   // Check input parameters.
40   //
41   if (Cert == NULL || SingleX509Cert == NULL || CertSize > INT_MAX) {
42     return FALSE;
43   }
44 
45   //
46   // Read DER-encoded X509 Certificate and Construct X509 object.
47   //
48   Temp     = Cert;
49   X509Cert = d2i_X509 (NULL, &Temp, (long) CertSize);
50   if (X509Cert == NULL) {
51     return FALSE;
52   }
53 
54   *SingleX509Cert = (UINT8 *) X509Cert;
55 
56   return TRUE;
57 }
58 
59 /**
60   Construct a X509 stack object from a list of DER-encoded certificate data.
61 
62   If X509Stack is NULL, then return FALSE.
63 
64   @param[in, out]  X509Stack  On input, pointer to an existing or NULL X509 stack object.
65                               On output, pointer to the X509 stack object with new
66                               inserted X509 certificate.
67   @param           ...        A list of DER-encoded single certificate data followed
68                               by certificate size. A NULL terminates the list. The
69                               pairs are the arguments to X509ConstructCertificate().
70 
71   @retval     TRUE            The X509 stack construction succeeded.
72   @retval     FALSE           The construction operation failed.
73 
74 **/
75 BOOLEAN
76 EFIAPI
X509ConstructCertificateStack(IN OUT UINT8 ** X509Stack,...)77 X509ConstructCertificateStack (
78   IN OUT  UINT8  **X509Stack,
79   ...
80   )
81 {
82   UINT8           *Cert;
83   UINTN           CertSize;
84   X509            *X509Cert;
85   STACK_OF(X509)  *CertStack;
86   BOOLEAN         Status;
87   VA_LIST         Args;
88   UINTN           Index;
89 
90   //
91   // Check input parameters.
92   //
93   if (X509Stack == NULL) {
94     return FALSE;
95   }
96 
97   Status = FALSE;
98 
99   //
100   // Initialize X509 stack object.
101   //
102   CertStack = (STACK_OF(X509) *) (*X509Stack);
103   if (CertStack == NULL) {
104     CertStack = sk_X509_new_null ();
105     if (CertStack == NULL) {
106       return Status;
107     }
108   }
109 
110   VA_START (Args, X509Stack);
111 
112   for (Index = 0; ; Index++) {
113     //
114     // If Cert is NULL, then it is the end of the list.
115     //
116     Cert = VA_ARG (Args, UINT8 *);
117     if (Cert == NULL) {
118       break;
119     }
120 
121     CertSize = VA_ARG (Args, UINTN);
122     if (CertSize == 0) {
123       break;
124     }
125 
126     //
127     // Construct X509 Object from the given DER-encoded certificate data.
128     //
129     X509Cert = NULL;
130     Status = X509ConstructCertificate (
131                (CONST UINT8 *) Cert,
132                CertSize,
133                (UINT8 **) &X509Cert
134                );
135     if (!Status) {
136       if (X509Cert != NULL) {
137         X509_free (X509Cert);
138       }
139       break;
140     }
141 
142     //
143     // Insert the new X509 object into X509 stack object.
144     //
145     sk_X509_push (CertStack, X509Cert);
146   }
147 
148   VA_END (Args);
149 
150   if (!Status) {
151     sk_X509_pop_free (CertStack, X509_free);
152   } else {
153     *X509Stack = (UINT8 *) CertStack;
154   }
155 
156   return Status;
157 }
158 
159 /**
160   Release the specified X509 object.
161 
162   If X509Cert is NULL, then return FALSE.
163 
164   @param[in]  X509Cert  Pointer to the X509 object to be released.
165 
166 **/
167 VOID
168 EFIAPI
X509Free(IN VOID * X509Cert)169 X509Free (
170   IN  VOID  *X509Cert
171   )
172 {
173   //
174   // Check input parameters.
175   //
176   if (X509Cert == NULL) {
177     return;
178   }
179 
180   //
181   // Free OpenSSL X509 object.
182   //
183   X509_free ((X509 *) X509Cert);
184 }
185 
186 /**
187   Release the specified X509 stack object.
188 
189   If X509Stack is NULL, then return FALSE.
190 
191   @param[in]  X509Stack  Pointer to the X509 stack object to be released.
192 
193 **/
194 VOID
195 EFIAPI
X509StackFree(IN VOID * X509Stack)196 X509StackFree (
197   IN  VOID  *X509Stack
198   )
199 {
200   //
201   // Check input parameters.
202   //
203   if (X509Stack == NULL) {
204     return;
205   }
206 
207   //
208   // Free OpenSSL X509 stack object.
209   //
210   sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free);
211 }
212 
213 /**
214   Retrieve the subject bytes from one X.509 certificate.
215 
216   @param[in]      Cert         Pointer to the DER-encoded X509 certificate.
217   @param[in]      CertSize     Size of the X509 certificate in bytes.
218   @param[out]     CertSubject  Pointer to the retrieved certificate subject bytes.
219   @param[in, out] SubjectSize  The size in bytes of the CertSubject buffer on input,
220                                and the size of buffer returned CertSubject on output.
221 
222   If Cert is NULL, then return FALSE.
223   If SubjectSize is NULL, then return FALSE.
224 
225   @retval  TRUE   The certificate subject retrieved successfully.
226   @retval  FALSE  Invalid certificate, or the SubjectSize is too small for the result.
227                   The SubjectSize will be updated with the required size.
228 
229 **/
230 BOOLEAN
231 EFIAPI
X509GetSubjectName(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT UINT8 * CertSubject,IN OUT UINTN * SubjectSize)232 X509GetSubjectName (
233   IN      CONST UINT8  *Cert,
234   IN      UINTN        CertSize,
235   OUT     UINT8        *CertSubject,
236   IN OUT  UINTN        *SubjectSize
237   )
238 {
239   BOOLEAN    Status;
240   X509       *X509Cert;
241   X509_NAME  *X509Name;
242   UINTN      X509NameSize;
243 
244   //
245   // Check input parameters.
246   //
247   if (Cert == NULL || SubjectSize == NULL) {
248     return FALSE;
249   }
250 
251   X509Cert = NULL;
252 
253   //
254   // Read DER-encoded X509 Certificate and Construct X509 object.
255   //
256   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
257   if ((X509Cert == NULL) || (!Status)) {
258     Status = FALSE;
259     goto _Exit;
260   }
261 
262   Status = FALSE;
263 
264   //
265   // Retrieve subject name from certificate object.
266   //
267   X509Name = X509_get_subject_name (X509Cert);
268   if (X509Name == NULL) {
269     goto _Exit;
270   }
271 
272   X509NameSize = i2d_X509_NAME(X509Name, NULL);
273   if (*SubjectSize < X509NameSize) {
274     *SubjectSize = X509NameSize;
275     goto _Exit;
276   }
277   *SubjectSize = X509NameSize;
278   if (CertSubject != NULL) {
279     i2d_X509_NAME(X509Name, &CertSubject);
280     Status = TRUE;
281   }
282 
283 _Exit:
284   //
285   // Release Resources.
286   //
287   if (X509Cert != NULL) {
288     X509_free (X509Cert);
289   }
290 
291   return Status;
292 }
293 
294 /**
295   Retrieve a string from one X.509 certificate base on the Request_NID.
296 
297   @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
298   @param[in]      CertSize         Size of the X509 certificate in bytes.
299   @param[in]      Request_NID      NID of string to obtain
300   @param[out]     CommonName       Buffer to contain the retrieved certificate common
301                                    name string (UTF8). At most CommonNameSize bytes will be
302                                    written and the string will be null terminated. May be
303                                    NULL in order to determine the size buffer needed.
304   @param[in,out]  CommonNameSize   The size in bytes of the CommonName buffer on input,
305                                    and the size of buffer returned CommonName on output.
306                                    If CommonName is NULL then the amount of space needed
307                                    in buffer (including the final null) is returned.
308 
309   @retval RETURN_SUCCESS           The certificate CommonName retrieved successfully.
310   @retval RETURN_INVALID_PARAMETER If Cert is NULL.
311                                    If CommonNameSize is NULL.
312                                    If CommonName is not NULL and *CommonNameSize is 0.
313                                    If Certificate is invalid.
314   @retval RETURN_NOT_FOUND         If no NID Name entry exists.
315   @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size
316                                    (including the final null) is returned in the
317                                    CommonNameSize parameter.
318   @retval RETURN_UNSUPPORTED       The operation is not supported.
319 
320 **/
321 STATIC
322 RETURN_STATUS
InternalX509GetNIDName(IN CONST UINT8 * Cert,IN UINTN CertSize,IN INT32 Request_NID,OUT CHAR8 * CommonName,OPTIONAL IN OUT UINTN * CommonNameSize)323 InternalX509GetNIDName (
324   IN      CONST UINT8   *Cert,
325   IN      UINTN         CertSize,
326   IN      INT32         Request_NID,
327   OUT     CHAR8         *CommonName,  OPTIONAL
328   IN OUT  UINTN         *CommonNameSize
329   )
330 {
331   RETURN_STATUS    ReturnStatus;
332   BOOLEAN          Status;
333   X509             *X509Cert;
334   X509_NAME        *X509Name;
335   INT32            Index;
336   INTN             Length;
337   X509_NAME_ENTRY  *Entry;
338   ASN1_STRING      *EntryData;
339   UINT8            *UTF8Name;
340 
341   ReturnStatus = RETURN_INVALID_PARAMETER;
342   UTF8Name     = NULL;
343 
344   //
345   // Check input parameters.
346   //
347   if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {
348     return ReturnStatus;
349   }
350   if ((CommonName != NULL) && (*CommonNameSize == 0)) {
351     return ReturnStatus;
352   }
353 
354   X509Cert = NULL;
355   //
356   // Read DER-encoded X509 Certificate and Construct X509 object.
357   //
358   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
359   if ((X509Cert == NULL) || (!Status)) {
360     //
361     // Invalid X.509 Certificate
362     //
363     goto _Exit;
364   }
365 
366   Status = FALSE;
367 
368   //
369   // Retrieve subject name from certificate object.
370   //
371   X509Name = X509_get_subject_name (X509Cert);
372   if (X509Name == NULL) {
373     //
374     // Fail to retrieve subject name content
375     //
376     goto _Exit;
377   }
378 
379   //
380   // Retrive the string from X.509 Subject base on the Request_NID
381   //
382   Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);
383   if (Index < 0) {
384     //
385     // No Request_NID name entry exists in X509_NAME object
386     //
387     *CommonNameSize = 0;
388     ReturnStatus    = RETURN_NOT_FOUND;
389     goto _Exit;
390   }
391 
392   Entry = X509_NAME_get_entry (X509Name, Index);
393   if (Entry == NULL) {
394     //
395     // Fail to retrieve name entry data
396     //
397     *CommonNameSize = 0;
398     ReturnStatus    = RETURN_NOT_FOUND;
399     goto _Exit;
400   }
401 
402   EntryData = X509_NAME_ENTRY_get_data (Entry);
403 
404   Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);
405   if (Length < 0) {
406     //
407     // Fail to convert the Name string
408     //
409     *CommonNameSize = 0;
410     ReturnStatus    = RETURN_INVALID_PARAMETER;
411     goto _Exit;
412   }
413 
414   if (CommonName == NULL) {
415     *CommonNameSize = Length + 1;
416     ReturnStatus = RETURN_BUFFER_TOO_SMALL;
417   } else {
418     *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;
419     CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);
420     CommonName[*CommonNameSize - 1] = '\0';
421     ReturnStatus = RETURN_SUCCESS;
422   }
423 
424 _Exit:
425   //
426   // Release Resources.
427   //
428   if (X509Cert != NULL) {
429     X509_free (X509Cert);
430   }
431   if (UTF8Name != NULL) {
432     OPENSSL_free (UTF8Name);
433   }
434 
435   return ReturnStatus;
436 }
437 
438 /**
439   Retrieve the common name (CN) string from one X.509 certificate.
440 
441   @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
442   @param[in]      CertSize         Size of the X509 certificate in bytes.
443   @param[out]     CommonName       Buffer to contain the retrieved certificate common
444                                    name string. At most CommonNameSize bytes will be
445                                    written and the string will be null terminated. May be
446                                    NULL in order to determine the size buffer needed.
447   @param[in,out]  CommonNameSize   The size in bytes of the CommonName buffer on input,
448                                    and the size of buffer returned CommonName on output.
449                                    If CommonName is NULL then the amount of space needed
450                                    in buffer (including the final null) is returned.
451 
452   @retval RETURN_SUCCESS           The certificate CommonName retrieved successfully.
453   @retval RETURN_INVALID_PARAMETER If Cert is NULL.
454                                    If CommonNameSize is NULL.
455                                    If CommonName is not NULL and *CommonNameSize is 0.
456                                    If Certificate is invalid.
457   @retval RETURN_NOT_FOUND         If no CommonName entry exists.
458   @retval RETURN_BUFFER_TOO_SMALL  If the CommonName is NULL. The required buffer size
459                                    (including the final null) is returned in the
460                                    CommonNameSize parameter.
461   @retval RETURN_UNSUPPORTED       The operation is not supported.
462 
463 **/
464 RETURN_STATUS
465 EFIAPI
X509GetCommonName(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT CHAR8 * CommonName,OPTIONAL IN OUT UINTN * CommonNameSize)466 X509GetCommonName (
467   IN      CONST UINT8  *Cert,
468   IN      UINTN        CertSize,
469   OUT     CHAR8        *CommonName,  OPTIONAL
470   IN OUT  UINTN        *CommonNameSize
471   )
472 {
473   return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize);
474 }
475 
476 /**
477   Retrieve the organization name (O) string from one X.509 certificate.
478 
479   @param[in]      Cert             Pointer to the DER-encoded X509 certificate.
480   @param[in]      CertSize         Size of the X509 certificate in bytes.
481   @param[out]     NameBuffer       Buffer to contain the retrieved certificate organization
482                                    name string. At most NameBufferSize bytes will be
483                                    written and the string will be null terminated. May be
484                                    NULL in order to determine the size buffer needed.
485   @param[in,out]  NameBufferSize   The size in bytes of the Name buffer on input,
486                                    and the size of buffer returned Name on output.
487                                    If NameBuffer is NULL then the amount of space needed
488                                    in buffer (including the final null) is returned.
489 
490   @retval RETURN_SUCCESS           The certificate Organization Name retrieved successfully.
491   @retval RETURN_INVALID_PARAMETER If Cert is NULL.
492                                    If NameBufferSize is NULL.
493                                    If NameBuffer is not NULL and *CommonNameSize is 0.
494                                    If Certificate is invalid.
495   @retval RETURN_NOT_FOUND         If no Organization Name entry exists.
496   @retval RETURN_BUFFER_TOO_SMALL  If the NameBuffer is NULL. The required buffer size
497                                    (including the final null) is returned in the
498                                    CommonNameSize parameter.
499   @retval RETURN_UNSUPPORTED       The operation is not supported.
500 
501 **/
502 RETURN_STATUS
503 EFIAPI
X509GetOrganizationName(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT CHAR8 * NameBuffer,OPTIONAL IN OUT UINTN * NameBufferSize)504 X509GetOrganizationName (
505   IN      CONST UINT8   *Cert,
506   IN      UINTN         CertSize,
507   OUT     CHAR8         *NameBuffer,  OPTIONAL
508   IN OUT  UINTN         *NameBufferSize
509   )
510 {
511   return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);
512 }
513 
514 /**
515   Retrieve the RSA Public Key from one DER-encoded X509 certificate.
516 
517   @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
518   @param[in]  CertSize     Size of the X509 certificate in bytes.
519   @param[out] RsaContext   Pointer to new-generated RSA context which contain the retrieved
520                            RSA public key component. Use RsaFree() function to free the
521                            resource.
522 
523   If Cert is NULL, then return FALSE.
524   If RsaContext is NULL, then return FALSE.
525 
526   @retval  TRUE   RSA Public Key was retrieved successfully.
527   @retval  FALSE  Fail to retrieve RSA public key from X509 certificate.
528 
529 **/
530 BOOLEAN
531 EFIAPI
RsaGetPublicKeyFromX509(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT VOID ** RsaContext)532 RsaGetPublicKeyFromX509 (
533   IN   CONST UINT8  *Cert,
534   IN   UINTN        CertSize,
535   OUT  VOID         **RsaContext
536   )
537 {
538   BOOLEAN   Status;
539   EVP_PKEY  *Pkey;
540   X509      *X509Cert;
541 
542   //
543   // Check input parameters.
544   //
545   if (Cert == NULL || RsaContext == NULL) {
546     return FALSE;
547   }
548 
549   Pkey     = NULL;
550   X509Cert = NULL;
551 
552   //
553   // Read DER-encoded X509 Certificate and Construct X509 object.
554   //
555   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
556   if ((X509Cert == NULL) || (!Status)) {
557     Status = FALSE;
558     goto _Exit;
559   }
560 
561   Status = FALSE;
562 
563   //
564   // Retrieve and check EVP_PKEY data from X509 Certificate.
565   //
566   Pkey = X509_get_pubkey (X509Cert);
567   if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {
568     goto _Exit;
569   }
570 
571   //
572   // Duplicate RSA Context from the retrieved EVP_PKEY.
573   //
574   if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {
575     Status = TRUE;
576   }
577 
578 _Exit:
579   //
580   // Release Resources.
581   //
582   if (X509Cert != NULL) {
583     X509_free (X509Cert);
584   }
585 
586   if (Pkey != NULL) {
587     EVP_PKEY_free (Pkey);
588   }
589 
590   return Status;
591 }
592 
593 /**
594   Verify one X509 certificate was issued by the trusted CA.
595 
596   @param[in]      Cert         Pointer to the DER-encoded X509 certificate to be verified.
597   @param[in]      CertSize     Size of the X509 certificate in bytes.
598   @param[in]      CACert       Pointer to the DER-encoded trusted CA certificate.
599   @param[in]      CACertSize   Size of the CA Certificate in bytes.
600 
601   If Cert is NULL, then return FALSE.
602   If CACert is NULL, then return FALSE.
603 
604   @retval  TRUE   The certificate was issued by the trusted CA.
605   @retval  FALSE  Invalid certificate or the certificate was not issued by the given
606                   trusted CA.
607 
608 **/
609 BOOLEAN
610 EFIAPI
X509VerifyCert(IN CONST UINT8 * Cert,IN UINTN CertSize,IN CONST UINT8 * CACert,IN UINTN CACertSize)611 X509VerifyCert (
612   IN  CONST UINT8  *Cert,
613   IN  UINTN        CertSize,
614   IN  CONST UINT8  *CACert,
615   IN  UINTN        CACertSize
616   )
617 {
618   BOOLEAN         Status;
619   X509            *X509Cert;
620   X509            *X509CACert;
621   X509_STORE      *CertStore;
622   X509_STORE_CTX  *CertCtx;
623 
624   //
625   // Check input parameters.
626   //
627   if (Cert == NULL || CACert == NULL) {
628     return FALSE;
629   }
630 
631   Status     = FALSE;
632   X509Cert   = NULL;
633   X509CACert = NULL;
634   CertStore  = NULL;
635   CertCtx    = NULL;
636 
637   //
638   // Register & Initialize necessary digest algorithms for certificate verification.
639   //
640   if (EVP_add_digest (EVP_md5 ()) == 0) {
641     goto _Exit;
642   }
643   if (EVP_add_digest (EVP_sha1 ()) == 0) {
644     goto _Exit;
645   }
646   if (EVP_add_digest (EVP_sha256 ()) == 0) {
647     goto _Exit;
648   }
649 
650   //
651   // Read DER-encoded certificate to be verified and Construct X509 object.
652   //
653   Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert);
654   if ((X509Cert == NULL) || (!Status)) {
655     Status = FALSE;
656     goto _Exit;
657   }
658 
659   //
660   // Read DER-encoded root certificate and Construct X509 object.
661   //
662   Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert);
663   if ((X509CACert == NULL) || (!Status)) {
664     Status = FALSE;
665     goto _Exit;
666   }
667 
668   Status = FALSE;
669 
670   //
671   // Set up X509 Store for trusted certificate.
672   //
673   CertStore = X509_STORE_new ();
674   if (CertStore == NULL) {
675     goto _Exit;
676   }
677   if (!(X509_STORE_add_cert (CertStore, X509CACert))) {
678     goto _Exit;
679   }
680 
681   //
682   // Allow partial certificate chains, terminated by a non-self-signed but
683   // still trusted intermediate certificate. Also disable time checks.
684   //
685   X509_STORE_set_flags (CertStore,
686                         X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
687 
688   //
689   // Set up X509_STORE_CTX for the subsequent verification operation.
690   //
691   CertCtx = X509_STORE_CTX_new ();
692   if (CertCtx == NULL) {
693     goto _Exit;
694   }
695   if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {
696     goto _Exit;
697   }
698 
699   //
700   // X509 Certificate Verification.
701   //
702   Status = (BOOLEAN) X509_verify_cert (CertCtx);
703   X509_STORE_CTX_cleanup (CertCtx);
704 
705 _Exit:
706   //
707   // Release Resources.
708   //
709   if (X509Cert != NULL) {
710     X509_free (X509Cert);
711   }
712 
713   if (X509CACert != NULL) {
714     X509_free (X509CACert);
715   }
716 
717   if (CertStore != NULL) {
718     X509_STORE_free (CertStore);
719   }
720 
721   X509_STORE_CTX_free (CertCtx);
722 
723   return Status;
724 }
725 
726 /**
727   Retrieve the TBSCertificate from one given X.509 certificate.
728 
729   @param[in]      Cert         Pointer to the given DER-encoded X509 certificate.
730   @param[in]      CertSize     Size of the X509 certificate in bytes.
731   @param[out]     TBSCert      DER-Encoded To-Be-Signed certificate.
732   @param[out]     TBSCertSize  Size of the TBS certificate in bytes.
733 
734   If Cert is NULL, then return FALSE.
735   If TBSCert is NULL, then return FALSE.
736   If TBSCertSize is NULL, then return FALSE.
737 
738   @retval  TRUE   The TBSCertificate was retrieved successfully.
739   @retval  FALSE  Invalid X.509 certificate.
740 
741 **/
742 BOOLEAN
743 EFIAPI
X509GetTBSCert(IN CONST UINT8 * Cert,IN UINTN CertSize,OUT UINT8 ** TBSCert,OUT UINTN * TBSCertSize)744 X509GetTBSCert (
745   IN  CONST UINT8  *Cert,
746   IN  UINTN        CertSize,
747   OUT UINT8        **TBSCert,
748   OUT UINTN        *TBSCertSize
749   )
750 {
751   CONST UINT8  *Temp;
752   UINT32       Asn1Tag;
753   UINT32       ObjClass;
754   UINTN        Length;
755 
756   //
757   // Check input parameters.
758   //
759   if ((Cert == NULL) || (TBSCert == NULL) ||
760       (TBSCertSize == NULL) || (CertSize > INT_MAX)) {
761     return FALSE;
762   }
763 
764   //
765   // An X.509 Certificate is: (defined in RFC3280)
766   //   Certificate  ::=  SEQUENCE  {
767   //     tbsCertificate       TBSCertificate,
768   //     signatureAlgorithm   AlgorithmIdentifier,
769   //     signature            BIT STRING }
770   //
771   // and
772   //
773   //  TBSCertificate  ::=  SEQUENCE  {
774   //    version         [0]  Version DEFAULT v1,
775   //    ...
776   //    }
777   //
778   // So we can just ASN1-parse the x.509 DER-encoded data. If we strip
779   // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
780   //
781   Temp   = Cert;
782   Length = 0;
783   ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);
784 
785   if (Asn1Tag != V_ASN1_SEQUENCE) {
786     return FALSE;
787   }
788 
789   *TBSCert = (UINT8 *)Temp;
790 
791   ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);
792   //
793   // Verify the parsed TBSCertificate is one correct SEQUENCE data.
794   //
795   if (Asn1Tag != V_ASN1_SEQUENCE) {
796     return FALSE;
797   }
798 
799   *TBSCertSize = Length + (Temp - *TBSCert);
800 
801   return TRUE;
802 }
803