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