]> git.proxmox.com Git - mirror_edk2.git/blob - CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Verify.c
CryptoPkg/BaseCryptLib: Add NULL pointer checks in DH and P7Verify
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptPkcs7Verify.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 - 2017, 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.
244 @param[out] StackLength Length of signer's certificates in bytes.
245 @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates.
246 It's caller's responsibility to free the buffer.
247 @param[out] CertLength Length of the trusted certificate in bytes.
248
249 @retval TRUE The operation is finished successfully.
250 @retval FALSE Error occurs during the operation.
251
252 **/
253 BOOLEAN
254 EFIAPI
255 Pkcs7GetSigners (
256 IN CONST UINT8 *P7Data,
257 IN UINTN P7Length,
258 OUT UINT8 **CertStack,
259 OUT UINTN *StackLength,
260 OUT UINT8 **TrustedCert,
261 OUT UINTN *CertLength
262 )
263 {
264 PKCS7 *Pkcs7;
265 BOOLEAN Status;
266 UINT8 *SignedData;
267 CONST UINT8 *Temp;
268 UINTN SignedDataSize;
269 BOOLEAN Wrapped;
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 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 @param[out] ChainLength Length of the chained certificates list buffer in bytes.
443 @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's
444 responsibility to free the buffer.
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 OldSize = BufferSize;
616 CertBuf = NULL;
617
618 for (Index = 0; ; Index++) {
619 Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize);
620 if (!Status) {
621 break;
622 }
623
624 OldSize = BufferSize;
625 OldBuf = CertBuf;
626 BufferSize = OldSize + CertSize + sizeof (UINT32);
627 CertBuf = malloc (BufferSize);
628
629 if (CertBuf == NULL) {
630 Status = FALSE;
631 goto _Error;
632 }
633 if (OldBuf != NULL) {
634 CopyMem (CertBuf, OldBuf, OldSize);
635 free (OldBuf);
636 OldBuf = NULL;
637 }
638
639 WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
640 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
641
642 free (SingleCert);
643 SingleCert = NULL;
644 }
645
646 if (CertBuf != NULL) {
647 //
648 // Update CertNumber.
649 //
650 CertBuf[0] = Index;
651
652 *SignerChainCerts = CertBuf;
653 *ChainLength = BufferSize;
654 }
655 }
656
657 if (CtxUntrusted != NULL) {
658 BufferSize = sizeof (UINT8);
659 OldSize = BufferSize;
660 CertBuf = NULL;
661
662 for (Index = 0; ; Index++) {
663 Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize);
664 if (!Status) {
665 break;
666 }
667
668 OldSize = BufferSize;
669 OldBuf = CertBuf;
670 BufferSize = OldSize + CertSize + sizeof (UINT32);
671 CertBuf = malloc (BufferSize);
672
673 if (CertBuf == NULL) {
674 Status = FALSE;
675 goto _Error;
676 }
677 if (OldBuf != NULL) {
678 CopyMem (CertBuf, OldBuf, OldSize);
679 free (OldBuf);
680 OldBuf = NULL;
681 }
682
683 WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize);
684 CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize);
685
686 free (SingleCert);
687 SingleCert = NULL;
688 }
689
690 if (CertBuf != NULL) {
691 //
692 // Update CertNumber.
693 //
694 CertBuf[0] = Index;
695
696 *UnchainCerts = CertBuf;
697 *UnchainLength = BufferSize;
698 }
699 }
700
701 Status = TRUE;
702
703 _Error:
704 //
705 // Release Resources.
706 //
707 if (!Wrapped && (NewP7Data != NULL)) {
708 free (NewP7Data);
709 }
710
711 if (Pkcs7 != NULL) {
712 PKCS7_free (Pkcs7);
713 }
714 sk_X509_free (Signers);
715
716 if (CertCtx != NULL) {
717 X509_STORE_CTX_cleanup (CertCtx);
718 X509_STORE_CTX_free (CertCtx);
719 }
720
721 if (SingleCert != NULL) {
722 free (SingleCert);
723 }
724
725 if (OldBuf != NULL) {
726 free (OldBuf);
727 }
728
729 if (!Status && (CertBuf != NULL)) {
730 free (CertBuf);
731 *SignerChainCerts = NULL;
732 *UnchainCerts = NULL;
733 }
734
735 return Status;
736 }
737
738 /**
739 Verifies the validity of a PKCS#7 signed data as described in "PKCS #7:
740 Cryptographic Message Syntax Standard". The input signed data could be wrapped
741 in a ContentInfo structure.
742
743 If P7Data, TrustedCert or InData is NULL, then return FALSE.
744 If P7Length, CertLength or DataLength overflow, then return FALSE.
745
746 Caution: This function may receive untrusted input.
747 UEFI Authenticated Variable is external input, so this function will do basic
748 check for PKCS#7 data structure.
749
750 @param[in] P7Data Pointer to the PKCS#7 message to verify.
751 @param[in] P7Length Length of the PKCS#7 message in bytes.
752 @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which
753 is used for certificate chain verification.
754 @param[in] CertLength Length of the trusted certificate in bytes.
755 @param[in] InData Pointer to the content to be verified.
756 @param[in] DataLength Length of InData in bytes.
757
758 @retval TRUE The specified PKCS#7 signed data is valid.
759 @retval FALSE Invalid PKCS#7 signed data.
760
761 **/
762 BOOLEAN
763 EFIAPI
764 Pkcs7Verify (
765 IN CONST UINT8 *P7Data,
766 IN UINTN P7Length,
767 IN CONST UINT8 *TrustedCert,
768 IN UINTN CertLength,
769 IN CONST UINT8 *InData,
770 IN UINTN DataLength
771 )
772 {
773 PKCS7 *Pkcs7;
774 BIO *DataBio;
775 BOOLEAN Status;
776 X509 *Cert;
777 X509_STORE *CertStore;
778 UINT8 *SignedData;
779 CONST UINT8 *Temp;
780 UINTN SignedDataSize;
781 BOOLEAN Wrapped;
782
783 //
784 // Check input parameters.
785 //
786 if (P7Data == NULL || TrustedCert == NULL || InData == NULL ||
787 P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) {
788 return FALSE;
789 }
790
791 Pkcs7 = NULL;
792 DataBio = NULL;
793 Cert = NULL;
794 CertStore = NULL;
795
796 //
797 // Register & Initialize necessary digest algorithms for PKCS#7 Handling
798 //
799 if (EVP_add_digest (EVP_md5 ()) == 0) {
800 return FALSE;
801 }
802 if (EVP_add_digest (EVP_sha1 ()) == 0) {
803 return FALSE;
804 }
805 if (EVP_add_digest (EVP_sha256 ()) == 0) {
806 return FALSE;
807 }
808 if (EVP_add_digest (EVP_sha384 ()) == 0) {
809 return FALSE;
810 }
811 if (EVP_add_digest (EVP_sha512 ()) == 0) {
812 return FALSE;
813 }
814 if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) {
815 return FALSE;
816 }
817
818 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
819 if (!Status) {
820 return Status;
821 }
822
823 Status = FALSE;
824
825 //
826 // Retrieve PKCS#7 Data (DER encoding)
827 //
828 if (SignedDataSize > INT_MAX) {
829 goto _Exit;
830 }
831
832 Temp = SignedData;
833 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize);
834 if (Pkcs7 == NULL) {
835 goto _Exit;
836 }
837
838 //
839 // Check if it's PKCS#7 Signed Data (for Authenticode Scenario)
840 //
841 if (!PKCS7_type_is_signed (Pkcs7)) {
842 goto _Exit;
843 }
844
845 //
846 // Read DER-encoded root certificate and Construct X509 Certificate
847 //
848 Temp = TrustedCert;
849 Cert = d2i_X509 (NULL, &Temp, (long) CertLength);
850 if (Cert == NULL) {
851 goto _Exit;
852 }
853
854 //
855 // Setup X509 Store for trusted certificate
856 //
857 CertStore = X509_STORE_new ();
858 if (CertStore == NULL) {
859 goto _Exit;
860 }
861 if (!(X509_STORE_add_cert (CertStore, Cert))) {
862 goto _Exit;
863 }
864
865 //
866 // For generic PKCS#7 handling, InData may be NULL if the content is present
867 // in PKCS#7 structure. So ignore NULL checking here.
868 //
869 DataBio = BIO_new (BIO_s_mem ());
870 if (DataBio == NULL) {
871 goto _Exit;
872 }
873
874 if (BIO_write (DataBio, InData, (int) DataLength) <= 0) {
875 goto _Exit;
876 }
877
878 //
879 // Allow partial certificate chains, terminated by a non-self-signed but
880 // still trusted intermediate certificate. Also disable time checks.
881 //
882 X509_STORE_set_flags (CertStore,
883 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME);
884
885 //
886 // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and
887 // doesn't support the extended key usage for Authenticode Code Signing.
888 // Bypass the certificate purpose checking by enabling any purposes setting.
889 //
890 X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY);
891
892 //
893 // Verifies the PKCS#7 signedData structure
894 //
895 Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY);
896
897 _Exit:
898 //
899 // Release Resources
900 //
901 BIO_free (DataBio);
902 X509_free (Cert);
903 X509_STORE_free (CertStore);
904 PKCS7_free (Pkcs7);
905
906 if (!Wrapped) {
907 OPENSSL_free (SignedData);
908 }
909
910 return Status;
911 }
912
913 /**
914 Extracts the attached content from a PKCS#7 signed data if existed. The input signed
915 data could be wrapped in a ContentInfo structure.
916
917 If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow,
918 then return FALSE. If the P7Data is not correctly formatted, then return FALSE.
919
920 Caution: This function may receive untrusted input. So this function will do
921 basic check for PKCS#7 data structure.
922
923 @param[in] P7Data Pointer to the PKCS#7 signed data to process.
924 @param[in] P7Length Length of the PKCS#7 signed data in bytes.
925 @param[out] Content Pointer to the extracted content from the PKCS#7 signedData.
926 It's caller's responsibility to free the buffer.
927 @param[out] ContentSize The size of the extracted content in bytes.
928
929 @retval TRUE The P7Data was correctly formatted for processing.
930 @retval FALSE The P7Data was not correctly formatted for processing.
931
932 **/
933 BOOLEAN
934 EFIAPI
935 Pkcs7GetAttachedContent (
936 IN CONST UINT8 *P7Data,
937 IN UINTN P7Length,
938 OUT VOID **Content,
939 OUT UINTN *ContentSize
940 )
941 {
942 BOOLEAN Status;
943 PKCS7 *Pkcs7;
944 UINT8 *SignedData;
945 UINTN SignedDataSize;
946 BOOLEAN Wrapped;
947 CONST UINT8 *Temp;
948 ASN1_OCTET_STRING *OctStr;
949
950 //
951 // Check input parameter.
952 //
953 if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {
954 return FALSE;
955 }
956
957 *Content = NULL;
958 Pkcs7 = NULL;
959 SignedData = NULL;
960 OctStr = NULL;
961
962 Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
963 if (!Status || (SignedDataSize > INT_MAX)) {
964 goto _Exit;
965 }
966
967 Status = FALSE;
968
969 //
970 // Decoding PKCS#7 SignedData
971 //
972 Temp = SignedData;
973 Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize);
974 if (Pkcs7 == NULL) {
975 goto _Exit;
976 }
977
978 //
979 // The type of Pkcs7 must be signedData
980 //
981 if (!PKCS7_type_is_signed (Pkcs7)) {
982 goto _Exit;
983 }
984
985 //
986 // Check for detached or attached content
987 //
988 if (PKCS7_get_detached (Pkcs7)) {
989 //
990 // No Content supplied for PKCS7 detached signedData
991 //
992 *Content = NULL;
993 *ContentSize = 0;
994 } else {
995 //
996 // Retrieve the attached content in PKCS7 signedData
997 //
998 OctStr = Pkcs7->d.sign->contents->d.data;
999 if ((OctStr->length > 0) && (OctStr->data != NULL)) {
1000 *ContentSize = OctStr->length;
1001 *Content = malloc (*ContentSize);
1002 if (*Content == NULL) {
1003 *ContentSize = 0;
1004 goto _Exit;
1005 }
1006 CopyMem (*Content, OctStr->data, *ContentSize);
1007 }
1008 }
1009 Status = TRUE;
1010
1011 _Exit:
1012 //
1013 // Release Resources
1014 //
1015 PKCS7_free (Pkcs7);
1016
1017 if (!Wrapped) {
1018 OPENSSL_free (SignedData);
1019 }
1020
1021 return Status;
1022 }