VirtualBox

Ignore:
Timestamp:
May 8, 2020 11:55:55 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
137816
Message:

VBoxManage/signova: Use new tar update functionality to complete the OVA signing job. Refactored the code a little to only process the TAR file once. Fixed a .cert file formatting bug. bugref:9699

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp

    r84167 r84208  
    17981798 * @param   pszOva              The name of the OVA.
    17991799 * @param   iVerbosity          The noise level.
    1800  * @param   pStrName            Where to return the manifest name.
    1801  * @param   phVfsManifest       Where to return the manifest file handle (in mem).
    1802  * @param   pStrSignatureName   Where to return the cert-file name if already
    1803  *                              signed.
     1800 * @param   fReSign             Whether it is acceptable to have an existing signature
     1801 *                              in the OVA or not.
     1802 * @param   phVfsFssOva         Where to return the OVA file system stream handle.
     1803 *                              This has been opened for updating and we're positioned
     1804 *                              at the end of the stream.
     1805 * @param   pStrManifestName    Where to return the manifest name.
     1806 * @param   phVfsManifest       Where to return the manifest file handle (copy in mem).
     1807 * @param   phVfsOldSignature   Where to return the handle to the old signature object.
     1808 *
     1809 * @note    Caller must clean up return values on failure too!
    18041810 */
    1805 static int getManifestFromOva(const char *pszOva, unsigned iVerbosity,
    1806                               Utf8Str *pStrName, PRTVFSFILE phVfsManifest, Utf8Str *pStrSignatureName)
     1811static int openOvaAndGetManifestAndOldSignature(const char *pszOva, unsigned iVerbosity, bool fReSign,
     1812                                                PRTVFSFSSTREAM phVfsFssOva, Utf8Str *pStrManifestName,
     1813                                                PRTVFSFILE phVfsManifest, PRTVFSOBJ phVfsOldSignature)
    18071814{
    18081815    /*
    18091816     * Clear return values.
    18101817     */
    1811     *phVfsManifest = NIL_RTVFSFILE;
    1812     pStrName->setNull();
    1813     pStrSignatureName->setNull();
     1818    *phVfsFssOva       = NIL_RTVFSFSSTREAM;
     1819    pStrManifestName->setNull();
     1820    *phVfsManifest     = NIL_RTVFSFILE;
     1821    *phVfsOldSignature = NIL_RTVFSOBJ;
    18141822
    18151823    /*
    18161824     * Open the file as a tar file system stream.
    18171825     */
    1818     RTVFSIOSTREAM hVfsIosOva;
    1819     int rc = RTVfsIoStrmOpenNormal(pszOva, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, &hVfsIosOva);
     1826    RTVFSFILE hVfsFileOva;
     1827    int rc = RTVfsFileOpenNormal(pszOva, RTFILE_O_OPEN | RTFILE_O_READWRITE | RTFILE_O_DENY_WRITE, &hVfsFileOva);
    18201828    if (RT_FAILURE(rc))
    1821         return RTMsgErrorExitFailure("Failed to open OVA '%s' for reading: %Rrc", pszOva, rc);
    1822 
    1823     RTVFSFSSTREAM hVfsFssIn;
    1824     rc = RTZipTarFsStreamFromIoStream(hVfsIosOva, 0 /*fFlags*/, &hVfsFssIn);
    1825     RTVfsIoStrmRelease(hVfsIosOva);
     1829        return RTMsgErrorExitFailure("Failed to open OVA '%s' for updating: %Rrc", pszOva, rc);
     1830
     1831    RTVFSFSSTREAM hVfsFssOva;
     1832    rc = RTZipTarFsStreamForFile(hVfsFileOva, RTZIPTARFORMAT_DEFAULT, RTZIPTAR_C_UPDATE, &hVfsFssOva);
     1833    RTVfsFileRelease(hVfsFileOva);
    18261834    if (RT_FAILURE(rc))
    18271835        return RTMsgErrorExitFailure("Failed to open OVA '%s' as a TAR file: %Rrc", pszOva, rc);
     1836    *phVfsFssOva = hVfsFssOva;
    18281837
    18291838    /*
     
    18321841    if (iVerbosity >= 2)
    18331842        RTMsgInfo("Scanning OVA '%s' for a manifest and signature...", pszOva);
     1843    enum { kScanning, kSeenManifest, kSeenSignature } enmState = kScanning;
    18341844    for (;;)
    18351845    {
     
    18401850        RTVFSOBJTYPE    enmType;
    18411851        RTVFSOBJ        hVfsObj;
    1842         rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, &enmType, &hVfsObj);
     1852        rc = RTVfsFsStrmNext(hVfsFssOva, &pszName, &enmType, &hVfsObj);
    18431853        if (RT_FAILURE(rc))
    18441854        {
     
    18511861
    18521862        if (iVerbosity > 2)
    1853             RTMsgInfo("  %s %s\n",
    1854                       enmType == RTVFSOBJTYPE_IO_STREAM || enmType == RTVFSOBJTYPE_FILE ? "file"
    1855                       : enmType == RTVFSOBJTYPE_DIR ? "dir " : "unk ",
    1856                       pszName);
     1863            RTMsgInfo("  %s %s\n", RTVfsTypeName(enmType), pszName);
    18571864
    18581865        /*
    18591866         * Should we process this entry?
    18601867         */
    1861         if (   enmType  == RTVFSOBJTYPE_IO_STREAM
    1862             || enmType  == RTVFSOBJTYPE_FILE)
     1868        const char *pszSuffix = RTPathSuffix(pszName);
     1869        if (   pszSuffix
     1870            && RTStrICmpAscii(pszSuffix, ".mf") == 0
     1871            && (enmType == RTVFSOBJTYPE_IO_STREAM || enmType == RTVFSOBJTYPE_FILE))
    18631872        {
    1864             const char *pszSuffix = RTPathSuffix(pszName);
    1865             if (pszSuffix && RTStrICmpAscii(pszSuffix, ".mf") == 0)
     1873            if (   enmState >= kSeenManifest
     1874                || *phVfsManifest != NIL_RTVFSFILE /* paranoia */)
     1875                rc = RTMsgErrorRc(VERR_DUPLICATE, "OVA contains multiple manifests! first: %s  second: %s",
     1876                                  pStrManifestName->c_str(), pszName);
     1877            else
    18661878            {
    1867                 if (*phVfsManifest != NIL_RTVFSFILE)
    1868                     rc = RTMsgErrorRc(VERR_DUPLICATE, "OVA contains multiple manifests! first: %s  second: %s",
    1869                                       pStrName->c_str(), pszName);
     1879                enmState = kSeenManifest;
     1880                if (iVerbosity >= 2)
     1881                    RTMsgInfo("Found manifest file: %s", pszName);
     1882                rc = pStrManifestName->assignNoThrow(pszName);
     1883                if (RT_SUCCESS(rc))
     1884                {
     1885                    RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
     1886                    Assert(hVfsIos != NIL_RTVFSIOSTREAM);
     1887                    rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsManifest);
     1888                    RTVfsIoStrmRelease(hVfsIos);     /* consumes stream handle.  */
     1889                    if (RT_FAILURE(rc))
     1890                        rc = RTMsgErrorRc(VERR_DUPLICATE, "Failed to memorize the manifest: %Rrc", rc);
     1891                }
    18701892                else
    1871                 {
    1872                     if (iVerbosity >= 2)
    1873                         RTMsgInfo("Found manifest file: %s", pszName);
    1874                     rc = pStrName->assignNoThrow(pszName);
    1875                     if (RT_SUCCESS(rc))
    1876                     {
    1877                         RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
    1878                         Assert(hVfsIos != NIL_RTVFSIOSTREAM);
    1879                         rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsManifest);
    1880                         RTVfsIoStrmRelease(hVfsIos);     /* consumes stream handle.  */
    1881                         if (RT_FAILURE(rc))
    1882                             rc = RTMsgErrorRc(VERR_DUPLICATE, "Failed to memorize the manifest: %Rrc", rc);
    1883                     }
    1884                     else
    1885                         RTMsgError("Out of memory!");
    1886                 }
     1893                    RTMsgError("Out of memory!");
    18871894            }
    1888             else if (pszSuffix && RTStrICmpAscii(pszSuffix, ".cert") == 0)
     1895        }
     1896        else if (   pszSuffix
     1897                 && RTStrICmpAscii(pszSuffix, ".cert") == 0
     1898                 && (enmType == RTVFSOBJTYPE_IO_STREAM || enmType == RTVFSOBJTYPE_FILE))
     1899        {
     1900            if (   enmState >= kSeenSignature
     1901                || *phVfsOldSignature != NIL_RTVFSOBJ /* paranoia */)
     1902                rc = RTMsgErrorRc(VERR_WRONG_ORDER, "Multiple signature files! (%s)", pszName);
     1903            else
    18891904            {
     1905                enmState = kSeenSignature;
    18901906                if (iVerbosity >= 2)
    18911907                    RTMsgInfo("Found existing signature file: %s", pszName);
    1892                 rc = pStrSignatureName->assignNoThrow(pszName);
     1908                *phVfsOldSignature = hVfsObj;
     1909                hVfsObj = NIL_RTVFSOBJ;
    18931910            }
    18941911        }
     1912        else if (enmState >= kSeenManifest)
     1913            rc = RTMsgErrorRc(VERR_WRONG_ORDER, "Invalid OVA file ordering! (%s)", pszName);
    18951914
    18961915        /*
     
    19031922    }
    19041923
    1905     RTVfsFsStrmRelease(hVfsFssIn);
    1906 
    19071924    /*
    19081925     * Complain if no manifest.
     
    19101927    if (RT_SUCCESS(rc) && *phVfsManifest == NIL_RTVFSFILE)
    19111928        rc = RTMsgErrorRc(VERR_NOT_FOUND, "The OVA contains no manifest and cannot be signed!");
     1929    else if (RT_SUCCESS(rc) && *phVfsOldSignature != NIL_RTVFSOBJ && !fReSign)
     1930        rc = RTMsgErrorRc(VERR_ALREADY_EXISTS,
     1931                          "The OVA is already signed! (Use the --force option to force re-signing it.)");
    19121932
    19131933    return rc;
     1934}
     1935
     1936
     1937/**
     1938 * Continues where openOvaAndGetManifestAndOldSignature() left off and writes
     1939 * the signature file to the OVA.
     1940 *
     1941 * When @a hVfsOldSignature isn't NIL, the old signature it represent will be
     1942 * replaced.  The open function has already made sure there isn't anything
     1943 * following the .cert file in that case.
     1944 */
     1945static int updateTheOvaSignature(RTVFSFSSTREAM hVfsFssOva, const char *pszOva,
     1946                                 const char *pszSignatureName, RTVFSFILE hVfsFileSignature, RTVFSOBJ hVfsOldSignature)
     1947{
     1948    /*
     1949     * Truncate the file at the old signature, if present.
     1950     */
     1951    int rc;
     1952    if (hVfsOldSignature != NIL_RTVFSOBJ)
     1953    {
     1954        rc = RTZipTarFsStreamTruncate(hVfsFssOva, hVfsOldSignature, false /*fAfter*/);
     1955        if (RT_FAILURE(rc))
     1956            return RTMsgErrorRc(rc, "RTZipTarFsStreamTruncate failed on '%s': %Rrc", pszOva, rc);
     1957    }
     1958
     1959    /*
     1960     * Append the signature file.  We have to rewind it first or
     1961     * we'll end up with VERR_EOF, probably not a great idea...
     1962     */
     1963    rc = RTVfsFileSeek(hVfsFileSignature, 0, RTFILE_SEEK_BEGIN, NULL);
     1964    if (RT_FAILURE(rc))
     1965        return RTMsgErrorRc(rc, "RTVfsFileSeek(hVfsFileSignature) failed: %Rrc", rc);
     1966
     1967    RTVFSOBJ hVfsObj = RTVfsObjFromFile(hVfsFileSignature);
     1968    rc = RTVfsFsStrmAdd(hVfsFssOva, pszSignatureName, hVfsObj, 0 /*fFlags*/);
     1969    RTVfsObjRelease(hVfsObj);
     1970    if (RT_FAILURE(rc))
     1971        return RTMsgErrorRc(rc, "RTVfsFsStrmAdd('%s') failed on '%s': %Rrc", pszSignatureName, pszOva, rc);
     1972
     1973    /*
     1974     * Terminate the file system stream.
     1975     */
     1976    rc = RTVfsFsStrmEnd(hVfsFssOva);
     1977    if (RT_FAILURE(rc))
     1978        return RTMsgErrorRc(rc, "RTVfsFsStrmEnd failed on '%s': %Rrc", pszOva, rc);
     1979
     1980    return VINF_SUCCESS;
    19141981}
    19151982
     
    20032070                        if (RT_SUCCESS(rc))
    20042071                        {
    2005                             rc = (int)RTVfsFilePrintf(hVfsFileSignature, "%s(%s) = %.*Rhxs\n\n",
     2072                            rc = (int)RTVfsFilePrintf(hVfsFileSignature, "%s(%s) = %#.*Rhxs\n\n",
    20062073                                                      pszDigestType, pszManifestName, cbSignature, pvSignature);
    20072074                            if (RT_SUCCESS(rc))
     
    20552122
    20562123/**
    2057  * Alters the OVA file, adding (or replacing) the @a pszSignatureName member.
    2058  */
    2059 static int updateTheOvaSignature(const char *pszOva, const char *pszSignatureName, RTVFSFILE hVfsFileSignature, bool fIsSigned)
    2060 {
    2061     RT_NOREF(pszOva, pszSignatureName, hVfsFileSignature, fIsSigned);
    2062 
    2063     RTMsgError("TODO: updateTheOvaSignature");
    2064     return VINF_SUCCESS;
    2065 }
    2066 
    2067 
    2068 /**
    20692124 * Handles the 'ovasign' command.
    20702125 */
     
    21952250
    21962251    /*
    2197      * Read the certificate and private key.
     2252     * Open the OVA, read the manifest and look for any existing signature.
    21982253     */
    2199     RTERRINFOSTATIC     ErrInfo;
    2200     RTCRX509CERTIFICATE Certificate;
    2201     rc = RTCrX509Certificate_ReadFromFile(&Certificate, pszCertificate, 0, &g_RTAsn1DefaultAllocator,
    2202                                           RTErrInfoInitStatic(&ErrInfo));
    2203     if (RT_FAILURE(rc))
    2204         return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszCertificate, rc, &ErrInfo.Core);
    2205 
    2206     RTCRKEY hPrivateKey = NIL_RTCRKEY;
    2207     rc = RTCrKeyCreateFromFile(&hPrivateKey, 0 /*fFlags*/, pszPrivateKey, strPrivateKeyPassword.c_str(),
    2208                                RTErrInfoInitStatic(&ErrInfo));
     2254    RTVFSFSSTREAM   hVfsFssOva       = NIL_RTVFSFSSTREAM;
     2255    RTVFSOBJ        hVfsOldSignature = NIL_RTVFSOBJ;
     2256    RTVFSFILE       hVfsFileManifest = NIL_RTVFSFILE;
     2257    Utf8Str         strManifestName;
     2258    rc = openOvaAndGetManifestAndOldSignature(pszOva, iVerbosity, fReSign,
     2259                                              &hVfsFssOva, &strManifestName, &hVfsFileManifest, &hVfsOldSignature);
    22092260    if (RT_SUCCESS(rc))
    22102261    {
    2211         if (iVerbosity > 1)
    2212             RTMsgInfo("Successfully read the certificate and private key.");
    2213 
    22142262        /*
    2215          * Extract the manifest from the OVA and check whether it is already signed.
     2263         * Read the certificate and private key.
    22162264         */
    2217         Utf8Str     strManifestName;
    2218         Utf8Str     strSignatureName;
    2219         RTVFSFILE   hVfsFileManifest = NIL_RTVFSFILE;
    2220         rc = getManifestFromOva(pszOva, iVerbosity, &strManifestName, &hVfsFileManifest, &strSignatureName);
     2265        RTERRINFOSTATIC     ErrInfo;
     2266        RTCRX509CERTIFICATE Certificate;
     2267        rc = RTCrX509Certificate_ReadFromFile(&Certificate, pszCertificate, 0, &g_RTAsn1DefaultAllocator,
     2268                                              RTErrInfoInitStatic(&ErrInfo));
     2269        if (RT_FAILURE(rc))
     2270            return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszCertificate, rc, &ErrInfo.Core);
     2271
     2272        RTCRKEY hPrivateKey = NIL_RTCRKEY;
     2273        rc = RTCrKeyCreateFromFile(&hPrivateKey, 0 /*fFlags*/, pszPrivateKey, strPrivateKeyPassword.c_str(),
     2274                                   RTErrInfoInitStatic(&ErrInfo));
    22212275        if (RT_SUCCESS(rc))
    22222276        {
    2223             bool const fIsSigned = strSignatureName.isNotEmpty();
    2224             if (!fIsSigned || fReSign)
     2277            if (iVerbosity > 1)
     2278                RTMsgInfo("Successfully read the certificate and private key.");
     2279
     2280            /*
     2281             * Do the signing and create the signature file.
     2282             */
     2283            RTVFSFILE hVfsFileSignature = NIL_RTVFSFILE;
     2284            rc = doTheOvaSigning(&Certificate, hPrivateKey, strManifestName.c_str(), hVfsFileManifest,
     2285                                 fPkcs7, cIntermediateCerts, apszIntermediateCerts,
     2286                                 &ErrInfo, &hVfsFileSignature);
     2287
     2288            /*
     2289             * Construct the signature filename:
     2290             */
     2291            if (RT_SUCCESS(rc))
    22252292            {
    2226                 /*
    2227                  * Do the signing and create the signature file.
    2228                  */
    2229                 RTVFSFILE hVfsFileSignature = NIL_RTVFSFILE;
    2230                 rc = doTheOvaSigning(&Certificate, hPrivateKey, strManifestName.c_str(), hVfsFileManifest,
    2231                                      fPkcs7, cIntermediateCerts, apszIntermediateCerts,
    2232                                      &ErrInfo, &hVfsFileSignature);
    2233 
    2234                 /*
    2235                  * Construct the signature filename if there isn't one already:
    2236                  */
    2237                 if (RT_SUCCESS(rc) && strSignatureName.isEmpty())
    2238                 {
    2239                     rc = strSignatureName.assignNoThrow(strManifestName);
    2240                     if (RT_SUCCESS(rc))
    2241                         rc = strSignatureName.stripSuffix().appendNoThrow(".cert");
    2242                 }
     2293                Utf8Str strSignatureName;
     2294                rc = strSignatureName.assignNoThrow(strManifestName);
     2295                if (RT_SUCCESS(rc))
     2296                    rc = strSignatureName.stripSuffix().appendNoThrow(".cert");
    22432297                if (RT_SUCCESS(rc) && !fDryRun)
    22442298                {
     
    22462300                     * Update the OVA.
    22472301                     */
    2248                     rc = updateTheOvaSignature(pszOva, strSignatureName.c_str(), hVfsFileSignature, fIsSigned);
     2302                    rc = updateTheOvaSignature(hVfsFssOva, pszOva, strSignatureName.c_str(), hVfsFileSignature, hVfsOldSignature);
    22492303                }
    22502304            }
    2251             else
    2252                 rc = RTMsgErrorRc(VERR_ALREADY_EXISTS,
    2253                                   "The OVA is already signed! (Use the --force option to force re-signing it.)");
     2305            RTCrKeyRelease(hPrivateKey);
    22542306        }
    2255         RTCrKeyRelease(hPrivateKey);
     2307        else
     2308            RTPrintf("Error reading the private key from %s: %Rrc%#RTeim", pszPrivateKey, rc, &ErrInfo.Core);
     2309        RTCrX509Certificate_Delete(&Certificate);
    22562310    }
    2257     else
    2258         RTPrintf("Error reading the private key from %s: %Rrc%#RTeim", pszPrivateKey, rc, &ErrInfo.Core);
    2259     RTCrX509Certificate_Delete(&Certificate);
     2311
     2312    RTVfsObjRelease(hVfsOldSignature);
     2313    RTVfsFileRelease(hVfsFileManifest);
     2314    RTVfsFsStrmRelease(hVfsFssOva);
    22602315
    22612316    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : 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