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