]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptX509.c
... / ...
CommitLineData
1/** @file\r
2 X.509 Certificate Handler Wrapper Implementation over OpenSSL.\r
3\r
4Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "InternalCryptLib.h"\r
10#include <openssl/x509.h>\r
11#include <openssl/x509v3.h>\r
12#include <crypto/asn1.h>\r
13#include <openssl/asn1.h>\r
14#include <openssl/rsa.h>\r
15\r
16/* OID*/\r
17#define OID_EXT_KEY_USAGE { 0x55, 0x1D, 0x25 }\r
18#define OID_BASIC_CONSTRAINTS { 0x55, 0x1D, 0x13 }\r
19\r
20static CONST UINT8 mOidExtKeyUsage[] = OID_EXT_KEY_USAGE;\r
21static CONST UINT8 mOidBasicConstraints[] = OID_BASIC_CONSTRAINTS;\r
22\r
23#define CRYPTO_ASN1_TAG_CLASS_MASK 0xC0\r
24#define CRYPTO_ASN1_TAG_PC_MASK 0x20\r
25#define CRYPTO_ASN1_TAG_VALUE_MASK 0x1F\r
26\r
27/**\r
28 Construct a X509 object from DER-encoded certificate data.\r
29\r
30 If Cert is NULL, then return FALSE.\r
31 If SingleX509Cert is NULL, then return FALSE.\r
32\r
33 @param[in] Cert Pointer to the DER-encoded certificate data.\r
34 @param[in] CertSize The size of certificate data in bytes.\r
35 @param[out] SingleX509Cert The generated X509 object.\r
36\r
37 @retval TRUE The X509 object generation succeeded.\r
38 @retval FALSE The operation failed.\r
39\r
40**/\r
41BOOLEAN\r
42EFIAPI\r
43X509ConstructCertificate (\r
44 IN CONST UINT8 *Cert,\r
45 IN UINTN CertSize,\r
46 OUT UINT8 **SingleX509Cert\r
47 )\r
48{\r
49 X509 *X509Cert;\r
50 CONST UINT8 *Temp;\r
51\r
52 //\r
53 // Check input parameters.\r
54 //\r
55 if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize > INT_MAX)) {\r
56 return FALSE;\r
57 }\r
58\r
59 //\r
60 // Read DER-encoded X509 Certificate and Construct X509 object.\r
61 //\r
62 Temp = Cert;\r
63 X509Cert = d2i_X509 (NULL, &Temp, (long)CertSize);\r
64 if (X509Cert == NULL) {\r
65 return FALSE;\r
66 }\r
67\r
68 *SingleX509Cert = (UINT8 *)X509Cert;\r
69\r
70 return TRUE;\r
71}\r
72\r
73/**\r
74 Construct a X509 stack object from a list of DER-encoded certificate data.\r
75\r
76 If X509Stack is NULL, then return FALSE.\r
77 If this interface is not supported, then return FALSE.\r
78\r
79 @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.\r
80 On output, pointer to the X509 stack object with new\r
81 inserted X509 certificate.\r
82 @param[in] Args VA_LIST marker for the variable argument list.\r
83 A list of DER-encoded single certificate data followed\r
84 by certificate size. A NULL terminates the list. The\r
85 pairs are the arguments to X509ConstructCertificate().\r
86\r
87 @retval TRUE The X509 stack construction succeeded.\r
88 @retval FALSE The construction operation failed.\r
89 @retval FALSE This interface is not supported.\r
90\r
91**/\r
92BOOLEAN\r
93EFIAPI\r
94X509ConstructCertificateStackV (\r
95 IN OUT UINT8 **X509Stack,\r
96 IN VA_LIST Args\r
97 )\r
98{\r
99 UINT8 *Cert;\r
100 UINTN CertSize;\r
101 X509 *X509Cert;\r
102\r
103 STACK_OF (X509) *CertStack;\r
104 BOOLEAN Status;\r
105 UINTN Index;\r
106\r
107 //\r
108 // Check input parameters.\r
109 //\r
110 if (X509Stack == NULL) {\r
111 return FALSE;\r
112 }\r
113\r
114 Status = FALSE;\r
115\r
116 //\r
117 // Initialize X509 stack object.\r
118 //\r
119 CertStack = (STACK_OF (X509) *)(*X509Stack);\r
120 if (CertStack == NULL) {\r
121 CertStack = sk_X509_new_null ();\r
122 if (CertStack == NULL) {\r
123 return Status;\r
124 }\r
125 }\r
126\r
127 for (Index = 0; ; Index++) {\r
128 //\r
129 // If Cert is NULL, then it is the end of the list.\r
130 //\r
131 Cert = VA_ARG (Args, UINT8 *);\r
132 if (Cert == NULL) {\r
133 break;\r
134 }\r
135\r
136 CertSize = VA_ARG (Args, UINTN);\r
137 if (CertSize == 0) {\r
138 break;\r
139 }\r
140\r
141 //\r
142 // Construct X509 Object from the given DER-encoded certificate data.\r
143 //\r
144 X509Cert = NULL;\r
145 Status = X509ConstructCertificate (\r
146 (CONST UINT8 *)Cert,\r
147 CertSize,\r
148 (UINT8 **)&X509Cert\r
149 );\r
150 if (!Status) {\r
151 if (X509Cert != NULL) {\r
152 X509_free (X509Cert);\r
153 }\r
154\r
155 break;\r
156 }\r
157\r
158 //\r
159 // Insert the new X509 object into X509 stack object.\r
160 //\r
161 sk_X509_push (CertStack, X509Cert);\r
162 }\r
163\r
164 if (!Status) {\r
165 sk_X509_pop_free (CertStack, X509_free);\r
166 } else {\r
167 *X509Stack = (UINT8 *)CertStack;\r
168 }\r
169\r
170 return Status;\r
171}\r
172\r
173/**\r
174 Construct a X509 stack object from a list of DER-encoded certificate data.\r
175\r
176 If X509Stack is NULL, then return FALSE.\r
177\r
178 @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.\r
179 On output, pointer to the X509 stack object with new\r
180 inserted X509 certificate.\r
181 @param ... A list of DER-encoded single certificate data followed\r
182 by certificate size. A NULL terminates the list. The\r
183 pairs are the arguments to X509ConstructCertificate().\r
184\r
185 @retval TRUE The X509 stack construction succeeded.\r
186 @retval FALSE The construction operation failed.\r
187\r
188**/\r
189BOOLEAN\r
190EFIAPI\r
191X509ConstructCertificateStack (\r
192 IN OUT UINT8 **X509Stack,\r
193 ...\r
194 )\r
195{\r
196 VA_LIST Args;\r
197 BOOLEAN Result;\r
198\r
199 VA_START (Args, X509Stack);\r
200 Result = X509ConstructCertificateStackV (X509Stack, Args);\r
201 VA_END (Args);\r
202 return Result;\r
203}\r
204\r
205/**\r
206 Release the specified X509 object.\r
207\r
208 If X509Cert is NULL, then return FALSE.\r
209\r
210 @param[in] X509Cert Pointer to the X509 object to be released.\r
211\r
212**/\r
213VOID\r
214EFIAPI\r
215X509Free (\r
216 IN VOID *X509Cert\r
217 )\r
218{\r
219 //\r
220 // Check input parameters.\r
221 //\r
222 if (X509Cert == NULL) {\r
223 return;\r
224 }\r
225\r
226 //\r
227 // Free OpenSSL X509 object.\r
228 //\r
229 X509_free ((X509 *)X509Cert);\r
230}\r
231\r
232/**\r
233 Release the specified X509 stack object.\r
234\r
235 If X509Stack is NULL, then return FALSE.\r
236\r
237 @param[in] X509Stack Pointer to the X509 stack object to be released.\r
238\r
239**/\r
240VOID\r
241EFIAPI\r
242X509StackFree (\r
243 IN VOID *X509Stack\r
244 )\r
245{\r
246 //\r
247 // Check input parameters.\r
248 //\r
249 if (X509Stack == NULL) {\r
250 return;\r
251 }\r
252\r
253 //\r
254 // Free OpenSSL X509 stack object.\r
255 //\r
256 sk_X509_pop_free ((STACK_OF (X509) *) X509Stack, X509_free);\r
257}\r
258\r
259/**\r
260 Retrieve the subject bytes from one X.509 certificate.\r
261\r
262 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
263 @param[in] CertSize Size of the X509 certificate in bytes.\r
264 @param[out] CertSubject Pointer to the retrieved certificate subject bytes.\r
265 @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input,\r
266 and the size of buffer returned CertSubject on output.\r
267\r
268 If Cert is NULL, then return FALSE.\r
269 If SubjectSize is NULL, then return FALSE.\r
270\r
271 @retval TRUE The certificate subject retrieved successfully.\r
272 @retval FALSE Invalid certificate, or the SubjectSize is too small for the result.\r
273 The SubjectSize will be updated with the required size.\r
274\r
275**/\r
276BOOLEAN\r
277EFIAPI\r
278X509GetSubjectName (\r
279 IN CONST UINT8 *Cert,\r
280 IN UINTN CertSize,\r
281 OUT UINT8 *CertSubject,\r
282 IN OUT UINTN *SubjectSize\r
283 )\r
284{\r
285 BOOLEAN Status;\r
286 X509 *X509Cert;\r
287 X509_NAME *X509Name;\r
288 UINTN X509NameSize;\r
289\r
290 //\r
291 // Check input parameters.\r
292 //\r
293 if ((Cert == NULL) || (SubjectSize == NULL)) {\r
294 return FALSE;\r
295 }\r
296\r
297 X509Cert = NULL;\r
298\r
299 //\r
300 // Read DER-encoded X509 Certificate and Construct X509 object.\r
301 //\r
302 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
303 if ((X509Cert == NULL) || (!Status)) {\r
304 Status = FALSE;\r
305 goto _Exit;\r
306 }\r
307\r
308 Status = FALSE;\r
309\r
310 //\r
311 // Retrieve subject name from certificate object.\r
312 //\r
313 X509Name = X509_get_subject_name (X509Cert);\r
314 if (X509Name == NULL) {\r
315 goto _Exit;\r
316 }\r
317\r
318 X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
319 if (*SubjectSize < X509NameSize) {\r
320 *SubjectSize = X509NameSize;\r
321 goto _Exit;\r
322 }\r
323\r
324 *SubjectSize = X509NameSize;\r
325 if (CertSubject != NULL) {\r
326 i2d_X509_NAME (X509Name, &CertSubject);\r
327 Status = TRUE;\r
328 }\r
329\r
330_Exit:\r
331 //\r
332 // Release Resources.\r
333 //\r
334 if (X509Cert != NULL) {\r
335 X509_free (X509Cert);\r
336 }\r
337\r
338 return Status;\r
339}\r
340\r
341/**\r
342 Retrieve a string from one X.509 certificate base on the Request_NID.\r
343\r
344 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
345 @param[in] CertSize Size of the X509 certificate in bytes.\r
346 @param[in] Request_NID NID of string to obtain\r
347 @param[out] CommonName Buffer to contain the retrieved certificate common\r
348 name string (UTF8). At most CommonNameSize bytes will be\r
349 written and the string will be null terminated. May be\r
350 NULL in order to determine the size buffer needed.\r
351 @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,\r
352 and the size of buffer returned CommonName on output.\r
353 If CommonName is NULL then the amount of space needed\r
354 in buffer (including the final null) is returned.\r
355\r
356 @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.\r
357 @retval RETURN_INVALID_PARAMETER If Cert is NULL.\r
358 If CommonNameSize is NULL.\r
359 If CommonName is not NULL and *CommonNameSize is 0.\r
360 If Certificate is invalid.\r
361 @retval RETURN_NOT_FOUND If no NID Name entry exists.\r
362 @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size\r
363 (including the final null) is returned in the\r
364 CommonNameSize parameter.\r
365 @retval RETURN_UNSUPPORTED The operation is not supported.\r
366\r
367**/\r
368STATIC\r
369RETURN_STATUS\r
370InternalX509GetNIDName (\r
371 IN CONST UINT8 *Cert,\r
372 IN UINTN CertSize,\r
373 IN INT32 Request_NID,\r
374 OUT CHAR8 *CommonName OPTIONAL,\r
375 IN OUT UINTN *CommonNameSize\r
376 )\r
377{\r
378 RETURN_STATUS ReturnStatus;\r
379 BOOLEAN Status;\r
380 X509 *X509Cert;\r
381 X509_NAME *X509Name;\r
382 INT32 Index;\r
383 INTN Length;\r
384 X509_NAME_ENTRY *Entry;\r
385 ASN1_STRING *EntryData;\r
386 UINT8 *UTF8Name;\r
387\r
388 ReturnStatus = RETURN_INVALID_PARAMETER;\r
389 UTF8Name = NULL;\r
390\r
391 //\r
392 // Check input parameters.\r
393 //\r
394 if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) {\r
395 return ReturnStatus;\r
396 }\r
397\r
398 if ((CommonName != NULL) && (*CommonNameSize == 0)) {\r
399 return ReturnStatus;\r
400 }\r
401\r
402 X509Cert = NULL;\r
403 //\r
404 // Read DER-encoded X509 Certificate and Construct X509 object.\r
405 //\r
406 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
407 if ((X509Cert == NULL) || (!Status)) {\r
408 //\r
409 // Invalid X.509 Certificate\r
410 //\r
411 goto _Exit;\r
412 }\r
413\r
414 Status = FALSE;\r
415\r
416 //\r
417 // Retrieve subject name from certificate object.\r
418 //\r
419 X509Name = X509_get_subject_name (X509Cert);\r
420 if (X509Name == NULL) {\r
421 //\r
422 // Fail to retrieve subject name content\r
423 //\r
424 goto _Exit;\r
425 }\r
426\r
427 //\r
428 // Retrive the string from X.509 Subject base on the Request_NID\r
429 //\r
430 Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);\r
431 if (Index < 0) {\r
432 //\r
433 // No Request_NID name entry exists in X509_NAME object\r
434 //\r
435 *CommonNameSize = 0;\r
436 ReturnStatus = RETURN_NOT_FOUND;\r
437 goto _Exit;\r
438 }\r
439\r
440 Entry = X509_NAME_get_entry (X509Name, Index);\r
441 if (Entry == NULL) {\r
442 //\r
443 // Fail to retrieve name entry data\r
444 //\r
445 *CommonNameSize = 0;\r
446 ReturnStatus = RETURN_NOT_FOUND;\r
447 goto _Exit;\r
448 }\r
449\r
450 EntryData = X509_NAME_ENTRY_get_data (Entry);\r
451\r
452 Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData);\r
453 if (Length < 0) {\r
454 //\r
455 // Fail to convert the Name string\r
456 //\r
457 *CommonNameSize = 0;\r
458 ReturnStatus = RETURN_INVALID_PARAMETER;\r
459 goto _Exit;\r
460 }\r
461\r
462 if (CommonName == NULL) {\r
463 *CommonNameSize = Length + 1;\r
464 ReturnStatus = RETURN_BUFFER_TOO_SMALL;\r
465 } else {\r
466 *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;\r
467 CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);\r
468 CommonName[*CommonNameSize - 1] = '\0';\r
469 ReturnStatus = RETURN_SUCCESS;\r
470 }\r
471\r
472_Exit:\r
473 //\r
474 // Release Resources.\r
475 //\r
476 if (X509Cert != NULL) {\r
477 X509_free (X509Cert);\r
478 }\r
479\r
480 if (UTF8Name != NULL) {\r
481 OPENSSL_free (UTF8Name);\r
482 }\r
483\r
484 return ReturnStatus;\r
485}\r
486\r
487/**\r
488 Retrieve the common name (CN) string from one X.509 certificate.\r
489\r
490 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
491 @param[in] CertSize Size of the X509 certificate in bytes.\r
492 @param[out] CommonName Buffer to contain the retrieved certificate common\r
493 name string. At most CommonNameSize bytes will be\r
494 written and the string will be null terminated. May be\r
495 NULL in order to determine the size buffer needed.\r
496 @param[in,out] CommonNameSize The size in bytes of the CommonName buffer on input,\r
497 and the size of buffer returned CommonName on output.\r
498 If CommonName is NULL then the amount of space needed\r
499 in buffer (including the final null) is returned.\r
500\r
501 @retval RETURN_SUCCESS The certificate CommonName retrieved successfully.\r
502 @retval RETURN_INVALID_PARAMETER If Cert is NULL.\r
503 If CommonNameSize is NULL.\r
504 If CommonName is not NULL and *CommonNameSize is 0.\r
505 If Certificate is invalid.\r
506 @retval RETURN_NOT_FOUND If no CommonName entry exists.\r
507 @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size\r
508 (including the final null) is returned in the\r
509 CommonNameSize parameter.\r
510 @retval RETURN_UNSUPPORTED The operation is not supported.\r
511\r
512**/\r
513RETURN_STATUS\r
514EFIAPI\r
515X509GetCommonName (\r
516 IN CONST UINT8 *Cert,\r
517 IN UINTN CertSize,\r
518 OUT CHAR8 *CommonName OPTIONAL,\r
519 IN OUT UINTN *CommonNameSize\r
520 )\r
521{\r
522 return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize);\r
523}\r
524\r
525/**\r
526 Retrieve the organization name (O) string from one X.509 certificate.\r
527\r
528 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
529 @param[in] CertSize Size of the X509 certificate in bytes.\r
530 @param[out] NameBuffer Buffer to contain the retrieved certificate organization\r
531 name string. At most NameBufferSize bytes will be\r
532 written and the string will be null terminated. May be\r
533 NULL in order to determine the size buffer needed.\r
534 @param[in,out] NameBufferSize The size in bytes of the Name buffer on input,\r
535 and the size of buffer returned Name on output.\r
536 If NameBuffer is NULL then the amount of space needed\r
537 in buffer (including the final null) is returned.\r
538\r
539 @retval RETURN_SUCCESS The certificate Organization Name retrieved successfully.\r
540 @retval RETURN_INVALID_PARAMETER If Cert is NULL.\r
541 If NameBufferSize is NULL.\r
542 If NameBuffer is not NULL and *CommonNameSize is 0.\r
543 If Certificate is invalid.\r
544 @retval RETURN_NOT_FOUND If no Organization Name entry exists.\r
545 @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size\r
546 (including the final null) is returned in the\r
547 CommonNameSize parameter.\r
548 @retval RETURN_UNSUPPORTED The operation is not supported.\r
549\r
550**/\r
551RETURN_STATUS\r
552EFIAPI\r
553X509GetOrganizationName (\r
554 IN CONST UINT8 *Cert,\r
555 IN UINTN CertSize,\r
556 OUT CHAR8 *NameBuffer OPTIONAL,\r
557 IN OUT UINTN *NameBufferSize\r
558 )\r
559{\r
560 return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);\r
561}\r
562\r
563/**\r
564 Retrieve the RSA Public Key from one DER-encoded X509 certificate.\r
565\r
566 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
567 @param[in] CertSize Size of the X509 certificate in bytes.\r
568 @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved\r
569 RSA public key component. Use RsaFree() function to free the\r
570 resource.\r
571\r
572 If Cert is NULL, then return FALSE.\r
573 If RsaContext is NULL, then return FALSE.\r
574\r
575 @retval TRUE RSA Public Key was retrieved successfully.\r
576 @retval FALSE Fail to retrieve RSA public key from X509 certificate.\r
577\r
578**/\r
579BOOLEAN\r
580EFIAPI\r
581RsaGetPublicKeyFromX509 (\r
582 IN CONST UINT8 *Cert,\r
583 IN UINTN CertSize,\r
584 OUT VOID **RsaContext\r
585 )\r
586{\r
587 BOOLEAN Status;\r
588 EVP_PKEY *Pkey;\r
589 X509 *X509Cert;\r
590\r
591 //\r
592 // Check input parameters.\r
593 //\r
594 if ((Cert == NULL) || (RsaContext == NULL)) {\r
595 return FALSE;\r
596 }\r
597\r
598 Pkey = NULL;\r
599 X509Cert = NULL;\r
600\r
601 //\r
602 // Read DER-encoded X509 Certificate and Construct X509 object.\r
603 //\r
604 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
605 if ((X509Cert == NULL) || (!Status)) {\r
606 Status = FALSE;\r
607 goto _Exit;\r
608 }\r
609\r
610 Status = FALSE;\r
611\r
612 //\r
613 // Retrieve and check EVP_PKEY data from X509 Certificate.\r
614 //\r
615 Pkey = X509_get_pubkey (X509Cert);\r
616 if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {\r
617 goto _Exit;\r
618 }\r
619\r
620 //\r
621 // Duplicate RSA Context from the retrieved EVP_PKEY.\r
622 //\r
623 if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {\r
624 Status = TRUE;\r
625 }\r
626\r
627_Exit:\r
628 //\r
629 // Release Resources.\r
630 //\r
631 if (X509Cert != NULL) {\r
632 X509_free (X509Cert);\r
633 }\r
634\r
635 if (Pkey != NULL) {\r
636 EVP_PKEY_free (Pkey);\r
637 }\r
638\r
639 return Status;\r
640}\r
641\r
642/**\r
643 Verify one X509 certificate was issued by the trusted CA.\r
644\r
645 @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified.\r
646 @param[in] CertSize Size of the X509 certificate in bytes.\r
647 @param[in] CACert Pointer to the DER-encoded trusted CA certificate.\r
648 @param[in] CACertSize Size of the CA Certificate in bytes.\r
649\r
650 If Cert is NULL, then return FALSE.\r
651 If CACert is NULL, then return FALSE.\r
652\r
653 @retval TRUE The certificate was issued by the trusted CA.\r
654 @retval FALSE Invalid certificate or the certificate was not issued by the given\r
655 trusted CA.\r
656\r
657**/\r
658BOOLEAN\r
659EFIAPI\r
660X509VerifyCert (\r
661 IN CONST UINT8 *Cert,\r
662 IN UINTN CertSize,\r
663 IN CONST UINT8 *CACert,\r
664 IN UINTN CACertSize\r
665 )\r
666{\r
667 BOOLEAN Status;\r
668 X509 *X509Cert;\r
669 X509 *X509CACert;\r
670 X509_STORE *CertStore;\r
671 X509_STORE_CTX *CertCtx;\r
672\r
673 //\r
674 // Check input parameters.\r
675 //\r
676 if ((Cert == NULL) || (CACert == NULL)) {\r
677 return FALSE;\r
678 }\r
679\r
680 Status = FALSE;\r
681 X509Cert = NULL;\r
682 X509CACert = NULL;\r
683 CertStore = NULL;\r
684 CertCtx = NULL;\r
685\r
686 //\r
687 // Register & Initialize necessary digest algorithms for certificate verification.\r
688 //\r
689 if (EVP_add_digest (EVP_md5 ()) == 0) {\r
690 goto _Exit;\r
691 }\r
692\r
693 if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
694 goto _Exit;\r
695 }\r
696\r
697 if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
698 goto _Exit;\r
699 }\r
700\r
701 //\r
702 // Read DER-encoded certificate to be verified and Construct X509 object.\r
703 //\r
704 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
705 if ((X509Cert == NULL) || (!Status)) {\r
706 Status = FALSE;\r
707 goto _Exit;\r
708 }\r
709\r
710 //\r
711 // Read DER-encoded root certificate and Construct X509 object.\r
712 //\r
713 Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **)&X509CACert);\r
714 if ((X509CACert == NULL) || (!Status)) {\r
715 Status = FALSE;\r
716 goto _Exit;\r
717 }\r
718\r
719 Status = FALSE;\r
720\r
721 //\r
722 // Set up X509 Store for trusted certificate.\r
723 //\r
724 CertStore = X509_STORE_new ();\r
725 if (CertStore == NULL) {\r
726 goto _Exit;\r
727 }\r
728\r
729 if (!(X509_STORE_add_cert (CertStore, X509CACert))) {\r
730 goto _Exit;\r
731 }\r
732\r
733 //\r
734 // Allow partial certificate chains, terminated by a non-self-signed but\r
735 // still trusted intermediate certificate. Also disable time checks.\r
736 //\r
737 X509_STORE_set_flags (\r
738 CertStore,\r
739 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME\r
740 );\r
741\r
742 //\r
743 // Set up X509_STORE_CTX for the subsequent verification operation.\r
744 //\r
745 CertCtx = X509_STORE_CTX_new ();\r
746 if (CertCtx == NULL) {\r
747 goto _Exit;\r
748 }\r
749\r
750 if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {\r
751 goto _Exit;\r
752 }\r
753\r
754 //\r
755 // X509 Certificate Verification.\r
756 //\r
757 Status = (BOOLEAN)X509_verify_cert (CertCtx);\r
758 X509_STORE_CTX_cleanup (CertCtx);\r
759\r
760_Exit:\r
761 //\r
762 // Release Resources.\r
763 //\r
764 if (X509Cert != NULL) {\r
765 X509_free (X509Cert);\r
766 }\r
767\r
768 if (X509CACert != NULL) {\r
769 X509_free (X509CACert);\r
770 }\r
771\r
772 if (CertStore != NULL) {\r
773 X509_STORE_free (CertStore);\r
774 }\r
775\r
776 X509_STORE_CTX_free (CertCtx);\r
777\r
778 return Status;\r
779}\r
780\r
781/**\r
782 Retrieve the TBSCertificate from one given X.509 certificate.\r
783\r
784 @param[in] Cert Pointer to the given DER-encoded X509 certificate.\r
785 @param[in] CertSize Size of the X509 certificate in bytes.\r
786 @param[out] TBSCert DER-Encoded To-Be-Signed certificate.\r
787 @param[out] TBSCertSize Size of the TBS certificate in bytes.\r
788\r
789 If Cert is NULL, then return FALSE.\r
790 If TBSCert is NULL, then return FALSE.\r
791 If TBSCertSize is NULL, then return FALSE.\r
792\r
793 @retval TRUE The TBSCertificate was retrieved successfully.\r
794 @retval FALSE Invalid X.509 certificate.\r
795\r
796**/\r
797BOOLEAN\r
798EFIAPI\r
799X509GetTBSCert (\r
800 IN CONST UINT8 *Cert,\r
801 IN UINTN CertSize,\r
802 OUT UINT8 **TBSCert,\r
803 OUT UINTN *TBSCertSize\r
804 )\r
805{\r
806 CONST UINT8 *Temp;\r
807 UINT32 Asn1Tag;\r
808 UINT32 ObjClass;\r
809 UINTN Length;\r
810\r
811 //\r
812 // Check input parameters.\r
813 //\r
814 if ((Cert == NULL) || (TBSCert == NULL) ||\r
815 (TBSCertSize == NULL) || (CertSize > INT_MAX))\r
816 {\r
817 return FALSE;\r
818 }\r
819\r
820 //\r
821 // An X.509 Certificate is: (defined in RFC3280)\r
822 // Certificate ::= SEQUENCE {\r
823 // tbsCertificate TBSCertificate,\r
824 // signatureAlgorithm AlgorithmIdentifier,\r
825 // signature BIT STRING }\r
826 //\r
827 // and\r
828 //\r
829 // TBSCertificate ::= SEQUENCE {\r
830 // version [0] Version DEFAULT v1,\r
831 // ...\r
832 // }\r
833 //\r
834 // So we can just ASN1-parse the x.509 DER-encoded data. If we strip\r
835 // the first SEQUENCE, the second SEQUENCE is the TBSCertificate.\r
836 //\r
837 Temp = Cert;\r
838 Length = 0;\r
839 ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);\r
840\r
841 if (Asn1Tag != V_ASN1_SEQUENCE) {\r
842 return FALSE;\r
843 }\r
844\r
845 *TBSCert = (UINT8 *)Temp;\r
846\r
847 ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);\r
848 //\r
849 // Verify the parsed TBSCertificate is one correct SEQUENCE data.\r
850 //\r
851 if (Asn1Tag != V_ASN1_SEQUENCE) {\r
852 return FALSE;\r
853 }\r
854\r
855 *TBSCertSize = Length + (Temp - *TBSCert);\r
856\r
857 return TRUE;\r
858}\r
859\r
860/**\r
861 Retrieve the EC Public Key from one DER-encoded X509 certificate.\r
862\r
863 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
864 @param[in] CertSize Size of the X509 certificate in bytes.\r
865 @param[out] EcContext Pointer to new-generated EC DSA context which contain the retrieved\r
866 EC public key component. Use EcFree() function to free the\r
867 resource.\r
868\r
869 If Cert is NULL, then return FALSE.\r
870 If EcContext is NULL, then return FALSE.\r
871\r
872 @retval TRUE EC Public Key was retrieved successfully.\r
873 @retval FALSE Fail to retrieve EC public key from X509 certificate.\r
874\r
875**/\r
876BOOLEAN\r
877EFIAPI\r
878EcGetPublicKeyFromX509 (\r
879 IN CONST UINT8 *Cert,\r
880 IN UINTN CertSize,\r
881 OUT VOID **EcContext\r
882 )\r
883{\r
884 BOOLEAN Status;\r
885 EVP_PKEY *Pkey;\r
886 X509 *X509Cert;\r
887\r
888 //\r
889 // Check input parameters.\r
890 //\r
891 if ((Cert == NULL) || (EcContext == NULL)) {\r
892 return FALSE;\r
893 }\r
894\r
895 Pkey = NULL;\r
896 X509Cert = NULL;\r
897\r
898 //\r
899 // Read DER-encoded X509 Certificate and Construct X509 object.\r
900 //\r
901 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
902 if ((X509Cert == NULL) || (!Status)) {\r
903 Status = FALSE;\r
904 goto _Exit;\r
905 }\r
906\r
907 Status = FALSE;\r
908\r
909 //\r
910 // Retrieve and check EVP_PKEY data from X509 Certificate.\r
911 //\r
912 Pkey = X509_get_pubkey (X509Cert);\r
913 if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_EC)) {\r
914 goto _Exit;\r
915 }\r
916\r
917 //\r
918 // Duplicate EC Context from the retrieved EVP_PKEY.\r
919 //\r
920 if ((*EcContext = EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey))) != NULL) {\r
921 Status = TRUE;\r
922 }\r
923\r
924_Exit:\r
925 //\r
926 // Release Resources.\r
927 //\r
928 if (X509Cert != NULL) {\r
929 X509_free (X509Cert);\r
930 }\r
931\r
932 if (Pkey != NULL) {\r
933 EVP_PKEY_free (Pkey);\r
934 }\r
935\r
936 return Status;\r
937}\r
938\r
939/**\r
940 Retrieve the version from one X.509 certificate.\r
941\r
942 If Cert is NULL, then return FALSE.\r
943 If CertSize is 0, then return FALSE.\r
944 If this interface is not supported, then return FALSE.\r
945\r
946 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
947 @param[in] CertSize Size of the X509 certificate in bytes.\r
948 @param[out] Version Pointer to the retrieved version integer.\r
949\r
950 @retval TRUE The certificate version retrieved successfully.\r
951 @retval FALSE If Cert is NULL or CertSize is Zero.\r
952 @retval FALSE The operation is not supported.\r
953\r
954**/\r
955BOOLEAN\r
956EFIAPI\r
957X509GetVersion (\r
958 IN CONST UINT8 *Cert,\r
959 IN UINTN CertSize,\r
960 OUT UINTN *Version\r
961 )\r
962{\r
963 BOOLEAN Status;\r
964 X509 *X509Cert;\r
965\r
966 X509Cert = NULL;\r
967 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
968 if ((X509Cert == NULL) || (!Status)) {\r
969 //\r
970 // Invalid X.509 Certificate\r
971 //\r
972 Status = FALSE;\r
973 }\r
974\r
975 if (Status) {\r
976 *Version = X509_get_version (X509Cert);\r
977 }\r
978\r
979 if (X509Cert != NULL) {\r
980 X509_free (X509Cert);\r
981 }\r
982\r
983 return Status;\r
984}\r
985\r
986/**\r
987 Retrieve the serialNumber from one X.509 certificate.\r
988\r
989 If Cert is NULL, then return FALSE.\r
990 If CertSize is 0, then return FALSE.\r
991 If this interface is not supported, then return FALSE.\r
992\r
993 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
994 @param[in] CertSize Size of the X509 certificate in bytes.\r
995 @param[out] SerialNumber Pointer to the retrieved certificate SerialNumber bytes.\r
996 @param[in, out] SerialNumberSize The size in bytes of the SerialNumber buffer on input,\r
997 and the size of buffer returned SerialNumber on output.\r
998\r
999 @retval TRUE The certificate serialNumber retrieved successfully.\r
1000 @retval FALSE If Cert is NULL or CertSize is Zero.\r
1001 If SerialNumberSize is NULL.\r
1002 If Certificate is invalid.\r
1003 @retval FALSE If no SerialNumber exists.\r
1004 @retval FALSE If the SerialNumber is NULL. The required buffer size\r
1005 (including the final null) is returned in the\r
1006 SerialNumberSize parameter.\r
1007 @retval FALSE The operation is not supported.\r
1008**/\r
1009BOOLEAN\r
1010EFIAPI\r
1011X509GetSerialNumber (\r
1012 IN CONST UINT8 *Cert,\r
1013 IN UINTN CertSize,\r
1014 OUT UINT8 *SerialNumber, OPTIONAL\r
1015 IN OUT UINTN *SerialNumberSize\r
1016 )\r
1017{\r
1018 BOOLEAN Status;\r
1019 X509 *X509Cert;\r
1020 ASN1_INTEGER *Asn1Integer;\r
1021\r
1022 Status = FALSE;\r
1023 //\r
1024 // Check input parameters.\r
1025 //\r
1026 if ((Cert == NULL) || (SerialNumberSize == NULL)) {\r
1027 return Status;\r
1028 }\r
1029\r
1030 X509Cert = NULL;\r
1031\r
1032 //\r
1033 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1034 //\r
1035 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1036 if ((X509Cert == NULL) || (!Status)) {\r
1037 *SerialNumberSize = 0;\r
1038 Status = FALSE;\r
1039 goto _Exit;\r
1040 }\r
1041\r
1042 //\r
1043 // Retrieve subject name from certificate object.\r
1044 //\r
1045 Asn1Integer = X509_get_serialNumber (X509Cert);\r
1046 if (Asn1Integer == NULL) {\r
1047 *SerialNumberSize = 0;\r
1048 Status = FALSE;\r
1049 goto _Exit;\r
1050 }\r
1051\r
1052 if (*SerialNumberSize < (UINTN)Asn1Integer->length) {\r
1053 *SerialNumberSize = (UINTN)Asn1Integer->length;\r
1054 Status = FALSE;\r
1055 goto _Exit;\r
1056 }\r
1057\r
1058 if (SerialNumber != NULL) {\r
1059 CopyMem (SerialNumber, Asn1Integer->data, *SerialNumberSize);\r
1060 Status = TRUE;\r
1061 }\r
1062\r
1063 *SerialNumberSize = (UINTN)Asn1Integer->length;\r
1064\r
1065_Exit:\r
1066 //\r
1067 // Release Resources.\r
1068 //\r
1069 if (X509Cert != NULL) {\r
1070 X509_free (X509Cert);\r
1071 }\r
1072\r
1073 return Status;\r
1074}\r
1075\r
1076/**\r
1077 Retrieve the issuer bytes from one X.509 certificate.\r
1078\r
1079 If Cert is NULL, then return FALSE.\r
1080 If CertIssuerSize is NULL, then return FALSE.\r
1081 If this interface is not supported, then return FALSE.\r
1082\r
1083 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1084 @param[in] CertSize Size of the X509 certificate in bytes.\r
1085 @param[out] CertIssuer Pointer to the retrieved certificate subject bytes.\r
1086 @param[in, out] CertIssuerSize The size in bytes of the CertIssuer buffer on input,\r
1087 and the size of buffer returned CertSubject on output.\r
1088\r
1089 @retval TRUE The certificate issuer retrieved successfully.\r
1090 @retval FALSE Invalid certificate, or the CertIssuerSize is too small for the result.\r
1091 The CertIssuerSize will be updated with the required size.\r
1092 @retval FALSE This interface is not supported.\r
1093\r
1094**/\r
1095BOOLEAN\r
1096EFIAPI\r
1097X509GetIssuerName (\r
1098 IN CONST UINT8 *Cert,\r
1099 IN UINTN CertSize,\r
1100 OUT UINT8 *CertIssuer,\r
1101 IN OUT UINTN *CertIssuerSize\r
1102 )\r
1103{\r
1104 BOOLEAN Status;\r
1105 X509 *X509Cert;\r
1106 X509_NAME *X509Name;\r
1107 UINTN X509NameSize;\r
1108\r
1109 //\r
1110 // Check input parameters.\r
1111 //\r
1112 if ((Cert == NULL) || (CertIssuerSize == NULL)) {\r
1113 return FALSE;\r
1114 }\r
1115\r
1116 X509Cert = NULL;\r
1117\r
1118 //\r
1119 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1120 //\r
1121 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1122 if ((X509Cert == NULL) || (!Status)) {\r
1123 Status = FALSE;\r
1124 goto _Exit;\r
1125 }\r
1126\r
1127 Status = FALSE;\r
1128\r
1129 //\r
1130 // Retrieve subject name from certificate object.\r
1131 //\r
1132 X509Name = X509_get_subject_name (X509Cert);\r
1133 if (X509Name == NULL) {\r
1134 goto _Exit;\r
1135 }\r
1136\r
1137 X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
1138 if (*CertIssuerSize < X509NameSize) {\r
1139 *CertIssuerSize = X509NameSize;\r
1140 goto _Exit;\r
1141 }\r
1142\r
1143 *CertIssuerSize = X509NameSize;\r
1144 if (CertIssuer != NULL) {\r
1145 i2d_X509_NAME (X509Name, &CertIssuer);\r
1146 Status = TRUE;\r
1147 }\r
1148\r
1149_Exit:\r
1150 //\r
1151 // Release Resources.\r
1152 //\r
1153 if (X509Cert != NULL) {\r
1154 X509_free (X509Cert);\r
1155 }\r
1156\r
1157 return Status;\r
1158}\r
1159\r
1160/**\r
1161 Retrieve the Signature Algorithm from one X.509 certificate.\r
1162\r
1163 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1164 @param[in] CertSize Size of the X509 certificate in bytes.\r
1165 @param[out] Oid Signature Algorithm Object identifier buffer.\r
1166 @param[in,out] OidSize Signature Algorithm Object identifier buffer size\r
1167\r
1168 @retval TRUE The certificate Extension data retrieved successfully.\r
1169 @retval FALSE If Cert is NULL.\r
1170 If OidSize is NULL.\r
1171 If Oid is not NULL and *OidSize is 0.\r
1172 If Certificate is invalid.\r
1173 @retval FALSE If no SignatureType.\r
1174 @retval FALSE If the Oid is NULL. The required buffer size\r
1175 is returned in the OidSize.\r
1176 @retval FALSE The operation is not supported.\r
1177**/\r
1178BOOLEAN\r
1179EFIAPI\r
1180X509GetSignatureAlgorithm (\r
1181 IN CONST UINT8 *Cert,\r
1182 IN UINTN CertSize,\r
1183 OUT UINT8 *Oid, OPTIONAL\r
1184 IN OUT UINTN *OidSize\r
1185 )\r
1186{\r
1187 BOOLEAN Status;\r
1188 X509 *X509Cert;\r
1189 int Nid;\r
1190 ASN1_OBJECT *Asn1Obj;\r
1191\r
1192 //\r
1193 // Check input parameters.\r
1194 //\r
1195 if ((Cert == NULL) || (OidSize == NULL) || (CertSize == 0)) {\r
1196 return FALSE;\r
1197 }\r
1198\r
1199 X509Cert = NULL;\r
1200 Status = FALSE;\r
1201\r
1202 //\r
1203 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1204 //\r
1205 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1206 if ((X509Cert == NULL) || (!Status)) {\r
1207 Status = FALSE;\r
1208 goto _Exit;\r
1209 }\r
1210\r
1211 //\r
1212 // Retrieve subject name from certificate object.\r
1213 //\r
1214 Nid = X509_get_signature_nid (X509Cert);\r
1215 if (Nid == NID_undef) {\r
1216 *OidSize = 0;\r
1217 Status = FALSE;\r
1218 goto _Exit;\r
1219 }\r
1220\r
1221 Asn1Obj = OBJ_nid2obj (Nid);\r
1222 if (Asn1Obj == NULL) {\r
1223 *OidSize = 0;\r
1224 Status = FALSE;\r
1225 goto _Exit;\r
1226 }\r
1227\r
1228 if (*OidSize < (UINTN)Asn1Obj->length) {\r
1229 *OidSize = Asn1Obj->length;\r
1230 Status = FALSE;\r
1231 goto _Exit;\r
1232 }\r
1233\r
1234 if (Oid != NULL) {\r
1235 CopyMem (Oid, Asn1Obj->data, Asn1Obj->length);\r
1236 }\r
1237\r
1238 *OidSize = Asn1Obj->length;\r
1239 Status = TRUE;\r
1240\r
1241_Exit:\r
1242 //\r
1243 // Release Resources.\r
1244 //\r
1245 if (X509Cert != NULL) {\r
1246 X509_free (X509Cert);\r
1247 }\r
1248\r
1249 return Status;\r
1250}\r
1251\r
1252/**\r
1253 Retrieve Extension data from one X.509 certificate.\r
1254\r
1255 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1256 @param[in] CertSize Size of the X509 certificate in bytes.\r
1257 @param[in] Oid Object identifier buffer\r
1258 @param[in] OidSize Object identifier buffer size\r
1259 @param[out] ExtensionData Extension bytes.\r
1260 @param[in, out] ExtensionDataSize Extension bytes size.\r
1261\r
1262 @retval TRUE The certificate Extension data retrieved successfully.\r
1263 @retval FALSE If Cert is NULL.\r
1264 If ExtensionDataSize is NULL.\r
1265 If ExtensionData is not NULL and *ExtensionDataSize is 0.\r
1266 If Certificate is invalid.\r
1267 @retval FALSE If no Extension entry match Oid.\r
1268 @retval FALSE If the ExtensionData is NULL. The required buffer size\r
1269 is returned in the ExtensionDataSize parameter.\r
1270 @retval FALSE The operation is not supported.\r
1271**/\r
1272BOOLEAN\r
1273EFIAPI\r
1274X509GetExtensionData (\r
1275 IN CONST UINT8 *Cert,\r
1276 IN UINTN CertSize,\r
1277 IN CONST UINT8 *Oid,\r
1278 IN UINTN OidSize,\r
1279 OUT UINT8 *ExtensionData,\r
1280 IN OUT UINTN *ExtensionDataSize\r
1281 )\r
1282{\r
1283 BOOLEAN Status;\r
1284 INTN i;\r
1285 X509 *X509Cert;\r
1286\r
1287 CONST STACK_OF (X509_EXTENSION) *Extensions;\r
1288 ASN1_OBJECT *Asn1Obj;\r
1289 ASN1_OCTET_STRING *Asn1Oct;\r
1290 X509_EXTENSION *Ext;\r
1291 UINTN ObjLength;\r
1292 UINTN OctLength;\r
1293\r
1294 //\r
1295 // Check input parameters.\r
1296 //\r
1297 if ((Cert == NULL) || (CertSize == 0) || (Oid == NULL) || (OidSize == 0) || (ExtensionDataSize == NULL)) {\r
1298 return FALSE;\r
1299 }\r
1300\r
1301 X509Cert = NULL;\r
1302 Status = FALSE;\r
1303\r
1304 //\r
1305 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1306 //\r
1307 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1308 if ((X509Cert == NULL) || (!Status)) {\r
1309 *ExtensionDataSize = 0;\r
1310 goto Cleanup;\r
1311 }\r
1312\r
1313 //\r
1314 // Retrieve Extensions from certificate object.\r
1315 //\r
1316 Extensions = X509_get0_extensions (X509Cert);\r
1317 if (sk_X509_EXTENSION_num (Extensions) <= 0) {\r
1318 *ExtensionDataSize = 0;\r
1319 goto Cleanup;\r
1320 }\r
1321\r
1322 //\r
1323 // Traverse Extensions\r
1324 //\r
1325 Status = FALSE;\r
1326 Asn1Oct = NULL;\r
1327 OctLength = 0;\r
1328 for (i = 0; i < sk_X509_EXTENSION_num (Extensions); i++) {\r
1329 Ext = sk_X509_EXTENSION_value (Extensions, (int)i);\r
1330 if (Ext == NULL) {\r
1331 continue;\r
1332 }\r
1333\r
1334 Asn1Obj = X509_EXTENSION_get_object (Ext);\r
1335 if (Asn1Obj == NULL) {\r
1336 continue;\r
1337 }\r
1338\r
1339 Asn1Oct = X509_EXTENSION_get_data (Ext);\r
1340 if (Asn1Oct == NULL) {\r
1341 continue;\r
1342 }\r
1343\r
1344 ObjLength = OBJ_length (Asn1Obj);\r
1345 OctLength = ASN1_STRING_length (Asn1Oct);\r
1346 if ((OidSize == ObjLength) && (CompareMem (OBJ_get0_data (Asn1Obj), Oid, OidSize) == 0)) {\r
1347 //\r
1348 // Extension Found\r
1349 //\r
1350 Status = TRUE;\r
1351 break;\r
1352 }\r
1353\r
1354 //\r
1355 // reset to 0 if not found\r
1356 //\r
1357 OctLength = 0;\r
1358 }\r
1359\r
1360 if (Status) {\r
1361 if (*ExtensionDataSize < OctLength) {\r
1362 *ExtensionDataSize = OctLength;\r
1363 Status = FALSE;\r
1364 goto Cleanup;\r
1365 }\r
1366\r
1367 if (Asn1Oct != NULL) {\r
1368 CopyMem (ExtensionData, ASN1_STRING_get0_data (Asn1Oct), OctLength);\r
1369 }\r
1370\r
1371 *ExtensionDataSize = OctLength;\r
1372 } else {\r
1373 *ExtensionDataSize = 0;\r
1374 }\r
1375\r
1376Cleanup:\r
1377 //\r
1378 // Release Resources.\r
1379 //\r
1380 if (X509Cert != NULL) {\r
1381 X509_free (X509Cert);\r
1382 }\r
1383\r
1384 return Status;\r
1385}\r
1386\r
1387/**\r
1388 Retrieve the Extended Key Usage from one X.509 certificate.\r
1389\r
1390 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1391 @param[in] CertSize Size of the X509 certificate in bytes.\r
1392 @param[out] Usage Key Usage bytes.\r
1393 @param[in, out] UsageSize Key Usage buffer sizs in bytes.\r
1394\r
1395 @retval TRUE The Usage bytes retrieve successfully.\r
1396 @retval FALSE If Cert is NULL.\r
1397 If CertSize is NULL.\r
1398 If Usage is not NULL and *UsageSize is 0.\r
1399 If Cert is invalid.\r
1400 @retval FALSE If the Usage is NULL. The required buffer size\r
1401 is returned in the UsageSize parameter.\r
1402 @retval FALSE The operation is not supported.\r
1403**/\r
1404BOOLEAN\r
1405EFIAPI\r
1406X509GetExtendedKeyUsage (\r
1407 IN CONST UINT8 *Cert,\r
1408 IN UINTN CertSize,\r
1409 OUT UINT8 *Usage,\r
1410 IN OUT UINTN *UsageSize\r
1411 )\r
1412{\r
1413 BOOLEAN Status;\r
1414\r
1415 Status = X509GetExtensionData (Cert, CertSize, mOidExtKeyUsage, sizeof (mOidExtKeyUsage), Usage, UsageSize);\r
1416 return Status;\r
1417}\r
1418\r
1419/**\r
1420 Retrieve the Validity from one X.509 certificate\r
1421\r
1422 If Cert is NULL, then return FALSE.\r
1423 If CertIssuerSize is NULL, then return FALSE.\r
1424 If this interface is not supported, then return FALSE.\r
1425\r
1426 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1427 @param[in] CertSize Size of the X509 certificate in bytes.\r
1428 @param[out] From notBefore Pointer to DateTime object.\r
1429 @param[in,out] FromSize notBefore DateTime object size.\r
1430 @param[out] To notAfter Pointer to DateTime object.\r
1431 @param[in,out] ToSize notAfter DateTime object size.\r
1432\r
1433 Note: X509CompareDateTime to compare DateTime oject\r
1434 x509SetDateTime to get a DateTime object from a DateTimeStr\r
1435\r
1436 @retval TRUE The certificate Validity retrieved successfully.\r
1437 @retval FALSE Invalid certificate, or Validity retrieve failed.\r
1438 @retval FALSE This interface is not supported.\r
1439**/\r
1440BOOLEAN\r
1441EFIAPI\r
1442X509GetValidity (\r
1443 IN CONST UINT8 *Cert,\r
1444 IN UINTN CertSize,\r
1445 IN UINT8 *From,\r
1446 IN OUT UINTN *FromSize,\r
1447 IN UINT8 *To,\r
1448 IN OUT UINTN *ToSize\r
1449 )\r
1450{\r
1451 BOOLEAN Status;\r
1452 X509 *X509Cert;\r
1453 CONST ASN1_TIME *F;\r
1454 CONST ASN1_TIME *T;\r
1455 UINTN TSize;\r
1456 UINTN FSize;\r
1457\r
1458 //\r
1459 // Check input parameters.\r
1460 //\r
1461 if ((Cert == NULL) || (FromSize == NULL) || (ToSize == NULL) || (CertSize == 0)) {\r
1462 return FALSE;\r
1463 }\r
1464\r
1465 X509Cert = NULL;\r
1466 Status = FALSE;\r
1467\r
1468 //\r
1469 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1470 //\r
1471 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1472 if ((X509Cert == NULL) || (!Status)) {\r
1473 goto _Exit;\r
1474 }\r
1475\r
1476 //\r
1477 // Retrieve Validity from/to from certificate object.\r
1478 //\r
1479 F = X509_get0_notBefore (X509Cert);\r
1480 T = X509_get0_notAfter (X509Cert);\r
1481\r
1482 if ((F == NULL) || (T == NULL)) {\r
1483 goto _Exit;\r
1484 }\r
1485\r
1486 FSize = sizeof (ASN1_TIME) + F->length;\r
1487 if (*FromSize < FSize) {\r
1488 *FromSize = FSize;\r
1489 goto _Exit;\r
1490 }\r
1491\r
1492 *FromSize = FSize;\r
1493 if (From != NULL) {\r
1494 CopyMem (From, F, sizeof (ASN1_TIME));\r
1495 ((ASN1_TIME *)From)->data = From + sizeof (ASN1_TIME);\r
1496 CopyMem (From + sizeof (ASN1_TIME), F->data, F->length);\r
1497 }\r
1498\r
1499 TSize = sizeof (ASN1_TIME) + T->length;\r
1500 if (*ToSize < TSize) {\r
1501 *ToSize = TSize;\r
1502 goto _Exit;\r
1503 }\r
1504\r
1505 *ToSize = TSize;\r
1506 if (To != NULL) {\r
1507 CopyMem (To, T, sizeof (ASN1_TIME));\r
1508 ((ASN1_TIME *)To)->data = To + sizeof (ASN1_TIME);\r
1509 CopyMem (To + sizeof (ASN1_TIME), T->data, T->length);\r
1510 }\r
1511\r
1512 Status = TRUE;\r
1513\r
1514_Exit:\r
1515 //\r
1516 // Release Resources.\r
1517 //\r
1518 if (X509Cert != NULL) {\r
1519 X509_free (X509Cert);\r
1520 }\r
1521\r
1522 return Status;\r
1523}\r
1524\r
1525/**\r
1526 Format a DateTimeStr to DataTime object in DataTime Buffer\r
1527\r
1528 If DateTimeStr is NULL, then return FALSE.\r
1529 If DateTimeSize is NULL, then return FALSE.\r
1530 If this interface is not supported, then return FALSE.\r
1531\r
1532 @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ\r
1533 Ref: https://www.w3.org/TR/NOTE-datetime\r
1534 Z stand for UTC time\r
1535 @param[out] DateTime Pointer to a DateTime object.\r
1536 @param[in,out] DateTimeSize DateTime object buffer size.\r
1537\r
1538 @retval TRUE The DateTime object create successfully.\r
1539 @retval FALSE If DateTimeStr is NULL.\r
1540 If DateTimeSize is NULL.\r
1541 If DateTime is not NULL and *DateTimeSize is 0.\r
1542 If Year Month Day Hour Minute Second combination is invalid datetime.\r
1543 @retval FALSE If the DateTime is NULL. The required buffer size\r
1544 (including the final null) is returned in the\r
1545 DateTimeSize parameter.\r
1546 @retval FALSE The operation is not supported.\r
1547**/\r
1548BOOLEAN\r
1549EFIAPI\r
1550X509FormatDateTime (\r
1551 IN CONST CHAR8 *DateTimeStr,\r
1552 OUT VOID *DateTime,\r
1553 IN OUT UINTN *DateTimeSize\r
1554 )\r
1555{\r
1556 BOOLEAN Status;\r
1557 INT32 Ret;\r
1558 ASN1_TIME *Dt;\r
1559 UINTN DSize;\r
1560\r
1561 Dt = NULL;\r
1562 Status = FALSE;\r
1563\r
1564 Dt = ASN1_TIME_new ();\r
1565 if (Dt == NULL) {\r
1566 Status = FALSE;\r
1567 goto Cleanup;\r
1568 }\r
1569\r
1570 Ret = ASN1_TIME_set_string_X509 (Dt, DateTimeStr);\r
1571 if (Ret != 1) {\r
1572 Status = FALSE;\r
1573 goto Cleanup;\r
1574 }\r
1575\r
1576 DSize = sizeof (ASN1_TIME) + Dt->length;\r
1577 if (*DateTimeSize < DSize) {\r
1578 *DateTimeSize = DSize;\r
1579 Status = FALSE;\r
1580 goto Cleanup;\r
1581 }\r
1582\r
1583 *DateTimeSize = DSize;\r
1584 if (DateTime != NULL) {\r
1585 CopyMem (DateTime, Dt, sizeof (ASN1_TIME));\r
1586 ((ASN1_TIME *)DateTime)->data = (UINT8 *)DateTime + sizeof (ASN1_TIME);\r
1587 CopyMem ((UINT8 *)DateTime + sizeof (ASN1_TIME), Dt->data, Dt->length);\r
1588 }\r
1589\r
1590 Status = TRUE;\r
1591\r
1592Cleanup:\r
1593 if (Dt != NULL) {\r
1594 ASN1_TIME_free (Dt);\r
1595 }\r
1596\r
1597 return Status;\r
1598}\r
1599\r
1600/**\r
1601 Compare DateTime1 object and DateTime2 object.\r
1602\r
1603 If DateTime1 is NULL, then return -2.\r
1604 If DateTime2 is NULL, then return -2.\r
1605 If DateTime1 == DateTime2, then return 0\r
1606 If DateTime1 > DateTime2, then return 1\r
1607 If DateTime1 < DateTime2, then return -1\r
1608\r
1609 @param[in] DateTime1 Pointer to a DateTime Ojbect\r
1610 @param[in] DateTime2 Pointer to a DateTime Object\r
1611\r
1612 @retval 0 If DateTime1 == DateTime2\r
1613 @retval 1 If DateTime1 > DateTime2\r
1614 @retval -1 If DateTime1 < DateTime2\r
1615**/\r
1616INT32\r
1617EFIAPI\r
1618X509CompareDateTime (\r
1619 IN CONST VOID *DateTime1,\r
1620 IN CONST VOID *DateTime2\r
1621 )\r
1622{\r
1623 return (INT32)ASN1_TIME_compare (DateTime1, DateTime2);\r
1624}\r
1625\r
1626/**\r
1627 Retrieve the Key Usage from one X.509 certificate.\r
1628\r
1629 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1630 @param[in] CertSize Size of the X509 certificate in bytes.\r
1631 @param[out] Usage Key Usage (CRYPTO_X509_KU_*)\r
1632\r
1633 @retval TRUE The certificate Key Usage retrieved successfully.\r
1634 @retval FALSE Invalid certificate, or Usage is NULL\r
1635 @retval FALSE This interface is not supported.\r
1636**/\r
1637BOOLEAN\r
1638EFIAPI\r
1639X509GetKeyUsage (\r
1640 IN CONST UINT8 *Cert,\r
1641 IN UINTN CertSize,\r
1642 OUT UINTN *Usage\r
1643 )\r
1644{\r
1645 BOOLEAN Status;\r
1646 X509 *X509Cert;\r
1647\r
1648 //\r
1649 // Check input parameters.\r
1650 //\r
1651 if ((Cert == NULL) || (Usage == NULL)) {\r
1652 return FALSE;\r
1653 }\r
1654\r
1655 X509Cert = NULL;\r
1656 Status = FALSE;\r
1657\r
1658 //\r
1659 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1660 //\r
1661 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1662 if ((X509Cert == NULL) || (!Status)) {\r
1663 goto _Exit;\r
1664 }\r
1665\r
1666 //\r
1667 // Retrieve subject name from certificate object.\r
1668 //\r
1669 *Usage = X509_get_key_usage (X509Cert);\r
1670 if (*Usage == NID_undef) {\r
1671 goto _Exit;\r
1672 }\r
1673\r
1674 Status = TRUE;\r
1675\r
1676_Exit:\r
1677 //\r
1678 // Release Resources.\r
1679 //\r
1680 if (X509Cert != NULL) {\r
1681 X509_free (X509Cert);\r
1682 }\r
1683\r
1684 return Status;\r
1685}\r
1686\r
1687/**\r
1688 Verify one X509 certificate was issued by the trusted CA.\r
1689 @param[in] RootCert Trusted Root Certificate buffer\r
1690\r
1691 @param[in] RootCertLength Trusted Root Certificate buffer length\r
1692 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates\r
1693 where the first certificate is signed by the Root\r
1694 Certificate or is the Root Cerificate itself. and\r
1695 subsequent cerificate is signed by the preceding\r
1696 cerificate.\r
1697 @param[in] CertChainLength Total length of the certificate chain, in bytes.\r
1698\r
1699 @retval TRUE All cerificates was issued by the first certificate in X509Certchain.\r
1700 @retval FALSE Invalid certificate or the certificate was not issued by the given\r
1701 trusted CA.\r
1702**/\r
1703BOOLEAN\r
1704EFIAPI\r
1705X509VerifyCertChain (\r
1706 IN CONST UINT8 *RootCert,\r
1707 IN UINTN RootCertLength,\r
1708 IN CONST UINT8 *CertChain,\r
1709 IN UINTN CertChainLength\r
1710 )\r
1711{\r
1712 CONST UINT8 *TmpPtr;\r
1713 UINTN Length;\r
1714 UINT32 Asn1Tag;\r
1715 UINT32 ObjClass;\r
1716 CONST UINT8 *CurrentCert;\r
1717 UINTN CurrentCertLen;\r
1718 CONST UINT8 *PrecedingCert;\r
1719 UINTN PrecedingCertLen;\r
1720 BOOLEAN VerifyFlag;\r
1721 INT32 Ret;\r
1722\r
1723 PrecedingCert = RootCert;\r
1724 PrecedingCertLen = RootCertLength;\r
1725\r
1726 CurrentCert = CertChain;\r
1727 Length = 0;\r
1728 CurrentCertLen = 0;\r
1729\r
1730 VerifyFlag = FALSE;\r
1731 while (TRUE) {\r
1732 TmpPtr = CurrentCert;\r
1733 Ret = ASN1_get_object (\r
1734 (CONST UINT8 **)&TmpPtr,\r
1735 (long *)&Length,\r
1736 (int *)&Asn1Tag,\r
1737 (int *)&ObjClass,\r
1738 (long)(CertChainLength + CertChain - TmpPtr)\r
1739 );\r
1740 if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
1741 break;\r
1742 }\r
1743\r
1744 //\r
1745 // Calculate CurrentCert length;\r
1746 //\r
1747 CurrentCertLen = TmpPtr - CurrentCert + Length;\r
1748\r
1749 //\r
1750 // Verify CurrentCert with preceding cert;\r
1751 //\r
1752 VerifyFlag = X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen);\r
1753 if (VerifyFlag == FALSE) {\r
1754 break;\r
1755 }\r
1756\r
1757 //\r
1758 // move Current cert to Preceding cert\r
1759 //\r
1760 PrecedingCertLen = CurrentCertLen;\r
1761 PrecedingCert = CurrentCert;\r
1762\r
1763 //\r
1764 // Move to next\r
1765 //\r
1766 CurrentCert = CurrentCert + CurrentCertLen;\r
1767 }\r
1768\r
1769 return VerifyFlag;\r
1770}\r
1771\r
1772/**\r
1773 Get one X509 certificate from CertChain.\r
1774\r
1775 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates\r
1776 where the first certificate is signed by the Root\r
1777 Certificate or is the Root Cerificate itself. and\r
1778 subsequent cerificate is signed by the preceding\r
1779 cerificate.\r
1780 @param[in] CertChainLength Total length of the certificate chain, in bytes.\r
1781\r
1782 @param[in] CertIndex Index of certificate.\r
1783\r
1784 @param[out] Cert The certificate at the index of CertChain.\r
1785 @param[out] CertLength The length certificate at the index of CertChain.\r
1786\r
1787 @retval TRUE Success.\r
1788 @retval FALSE Failed to get certificate from certificate chain.\r
1789**/\r
1790BOOLEAN\r
1791EFIAPI\r
1792X509GetCertFromCertChain (\r
1793 IN CONST UINT8 *CertChain,\r
1794 IN UINTN CertChainLength,\r
1795 IN CONST INT32 CertIndex,\r
1796 OUT CONST UINT8 **Cert,\r
1797 OUT UINTN *CertLength\r
1798 )\r
1799{\r
1800 UINTN Asn1Len;\r
1801 INT32 CurrentIndex;\r
1802 UINTN CurrentCertLen;\r
1803 CONST UINT8 *CurrentCert;\r
1804 CONST UINT8 *TmpPtr;\r
1805 INT32 Ret;\r
1806 UINT32 Asn1Tag;\r
1807 UINT32 ObjClass;\r
1808\r
1809 //\r
1810 // Check input parameters.\r
1811 //\r
1812 if ((CertChain == NULL) || (Cert == NULL) ||\r
1813 (CertIndex < -1) || (CertLength == NULL))\r
1814 {\r
1815 return FALSE;\r
1816 }\r
1817\r
1818 Asn1Len = 0;\r
1819 CurrentCertLen = 0;\r
1820 CurrentCert = CertChain;\r
1821 CurrentIndex = -1;\r
1822\r
1823 //\r
1824 // Traverse the certificate chain\r
1825 //\r
1826 while (TRUE) {\r
1827 TmpPtr = CurrentCert;\r
1828\r
1829 // Get asn1 object and taglen\r
1830 Ret = ASN1_get_object (\r
1831 (CONST UINT8 **)&TmpPtr,\r
1832 (long *)&Asn1Len,\r
1833 (int *)&Asn1Tag,\r
1834 (int *)&ObjClass,\r
1835 (long)(CertChainLength + CertChain - TmpPtr)\r
1836 );\r
1837 if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
1838 break;\r
1839 }\r
1840\r
1841 //\r
1842 // Calculate CurrentCert length;\r
1843 //\r
1844 CurrentCertLen = TmpPtr - CurrentCert + Asn1Len;\r
1845 CurrentIndex++;\r
1846\r
1847 if (CurrentIndex == CertIndex) {\r
1848 *Cert = CurrentCert;\r
1849 *CertLength = CurrentCertLen;\r
1850 return TRUE;\r
1851 }\r
1852\r
1853 //\r
1854 // Move to next\r
1855 //\r
1856 CurrentCert = CurrentCert + CurrentCertLen;\r
1857 }\r
1858\r
1859 //\r
1860 // If CertIndex is -1, Return the last certificate\r
1861 //\r
1862 if ((CertIndex == -1) && (CurrentIndex >= 0)) {\r
1863 *Cert = CurrentCert - CurrentCertLen;\r
1864 *CertLength = CurrentCertLen;\r
1865 return TRUE;\r
1866 }\r
1867\r
1868 return FALSE;\r
1869}\r
1870\r
1871/**\r
1872 Retrieve the tag and length of the tag.\r
1873\r
1874 @param Ptr The position in the ASN.1 data\r
1875 @param End End of data\r
1876 @param Length The variable that will receive the length\r
1877 @param Tag The expected tag\r
1878\r
1879 @retval TRUE Get tag successful\r
1880 @retval FALSe Failed to get tag or tag not match\r
1881**/\r
1882BOOLEAN\r
1883EFIAPI\r
1884Asn1GetTag (\r
1885 IN OUT UINT8 **Ptr,\r
1886 IN CONST UINT8 *End,\r
1887 OUT UINTN *Length,\r
1888 IN UINT32 Tag\r
1889 )\r
1890{\r
1891 UINT8 *PtrOld;\r
1892 INT32 ObjTag;\r
1893 INT32 ObjCls;\r
1894 long ObjLength;\r
1895\r
1896 //\r
1897 // Save Ptr position\r
1898 //\r
1899 PtrOld = *Ptr;\r
1900\r
1901 ASN1_get_object ((CONST UINT8 **)Ptr, &ObjLength, &ObjTag, &ObjCls, (INT32)(End - (*Ptr)));\r
1902 if ((ObjTag == (INT32)(Tag & CRYPTO_ASN1_TAG_VALUE_MASK)) &&\r
1903 (ObjCls == (INT32)(Tag & CRYPTO_ASN1_TAG_CLASS_MASK)))\r
1904 {\r
1905 *Length = (UINTN)ObjLength;\r
1906 return TRUE;\r
1907 } else {\r
1908 //\r
1909 // if doesn't match Tag, restore Ptr to origin Ptr\r
1910 //\r
1911 *Ptr = PtrOld;\r
1912 return FALSE;\r
1913 }\r
1914}\r
1915\r
1916/**\r
1917 Retrieve the basic constraints from one X.509 certificate.\r
1918\r
1919 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1920 @param[in] CertSize size of the X509 certificate in bytes.\r
1921 @param[out] BasicConstraints basic constraints bytes.\r
1922 @param[in, out] BasicConstraintsSize basic constraints buffer sizs in bytes.\r
1923\r
1924 @retval TRUE The basic constraints retrieve successfully.\r
1925 @retval FALSE If cert is NULL.\r
1926 If cert_size is NULL.\r
1927 If basic_constraints is not NULL and *basic_constraints_size is 0.\r
1928 If cert is invalid.\r
1929 @retval FALSE The required buffer size is small.\r
1930 The return buffer size is basic_constraints_size parameter.\r
1931 @retval FALSE If no Extension entry match oid.\r
1932 @retval FALSE The operation is not supported.\r
1933 **/\r
1934BOOLEAN\r
1935EFIAPI\r
1936X509GetExtendedBasicConstraints (\r
1937 CONST UINT8 *Cert,\r
1938 UINTN CertSize,\r
1939 UINT8 *BasicConstraints,\r
1940 UINTN *BasicConstraintsSize\r
1941 )\r
1942{\r
1943 BOOLEAN Status;\r
1944\r
1945 if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {\r
1946 return FALSE;\r
1947 }\r
1948\r
1949 Status = X509GetExtensionData (\r
1950 (UINT8 *)Cert,\r
1951 CertSize,\r
1952 mOidBasicConstraints,\r
1953 sizeof (mOidBasicConstraints),\r
1954 BasicConstraints,\r
1955 BasicConstraintsSize\r
1956 );\r
1957\r
1958 return Status;\r
1959}\r