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