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