]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
CryptoPkg: add new X509 function.
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptX509.c
CommitLineData
4a567c96 1/** @file\r
2 X.509 Certificate Handler Wrapper Implementation over OpenSSL.\r
3\r
66862136 4Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>\r
2009f6b4 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
4a567c96 6\r
7**/\r
8\r
9#include "InternalCryptLib.h"\r
10#include <openssl/x509.h>\r
8ecae3d6
QZ
11#include <openssl/x509v3.h>\r
12#include <crypto/asn1.h>\r
13#include <openssl/asn1.h>\r
1cae0c83 14#include <openssl/rsa.h>\r
b7d320f8 15\r
8ecae3d6
QZ
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
b7d320f8 27/**\r
28 Construct a X509 object from DER-encoded certificate data.\r
29\r
16d2c32c 30 If Cert is NULL, then return FALSE.\r
31 If SingleX509Cert is NULL, then return FALSE.\r
b7d320f8 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
1463ce18
QL
49 X509 *X509Cert;\r
50 CONST UINT8 *Temp;\r
b7d320f8 51\r
52 //\r
16d2c32c 53 // Check input parameters.\r
b7d320f8 54 //\r
7c342378 55 if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize > INT_MAX)) {\r
16d2c32c 56 return FALSE;\r
57 }\r
da9e7418 58\r
b7d320f8 59 //\r
60 // Read DER-encoded X509 Certificate and Construct X509 object.\r
61 //\r
1463ce18 62 Temp = Cert;\r
7c342378 63 X509Cert = d2i_X509 (NULL, &Temp, (long)CertSize);\r
b7d320f8 64 if (X509Cert == NULL) {\r
02ee8d3b 65 return FALSE;\r
b7d320f8 66 }\r
67\r
7c342378 68 *SingleX509Cert = (UINT8 *)X509Cert;\r
b7d320f8 69\r
02ee8d3b 70 return TRUE;\r
b7d320f8 71}\r
72\r
73/**\r
74 Construct a X509 stack object from a list of DER-encoded certificate data.\r
75\r
16d2c32c 76 If X509Stack is NULL, then return FALSE.\r
66862136 77 If this interface is not supported, then return FALSE.\r
b7d320f8 78\r
952bd229 79 @param[in, out] X509Stack On input, pointer to an existing or NULL X509 stack object.\r
b7d320f8 80 On output, pointer to the X509 stack object with new\r
81 inserted X509 certificate.\r
66862136
MK
82 @param[in] Args VA_LIST marker for the variable argument list.\r
83 A list of DER-encoded single certificate data followed\r
b7d320f8 84 by certificate size. A NULL terminates the list. The\r
85 pairs are the arguments to X509ConstructCertificate().\r
f56b11d2 86\r
b7d320f8 87 @retval TRUE The X509 stack construction succeeded.\r
88 @retval FALSE The construction operation failed.\r
66862136 89 @retval FALSE This interface is not supported.\r
b7d320f8 90\r
91**/\r
92BOOLEAN\r
93EFIAPI\r
66862136
MK
94X509ConstructCertificateStackV (\r
95 IN OUT UINT8 **X509Stack,\r
96 IN VA_LIST Args\r
b7d320f8 97 )\r
98{\r
7c342378
MK
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
b7d320f8 106\r
107 //\r
16d2c32c 108 // Check input parameters.\r
b7d320f8 109 //\r
16d2c32c 110 if (X509Stack == NULL) {\r
111 return FALSE;\r
112 }\r
b7d320f8 113\r
114 Status = FALSE;\r
115\r
116 //\r
117 // Initialize X509 stack object.\r
118 //\r
7c342378 119 CertStack = (STACK_OF (X509) *)(*X509Stack);\r
b7d320f8 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
b7d320f8 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
1463ce18
QL
137 if (CertSize == 0) {\r
138 break;\r
139 }\r
b7d320f8 140\r
141 //\r
142 // Construct X509 Object from the given DER-encoded certificate data.\r
143 //\r
952bd229 144 X509Cert = NULL;\r
7c342378
MK
145 Status = X509ConstructCertificate (\r
146 (CONST UINT8 *)Cert,\r
147 CertSize,\r
148 (UINT8 **)&X509Cert\r
149 );\r
b7d320f8 150 if (!Status) {\r
1463ce18
QL
151 if (X509Cert != NULL) {\r
152 X509_free (X509Cert);\r
153 }\r
7c342378 154\r
b7d320f8 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
b7d320f8 164 if (!Status) {\r
165 sk_X509_pop_free (CertStack, X509_free);\r
166 } else {\r
7c342378 167 *X509Stack = (UINT8 *)CertStack;\r
b7d320f8 168 }\r
169\r
170 return Status;\r
171}\r
172\r
66862136
MK
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
b7d320f8 205/**\r
206 Release the specified X509 object.\r
207\r
16d2c32c 208 If X509Cert is NULL, then return FALSE.\r
b7d320f8 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
f56b11d2 218{\r
16d2c32c 219 //\r
220 // Check input parameters.\r
221 //\r
222 if (X509Cert == NULL) {\r
223 return;\r
224 }\r
f56b11d2 225\r
b7d320f8 226 //\r
227 // Free OpenSSL X509 object.\r
228 //\r
7c342378 229 X509_free ((X509 *)X509Cert);\r
b7d320f8 230}\r
231\r
232/**\r
233 Release the specified X509 stack object.\r
234\r
16d2c32c 235 If X509Stack is NULL, then return FALSE.\r
b7d320f8 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
16d2c32c 246 //\r
247 // Check input parameters.\r
248 //\r
249 if (X509Stack == NULL) {\r
250 return;\r
251 }\r
f56b11d2 252\r
b7d320f8 253 //\r
254 // Free OpenSSL X509 stack object.\r
255 //\r
7c342378 256 sk_X509_pop_free ((STACK_OF (X509) *) X509Stack, X509_free);\r
b7d320f8 257}\r
258\r
4a567c96 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
16d2c32c 268 If Cert is NULL, then return FALSE.\r
269 If SubjectSize is NULL, then return FALSE.\r
4a567c96 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
4a567c96 286 X509 *X509Cert;\r
287 X509_NAME *X509Name;\r
eeb8928a 288 UINTN X509NameSize;\r
4a567c96 289\r
290 //\r
16d2c32c 291 // Check input parameters.\r
4a567c96 292 //\r
7c342378 293 if ((Cert == NULL) || (SubjectSize == NULL)) {\r
16d2c32c 294 return FALSE;\r
295 }\r
4a567c96 296\r
4a567c96 297 X509Cert = NULL;\r
298\r
299 //\r
300 // Read DER-encoded X509 Certificate and Construct X509 object.\r
301 //\r
7c342378 302 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
b7d320f8 303 if ((X509Cert == NULL) || (!Status)) {\r
dda39f3a 304 Status = FALSE;\r
4a567c96 305 goto _Exit;\r
306 }\r
307\r
dda39f3a 308 Status = FALSE;\r
309\r
4a567c96 310 //\r
311 // Retrieve subject name from certificate object.\r
312 //\r
313 X509Name = X509_get_subject_name (X509Cert);\r
dda39f3a 314 if (X509Name == NULL) {\r
315 goto _Exit;\r
316 }\r
317\r
7c342378 318 X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
eeb8928a
DW
319 if (*SubjectSize < X509NameSize) {\r
320 *SubjectSize = X509NameSize;\r
4a567c96 321 goto _Exit;\r
322 }\r
7c342378 323\r
eeb8928a 324 *SubjectSize = X509NameSize;\r
4a567c96 325 if (CertSubject != NULL) {\r
7c342378 326 i2d_X509_NAME (X509Name, &CertSubject);\r
4a567c96 327 Status = TRUE;\r
328 }\r
329\r
330_Exit:\r
331 //\r
332 // Release Resources.\r
333 //\r
dda39f3a 334 if (X509Cert != NULL) {\r
335 X509_free (X509Cert);\r
336 }\r
4a567c96 337\r
338 return Status;\r
339}\r
5b7c2245
QL
340\r
341/**\r
912e1e1e 342 Retrieve a string from one X.509 certificate base on the Request_NID.\r
5b7c2245
QL
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
912e1e1e 346 @param[in] Request_NID NID of string to obtain\r
5b7c2245 347 @param[out] CommonName Buffer to contain the retrieved certificate common\r
0b6457ef 348 name string (UTF8). At most CommonNameSize bytes will be\r
5b7c2245
QL
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
912e1e1e 361 @retval RETURN_NOT_FOUND If no NID Name entry exists.\r
5b7c2245 362 @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size\r
630f67dd 363 (including the final null) is returned in the\r
5b7c2245
QL
364 CommonNameSize parameter.\r
365 @retval RETURN_UNSUPPORTED The operation is not supported.\r
366\r
367**/\r
912e1e1e 368STATIC\r
5b7c2245 369RETURN_STATUS\r
912e1e1e 370InternalX509GetNIDName (\r
7c342378
MK
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
5b7c2245
QL
376 )\r
377{\r
0b6457ef
LQ
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
5b7c2245
QL
387\r
388 ReturnStatus = RETURN_INVALID_PARAMETER;\r
0b6457ef 389 UTF8Name = NULL;\r
5b7c2245
QL
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
7c342378 397\r
5b7c2245
QL
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
7c342378 406 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
5b7c2245
QL
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
912e1e1e 428 // Retrive the string from X.509 Subject base on the Request_NID\r
5b7c2245 429 //\r
912e1e1e 430 Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1);\r
0b6457ef 431 if (Index < 0) {\r
5b7c2245 432 //\r
912e1e1e 433 // No Request_NID name entry exists in X509_NAME object\r
5b7c2245
QL
434 //\r
435 *CommonNameSize = 0;\r
436 ReturnStatus = RETURN_NOT_FOUND;\r
437 goto _Exit;\r
438 }\r
439\r
0b6457ef
LQ
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
912e1e1e 455 // Fail to convert the Name string\r
0b6457ef
LQ
456 //\r
457 *CommonNameSize = 0;\r
458 ReturnStatus = RETURN_INVALID_PARAMETER;\r
459 goto _Exit;\r
460 }\r
461\r
5b7c2245 462 if (CommonName == NULL) {\r
0b6457ef 463 *CommonNameSize = Length + 1;\r
7c342378 464 ReturnStatus = RETURN_BUFFER_TOO_SMALL;\r
5b7c2245 465 } else {\r
0b6457ef
LQ
466 *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1;\r
467 CopyMem (CommonName, UTF8Name, *CommonNameSize - 1);\r
468 CommonName[*CommonNameSize - 1] = '\0';\r
7c342378 469 ReturnStatus = RETURN_SUCCESS;\r
5b7c2245
QL
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
7c342378 479\r
0b6457ef
LQ
480 if (UTF8Name != NULL) {\r
481 OPENSSL_free (UTF8Name);\r
482 }\r
5b7c2245
QL
483\r
484 return ReturnStatus;\r
485}\r
4a567c96 486\r
912e1e1e
BB
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
c8f46130 518 OUT CHAR8 *CommonName OPTIONAL,\r
912e1e1e
BB
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
7c342378
MK
554 IN CONST UINT8 *Cert,\r
555 IN UINTN CertSize,\r
556 OUT CHAR8 *NameBuffer OPTIONAL,\r
557 IN OUT UINTN *NameBufferSize\r
912e1e1e
BB
558 )\r
559{\r
560 return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize);\r
561}\r
562\r
4a567c96 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
16d2c32c 572 If Cert is NULL, then return FALSE.\r
573 If RsaContext is NULL, then return FALSE.\r
4a567c96 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
4a567c96 589 X509 *X509Cert;\r
f56b11d2 590\r
4a567c96 591 //\r
16d2c32c 592 // Check input parameters.\r
4a567c96 593 //\r
7c342378 594 if ((Cert == NULL) || (RsaContext == NULL)) {\r
16d2c32c 595 return FALSE;\r
596 }\r
4a567c96 597\r
4a567c96 598 Pkey = NULL;\r
4a567c96 599 X509Cert = NULL;\r
600\r
601 //\r
602 // Read DER-encoded X509 Certificate and Construct X509 object.\r
603 //\r
7c342378 604 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
b7d320f8 605 if ((X509Cert == NULL) || (!Status)) {\r
dda39f3a 606 Status = FALSE;\r
4a567c96 607 goto _Exit;\r
608 }\r
609\r
dda39f3a 610 Status = FALSE;\r
611\r
4a567c96 612 //\r
613 // Retrieve and check EVP_PKEY data from X509 Certificate.\r
614 //\r
615 Pkey = X509_get_pubkey (X509Cert);\r
f56b11d2 616 if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) {\r
4a567c96 617 goto _Exit;\r
618 }\r
619\r
620 //\r
621 // Duplicate RSA Context from the retrieved EVP_PKEY.\r
622 //\r
f56b11d2 623 if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) {\r
4a567c96 624 Status = TRUE;\r
625 }\r
626\r
627_Exit:\r
628 //\r
629 // Release Resources.\r
630 //\r
dda39f3a 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
f56b11d2 637 }\r
4a567c96 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
16d2c32c 650 If Cert is NULL, then return FALSE.\r
651 If CACert is NULL, then return FALSE.\r
4a567c96 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
4a567c96 668 X509 *X509Cert;\r
669 X509 *X509CACert;\r
670 X509_STORE *CertStore;\r
f56b11d2
QL
671 X509_STORE_CTX *CertCtx;\r
672\r
4a567c96 673 //\r
16d2c32c 674 // Check input parameters.\r
4a567c96 675 //\r
7c342378 676 if ((Cert == NULL) || (CACert == NULL)) {\r
16d2c32c 677 return FALSE;\r
678 }\r
4a567c96 679\r
680 Status = FALSE;\r
4a567c96 681 X509Cert = NULL;\r
682 X509CACert = NULL;\r
683 CertStore = NULL;\r
f56b11d2 684 CertCtx = NULL;\r
4a567c96 685\r
686 //\r
687 // Register & Initialize necessary digest algorithms for certificate verification.\r
688 //\r
dda39f3a 689 if (EVP_add_digest (EVP_md5 ()) == 0) {\r
690 goto _Exit;\r
691 }\r
7c342378 692\r
dda39f3a 693 if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
694 goto _Exit;\r
695 }\r
7c342378 696\r
dda39f3a 697 if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
698 goto _Exit;\r
699 }\r
4a567c96 700\r
701 //\r
702 // Read DER-encoded certificate to be verified and Construct X509 object.\r
703 //\r
7c342378 704 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
b7d320f8 705 if ((X509Cert == NULL) || (!Status)) {\r
dda39f3a 706 Status = FALSE;\r
4a567c96 707 goto _Exit;\r
708 }\r
709\r
710 //\r
711 // Read DER-encoded root certificate and Construct X509 object.\r
712 //\r
7c342378 713 Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **)&X509CACert);\r
b7d320f8 714 if ((X509CACert == NULL) || (!Status)) {\r
dda39f3a 715 Status = FALSE;\r
4a567c96 716 goto _Exit;\r
717 }\r
718\r
dda39f3a 719 Status = FALSE;\r
720\r
4a567c96 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
7c342378 728\r
4a567c96 729 if (!(X509_STORE_add_cert (CertStore, X509CACert))) {\r
730 goto _Exit;\r
731 }\r
732\r
68547181
DW
733 //\r
734 // Allow partial certificate chains, terminated by a non-self-signed but\r
de0408be 735 // still trusted intermediate certificate. Also disable time checks.\r
68547181 736 //\r
7c342378
MK
737 X509_STORE_set_flags (\r
738 CertStore,\r
739 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME\r
740 );\r
68547181 741\r
4a567c96 742 //\r
743 // Set up X509_STORE_CTX for the subsequent verification operation.\r
744 //\r
f56b11d2
QL
745 CertCtx = X509_STORE_CTX_new ();\r
746 if (CertCtx == NULL) {\r
747 goto _Exit;\r
748 }\r
7c342378 749\r
f56b11d2 750 if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) {\r
4a567c96 751 goto _Exit;\r
752 }\r
753\r
754 //\r
755 // X509 Certificate Verification.\r
756 //\r
7c342378 757 Status = (BOOLEAN)X509_verify_cert (CertCtx);\r
f56b11d2 758 X509_STORE_CTX_cleanup (CertCtx);\r
4a567c96 759\r
760_Exit:\r
761 //\r
762 // Release Resources.\r
763 //\r
dda39f3a 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
4a567c96 771\r
dda39f3a 772 if (CertStore != NULL) {\r
773 X509_STORE_free (CertStore);\r
774 }\r
f56b11d2
QL
775\r
776 X509_STORE_CTX_free (CertCtx);\r
777\r
4a567c96 778 return Status;\r
779}\r
12d95665
LQ
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
2067d9f8
ZC
807 UINT32 Asn1Tag;\r
808 UINT32 ObjClass;\r
12d95665
LQ
809 UINTN Length;\r
810\r
811 //\r
812 // Check input parameters.\r
813 //\r
1463ce18 814 if ((Cert == NULL) || (TBSCert == NULL) ||\r
7c342378
MK
815 (TBSCertSize == NULL) || (CertSize > INT_MAX))\r
816 {\r
12d95665
LQ
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
2067d9f8
ZC
837 Temp = Cert;\r
838 Length = 0;\r
12d95665
LQ
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
f56b11d2 856\r
12d95665
LQ
857 return TRUE;\r
858}\r
f21a1d48
QZ
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 #if FixedPcdGetBool (PcdOpensslEcEnabled)\r
885 BOOLEAN Status;\r
886 EVP_PKEY *Pkey;\r
887 X509 *X509Cert;\r
888\r
889 //\r
890 // Check input parameters.\r
891 //\r
892 if ((Cert == NULL) || (EcContext == NULL)) {\r
893 return FALSE;\r
894 }\r
895\r
896 Pkey = NULL;\r
897 X509Cert = NULL;\r
898\r
899 //\r
900 // Read DER-encoded X509 Certificate and Construct X509 object.\r
901 //\r
902 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
903 if ((X509Cert == NULL) || (!Status)) {\r
904 Status = FALSE;\r
905 goto _Exit;\r
906 }\r
907\r
908 Status = FALSE;\r
909\r
910 //\r
911 // Retrieve and check EVP_PKEY data from X509 Certificate.\r
912 //\r
913 Pkey = X509_get_pubkey (X509Cert);\r
914 if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_EC)) {\r
915 goto _Exit;\r
916 }\r
917\r
918 //\r
919 // Duplicate EC Context from the retrieved EVP_PKEY.\r
920 //\r
921 if ((*EcContext = EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey))) != NULL) {\r
922 Status = TRUE;\r
923 }\r
924\r
925_Exit:\r
926 //\r
927 // Release Resources.\r
928 //\r
929 if (X509Cert != NULL) {\r
930 X509_free (X509Cert);\r
931 }\r
932\r
933 if (Pkey != NULL) {\r
934 EVP_PKEY_free (Pkey);\r
935 }\r
936\r
937 return Status;\r
938 #else\r
939 return FALSE;\r
940 #endif\r
941}\r
8ecae3d6
QZ
942\r
943/**\r
944 Retrieve the version from one X.509 certificate.\r
945\r
946 If Cert is NULL, then return FALSE.\r
947 If CertSize is 0, then return FALSE.\r
948 If this interface is not supported, then return FALSE.\r
949\r
950 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
951 @param[in] CertSize Size of the X509 certificate in bytes.\r
952 @param[out] Version Pointer to the retrieved version integer.\r
953\r
954 @retval TRUE The certificate version retrieved successfully.\r
955 @retval FALSE If Cert is NULL or CertSize is Zero.\r
956 @retval FALSE The operation is not supported.\r
957\r
958**/\r
959BOOLEAN\r
960EFIAPI\r
961X509GetVersion (\r
962 IN CONST UINT8 *Cert,\r
963 IN UINTN CertSize,\r
964 OUT UINTN *Version\r
965 )\r
966{\r
967 BOOLEAN Status;\r
968 X509 *X509Cert;\r
969\r
970 X509Cert = NULL;\r
971 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
972 if ((X509Cert == NULL) || (!Status)) {\r
973 //\r
974 // Invalid X.509 Certificate\r
975 //\r
976 Status = FALSE;\r
977 }\r
978\r
979 if (Status) {\r
980 *Version = X509_get_version (X509Cert);\r
981 }\r
982\r
983 if (X509Cert != NULL) {\r
984 X509_free (X509Cert);\r
985 }\r
986\r
987 return Status;\r
988}\r
989\r
990/**\r
991 Retrieve the serialNumber from one X.509 certificate.\r
992\r
993 If Cert is NULL, then return FALSE.\r
994 If CertSize is 0, then return FALSE.\r
995 If this interface is not supported, then return FALSE.\r
996\r
997 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
998 @param[in] CertSize Size of the X509 certificate in bytes.\r
999 @param[out] SerialNumber Pointer to the retrieved certificate SerialNumber bytes.\r
1000 @param[in, out] SerialNumberSize The size in bytes of the SerialNumber buffer on input,\r
1001 and the size of buffer returned SerialNumber on output.\r
1002\r
1003 @retval TRUE The certificate serialNumber retrieved successfully.\r
1004 @retval FALSE If Cert is NULL or CertSize is Zero.\r
1005 If SerialNumberSize is NULL.\r
1006 If Certificate is invalid.\r
1007 @retval FALSE If no SerialNumber exists.\r
1008 @retval FALSE If the SerialNumber is NULL. The required buffer size\r
1009 (including the final null) is returned in the\r
1010 SerialNumberSize parameter.\r
1011 @retval FALSE The operation is not supported.\r
1012**/\r
1013BOOLEAN\r
1014EFIAPI\r
1015X509GetSerialNumber (\r
1016 IN CONST UINT8 *Cert,\r
1017 IN UINTN CertSize,\r
1018 OUT UINT8 *SerialNumber, OPTIONAL\r
1019 IN OUT UINTN *SerialNumberSize\r
1020 )\r
1021{\r
1022 BOOLEAN Status;\r
1023 X509 *X509Cert;\r
1024 ASN1_INTEGER *Asn1Integer;\r
1025\r
1026 Status = FALSE;\r
1027 //\r
1028 // Check input parameters.\r
1029 //\r
1030 if ((Cert == NULL) || (SerialNumberSize == NULL)) {\r
1031 return Status;\r
1032 }\r
1033\r
1034 X509Cert = NULL;\r
1035\r
1036 //\r
1037 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1038 //\r
1039 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1040 if ((X509Cert == NULL) || (!Status)) {\r
1041 *SerialNumberSize = 0;\r
1042 Status = FALSE;\r
1043 goto _Exit;\r
1044 }\r
1045\r
1046 //\r
1047 // Retrieve subject name from certificate object.\r
1048 //\r
1049 Asn1Integer = X509_get_serialNumber (X509Cert);\r
1050 if (Asn1Integer == NULL) {\r
1051 *SerialNumberSize = 0;\r
1052 Status = FALSE;\r
1053 goto _Exit;\r
1054 }\r
1055\r
1056 if (*SerialNumberSize < (UINTN)Asn1Integer->length) {\r
1057 *SerialNumberSize = (UINTN)Asn1Integer->length;\r
1058 Status = FALSE;\r
1059 goto _Exit;\r
1060 }\r
1061\r
1062 if (SerialNumber != NULL) {\r
1063 CopyMem (SerialNumber, Asn1Integer->data, *SerialNumberSize);\r
1064 Status = TRUE;\r
1065 }\r
1066\r
1067 *SerialNumberSize = (UINTN)Asn1Integer->length;\r
1068\r
1069_Exit:\r
1070 //\r
1071 // Release Resources.\r
1072 //\r
1073 if (X509Cert != NULL) {\r
1074 X509_free (X509Cert);\r
1075 }\r
1076\r
1077 return Status;\r
1078}\r
1079\r
1080/**\r
1081 Retrieve the issuer bytes from one X.509 certificate.\r
1082\r
1083 If Cert is NULL, then return FALSE.\r
1084 If CertIssuerSize is NULL, then return FALSE.\r
1085 If this interface is not supported, then return FALSE.\r
1086\r
1087 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1088 @param[in] CertSize Size of the X509 certificate in bytes.\r
1089 @param[out] CertIssuer Pointer to the retrieved certificate subject bytes.\r
1090 @param[in, out] CertIssuerSize The size in bytes of the CertIssuer buffer on input,\r
1091 and the size of buffer returned CertSubject on output.\r
1092\r
1093 @retval TRUE The certificate issuer retrieved successfully.\r
1094 @retval FALSE Invalid certificate, or the CertIssuerSize is too small for the result.\r
1095 The CertIssuerSize will be updated with the required size.\r
1096 @retval FALSE This interface is not supported.\r
1097\r
1098**/\r
1099BOOLEAN\r
1100EFIAPI\r
1101X509GetIssuerName (\r
1102 IN CONST UINT8 *Cert,\r
1103 IN UINTN CertSize,\r
1104 OUT UINT8 *CertIssuer,\r
1105 IN OUT UINTN *CertIssuerSize\r
1106 )\r
1107{\r
1108 BOOLEAN Status;\r
1109 X509 *X509Cert;\r
1110 X509_NAME *X509Name;\r
1111 UINTN X509NameSize;\r
1112\r
1113 //\r
1114 // Check input parameters.\r
1115 //\r
1116 if ((Cert == NULL) || (CertIssuerSize == NULL)) {\r
1117 return FALSE;\r
1118 }\r
1119\r
1120 X509Cert = NULL;\r
1121\r
1122 //\r
1123 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1124 //\r
1125 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1126 if ((X509Cert == NULL) || (!Status)) {\r
1127 Status = FALSE;\r
1128 goto _Exit;\r
1129 }\r
1130\r
1131 Status = FALSE;\r
1132\r
1133 //\r
1134 // Retrieve subject name from certificate object.\r
1135 //\r
1136 X509Name = X509_get_subject_name (X509Cert);\r
1137 if (X509Name == NULL) {\r
1138 goto _Exit;\r
1139 }\r
1140\r
1141 X509NameSize = i2d_X509_NAME (X509Name, NULL);\r
1142 if (*CertIssuerSize < X509NameSize) {\r
1143 *CertIssuerSize = X509NameSize;\r
1144 goto _Exit;\r
1145 }\r
1146\r
1147 *CertIssuerSize = X509NameSize;\r
1148 if (CertIssuer != NULL) {\r
1149 i2d_X509_NAME (X509Name, &CertIssuer);\r
1150 Status = TRUE;\r
1151 }\r
1152\r
1153_Exit:\r
1154 //\r
1155 // Release Resources.\r
1156 //\r
1157 if (X509Cert != NULL) {\r
1158 X509_free (X509Cert);\r
1159 }\r
1160\r
1161 return Status;\r
1162}\r
1163\r
1164/**\r
1165 Retrieve the Signature Algorithm from one X.509 certificate.\r
1166\r
1167 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1168 @param[in] CertSize Size of the X509 certificate in bytes.\r
1169 @param[out] Oid Signature Algorithm Object identifier buffer.\r
1170 @param[in,out] OidSize Signature Algorithm Object identifier buffer size\r
1171\r
1172 @retval TRUE The certificate Extension data retrieved successfully.\r
1173 @retval FALSE If Cert is NULL.\r
1174 If OidSize is NULL.\r
1175 If Oid is not NULL and *OidSize is 0.\r
1176 If Certificate is invalid.\r
1177 @retval FALSE If no SignatureType.\r
1178 @retval FALSE If the Oid is NULL. The required buffer size\r
1179 is returned in the OidSize.\r
1180 @retval FALSE The operation is not supported.\r
1181**/\r
1182BOOLEAN\r
1183EFIAPI\r
1184X509GetSignatureAlgorithm (\r
1185 IN CONST UINT8 *Cert,\r
1186 IN UINTN CertSize,\r
1187 OUT UINT8 *Oid, OPTIONAL\r
1188 IN OUT UINTN *OidSize\r
1189 )\r
1190{\r
1191 BOOLEAN Status;\r
1192 X509 *X509Cert;\r
1193 int Nid;\r
1194 ASN1_OBJECT *Asn1Obj;\r
1195\r
1196 //\r
1197 // Check input parameters.\r
1198 //\r
1199 if ((Cert == NULL) || (OidSize == NULL) || (CertSize == 0)) {\r
1200 return FALSE;\r
1201 }\r
1202\r
1203 X509Cert = NULL;\r
1204 Status = FALSE;\r
1205\r
1206 //\r
1207 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1208 //\r
1209 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1210 if ((X509Cert == NULL) || (!Status)) {\r
1211 Status = FALSE;\r
1212 goto _Exit;\r
1213 }\r
1214\r
1215 //\r
1216 // Retrieve subject name from certificate object.\r
1217 //\r
1218 Nid = X509_get_signature_nid (X509Cert);\r
1219 if (Nid == NID_undef) {\r
1220 *OidSize = 0;\r
1221 Status = FALSE;\r
1222 goto _Exit;\r
1223 }\r
1224\r
1225 Asn1Obj = OBJ_nid2obj (Nid);\r
1226 if (Asn1Obj == NULL) {\r
1227 *OidSize = 0;\r
1228 Status = FALSE;\r
1229 goto _Exit;\r
1230 }\r
1231\r
1232 if (*OidSize < (UINTN)Asn1Obj->length) {\r
1233 *OidSize = Asn1Obj->length;\r
1234 Status = FALSE;\r
1235 goto _Exit;\r
1236 }\r
1237\r
1238 if (Oid != NULL) {\r
1239 CopyMem (Oid, Asn1Obj->data, Asn1Obj->length);\r
1240 }\r
1241\r
1242 *OidSize = Asn1Obj->length;\r
1243 Status = TRUE;\r
1244\r
1245_Exit:\r
1246 //\r
1247 // Release Resources.\r
1248 //\r
1249 if (X509Cert != NULL) {\r
1250 X509_free (X509Cert);\r
1251 }\r
1252\r
1253 return Status;\r
1254}\r
1255\r
1256/**\r
1257 Retrieve Extension data from one X.509 certificate.\r
1258\r
1259 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1260 @param[in] CertSize Size of the X509 certificate in bytes.\r
1261 @param[in] Oid Object identifier buffer\r
1262 @param[in] OidSize Object identifier buffer size\r
1263 @param[out] ExtensionData Extension bytes.\r
1264 @param[in, out] ExtensionDataSize Extension bytes size.\r
1265\r
1266 @retval TRUE The certificate Extension data retrieved successfully.\r
1267 @retval FALSE If Cert is NULL.\r
1268 If ExtensionDataSize is NULL.\r
1269 If ExtensionData is not NULL and *ExtensionDataSize is 0.\r
1270 If Certificate is invalid.\r
1271 @retval FALSE If no Extension entry match Oid.\r
1272 @retval FALSE If the ExtensionData is NULL. The required buffer size\r
1273 is returned in the ExtensionDataSize parameter.\r
1274 @retval FALSE The operation is not supported.\r
1275**/\r
1276BOOLEAN\r
1277EFIAPI\r
1278X509GetExtensionData (\r
1279 IN CONST UINT8 *Cert,\r
1280 IN UINTN CertSize,\r
1281 IN CONST UINT8 *Oid,\r
1282 IN UINTN OidSize,\r
1283 OUT UINT8 *ExtensionData,\r
1284 IN OUT UINTN *ExtensionDataSize\r
1285 )\r
1286{\r
1287 BOOLEAN Status;\r
1288 INTN i;\r
1289 X509 *X509Cert;\r
1290\r
1291 CONST STACK_OF (X509_EXTENSION) *Extensions;\r
1292 ASN1_OBJECT *Asn1Obj;\r
1293 ASN1_OCTET_STRING *Asn1Oct;\r
1294 X509_EXTENSION *Ext;\r
1295 UINTN ObjLength;\r
1296 UINTN OctLength;\r
1297\r
1298 //\r
1299 // Check input parameters.\r
1300 //\r
1301 if ((Cert == NULL) || (CertSize == 0) || (Oid == NULL) || (OidSize == 0) || (ExtensionDataSize == NULL)) {\r
1302 return FALSE;\r
1303 }\r
1304\r
1305 X509Cert = NULL;\r
1306 Status = FALSE;\r
1307\r
1308 //\r
1309 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1310 //\r
1311 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1312 if ((X509Cert == NULL) || (!Status)) {\r
1313 *ExtensionDataSize = 0;\r
1314 goto Cleanup;\r
1315 }\r
1316\r
1317 //\r
1318 // Retrieve Extensions from certificate object.\r
1319 //\r
1320 Extensions = X509_get0_extensions (X509Cert);\r
1321 if (sk_X509_EXTENSION_num (Extensions) <= 0) {\r
1322 *ExtensionDataSize = 0;\r
1323 goto Cleanup;\r
1324 }\r
1325\r
1326 //\r
1327 // Traverse Extensions\r
1328 //\r
1329 Status = FALSE;\r
1330 Asn1Oct = NULL;\r
1331 OctLength = 0;\r
1332 for (i = 0; i < sk_X509_EXTENSION_num (Extensions); i++) {\r
1333 Ext = sk_X509_EXTENSION_value (Extensions, (int)i);\r
1334 if (Ext == NULL) {\r
1335 continue;\r
1336 }\r
1337\r
1338 Asn1Obj = X509_EXTENSION_get_object (Ext);\r
1339 if (Asn1Obj == NULL) {\r
1340 continue;\r
1341 }\r
1342\r
1343 Asn1Oct = X509_EXTENSION_get_data (Ext);\r
1344 if (Asn1Oct == NULL) {\r
1345 continue;\r
1346 }\r
1347\r
1348 ObjLength = OBJ_length (Asn1Obj);\r
1349 OctLength = ASN1_STRING_length (Asn1Oct);\r
1350 if ((OidSize == ObjLength) && (CompareMem (OBJ_get0_data (Asn1Obj), Oid, OidSize) == 0)) {\r
1351 //\r
1352 // Extension Found\r
1353 //\r
1354 Status = TRUE;\r
1355 break;\r
1356 }\r
1357\r
1358 //\r
1359 // reset to 0 if not found\r
1360 //\r
1361 OctLength = 0;\r
1362 }\r
1363\r
1364 if (Status) {\r
1365 if (*ExtensionDataSize < OctLength) {\r
1366 *ExtensionDataSize = OctLength;\r
1367 Status = FALSE;\r
1368 goto Cleanup;\r
1369 }\r
1370\r
1371 if (Asn1Oct != NULL) {\r
1372 CopyMem (ExtensionData, ASN1_STRING_get0_data (Asn1Oct), OctLength);\r
1373 }\r
1374\r
1375 *ExtensionDataSize = OctLength;\r
1376 } else {\r
1377 *ExtensionDataSize = 0;\r
1378 }\r
1379\r
1380Cleanup:\r
1381 //\r
1382 // Release Resources.\r
1383 //\r
1384 if (X509Cert != NULL) {\r
1385 X509_free (X509Cert);\r
1386 }\r
1387\r
1388 return Status;\r
1389}\r
1390\r
1391/**\r
1392 Retrieve the Extended Key Usage from one X.509 certificate.\r
1393\r
1394 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1395 @param[in] CertSize Size of the X509 certificate in bytes.\r
1396 @param[out] Usage Key Usage bytes.\r
1397 @param[in, out] UsageSize Key Usage buffer sizs in bytes.\r
1398\r
1399 @retval TRUE The Usage bytes retrieve successfully.\r
1400 @retval FALSE If Cert is NULL.\r
1401 If CertSize is NULL.\r
1402 If Usage is not NULL and *UsageSize is 0.\r
1403 If Cert is invalid.\r
1404 @retval FALSE If the Usage is NULL. The required buffer size\r
1405 is returned in the UsageSize parameter.\r
1406 @retval FALSE The operation is not supported.\r
1407**/\r
1408BOOLEAN\r
1409EFIAPI\r
1410X509GetExtendedKeyUsage (\r
1411 IN CONST UINT8 *Cert,\r
1412 IN UINTN CertSize,\r
1413 OUT UINT8 *Usage,\r
1414 IN OUT UINTN *UsageSize\r
1415 )\r
1416{\r
1417 BOOLEAN Status;\r
1418\r
1419 Status = X509GetExtensionData (Cert, CertSize, mOidExtKeyUsage, sizeof (mOidExtKeyUsage), Usage, UsageSize);\r
1420 return Status;\r
1421}\r
1422\r
1423/**\r
1424 Retrieve the Validity from one X.509 certificate\r
1425\r
1426 If Cert is NULL, then return FALSE.\r
1427 If CertIssuerSize is NULL, then return FALSE.\r
1428 If this interface is not supported, then return FALSE.\r
1429\r
1430 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1431 @param[in] CertSize Size of the X509 certificate in bytes.\r
1432 @param[out] From notBefore Pointer to DateTime object.\r
1433 @param[in,out] FromSize notBefore DateTime object size.\r
1434 @param[out] To notAfter Pointer to DateTime object.\r
1435 @param[in,out] ToSize notAfter DateTime object size.\r
1436\r
1437 Note: X509CompareDateTime to compare DateTime oject\r
1438 x509SetDateTime to get a DateTime object from a DateTimeStr\r
1439\r
1440 @retval TRUE The certificate Validity retrieved successfully.\r
1441 @retval FALSE Invalid certificate, or Validity retrieve failed.\r
1442 @retval FALSE This interface is not supported.\r
1443**/\r
1444BOOLEAN\r
1445EFIAPI\r
1446X509GetValidity (\r
1447 IN CONST UINT8 *Cert,\r
1448 IN UINTN CertSize,\r
1449 IN UINT8 *From,\r
1450 IN OUT UINTN *FromSize,\r
1451 IN UINT8 *To,\r
1452 IN OUT UINTN *ToSize\r
1453 )\r
1454{\r
1455 BOOLEAN Status;\r
1456 X509 *X509Cert;\r
1457 CONST ASN1_TIME *F;\r
1458 CONST ASN1_TIME *T;\r
1459 UINTN TSize;\r
1460 UINTN FSize;\r
1461\r
1462 //\r
1463 // Check input parameters.\r
1464 //\r
1465 if ((Cert == NULL) || (FromSize == NULL) || (ToSize == NULL) || (CertSize == 0)) {\r
1466 return FALSE;\r
1467 }\r
1468\r
1469 X509Cert = NULL;\r
1470 Status = FALSE;\r
1471\r
1472 //\r
1473 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1474 //\r
1475 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1476 if ((X509Cert == NULL) || (!Status)) {\r
1477 goto _Exit;\r
1478 }\r
1479\r
1480 //\r
1481 // Retrieve Validity from/to from certificate object.\r
1482 //\r
1483 F = X509_get0_notBefore (X509Cert);\r
1484 T = X509_get0_notAfter (X509Cert);\r
1485\r
1486 if ((F == NULL) || (T == NULL)) {\r
1487 goto _Exit;\r
1488 }\r
1489\r
1490 FSize = sizeof (ASN1_TIME) + F->length;\r
1491 if (*FromSize < FSize) {\r
1492 *FromSize = FSize;\r
1493 goto _Exit;\r
1494 }\r
1495\r
1496 *FromSize = FSize;\r
1497 if (From != NULL) {\r
1498 CopyMem (From, F, sizeof (ASN1_TIME));\r
1499 ((ASN1_TIME *)From)->data = From + sizeof (ASN1_TIME);\r
1500 CopyMem (From + sizeof (ASN1_TIME), F->data, F->length);\r
1501 }\r
1502\r
1503 TSize = sizeof (ASN1_TIME) + T->length;\r
1504 if (*ToSize < TSize) {\r
1505 *ToSize = TSize;\r
1506 goto _Exit;\r
1507 }\r
1508\r
1509 *ToSize = TSize;\r
1510 if (To != NULL) {\r
1511 CopyMem (To, T, sizeof (ASN1_TIME));\r
1512 ((ASN1_TIME *)To)->data = To + sizeof (ASN1_TIME);\r
1513 CopyMem (To + sizeof (ASN1_TIME), T->data, T->length);\r
1514 }\r
1515\r
1516 Status = TRUE;\r
1517\r
1518_Exit:\r
1519 //\r
1520 // Release Resources.\r
1521 //\r
1522 if (X509Cert != NULL) {\r
1523 X509_free (X509Cert);\r
1524 }\r
1525\r
1526 return Status;\r
1527}\r
1528\r
1529/**\r
1530 Format a DateTimeStr to DataTime object in DataTime Buffer\r
1531\r
1532 If DateTimeStr is NULL, then return FALSE.\r
1533 If DateTimeSize is NULL, then return FALSE.\r
1534 If this interface is not supported, then return FALSE.\r
1535\r
1536 @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ\r
1537 Ref: https://www.w3.org/TR/NOTE-datetime\r
1538 Z stand for UTC time\r
1539 @param[out] DateTime Pointer to a DateTime object.\r
1540 @param[in,out] DateTimeSize DateTime object buffer size.\r
1541\r
1542 @retval TRUE The DateTime object create successfully.\r
1543 @retval FALSE If DateTimeStr is NULL.\r
1544 If DateTimeSize is NULL.\r
1545 If DateTime is not NULL and *DateTimeSize is 0.\r
1546 If Year Month Day Hour Minute Second combination is invalid datetime.\r
1547 @retval FALSE If the DateTime is NULL. The required buffer size\r
1548 (including the final null) is returned in the\r
1549 DateTimeSize parameter.\r
1550 @retval FALSE The operation is not supported.\r
1551**/\r
1552BOOLEAN\r
1553EFIAPI\r
1554X509FormatDateTime (\r
1555 IN CONST CHAR8 *DateTimeStr,\r
1556 OUT VOID *DateTime,\r
1557 IN OUT UINTN *DateTimeSize\r
1558 )\r
1559{\r
1560 BOOLEAN Status;\r
1561 INT32 Ret;\r
1562 ASN1_TIME *Dt;\r
1563 UINTN DSize;\r
1564\r
1565 Dt = NULL;\r
1566 Status = FALSE;\r
1567\r
1568 Dt = ASN1_TIME_new ();\r
1569 if (Dt == NULL) {\r
1570 Status = FALSE;\r
1571 goto Cleanup;\r
1572 }\r
1573\r
1574 Ret = ASN1_TIME_set_string_X509 (Dt, DateTimeStr);\r
1575 if (Ret != 1) {\r
1576 Status = FALSE;\r
1577 goto Cleanup;\r
1578 }\r
1579\r
1580 DSize = sizeof (ASN1_TIME) + Dt->length;\r
1581 if (*DateTimeSize < DSize) {\r
1582 *DateTimeSize = DSize;\r
1583 Status = FALSE;\r
1584 goto Cleanup;\r
1585 }\r
1586\r
1587 *DateTimeSize = DSize;\r
1588 if (DateTime != NULL) {\r
1589 CopyMem (DateTime, Dt, sizeof (ASN1_TIME));\r
1590 ((ASN1_TIME *)DateTime)->data = (UINT8 *)DateTime + sizeof (ASN1_TIME);\r
1591 CopyMem ((UINT8 *)DateTime + sizeof (ASN1_TIME), Dt->data, Dt->length);\r
1592 }\r
1593\r
1594 Status = TRUE;\r
1595\r
1596Cleanup:\r
1597 if (Dt != NULL) {\r
1598 ASN1_TIME_free (Dt);\r
1599 }\r
1600\r
1601 return Status;\r
1602}\r
1603\r
1604/**\r
1605 Compare DateTime1 object and DateTime2 object.\r
1606\r
1607 If DateTime1 is NULL, then return -2.\r
1608 If DateTime2 is NULL, then return -2.\r
1609 If DateTime1 == DateTime2, then return 0\r
1610 If DateTime1 > DateTime2, then return 1\r
1611 If DateTime1 < DateTime2, then return -1\r
1612\r
1613 @param[in] DateTime1 Pointer to a DateTime Ojbect\r
1614 @param[in] DateTime2 Pointer to a DateTime Object\r
1615\r
1616 @retval 0 If DateTime1 == DateTime2\r
1617 @retval 1 If DateTime1 > DateTime2\r
1618 @retval -1 If DateTime1 < DateTime2\r
1619**/\r
1620INT32\r
1621EFIAPI\r
1622X509CompareDateTime (\r
1623 IN CONST VOID *DateTime1,\r
1624 IN CONST VOID *DateTime2\r
1625 )\r
1626{\r
1627 return (INT32)ASN1_TIME_compare (DateTime1, DateTime2);\r
1628}\r
1629\r
1630/**\r
1631 Retrieve the Key Usage from one X.509 certificate.\r
1632\r
1633 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1634 @param[in] CertSize Size of the X509 certificate in bytes.\r
1635 @param[out] Usage Key Usage (CRYPTO_X509_KU_*)\r
1636\r
1637 @retval TRUE The certificate Key Usage retrieved successfully.\r
1638 @retval FALSE Invalid certificate, or Usage is NULL\r
1639 @retval FALSE This interface is not supported.\r
1640**/\r
1641BOOLEAN\r
1642EFIAPI\r
1643X509GetKeyUsage (\r
1644 IN CONST UINT8 *Cert,\r
1645 IN UINTN CertSize,\r
1646 OUT UINTN *Usage\r
1647 )\r
1648{\r
1649 BOOLEAN Status;\r
1650 X509 *X509Cert;\r
1651\r
1652 //\r
1653 // Check input parameters.\r
1654 //\r
1655 if ((Cert == NULL) || (Usage == NULL)) {\r
1656 return FALSE;\r
1657 }\r
1658\r
1659 X509Cert = NULL;\r
1660 Status = FALSE;\r
1661\r
1662 //\r
1663 // Read DER-encoded X509 Certificate and Construct X509 object.\r
1664 //\r
1665 Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);\r
1666 if ((X509Cert == NULL) || (!Status)) {\r
1667 goto _Exit;\r
1668 }\r
1669\r
1670 //\r
1671 // Retrieve subject name from certificate object.\r
1672 //\r
1673 *Usage = X509_get_key_usage (X509Cert);\r
1674 if (*Usage == NID_undef) {\r
1675 goto _Exit;\r
1676 }\r
1677\r
1678 Status = TRUE;\r
1679\r
1680_Exit:\r
1681 //\r
1682 // Release Resources.\r
1683 //\r
1684 if (X509Cert != NULL) {\r
1685 X509_free (X509Cert);\r
1686 }\r
1687\r
1688 return Status;\r
1689}\r
1690\r
1691/**\r
1692 Verify one X509 certificate was issued by the trusted CA.\r
1693 @param[in] RootCert Trusted Root Certificate buffer\r
1694\r
1695 @param[in] RootCertLength Trusted Root Certificate buffer length\r
1696 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates\r
1697 where the first certificate is signed by the Root\r
1698 Certificate or is the Root Cerificate itself. and\r
1699 subsequent cerificate is signed by the preceding\r
1700 cerificate.\r
1701 @param[in] CertChainLength Total length of the certificate chain, in bytes.\r
1702\r
1703 @retval TRUE All cerificates was issued by the first certificate in X509Certchain.\r
1704 @retval FALSE Invalid certificate or the certificate was not issued by the given\r
1705 trusted CA.\r
1706**/\r
1707BOOLEAN\r
1708EFIAPI\r
1709X509VerifyCertChain (\r
1710 IN CONST UINT8 *RootCert,\r
1711 IN UINTN RootCertLength,\r
1712 IN CONST UINT8 *CertChain,\r
1713 IN UINTN CertChainLength\r
1714 )\r
1715{\r
1716 CONST UINT8 *TmpPtr;\r
1717 UINTN Length;\r
1718 UINT32 Asn1Tag;\r
1719 UINT32 ObjClass;\r
1720 CONST UINT8 *CurrentCert;\r
1721 UINTN CurrentCertLen;\r
1722 CONST UINT8 *PrecedingCert;\r
1723 UINTN PrecedingCertLen;\r
1724 BOOLEAN VerifyFlag;\r
1725 INT32 Ret;\r
1726\r
1727 PrecedingCert = RootCert;\r
1728 PrecedingCertLen = RootCertLength;\r
1729\r
1730 CurrentCert = CertChain;\r
1731 Length = 0;\r
1732 CurrentCertLen = 0;\r
1733\r
1734 VerifyFlag = FALSE;\r
1735 while (TRUE) {\r
1736 TmpPtr = CurrentCert;\r
1737 Ret = ASN1_get_object (\r
1738 (CONST UINT8 **)&TmpPtr,\r
1739 (long *)&Length,\r
1740 (int *)&Asn1Tag,\r
1741 (int *)&ObjClass,\r
1742 (long)(CertChainLength + CertChain - TmpPtr)\r
1743 );\r
1744 if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
1745 break;\r
1746 }\r
1747\r
1748 //\r
1749 // Calculate CurrentCert length;\r
1750 //\r
1751 CurrentCertLen = TmpPtr - CurrentCert + Length;\r
1752\r
1753 //\r
1754 // Verify CurrentCert with preceding cert;\r
1755 //\r
1756 VerifyFlag = X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen);\r
1757 if (VerifyFlag == FALSE) {\r
1758 break;\r
1759 }\r
1760\r
1761 //\r
1762 // move Current cert to Preceding cert\r
1763 //\r
1764 PrecedingCertLen = CurrentCertLen;\r
1765 PrecedingCert = CurrentCert;\r
1766\r
1767 //\r
1768 // Move to next\r
1769 //\r
1770 CurrentCert = CurrentCert + CurrentCertLen;\r
1771 }\r
1772\r
1773 return VerifyFlag;\r
1774}\r
1775\r
1776/**\r
1777 Get one X509 certificate from CertChain.\r
1778\r
1779 @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates\r
1780 where the first certificate is signed by the Root\r
1781 Certificate or is the Root Cerificate itself. and\r
1782 subsequent cerificate is signed by the preceding\r
1783 cerificate.\r
1784 @param[in] CertChainLength Total length of the certificate chain, in bytes.\r
1785\r
1786 @param[in] CertIndex Index of certificate.\r
1787\r
1788 @param[out] Cert The certificate at the index of CertChain.\r
1789 @param[out] CertLength The length certificate at the index of CertChain.\r
1790\r
1791 @retval TRUE Success.\r
1792 @retval FALSE Failed to get certificate from certificate chain.\r
1793**/\r
1794BOOLEAN\r
1795EFIAPI\r
1796X509GetCertFromCertChain (\r
1797 IN CONST UINT8 *CertChain,\r
1798 IN UINTN CertChainLength,\r
1799 IN CONST INT32 CertIndex,\r
1800 OUT CONST UINT8 **Cert,\r
1801 OUT UINTN *CertLength\r
1802 )\r
1803{\r
1804 UINTN Asn1Len;\r
1805 INT32 CurrentIndex;\r
1806 UINTN CurrentCertLen;\r
1807 CONST UINT8 *CurrentCert;\r
1808 CONST UINT8 *TmpPtr;\r
1809 INT32 Ret;\r
1810 UINT32 Asn1Tag;\r
1811 UINT32 ObjClass;\r
1812\r
1813 //\r
1814 // Check input parameters.\r
1815 //\r
1816 if ((CertChain == NULL) || (Cert == NULL) ||\r
1817 (CertIndex < -1) || (CertLength == NULL))\r
1818 {\r
1819 return FALSE;\r
1820 }\r
1821\r
1822 Asn1Len = 0;\r
1823 CurrentCertLen = 0;\r
1824 CurrentCert = CertChain;\r
1825 CurrentIndex = -1;\r
1826\r
1827 //\r
1828 // Traverse the certificate chain\r
1829 //\r
1830 while (TRUE) {\r
1831 TmpPtr = CurrentCert;\r
1832\r
1833 // Get asn1 object and taglen\r
1834 Ret = ASN1_get_object (\r
1835 (CONST UINT8 **)&TmpPtr,\r
1836 (long *)&Asn1Len,\r
1837 (int *)&Asn1Tag,\r
1838 (int *)&ObjClass,\r
1839 (long)(CertChainLength + CertChain - TmpPtr)\r
1840 );\r
1841 if ((Asn1Tag != V_ASN1_SEQUENCE) || (Ret == 0x80)) {\r
1842 break;\r
1843 }\r
1844\r
1845 //\r
1846 // Calculate CurrentCert length;\r
1847 //\r
1848 CurrentCertLen = TmpPtr - CurrentCert + Asn1Len;\r
1849 CurrentIndex++;\r
1850\r
1851 if (CurrentIndex == CertIndex) {\r
1852 *Cert = CurrentCert;\r
1853 *CertLength = CurrentCertLen;\r
1854 return TRUE;\r
1855 }\r
1856\r
1857 //\r
1858 // Move to next\r
1859 //\r
1860 CurrentCert = CurrentCert + CurrentCertLen;\r
1861 }\r
1862\r
1863 //\r
1864 // If CertIndex is -1, Return the last certificate\r
1865 //\r
1866 if ((CertIndex == -1) && (CurrentIndex >= 0)) {\r
1867 *Cert = CurrentCert - CurrentCertLen;\r
1868 *CertLength = CurrentCertLen;\r
1869 return TRUE;\r
1870 }\r
1871\r
1872 return FALSE;\r
1873}\r
1874\r
1875/**\r
1876 Retrieve the tag and length of the tag.\r
1877\r
1878 @param Ptr The position in the ASN.1 data\r
1879 @param End End of data\r
1880 @param Length The variable that will receive the length\r
1881 @param Tag The expected tag\r
1882\r
1883 @retval TRUE Get tag successful\r
1884 @retval FALSe Failed to get tag or tag not match\r
1885**/\r
1886BOOLEAN\r
1887EFIAPI\r
1888Asn1GetTag (\r
1889 IN OUT UINT8 **Ptr,\r
1890 IN CONST UINT8 *End,\r
1891 OUT UINTN *Length,\r
1892 IN UINT32 Tag\r
1893 )\r
1894{\r
1895 UINT8 *PtrOld;\r
1896 INT32 ObjTag;\r
1897 INT32 ObjCls;\r
1898 long ObjLength;\r
1899\r
1900 //\r
1901 // Save Ptr position\r
1902 //\r
1903 PtrOld = *Ptr;\r
1904\r
1905 ASN1_get_object ((CONST UINT8 **)Ptr, &ObjLength, &ObjTag, &ObjCls, (INT32)(End - (*Ptr)));\r
1906 if ((ObjTag == (INT32)(Tag & CRYPTO_ASN1_TAG_VALUE_MASK)) &&\r
1907 (ObjCls == (INT32)(Tag & CRYPTO_ASN1_TAG_CLASS_MASK)))\r
1908 {\r
1909 *Length = (UINTN)ObjLength;\r
1910 return TRUE;\r
1911 } else {\r
1912 //\r
1913 // if doesn't match Tag, restore Ptr to origin Ptr\r
1914 //\r
1915 *Ptr = PtrOld;\r
1916 return FALSE;\r
1917 }\r
1918}\r
1919\r
1920/**\r
1921 Retrieve the basic constraints from one X.509 certificate.\r
1922\r
1923 @param[in] Cert Pointer to the DER-encoded X509 certificate.\r
1924 @param[in] CertSize size of the X509 certificate in bytes.\r
1925 @param[out] BasicConstraints basic constraints bytes.\r
1926 @param[in, out] BasicConstraintsSize basic constraints buffer sizs in bytes.\r
1927\r
1928 @retval TRUE The basic constraints retrieve successfully.\r
1929 @retval FALSE If cert is NULL.\r
1930 If cert_size is NULL.\r
1931 If basic_constraints is not NULL and *basic_constraints_size is 0.\r
1932 If cert is invalid.\r
1933 @retval FALSE The required buffer size is small.\r
1934 The return buffer size is basic_constraints_size parameter.\r
1935 @retval FALSE If no Extension entry match oid.\r
1936 @retval FALSE The operation is not supported.\r
1937 **/\r
1938BOOLEAN\r
1939EFIAPI\r
1940X509GetExtendedBasicConstraints (\r
1941 CONST UINT8 *Cert,\r
1942 UINTN CertSize,\r
1943 UINT8 *BasicConstraints,\r
1944 UINTN *BasicConstraintsSize\r
1945 )\r
1946{\r
1947 BOOLEAN Status;\r
1948\r
1949 if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {\r
1950 return FALSE;\r
1951 }\r
1952\r
1953 Status = X509GetExtensionData (\r
1954 (UINT8 *)Cert,\r
1955 CertSize,\r
1956 mOidBasicConstraints,\r
1957 sizeof (mOidBasicConstraints),\r
1958 BasicConstraints,\r
1959 BasicConstraintsSize\r
1960 );\r
1961\r
1962 return Status;\r
1963}\r