VirtualBox

Changeset 64883 in vbox for trunk/src/VBox/Runtime/tools


Ignore:
Timestamp:
Dec 15, 2016 3:26:20 PM (8 years ago)
Author:
vboxsync
Message:

IPRT/ASN.1: Refactored array handling (SET OF, SEQUENCE OF) to use a pointer array instead of an object instance array. The old approach would move objects around in memory after they'd be initialized/decoded, making certain core optimziations involving pointers to object members impossible, as well as causing potentially causing trouble when modifying structures that takes down pointers after decoding. Fixed validation bug in rtCrX509Name_CheckSanityExtra where it didn't check that the RDNs had subitems but instead checked the parent twice (slight risk).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/tools/RTSignTool.cpp

    r64877 r64883  
    6363
    6464
    65 typedef struct SHOWEXEPKCS7
    66 {
    67     uint8_t const              *pbBuf;
     65/**
     66 * PKCS\#7 signature data.
     67 */
     68typedef struct SIGNTOOLPKCS7
     69{
     70    /** The raw signature. */
     71    uint8_t                    *pbBuf;
     72    /** Size of the raw signature. */
    6873    size_t                      cbBuf;
     74    /** The filename.   */
    6975    const char                 *pszFilename;
    70     unsigned                    cVerbosity;
    71     RTLDRMOD                    hLdrMod;
    7276    /** The outer content info wrapper. */
    7377    RTCRPKCS7CONTENTINFO        ContentInfo;
     
    7680    /** Pointer to the indirect data content. */
    7781    PRTCRSPCINDIRECTDATACONTENT pIndData;
    78 
     82} SIGNTOOLPKCS7;
     83typedef SIGNTOOLPKCS7 *PSIGNTOOLPKCS7;
     84
     85
     86/**
     87 * PKCS\#7 signature data for executable.
     88 */
     89typedef struct SIGNTOOLPKCS7EXE : public SIGNTOOLPKCS7
     90{
     91    /** The module handle. */
     92    RTLDRMOD                    hLdrMod;
     93} SIGNTOOLPKCS7EXE;
     94typedef SIGNTOOLPKCS7EXE *PSIGNTOOLPKCS7EXE;
     95
     96
     97/**
     98 * Data for the show exe (signature) command.
     99 */
     100typedef struct SHOWEXEPKCS7 : public SIGNTOOLPKCS7EXE
     101{
     102    /** The verbosity. */
     103    unsigned                    cVerbosity;
     104    /** The prefix buffer. */
    79105    char                        szPrefix[256];
     106    /** Temporary buffer. */
    80107    char                        szTmp[4096];
    81108} SHOWEXEPKCS7;
     
    94121
    95122
    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                 else
    150                     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 DEBUG
    176     size_t     cbBuf = 64;
    177 #else
    178     size_t     cbBuf = _512K;
    179 #endif
    180     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                                 else
    236                                     RTMsgError("RTFileClose failed: %Rrc", rc);
    237                             }
    238                             else
    239                                 RTMsgError("RTFileWrite failed: %Rrc", rc);
    240                             RTFileClose(hFile);
    241                         }
    242                         else
    243                             RTMsgError("Error opening '%s': %Rrc", pszOut, rc);
    244                     }
    245                     else
    246                         RTMsgError("Certificate not found.");
    247                 }
    248                 else
    249                     RTMsgError("SignerInfo count: %u", pSd->SignerInfos.cItems);
    250             }
    251             else
    252                 RTMsgError("No PKCS7 content: ContentType=%s", Pkcs7Ci.ContentType.szObjId);
    253             RTAsn1VtDelete(&Pkcs7Ci.SeqCore.Asn1Core);
    254         }
    255         else
    256             RTMsgError("RTPkcs7ContentInfoDecodeAsn1 failed: %Rrc - %s", rc, s_StaticErrInfo.szMsg);
    257     }
    258     else
    259         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_TOOL
    268 
    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 VERIFYEXESTATE
    282 {
    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 VBOX
    294 /** Certificate store load set.
    295  * Declared outside HandleVerifyExe because of braindead gcc visibility crap. */
    296 struct STSTORESET
    297 {
    298     RTCRSTORE       hStore;
    299     PCSUPTAENTRY    paTAs;
    300     unsigned        cTAs;
    301 };
    302 # endif
    303 
    304123/**
    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 */
     128static 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 */
     145static 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);
    659155}
    660156
     
    663159 * Decodes the PKCS #7 blob pointed to by pThis->pbBuf.
    664160 *
    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 */
     164static int SignToolPkcs7_Decode(PSIGNTOOLPKCS7 pThis)
    669165{
    670166    RTERRINFOSTATIC     ErrInfo;
     
    724220
    725221/**
     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 */
     231static 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 */
     313static 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
     320static 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 */
     442static 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
     450static 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 */
     525static 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
     534typedef 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. */
     549struct 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 */
     561static 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}  */
     660static 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. */
     701static 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
     742static 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 */
     905static 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 */
     920static 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/**
    726978 * Display an object ID.
    727979 *
     
    8021054                else
    8031055                    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");
    8051057            }
    8061058            break;
     
    8121064            for (unsigned i = 0; i < pAttr->uValues.pObjIdSeqs->cItems; i++)
    8131065            {
    814                 uint32_t const cObjIds = pAttr->uValues.pObjIdSeqs->paItems[i].cItems;
     1066                uint32_t const cObjIds = pAttr->uValues.pObjIdSeqs->papItems[i]->cItems;
    8151067                for (unsigned j = 0; j < cObjIds; j++)
    8161068                {
     
    8211073                    if (cObjIds != 1)
    8221074                        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");
    8241076                }
    8251077            }
     
    8321084            for (unsigned i = 0; i < pAttr->uValues.pOctetStrings->cItems; i++)
    8331085            {
    834                 PCRTASN1OCTETSTRING pOctetString = &pAttr->uValues.pOctetStrings->paItems[i];
     1086                PCRTASN1OCTETSTRING pOctetString = pAttr->uValues.pOctetStrings->papItems[i];
    8351087                uint32_t cbContent = pOctetString->Asn1Core.cb;
    8361088                if (cbContent > 0 && (cbContent <= 128 || pThis->cVerbosity >= 2))
     
    8791131                    offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "  ");
    8801132                //    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];
    8821134                int rc2;
    8831135                if (RTCrPkcs7ContentInfo_IsSignedData(pContentInfo))
     
    9601212                                                "MonikerAttrib[%u]: ", i);
    9611213
    962                                     switch (pData->paItems[i].enmType)
     1214                                    switch (pData->papItems[i]->enmType)
    9631215                                    {
    9641216                                        case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2:
    9651217                                        case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1:
    9661218                                        {
    967                                             PCRTCRSPCSERIALIZEDPAGEHASHES pPgHashes = pData->paItems[i].u.pPageHashes;
    968                                             uint32_t const cbHash =    pData->paItems[i].enmType
     1219                                            PCRTCRSPCSERIALIZEDPAGEHASHES pPgHashes = pData->papItems[i]->u.pPageHashes;
     1220                                            uint32_t const cbHash =    pData->papItems[i]->enmType
    9691221                                                                    == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1
    9701222                                                                  ? 160/8 /*SHA-1*/ : 256/8 /*SHA-256*/;
     
    9721224
    9731225                                            RTPrintf("%sPage Hashes version %u - %u pages (%u bytes total)\n", pThis->szPrefix,
    974                                                         pData->paItems[i].enmType
     1226                                                        pData->papItems[i]->enmType
    9751227                                                     == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 ? 1 : 2,
    9761228                                                     cPages, pPgHashes->RawData.Asn1Core.cb);
     
    10061258
    10071259                                        case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN:
    1008                                             HandleShowExeWorkerDisplayObjIdSimple(pThis, &pData->paItems[i].Type, "\n");
     1260                                            HandleShowExeWorkerDisplayObjIdSimple(pThis, &pData->papItems[i]->Type, "\n");
    10091261                                            break;
    10101262                                        case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT:
     
    10121264                                            break;
    10131265                                        default:
    1014                                             RTPrintf("%senmType=%d!\n", pThis->szPrefix, pData->paItems[i].enmType);
     1266                                            RTPrintf("%senmType=%d!\n", pThis->szPrefix, pData->papItems[i]->enmType);
    10151267                                            break;
    10161268                                    }
     
    10991351    for (unsigned i = 0; i < pSignedData->DigestAlgorithms.cItems; i++)
    11001352    {
    1101         PCRTCRX509ALGORITHMIDENTIFIER pAlgoId = &pSignedData->DigestAlgorithms.paItems[i];
     1353        PCRTCRX509ALGORITHMIDENTIFIER pAlgoId = pSignedData->DigestAlgorithms.papItems[i];
    11021354        const char *pszDigestType = RTCrDigestTypeToName(RTCrX509AlgorithmIdentifier_QueryDigestType(pAlgoId));
    11031355        if (!pszDigestType)
     
    11211373    }
    11221374    else
    1123         RTPrintf("%s     ContentType: %s\n", pThis->szPrefix, pSignedData->ContentInfo.ContentType.szObjId);
     1375        HandleShowExeWorkerDisplayObjId(pThis, &pSignedData->ContentInfo.ContentType, "     ContentType: ", " - not implemented.\n");
    11241376
    11251377    /*
    11261378     * Display certificates (Certificates).
    11271379     */
     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);
    11281386
    11291387    /*
     
    11341392    for (unsigned i = 0; i < cSigInfos; i++)
    11351393    {
    1136         PRTCRPKCS7SIGNERINFO pSigInfo = &pSignedData->SignerInfos.paItems[i];
     1394        PRTCRPKCS7SIGNERINFO pSigInfo = pSignedData->SignerInfos.papItems[i];
    11371395        size_t offPrefix2 = offPrefix;
    11381396        if (cSigInfos != 1)
     
    11701428            for (unsigned j = 0; j < pSigInfo->AuthenticatedAttributes.cItems; j++)
    11711429            {
    1172                 PRTCRPKCS7ATTRIBUTE pAttr = &pSigInfo->AuthenticatedAttributes.paItems[j];
     1430                PRTCRPKCS7ATTRIBUTE pAttr = pSigInfo->AuthenticatedAttributes.papItems[j];
    11731431                size_t offPrefix3 = offPrefix2 + RTStrPrintf(&pThis->szPrefix[offPrefix2], sizeof(pThis->szPrefix) - offPrefix2,
    11741432                                                             "              AuthAttrib[%u]: ", j);
     
    11861444            for (unsigned j = 0; j < pSigInfo->UnauthenticatedAttributes.cItems; j++)
    11871445            {
    1188                 PRTCRPKCS7ATTRIBUTE pAttr = &pSigInfo->UnauthenticatedAttributes.paItems[j];
     1446                PRTCRPKCS7ATTRIBUTE pAttr = pSigInfo->UnauthenticatedAttributes.papItems[j];
    11891447                size_t offPrefix3 = offPrefix2 + RTStrPrintf(&pThis->szPrefix[offPrefix2], sizeof(pThis->szPrefix) - offPrefix2,
    11901448                                                             "            UnauthAttrib[%u]: ", j);
     
    12121470static RTEXITCODE HandleShowExeWorker(const char *pszFilename, unsigned cVerbosity, RTLDRARCH enmLdrArch)
    12131471{
    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;
    12781486}
    12791487
     
    15991807    { "extract-exe-signer-cert",        HandleExtractExeSignerCert,         HelpExtractExeSignerCert },
    16001808#ifndef IPRT_IN_BUILD_TOOL
     1809    { "add-nested-exe-signature",       HandleAddNestedExeSignature,        HelpAddNestedExeSignature },
    16011810    { "verify-exe",                     HandleVerifyExe,                    HelpVerifyExe },
    16021811    { "show-exe",                       HandleShowExe,                      HelpShowExe },
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette