Changeset 64892 in vbox for trunk/src/VBox/Runtime/tools
- Timestamp:
- Dec 15, 2016 9:22:32 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/tools/RTSignTool.cpp
r64886 r64892 42 42 #include <iprt/string.h> 43 43 #include <iprt/uuid.h> 44 #include <iprt/zero.h> 45 #ifndef RT_OS_WINDOWS 46 # include <iprt/formats/pecoff.h> 47 #endif 44 48 #include <iprt/crypto/digest.h> 45 49 #include <iprt/crypto/x509.h> … … 49 53 #ifdef VBOX 50 54 # include <VBox/sup.h> /* Certificates */ 55 #endif 56 #ifdef RT_OS_WINDOWS 57 # include <iprt/win/windows.h> 58 # include <ImageHlp.h> 51 59 #endif 52 60 … … 80 88 /** Pointer to the indirect data content. */ 81 89 PRTCRSPCINDIRECTDATACONTENT pIndData; 90 91 /** Newly encoded raw signature. 92 * @sa SignToolPkcs7_Encode() */ 93 uint8_t *pbNewBuf; 94 /** Size of newly encoded raw signature. */ 95 size_t cbNewBuf; 96 82 97 } SIGNTOOLPKCS7; 83 98 typedef SIGNTOOLPKCS7 *PSIGNTOOLPKCS7; … … 117 132 static RTEXITCODE HandleVersion(int cArgs, char **papszArgs); 118 133 #ifndef IPRT_IN_BUILD_TOOL 119 static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix); 134 static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix, 135 PCRTCRPKCS7CONTENTINFO pContentInfo); 120 136 #endif 121 137 … … 135 151 pThis->pbBuf = NULL; 136 152 pThis->cbBuf = 0; 153 RTMemFree(pThis->pbNewBuf); 154 pThis->pbNewBuf = NULL; 155 pThis->cbNewBuf = 0; 137 156 } 138 157 … … 217 236 return rc; 218 237 } 238 239 240 /** 241 * Encodes the signature into the SIGNTOOLPKCS7::pbNewBuf and 242 * SIGNTOOLPKCS7::cbNewBuf members. 243 * 244 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message 245 * on failure. 246 * @param pThis The signature to encode. 247 * @param cVerbosity The verbosity. 248 */ 249 static RTEXITCODE SignToolPkcs7_Encode(PSIGNTOOLPKCS7 pThis, unsigned cVerbosity) 250 { 251 RTERRINFOSTATIC StaticErrInfo; 252 PRTASN1CORE pRoot = RTCrPkcs7ContentInfo_GetAsn1Core(&pThis->ContentInfo); 253 uint32_t cbEncoded; 254 int rc = RTAsn1EncodePrepare(pRoot, RTASN1ENCODE_F_DER, &cbEncoded, RTErrInfoInitStatic(&StaticErrInfo)); 255 if (RT_SUCCESS(rc)) 256 { 257 if (cVerbosity >= 4) 258 RTAsn1Dump(pRoot, 0, 0, RTStrmDumpPrintfV, g_pStdOut); 259 260 RTMemFree(pThis->pbNewBuf); 261 pThis->cbNewBuf = cbEncoded; 262 pThis->pbNewBuf = (uint8_t *)RTMemAllocZ(cbEncoded); 263 if (pThis->pbNewBuf) 264 { 265 rc = RTAsn1EncodeToBuffer(pRoot, RTASN1ENCODE_F_DER, pThis->pbNewBuf, pThis->cbNewBuf, 266 RTErrInfoInitStatic(&StaticErrInfo)); 267 if (RT_SUCCESS(rc)) 268 { 269 if (cVerbosity > 1) 270 RTMsgInfo("Encoded signature to %u bytes", cbEncoded); 271 return RTEXITCODE_SUCCESS; 272 } 273 RTMsgError("RTAsn1EncodeToBuffer failed: %Rrc", rc); 274 275 RTMemFree(pThis->pbNewBuf); 276 pThis->pbNewBuf = NULL; 277 } 278 else 279 RTMsgError("Failed to allocate %u bytes!", cbEncoded); 280 } 281 else 282 RTMsgError("RTAsn1EncodePrepare failed: %Rrc - %s", rc, StaticErrInfo.szMsg); 283 return RTEXITCODE_FAILURE; 284 } 285 286 287 /** 288 * Adds the @a pSrc signature as a nested signature. 289 * 290 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message 291 * on failure. 292 * @param pThis The signature to modify. 293 * @param pSrc The signature to add as nested. 294 * @param cVerbosity The verbosity. 295 */ 296 static RTEXITCODE SignToolPkcs7_AddNestedSignature(PSIGNTOOLPKCS7 pThis, PSIGNTOOLPKCS7 pSrc, unsigned cVerbosity) 297 { 298 PRTCRPKCS7SIGNERINFO pSignerInfo = pThis->pSignedData->SignerInfos.papItems[0]; 299 int32_t iPos = RTCrPkcs7Attributes_Append(&pSignerInfo->UnauthenticatedAttributes); 300 if (iPos >= 0) 301 { 302 PRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos]; 303 int rc = RTAsn1ObjId_InitFromString(&pAttr->Type, RTCR_PKCS9_ID_MS_NESTED_SIGNATURE, pAttr->Allocation.pAllocator); 304 if (RT_SUCCESS(rc)) 305 { 306 /** @todo Generalize the Type + enmType DYN stuff and generate setters. */ 307 Assert(pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT); 308 Assert(pAttr->uValues.pContentInfos == NULL); 309 pAttr->enmType = RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE; 310 rc = RTAsn1MemAllocZ(&pAttr->Allocation, (void **)&pAttr->uValues.pContentInfos, 311 sizeof(*pAttr->uValues.pContentInfos)); 312 if (RT_SUCCESS(rc)) 313 { 314 rc = RTCrPkcs7SetOfContentInfos_Init(pAttr->uValues.pContentInfos, pAttr->Allocation.pAllocator); 315 if (RT_SUCCESS(rc)) 316 { 317 iPos = RTCrPkcs7SetOfContentInfos_Append(pAttr->uValues.pContentInfos); 318 if (iPos >= 0) 319 { 320 PRTCRPKCS7CONTENTINFO pCntInfo = pAttr->uValues.pContentInfos->papItems[iPos]; 321 rc = RTCrPkcs7ContentInfo_Clone(pCntInfo, &pSrc->ContentInfo, pAttr->Allocation.pAllocator); 322 if (RT_SUCCESS(rc)) 323 { 324 if (cVerbosity > 0) 325 RTMsgInfo("Added nested signature"); 326 return RTEXITCODE_SUCCESS; 327 } 328 329 RTMsgError("RTCrPkcs7ContentInfo_Clone failed: %Rrc", iPos); 330 } 331 else 332 RTMsgError("RTCrPkcs7ContentInfos_Append failed: %Rrc", iPos); 333 } 334 else 335 RTMsgError("RTCrPkcs7ContentInfos_Init failed: %Rrc", rc); 336 } 337 else 338 RTMsgError("RTAsn1MemAllocZ failed: %Rrc", rc); 339 } 340 else 341 RTMsgError("RTAsn1ObjId_InitFromString failed: %Rrc", rc); 342 } 343 else 344 RTMsgError("RTCrPkcs7Attributes_Append failed: %Rrc", iPos); 345 NOREF(cVerbosity); 346 return RTEXITCODE_FAILURE; 347 } 348 219 349 220 350 … … 306 436 307 437 } 438 439 440 /** 441 * Calculates the checksum of an executable. 442 * 443 * @returns Success indicator (errors are reported) 444 * @param pThis The exe file to checksum. 445 * @param hFile The file handle. 446 * @param puCheckSum Where to return the checksum. 447 */ 448 static bool SignToolPkcs7Exe_CalcPeCheckSum(PSIGNTOOLPKCS7EXE pThis, RTFILE hFile, uint32_t *puCheckSum) 449 { 450 #ifdef RT_OS_WINDOWS 451 /* 452 * Try use IMAGEHLP!MapFileAndCheckSumW first. 453 */ 454 PRTUTF16 pwszPath; 455 int rc = RTStrToUtf16(pThis->pszFilename, &pwszPath); 456 if (RT_SUCCESS(rc)) 457 { 458 decltype(MapFileAndCheckSumW) *pfnMapFileAndCheckSumW; 459 pfnMapFileAndCheckSumW = (decltype(MapFileAndCheckSumW) *)RTLdrGetSystemSymbol("IMAGEHLP.DLL", "MapFileAndCheckSumW"); 460 if (pfnMapFileAndCheckSumW) 461 { 462 DWORD uHeaderSum = UINT32_MAX; 463 DWORD uCheckSum = UINT32_MAX; 464 DWORD dwRc = pfnMapFileAndCheckSumW(pwszPath, &uHeaderSum, &uCheckSum); 465 if (dwRc == CHECKSUM_SUCCESS) 466 { 467 *puCheckSum = uCheckSum; 468 return true; 469 } 470 } 471 } 472 #endif 473 474 RT_NOREF(pThis, hFile, puCheckSum); 475 RTMsgError("Implement check sum calcuation fallback!"); 476 return false; 477 } 478 479 480 /** 481 * Writes the signature to the file. 482 * 483 * This has the side-effect of closing the hLdrMod member. So, it can only be 484 * called once! 485 * 486 * Caller must have called SignToolPkcs7_Encode() prior to this function. 487 * 488 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error 489 * message on failure. 490 * @param pThis The file which to write. 491 * @param cVerbosity The verbosity. 492 */ 493 static RTEXITCODE SignToolPkcs7Exe_WriteSignatureToFile(PSIGNTOOLPKCS7EXE pThis, unsigned cVerbosity) 494 { 495 AssertReturn(pThis->cbNewBuf && pThis->pbNewBuf, RTEXITCODE_FAILURE); 496 497 /* 498 * Get the file header offset and arch before closing the destination handle. 499 */ 500 uint32_t offNtHdrs; 501 int rc = RTLdrQueryProp(pThis->hLdrMod, RTLDRPROP_FILE_OFF_HEADER, &offNtHdrs, sizeof(offNtHdrs)); 502 if (RT_SUCCESS(rc)) 503 { 504 RTLDRARCH enmLdrArch = RTLdrGetArch(pThis->hLdrMod); 505 if (enmLdrArch != RTLDRARCH_INVALID) 506 { 507 RTLdrClose(pThis->hLdrMod); 508 pThis->hLdrMod = NIL_RTLDRMOD; 509 unsigned cbNtHdrs = 0; 510 switch (enmLdrArch) 511 { 512 case RTLDRARCH_AMD64: 513 cbNtHdrs = sizeof(IMAGE_NT_HEADERS64); 514 break; 515 case RTLDRARCH_X86_32: 516 cbNtHdrs = sizeof(IMAGE_NT_HEADERS32); 517 break; 518 default: 519 RTMsgError("Unknown image arch: %d", enmLdrArch); 520 } 521 if (cbNtHdrs > 0) 522 { 523 if (cVerbosity > 0) 524 RTMsgInfo("offNtHdrs=%#x cbNtHdrs=%u\n", offNtHdrs, cbNtHdrs); 525 526 /* 527 * Open the executable file for writing. 528 */ 529 RTFILE hFile; 530 rc = RTFileOpen(&hFile, pThis->pszFilename, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 531 if (RT_SUCCESS(rc)) 532 { 533 /* Read the file header and locate the security directory entry. */ 534 union 535 { 536 IMAGE_NT_HEADERS32 NtHdrs32; 537 IMAGE_NT_HEADERS64 NtHdrs64; 538 } uBuf; 539 PIMAGE_DATA_DIRECTORY pSecDir = cbNtHdrs == sizeof(IMAGE_NT_HEADERS64) 540 ? &uBuf.NtHdrs64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] 541 : &uBuf.NtHdrs32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; 542 543 rc = RTFileReadAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL); 544 if ( RT_SUCCESS(rc) 545 && uBuf.NtHdrs32.Signature == IMAGE_NT_SIGNATURE) 546 { 547 /* 548 * Drop any old signature by truncating the file. 549 */ 550 if ( pSecDir->Size > 8 551 && pSecDir->VirtualAddress > offNtHdrs + sizeof(IMAGE_NT_HEADERS32)) 552 { 553 rc = RTFileSetSize(hFile, pSecDir->VirtualAddress); 554 if (RT_FAILURE(rc)) 555 RTMsgError("Error truncating file to %#x bytes: %Rrc", pSecDir->VirtualAddress, rc); 556 } 557 else 558 rc = RTMsgErrorRc(VERR_BAD_EXE_FORMAT, "Bad security directory entry: VA=%#x Size=%#x", 559 pSecDir->VirtualAddress, pSecDir->Size); 560 if (RT_SUCCESS(rc)) 561 { 562 /* 563 * Sector align the signature portion. 564 */ 565 uint32_t const cbWinCert = RT_OFFSETOF(WIN_CERTIFICATE, bCertificate); 566 uint64_t offCur = 0; 567 rc = RTFileGetSize(hFile, &offCur); 568 if ( RT_SUCCESS(rc) 569 && offCur < _2G) 570 { 571 if (offCur & 0x1ff) 572 { 573 uint32_t cbNeeded = 0x200 - ((uint32_t)offCur & 0x1ff); 574 rc = RTFileWriteAt(hFile, offCur, g_abRTZero4K, cbNeeded, NULL); 575 if (RT_SUCCESS(rc)) 576 offCur += cbNeeded; 577 } 578 if (RT_SUCCESS(rc)) 579 { 580 /* 581 * Write the header followed by the signature data. 582 */ 583 pSecDir->VirtualAddress = (uint32_t)offCur; 584 pSecDir->Size = cbWinCert + (uint32_t)pThis->cbNewBuf; 585 if (cVerbosity >= 2) 586 RTMsgInfo("Writing %u (%#x) bytes of signature at %#x (%u).\n", 587 pSecDir->Size, pSecDir->Size, pSecDir->VirtualAddress, pSecDir->VirtualAddress); 588 589 WIN_CERTIFICATE WinCert; 590 WinCert.dwLength = pSecDir->Size; 591 WinCert.wRevision = WIN_CERT_REVISION_2_0; 592 WinCert.wCertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA; 593 594 rc = RTFileWriteAt(hFile, offCur, &WinCert, cbWinCert, NULL); 595 if (RT_SUCCESS(rc)) 596 { 597 offCur += cbWinCert; 598 rc = RTFileWriteAt(hFile, offCur, pThis->pbNewBuf, pThis->cbNewBuf, NULL); 599 if (RT_SUCCESS(rc)) 600 { 601 /* 602 * Reset the checksum (sec dir updated already) and rewrite the header. 603 */ 604 uBuf.NtHdrs32.OptionalHeader.CheckSum = 0; 605 offCur = offNtHdrs; 606 rc = RTFileWriteAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL); 607 if (RT_SUCCESS(rc)) 608 rc = RTFileFlush(hFile); 609 if (RT_SUCCESS(rc)) 610 { 611 /* 612 * Calc checksum and write out the header again. 613 */ 614 uint32_t uCheckSum = UINT32_MAX; 615 if (SignToolPkcs7Exe_CalcPeCheckSum(pThis, hFile, &uCheckSum)) 616 { 617 rc = RTFileWriteAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL); 618 if (RT_SUCCESS(rc)) 619 rc = RTFileFlush(hFile); 620 if (RT_SUCCESS(rc)) 621 { 622 rc = RTFileClose(hFile); 623 if (RT_SUCCESS(rc)) 624 return RTEXITCODE_SUCCESS; 625 RTMsgError("RTFileClose failed: %Rrc\n", rc); 626 return RTEXITCODE_FAILURE; 627 } 628 } 629 } 630 } 631 } 632 } 633 if (RT_FAILURE(rc)) 634 RTMsgError("Write error at %#RX64: %Rrc", offCur, rc); 635 } 636 else if (RT_SUCCESS(rc)) 637 RTMsgError("File to big: %'RU64 bytes", offCur); 638 else 639 RTMsgError("RTFileGetSize failed: %Rrc", rc); 640 } 641 } 642 else if (RT_SUCCESS(rc)) 643 RTMsgError("Not NT executable header!"); 644 else 645 RTMsgError("Error reading NT headers (%#x bytes) at %#x: %Rrc", cbNtHdrs, offNtHdrs, rc); 646 RTFileClose(hFile); 647 } 648 else 649 RTMsgError("Failed to open '%s' for writing: %Rrc", pThis->pszFilename, rc); 650 } 651 } 652 else 653 RTMsgError("RTLdrGetArch failed!"); 654 } 655 else 656 RTMsgError("RTLdrQueryProp/RTLDRPROP_FILE_OFF_HEADER failed: %Rrc", rc); 657 return RTEXITCODE_FAILURE; 658 } 659 308 660 309 661 … … 473 825 case 'v': cVerbosity++; break; 474 826 case 'V': return HandleVersion(cArgs, papszArgs); 475 case 'h': return Help ExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);827 case 'h': return HelpAddNestedExeSignature(g_pStdOut, RTSIGNTOOLHELP_FULL); 476 828 477 829 case VINF_GETOPT_NOT_OPTION: … … 503 855 /* Ditto for the destination PKCS#7 signature. */ 504 856 SIGNTOOLPKCS7EXE Dst; 505 rcExit = SignToolPkcs7Exe_InitFromFile(&Dst, psz Src, cVerbosity);857 rcExit = SignToolPkcs7Exe_InitFromFile(&Dst, pszDst, cVerbosity); 506 858 if (rcExit == RTEXITCODE_SUCCESS) 507 859 { 508 /* Add the source to the destination as a nested signature. */ 509 //Src.pSignedData->SignerInfos.paItems 510 511 860 /* Do the signature manipulation. */ 861 rcExit = SignToolPkcs7_AddNestedSignature(&Dst, &Src, cVerbosity); 862 if (rcExit == RTEXITCODE_SUCCESS) 863 rcExit = SignToolPkcs7_Encode(&Dst, cVerbosity); 864 865 /* Update the destination executable file. */ 866 if (rcExit == RTEXITCODE_SUCCESS) 867 rcExit = SignToolPkcs7Exe_WriteSignatureToFile(&Dst, cVerbosity); 512 868 SignToolPkcs7Exe_Delete(&Dst); 513 869 } … … 1071 1427 int rc2; 1072 1428 if (RTCrPkcs7ContentInfo_IsSignedData(pContentInfo)) 1073 rc2 = HandleShowExeWorkerPkcs7Display(pThis, pContentInfo->u.pSignedData, offPrefix2 );1429 rc2 = HandleShowExeWorkerPkcs7Display(pThis, pContentInfo->u.pSignedData, offPrefix2, pContentInfo); 1074 1430 else 1075 1431 rc2 = RTMsgErrorRc(VERR_ASN1_UNEXPECTED_OBJ_ID, "%sPKCS#7 content in nested signature is not 'signedData': %s", … … 1275 1631 * @returns IPRT status code. 1276 1632 * @param pThis The show exe instance data. 1633 * @param pSignedData The signed data to display. 1277 1634 * @param offPrefix The current prefix offset. 1278 * @param pSignedData The signed data to display. 1279 */ 1280 static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix) 1635 * @param pContentInfo The content info structure (for the size). 1636 */ 1637 static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix, 1638 PCRTCRPKCS7CONTENTINFO pContentInfo) 1281 1639 { 1282 1640 pThis->szPrefix[offPrefix] = '\0'; 1641 RTPrintf("%sPKCS#7 signature: %u (%#x) bytes\n", pThis->szPrefix, 1642 RTASN1CORE_GET_RAW_ASN1_SIZE(&pContentInfo->SeqCore.Asn1Core), 1643 RTASN1CORE_GET_RAW_ASN1_SIZE(&pContentInfo->SeqCore.Asn1Core)); 1283 1644 1284 1645 /* … … 1414 1775 if (rcExit == RTEXITCODE_SUCCESS) 1415 1776 { 1416 int rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0 );1777 int rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0, &This.ContentInfo); 1417 1778 if (RT_FAILURE(rc)) 1418 1779 rcExit = RTEXITCODE_FAILURE;
Note:
See TracChangeset
for help on using the changeset viewer.