VirtualBox

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


Ignore:
Timestamp:
Dec 15, 2016 9:22:32 PM (8 years ago)
Author:
vboxsync
Message:

RTSignTool: More on the add-nested-exe-signature command.

File:
1 edited

Legend:

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

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