Changeset 64883 in vbox for trunk/src/VBox/Runtime/tools
- Timestamp:
- Dec 15, 2016 3:26:20 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/tools/RTSignTool.cpp
r64877 r64883 63 63 64 64 65 typedef struct SHOWEXEPKCS7 66 { 67 uint8_t const *pbBuf; 65 /** 66 * PKCS\#7 signature data. 67 */ 68 typedef struct SIGNTOOLPKCS7 69 { 70 /** The raw signature. */ 71 uint8_t *pbBuf; 72 /** Size of the raw signature. */ 68 73 size_t cbBuf; 74 /** The filename. */ 69 75 const char *pszFilename; 70 unsigned cVerbosity;71 RTLDRMOD hLdrMod;72 76 /** The outer content info wrapper. */ 73 77 RTCRPKCS7CONTENTINFO ContentInfo; … … 76 80 /** Pointer to the indirect data content. */ 77 81 PRTCRSPCINDIRECTDATACONTENT pIndData; 78 82 } SIGNTOOLPKCS7; 83 typedef SIGNTOOLPKCS7 *PSIGNTOOLPKCS7; 84 85 86 /** 87 * PKCS\#7 signature data for executable. 88 */ 89 typedef struct SIGNTOOLPKCS7EXE : public SIGNTOOLPKCS7 90 { 91 /** The module handle. */ 92 RTLDRMOD hLdrMod; 93 } SIGNTOOLPKCS7EXE; 94 typedef SIGNTOOLPKCS7EXE *PSIGNTOOLPKCS7EXE; 95 96 97 /** 98 * Data for the show exe (signature) command. 99 */ 100 typedef struct SHOWEXEPKCS7 : public SIGNTOOLPKCS7EXE 101 { 102 /** The verbosity. */ 103 unsigned cVerbosity; 104 /** The prefix buffer. */ 79 105 char szPrefix[256]; 106 /** Temporary buffer. */ 80 107 char szTmp[4096]; 81 108 } SHOWEXEPKCS7; … … 94 121 95 122 96 97 98 /*99 * The 'extract-exe-signer-cert' command.100 */101 static RTEXITCODE HelpExtractExeSignerCert(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)102 {103 RT_NOREF_PV(enmLevel);104 RTStrmPrintf(pStrm, "extract-exe-signer-cert [--ber|--cer|--der] [--exe|-e] <exe> [--output|-o] <outfile.cer>\n");105 return RTEXITCODE_SUCCESS;106 }107 108 static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs)109 {110 /*111 * Parse arguments.112 */113 static const RTGETOPTDEF s_aOptions[] =114 {115 { "--ber", 'b', RTGETOPT_REQ_NOTHING },116 { "--cer", 'c', RTGETOPT_REQ_NOTHING },117 { "--der", 'd', RTGETOPT_REQ_NOTHING },118 { "--exe", 'e', RTGETOPT_REQ_STRING },119 { "--output", 'o', RTGETOPT_REQ_STRING },120 };121 122 const char *pszExe = NULL;123 const char *pszOut = NULL;124 RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER;125 uint32_t fCursorFlags = RTASN1CURSOR_FLAGS_DER;126 127 RTGETOPTSTATE GetState;128 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);129 AssertRCReturn(rc, RTEXITCODE_FAILURE);130 RTGETOPTUNION ValueUnion;131 int ch;132 while ((ch = RTGetOpt(&GetState, &ValueUnion)))133 {134 switch (ch)135 {136 case 'e': pszExe = ValueUnion.psz; break;137 case 'o': pszOut = ValueUnion.psz; break;138 case 'b': fCursorFlags = 0; break;139 case 'c': fCursorFlags = RTASN1CURSOR_FLAGS_CER; break;140 case 'd': fCursorFlags = RTASN1CURSOR_FLAGS_DER; break;141 case 'V': return HandleVersion(cArgs, papszArgs);142 case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);143 144 case VINF_GETOPT_NOT_OPTION:145 if (!pszExe)146 pszExe = ValueUnion.psz;147 else if (!pszOut)148 pszOut = ValueUnion.psz;149 else150 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);151 break;152 153 default:154 return RTGetOptPrintError(ch, &ValueUnion);155 }156 }157 if (!pszExe)158 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");159 if (!pszOut)160 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");161 if (RTPathExists(pszOut))162 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut);163 164 /*165 * Do it.166 */167 168 /* Open the executable image and query the PKCS7 info. */169 RTLDRMOD hLdrMod;170 rc = RTLdrOpen(pszExe, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod);171 if (RT_FAILURE(rc))172 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszExe, rc);173 174 RTEXITCODE rcExit = RTEXITCODE_FAILURE;175 #ifdef DEBUG176 size_t cbBuf = 64;177 #else178 size_t cbBuf = _512K;179 #endif180 void *pvBuf = RTMemAlloc(cbBuf);181 size_t cbRet = 0;182 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);183 if (rc == VERR_BUFFER_OVERFLOW && cbRet < _4M && cbRet > 0)184 {185 RTMemFree(pvBuf);186 cbBuf = cbRet;187 pvBuf = RTMemAlloc(cbBuf);188 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbRet);189 }190 if (RT_SUCCESS(rc))191 {192 static RTERRINFOSTATIC s_StaticErrInfo;193 RTErrInfoInitStatic(&s_StaticErrInfo);194 195 /*196 * Decode the output.197 */198 RTASN1CURSORPRIMARY PrimaryCursor;199 RTAsn1CursorInitPrimary(&PrimaryCursor, pvBuf, (uint32_t)cbRet, &s_StaticErrInfo.Core,200 &g_RTAsn1DefaultAllocator, fCursorFlags, "exe");201 RTCRPKCS7CONTENTINFO Pkcs7Ci;202 rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &Pkcs7Ci, "pkcs7");203 if (RT_SUCCESS(rc))204 {205 if (RTCrPkcs7ContentInfo_IsSignedData(&Pkcs7Ci))206 {207 PCRTCRPKCS7SIGNEDDATA pSd = Pkcs7Ci.u.pSignedData;208 if (pSd->SignerInfos.cItems == 1)209 {210 PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSd->SignerInfos.paItems[0].IssuerAndSerialNumber;211 PCRTCRX509CERTIFICATE pCert;212 pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSd->Certificates,213 &pISN->Name, &pISN->SerialNumber);214 if (pCert)215 {216 /*217 * Write it out.218 */219 RTFILE hFile;220 rc = RTFileOpen(&hFile, pszOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE);221 if (RT_SUCCESS(rc))222 {223 uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb;224 rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr,225 cbCert, NULL);226 if (RT_SUCCESS(rc))227 {228 rc = RTFileClose(hFile);229 if (RT_SUCCESS(rc))230 {231 hFile = NIL_RTFILE;232 rcExit = RTEXITCODE_SUCCESS;233 RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszOut);234 }235 else236 RTMsgError("RTFileClose failed: %Rrc", rc);237 }238 else239 RTMsgError("RTFileWrite failed: %Rrc", rc);240 RTFileClose(hFile);241 }242 else243 RTMsgError("Error opening '%s': %Rrc", pszOut, rc);244 }245 else246 RTMsgError("Certificate not found.");247 }248 else249 RTMsgError("SignerInfo count: %u", pSd->SignerInfos.cItems);250 }251 else252 RTMsgError("No PKCS7 content: ContentType=%s", Pkcs7Ci.ContentType.szObjId);253 RTAsn1VtDelete(&Pkcs7Ci.SeqCore.Asn1Core);254 }255 else256 RTMsgError("RTPkcs7ContentInfoDecodeAsn1 failed: %Rrc - %s", rc, s_StaticErrInfo.szMsg);257 }258 else259 RTMsgError("RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc", pszExe, rc);260 RTMemFree(pvBuf);261 rc = RTLdrClose(hLdrMod);262 if (RT_FAILURE(rc))263 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc);264 return rcExit;265 }266 267 #ifndef IPRT_IN_BUILD_TOOL268 269 /*270 * The 'verify-exe' command.271 */272 static RTEXITCODE HelpVerifyExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)273 {274 RT_NOREF_PV(enmLevel);275 RTStrmPrintf(pStrm,276 "verify-exe [--verbose|--quiet] [--kernel] [--root <root-cert.der>] [--additional <supp-cert.der>]\n"277 " [--type <win|osx>] <exe1> [exe2 [..]]\n");278 return RTEXITCODE_SUCCESS;279 }280 281 typedef struct VERIFYEXESTATE282 {283 RTCRSTORE hRootStore;284 RTCRSTORE hKernelRootStore;285 RTCRSTORE hAdditionalStore;286 bool fKernel;287 int cVerbose;288 enum { kSignType_Windows, kSignType_OSX } enmSignType;289 uint64_t uTimestamp;290 RTLDRARCH enmLdrArch;291 } VERIFYEXESTATE;292 293 # ifdef VBOX294 /** Certificate store load set.295 * Declared outside HandleVerifyExe because of braindead gcc visibility crap. */296 struct STSTORESET297 {298 RTCRSTORE hStore;299 PCSUPTAENTRY paTAs;300 unsigned cTAs;301 };302 # endif303 304 123 /** 305 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, 306 * Standard code signing. Use this for Microsoft SPC.} 307 */ 308 static DECLCALLBACK(int) VerifyExecCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, 309 void *pvUser, PRTERRINFO pErrInfo) 310 { 311 VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser; 312 uint32_t cPaths = hCertPaths != NIL_RTCRX509CERTPATHS ? RTCrX509CertPathsGetPathCount(hCertPaths) : 0; 313 314 /* 315 * Dump all the paths. 316 */ 317 if (pState->cVerbose > 0) 318 { 319 for (uint32_t iPath = 0; iPath < cPaths; iPath++) 320 { 321 RTPrintf("---\n"); 322 RTCrX509CertPathsDumpOne(hCertPaths, iPath, pState->cVerbose, RTStrmDumpPrintfV, g_pStdOut); 323 *pErrInfo->pszMsg = '\0'; 324 } 325 RTPrintf("---\n"); 326 } 327 328 /* 329 * Test signing certificates normally doesn't have all the necessary 330 * features required below. So, treat them as special cases. 331 */ 332 if ( hCertPaths == NIL_RTCRX509CERTPATHS 333 && RTCrX509Name_Compare(&pCert->TbsCertificate.Issuer, &pCert->TbsCertificate.Subject) == 0) 334 { 335 RTMsgInfo("Test signed.\n"); 336 return VINF_SUCCESS; 337 } 338 339 if (hCertPaths == NIL_RTCRX509CERTPATHS) 340 RTMsgInfo("Signed by trusted certificate.\n"); 341 342 /* 343 * Standard code signing capabilites required. 344 */ 345 int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo); 346 if ( RT_SUCCESS(rc) 347 && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA)) 348 { 349 /* 350 * If kernel signing, a valid certificate path must be anchored by the 351 * microsoft kernel signing root certificate. The only alternative is 352 * test signing. 353 */ 354 if (pState->fKernel && hCertPaths != NIL_RTCRX509CERTPATHS) 355 { 356 uint32_t cFound = 0; 357 uint32_t cValid = 0; 358 for (uint32_t iPath = 0; iPath < cPaths; iPath++) 359 { 360 bool fTrusted; 361 PCRTCRX509NAME pSubject; 362 PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo; 363 int rcVerify; 364 rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo, 365 NULL, NULL /*pCertCtx*/, &rcVerify); 366 AssertRCBreak(rc); 367 368 if (RT_SUCCESS(rcVerify)) 369 { 370 Assert(fTrusted); 371 cValid++; 372 373 /* Search the kernel signing root store for a matching anchor. */ 374 RTCRSTORECERTSEARCH Search; 375 rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(pState->hKernelRootStore, pSubject, &Search); 376 AssertRCBreak(rc); 377 PCRTCRCERTCTX pCertCtx; 378 while ((pCertCtx = RTCrStoreCertSearchNext(pState->hKernelRootStore, &Search)) != NULL) 379 { 380 PCRTCRX509SUBJECTPUBLICKEYINFO pPubKeyInfo; 381 if (pCertCtx->pCert) 382 pPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo; 383 else if (pCertCtx->pTaInfo) 384 pPubKeyInfo = &pCertCtx->pTaInfo->PubKey; 385 else 386 pPubKeyInfo = NULL; 387 if (RTCrX509SubjectPublicKeyInfo_Compare(pPubKeyInfo, pPublicKeyInfo) == 0) 388 cFound++; 389 RTCrCertCtxRelease(pCertCtx); 390 } 391 392 int rc2 = RTCrStoreCertSearchDestroy(pState->hKernelRootStore, &Search); AssertRC(rc2); 393 } 394 } 395 if (RT_SUCCESS(rc) && cFound == 0) 396 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "Not valid kernel code signature."); 397 if (RT_SUCCESS(rc) && cValid != 2) 398 RTMsgWarning("%u valid paths, expected 2", cValid); 399 } 400 } 401 402 return rc; 403 } 404 405 406 /** @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA} */ 407 static DECLCALLBACK(int) VerifyExeCallback(RTLDRMOD hLdrMod, RTLDRSIGNATURETYPE enmSignature, 408 void const *pvSignature, size_t cbSignature, 409 PRTERRINFO pErrInfo, void *pvUser) 410 { 411 VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser; 412 RT_NOREF_PV(hLdrMod); RT_NOREF_PV(cbSignature); 413 414 switch (enmSignature) 415 { 416 case RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA: 417 { 418 PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pvSignature; 419 420 RTTIMESPEC ValidationTime; 421 RTTimeSpecSetSeconds(&ValidationTime, pState->uTimestamp); 422 423 /* 424 * Dump the signed data if so requested. 425 */ 426 if (pState->cVerbose) 427 RTAsn1Dump(&pContentInfo->SeqCore.Asn1Core, 0, 0, RTStrmDumpPrintfV, g_pStdOut); 428 429 430 /* 431 * Do the actual verification. Will have to modify this so it takes 432 * the authenticode policies into account. 433 */ 434 return RTCrPkcs7VerifySignedData(pContentInfo, 435 RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY 436 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT 437 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT, 438 pState->hAdditionalStore, pState->hRootStore, &ValidationTime, 439 VerifyExecCertVerifyCallback, pState, pErrInfo); 440 } 441 442 default: 443 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Unsupported signature type: %d", enmSignature); 444 } 445 } 446 447 /** Worker for HandleVerifyExe. */ 448 static RTEXITCODE HandleVerifyExeWorker(VERIFYEXESTATE *pState, const char *pszFilename, PRTERRINFOSTATIC pStaticErrInfo) 449 { 450 /* 451 * Open the executable image and verify it. 452 */ 453 RTLDRMOD hLdrMod; 454 int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, pState->enmLdrArch, &hLdrMod); 455 if (RT_FAILURE(rc)) 456 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszFilename, rc); 457 458 459 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pState->uTimestamp, sizeof(pState->uTimestamp)); 460 if (RT_SUCCESS(rc)) 461 { 462 rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo)); 463 if (RT_SUCCESS(rc)) 464 RTMsgInfo("'%s' is valid.\n", pszFilename); 465 else if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME) 466 { 467 RTTIMESPEC Now; 468 pState->uTimestamp = RTTimeSpecGetSeconds(RTTimeNow(&Now)); 469 rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo)); 470 if (RT_SUCCESS(rc)) 471 RTMsgInfo("'%s' is valid now, but not at link time.\n", pszFilename); 472 } 473 if (RT_FAILURE(rc)) 474 RTMsgError("RTLdrVerifySignature failed on '%s': %Rrc - %s\n", pszFilename, rc, pStaticErrInfo->szMsg); 475 } 476 else 477 RTMsgError("RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on '%s': %Rrc\n", pszFilename, rc); 478 479 int rc2 = RTLdrClose(hLdrMod); 480 if (RT_FAILURE(rc2)) 481 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc2); 482 if (RT_FAILURE(rc)) 483 return rc != VERR_LDRVI_NOT_SIGNED ? RTEXITCODE_FAILURE : RTEXITCODE_SKIPPED; 484 485 return RTEXITCODE_SUCCESS; 486 } 487 488 489 static RTEXITCODE HandleVerifyExe(int cArgs, char **papszArgs) 490 { 491 RTERRINFOSTATIC StaticErrInfo; 492 493 /* Note! This code does not try to clean up the crypto stores on failure. 494 This is intentional as the code is only expected to be used in a 495 one-command-per-process environment where we do exit() upon 496 returning from this function. */ 497 498 /* 499 * Parse arguments. 500 */ 501 static const RTGETOPTDEF s_aOptions[] = 502 { 503 { "--kernel", 'k', RTGETOPT_REQ_NOTHING }, 504 { "--root", 'r', RTGETOPT_REQ_STRING }, 505 { "--additional", 'a', RTGETOPT_REQ_STRING }, 506 { "--add", 'a', RTGETOPT_REQ_STRING }, 507 { "--type", 't', RTGETOPT_REQ_STRING }, 508 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 509 { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, 510 }; 511 512 VERIFYEXESTATE State = 513 { 514 NIL_RTCRSTORE, NIL_RTCRSTORE, NIL_RTCRSTORE, false, false, 515 VERIFYEXESTATE::kSignType_Windows, 0, RTLDRARCH_WHATEVER 516 }; 517 int rc = RTCrStoreCreateInMem(&State.hRootStore, 0); 518 if (RT_SUCCESS(rc)) 519 rc = RTCrStoreCreateInMem(&State.hKernelRootStore, 0); 520 if (RT_SUCCESS(rc)) 521 rc = RTCrStoreCreateInMem(&State.hAdditionalStore, 0); 522 if (RT_FAILURE(rc)) 523 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error creating in-memory certificate store: %Rrc", rc); 524 525 RTGETOPTSTATE GetState; 526 rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 527 AssertRCReturn(rc, RTEXITCODE_FAILURE); 528 RTGETOPTUNION ValueUnion; 529 int ch; 530 while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION) 531 { 532 switch (ch) 533 { 534 case 'r': case 'a': 535 rc = RTCrStoreCertAddFromFile(ch == 'r' ? State.hRootStore : State.hAdditionalStore, 536 RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, 537 ValueUnion.psz, RTErrInfoInitStatic(&StaticErrInfo)); 538 if (RT_FAILURE(rc)) 539 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading certificate '%s': %Rrc - %s", 540 ValueUnion.psz, rc, StaticErrInfo.szMsg); 541 if (RTErrInfoIsSet(&StaticErrInfo.Core)) 542 RTMsgWarning("Warnings loading certificate '%s': %s", ValueUnion.psz, StaticErrInfo.szMsg); 543 break; 544 545 case 't': 546 if (!strcmp(ValueUnion.psz, "win") || !strcmp(ValueUnion.psz, "windows")) 547 State.enmSignType = VERIFYEXESTATE::kSignType_Windows; 548 else if (!strcmp(ValueUnion.psz, "osx") || !strcmp(ValueUnion.psz, "apple")) 549 State.enmSignType = VERIFYEXESTATE::kSignType_OSX; 550 else 551 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown signing type: '%s'", ValueUnion.psz); 552 break; 553 554 case 'k': State.fKernel = true; break; 555 case 'v': State.cVerbose++; break; 556 case 'q': State.cVerbose = 0; break; 557 case 'V': return HandleVersion(cArgs, papszArgs); 558 case 'h': return HelpVerifyExe(g_pStdOut, RTSIGNTOOLHELP_FULL); 559 default: return RTGetOptPrintError(ch, &ValueUnion); 560 } 561 } 562 if (ch != VINF_GETOPT_NOT_OPTION) 563 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given."); 564 565 /* 566 * Populate the certificate stores according to the signing type. 567 */ 568 #ifdef VBOX 569 unsigned cSets = 0; 570 struct STSTORESET aSets[6]; 571 #endif 572 573 switch (State.enmSignType) 574 { 575 case VERIFYEXESTATE::kSignType_Windows: 576 #ifdef VBOX 577 aSets[cSets].hStore = State.hRootStore; 578 aSets[cSets].paTAs = g_aSUPTimestampTAs; 579 aSets[cSets].cTAs = g_cSUPTimestampTAs; 580 cSets++; 581 aSets[cSets].hStore = State.hRootStore; 582 aSets[cSets].paTAs = g_aSUPSpcRootTAs; 583 aSets[cSets].cTAs = g_cSUPSpcRootTAs; 584 cSets++; 585 aSets[cSets].hStore = State.hRootStore; 586 aSets[cSets].paTAs = g_aSUPNtKernelRootTAs; 587 aSets[cSets].cTAs = g_cSUPNtKernelRootTAs; 588 cSets++; 589 aSets[cSets].hStore = State.hKernelRootStore; 590 aSets[cSets].paTAs = g_aSUPNtKernelRootTAs; 591 aSets[cSets].cTAs = g_cSUPNtKernelRootTAs; 592 cSets++; 593 #endif 594 break; 595 596 case VERIFYEXESTATE::kSignType_OSX: 597 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Mac OS X executable signing is not implemented."); 598 } 599 600 #ifdef VBOX 601 for (unsigned i = 0; i < cSets; i++) 602 for (unsigned j = 0; j < aSets[i].cTAs; j++) 603 { 604 rc = RTCrStoreCertAddEncoded(aSets[i].hStore, RTCRCERTCTX_F_ENC_TAF_DER, aSets[i].paTAs[j].pch, 605 aSets[i].paTAs[j].cb, RTErrInfoInitStatic(&StaticErrInfo)); 606 if (RT_FAILURE(rc)) 607 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTCrStoreCertAddEncoded failed (%u/%u): %s", 608 i, j, StaticErrInfo.szMsg); 609 } 610 #endif 611 612 /* 613 * Do it. 614 */ 615 RTEXITCODE rcExit; 616 for (;;) 617 { 618 rcExit = HandleVerifyExeWorker(&State, ValueUnion.psz, &StaticErrInfo); 619 if (rcExit != RTEXITCODE_SUCCESS) 620 break; 621 622 /* 623 * Next file 624 */ 625 ch = RTGetOpt(&GetState, &ValueUnion); 626 if (ch == 0) 627 break; 628 if (ch != VINF_GETOPT_NOT_OPTION) 629 { 630 rcExit = RTGetOptPrintError(ch, &ValueUnion); 631 break; 632 } 633 } 634 635 /* 636 * Clean up. 637 */ 638 uint32_t cRefs; 639 cRefs = RTCrStoreRelease(State.hRootStore); Assert(cRefs == 0); 640 cRefs = RTCrStoreRelease(State.hKernelRootStore); Assert(cRefs == 0); 641 cRefs = RTCrStoreRelease(State.hAdditionalStore); Assert(cRefs == 0); 642 643 return rcExit; 644 } 645 646 #endif /* !IPRT_IN_BUILD_TOOL */ 647 //// 648 #ifndef IPRT_IN_BUILD_TOOL 649 650 /* 651 * The 'show-exe' command. 652 */ 653 static RTEXITCODE HelpShowExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel) 654 { 655 RT_NOREF_PV(enmLevel); 656 RTStrmPrintf(pStrm, 657 "show-exe [--verbose|-v] [--quiet|-q] <exe1> [exe2 [..]]\n"); 658 return RTEXITCODE_SUCCESS; 124 * Deletes the structure. 125 * 126 * @param pThis The structure to initialize. 127 */ 128 static void SignToolPkcs7_Delete(PSIGNTOOLPKCS7 pThis) 129 { 130 RTCrPkcs7ContentInfo_Delete(&pThis->ContentInfo); 131 pThis->pIndData = NULL; 132 pThis->pSignedData = NULL; 133 pThis->pIndData = NULL; 134 RTMemFree(pThis->pbBuf); 135 pThis->pbBuf = NULL; 136 pThis->cbBuf = 0; 137 } 138 139 140 /** 141 * Deletes the structure. 142 * 143 * @param pThis The structure to initialize. 144 */ 145 static void SignToolPkcs7Exe_Delete(PSIGNTOOLPKCS7EXE pThis) 146 { 147 if (pThis->hLdrMod != NIL_RTLDRMOD) 148 { 149 int rc2 = RTLdrClose(pThis->hLdrMod); 150 if (RT_FAILURE(rc2)) 151 RTMsgError("RTLdrClose failed: %Rrc\n", rc2); 152 pThis->hLdrMod = NIL_RTLDRMOD; 153 } 154 SignToolPkcs7_Delete(pThis); 659 155 } 660 156 … … 663 159 * Decodes the PKCS #7 blob pointed to by pThis->pbBuf. 664 160 * 665 * @returns IPRT status code .666 * @param pThis The show exe instance data.667 */ 668 static int HandleShowExeWorkerPkcs7Decode(PSHOWEXEPKCS7 pThis)161 * @returns IPRT status code (error message already shown on failure). 162 * @param pThis The PKCS\#7 signature to decode. 163 */ 164 static int SignToolPkcs7_Decode(PSIGNTOOLPKCS7 pThis) 669 165 { 670 166 RTERRINFOSTATIC ErrInfo; … … 724 220 725 221 /** 222 * Reads and decodes PKCS\#7 signature from the given executable. 223 * 224 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message 225 * on failure. 226 * @param pThis The structure to initialize. 227 * @param pszFilename The executable filename. 228 * @param cVerbosity The verbosity. 229 * @param enmLdrArch For FAT binaries. 230 */ 231 static RTEXITCODE SignToolPkcs7Exe_InitFromFile(PSIGNTOOLPKCS7EXE pThis, const char *pszFilename, 232 unsigned cVerbosity, RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER) 233 { 234 /* 235 * Init the return structure. 236 */ 237 RT_ZERO(*pThis); 238 pThis->hLdrMod = NIL_RTLDRMOD; 239 pThis->pszFilename = pszFilename; 240 241 /* 242 * Open the image and check if it's signed. 243 */ 244 int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, enmLdrArch, &pThis->hLdrMod); 245 if (RT_SUCCESS(rc)) 246 { 247 bool fIsSigned = false; 248 rc = RTLdrQueryProp(pThis->hLdrMod, RTLDRPROP_IS_SIGNED, &fIsSigned, sizeof(fIsSigned)); 249 if (RT_SUCCESS(rc) && fIsSigned) 250 { 251 /* 252 * Query the PKCS#7 data (assuming M$ style signing) and hand it to a worker. 253 */ 254 size_t cbActual = 0; 255 #ifdef DEBUG 256 size_t cbBuf = 64; 257 #else 258 size_t cbBuf = _512K; 259 #endif 260 void *pvBuf = RTMemAllocZ(cbBuf); 261 if (pvBuf) 262 { 263 rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbActual); 264 if (rc == VERR_BUFFER_OVERFLOW) 265 { 266 RTMemFree(pvBuf); 267 cbBuf = cbActual; 268 pvBuf = RTMemAllocZ(cbActual); 269 if (pvBuf) 270 rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, 271 pvBuf, cbBuf, &cbActual); 272 else 273 rc = VERR_NO_MEMORY; 274 } 275 } 276 else 277 rc = VERR_NO_MEMORY; 278 279 pThis->pbBuf = (uint8_t *)pvBuf; 280 pThis->cbBuf = cbActual; 281 if (RT_SUCCESS(rc)) 282 { 283 if (cVerbosity > 2) 284 RTPrintf("PKCS#7 signature: %u bytes\n", cbActual); 285 286 /* 287 * Decode it. 288 */ 289 rc = SignToolPkcs7_Decode(pThis); 290 if (RT_SUCCESS(rc)) 291 return RTEXITCODE_SUCCESS; 292 } 293 else 294 RTMsgError("RTLdrQueryPropEx/RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc\n", pszFilename, rc); 295 } 296 else if (RT_SUCCESS(rc)) 297 RTMsgInfo("'%s': not signed\n", pszFilename); 298 else 299 RTMsgError("RTLdrQueryProp/RTLDRPROP_IS_SIGNED failed on '%s': %Rrc\n", pszFilename, rc); 300 } 301 else 302 RTMsgError("Error opening executable image '%s': %Rrc", pszFilename, rc); 303 304 SignToolPkcs7Exe_Delete(pThis); 305 return RTEXITCODE_FAILURE; 306 307 } 308 309 310 /* 311 * The 'extract-exe-signer-cert' command. 312 */ 313 static RTEXITCODE HelpExtractExeSignerCert(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel) 314 { 315 RT_NOREF_PV(enmLevel); 316 RTStrmPrintf(pStrm, "extract-exe-signer-cert [--ber|--cer|--der] [--exe|-e] <exe> [--output|-o] <outfile.cer>\n"); 317 return RTEXITCODE_SUCCESS; 318 } 319 320 static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs) 321 { 322 /* 323 * Parse arguments. 324 */ 325 static const RTGETOPTDEF s_aOptions[] = 326 { 327 { "--ber", 'b', RTGETOPT_REQ_NOTHING }, 328 { "--cer", 'c', RTGETOPT_REQ_NOTHING }, 329 { "--der", 'd', RTGETOPT_REQ_NOTHING }, 330 { "--exe", 'e', RTGETOPT_REQ_STRING }, 331 { "--output", 'o', RTGETOPT_REQ_STRING }, 332 }; 333 334 const char *pszExe = NULL; 335 const char *pszOut = NULL; 336 RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER; 337 unsigned cVerbosity = 0; 338 uint32_t fCursorFlags = RTASN1CURSOR_FLAGS_DER; 339 340 RTGETOPTSTATE GetState; 341 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 342 AssertRCReturn(rc, RTEXITCODE_FAILURE); 343 RTGETOPTUNION ValueUnion; 344 int ch; 345 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 346 { 347 switch (ch) 348 { 349 case 'e': pszExe = ValueUnion.psz; break; 350 case 'o': pszOut = ValueUnion.psz; break; 351 case 'b': fCursorFlags = 0; break; 352 case 'c': fCursorFlags = RTASN1CURSOR_FLAGS_CER; break; 353 case 'd': fCursorFlags = RTASN1CURSOR_FLAGS_DER; break; 354 case 'V': return HandleVersion(cArgs, papszArgs); 355 case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL); 356 357 case VINF_GETOPT_NOT_OPTION: 358 if (!pszExe) 359 pszExe = ValueUnion.psz; 360 else if (!pszOut) 361 pszOut = ValueUnion.psz; 362 else 363 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz); 364 break; 365 366 default: 367 return RTGetOptPrintError(ch, &ValueUnion); 368 } 369 } 370 if (!pszExe) 371 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given."); 372 if (!pszOut) 373 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given."); 374 if (RTPathExists(pszOut)) 375 return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut); 376 377 /* 378 * Do it. 379 */ 380 /* Read & decode the PKCS#7 signature. */ 381 SIGNTOOLPKCS7EXE This; 382 RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&This, pszExe, cVerbosity, enmLdrArch); 383 if (rcExit == RTEXITCODE_SUCCESS) 384 { 385 /* Find the signing certificate (ASSUMING there's only one signer and that 386 the certificate used is shipped in the set of certificates). */ 387 rcExit = RTEXITCODE_FAILURE; 388 if (This.pSignedData->SignerInfos.cItems == 1) 389 { 390 PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &This.pSignedData->SignerInfos.papItems[0]->IssuerAndSerialNumber; 391 PCRTCRX509CERTIFICATE pCert; 392 pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&This.pSignedData->Certificates, 393 &pISN->Name, &pISN->SerialNumber); 394 if (pCert) 395 { 396 /* 397 * Write it out. 398 */ 399 RTFILE hFile; 400 rc = RTFileOpen(&hFile, pszOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE); 401 if (RT_SUCCESS(rc)) 402 { 403 uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb; 404 rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr, 405 cbCert, NULL); 406 if (RT_SUCCESS(rc)) 407 { 408 rc = RTFileClose(hFile); 409 if (RT_SUCCESS(rc)) 410 { 411 hFile = NIL_RTFILE; 412 rcExit = RTEXITCODE_SUCCESS; 413 RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszOut); 414 } 415 else 416 RTMsgError("RTFileClose failed: %Rrc", rc); 417 } 418 else 419 RTMsgError("RTFileWrite failed: %Rrc", rc); 420 RTFileClose(hFile); 421 } 422 else 423 RTMsgError("Error opening '%s' for writing: %Rrc", pszOut, rc); 424 } 425 else 426 RTMsgError("Certificate not found."); 427 } 428 else 429 RTMsgError("SignerInfo count: %u", This.pSignedData->SignerInfos.cItems); 430 431 432 /* Delete the signature data. */ 433 SignToolPkcs7Exe_Delete(&This); 434 } 435 return rcExit; 436 } 437 438 439 /* 440 * The 'add-nested-exe-signature' command. 441 */ 442 static RTEXITCODE HelpAddNestedExeSignature(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel) 443 { 444 RT_NOREF_PV(enmLevel); 445 RTStrmPrintf(pStrm, "add-nested-exe-signature [-v|--verbose] <destination-exe> <source-exe>\n"); 446 return RTEXITCODE_SUCCESS; 447 } 448 449 450 static RTEXITCODE HandleAddNestedExeSignature(int cArgs, char **papszArgs) 451 { 452 /* 453 * Parse arguments. 454 */ 455 static const RTGETOPTDEF s_aOptions[] = 456 { 457 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 458 }; 459 460 const char *pszDst = NULL; 461 const char *pszSrc = NULL; 462 unsigned cVerbosity = 0; 463 464 RTGETOPTSTATE GetState; 465 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 466 AssertRCReturn(rc, RTEXITCODE_FAILURE); 467 RTGETOPTUNION ValueUnion; 468 int ch; 469 while ((ch = RTGetOpt(&GetState, &ValueUnion))) 470 { 471 switch (ch) 472 { 473 case 'v': cVerbosity++; break; 474 case 'V': return HandleVersion(cArgs, papszArgs); 475 case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL); 476 477 case VINF_GETOPT_NOT_OPTION: 478 if (!pszDst) 479 pszDst = ValueUnion.psz; 480 else if (!pszSrc) 481 pszSrc = ValueUnion.psz; 482 else 483 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz); 484 break; 485 486 default: 487 return RTGetOptPrintError(ch, &ValueUnion); 488 } 489 } 490 if (!pszDst) 491 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No destination excutable given."); 492 if (!pszSrc) 493 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No source executable file given."); 494 495 /* 496 * Do it. 497 */ 498 /* Read & decode the source PKCS#7 signature. */ 499 SIGNTOOLPKCS7EXE Src; 500 RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&Src, pszSrc, cVerbosity); 501 if (rcExit == RTEXITCODE_SUCCESS) 502 { 503 /* Ditto for the destination PKCS#7 signature. */ 504 SIGNTOOLPKCS7EXE Dst; 505 RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&Dst, pszSrc, cVerbosity); 506 if (rcExit == RTEXITCODE_SUCCESS) 507 { 508 /* Add the source to the destination as a nested signature. */ 509 //Src.pSignedData->SignerInfos.paItems 510 511 512 SignToolPkcs7Exe_Delete(&Dst); 513 } 514 SignToolPkcs7Exe_Delete(&Src); 515 } 516 517 return rcExit; 518 } 519 520 #ifndef IPRT_IN_BUILD_TOOL 521 522 /* 523 * The 'verify-exe' command. 524 */ 525 static RTEXITCODE HelpVerifyExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel) 526 { 527 RT_NOREF_PV(enmLevel); 528 RTStrmPrintf(pStrm, 529 "verify-exe [--verbose|--quiet] [--kernel] [--root <root-cert.der>] [--additional <supp-cert.der>]\n" 530 " [--type <win|osx>] <exe1> [exe2 [..]]\n"); 531 return RTEXITCODE_SUCCESS; 532 } 533 534 typedef struct VERIFYEXESTATE 535 { 536 RTCRSTORE hRootStore; 537 RTCRSTORE hKernelRootStore; 538 RTCRSTORE hAdditionalStore; 539 bool fKernel; 540 int cVerbose; 541 enum { kSignType_Windows, kSignType_OSX } enmSignType; 542 uint64_t uTimestamp; 543 RTLDRARCH enmLdrArch; 544 } VERIFYEXESTATE; 545 546 # ifdef VBOX 547 /** Certificate store load set. 548 * Declared outside HandleVerifyExe because of braindead gcc visibility crap. */ 549 struct STSTORESET 550 { 551 RTCRSTORE hStore; 552 PCSUPTAENTRY paTAs; 553 unsigned cTAs; 554 }; 555 # endif 556 557 /** 558 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, 559 * Standard code signing. Use this for Microsoft SPC.} 560 */ 561 static DECLCALLBACK(int) VerifyExecCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags, 562 void *pvUser, PRTERRINFO pErrInfo) 563 { 564 VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser; 565 uint32_t cPaths = hCertPaths != NIL_RTCRX509CERTPATHS ? RTCrX509CertPathsGetPathCount(hCertPaths) : 0; 566 567 /* 568 * Dump all the paths. 569 */ 570 if (pState->cVerbose > 0) 571 { 572 for (uint32_t iPath = 0; iPath < cPaths; iPath++) 573 { 574 RTPrintf("---\n"); 575 RTCrX509CertPathsDumpOne(hCertPaths, iPath, pState->cVerbose, RTStrmDumpPrintfV, g_pStdOut); 576 *pErrInfo->pszMsg = '\0'; 577 } 578 RTPrintf("---\n"); 579 } 580 581 /* 582 * Test signing certificates normally doesn't have all the necessary 583 * features required below. So, treat them as special cases. 584 */ 585 if ( hCertPaths == NIL_RTCRX509CERTPATHS 586 && RTCrX509Name_Compare(&pCert->TbsCertificate.Issuer, &pCert->TbsCertificate.Subject) == 0) 587 { 588 RTMsgInfo("Test signed.\n"); 589 return VINF_SUCCESS; 590 } 591 592 if (hCertPaths == NIL_RTCRX509CERTPATHS) 593 RTMsgInfo("Signed by trusted certificate.\n"); 594 595 /* 596 * Standard code signing capabilites required. 597 */ 598 int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo); 599 if ( RT_SUCCESS(rc) 600 && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA)) 601 { 602 /* 603 * If kernel signing, a valid certificate path must be anchored by the 604 * microsoft kernel signing root certificate. The only alternative is 605 * test signing. 606 */ 607 if (pState->fKernel && hCertPaths != NIL_RTCRX509CERTPATHS) 608 { 609 uint32_t cFound = 0; 610 uint32_t cValid = 0; 611 for (uint32_t iPath = 0; iPath < cPaths; iPath++) 612 { 613 bool fTrusted; 614 PCRTCRX509NAME pSubject; 615 PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo; 616 int rcVerify; 617 rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo, 618 NULL, NULL /*pCertCtx*/, &rcVerify); 619 AssertRCBreak(rc); 620 621 if (RT_SUCCESS(rcVerify)) 622 { 623 Assert(fTrusted); 624 cValid++; 625 626 /* Search the kernel signing root store for a matching anchor. */ 627 RTCRSTORECERTSEARCH Search; 628 rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(pState->hKernelRootStore, pSubject, &Search); 629 AssertRCBreak(rc); 630 PCRTCRCERTCTX pCertCtx; 631 while ((pCertCtx = RTCrStoreCertSearchNext(pState->hKernelRootStore, &Search)) != NULL) 632 { 633 PCRTCRX509SUBJECTPUBLICKEYINFO pPubKeyInfo; 634 if (pCertCtx->pCert) 635 pPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo; 636 else if (pCertCtx->pTaInfo) 637 pPubKeyInfo = &pCertCtx->pTaInfo->PubKey; 638 else 639 pPubKeyInfo = NULL; 640 if (RTCrX509SubjectPublicKeyInfo_Compare(pPubKeyInfo, pPublicKeyInfo) == 0) 641 cFound++; 642 RTCrCertCtxRelease(pCertCtx); 643 } 644 645 int rc2 = RTCrStoreCertSearchDestroy(pState->hKernelRootStore, &Search); AssertRC(rc2); 646 } 647 } 648 if (RT_SUCCESS(rc) && cFound == 0) 649 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "Not valid kernel code signature."); 650 if (RT_SUCCESS(rc) && cValid != 2) 651 RTMsgWarning("%u valid paths, expected 2", cValid); 652 } 653 } 654 655 return rc; 656 } 657 658 659 /** @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA} */ 660 static DECLCALLBACK(int) VerifyExeCallback(RTLDRMOD hLdrMod, RTLDRSIGNATURETYPE enmSignature, 661 void const *pvSignature, size_t cbSignature, 662 PRTERRINFO pErrInfo, void *pvUser) 663 { 664 VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser; 665 RT_NOREF_PV(hLdrMod); RT_NOREF_PV(cbSignature); 666 667 switch (enmSignature) 668 { 669 case RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA: 670 { 671 PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pvSignature; 672 673 RTTIMESPEC ValidationTime; 674 RTTimeSpecSetSeconds(&ValidationTime, pState->uTimestamp); 675 676 /* 677 * Dump the signed data if so requested. 678 */ 679 if (pState->cVerbose) 680 RTAsn1Dump(&pContentInfo->SeqCore.Asn1Core, 0, 0, RTStrmDumpPrintfV, g_pStdOut); 681 682 683 /* 684 * Do the actual verification. Will have to modify this so it takes 685 * the authenticode policies into account. 686 */ 687 return RTCrPkcs7VerifySignedData(pContentInfo, 688 RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY 689 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT 690 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT, 691 pState->hAdditionalStore, pState->hRootStore, &ValidationTime, 692 VerifyExecCertVerifyCallback, pState, pErrInfo); 693 } 694 695 default: 696 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Unsupported signature type: %d", enmSignature); 697 } 698 } 699 700 /** Worker for HandleVerifyExe. */ 701 static RTEXITCODE HandleVerifyExeWorker(VERIFYEXESTATE *pState, const char *pszFilename, PRTERRINFOSTATIC pStaticErrInfo) 702 { 703 /* 704 * Open the executable image and verify it. 705 */ 706 RTLDRMOD hLdrMod; 707 int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, pState->enmLdrArch, &hLdrMod); 708 if (RT_FAILURE(rc)) 709 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszFilename, rc); 710 711 712 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &pState->uTimestamp, sizeof(pState->uTimestamp)); 713 if (RT_SUCCESS(rc)) 714 { 715 rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo)); 716 if (RT_SUCCESS(rc)) 717 RTMsgInfo("'%s' is valid.\n", pszFilename); 718 else if (rc == VERR_CR_X509_CPV_NOT_VALID_AT_TIME) 719 { 720 RTTIMESPEC Now; 721 pState->uTimestamp = RTTimeSpecGetSeconds(RTTimeNow(&Now)); 722 rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo)); 723 if (RT_SUCCESS(rc)) 724 RTMsgInfo("'%s' is valid now, but not at link time.\n", pszFilename); 725 } 726 if (RT_FAILURE(rc)) 727 RTMsgError("RTLdrVerifySignature failed on '%s': %Rrc - %s\n", pszFilename, rc, pStaticErrInfo->szMsg); 728 } 729 else 730 RTMsgError("RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on '%s': %Rrc\n", pszFilename, rc); 731 732 int rc2 = RTLdrClose(hLdrMod); 733 if (RT_FAILURE(rc2)) 734 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc2); 735 if (RT_FAILURE(rc)) 736 return rc != VERR_LDRVI_NOT_SIGNED ? RTEXITCODE_FAILURE : RTEXITCODE_SKIPPED; 737 738 return RTEXITCODE_SUCCESS; 739 } 740 741 742 static RTEXITCODE HandleVerifyExe(int cArgs, char **papszArgs) 743 { 744 RTERRINFOSTATIC StaticErrInfo; 745 746 /* Note! This code does not try to clean up the crypto stores on failure. 747 This is intentional as the code is only expected to be used in a 748 one-command-per-process environment where we do exit() upon 749 returning from this function. */ 750 751 /* 752 * Parse arguments. 753 */ 754 static const RTGETOPTDEF s_aOptions[] = 755 { 756 { "--kernel", 'k', RTGETOPT_REQ_NOTHING }, 757 { "--root", 'r', RTGETOPT_REQ_STRING }, 758 { "--additional", 'a', RTGETOPT_REQ_STRING }, 759 { "--add", 'a', RTGETOPT_REQ_STRING }, 760 { "--type", 't', RTGETOPT_REQ_STRING }, 761 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 762 { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, 763 }; 764 765 VERIFYEXESTATE State = 766 { 767 NIL_RTCRSTORE, NIL_RTCRSTORE, NIL_RTCRSTORE, false, false, 768 VERIFYEXESTATE::kSignType_Windows, 0, RTLDRARCH_WHATEVER 769 }; 770 int rc = RTCrStoreCreateInMem(&State.hRootStore, 0); 771 if (RT_SUCCESS(rc)) 772 rc = RTCrStoreCreateInMem(&State.hKernelRootStore, 0); 773 if (RT_SUCCESS(rc)) 774 rc = RTCrStoreCreateInMem(&State.hAdditionalStore, 0); 775 if (RT_FAILURE(rc)) 776 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error creating in-memory certificate store: %Rrc", rc); 777 778 RTGETOPTSTATE GetState; 779 rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 780 AssertRCReturn(rc, RTEXITCODE_FAILURE); 781 RTGETOPTUNION ValueUnion; 782 int ch; 783 while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION) 784 { 785 switch (ch) 786 { 787 case 'r': case 'a': 788 rc = RTCrStoreCertAddFromFile(ch == 'r' ? State.hRootStore : State.hAdditionalStore, 789 RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, 790 ValueUnion.psz, RTErrInfoInitStatic(&StaticErrInfo)); 791 if (RT_FAILURE(rc)) 792 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error loading certificate '%s': %Rrc - %s", 793 ValueUnion.psz, rc, StaticErrInfo.szMsg); 794 if (RTErrInfoIsSet(&StaticErrInfo.Core)) 795 RTMsgWarning("Warnings loading certificate '%s': %s", ValueUnion.psz, StaticErrInfo.szMsg); 796 break; 797 798 case 't': 799 if (!strcmp(ValueUnion.psz, "win") || !strcmp(ValueUnion.psz, "windows")) 800 State.enmSignType = VERIFYEXESTATE::kSignType_Windows; 801 else if (!strcmp(ValueUnion.psz, "osx") || !strcmp(ValueUnion.psz, "apple")) 802 State.enmSignType = VERIFYEXESTATE::kSignType_OSX; 803 else 804 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown signing type: '%s'", ValueUnion.psz); 805 break; 806 807 case 'k': State.fKernel = true; break; 808 case 'v': State.cVerbose++; break; 809 case 'q': State.cVerbose = 0; break; 810 case 'V': return HandleVersion(cArgs, papszArgs); 811 case 'h': return HelpVerifyExe(g_pStdOut, RTSIGNTOOLHELP_FULL); 812 default: return RTGetOptPrintError(ch, &ValueUnion); 813 } 814 } 815 if (ch != VINF_GETOPT_NOT_OPTION) 816 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given."); 817 818 /* 819 * Populate the certificate stores according to the signing type. 820 */ 821 #ifdef VBOX 822 unsigned cSets = 0; 823 struct STSTORESET aSets[6]; 824 #endif 825 826 switch (State.enmSignType) 827 { 828 case VERIFYEXESTATE::kSignType_Windows: 829 #ifdef VBOX 830 aSets[cSets].hStore = State.hRootStore; 831 aSets[cSets].paTAs = g_aSUPTimestampTAs; 832 aSets[cSets].cTAs = g_cSUPTimestampTAs; 833 cSets++; 834 aSets[cSets].hStore = State.hRootStore; 835 aSets[cSets].paTAs = g_aSUPSpcRootTAs; 836 aSets[cSets].cTAs = g_cSUPSpcRootTAs; 837 cSets++; 838 aSets[cSets].hStore = State.hRootStore; 839 aSets[cSets].paTAs = g_aSUPNtKernelRootTAs; 840 aSets[cSets].cTAs = g_cSUPNtKernelRootTAs; 841 cSets++; 842 aSets[cSets].hStore = State.hKernelRootStore; 843 aSets[cSets].paTAs = g_aSUPNtKernelRootTAs; 844 aSets[cSets].cTAs = g_cSUPNtKernelRootTAs; 845 cSets++; 846 #endif 847 break; 848 849 case VERIFYEXESTATE::kSignType_OSX: 850 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Mac OS X executable signing is not implemented."); 851 } 852 853 #ifdef VBOX 854 for (unsigned i = 0; i < cSets; i++) 855 for (unsigned j = 0; j < aSets[i].cTAs; j++) 856 { 857 rc = RTCrStoreCertAddEncoded(aSets[i].hStore, RTCRCERTCTX_F_ENC_TAF_DER, aSets[i].paTAs[j].pch, 858 aSets[i].paTAs[j].cb, RTErrInfoInitStatic(&StaticErrInfo)); 859 if (RT_FAILURE(rc)) 860 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTCrStoreCertAddEncoded failed (%u/%u): %s", 861 i, j, StaticErrInfo.szMsg); 862 } 863 #endif 864 865 /* 866 * Do it. 867 */ 868 RTEXITCODE rcExit; 869 for (;;) 870 { 871 rcExit = HandleVerifyExeWorker(&State, ValueUnion.psz, &StaticErrInfo); 872 if (rcExit != RTEXITCODE_SUCCESS) 873 break; 874 875 /* 876 * Next file 877 */ 878 ch = RTGetOpt(&GetState, &ValueUnion); 879 if (ch == 0) 880 break; 881 if (ch != VINF_GETOPT_NOT_OPTION) 882 { 883 rcExit = RTGetOptPrintError(ch, &ValueUnion); 884 break; 885 } 886 } 887 888 /* 889 * Clean up. 890 */ 891 uint32_t cRefs; 892 cRefs = RTCrStoreRelease(State.hRootStore); Assert(cRefs == 0); 893 cRefs = RTCrStoreRelease(State.hKernelRootStore); Assert(cRefs == 0); 894 cRefs = RTCrStoreRelease(State.hAdditionalStore); Assert(cRefs == 0); 895 896 return rcExit; 897 } 898 899 #endif /* !IPRT_IN_BUILD_TOOL */ 900 #ifndef IPRT_IN_BUILD_TOOL 901 902 /* 903 * The 'show-exe' command. 904 */ 905 static RTEXITCODE HelpShowExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel) 906 { 907 RT_NOREF_PV(enmLevel); 908 RTStrmPrintf(pStrm, 909 "show-exe [--verbose|-v] [--quiet|-q] <exe1> [exe2 [..]]\n"); 910 return RTEXITCODE_SUCCESS; 911 } 912 913 914 /** 915 * Decodes the PKCS #7 blob pointed to by pThis->pbBuf. 916 * 917 * @returns IPRT status code. 918 * @param pThis The show exe instance data. 919 */ 920 static int HandleShowExeWorkerPkcs7Decode(PSHOWEXEPKCS7 pThis) 921 { 922 RTERRINFOSTATIC ErrInfo; 923 RTASN1CURSORPRIMARY PrimaryCursor; 924 RTAsn1CursorInitPrimary(&PrimaryCursor, pThis->pbBuf, (uint32_t)pThis->cbBuf, RTErrInfoInitStatic(&ErrInfo), 925 &g_RTAsn1DefaultAllocator, 0, "WinCert"); 926 927 int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pThis->ContentInfo, "CI"); 928 if (RT_SUCCESS(rc)) 929 { 930 if (RTCrPkcs7ContentInfo_IsSignedData(&pThis->ContentInfo)) 931 { 932 pThis->pSignedData = pThis->ContentInfo.u.pSignedData; 933 934 /* 935 * Decode the authenticode bits. 936 */ 937 if (!strcmp(pThis->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID)) 938 { 939 pThis->pIndData = pThis->pSignedData->ContentInfo.u.pIndirectDataContent; 940 Assert(pThis->pIndData); 941 942 /* 943 * Check that things add up. 944 */ 945 rc = RTCrPkcs7SignedData_CheckSanity(pThis->pSignedData, 946 RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE 947 | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH 948 | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT, 949 RTErrInfoInitStatic(&ErrInfo), "SD"); 950 if (RT_FAILURE(rc)) 951 RTMsgError("PKCS#7 sanity check failed for '%s': %Rrc - %s\n", pThis->pszFilename, rc, ErrInfo.szMsg); 952 if (RT_SUCCESS(rc)) 953 { 954 rc = RTCrSpcIndirectDataContent_CheckSanityEx(pThis->pIndData, 955 pThis->pSignedData, 956 RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH, 957 RTErrInfoInitStatic(&ErrInfo)); 958 if (RT_FAILURE(rc)) 959 RTMsgError("SPC indirect data content sanity check failed for '%s': %Rrc - %s\n", 960 pThis->pszFilename, rc, ErrInfo.szMsg); 961 } 962 } 963 else 964 RTMsgError("Unexpected the signed content in '%s': %s (expected %s)", pThis->pszFilename, 965 pThis->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID); 966 } 967 else 968 RTMsgError("PKCS#7 content is inside '%s' is not 'signedData': %s\n", 969 pThis->pszFilename, pThis->ContentInfo.ContentType.szObjId); 970 } 971 else 972 RTMsgError("RTCrPkcs7ContentInfo_DecodeAsn1 failed on '%s': %Rrc - %s\n", pThis->pszFilename, rc, ErrInfo.szMsg); 973 return rc; 974 } 975 976 977 /** 726 978 * Display an object ID. 727 979 * … … 802 1054 else 803 1055 RTPrintf("%s ObjId[%u]: ", pThis->szPrefix, i); 804 HandleShowExeWorkerDisplayObjIdSimple(pThis, &pAttr->uValues.pObjIds->paItems[i], "\n");1056 HandleShowExeWorkerDisplayObjIdSimple(pThis, pAttr->uValues.pObjIds->papItems[i], "\n"); 805 1057 } 806 1058 break; … … 812 1064 for (unsigned i = 0; i < pAttr->uValues.pObjIdSeqs->cItems; i++) 813 1065 { 814 uint32_t const cObjIds = pAttr->uValues.pObjIdSeqs->pa Items[i].cItems;1066 uint32_t const cObjIds = pAttr->uValues.pObjIdSeqs->papItems[i]->cItems; 815 1067 for (unsigned j = 0; j < cObjIds; j++) 816 1068 { … … 821 1073 if (cObjIds != 1) 822 1074 RTPrintf(" ObjId[%u]: ", j); 823 HandleShowExeWorkerDisplayObjIdSimple(pThis, &pAttr->uValues.pObjIdSeqs->paItems[i].paItems[i], "\n");1075 HandleShowExeWorkerDisplayObjIdSimple(pThis, pAttr->uValues.pObjIdSeqs->papItems[i]->papItems[i], "\n"); 824 1076 } 825 1077 } … … 832 1084 for (unsigned i = 0; i < pAttr->uValues.pOctetStrings->cItems; i++) 833 1085 { 834 PCRTASN1OCTETSTRING pOctetString = &pAttr->uValues.pOctetStrings->paItems[i];1086 PCRTASN1OCTETSTRING pOctetString = pAttr->uValues.pOctetStrings->papItems[i]; 835 1087 uint32_t cbContent = pOctetString->Asn1Core.cb; 836 1088 if (cbContent > 0 && (cbContent <= 128 || pThis->cVerbosity >= 2)) … … 879 1131 offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, " "); 880 1132 // offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "NestedSig: ", i); 881 PCRTCRPKCS7CONTENTINFO pContentInfo = &pAttr->uValues.pContentInfos->paItems[i];1133 PCRTCRPKCS7CONTENTINFO pContentInfo = pAttr->uValues.pContentInfos->papItems[i]; 882 1134 int rc2; 883 1135 if (RTCrPkcs7ContentInfo_IsSignedData(pContentInfo)) … … 960 1212 "MonikerAttrib[%u]: ", i); 961 1213 962 switch (pData->pa Items[i].enmType)1214 switch (pData->papItems[i]->enmType) 963 1215 { 964 1216 case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2: 965 1217 case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1: 966 1218 { 967 PCRTCRSPCSERIALIZEDPAGEHASHES pPgHashes = pData->pa Items[i].u.pPageHashes;968 uint32_t const cbHash = pData->pa Items[i].enmType1219 PCRTCRSPCSERIALIZEDPAGEHASHES pPgHashes = pData->papItems[i]->u.pPageHashes; 1220 uint32_t const cbHash = pData->papItems[i]->enmType 969 1221 == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 970 1222 ? 160/8 /*SHA-1*/ : 256/8 /*SHA-256*/; … … 972 1224 973 1225 RTPrintf("%sPage Hashes version %u - %u pages (%u bytes total)\n", pThis->szPrefix, 974 pData->pa Items[i].enmType1226 pData->papItems[i]->enmType 975 1227 == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 ? 1 : 2, 976 1228 cPages, pPgHashes->RawData.Asn1Core.cb); … … 1006 1258 1007 1259 case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN: 1008 HandleShowExeWorkerDisplayObjIdSimple(pThis, &pData->pa Items[i].Type, "\n");1260 HandleShowExeWorkerDisplayObjIdSimple(pThis, &pData->papItems[i]->Type, "\n"); 1009 1261 break; 1010 1262 case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT: … … 1012 1264 break; 1013 1265 default: 1014 RTPrintf("%senmType=%d!\n", pThis->szPrefix, pData->pa Items[i].enmType);1266 RTPrintf("%senmType=%d!\n", pThis->szPrefix, pData->papItems[i]->enmType); 1015 1267 break; 1016 1268 } … … 1099 1351 for (unsigned i = 0; i < pSignedData->DigestAlgorithms.cItems; i++) 1100 1352 { 1101 PCRTCRX509ALGORITHMIDENTIFIER pAlgoId = &pSignedData->DigestAlgorithms.paItems[i];1353 PCRTCRX509ALGORITHMIDENTIFIER pAlgoId = pSignedData->DigestAlgorithms.papItems[i]; 1102 1354 const char *pszDigestType = RTCrDigestTypeToName(RTCrX509AlgorithmIdentifier_QueryDigestType(pAlgoId)); 1103 1355 if (!pszDigestType) … … 1121 1373 } 1122 1374 else 1123 RTPrintf("%s ContentType: %s\n", pThis->szPrefix, pSignedData->ContentInfo.ContentType.szObjId);1375 HandleShowExeWorkerDisplayObjId(pThis, &pSignedData->ContentInfo.ContentType, " ContentType: ", " - not implemented.\n"); 1124 1376 1125 1377 /* 1126 1378 * Display certificates (Certificates). 1127 1379 */ 1380 if (pSignedData->Certificates.cItems > 0) 1381 RTPrintf("%s Certificates: %u\n", pThis->szPrefix, pSignedData->Certificates.cItems); 1382 /** @todo display certificates. */ 1383 1384 if (pSignedData->Crls.cb > 0) 1385 RTPrintf("%s CRLs: %u bytes\n", pThis->szPrefix, pSignedData->Crls.cb); 1128 1386 1129 1387 /* … … 1134 1392 for (unsigned i = 0; i < cSigInfos; i++) 1135 1393 { 1136 PRTCRPKCS7SIGNERINFO pSigInfo = &pSignedData->SignerInfos.paItems[i];1394 PRTCRPKCS7SIGNERINFO pSigInfo = pSignedData->SignerInfos.papItems[i]; 1137 1395 size_t offPrefix2 = offPrefix; 1138 1396 if (cSigInfos != 1) … … 1170 1428 for (unsigned j = 0; j < pSigInfo->AuthenticatedAttributes.cItems; j++) 1171 1429 { 1172 PRTCRPKCS7ATTRIBUTE pAttr = &pSigInfo->AuthenticatedAttributes.paItems[j];1430 PRTCRPKCS7ATTRIBUTE pAttr = pSigInfo->AuthenticatedAttributes.papItems[j]; 1173 1431 size_t offPrefix3 = offPrefix2 + RTStrPrintf(&pThis->szPrefix[offPrefix2], sizeof(pThis->szPrefix) - offPrefix2, 1174 1432 " AuthAttrib[%u]: ", j); … … 1186 1444 for (unsigned j = 0; j < pSigInfo->UnauthenticatedAttributes.cItems; j++) 1187 1445 { 1188 PRTCRPKCS7ATTRIBUTE pAttr = &pSigInfo->UnauthenticatedAttributes.paItems[j];1446 PRTCRPKCS7ATTRIBUTE pAttr = pSigInfo->UnauthenticatedAttributes.papItems[j]; 1189 1447 size_t offPrefix3 = offPrefix2 + RTStrPrintf(&pThis->szPrefix[offPrefix2], sizeof(pThis->szPrefix) - offPrefix2, 1190 1448 " UnauthAttrib[%u]: ", j); … … 1212 1470 static RTEXITCODE HandleShowExeWorker(const char *pszFilename, unsigned cVerbosity, RTLDRARCH enmLdrArch) 1213 1471 { 1214 /* 1215 * Open the image and check if it's signed. 1216 */ 1217 RTLDRMOD hLdrMod; 1218 int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod); 1219 if (RT_FAILURE(rc)) 1220 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszFilename, rc); 1221 1222 bool fIsSigned = false; 1223 rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_IS_SIGNED, &fIsSigned, sizeof(fIsSigned)); 1224 if (RT_SUCCESS(rc) && fIsSigned) 1225 { 1226 /* 1227 * Query the PKCS#7 data (assuming M$ style signing) and hand it to a worker. 1228 */ 1229 size_t cbActual = 0; 1230 size_t cbBuf = _64K; 1231 void *pvBuf = RTMemAllocZ(cbBuf); 1232 if (pvBuf) 1233 { 1234 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbActual); 1235 if (rc == VERR_BUFFER_OVERFLOW) 1236 { 1237 RTMemFree(pvBuf); 1238 cbBuf = cbActual; 1239 pvBuf = RTMemAllocZ(cbActual); 1240 if (pvBuf) 1241 rc = RTLdrQueryPropEx(hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbActual); 1242 else 1243 rc = VERR_NO_MEMORY; 1244 } 1245 } 1246 else 1247 rc = VERR_NO_MEMORY; 1248 if (RT_SUCCESS(rc)) 1249 { 1250 SHOWEXEPKCS7 This; 1251 RT_ZERO(This); 1252 This.pbBuf = (uint8_t const *)pvBuf; 1253 This.cbBuf = cbActual; 1254 This.cVerbosity = cVerbosity; 1255 This.pszFilename = pszFilename; 1256 This.hLdrMod = hLdrMod; 1257 rc = HandleShowExeWorkerPkcs7Decode(&This); 1258 if (RT_SUCCESS(rc)) 1259 rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0); 1260 RTCrPkcs7ContentInfo_Delete(&This.ContentInfo); 1261 } 1262 else 1263 RTMsgError("RTLdrQueryPropEx/RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc\n", pszFilename, rc); 1264 RTMemFree(pvBuf); 1265 } 1266 else if (RT_SUCCESS(rc)) 1267 RTMsgInfo("'%s': not signed\n", pszFilename); 1268 else 1269 RTMsgError("RTLdrQueryProp/RTLDRPROP_IS_SIGNED failed on '%s': %Rrc\n", pszFilename, rc); 1270 1271 int rc2 = RTLdrClose(hLdrMod); 1272 if (RT_FAILURE(rc2)) 1273 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc2); 1274 if (RT_FAILURE(rc)) 1275 return rc != VERR_LDRVI_NOT_SIGNED ? RTEXITCODE_FAILURE : RTEXITCODE_SKIPPED; 1276 1277 return RTEXITCODE_SUCCESS; 1472 SHOWEXEPKCS7 This; 1473 RT_ZERO(This); 1474 This.cVerbosity = cVerbosity; 1475 1476 RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&This, pszFilename, cVerbosity, enmLdrArch); 1477 if (rcExit == RTEXITCODE_SUCCESS) 1478 { 1479 int rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0); 1480 if (RT_FAILURE(rc)) 1481 rcExit = RTEXITCODE_FAILURE; 1482 SignToolPkcs7Exe_Delete(&This); 1483 } 1484 1485 return rcExit; 1278 1486 } 1279 1487 … … 1599 1807 { "extract-exe-signer-cert", HandleExtractExeSignerCert, HelpExtractExeSignerCert }, 1600 1808 #ifndef IPRT_IN_BUILD_TOOL 1809 { "add-nested-exe-signature", HandleAddNestedExeSignature, HelpAddNestedExeSignature }, 1601 1810 { "verify-exe", HandleVerifyExe, HelpVerifyExe }, 1602 1811 { "show-exe", HandleShowExe, HelpShowExe },
Note:
See TracChangeset
for help on using the changeset viewer.