]> git.proxmox.com Git - mirror_edk2.git/blame - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c
CryptoPkg: Apply uncrustify changes
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7VerifyCommon.c
CommitLineData
532616bb 1/** @file\r
2 PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This library will have external input - signature (e.g. UEFI Authenticated\r
6 Variable). It may by input in SMM mode.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated\r
11 Variable and will do basic check for data structure.\r
12\r
cc01b26e 13Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
2009f6b4 14SPDX-License-Identifier: BSD-2-Clause-Patent\r
532616bb 15\r
16**/\r
17\r
18#include "InternalCryptLib.h"\r
19\r
20#include <openssl/objects.h>\r
21#include <openssl/x509.h>\r
02ee8d3b 22#include <openssl/x509v3.h>\r
532616bb 23#include <openssl/pkcs7.h>\r
24\r
7c342378 25UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 };\r
532616bb 26\r
532616bb 27/**\r
28 Check input P7Data is a wrapped ContentInfo structure or not. If not construct\r
29 a new structure to wrap P7Data.\r
30\r
31 Caution: This function may receive untrusted input.\r
32 UEFI Authenticated Variable is external input, so this function will do basic\r
33 check for PKCS#7 data structure.\r
34\r
35 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
36 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
37 @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise\r
38 return FALSE.\r
2ac68e8b 39 @param[out] WrapData If return status of this function is TRUE:\r
532616bb 40 1) when WrapFlag is TRUE, pointer to P7Data.\r
41 2) when WrapFlag is FALSE, pointer to a new ContentInfo\r
42 structure. It's caller's responsibility to free this\r
43 buffer.\r
44 @param[out] WrapDataSize Length of ContentInfo structure in bytes.\r
45\r
46 @retval TRUE The operation is finished successfully.\r
47 @retval FALSE The operation is failed due to lack of resources.\r
48\r
49**/\r
50BOOLEAN\r
51WrapPkcs7Data (\r
52 IN CONST UINT8 *P7Data,\r
53 IN UINTN P7Length,\r
54 OUT BOOLEAN *WrapFlag,\r
55 OUT UINT8 **WrapData,\r
56 OUT UINTN *WrapDataSize\r
57 )\r
58{\r
7c342378
MK
59 BOOLEAN Wrapped;\r
60 UINT8 *SignedData;\r
532616bb 61\r
62 //\r
63 // Check whether input P7Data is a wrapped ContentInfo structure or not.\r
64 //\r
65 Wrapped = FALSE;\r
66 if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) {\r
67 if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) {\r
68 if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {\r
69 Wrapped = TRUE;\r
70 }\r
71 }\r
72 }\r
73\r
74 if (Wrapped) {\r
7c342378 75 *WrapData = (UINT8 *)P7Data;\r
532616bb 76 *WrapDataSize = P7Length;\r
77 } else {\r
78 //\r
79 // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.\r
80 //\r
81 *WrapDataSize = P7Length + 19;\r
82 *WrapData = malloc (*WrapDataSize);\r
83 if (*WrapData == NULL) {\r
84 *WrapFlag = Wrapped;\r
85 return FALSE;\r
86 }\r
87\r
88 SignedData = *WrapData;\r
89\r
90 //\r
91 // Part1: 0x30, 0x82.\r
92 //\r
93 SignedData[0] = 0x30;\r
94 SignedData[1] = 0x82;\r
95\r
96 //\r
97 // Part2: Length1 = P7Length + 19 - 4, in big endian.\r
98 //\r
7c342378
MK
99 SignedData[2] = (UINT8)(((UINT16)(*WrapDataSize - 4)) >> 8);\r
100 SignedData[3] = (UINT8)(((UINT16)(*WrapDataSize - 4)) & 0xff);\r
532616bb 101\r
102 //\r
103 // Part3: 0x06, 0x09.\r
104 //\r
105 SignedData[4] = 0x06;\r
106 SignedData[5] = 0x09;\r
107\r
108 //\r
109 // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.\r
110 //\r
111 CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue));\r
112\r
113 //\r
114 // Part5: 0xA0, 0x82.\r
115 //\r
116 SignedData[15] = 0xA0;\r
117 SignedData[16] = 0x82;\r
118\r
119 //\r
120 // Part6: Length2 = P7Length, in big endian.\r
121 //\r
7c342378
MK
122 SignedData[17] = (UINT8)(((UINT16)P7Length) >> 8);\r
123 SignedData[18] = (UINT8)(((UINT16)P7Length) & 0xff);\r
532616bb 124\r
125 //\r
126 // Part7: P7Data.\r
127 //\r
128 CopyMem (SignedData + 19, P7Data, P7Length);\r
129 }\r
130\r
131 *WrapFlag = Wrapped;\r
132 return TRUE;\r
133}\r
134\r
efad60c5 135/**\r
136 Pop single certificate from STACK_OF(X509).\r
137\r
138 If X509Stack, Cert, or CertSize is NULL, then return FALSE.\r
139\r
140 @param[in] X509Stack Pointer to a X509 stack object.\r
141 @param[out] Cert Pointer to a X509 certificate.\r
142 @param[out] CertSize Length of output X509 certificate in bytes.\r
2ac68e8b 143\r
efad60c5 144 @retval TRUE The X509 stack pop succeeded.\r
145 @retval FALSE The pop operation failed.\r
146\r
147**/\r
148BOOLEAN\r
149X509PopCertificate (\r
7c342378
MK
150 IN VOID *X509Stack,\r
151 OUT UINT8 **Cert,\r
152 OUT UINTN *CertSize\r
efad60c5 153 )\r
154{\r
7c342378
MK
155 BIO *CertBio;\r
156 X509 *X509Cert;\r
157\r
158 STACK_OF (X509) *CertStack;\r
159 BOOLEAN Status;\r
160 INT32 Result;\r
161 BUF_MEM *Ptr;\r
162 INT32 Length;\r
163 VOID *Buffer;\r
efad60c5 164\r
165 Status = FALSE;\r
166\r
167 if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) {\r
168 return Status;\r
169 }\r
170\r
7c342378 171 CertStack = (STACK_OF (X509) *) X509Stack;\r
efad60c5 172\r
173 X509Cert = sk_X509_pop (CertStack);\r
174\r
175 if (X509Cert == NULL) {\r
176 return Status;\r
177 }\r
178\r
179 Buffer = NULL;\r
180\r
181 CertBio = BIO_new (BIO_s_mem ());\r
182 if (CertBio == NULL) {\r
183 return Status;\r
184 }\r
185\r
186 Result = i2d_X509_bio (CertBio, X509Cert);\r
187 if (Result == 0) {\r
188 goto _Exit;\r
189 }\r
190\r
f56b11d2
QL
191 BIO_get_mem_ptr (CertBio, &Ptr);\r
192 Length = (INT32)(Ptr->length);\r
efad60c5 193 if (Length <= 0) {\r
194 goto _Exit;\r
195 }\r
196\r
197 Buffer = malloc (Length);\r
198 if (Buffer == NULL) {\r
199 goto _Exit;\r
200 }\r
201\r
202 Result = BIO_read (CertBio, Buffer, Length);\r
203 if (Result != Length) {\r
204 goto _Exit;\r
205 }\r
206\r
207 *Cert = Buffer;\r
208 *CertSize = Length;\r
209\r
210 Status = TRUE;\r
211\r
212_Exit:\r
213\r
214 BIO_free (CertBio);\r
215\r
216 if (!Status && (Buffer != NULL)) {\r
217 free (Buffer);\r
218 }\r
219\r
220 return Status;\r
221}\r
222\r
532616bb 223/**\r
224 Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7:\r
225 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
226 in a ContentInfo structure.\r
227\r
228 If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then\r
2998af86 229 return FALSE. If P7Length overflow, then return FALSE.\r
532616bb 230\r
231 Caution: This function may receive untrusted input.\r
232 UEFI Authenticated Variable is external input, so this function will do basic\r
233 check for PKCS#7 data structure.\r
234\r
235 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
236 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
237 @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data.\r
6fe575d0
LQ
238 It's caller's responsibility to free the buffer with\r
239 Pkcs7FreeSigners().\r
3702637a 240 This data structure is EFI_CERT_STACK type.\r
532616bb 241 @param[out] StackLength Length of signer's certificates in bytes.\r
242 @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.\r
6fe575d0
LQ
243 It's caller's responsibility to free the buffer with\r
244 Pkcs7FreeSigners().\r
532616bb 245 @param[out] CertLength Length of the trusted certificate in bytes.\r
246\r
247 @retval TRUE The operation is finished successfully.\r
248 @retval FALSE Error occurs during the operation.\r
249\r
250**/\r
251BOOLEAN\r
252EFIAPI\r
253Pkcs7GetSigners (\r
254 IN CONST UINT8 *P7Data,\r
255 IN UINTN P7Length,\r
256 OUT UINT8 **CertStack,\r
257 OUT UINTN *StackLength,\r
258 OUT UINT8 **TrustedCert,\r
259 OUT UINTN *CertLength\r
260 )\r
261{\r
7c342378
MK
262 PKCS7 *Pkcs7;\r
263 BOOLEAN Status;\r
264 UINT8 *SignedData;\r
265 CONST UINT8 *Temp;\r
266 UINTN SignedDataSize;\r
267 BOOLEAN Wrapped;\r
268\r
269 STACK_OF (X509) *Stack;\r
270 UINT8 Index;\r
271 UINT8 *CertBuf;\r
272 UINT8 *OldBuf;\r
273 UINTN BufferSize;\r
274 UINTN OldSize;\r
275 UINT8 *SingleCert;\r
276 UINTN SingleCertSize;\r
532616bb 277\r
278 if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||\r
7c342378
MK
279 (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX))\r
280 {\r
532616bb 281 return FALSE;\r
282 }\r
2ac68e8b 283\r
532616bb 284 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
285 if (!Status) {\r
286 return Status;\r
287 }\r
288\r
289 Status = FALSE;\r
290 Pkcs7 = NULL;\r
291 Stack = NULL;\r
292 CertBuf = NULL;\r
293 OldBuf = NULL;\r
294 SingleCert = NULL;\r
295\r
296 //\r
297 // Retrieve PKCS#7 Data (DER encoding)\r
298 //\r
299 if (SignedDataSize > INT_MAX) {\r
300 goto _Exit;\r
301 }\r
302\r
7c342378
MK
303 Temp = SignedData;\r
304 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);\r
532616bb 305 if (Pkcs7 == NULL) {\r
306 goto _Exit;\r
307 }\r
308\r
309 //\r
310 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
311 //\r
312 if (!PKCS7_type_is_signed (Pkcs7)) {\r
313 goto _Exit;\r
314 }\r
315\r
7c342378 316 Stack = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);\r
532616bb 317 if (Stack == NULL) {\r
318 goto _Exit;\r
319 }\r
320\r
321 //\r
322 // Convert CertStack to buffer in following format:\r
323 // UINT8 CertNumber;\r
324 // UINT32 Cert1Length;\r
325 // UINT8 Cert1[];\r
326 // UINT32 Cert2Length;\r
327 // UINT8 Cert2[];\r
328 // ...\r
329 // UINT32 CertnLength;\r
330 // UINT8 Certn[];\r
331 //\r
332 BufferSize = sizeof (UINT8);\r
333 OldSize = BufferSize;\r
2ac68e8b 334\r
532616bb 335 for (Index = 0; ; Index++) {\r
336 Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize);\r
337 if (!Status) {\r
338 break;\r
339 }\r
340\r
341 OldSize = BufferSize;\r
342 OldBuf = CertBuf;\r
343 BufferSize = OldSize + SingleCertSize + sizeof (UINT32);\r
344 CertBuf = malloc (BufferSize);\r
345\r
346 if (CertBuf == NULL) {\r
347 goto _Exit;\r
348 }\r
349\r
350 if (OldBuf != NULL) {\r
351 CopyMem (CertBuf, OldBuf, OldSize);\r
352 free (OldBuf);\r
353 OldBuf = NULL;\r
354 }\r
355\r
7c342378 356 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)SingleCertSize);\r
532616bb 357 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize);\r
358\r
359 free (SingleCert);\r
360 SingleCert = NULL;\r
361 }\r
362\r
363 if (CertBuf != NULL) {\r
364 //\r
365 // Update CertNumber.\r
366 //\r
367 CertBuf[0] = Index;\r
368\r
7c342378 369 *CertLength = BufferSize - OldSize - sizeof (UINT32);\r
532616bb 370 *TrustedCert = malloc (*CertLength);\r
371 if (*TrustedCert == NULL) {\r
372 goto _Exit;\r
373 }\r
374\r
375 CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);\r
376 *CertStack = CertBuf;\r
377 *StackLength = BufferSize;\r
7c342378 378 Status = TRUE;\r
2ac68e8b 379 }\r
532616bb 380\r
381_Exit:\r
382 //\r
383 // Release Resources\r
384 //\r
385 if (!Wrapped) {\r
386 free (SignedData);\r
387 }\r
388\r
389 if (Pkcs7 != NULL) {\r
390 PKCS7_free (Pkcs7);\r
391 }\r
392\r
393 if (Stack != NULL) {\r
7c342378 394 sk_X509_pop_free (Stack, X509_free);\r
532616bb 395 }\r
396\r
397 if (SingleCert != NULL) {\r
398 free (SingleCert);\r
399 }\r
400\r
401 if (!Status && (CertBuf != NULL)) {\r
402 free (CertBuf);\r
403 *CertStack = NULL;\r
404 }\r
405\r
406 if (OldBuf != NULL) {\r
407 free (OldBuf);\r
408 }\r
2ac68e8b 409\r
532616bb 410 return Status;\r
411}\r
412\r
413/**\r
414 Wrap function to use free() to free allocated memory for certificates.\r
415\r
416 @param[in] Certs Pointer to the certificates to be freed.\r
417\r
418**/\r
419VOID\r
420EFIAPI\r
421Pkcs7FreeSigners (\r
7c342378 422 IN UINT8 *Certs\r
532616bb 423 )\r
424{\r
425 if (Certs == NULL) {\r
426 return;\r
427 }\r
428\r
429 free (Certs);\r
430}\r
431\r
45419de6
QL
432/**\r
433 Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7:\r
434 Cryptographic Message Syntax Standard", and outputs two certificate lists chained and\r
435 unchained to the signer's certificates.\r
436 The input signed data could be wrapped in a ContentInfo structure.\r
437\r
438 @param[in] P7Data Pointer to the PKCS#7 message.\r
439 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
0f5f6b3d 440 @param[out] SignerChainCerts Pointer to the certificates list chained to signer's\r
6fe575d0
LQ
441 certificate. It's caller's responsibility to free the buffer\r
442 with Pkcs7FreeSigners().\r
3702637a 443 This data structure is EFI_CERT_STACK type.\r
45419de6
QL
444 @param[out] ChainLength Length of the chained certificates list buffer in bytes.\r
445 @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's\r
6fe575d0 446 responsibility to free the buffer with Pkcs7FreeSigners().\r
3702637a 447 This data structure is EFI_CERT_STACK type.\r
45419de6
QL
448 @param[out] UnchainLength Length of the unchained certificates list buffer in bytes.\r
449\r
450 @retval TRUE The operation is finished successfully.\r
451 @retval FALSE Error occurs during the operation.\r
452\r
453**/\r
454BOOLEAN\r
455EFIAPI\r
456Pkcs7GetCertificatesList (\r
457 IN CONST UINT8 *P7Data,\r
458 IN UINTN P7Length,\r
459 OUT UINT8 **SignerChainCerts,\r
460 OUT UINTN *ChainLength,\r
461 OUT UINT8 **UnchainCerts,\r
462 OUT UINTN *UnchainLength\r
463 )\r
464{\r
7c342378
MK
465 BOOLEAN Status;\r
466 UINT8 *NewP7Data;\r
467 UINTN NewP7Length;\r
468 BOOLEAN Wrapped;\r
469 UINT8 Index;\r
470 PKCS7 *Pkcs7;\r
471 X509_STORE_CTX *CertCtx;\r
472\r
473 STACK_OF (X509) *CtxChain;\r
474 STACK_OF (X509) *CtxUntrusted;\r
475 X509 *CtxCert;\r
476\r
477 STACK_OF (X509) *Signers;\r
478 X509 *Signer;\r
479 X509 *Cert;\r
480 X509 *Issuer;\r
481 X509_NAME *IssuerName;\r
482 UINT8 *CertBuf;\r
483 UINT8 *OldBuf;\r
484 UINTN BufferSize;\r
485 UINTN OldSize;\r
486 UINT8 *SingleCert;\r
487 UINTN CertSize;\r
45419de6
QL
488\r
489 //\r
490 // Initializations\r
491 //\r
7c342378
MK
492 Status = FALSE;\r
493 NewP7Data = NULL;\r
494 Pkcs7 = NULL;\r
495 CertCtx = NULL;\r
496 CtxChain = NULL;\r
497 CtxCert = NULL;\r
498 CtxUntrusted = NULL;\r
499 Cert = NULL;\r
500 SingleCert = NULL;\r
501 CertBuf = NULL;\r
502 OldBuf = NULL;\r
503 Signers = NULL;\r
45419de6 504\r
07cae065
HW
505 ZeroMem (&CertCtx, sizeof (CertCtx));\r
506\r
45419de6
QL
507 //\r
508 // Parameter Checking\r
509 //\r
510 if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) ||\r
7c342378
MK
511 (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX))\r
512 {\r
45419de6
QL
513 return Status;\r
514 }\r
515\r
516 *SignerChainCerts = NULL;\r
517 *ChainLength = 0;\r
518 *UnchainCerts = NULL;\r
519 *UnchainLength = 0;\r
520\r
521 //\r
522 // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed.\r
523 //\r
524 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length);\r
525 if (!Status || (NewP7Length > INT_MAX)) {\r
526 goto _Error;\r
527 }\r
528\r
529 //\r
530 // Decodes PKCS#7 SignedData\r
531 //\r
7c342378 532 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&NewP7Data, (int)NewP7Length);\r
45419de6
QL
533 if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) {\r
534 goto _Error;\r
535 }\r
536\r
537 //\r
538 // Obtains Signer's Certificate from PKCS#7 data\r
539 // NOTE: Only one signer case will be handled in this function, which means SignerInfos\r
0f5f6b3d 540 // should include only one signer's certificate.\r
45419de6
QL
541 //\r
542 Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY);\r
543 if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) {\r
544 goto _Error;\r
545 }\r
7c342378 546\r
45419de6
QL
547 Signer = sk_X509_value (Signers, 0);\r
548\r
f56b11d2
QL
549 CertCtx = X509_STORE_CTX_new ();\r
550 if (CertCtx == NULL) {\r
551 goto _Error;\r
552 }\r
7c342378 553\r
f56b11d2 554 if (!X509_STORE_CTX_init (CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) {\r
45419de6
QL
555 goto _Error;\r
556 }\r
7c342378 557\r
45419de6
QL
558 //\r
559 // Initialize Chained & Untrusted stack\r
560 //\r
f56b11d2
QL
561 CtxChain = X509_STORE_CTX_get0_chain (CertCtx);\r
562 CtxCert = X509_STORE_CTX_get0_cert (CertCtx);\r
563 if (CtxChain == NULL) {\r
564 if (((CtxChain = sk_X509_new_null ()) == NULL) ||\r
7c342378
MK
565 (!sk_X509_push (CtxChain, CtxCert)))\r
566 {\r
45419de6
QL
567 goto _Error;\r
568 }\r
569 }\r
7c342378 570\r
f56b11d2 571 CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx);\r
a9fb7b78
LQ
572 if (CtxUntrusted != NULL) {\r
573 (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer);\r
574 }\r
45419de6
QL
575\r
576 //\r
577 // Build certificates stack chained from Signer's certificate.\r
578 //\r
579 Cert = Signer;\r
7c342378 580 for ( ; ;) {\r
45419de6
QL
581 //\r
582 // Self-Issue checking\r
583 //\r
f56b11d2
QL
584 Issuer = NULL;\r
585 if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) {\r
586 if (X509_cmp (Issuer, Cert) == 0) {\r
587 break;\r
588 }\r
45419de6
QL
589 }\r
590\r
591 //\r
592 // Found the issuer of the current certificate\r
593 //\r
f56b11d2 594 if (CtxUntrusted != NULL) {\r
7c342378 595 Issuer = NULL;\r
f56b11d2
QL
596 IssuerName = X509_get_issuer_name (Cert);\r
597 Issuer = X509_find_by_subject (CtxUntrusted, IssuerName);\r
45419de6 598 if (Issuer != NULL) {\r
f56b11d2 599 if (!sk_X509_push (CtxChain, Issuer)) {\r
45419de6
QL
600 goto _Error;\r
601 }\r
7c342378 602\r
f56b11d2 603 (VOID)sk_X509_delete_ptr (CtxUntrusted, Issuer);\r
45419de6
QL
604\r
605 Cert = Issuer;\r
606 continue;\r
607 }\r
608 }\r
609\r
610 break;\r
611 }\r
612\r
613 //\r
614 // Converts Chained and Untrusted Certificate to Certificate Buffer in following format:\r
615 // UINT8 CertNumber;\r
616 // UINT32 Cert1Length;\r
617 // UINT8 Cert1[];\r
618 // UINT32 Cert2Length;\r
619 // UINT8 Cert2[];\r
620 // ...\r
621 // UINT32 CertnLength;\r
622 // UINT8 Certn[];\r
623 //\r
624\r
f56b11d2 625 if (CtxChain != NULL) {\r
45419de6 626 BufferSize = sizeof (UINT8);\r
45419de6
QL
627 CertBuf = NULL;\r
628\r
629 for (Index = 0; ; Index++) {\r
f56b11d2 630 Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize);\r
45419de6
QL
631 if (!Status) {\r
632 break;\r
633 }\r
634\r
635 OldSize = BufferSize;\r
636 OldBuf = CertBuf;\r
637 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
638 CertBuf = malloc (BufferSize);\r
639\r
640 if (CertBuf == NULL) {\r
641 Status = FALSE;\r
642 goto _Error;\r
643 }\r
7c342378 644\r
45419de6
QL
645 if (OldBuf != NULL) {\r
646 CopyMem (CertBuf, OldBuf, OldSize);\r
647 free (OldBuf);\r
648 OldBuf = NULL;\r
649 }\r
650\r
7c342378 651 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize);\r
45419de6
QL
652 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
653\r
654 free (SingleCert);\r
655 SingleCert = NULL;\r
656 }\r
657\r
658 if (CertBuf != NULL) {\r
659 //\r
660 // Update CertNumber.\r
661 //\r
662 CertBuf[0] = Index;\r
663\r
664 *SignerChainCerts = CertBuf;\r
665 *ChainLength = BufferSize;\r
666 }\r
667 }\r
668\r
f56b11d2 669 if (CtxUntrusted != NULL) {\r
45419de6 670 BufferSize = sizeof (UINT8);\r
45419de6
QL
671 CertBuf = NULL;\r
672\r
673 for (Index = 0; ; Index++) {\r
f56b11d2 674 Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize);\r
45419de6
QL
675 if (!Status) {\r
676 break;\r
677 }\r
678\r
679 OldSize = BufferSize;\r
680 OldBuf = CertBuf;\r
681 BufferSize = OldSize + CertSize + sizeof (UINT32);\r
682 CertBuf = malloc (BufferSize);\r
683\r
684 if (CertBuf == NULL) {\r
685 Status = FALSE;\r
686 goto _Error;\r
687 }\r
7c342378 688\r
45419de6
QL
689 if (OldBuf != NULL) {\r
690 CopyMem (CertBuf, OldBuf, OldSize);\r
691 free (OldBuf);\r
692 OldBuf = NULL;\r
693 }\r
694\r
7c342378 695 WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize);\r
45419de6
QL
696 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);\r
697\r
698 free (SingleCert);\r
699 SingleCert = NULL;\r
700 }\r
701\r
702 if (CertBuf != NULL) {\r
703 //\r
704 // Update CertNumber.\r
705 //\r
706 CertBuf[0] = Index;\r
707\r
708 *UnchainCerts = CertBuf;\r
709 *UnchainLength = BufferSize;\r
710 }\r
711 }\r
712\r
713 Status = TRUE;\r
714\r
715_Error:\r
716 //\r
717 // Release Resources.\r
718 //\r
719 if (!Wrapped && (NewP7Data != NULL)) {\r
720 free (NewP7Data);\r
721 }\r
722\r
723 if (Pkcs7 != NULL) {\r
724 PKCS7_free (Pkcs7);\r
725 }\r
7c342378 726\r
45419de6
QL
727 sk_X509_free (Signers);\r
728\r
a9fb7b78
LQ
729 if (CertCtx != NULL) {\r
730 X509_STORE_CTX_cleanup (CertCtx);\r
731 X509_STORE_CTX_free (CertCtx);\r
732 }\r
45419de6
QL
733\r
734 if (SingleCert != NULL) {\r
735 free (SingleCert);\r
736 }\r
737\r
738 if (OldBuf != NULL) {\r
739 free (OldBuf);\r
740 }\r
741\r
742 if (!Status && (CertBuf != NULL)) {\r
743 free (CertBuf);\r
744 *SignerChainCerts = NULL;\r
745 *UnchainCerts = NULL;\r
746 }\r
747\r
748 return Status;\r
749}\r
750\r
532616bb 751/**\r
2998af86 752 Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:\r
532616bb 753 Cryptographic Message Syntax Standard". The input signed data could be wrapped\r
754 in a ContentInfo structure.\r
755\r
756 If P7Data, TrustedCert or InData is NULL, then return FALSE.\r
2998af86 757 If P7Length, CertLength or DataLength overflow, then return FALSE.\r
532616bb 758\r
759 Caution: This function may receive untrusted input.\r
760 UEFI Authenticated Variable is external input, so this function will do basic\r
761 check for PKCS#7 data structure.\r
762\r
763 @param[in] P7Data Pointer to the PKCS#7 message to verify.\r
764 @param[in] P7Length Length of the PKCS#7 message in bytes.\r
765 @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which\r
766 is used for certificate chain verification.\r
767 @param[in] CertLength Length of the trusted certificate in bytes.\r
768 @param[in] InData Pointer to the content to be verified.\r
769 @param[in] DataLength Length of InData in bytes.\r
770\r
771 @retval TRUE The specified PKCS#7 signed data is valid.\r
772 @retval FALSE Invalid PKCS#7 signed data.\r
773\r
774**/\r
775BOOLEAN\r
776EFIAPI\r
777Pkcs7Verify (\r
778 IN CONST UINT8 *P7Data,\r
779 IN UINTN P7Length,\r
780 IN CONST UINT8 *TrustedCert,\r
781 IN UINTN CertLength,\r
782 IN CONST UINT8 *InData,\r
783 IN UINTN DataLength\r
784 )\r
785{\r
7c342378
MK
786 PKCS7 *Pkcs7;\r
787 BIO *DataBio;\r
788 BOOLEAN Status;\r
789 X509 *Cert;\r
790 X509_STORE *CertStore;\r
791 UINT8 *SignedData;\r
792 CONST UINT8 *Temp;\r
793 UINTN SignedDataSize;\r
794 BOOLEAN Wrapped;\r
532616bb 795\r
796 //\r
797 // Check input parameters.\r
798 //\r
7c342378
MK
799 if ((P7Data == NULL) || (TrustedCert == NULL) || (InData == NULL) ||\r
800 (P7Length > INT_MAX) || (CertLength > INT_MAX) || (DataLength > INT_MAX))\r
801 {\r
532616bb 802 return FALSE;\r
803 }\r
2ac68e8b 804\r
532616bb 805 Pkcs7 = NULL;\r
532616bb 806 DataBio = NULL;\r
807 Cert = NULL;\r
808 CertStore = NULL;\r
809\r
810 //\r
811 // Register & Initialize necessary digest algorithms for PKCS#7 Handling\r
812 //\r
dda39f3a 813 if (EVP_add_digest (EVP_md5 ()) == 0) {\r
814 return FALSE;\r
815 }\r
7c342378 816\r
dda39f3a 817 if (EVP_add_digest (EVP_sha1 ()) == 0) {\r
818 return FALSE;\r
819 }\r
7c342378 820\r
dda39f3a 821 if (EVP_add_digest (EVP_sha256 ()) == 0) {\r
822 return FALSE;\r
823 }\r
7c342378 824\r
2ac68e8b
QL
825 if (EVP_add_digest (EVP_sha384 ()) == 0) {\r
826 return FALSE;\r
827 }\r
7c342378 828\r
2ac68e8b
QL
829 if (EVP_add_digest (EVP_sha512 ()) == 0) {\r
830 return FALSE;\r
831 }\r
7c342378 832\r
dda39f3a 833 if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {\r
834 return FALSE;\r
835 }\r
836\r
532616bb 837 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);\r
838 if (!Status) {\r
839 return Status;\r
840 }\r
841\r
842 Status = FALSE;\r
2ac68e8b 843\r
532616bb 844 //\r
845 // Retrieve PKCS#7 Data (DER encoding)\r
846 //\r
847 if (SignedDataSize > INT_MAX) {\r
848 goto _Exit;\r
849 }\r
850\r
7c342378
MK
851 Temp = SignedData;\r
852 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);\r
532616bb 853 if (Pkcs7 == NULL) {\r
854 goto _Exit;\r
855 }\r
856\r
857 //\r
858 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)\r
859 //\r
860 if (!PKCS7_type_is_signed (Pkcs7)) {\r
861 goto _Exit;\r
862 }\r
863\r
864 //\r
865 // Read DER-encoded root certificate and Construct X509 Certificate\r
866 //\r
1463ce18 867 Temp = TrustedCert;\r
7c342378 868 Cert = d2i_X509 (NULL, &Temp, (long)CertLength);\r
532616bb 869 if (Cert == NULL) {\r
870 goto _Exit;\r
871 }\r
872\r
873 //\r
874 // Setup X509 Store for trusted certificate\r
875 //\r
876 CertStore = X509_STORE_new ();\r
877 if (CertStore == NULL) {\r
878 goto _Exit;\r
879 }\r
7c342378 880\r
532616bb 881 if (!(X509_STORE_add_cert (CertStore, Cert))) {\r
882 goto _Exit;\r
883 }\r
884\r
532616bb 885 //\r
886 // For generic PKCS#7 handling, InData may be NULL if the content is present\r
887 // in PKCS#7 structure. So ignore NULL checking here.\r
888 //\r
7c342378 889 DataBio = BIO_new_mem_buf (InData, (int)DataLength);\r
5b2956ea
YT
890 if (DataBio == NULL) {\r
891 goto _Exit;\r
892 }\r
893\r
68547181
DW
894 //\r
895 // Allow partial certificate chains, terminated by a non-self-signed but\r
de0408be 896 // still trusted intermediate certificate. Also disable time checks.\r
68547181 897 //\r
7c342378
MK
898 X509_STORE_set_flags (\r
899 CertStore,\r
900 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME\r
901 );\r
68547181 902\r
02ee8d3b 903 //\r
904 // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and\r
905 // doesn't support the extended key usage for Authenticode Code Signing.\r
906 // Bypass the certificate purpose checking by enabling any purposes setting.\r
907 //\r
908 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);\r
909\r
532616bb 910 //\r
911 // Verifies the PKCS#7 signedData structure\r
912 //\r
7c342378 913 Status = (BOOLEAN)PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);\r
532616bb 914\r
915_Exit:\r
916 //\r
917 // Release Resources\r
918 //\r
919 BIO_free (DataBio);\r
532616bb 920 X509_free (Cert);\r
921 X509_STORE_free (CertStore);\r
922 PKCS7_free (Pkcs7);\r
923\r
924 if (!Wrapped) {\r
925 OPENSSL_free (SignedData);\r
926 }\r
927\r
928 return Status;\r
afeb55e4 929}\r