VirtualBox

Changeset 95613 in vbox


Ignore:
Timestamp:
Jul 13, 2022 12:52:44 AM (2 years ago)
Author:
vboxsync
Message:

RTSignTool,IPRT: Working on signing executable images. bugref:8691

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/crypto/spc.h

    r93115 r95613  
    4343 * @{
    4444 */
     45
     46/** Value for RTCR_PKCS9_ID_MS_STATEMENT_TYPE. */
     47#define RTCRSPC_STMT_TYPE_INDIVIDUAL_CODE_SIGNING   "1.3.6.1.4.1.311.2.1.21"
    4548
    4649/**
  • trunk/src/VBox/Runtime/tools/RTSignTool.cpp

    r95605 r95613  
    3131#include <iprt/assert.h>
    3232#include <iprt/buildconfig.h>
     33#include <iprt/ctype.h>
    3334#include <iprt/err.h>
    3435#include <iprt/getopt.h>
     
    6566*   Defined Constants And Macros                                                                                                 *
    6667*********************************************************************************************************************************/
    67 #define OPT_TIMESTAMP_CERT_FILE         1000
    68 #define OPT_TIMESTAMP_KEY_FILE          1001
    69 #define OPT_TIMESTAMP_TYPE              1002
    70 #define OPT_TIMESTAMP_DATE              1003
    71 #define OPT_TIMESTAMP_YEAR              1004
     68#define OPT_HASH_PAGES                  1000
     69#define OPT_NO_HASH_PAGES               1001
     70#define OPT_CERT_FILE                   1002
     71#define OPT_KEY_FILE                    1003
     72#define OPT_ADD_CERT                    1004
     73
     74#define OPT_TIMESTAMP_CERT_FILE         1010
     75#define OPT_TIMESTAMP_KEY_FILE          1011
     76#define OPT_TIMESTAMP_TYPE              1012
     77#define OPT_TIMESTAMP_OVERRIDE          1016
    7278
    7379
     
    133139} SHOWEXEPKCS7;
    134140typedef SHOWEXEPKCS7 *PSHOWEXEPKCS7;
     141
     142
     143/**
     144 * Certificate w/ public key + private key pair for signing.
     145 */
     146typedef struct SIGNTOOLKEYPAIR
     147{
     148    RTCRX509CERTIFICATE     Cert;
     149    PCRTCRX509CERTIFICATE   pCertificate;
     150    RTCRKEY                 hPrivateKey;
     151
     152    SIGNTOOLKEYPAIR()
     153        : pCertificate(NULL)
     154        , hPrivateKey(NIL_RTCRKEY)
     155    {
     156        RT_ZERO(Cert);
     157    }
     158
     159    ~SIGNTOOLKEYPAIR()
     160    {
     161        if (hPrivateKey != NIL_RTCRKEY)
     162        {
     163            RTCrKeyRelease(hPrivateKey);
     164            hPrivateKey = NIL_RTCRKEY;
     165        }
     166        if (pCertificate == &Cert)
     167        {
     168            RTCrX509Certificate_Delete(&Cert);
     169            pCertificate = NULL;
     170        }
     171    }
     172
     173    bool isComplete(void) const
     174    {
     175        return pCertificate && hPrivateKey != NIL_RTCRKEY;
     176    }
     177
     178    bool isNull(void) const
     179    {
     180        return pCertificate == NULL && hPrivateKey == NIL_RTCRKEY;
     181    }
     182} SIGNTOOLKEYPAIR;
    135183
    136184
     
    915963#ifndef IPRT_IN_BUILD_TOOL
    916964
    917 static RTEXITCODE AddAuthAttribsForTimestamp(PRTCRPKCS7ATTRIBUTES pAuthAttribs, bool fTimestampTypeOld,
    918                                              RTTIMESPEC SigningTime,  PCRTCRX509CERTIFICATE pTimestampCert)
     965static RTEXITCODE SignToolPkcs7_AuthAttribsAddSigningTime(PRTCRPKCS7ATTRIBUTES pAuthAttribs, RTTIMESPEC SigningTime)
    919966{
    920967    /*
     
    945992    rc = RTAsn1SetOfTimes_Init(pAttr->uValues.pSigningTime, pAttr->Allocation.pAllocator);
    946993    if (RT_FAILURE(rc))
    947         return RTMsgErrorExitFailure("RTCrPkcs7ContentInfos_Init failed: %Rrc", rc);
     994        return RTMsgErrorExitFailure("RTAsn1SetOfTimes_Init failed: %Rrc", rc);
    948995
    949996    /* Create the timestamp. */
    950997    iPos = RTAsn1SetOfTimes_Append(pAttr->uValues.pSigningTime);
    951998    if (iPos < 0)
    952         return RTMsgErrorExitFailure("RTCrPkcs7SigningTimes_Append failed: %Rrc", iPos);
     999        return RTMsgErrorExitFailure("RTAsn1SetOfTimes_Append failed: %Rrc", iPos);
    9531000
    9541001    PRTASN1TIME pTime = pAttr->uValues.pSigningTime->papItems[iPos];
     
    9571004        return RTMsgErrorExitFailure("RTAsn1Time_SetTimeSpec failed: %Rrc", rc);
    9581005
     1006    return RTEXITCODE_SUCCESS;
     1007}
     1008
     1009static RTEXITCODE SignToolPkcs7_AuthAttribsAddObjIdSeqsEmpty(PRTCRPKCS7ATTRIBUTES pAuthAttribs, const char *pszAttrId)
     1010{
     1011    int32_t iPos = RTCrPkcs7Attributes_Append(pAuthAttribs);
     1012    if (iPos < 0)
     1013        return RTMsgErrorExitFailure("RTCrPkcs7Attributes_Append failed: %Rrc", iPos);
     1014
     1015    /* Create the attrib and its sub-set of timestamps. */
     1016    PRTCRPKCS7ATTRIBUTE pAttr = pAuthAttribs->papItems[iPos];
     1017    int rc = RTAsn1ObjId_InitFromString(&pAttr->Type, pszAttrId, pAttr->Allocation.pAllocator);
     1018    if (RT_FAILURE(rc))
     1019        return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszAttrId, rc);
     1020
     1021    /** @todo Generalize the Type + enmType DYN stuff and generate setters. */
     1022    Assert(pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT);
     1023    Assert(pAttr->uValues.pContentInfos == NULL);
     1024    pAttr->enmType = RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE;
     1025    rc = RTAsn1MemAllocZ(&pAttr->Allocation, (void **)&pAttr->uValues.pObjIdSeqs, sizeof(*pAttr->uValues.pObjIdSeqs));
     1026    if (RT_FAILURE(rc))
     1027        return RTMsgErrorExitFailure("RTAsn1MemAllocZ failed: %Rrc", rc);
     1028
     1029    rc = RTAsn1SetOfObjIdSeqs_Init(pAttr->uValues.pObjIdSeqs, pAttr->Allocation.pAllocator);
     1030    if (RT_FAILURE(rc))
     1031        return RTMsgErrorExitFailure("RTAsn1SetOfObjIdSeqs_Init failed: %Rrc", rc);
     1032
     1033    return RTEXITCODE_SUCCESS;
     1034}
     1035
     1036static RTEXITCODE SignToolPkcs7_AuthAttribsAddObjIdSeqsValue(PRTCRPKCS7ATTRIBUTES pAuthAttribs, const char *pszAttrId,
     1037                                                             const char *pszValueId)
     1038{
     1039    RTEXITCODE rcExit = SignToolPkcs7_AuthAttribsAddObjIdSeqsEmpty(pAuthAttribs, pszAttrId);
     1040    if (rcExit != RTEXITCODE_SUCCESS)
     1041        return rcExit;
     1042
     1043    /* Add attribute value entry. */
     1044    PRTCRPKCS7ATTRIBUTE pAttr = pAuthAttribs->papItems[pAuthAttribs->cItems - 1];
     1045    int32_t iPos = RTAsn1SetOfObjIdSeqs_Append(pAttr->uValues.pObjIdSeqs);
     1046    if (iPos < 0)
     1047        return RTMsgErrorExitFailure("RTAsn1SetOfObjIdSeqs_Append failed: %Rrc", iPos);
     1048    PRTASN1SEQOFOBJIDS pSeqObjIds = pAttr->uValues.pObjIdSeqs->papItems[iPos];
     1049
     1050    /* Add a object id to the value. */
     1051    RTASN1OBJID ObjIdValue;
     1052    int rc = RTAsn1ObjId_InitFromString(&ObjIdValue, pszValueId, &g_RTAsn1DefaultAllocator);
     1053    if (RT_FAILURE(rc))
     1054        return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszAttrId, rc);
     1055
     1056    rc = RTAsn1SeqOfObjIds_InsertEx(pSeqObjIds, 0 /*iPos*/, &ObjIdValue, &g_RTAsn1DefaultAllocator, NULL);
     1057    RTAsn1ObjId_Delete(&ObjIdValue);
     1058    if (RT_FAILURE(rc))
     1059        return RTMsgErrorExitFailure("RTAsn1SeqOfObjIds_InsertEx failed: %Rrc", iPos);
     1060
     1061    return RTEXITCODE_SUCCESS;
     1062}
     1063
     1064static RTEXITCODE SignToolPkcs7_AddAuthAttribsForTimestamp(PRTCRPKCS7ATTRIBUTES pAuthAttribs, bool fTimestampTypeOld,
     1065                                                           RTTIMESPEC SigningTime,  PCRTCRX509CERTIFICATE pTimestampCert)
     1066{
     1067    /*
     1068     * Add signing time.
     1069     */
     1070    RTEXITCODE rcExit = SignToolPkcs7_AuthAttribsAddSigningTime(pAuthAttribs, SigningTime);
     1071    if (rcExit != RTEXITCODE_SUCCESS)
     1072        return rcExit;
     1073
    9591074    /*
    9601075     * More later if we want to support fTimestampTypeOld = false perhaps?
     
    9621077    Assert(fTimestampTypeOld);
    9631078    RT_NOREF(fTimestampTypeOld, pTimestampCert);
     1079
     1080    return RTEXITCODE_SUCCESS;
     1081}
     1082
     1083static RTEXITCODE SignToolPkcs7_AddAuthAttribsForImageSignature(PRTCRPKCS7ATTRIBUTES pAuthAttribs, RTTIMESPEC SigningTime)
     1084{
     1085    /*
     1086     * Add SpcOpusInfo.  No attribute values.
     1087     *                      SEQ start -vv    vv- Type ObjId
     1088     *   1c60: 0e 03 02 1a 05 00 a0 70-30 10 06 0a 2b 06 01 04 .......p0...+...
     1089     *   1c70: 01 82 37 02 01 0c 31 02-30 00 30 19 06 09 2a 86 ..7...1.0.0...*.
     1090     *                   Set Of -^^    ^^- Empty Sequence.
     1091     */
     1092    RTEXITCODE rcExit = SignToolPkcs7_AuthAttribsAddObjIdSeqsEmpty(pAuthAttribs, RTCR_PKCS9_ID_MS_SP_OPUS_INFO);
     1093    if (rcExit != RTEXITCODE_SUCCESS)
     1094        return rcExit;
     1095
     1096    /*
     1097     * Add ContentType = Ms-SpcIndirectDataContext?
     1098     *                            SEQ start -vv    vv- Type ObjId
     1099     *   1c70: 01 82 37 02 01 0c 31 02-30 00 30 19 06 09 2a 86 ..7...1.0.0...*.
     1100     *   1c80: 48 86 f7 0d 01 09 03 31-0c 06 0a 2b 06 01 04 01 H......1...+....
     1101     *   1c90: 82 37 02 01 04       ^^-   ^^- ObjId
     1102     *                              ^- Set Of
     1103     */
     1104
     1105    /*
     1106     * Add Ms-SpcStatementType = Ms-SpcIndividualCodeSigning.
     1107     *             SEQ start -vv    vv- Type ObjId
     1108     *   1c90: 82 37 02 01 04 30 1c 06-0a 2b 06 01 04 01 82 37 .7...0...+.....7
     1109     *   1ca0: 02 01 0b 31 0e 30 0c 06-0a 2b 06 01 04 01 82 37 ...1.0...+.....7
     1110     *   1cb0: 02 01 15 ^^    ^^    ^^- ObjId
     1111     *          Set Of -^^    ^^- Sequence Of
     1112     */
     1113    rcExit = SignToolPkcs7_AuthAttribsAddObjIdSeqsValue(pAuthAttribs, RTCR_PKCS9_ID_MS_STATEMENT_TYPE,
     1114                                                        RTCRSPC_STMT_TYPE_INDIVIDUAL_CODE_SIGNING);
     1115    if (rcExit != RTEXITCODE_SUCCESS)
     1116        return rcExit;
     1117
     1118    /*
     1119     * Add signing time. We add this, even if signtool.exe, since OpenSSL will always do it otherwise.
     1120     */
     1121    rcExit = SignToolPkcs7_AuthAttribsAddSigningTime(pAuthAttribs, SigningTime);
     1122    if (rcExit != RTEXITCODE_SUCCESS)
     1123        return rcExit;
     1124
     1125    /** @todo more? Some certificate stuff?   */
    9641126
    9651127    return RTEXITCODE_SUCCESS;
     
    10571219static RTEXITCODE Pkcs7SignStuff(const char *pszWhat, const void *pvToDataToSign, size_t cbToDataToSign,
    10581220                                 PCRTCRPKCS7ATTRIBUTES pAuthAttribs, RTCRSTORE hAdditionalCerts, uint32_t fExtraFlags,
    1059                                  RTDIGESTTYPE enmDigestType, PCRTCRX509CERTIFICATE pTimestampCert, RTCRKEY hTimestampKey,
     1221                                 RTDIGESTTYPE enmDigestType, SIGNTOOLKEYPAIR *pCertKeyPair,
    10601222                                 unsigned cVerbosity, void **ppvSigned, size_t *pcbSigned,
    10611223                                 PRTCRPKCS7CONTENTINFO pContentInfo, PRTCRPKCS7SIGNEDDATA *ppSignedData)
     
    10711233    size_t cbSigned = 1024;
    10721234    int rc = RTCrPkcs7SimpleSignSignedData(RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP | fExtraFlags,
    1073                                            pTimestampCert, hTimestampKey, pvToDataToSign, cbToDataToSign,
     1235                                           pCertKeyPair->pCertificate, pCertKeyPair->hPrivateKey, pvToDataToSign, cbToDataToSign,
    10741236                                           enmDigestType, hAdditionalCerts, pAuthAttribs,
    10751237                                           NULL, &cbSigned, RTErrInfoInitStatic(&ErrInfo));
     
    10781240
    10791241    /* Allocate memory for it and do the actual signing. */
    1080     void *pvSigned = RTMemTmpAllocZ(cbSigned);
     1242    void *pvSigned = RTMemAllocZ(cbSigned);
    10811243    if (!pvSigned)
    10821244        return RTMsgErrorExitFailure("Failed to allocate %#zx bytes for %s signature", cbSigned, pszWhat);
    10831245    rc = RTCrPkcs7SimpleSignSignedData(RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP | fExtraFlags,
    1084                                        pTimestampCert, hTimestampKey, pvToDataToSign, cbToDataToSign,
     1246                                       pCertKeyPair->pCertificate, pCertKeyPair->hPrivateKey, pvToDataToSign, cbToDataToSign,
    10851247                                       enmDigestType, hAdditionalCerts, pAuthAttribs,
    10861248                                       pvSigned, &cbSigned, RTErrInfoInitStatic(&ErrInfo));
     
    11231285        RTCrPkcs7ContentInfo_Delete(pContentInfo);
    11241286    }
    1125     RTMemTmpFree(pvSigned);
     1287    RTMemFree(pvSigned);
    11261288    return RTEXITCODE_FAILURE;
    11271289}
    11281290
    1129 
    1130 static RTEXITCODE SignToolPkcs7_AddTimestampSignature(SIGNTOOLPKCS7EXE *pThis, unsigned cVerbosity, unsigned iSignature,
    1131                                                       bool fReplaceExisting, bool fTimestampTypeOld, RTTIMESPEC SigningTime,
    1132                                                       PCRTCRX509CERTIFICATE pTimestampCert, RTCRKEY hTimestampKey)
     1291static RTEXITCODE SignToolPkcs7_AddTimestampSignatureEx(PRTCRPKCS7SIGNERINFO pSignerInfo, PRTCRPKCS7SIGNEDDATA pSignedData,
     1292                                                        unsigned cVerbosity,  bool fReplaceExisting, bool fTimestampTypeOld,
     1293                                                        RTTIMESPEC SigningTime, SIGNTOOLKEYPAIR *pTimestampPair)
    11331294{
    11341295    AssertReturn(fTimestampTypeOld, RTMsgErrorExitFailure("New style signatures not supported yet"));
    1135 
    1136     /*
    1137      * Locate the signature specified by iSignature:
    1138      */
    1139     PRTCRPKCS7SIGNEDDATA pSignedData = NULL;
    1140     PRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(pThis, iSignature, &pSignedData);
    1141     if (!pSignerInfo)
    1142         return RTMsgErrorExitFailure("No signature #%u in %s", iSignature, pThis->pszFilename);
    11431296
    11441297    /*
     
    11511304        return RTMsgErrorExitFailure("RTCrPkcs7SetOfAttributes_Init failed: %Rrc", rc);
    11521305
    1153     RTEXITCODE rcExit = AddAuthAttribsForTimestamp(&AuthAttribs, fTimestampTypeOld, SigningTime, pTimestampCert);
     1306    RTEXITCODE rcExit = SignToolPkcs7_AddAuthAttribsForTimestamp(&AuthAttribs, fTimestampTypeOld, SigningTime,
     1307                                                                 pTimestampPair->pCertificate);
    11541308    if (rcExit == RTEXITCODE_SUCCESS)
    11551309    {
     
    11621316        rcExit = Pkcs7SignStuff("timestamp", pSignerInfo->EncryptedDigest.Asn1Core.uData.pv,
    11631317                                pSignerInfo->EncryptedDigest.Asn1Core.cb, &AuthAttribs, NIL_RTCRSTORE /*hAdditionalCerts*/,
    1164                                 RTCRPKCS7SIGN_SD_F_DEATCHED, RTDIGESTTYPE_SHA1, pTimestampCert, hTimestampKey, cVerbosity,
     1318                                RTCRPKCS7SIGN_SD_F_DEATCHED, RTDIGESTTYPE_SHA1, pTimestampPair, cVerbosity,
    11651319                                &pvSigned, NULL /*pcbSigned*/, &TsContentInfo, &pTsSignedData);
    11661320        if (rcExit == RTEXITCODE_SUCCESS)
     
    11981352             */
    11991353            if (rcExit == RTEXITCODE_SUCCESS)
    1200                 rcExit = SignToolPkcs7_AppendCertificate(pSignedData, pTimestampCert);
     1354                rcExit = SignToolPkcs7_AppendCertificate(pSignedData, pTimestampPair->pCertificate);
    12011355
    12021356            /*
     
    12041358             */
    12051359            RTCrPkcs7ContentInfo_Delete(&TsContentInfo);
    1206             RTMemTmpFree(pvSigned);
     1360            RTMemFree(pvSigned);
    12071361        }
    12081362    }
    12091363    RTCrPkcs7Attributes_Delete(&AuthAttribs);
    1210 
    1211     RT_NOREF(cVerbosity, fReplaceExisting, fTimestampTypeOld);
     1364    return rcExit;
     1365}
     1366
     1367static RTEXITCODE SignToolPkcs7_AddTimestampSignature(SIGNTOOLPKCS7EXE *pThis, unsigned cVerbosity, unsigned iSignature,
     1368                                                      bool fReplaceExisting, bool fTimestampTypeOld, RTTIMESPEC SigningTime,
     1369                                                      SIGNTOOLKEYPAIR *pTimestampPair)
     1370{
     1371    AssertReturn(fTimestampTypeOld, RTMsgErrorExitFailure("New style signatures not supported yet"));
     1372
     1373    /*
     1374     * Locate the signature specified by iSignature and add a timestamp to it.
     1375     */
     1376    PRTCRPKCS7SIGNEDDATA pSignedData = NULL;
     1377    PRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(pThis, iSignature, &pSignedData);
     1378    if (!pSignerInfo)
     1379        return RTMsgErrorExitFailure("No signature #%u in %s", iSignature, pThis->pszFilename);
     1380
     1381    return SignToolPkcs7_AddTimestampSignatureEx(pSignerInfo, pSignedData, cVerbosity, fReplaceExisting, fTimestampTypeOld,
     1382                                                 SigningTime, pTimestampPair);
     1383}
     1384
     1385static RTEXITCODE SignToolPkcs7_SignSpcIndData(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData,
     1386                                               unsigned cVerbosity, bool fReplaceExisting,  SIGNTOOLKEYPAIR *pSigningCertKey,
     1387                                               RTCRSTORE hAddCerts,  bool fTimestampTypeOld, RTTIMESPEC SigningTime,
     1388                                               SIGNTOOLKEYPAIR *pTimestampCertKey)
     1389{
     1390    /*
     1391     * Encode it.
     1392     */
     1393    RTERRINFOSTATIC ErrInfo;
     1394    PRTASN1CORE     pSpcRoot     = RTCrSpcIndirectDataContent_GetAsn1Core(pSpcIndData);
     1395    uint32_t        cbSpcEncoded = 0;
     1396    int rc = RTAsn1EncodePrepare(pSpcRoot, RTASN1ENCODE_F_DER, &cbSpcEncoded, RTErrInfoInitStatic(&ErrInfo));
     1397    if (RT_FAILURE(rc))
     1398        return RTMsgErrorExitFailure("RTAsn1EncodePrepare failed: %Rrc%RTeim", rc, &ErrInfo.Core);
     1399
     1400    if (cVerbosity >= 4)
     1401        RTAsn1Dump(pSpcRoot, 0, 0, RTStrmDumpPrintfV, g_pStdOut);
     1402
     1403    void *pvSpcEncoded = (uint8_t *)RTMemTmpAllocZ(cbSpcEncoded);
     1404    if (!pvSpcEncoded)
     1405        return RTMsgErrorExitFailure("Failed to allocate %#z bytes for SpcIndirectData", cbSpcEncoded);
     1406
     1407    RTEXITCODE rcExit = RTEXITCODE_FAILURE;
     1408    rc = RTAsn1EncodeToBuffer(pSpcRoot, RTASN1ENCODE_F_DER, pvSpcEncoded, cbSpcEncoded, RTErrInfoInitStatic(&ErrInfo));
     1409    if (RT_SUCCESS(rc))
     1410    {
     1411        /*
     1412         * Create additional authenticated attributes.
     1413         */
     1414        RTCRPKCS7ATTRIBUTES AuthAttribs;
     1415        rc = RTCrPkcs7Attributes_Init(&AuthAttribs, &g_RTAsn1DefaultAllocator);
     1416        if (RT_SUCCESS(rc))
     1417        {
     1418            rcExit = SignToolPkcs7_AddAuthAttribsForImageSignature(&AuthAttribs, SigningTime);
     1419            if (rcExit == RTEXITCODE_SUCCESS)
     1420            {
     1421                /*
     1422                 * Ditch the old signature if so desired.
     1423                 */
     1424                if (fReplaceExisting && pThis->pSignedData)
     1425                {
     1426                    RTCrPkcs7ContentInfo_Delete(&pThis->ContentInfo);
     1427                    pThis->pSignedData = NULL;
     1428                    RTMemFree(pThis->pbBuf);
     1429                    pThis->pbBuf = NULL;
     1430                    pThis->cbBuf = 0;
     1431                }
     1432
     1433                /*
     1434                 * Do the actual signing.
     1435                 */
     1436                SIGNTOOLPKCS7  Src     = { NULL, 0, NULL };
     1437                PSIGNTOOLPKCS7 pSigDst = !pThis->pSignedData ? pThis : &Src;
     1438                rcExit = Pkcs7SignStuff("image", pvSpcEncoded, cbSpcEncoded, &AuthAttribs, hAddCerts, 0 /*fExtraFlags*/,
     1439                                        RTDIGESTTYPE_SHA1 /** @todo*/, pSigningCertKey, cVerbosity,
     1440                                        (void **)&pSigDst->pbBuf, &pSigDst->cbBuf, &pSigDst->ContentInfo, &pSigDst->pSignedData);
     1441                if (rcExit == RTEXITCODE_SUCCESS)
     1442                {
     1443                    /*
     1444                     * Add a timestamp signature if requested.
     1445                     */
     1446                    if (pTimestampCertKey->isComplete())
     1447                        rcExit = SignToolPkcs7_AddTimestampSignatureEx(pSigDst->pSignedData->SignerInfos.papItems[0],
     1448                                                                       pSigDst->pSignedData,
     1449                                                                       cVerbosity, false /*fReplaceExisting*/,
     1450                                                                       fTimestampTypeOld, SigningTime, pTimestampCertKey);
     1451
     1452                    /*
     1453                     * Append the signature to the existing one, if that's what we're doing.
     1454                     */
     1455                    if (rcExit == RTEXITCODE_SUCCESS && pSigDst == &Src)
     1456                        rcExit = SignToolPkcs7_AddNestedSignature(pThis, &Src, cVerbosity, true /*fPrepend*/); /** @todo prepend/append option */
     1457
     1458                    /* cleanup */
     1459                    if (pSigDst == &Src)
     1460                        SignToolPkcs7_Delete(&Src);
     1461                }
     1462            }
     1463            RTCrPkcs7Attributes_Delete(&AuthAttribs);
     1464        }
     1465        else
     1466            RTMsgError("RTCrPkcs7SetOfAttributes_Init failed: %Rrc", rc);
     1467    }
     1468    else
     1469        RTMsgError("RTAsn1EncodeToBuffer failed: %Rrc", rc);
     1470    RTMemTmpFree(pvSpcEncoded);
     1471    return rcExit;
     1472}
     1473
     1474static RTEXITCODE SignToolPkcs7_SpcCompleteWithoutPageHashes(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData)
     1475{
     1476    RT_NOREF(pThis);
     1477    PRTCRSPCPEIMAGEDATA pPeImage = pSpcIndData->Data.uValue.pPeImage;
     1478    Assert(pPeImage);
     1479    //pPeImage->Flags
     1480
     1481    return RTEXITCODE_SUCCESS;
     1482}
     1483
     1484static RTEXITCODE SignToolPkcs7_SpcAddImagePageHashes(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData,
     1485                                                      RTDIGESTTYPE enmSigType)
     1486{
     1487    RT_NOREF(pThis, pSpcIndData, enmSigType);
     1488    return RTEXITCODE_SUCCESS;
     1489}
     1490
     1491static RTEXITCODE SignToolPkcs7_SpcAddImageHash(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData,
     1492                                                RTDIGESTTYPE enmSigType)
     1493{
     1494    uint32_t     const cbHash   = RTCrDigestTypeToHashSize(enmSigType);
     1495    const char * const pszAlgId = RTCrDigestTypeToAlgorithmOid(enmSigType);
     1496
     1497    /*
     1498     * Ask the loader for the hash.
     1499     */
     1500    uint8_t abHash[RTSHA512_HASH_SIZE];
     1501    int rc = RTLdrHashImage(pThis->hLdrMod, enmSigType, abHash, sizeof(abHash));
     1502    if (RT_FAILURE(rc))
     1503        return RTMsgErrorExitFailure("RTLdrHashImage/%s failed: %Rrc", RTCrDigestTypeToName(enmSigType), rc);
     1504
     1505    /*
     1506     * Set it.
     1507     */
     1508    /** @todo no setter, this should be okay, though...   */
     1509    rc = RTAsn1ObjId_InitFromString(&pSpcIndData->DigestInfo.DigestAlgorithm.Algorithm, pszAlgId, &g_RTAsn1DefaultAllocator);
     1510    if (RT_FAILURE(rc))
     1511        return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszAlgId, rc);
     1512
     1513    rc = RTAsn1ContentDup(&pSpcIndData->DigestInfo.Digest.Asn1Core, abHash, cbHash, &g_RTAsn1DefaultAllocator);
     1514    if (RT_FAILURE(rc))
     1515        return RTMsgErrorExitFailure("RTAsn1ContentDup/%#x failed: %Rrc", cbHash, rc);
     1516
     1517    return RTEXITCODE_SUCCESS;
     1518}
     1519
     1520
     1521static RTEXITCODE SignToolPkcs7_AddOrReplaceSignature(SIGNTOOLPKCS7EXE *pThis, unsigned cVerbosity, RTDIGESTTYPE enmSigType,
     1522                                                      bool fReplaceExisting,  bool fHashPages, SIGNTOOLKEYPAIR *pSigningCertKey,
     1523                                                      RTCRSTORE hAddCerts,  bool fTimestampTypeOld,
     1524                                                      RTTIMESPEC SigningTime, SIGNTOOLKEYPAIR *pTimestampCertKey)
     1525{
     1526    AssertReturn(fTimestampTypeOld || pTimestampCertKey->isNull(),
     1527                 RTMsgErrorExitFailure("New style signatures not supported yet"));
     1528
     1529    /*
     1530     * We must construct the data to be backed into the PKCS#7 signature
     1531     * and signed.
     1532     */
     1533    RTCRSPCINDIRECTDATACONTENT SpcIndData;
     1534    int rc = RTCrSpcIndirectDataContent_Init(&SpcIndData, &g_RTAsn1DefaultAllocator);
     1535    if (RT_FAILURE(rc))
     1536        return RTMsgErrorExitFailure("RTCrSpcIndirectDataContent_Init failed: %Rrc", rc);
     1537
     1538    /* Set the data to PE image. */
     1539    /** @todo Generalize the Type + enmType DYN stuff and generate setters. */
     1540    Assert(SpcIndData.Data.enmType == RTCRSPCAAOVTYPE_NOT_PRESENT);
     1541    Assert(SpcIndData.Data.uValue.pPeImage == NULL);
     1542    SpcIndData.Data.enmType = RTCRSPCAAOVTYPE_PE_IMAGE_DATA;
     1543    rc = RTAsn1MemAllocZ(&SpcIndData.Data.Allocation, (void **)&SpcIndData.Data.uValue.pPeImage,
     1544                         sizeof(*SpcIndData.Data.uValue.pPeImage));
     1545    RTEXITCODE rcExit;
     1546    if (RT_SUCCESS(rc))
     1547    {
     1548        rc = RTCrSpcPeImageData_Init(SpcIndData.Data.uValue.pPeImage, SpcIndData.Data.Allocation.pAllocator);
     1549        if (RT_SUCCESS(rc))
     1550        {
     1551            /* Add the hashes. */
     1552            rcExit = SignToolPkcs7_SpcAddImageHash(pThis, &SpcIndData, enmSigType);
     1553            if (rcExit == RTEXITCODE_SUCCESS)
     1554            {
     1555                if (fHashPages)
     1556                    rcExit = SignToolPkcs7_SpcAddImagePageHashes(pThis, &SpcIndData, enmSigType);
     1557                else
     1558                    rcExit = SignToolPkcs7_SpcCompleteWithoutPageHashes(pThis, &SpcIndData);
     1559
     1560                /*
     1561                 * Encode and sign the SPC data, timestamp it, and line it up for adding to the executable.
     1562                 */
     1563                if (rcExit == RTEXITCODE_SUCCESS)
     1564                    rcExit = SignToolPkcs7_SignSpcIndData(pThis, &SpcIndData, cVerbosity, fReplaceExisting, pSigningCertKey,
     1565                                                          hAddCerts, fTimestampTypeOld, SigningTime, pTimestampCertKey);
     1566            }
     1567        }
     1568        else
     1569            rcExit = RTMsgErrorExitFailure("RTCrPkcs7SignerInfos_Init failed: %Rrc", rc);
     1570    }
     1571    else
     1572        rcExit = RTMsgErrorExitFailure("RTAsn1MemAllocZ failed for RTCRSPCPEIMAGEDATA: %Rrc", rc);
     1573
     1574    RTCrSpcIndirectDataContent_Delete(&SpcIndData);
    12121575    return rcExit;
    12131576}
     
    15691932
    15701933/*********************************************************************************************************************************
     1934*   Option handlers shared by 'sign-exe', 'sign-cat', 'add-timestamp-exe-signature' and others.                                  *
     1935*********************************************************************************************************************************/
     1936static RTEXITCODE HandleOptCertFile(SIGNTOOLKEYPAIR *pKeyPair, const char *pszFile)
     1937{
     1938    if (pKeyPair->pCertificate == &pKeyPair->Cert)
     1939        RTCrX509Certificate_Delete(&pKeyPair->Cert);
     1940    pKeyPair->pCertificate = NULL;
     1941
     1942    RTERRINFOSTATIC ErrInfo;
     1943    int rc = RTCrX509Certificate_ReadFromFile(&pKeyPair->Cert, pszFile, 0, &g_RTAsn1DefaultAllocator,
     1944                                              RTErrInfoInitStatic(&ErrInfo));
     1945    if (RT_FAILURE(rc))
     1946        return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);
     1947    pKeyPair->pCertificate = &pKeyPair->Cert;
     1948    return RTEXITCODE_SUCCESS;
     1949}
     1950
     1951static RTEXITCODE HandleOptKeyFile(SIGNTOOLKEYPAIR *pKeyPair, const char *pszFile)
     1952{
     1953    RTCrKeyRelease(pKeyPair->hPrivateKey);
     1954
     1955    RTERRINFOSTATIC ErrInfo;
     1956    int rc = RTCrKeyCreateFromFile(&pKeyPair->hPrivateKey, 0 /*fFlags*/, pszFile,
     1957                                   NULL /*pszPassword*/, RTErrInfoInitStatic(&ErrInfo));
     1958    if (RT_SUCCESS(rc))
     1959        return RTEXITCODE_SUCCESS;
     1960
     1961    pKeyPair->hPrivateKey = NIL_RTCRKEY;
     1962    return RTMsgErrorExitFailure("Error reading private key from '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);
     1963}
     1964
     1965static RTEXITCODE HandleOptAddCert(PRTCRSTORE phStore, const char *pszFile)
     1966{
     1967    if (*phStore == NIL_RTCRSTORE)
     1968    {
     1969        int rc = RTCrStoreCreateInMem(phStore, 2);
     1970        if (RT_FAILURE(rc))
     1971            return RTMsgErrorExitFailure("RTCrStoreCreateInMem(,2) failed: %Rrc", rc);
     1972    }
     1973    RTERRINFOSTATIC ErrInfo;
     1974    int rc = RTCrStoreCertAddFromFile(*phStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND, pszFile, RTErrInfoInitStatic(&ErrInfo));
     1975    if (RT_FAILURE(rc))
     1976        return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);
     1977    return RTEXITCODE_SUCCESS;
     1978}
     1979
     1980static RTEXITCODE HandleOptSignatureType(RTDIGESTTYPE *penmSigType, const char *pszType)
     1981{
     1982    if (   RTStrICmpAscii(pszType, "sha1") == 0
     1983        || RTStrICmpAscii(pszType, "sha-1") == 0)
     1984        *penmSigType = RTDIGESTTYPE_SHA1;
     1985    else if (   RTStrICmpAscii(pszType, "sha256") == 0
     1986             || RTStrICmpAscii(pszType, "sha-256") == 0)
     1987        *penmSigType = RTDIGESTTYPE_SHA256;
     1988    else
     1989        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown signature type: %s (expected sha1 or sha256)", pszType);
     1990    return RTEXITCODE_SUCCESS;
     1991}
     1992
     1993
     1994static RTEXITCODE HandleOptTimestampType(bool *pfOldType, const char *pszType)
     1995{
     1996    if (strcmp(pszType, "old") == 0)
     1997        *pfOldType = true;
     1998    else if (strcmp(pszType, "new") == 0)
     1999        *pfOldType = false;
     2000    else
     2001        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown timestamp type: %s", pszType);
     2002    return RTEXITCODE_SUCCESS;
     2003}
     2004
     2005static RTEXITCODE HandleOptTimestampOverride(PRTTIMESPEC pSigningTime, const char *pszPartialTs)
     2006{
     2007    /*
     2008     * First try use it as-is.
     2009     */
     2010    if (RTTimeSpecFromString(pSigningTime, pszPartialTs) != NULL)
     2011        return RTEXITCODE_SUCCESS;
     2012
     2013    /* Check the input against a pattern, making sure we've got something that
     2014       makes sense before trying to merge. */
     2015    size_t const cchPartialTs = strlen(pszPartialTs);
     2016    static char s_szPattern[] = "0000-00-00T00:00:";
     2017    if (cchPartialTs > sizeof(s_szPattern) - 1) /* It is not a partial timestamp if we've got the seconds component. */
     2018        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp: %s", pszPartialTs);
     2019
     2020    for (size_t off = 0; off < cchPartialTs; off++)
     2021        switch (s_szPattern[off])
     2022        {
     2023            case '0':
     2024                if (!RT_C_IS_DIGIT(pszPartialTs[off]))
     2025                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected digit at position %u: %s",
     2026                                          off + 1, pszPartialTs);
     2027                break;
     2028            case '-':
     2029            case ':':
     2030                if (pszPartialTs[off] != s_szPattern[off])
     2031                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected '%c' at position %u: %s",
     2032                                          s_szPattern[off], off + 1, pszPartialTs);
     2033                break;
     2034            case 'T':
     2035                if (   pszPartialTs[off] != 'T'
     2036                    && pszPartialTs[off] != 't'
     2037                    && pszPartialTs[off] != ' ')
     2038                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected 'T' or space at position %u: %s",
     2039                                          off + 1, pszPartialTs);
     2040                break;
     2041            default:
     2042                return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Internal error");
     2043        }
     2044
     2045    if (RT_C_IS_DIGIT(s_szPattern[cchPartialTs]) && RT_C_IS_DIGIT(s_szPattern[cchPartialTs - 1]))
     2046        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Incomplete timstamp component: %s", pszPartialTs);
     2047
     2048    /*
     2049     * Take the current time and merge in the components from pszPartialTs.
     2050     */
     2051    char        szSigningTime[RTTIME_STR_LEN];
     2052    RTTIMESPEC  Now;
     2053    RTTimeSpecToString(RTTimeNow(&Now), szSigningTime, sizeof(szSigningTime));
     2054    memcpy(szSigningTime, pszPartialTs, cchPartialTs);
     2055    szSigningTime[4+1+2+1+2] = 'T';
     2056
     2057    /* Fix 29th for non-leap override: */
     2058    if (memcmp(&szSigningTime[5], RT_STR_TUPLE("02-29")) == 0)
     2059    {
     2060        if (!RTTimeIsLeapYear(RTStrToUInt32(szSigningTime)))
     2061            szSigningTime[9] = '8';
     2062    }
     2063    if (RTTimeSpecFromString(pSigningTime, szSigningTime) == NULL)
     2064        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp: %s (%s)", pszPartialTs, szSigningTime);
     2065
     2066    return RTEXITCODE_SUCCESS;
     2067}
     2068
     2069
     2070/*********************************************************************************************************************************
    15712071*   The 'add-timestamp-exe-signature' command.                                                                                   *
    15722072*********************************************************************************************************************************/
     
    15802080                        "add-timestamp-exe-signature [-v|--verbose] [--signature-index|-i <num>] "
    15812081                        "[--timestamp-cert-file <file>] "
     2082                        "[--timestamp-key-file <file>] "
    15822083                        "[--timestamp-type old|new] "
    15832084                        "[--timestamp-date <fake-isots>] "
     
    15892090                            "This is mainly to test timestamp code.\n"
    15902091                            "\n"
    1591                             "The --timestamp-date option takes an ISO timestamp, but will replace the time part with the "
    1592                             "current time.\n"
     2092                            "The --timestamp-override option can take a partial or full ISO timestamp.  It is merged "
     2093                            "with the current time if partial.\n"
    15932094                            "\n");
    15942095    return RTEXITCODE_SUCCESS;
    15952096}
    15962097
    1597 
    15982098static RTEXITCODE HandleAddTimestampExeSignature(int cArgs, char **papszArgs)
    15992099{
    1600     RTERRINFOSTATIC ErrInfo;
    1601 
    16022100    /*
    16032101     * Parse arguments.
     
    16092107        { "--timestamp-key-file",   OPT_TIMESTAMP_KEY_FILE,     RTGETOPT_REQ_STRING },
    16102108        { "--timestamp-type",       OPT_TIMESTAMP_TYPE,         RTGETOPT_REQ_STRING },
    1611         { "--timestamp-date",       OPT_TIMESTAMP_DATE,         RTGETOPT_REQ_STRING },
    1612         { "--timestamp-year",       OPT_TIMESTAMP_YEAR,         RTGETOPT_REQ_UINT32 },
     2109        { "--timestamp-override",   OPT_TIMESTAMP_OVERRIDE,     RTGETOPT_REQ_STRING },
    16132110        { "--replace-existing",     'r',                        RTGETOPT_REQ_NOTHING },
    16142111        { "--verbose",              'v',                        RTGETOPT_REQ_NOTHING },
     
    16192116    bool                    fReplaceExisting        = false;
    16202117    bool                    fTimestampTypeOld       = true;
    1621     RTCRX509CERTIFICATE     TimestampCertificate;               /* leaked */
    1622     PCRTCRX509CERTIFICATE   pTimestampCertificate   = NULL;
    1623     RTCRKEY                 hTimestampPrivateKey    = NIL_RTCRKEY;
     2118    SIGNTOOLKEYPAIR         TimestampCertKey;
    16242119    RTTIMESPEC              SigningTime;
    16252120    RTTimeNow(&SigningTime);
     
    16342129    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
    16352130    {
     2131        RTEXITCODE rcExit2 = RTEXITCODE_SUCCESS;
    16362132        switch (ch)
    16372133        {
    1638             case 'i':
    1639                 iSignature = ValueUnion.u32;
    1640                 break;
    1641 
    1642             case OPT_TIMESTAMP_CERT_FILE:
    1643             {
    1644                 if (pTimestampCertificate == &TimestampCertificate)
    1645                     RTCrX509Certificate_Delete(&TimestampCertificate);
    1646                 rc = RTCrX509Certificate_ReadFromFile(&TimestampCertificate, ValueUnion.psz, 0, &g_RTAsn1DefaultAllocator,
    1647                                                       RTErrInfoInitStatic(&ErrInfo));
    1648                 if (RT_FAILURE(rc))
    1649                     return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim",
    1650                                                  ValueUnion.psz, rc, &ErrInfo.Core);
    1651                 pTimestampCertificate = &TimestampCertificate;
    1652                 break;
    1653             }
    1654 
    1655             case OPT_TIMESTAMP_KEY_FILE:
    1656                 RTCrKeyRelease(hTimestampPrivateKey);
    1657                 rc = RTCrKeyCreateFromFile(&hTimestampPrivateKey, 0 /*fFlags*/, ValueUnion.psz,
    1658                                            NULL /*pszPassword*/, RTErrInfoInitStatic(&ErrInfo));
    1659                 if (RT_FAILURE(rc))
    1660                     return RTMsgErrorExitFailure("Error reading private key from '%s': %Rrc%#RTeim",
    1661                                                  ValueUnion.psz, rc, &ErrInfo.Core);
    1662                 break;
    1663 
    1664             case OPT_TIMESTAMP_TYPE:
    1665                 if (strcmp(ValueUnion.psz, "old") == 0)
    1666                     fTimestampTypeOld = true;
    1667                 else if (strcmp(ValueUnion.psz, "new") == 0)
    1668                     fTimestampTypeOld = false;
    1669                 else
    1670                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown timestamp type: %s", ValueUnion.psz);
    1671                 break;
    1672 
    1673             case OPT_TIMESTAMP_DATE:
    1674             {
    1675                 RTTIMESPEC Tmp;
    1676                 if (RTTimeSpecFromString(&Tmp, ValueUnion.psz))
     2134            case 'i':                       iSignature = ValueUnion.u32; break;
     2135            case OPT_TIMESTAMP_CERT_FILE:   rcExit2 = HandleOptCertFile(&TimestampCertKey, ValueUnion.psz); break;
     2136            case OPT_TIMESTAMP_KEY_FILE:    rcExit2 = HandleOptKeyFile(&TimestampCertKey, ValueUnion.psz); break;
     2137            case OPT_TIMESTAMP_TYPE:        rcExit2 = HandleOptTimestampType(&fTimestampTypeOld, ValueUnion.psz); break;
     2138            case OPT_TIMESTAMP_OVERRIDE:    rcExit2 = HandleOptTimestampOverride(&SigningTime, ValueUnion.psz); break;
     2139            case 'r':                       fReplaceExisting = true; break;
     2140            case 'v':                       cVerbosity++; break;
     2141            case 'V':                       return HandleVersion(cArgs, papszArgs);
     2142            case 'h':                       return HelpAddTimestampExeSignature(g_pStdOut, RTSIGNTOOLHELP_FULL);
     2143
     2144            case VINF_GETOPT_NOT_OPTION:
     2145                /* check that we've got all the info we need: */
     2146                if (TimestampCertKey.isComplete())
    16772147                {
    1678                     RTTIME Time, Now;
    1679                     RTTimeExplode(&Time, &Tmp);
    1680                     RTTimeExplode(&Now, RTTimeNow(&Tmp));
    1681                     Time.u8Hour        = Now.u8Hour;
    1682                     Time.u8Minute      = Now.u8Minute;
    1683                     Time.u8Second      = Now.u8Second;
    1684                     Time.u32Nanosecond = Now.u32Nanosecond;
    1685                     RTTimeImplode(&SigningTime, &Time);
     2148                    /* Do the work: */
     2149                    SIGNTOOLPKCS7EXE Exe;
     2150                    rcExit2 = SignToolPkcs7Exe_InitFromFile(&Exe, ValueUnion.psz, cVerbosity);
     2151                    if (rcExit2 == RTEXITCODE_SUCCESS)
     2152                    {
     2153                        rcExit2 = SignToolPkcs7_AddTimestampSignature(&Exe, cVerbosity, iSignature, fReplaceExisting,
     2154                                                                      fTimestampTypeOld, SigningTime, &TimestampCertKey);
     2155                        if (rcExit2 == RTEXITCODE_SUCCESS)
     2156                            rcExit2 = SignToolPkcs7_Encode(&Exe, cVerbosity);
     2157                        if (rcExit2 == RTEXITCODE_SUCCESS)
     2158                            rcExit2 = SignToolPkcs7Exe_WriteSignatureToFile(&Exe, cVerbosity);
     2159                        SignToolPkcs7Exe_Delete(&Exe);
     2160                    }
     2161                    if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
     2162                        rcExit = rcExit2;
     2163                    rcExit2 = RTEXITCODE_SUCCESS;
    16862164                }
    16872165                else
    1688                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp: %s", ValueUnion.psz);
     2166                {
     2167                    if (!TimestampCertKey.pCertificate)
     2168                        RTMsgError("No timestamp certificate was specified");
     2169                    if (TimestampCertKey.hPrivateKey == NIL_RTCRKEY)
     2170                        RTMsgError("No timestamp private key was specified");
     2171                    rcExit2 = RTEXITCODE_SYNTAX;
     2172                }
    16892173                break;
    1690             }
    1691 
    1692             case OPT_TIMESTAMP_YEAR:
    1693             {
    1694                 if (ValueUnion.u32 <= 1950 || ValueUnion.u32 >= 2050)
    1695                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp year: %u, valid range 1951-2049", ValueUnion.u32);
    1696 
    1697                 RTTIME Time;
    1698                 RTTimeExplode(&Time, RTTimeNow(&SigningTime));
    1699                 Time.i32Year = (int32_t)ValueUnion.u32;
    1700                 if (Time.u8MonthDay > 28 && Time.u8Month == 2 && !RTTimeIsLeapYear(Time.i32Year))
    1701                     Time.u8MonthDay = 28;
    1702                 Time.u16YearDay = 0;
    1703                 Time.fFlags    &= ~(RTTIME_FLAGS_COMMON_YEAR | RTTIME_FLAGS_LEAP_YEAR);
    1704                 RTTimeImplode(&SigningTime, RTTimeNormalize(&Time));
    1705                 break;
    1706             }
    1707 
    1708             case 'r':
    1709                 fReplaceExisting = true;
    1710                 break;
    1711 
    1712             case 'v':
    1713                 cVerbosity++;
    1714                 break;
    1715 
    1716             case 'V':
    1717                 return HandleVersion(cArgs, papszArgs);
    1718 
    1719             case 'h':
    1720                 return HelpAddTimestampExeSignature(g_pStdOut, RTSIGNTOOLHELP_FULL);
    1721 
    1722             case VINF_GETOPT_NOT_OPTION:
    1723             {
    1724                 /* check that we've got all the info we need: */
    1725                 if (!pTimestampCertificate)
    1726                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No timestamp certificate was specified");
    1727                 if (hTimestampPrivateKey == NIL_RTCRKEY)
    1728                     return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No timestamp private key was specified");
    1729 
    1730                 /* Do the work: */
    1731                 SIGNTOOLPKCS7EXE Exe;
    1732                 RTEXITCODE rcExit2 = SignToolPkcs7Exe_InitFromFile(&Exe, ValueUnion.psz, cVerbosity);
    1733                 if (rcExit2 == RTEXITCODE_SUCCESS)
    1734                 {
    1735                     rcExit2 = SignToolPkcs7_AddTimestampSignature(&Exe, cVerbosity, iSignature, fReplaceExisting,
    1736                                                                   fTimestampTypeOld, SigningTime,
    1737                                                                   pTimestampCertificate, hTimestampPrivateKey);
    1738                     if (rcExit2 == RTEXITCODE_SUCCESS)
    1739                         rcExit2 = SignToolPkcs7_Encode(&Exe, cVerbosity);
    1740                     if (rcExit2 == RTEXITCODE_SUCCESS)
    1741                         rcExit2 = SignToolPkcs7Exe_WriteSignatureToFile(&Exe, cVerbosity);
    1742                     SignToolPkcs7Exe_Delete(&Exe);
    1743                 }
    1744                 if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
    1745                     rcExit = rcExit2;
    1746                 break;
    1747             }
    17482174
    17492175            default:
    17502176                return RTGetOptPrintError(ch, &ValueUnion);
    17512177        }
    1752     }
     2178
     2179        if (rcExit2 != RTEXITCODE_SUCCESS)
     2180        {
     2181            rcExit = rcExit2;
     2182            break;
     2183        }
     2184    }
     2185    return rcExit;
     2186}
     2187
     2188#endif /*!IPRT_IN_BUILD_TOOL */
     2189
     2190
     2191/*********************************************************************************************************************************
     2192*   The 'sign-exe' command.                                                                                   *
     2193*********************************************************************************************************************************/
     2194#ifndef IPRT_IN_BUILD_TOOL
     2195
     2196static RTEXITCODE HelpSignExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
     2197{
     2198    RT_NOREF_PV(enmLevel);
     2199
     2200    RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
     2201                        "sign-exe [-v|--verbose] "
     2202                        "[--type sha1|sha256] "
     2203                        "[--hash-pages] "
     2204                        "[--no-hash-pages] "
     2205                        "[--append] "
     2206                        "[--cert-file <file>] "
     2207                        "[--cert-key <file>] "
     2208                        "[--add-cert <file>] "
     2209                        "[--timestamp-cert-file <file>] "
     2210                        "[--timestamp-key-file <file>] "
     2211                        "[--timestamp-type old|new] "
     2212                        "[--timestamp-date <fake-isots>] "
     2213                        "[--timestamp-year <fake-year>] "
     2214                        "[--replace-existing|-r] "
     2215                        "<exe>\n");
     2216    if (enmLevel == RTSIGNTOOLHELP_FULL)
     2217        RTStrmWrappedPrintf(pStrm, 0,
     2218                            "Create a new code signature for an executable.\n"
     2219                            "\n"
     2220                            "The --timestamp-override option can take a partial or full ISO timestamp.  It is merged "
     2221                            "with the current time if partial.\n"
     2222                            "\n");
     2223    return RTEXITCODE_SUCCESS;
     2224}
     2225
     2226
     2227static RTEXITCODE HandleSignExe(int cArgs, char **papszArgs)
     2228{
     2229    /*
     2230     * Parse arguments.
     2231     */
     2232    static const RTGETOPTDEF s_aOptions[] =
     2233    {
     2234        { "--append",               'a',                        RTGETOPT_REQ_NOTHING },
     2235        { "/as",                    'a',                        RTGETOPT_REQ_NOTHING },
     2236        { "--type",                 't',                        RTGETOPT_REQ_STRING },
     2237        { "/fd",                    't',                        RTGETOPT_REQ_STRING },
     2238        { "--hash-pages",           OPT_HASH_PAGES,             RTGETOPT_REQ_NOTHING },
     2239        { "/ph",                    OPT_HASH_PAGES,             RTGETOPT_REQ_NOTHING },
     2240        { "--no-hash-pages",        OPT_NO_HASH_PAGES,          RTGETOPT_REQ_NOTHING },
     2241        { "/nph",                   OPT_NO_HASH_PAGES,          RTGETOPT_REQ_NOTHING },
     2242        { "--add-cert",             OPT_ADD_CERT,               RTGETOPT_REQ_STRING },
     2243        { "/ac",                    OPT_ADD_CERT,               RTGETOPT_REQ_STRING },
     2244        { "--cert-file",            OPT_CERT_FILE,              RTGETOPT_REQ_STRING },
     2245        { "--key-file",             OPT_KEY_FILE,               RTGETOPT_REQ_STRING },
     2246        { "--timestamp-cert-file",  OPT_TIMESTAMP_CERT_FILE,    RTGETOPT_REQ_STRING },
     2247        { "--timestamp-key-file",   OPT_TIMESTAMP_KEY_FILE,     RTGETOPT_REQ_STRING },
     2248        { "--timestamp-type",       OPT_TIMESTAMP_TYPE,         RTGETOPT_REQ_STRING },
     2249        { "--timestamp-override",   OPT_TIMESTAMP_OVERRIDE,     RTGETOPT_REQ_STRING },
     2250        { "--verbose",              'v',                        RTGETOPT_REQ_NOTHING },
     2251        { "/v",                     'v',                        RTGETOPT_REQ_NOTHING },
     2252        { "/debug",                 'v',                        RTGETOPT_REQ_NOTHING },
     2253    };
     2254
     2255    unsigned                cVerbosity              = 0;
     2256    RTDIGESTTYPE            enmSigType              = RTDIGESTTYPE_SHA1;
     2257    bool                    fReplaceExisting        = true;
     2258    bool                    fHashPages              = false;
     2259    SIGNTOOLKEYPAIR         SigningCertKey;
     2260    RTCRSTORE               hAddCerts               = NIL_RTCRSTORE; /* leaked if returning directly (--help, --version) */
     2261    bool                    fTimestampTypeOld       = true;
     2262    SIGNTOOLKEYPAIR         TimestampCertKey;
     2263    RTTIMESPEC              SigningTime;
     2264    RTTimeNow(&SigningTime);
     2265
     2266    RTGETOPTSTATE   GetState;
     2267    int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     2268    AssertRCReturn(rc, RTEXITCODE_FAILURE);
     2269
     2270    RTEXITCODE      rcExit = RTEXITCODE_SUCCESS;
     2271    RTGETOPTUNION   ValueUnion;
     2272    int             ch;
     2273    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
     2274    {
     2275        RTEXITCODE rcExit2 = RTEXITCODE_SUCCESS;
     2276        switch (ch)
     2277        {
     2278            case 't':                       rcExit2 = HandleOptSignatureType(&enmSigType, ValueUnion.psz); break;
     2279            case 'a':                       fReplaceExisting = false; break;
     2280            case OPT_HASH_PAGES:            fHashPages = true; break;
     2281            case OPT_NO_HASH_PAGES:         fHashPages = false; break;
     2282            case OPT_CERT_FILE:             rcExit2 = HandleOptCertFile(&SigningCertKey, ValueUnion.psz); break;
     2283            case OPT_KEY_FILE:              rcExit2 = HandleOptKeyFile(&SigningCertKey, ValueUnion.psz); break;
     2284            case OPT_ADD_CERT:              rcExit2 = HandleOptAddCert(&hAddCerts, ValueUnion.psz); break;
     2285            case OPT_TIMESTAMP_CERT_FILE:   rcExit2 = HandleOptCertFile(&TimestampCertKey, ValueUnion.psz); break;
     2286            case OPT_TIMESTAMP_KEY_FILE:    rcExit2 = HandleOptKeyFile(&TimestampCertKey, ValueUnion.psz); break;
     2287            case OPT_TIMESTAMP_TYPE:        rcExit2 = HandleOptTimestampType(&fTimestampTypeOld, ValueUnion.psz); break;
     2288            case OPT_TIMESTAMP_OVERRIDE:    rcExit2 = HandleOptTimestampOverride(&SigningTime, ValueUnion.psz); break;
     2289            case 'v':                       cVerbosity++; break;
     2290            case 'V':                       return HandleVersion(cArgs, papszArgs);
     2291            case 'h':                       return HelpSignExe(g_pStdOut, RTSIGNTOOLHELP_FULL);
     2292
     2293            case VINF_GETOPT_NOT_OPTION:
     2294                /* check that we've got all the info we need: */
     2295                if (   SigningCertKey.isComplete()
     2296                    && (TimestampCertKey.isNull() || TimestampCertKey.isComplete()))
     2297                {
     2298                    /* Do the work: */
     2299                    SIGNTOOLPKCS7EXE Exe;
     2300                    /** @todo will fail if not already signed. */
     2301                    rcExit2 = SignToolPkcs7Exe_InitFromFile(&Exe, ValueUnion.psz, cVerbosity);
     2302                    if (rcExit2 == RTEXITCODE_SUCCESS)
     2303                    {
     2304                        rcExit2 = SignToolPkcs7_AddOrReplaceSignature(&Exe, cVerbosity, enmSigType, fReplaceExisting, fHashPages,
     2305                                                                      &SigningCertKey, hAddCerts,
     2306                                                                      fTimestampTypeOld, SigningTime, &TimestampCertKey);
     2307                        if (rcExit2 == RTEXITCODE_SUCCESS)
     2308                            rcExit2 = SignToolPkcs7_Encode(&Exe, cVerbosity);
     2309                        if (rcExit2 == RTEXITCODE_SUCCESS)
     2310                            rcExit2 = SignToolPkcs7Exe_WriteSignatureToFile(&Exe, cVerbosity);
     2311                        SignToolPkcs7Exe_Delete(&Exe);
     2312                    }
     2313                    if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
     2314                        rcExit = rcExit2;
     2315                    rcExit2 = RTEXITCODE_SUCCESS;
     2316                }
     2317                else
     2318                {
     2319                    if (!TimestampCertKey.pCertificate)
     2320                        RTMsgError("No signing certificate was specified");
     2321                    if (TimestampCertKey.hPrivateKey == NIL_RTCRKEY)
     2322                        RTMsgError("No signing private key was specified");
     2323
     2324                    if (!TimestampCertKey.pCertificate && !TimestampCertKey.isNull())
     2325                        RTMsgError("No timestamp certificate was specified");
     2326                    if (TimestampCertKey.hPrivateKey == NIL_RTCRKEY && !TimestampCertKey.isNull())
     2327                        RTMsgError("No timestamp private key was specified");
     2328                    rcExit2 = RTEXITCODE_SYNTAX;
     2329                }
     2330                break;
     2331
     2332            default:
     2333                return RTGetOptPrintError(ch, &ValueUnion);
     2334        }
     2335        if (rcExit2 != RTEXITCODE_SUCCESS)
     2336        {
     2337            rcExit = rcExit2;
     2338            break;
     2339        }
     2340    }
     2341
     2342    if (hAddCerts != NIL_RTCRSTORE)
     2343        RTCrStoreRelease(hAddCerts);
    17532344    return rcExit;
    17542345}
     
    23042895{
    23052896    HandleShowExeWorkerDisplayObjId(pThis, &pAttr->Type, "", ":\n");
     2897    if (pThis->cVerbosity > 4 && pAttr->SeqCore.Asn1Core.uData.pu8)
     2898        RTPrintf("%s uData.pu8=%p cb=%#x\n", pThis->szPrefix, pAttr->SeqCore.Asn1Core.uData.pu8, pAttr->SeqCore.Asn1Core.cb);
    23062899
    23072900    int rc = VINF_SUCCESS;
     
    32883881#ifndef IPRT_IN_BUILD_TOOL
    32893882    { "add-timestamp-exe-signature",    HandleAddTimestampExeSignature,     HelpAddTimestampExeSignature },
     3883    { "sign-exe",                       HandleSignExe,                      HelpSignExe  },
    32903884#endif
    32913885#ifndef IPRT_IN_BUILD_TOOL
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