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