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