]>
Commit | Line | Data |
---|---|---|
4a567c96 | 1 | /** @file\r |
2 | X.509 Certificate Handler Wrapper Implementation over OpenSSL.\r | |
3 | \r | |
66862136 | 4 | Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>\r |
2009f6b4 | 5 | SPDX-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 | |
20 | static CONST UINT8 mOidExtKeyUsage[] = OID_EXT_KEY_USAGE;\r | |
21 | static 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 | |
41 | BOOLEAN\r | |
42 | EFIAPI\r | |
43 | X509ConstructCertificate (\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 | |
92 | BOOLEAN\r | |
93 | EFIAPI\r | |
66862136 MK |
94 | X509ConstructCertificateStackV (\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 | |
189 | BOOLEAN\r | |
190 | EFIAPI\r | |
191 | X509ConstructCertificateStack (\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 | |
213 | VOID\r | |
214 | EFIAPI\r | |
215 | X509Free (\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 | |
240 | VOID\r | |
241 | EFIAPI\r | |
242 | X509StackFree (\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 | |
276 | BOOLEAN\r | |
277 | EFIAPI\r | |
278 | X509GetSubjectName (\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 | 368 | STATIC\r |
5b7c2245 | 369 | RETURN_STATUS\r |
912e1e1e | 370 | InternalX509GetNIDName (\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 | |
513 | RETURN_STATUS\r | |
514 | EFIAPI\r | |
515 | X509GetCommonName (\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 | |
551 | RETURN_STATUS\r | |
552 | EFIAPI\r | |
553 | X509GetOrganizationName (\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 | |
579 | BOOLEAN\r | |
580 | EFIAPI\r | |
581 | RsaGetPublicKeyFromX509 (\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 | |
658 | BOOLEAN\r | |
659 | EFIAPI\r | |
660 | X509VerifyCert (\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 | |
797 | BOOLEAN\r | |
798 | EFIAPI\r | |
799 | X509GetTBSCert (\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 | |
876 | BOOLEAN\r | |
877 | EFIAPI\r | |
878 | EcGetPublicKeyFromX509 (\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 | |
959 | BOOLEAN\r | |
960 | EFIAPI\r | |
961 | X509GetVersion (\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 | |
1013 | BOOLEAN\r | |
1014 | EFIAPI\r | |
1015 | X509GetSerialNumber (\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 | |
1099 | BOOLEAN\r | |
1100 | EFIAPI\r | |
1101 | X509GetIssuerName (\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 | |
1182 | BOOLEAN\r | |
1183 | EFIAPI\r | |
1184 | X509GetSignatureAlgorithm (\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 | |
1276 | BOOLEAN\r | |
1277 | EFIAPI\r | |
1278 | X509GetExtensionData (\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 | |
1380 | Cleanup:\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 | |
1408 | BOOLEAN\r | |
1409 | EFIAPI\r | |
1410 | X509GetExtendedKeyUsage (\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 | |
1444 | BOOLEAN\r | |
1445 | EFIAPI\r | |
1446 | X509GetValidity (\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 | |
1552 | BOOLEAN\r | |
1553 | EFIAPI\r | |
1554 | X509FormatDateTime (\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 | |
1596 | Cleanup:\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 | |
1620 | INT32\r | |
1621 | EFIAPI\r | |
1622 | X509CompareDateTime (\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 | |
1641 | BOOLEAN\r | |
1642 | EFIAPI\r | |
1643 | X509GetKeyUsage (\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 | |
1707 | BOOLEAN\r | |
1708 | EFIAPI\r | |
1709 | X509VerifyCertChain (\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 | |
1794 | BOOLEAN\r | |
1795 | EFIAPI\r | |
1796 | X509GetCertFromCertChain (\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 | |
1886 | BOOLEAN\r | |
1887 | EFIAPI\r | |
1888 | Asn1GetTag (\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 | |
1938 | BOOLEAN\r | |
1939 | EFIAPI\r | |
1940 | X509GetExtendedBasicConstraints (\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 |