VirtualBox

Ignore:
Timestamp:
May 5, 2020 7:25:25 PM (5 years ago)
Author:
vboxsync
Message:

VBoxManage,manual: Reworking the signova code. Incomplete. bugref:9699

File:
1 edited

Legend:

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

    r84145 r84151  
    17881788
    17891789
     1790/*********************************************************************************************************************************
     1791*   signova                                                                                                                      *
     1792*********************************************************************************************************************************/
     1793
     1794/**
     1795 * Reads the OVA and saves the manifest and signed status.
     1796 *
     1797 * @returns VBox status code (fully messaged).
     1798 * @param   pszOva              The name of the OVA.
     1799 * @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.
     1804 */
     1805static int getManifestFromOva(const char *pszOva, unsigned iVerbosity,
     1806                              Utf8Str *pStrName, PRTVFSFILE phVfsManifest, Utf8Str *pStrSignatureName)
     1807{
     1808    /*
     1809     * Clear return values.
     1810     */
     1811    *phVfsManifest = NIL_RTVFSFILE;
     1812    pStrName->setNull();
     1813    pStrSignatureName->setNull();
     1814
     1815    /*
     1816     * Open the file as a tar file system stream.
     1817     */
     1818    RTVFSIOSTREAM hVfsIosOva;
     1819    int rc = RTVfsIoStrmOpenNormal(pszOva, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, &hVfsIosOva);
     1820    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);
     1826    if (RT_FAILURE(rc))
     1827        return RTMsgErrorExitFailure("Failed to open OVA '%s' as a TAR file: %Rrc", pszOva, rc);
     1828
     1829    /*
     1830     * Scan the objects in the stream and locate the manifest and any existing cert file.
     1831     */
     1832    if (iVerbosity >= 2)
     1833        RTMsgInfo("Scanning OVA '%s' for a manifest and signature...", pszOva);
     1834    for (;;)
     1835    {
     1836        /*
     1837         * Retrive the next object.
     1838         */
     1839        char           *pszName;
     1840        RTVFSOBJTYPE    enmType;
     1841        RTVFSOBJ        hVfsObj;
     1842        rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, &enmType, &hVfsObj);
     1843        if (RT_FAILURE(rc))
     1844        {
     1845            if (rc == VERR_EOF)
     1846                rc = VINF_SUCCESS;
     1847            else
     1848                RTMsgError("RTVfsFsStrmNext returned %Rrc", rc);
     1849            break;
     1850        }
     1851
     1852        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);
     1857
     1858        /*
     1859         * Should we process this entry?
     1860         */
     1861        if (   enmType  == RTVFSOBJTYPE_IO_STREAM
     1862            || enmType  == RTVFSOBJTYPE_FILE)
     1863        {
     1864            const char *pszSuffix = RTPathSuffix(pszName);
     1865            if (pszSuffix && RTStrICmpAscii(pszSuffix, ".mf") == 0)
     1866            {
     1867                if (*phVfsManifest != NIL_RTVFSFILE)
     1868                    rc = RTMsgErrorRc(VERR_DUPLICATE, "OVA contains multiple manifests! first: %s  second: %s",
     1869                                      pStrName->c_str(), pszName);
     1870                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                }
     1887            }
     1888            else if (pszSuffix && RTStrICmpAscii(pszSuffix, ".cert") == 0)
     1889            {
     1890                if (iVerbosity >= 2)
     1891                    RTMsgInfo("Found existing signature file: %s", pszName);
     1892                rc = pStrSignatureName->assignNoThrow(pszName);
     1893            }
     1894        }
     1895
     1896        /*
     1897         * Release the current object and string.
     1898         */
     1899        RTVfsObjRelease(hVfsObj);
     1900        RTStrFree(pszName);
     1901        if (RT_FAILURE(rc))
     1902            break;
     1903    }
     1904
     1905    RTVfsFsStrmRelease(hVfsFssIn);
     1906
     1907    /*
     1908     * Complain if no manifest.
     1909     */
     1910    if (RT_SUCCESS(rc) && *phVfsManifest == NIL_RTVFSFILE)
     1911        rc = RTMsgErrorRc(VERR_NOT_FOUND, "The OVA contains no manifest and cannot be signed!");
     1912
     1913    return rc;
     1914}
     1915
     1916
     1917/**
     1918 * Creates a PKCS\#7 signature and appends it to the signature file in PEM
     1919 * format.
     1920 */
     1921static int doAddPkcs7Signature(PCRTCRX509CERTIFICATE pCertificate, RTCRKEY hPrivateKey,
     1922                               unsigned cIntermediateCerts, const char **papszIntermediateCerts,
     1923                               RTCRDIGEST hDigest, PRTERRINFOSTATIC pErrInfo, RTVFSFILE hVfsFileSignature)
     1924{
     1925    RT_NOREF(pCertificate, hPrivateKey, cIntermediateCerts, papszIntermediateCerts, hDigest, pErrInfo, hVfsFileSignature);
     1926    RTPrintf("TODO: doAddPkcs7Signature\n");
     1927    return VINF_SUCCESS;
     1928}
     1929
     1930
     1931/**
     1932 * Appends the certificate in PEM format to the given VFS file.
     1933 */
     1934static int doWriteCertificate(RTVFSFILE hVfsFileSignature, PCRTCRX509CERTIFICATE pCertificate)
     1935{
     1936    RT_NOREF(hVfsFileSignature, pCertificate);
     1937    RTPrintf("TODO: doWriteCertificate\n");
     1938    return VINF_SUCCESS;
     1939}
     1940
     1941
     1942/**
     1943 * Performs the OVA signing, producing an in-memory cert-file.
     1944 */
     1945static int doTheOvaSigning(PCRTCRX509CERTIFICATE pCertificate, RTCRKEY hPrivateKey,
     1946                           const char *pszManifestName, RTVFSFILE hVfsFileManifest,
     1947                           bool fPkcs7, unsigned cIntermediateCerts, const char **papszIntermediateCerts,
     1948                           PRTERRINFOSTATIC pErrInfo, PRTVFSFILE phVfsFileSignature)
     1949{
     1950    /*
     1951     * We currently hardcode the digest algorithm to SHA-256.
     1952     */
     1953    /** @todo fall back on SHA-1 if the key is too small for SHA-256. */
     1954    PCRTASN1OBJID const pObjId  = &pCertificate->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm;
     1955    RTCRDIGEST          hDigest = NIL_RTCRDIGEST;
     1956    int rc = RTCrDigestCreateByType(&hDigest, RTDIGESTTYPE_SHA256);
     1957    if (RT_FAILURE(rc))
     1958        return RTMsgErrorRc(rc, "Failed to create digest for %s: %Rrc", pObjId->szObjId, rc);
     1959
     1960    /* Figure out the digest type name for the .cert file: */
     1961    RTDIGESTTYPE const enmDigestType = RTCrDigestGetType(hDigest);
     1962    const char        *pszDigestType;
     1963    switch (enmDigestType)
     1964    {
     1965        case RTDIGESTTYPE_SHA1:         pszDigestType = "SHA1"; break;
     1966        case RTDIGESTTYPE_SHA256:       pszDigestType = "SHA256"; break;
     1967        case RTDIGESTTYPE_SHA512:       pszDigestType = "SHA512"; break;
     1968        default:
     1969            RTCrDigestRelease(hDigest);
     1970            return RTMsgErrorRc(VERR_INVALID_PARAMETER,
     1971                                "Unsupported digest type: %s", RTCrDigestTypeToName(enmDigestType));
     1972    }
     1973
     1974    /*
     1975     * Digest the manifest file.
     1976     */
     1977    rc = RTCrDigestUpdateFromVfsFile(hDigest, hVfsFileManifest, true /*fRewindFile*/);
     1978    if (RT_SUCCESS(rc))
     1979        rc = RTCrDigestFinal(hDigest, NULL, 0);
     1980    if (RT_SUCCESS(rc))
     1981    {
     1982        /*
     1983         * Sign the digest.  Two passes, first to figure the signature size, the
     1984         * second to do the actual signing.
     1985         */
     1986        PCRTASN1OBJID const   pAlgorithm  = &pCertificate->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm;
     1987        PCRTASN1DYNTYPE const pAlgoParams = &pCertificate->TbsCertificate.SubjectPublicKeyInfo.Algorithm.Parameters;
     1988        size_t cbSignature = 0;
     1989        rc = RTCrPkixPubKeySignDigest(pAlgorithm, hPrivateKey, pAlgoParams, hDigest, 0 /*fFlags*/,
     1990                                      NULL /*pvSignature*/, &cbSignature, RTErrInfoInitStatic(pErrInfo));
     1991        if (rc == VERR_BUFFER_OVERFLOW)
     1992        {
     1993            void *pvSignature = RTMemAllocZ(cbSignature);
     1994            if (pvSignature)
     1995            {
     1996                rc = RTCrPkixPubKeySignDigest(pAlgorithm, hPrivateKey, pAlgoParams, hDigest, 0,
     1997                                              pvSignature, &cbSignature, RTErrInfoInitStatic(pErrInfo));
     1998                if (RT_SUCCESS(rc))
     1999                {
     2000                    /*
     2001                     * Verify the signature using the certificate to make sure we've
     2002                     * been given the right private key.
     2003                     */
     2004                    rc = RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo(&pCertificate->TbsCertificate.SubjectPublicKeyInfo,
     2005                                                                          pvSignature, cbSignature, hDigest,
     2006                                                                          RTErrInfoInitStatic(pErrInfo));
     2007                    if (RT_SUCCESS(rc))
     2008                    {
     2009                        /*
     2010                         * Create the output file.
     2011                         */
     2012                        RTVFSFILE hVfsFileSignature;
     2013                        rc = RTVfsMemFileCreate(NIL_RTVFSIOSTREAM, _8K, &hVfsFileSignature);
     2014                        if (RT_SUCCESS(rc))
     2015                        {
     2016                            rc = RTVfsFilePrintf(hVfsFileSignature, "%s(%s) = %.*Rhxs\n\n",
     2017                                                 pszDigestType, pszManifestName, cbSignature, pvSignature);
     2018                            if (RT_SUCCESS(rc))
     2019                                rc = doWriteCertificate(hVfsFileSignature, pCertificate);
     2020                            else
     2021                                RTMsgError("Failed to produce signature file: %Rrc", rc);
     2022                            if (RT_SUCCESS(rc) && fPkcs7)
     2023                                rc = doAddPkcs7Signature(pCertificate, hPrivateKey, cIntermediateCerts, papszIntermediateCerts,
     2024                                                         hDigest, pErrInfo, hVfsFileSignature);
     2025                            if (RT_SUCCESS(rc))
     2026                            {
     2027                                /*
     2028                                 * Success.
     2029                                 */
     2030                                *phVfsFileSignature = hVfsFileSignature;
     2031                            }
     2032                            else
     2033                                RTVfsFileRelease(hVfsFileSignature);
     2034                        }
     2035                        else
     2036                            RTMsgError("RTVfsMemFileCreate failed: %Rrc", rc);
     2037                    }
     2038                    else
     2039                        RTMsgError("Encountered a problem when validating the signature we just created: %Rrc%#RTeim\n"
     2040                                   "Plase make sure the certificate and private key matches.", rc, &pErrInfo->Core);
     2041                }
     2042                else
     2043                    RTMsgError("2nd RTCrPkixPubKeySignDigest call failed: %Rrc%#RTeim", rc, pErrInfo->Core);
     2044                RTMemFree(pvSignature);
     2045            }
     2046            else
     2047                rc = RTMsgErrorRc(VERR_NO_MEMORY, "Out of memory!");
     2048        }
     2049        else
     2050            RTMsgError("RTCrPkixPubKeySignDigest failed: %Rrc%#RTeim", rc, pErrInfo->Core);
     2051    }
     2052    else
     2053        RTMsgError("Failed to create digest %s: %Rrc", RTCrDigestTypeToName(enmDigestType), rc);
     2054    RTCrDigestRelease(hDigest);
     2055    return rc;
     2056}
     2057
     2058
     2059/**
     2060 * Alters the OVA file, adding (or replacing) the @a pszSignatureName member.
     2061 */
     2062static int updateTheOvaSignature(const char *pszOva, const char *pszSignatureName, RTVFSFILE hVfsFileSignature, bool fIsSigned)
     2063{
     2064    RT_NOREF(pszOva, pszSignatureName, hVfsFileSignature, fIsSigned);
     2065
     2066    RTMsgError("TODO: updateTheOvaSignature");
     2067    return VINF_SUCCESS;
     2068}
     2069
     2070
     2071/**
     2072 * Handles the 'ovasign' command.
     2073 */
    17902074RTEXITCODE handleSignAppliance(HandlerArg *arg)
    17912075{
     
    18032087        { "--intermediate-cert-file",   'i', RTGETOPT_REQ_STRING },
    18042088        { "--force",                    'f', RTGETOPT_REQ_NOTHING },
    1805         { "--out-cert",                 'O', RTGETOPT_REQ_NOTHING },
     2089        { "--verbose",                  'v', RTGETOPT_REQ_NOTHING },
     2090        { "--quiet",                    'q', RTGETOPT_REQ_NOTHING },
    18062091        { "--dry-run",                  'D', RTGETOPT_REQ_NOTHING },
    18072092    };
     
    18192104    const char *apszIntermediateCerts[32];
    18202105    bool        fReSign             = false;
    1821 
    1822     bool        fOutCert            = false;
     2106    unsigned    iVerbosity          = 1;
     2107
    18232108    bool        fDryRun             = false;
    18242109
     
    18722157                break;
    18732158
    1874 
    1875             case 'O':
    1876                 fOutCert = true;
     2159            case 'v':
     2160                iVerbosity++;
     2161                break;
     2162
     2163            case 'q':
     2164                iVerbosity = 0;
    18772165                break;
    18782166
     
    18952183    /* Required paramaters: */
    18962184    if (!pszOva || !*pszOva)
    1897         return RTMsgErrorExit(RTEXITCODE_FAILURE, "No OVA file was specified!");
     2185        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No OVA file was specified!");
    18982186    if (!pszCertificate || !*pszCertificate)
    1899         return RTMsgErrorExit(RTEXITCODE_FAILURE, "No signing certificate (--certificate=<file>) was specified!");
     2187        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No signing certificate (--certificate=<file>) was specified!");
    19002188    if (!pszPrivateKey || !*pszPrivateKey)
    1901         return RTMsgErrorExit(RTEXITCODE_FAILURE, "No signing private key (--private-key=<file>) was specified!");
     2189        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No signing private key (--private-key=<file>) was specified!");
    19022190
    19032191    /* Check that input files exists before we commence: */
    19042192    if (!RTFileExists(pszOva))
    1905         return RTMsgErrorExit(RTEXITCODE_FAILURE, "The specified OVA file was not found: %s", pszOva);
     2193        return RTMsgErrorExitFailure("The specified OVA file was not found: %s", pszOva);
    19062194    if (!RTFileExists(pszCertificate))
    1907         return RTMsgErrorExit(RTEXITCODE_FAILURE, "The specified certificate file was not found: %s", pszCertificate);
     2195        return RTMsgErrorExitFailure("The specified certificate file was not found: %s", pszCertificate);
    19082196    if (!RTFileExists(pszPrivateKey))
    1909         return RTMsgErrorExit(RTEXITCODE_FAILURE, "The specified private key file was not found: %s", pszPrivateKey);
     2197        return RTMsgErrorExitFailure("The specified private key file was not found: %s", pszPrivateKey);
    19102198
    19112199    /*
    1912      *
     2200     * Read the certificate and private key.
    19132201     */
    1914     HRESULT hrc = S_OK;
    1915 
    1916     Utf8Str strManifestData;
    1917     Utf8Str strManifestName;
    1918     Utf8Str strAppliancePath;
    1919     Utf8Str strApplianceFullPath;
    1920 
    1921     char *pszAbsFilePath = RTPathAbsDup(pszOva);
    1922 
    1923     do
    1924     {
    1925 
    1926         if (!RTFileExists(pszAbsFilePath))
    1927             return RTMsgErrorExit(RTEXITCODE_FAILURE, "The OVA package %s wasn't found", pszAbsFilePath);
    1928 
    1929         ComPtr<IAppliance> pAppliance;
    1930         CHECK_ERROR_BREAK(arg->virtualBox, CreateAppliance(pAppliance.asOutParam()));
    1931 
    1932         ComPtr<IProgress> progressRead;
    1933         CHECK_ERROR_BREAK(pAppliance, Read(Bstr(pszAbsFilePath).raw(), progressRead.asOutParam()));
    1934         RTStrFree(pszAbsFilePath);
    1935 
    1936         hrc = showProgress(progressRead);
    1937         CHECK_PROGRESS_ERROR_RET(progressRead, ("Appliance read failed"), RTEXITCODE_FAILURE);
    1938 
    1939         /* fetch the path, there is stuff like username/password removed if any */
    1940         Bstr path;
    1941         CHECK_ERROR_BREAK(pAppliance, COMGETTER(Path)(path.asOutParam()));
    1942 
    1943         strAppliancePath = path;
    1944         strApplianceFullPath = strAppliancePath;
    1945         strAppliancePath.stripFilename();
    1946 
    1947         RTPrintf("The original OVA package folder is %s\n\n", strAppliancePath.c_str());
    1948 
    1949         /* fetch the manifest */
    1950         Bstr manifest;
    1951         Bstr manifestName;
    1952         CHECK_ERROR_BREAK(pAppliance, GetManifest(manifest.asOutParam(), manifestName.asOutParam()));
    1953 
    1954         strManifestData = manifest;
    1955         strManifestName = manifestName;
    1956 
    1957         if (strManifestName.isEmpty() || strManifestData.isEmpty())
    1958         {
    1959             RTPrintf("Manifest file wasn't found in the OVA package %s\n\n", strApplianceFullPath.c_str());
    1960             hrc = E_FAIL;
    1961         }
    1962 
    1963     }while (0);
    1964 
    1965     if (FAILED(hrc))
    1966         return RTEXITCODE_FAILURE;
    1967 
    1968 
    1969     /* Read the private key */
    1970     RTERRINFOSTATIC ErrInfo;
    1971     RTCRKEY         hPrivateKey = NIL_RTCRKEY;
    1972     rc = RTCrKeyCreateFromFile(&hPrivateKey, RTCRPEMREADFILE_F_SENSITIVE, pszPrivateKey,
    1973                                strPrivateKeyPassword.c_str(), RTErrInfoInitStatic(&ErrInfo));
     2202    RTERRINFOSTATIC     ErrInfo;
     2203    RTCRX509CERTIFICATE Certificate;
     2204    rc = RTCrX509Certificate_ReadFromFile(&Certificate, pszCertificate, 0, &g_RTAsn1DefaultAllocator,
     2205                                          RTErrInfoInitStatic(&ErrInfo));
     2206    if (RT_FAILURE(rc))
     2207        return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszCertificate, rc, &ErrInfo.Core);
     2208
     2209    RTCRKEY hPrivateKey = NIL_RTCRKEY;
     2210    rc = RTCrKeyCreateFromFile(&hPrivateKey, 0 /*fFlags*/, pszPrivateKey, strPrivateKeyPassword.c_str(),
     2211                               RTErrInfoInitStatic(&ErrInfo));
    19742212    if (RT_SUCCESS(rc))
    19752213    {
    1976         RTPrintf("Reading the private key from %s was done.\n\n", pszPrivateKey);
    1977 
    1978         /* Read the certificate */
    1979         RTCRX509CERTIFICATE     Certificate;
    1980         rc = RTCrX509Certificate_ReadFromFile(&Certificate, pszCertificate, 0, &g_RTAsn1DefaultAllocator,
    1981                                               RTErrInfoInitStatic(&ErrInfo));
    1982         if (RT_FAILURE(rc))
    1983         {
    1984             RTCrKeyRelease(hPrivateKey);
    1985             return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error reading certificate from %s: %Rrc%#RTeim",
    1986                                   pszCertificate, rc, &ErrInfo.Core);
    1987         }
    1988 
    1989         RTPrintf("Reading the certificate from %s was done.\n\n", pszCertificate);
     2214        if (iVerbosity > 1)
     2215            RTMsgInfo("Successfully read the certificate and private key.");
    19902216
    19912217        /*
    1992          * Get the manifest from Appliance and sign it.
    1993          * We have the private key, the password, the certificate.
    1994          * Also it's needed a digist algorithm SHA1/SHA256/SHA512.
    1995          * OVF2.0 standard proposes to use SHA256.
     2218         * Extract the manifest from the OVA and check whether it is already signed.
    19962219         */
    1997 
    1998         RTDIGESTTYPE digestType = RTDIGESTTYPE_SHA256;
    1999         RTMANIFEST hManifest;
    2000         RTCRDIGEST hDigest;
    2001 
    2002         rc = RTManifestCreate(0 /*fFlags*/, &hManifest);
    2003         if (RT_FAILURE(rc))
    2004         {
    2005             RTCrKeyRelease(hPrivateKey);
    2006             return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error manifest creation: %Rrc", rc);
    2007         }
    2008 
    2009         /* Calc the digest of the manifest using the algorithm found above. */
    2010         rc = RTCrDigestCreateByType(&hDigest, digestType);
     2220        Utf8Str     strManifestName;
     2221        Utf8Str     strSignatureName;
     2222        RTVFSFILE   hVfsFileManifest = NIL_RTVFSFILE;
     2223        rc = getManifestFromOva(pszOva, iVerbosity, &strManifestName, &hVfsFileManifest, &strSignatureName);
    20112224        if (RT_SUCCESS(rc))
    20122225        {
    2013             rc = RTCrDigestUpdate(hDigest, strManifestData.c_str(), strManifestData.length());
    2014             if (RT_SUCCESS(rc))
     2226            bool const fIsSigned = strSignatureName.isNotEmpty();
     2227            if (!fIsSigned || fReSign)
    20152228            {
    2016                 uint8_t const * bHash =  RTCrDigestGetHash(hDigest);
    2017 
    2018                 char szDigest[_4K];
    2019                 rc = RTSha256ToString(bHash, szDigest, sizeof(szDigest));
    2020                 RTPrintf("The digest of manifest is:\n%s\n\n", szDigest);
    2021 
    2022                 PCRTASN1DYNTYPE pParameters = NULL;
    2023 
    2024                 char   signatureBuf[_16K];
    2025                 size_t cbSignature = sizeof(signatureBuf);
    2026                 rc= RTCrPkixPubKeySignDigest(&Certificate.SignatureAlgorithm.Algorithm,
    2027                                               hPrivateKey,
    2028                                               pParameters,
    2029                                               hDigest,
    2030                                               0,
    2031                                               signatureBuf,
    2032                                               &cbSignature,
    2033                                               RTErrInfoInitStatic(&ErrInfo));
    2034                 if (RT_SUCCESS(rc))
     2229                /*
     2230                 * Do the signing and create the signature file.
     2231                 */
     2232                RTVFSFILE hVfsFileSignature = NIL_RTVFSFILE;
     2233                rc = doTheOvaSigning(&Certificate, hPrivateKey, strManifestName.c_str(), hVfsFileManifest,
     2234                                     fPkcs7, cIntermediateCerts, apszIntermediateCerts,
     2235                                     &ErrInfo, &hVfsFileSignature);
     2236
     2237                /*
     2238                 * Construct the signature filename if there isn't one already:
     2239                 */
     2240                if (RT_SUCCESS(rc) && strSignatureName.isEmpty())
    20352241                {
    2036                     char szSignature[_4K];
    2037                     RTStrPrintHexBytes(szSignature, sizeof(szSignature), signatureBuf, cbSignature, 0 /*fFlags*/);
    2038 
    2039                     /* Verify the signature back using the public key information from the certificate */
    2040                     rc = RTCrPkixPubKeyVerifySignedDigestByCertPubKeyInfo(&Certificate.TbsCertificate.SubjectPublicKeyInfo,
    2041                                                                           signatureBuf, cbSignature, hDigest,
    2042                                                                           RTErrInfoInitStatic(&ErrInfo));
    2043                     if (RT_FAILURE(rc))
    2044                     {
    2045                         /* Dont' forget */
    2046                         RTCrDigestRelease(hDigest);
    2047                         RTCrKeyRelease(hPrivateKey);
    2048                         if (rc == VERR_CR_PKIX_SIGNATURE_MISMATCH)
    2049                             return RTMsgErrorExit(RTEXITCODE_FAILURE, "The manifest signature does not match");
    2050 
    2051                         return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error validating the manifest signature (%Rrc%#RTeim)",
    2052                                               rc, &ErrInfo.Core);
    2053                     }
    2054                     RTPrintf("The manifest signature was validated successfully\n\n");
    2055 
     2242                    rc = strSignatureName.assignNoThrow(strManifestName);
     2243                    if (RT_SUCCESS(rc))
     2244                        rc = strSignatureName.stripSuffix().appendNoThrow(".cert");
     2245                }
     2246                if (RT_SUCCESS(rc) && !fDryRun)
     2247                {
    20562248                    /*
    2057                      * Preparing the digest signature according to OVF2.0 standard.
    2058                      * Only SHA1 and SHA256 are supported for now.
     2249                     * Update the OVA.
    20592250                     */
    2060                     Utf8Str strDigestSignature;
    2061 
    2062                     switch (digestType)
    2063                     {
    2064                         case RTDIGESTTYPE_SHA1:
    2065                             strDigestSignature.append("SHA1");
    2066                             break;
    2067                         case RTDIGESTTYPE_SHA256:
    2068                         default:
    2069                             strDigestSignature.append("SHA256");
    2070                             break;
    2071                     }
    2072 
    2073                     strDigestSignature.append('(').append(strManifestName).append(')').append(" = ");
    2074                     strDigestSignature.append(szSignature);
    2075 
    2076                     /*
    2077                      * Especially add a new line character to avoid placing the certificate on the same line
    2078                      * with the digest signature.
    2079                      */
    2080                     strDigestSignature.append('\n');
    2081 
    2082                     RTPrintf("The signed digest is:\n%s\n", strDigestSignature.c_str());
    2083 
    2084                     /* Just stop here in the case of dry-run scenario */
    2085                     if (fDryRun)
    2086                     {
    2087                         /* Dont' forget */
    2088                         RTCrDigestRelease(hDigest);
    2089                         RTCrKeyRelease(hPrivateKey);
    2090                         return RTEXITCODE_SUCCESS;
    2091                     }
    2092 
    2093                     /* Make up the certificate name */
    2094                     const char *pszSuffix = strrchr(strManifestName.c_str(), '.');
    2095                     Utf8Str strOVFCertificateName = Utf8Str(strManifestName.c_str(), pszSuffix - strManifestName.c_str());
    2096                     strOVFCertificateName.append(".cert");
    2097 
    2098                     /* Create a memory I/O stream and write the digest signature and the certificate to it. */
    2099                     RTVFSIOSTREAM hVfsIosOVFCertificate;
    2100 
    2101                     rc = RTVfsMemIoStrmCreate(NIL_RTVFSIOSTREAM, _1K, &hVfsIosOVFCertificate);
    2102                     if (RT_SUCCESS(rc))
    2103                     {
    2104                         size_t cbWritten = 0;
    2105                         rc = RTVfsIoStrmWrite(hVfsIosOVFCertificate, strDigestSignature.c_str(), strDigestSignature.length(),
    2106                                               true /*fBlocking*/, &cbWritten);
    2107                         if (RT_SUCCESS(rc))
    2108                         {
    2109                             Utf8Str strX509CertificateContent;
    2110                             /* Open and read the passed certificate file as a standard file */
    2111                             RTVFSFILE     hVfsOriginalX509Certificate;
    2112                             rc = RTVfsFileOpenNormal(pszCertificate, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE,
    2113                                                      &hVfsOriginalX509Certificate);
    2114                             if (RT_SUCCESS(rc))
    2115                             {
    2116                                 for (;;)
    2117                                 {
    2118                                     char   abBuf[_4K];
    2119                                     size_t cbRead;
    2120                                     rc = RTVfsFileRead(hVfsOriginalX509Certificate, abBuf, sizeof(abBuf), &cbRead);
    2121                                     if (RT_SUCCESS(rc))
    2122                                     {
    2123                                         bool const fEof = rc == VINF_EOF;
    2124                                         strX509CertificateContent.append(abBuf, cbRead);
    2125                                         if (fEof)
    2126                                             break;
    2127                                     }
    2128                                     else
    2129                                         break;
    2130                                 }
    2131                             }
    2132                             else
    2133                                 RTPrintf("Reading the certificate from the file %s failed (%Rrc)", pszCertificate, rc);
    2134 
    2135                             /* Dont' forget */
    2136                             RTVfsFileRelease(hVfsOriginalX509Certificate);
    2137 
    2138                             if (RT_SUCCESS(rc))
    2139                             {
    2140                                 cbWritten = 0;
    2141                                 /* Write out the certificate into the stream */
    2142                                 rc = RTVfsIoStrmWrite(hVfsIosOVFCertificate, strX509CertificateContent.c_str(),
    2143                                                       strX509CertificateContent.length(), true /*fBlocking*/, &cbWritten);
    2144 
    2145                                 if (RT_FAILURE(rc))
    2146                                     RTPrintf("RTVfsIoStrmWrite failed on adding the certificate into the stream (%Rrc)", rc);
    2147                             }
    2148                             else
    2149                                 RTPrintf("Reading the certificate from the file %s failed (%Rrc)", pszCertificate, rc);
    2150                         }
    2151                         else
    2152                             RTPrintf("RTVfsIoStrmWrite failed  on adding the digest into the stream (%Rrc)", rc);
    2153                     }
    2154                     else
    2155                         RTPrintf("RTVfsMemIoStrmCreate failed (%Rrc)", rc);
    2156 
    2157                     if (RT_FAILURE(rc))
    2158                     {
    2159                         /* Dont' forget */
    2160                         RTVfsIoStrmRelease(hVfsIosOVFCertificate);
    2161                         return RTEXITCODE_FAILURE;
    2162                     }
    2163 
    2164 
    2165                     /* Make up new appliance name */
    2166                     const char *pszSuffix1 = strrchr(strManifestName.c_str(), '.');
    2167                     Utf8Str strSignedOVAName(strAppliancePath);
    2168                     strSignedOVAName.append(RTPATH_DELIMITER).append(strManifestName.c_str(),
    2169                                                                      pszSuffix1 - strManifestName.c_str());
    2170                     strSignedOVAName.append("-signed.ova");
    2171 
    2172                     RTPrintf("The path for new OVA signed package is '%s'\n\n", strSignedOVAName.c_str());
    2173 
    2174                     /*
    2175                      * Open new OVA file (it's a standard TAR file) as a file stream
    2176                      */
    2177                     RTVFSIOSTREAM hVfsIosSignedOVAPackage;
    2178                     rc = RTVfsIoStrmOpenNormal(strSignedOVAName.c_str(),
    2179                                                RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
    2180                                                &hVfsIosSignedOVAPackage);
    2181                     if (RT_SUCCESS(rc))
    2182                     {
    2183                         RTVFSFSSTREAM hVfsFssOVADest;
    2184                         rc = RTZipTarFsStreamToIoStream(hVfsIosSignedOVAPackage, RTZIPTARFORMAT_USTAR,
    2185                                                         0 /*fFlags*/, &hVfsFssOVADest);
    2186                         RTVfsIoStrmRelease(hVfsIosSignedOVAPackage);
    2187 
    2188                         if (RT_SUCCESS(rc))
    2189                         {
    2190                             bool fCertPresence = false;
    2191                             RTZipTarFsStreamSetFileMode(hVfsFssOVADest, 0660, 0440);
    2192 
    2193                             /*
    2194                              * Open the original OVA file (it's a standard TAR file) as a file stream
    2195                              */
    2196                             RTVFSIOSTREAM hVfsIosOVASrc;
    2197                             rc = RTVfsIoStrmOpenNormal(strApplianceFullPath.c_str(),
    2198                                                        RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
    2199                                                        &hVfsIosOVASrc);
    2200                             if (RT_SUCCESS(rc))
    2201                             {
    2202                                 RTVFSFSSTREAM hVfsFssOVASrc;
    2203                                 rc = RTZipTarFsStreamFromIoStream(hVfsIosOVASrc, 0 /*fFlags*/, &hVfsFssOVASrc);
    2204                                 /* Dont' forget */
    2205                                 RTVfsIoStrmRelease(hVfsIosOVASrc);
    2206 
    2207                                 if (RT_SUCCESS(rc))
    2208                                 {
    2209                                     for (;;)
    2210                                     {
    2211                                         char *pszName = NULL;
    2212                                         RTVFSOBJTYPE enmType;
    2213                                         RTVFSOBJ     hVfsObj;
    2214                                         hrc = S_OK;
    2215                                         rc = RTVfsFsStrmNext(hVfsFssOVASrc, &pszName, &enmType, &hVfsObj);
    2216                                         if (RT_FAILURE(rc))
    2217                                         {
    2218                                             if (rc != VERR_EOF)
    2219                                                 RTPrintf("Error reading the OVA file '%s' (%Rrc)",
    2220                                                          strApplianceFullPath.c_str(), rc);
    2221                                             else
    2222                                                 rc = VINF_SUCCESS;
    2223 
    2224                                             break;
    2225                                         }
    2226 
    2227                                         /*
    2228                                          * in the case when the certificate has been already presented in the OVA package
    2229                                          */
    2230                                         if (strOVFCertificateName.equals(pszName))
    2231                                         {
    2232                                             RTPrintf("Some certificate has already presented in the OVA package\n\n");
    2233                                             fCertPresence = true;//remember for later usage
    2234                                             /* if the flag --force has been set just skip it and go further */
    2235                                             if (fReSign)
    2236                                                 continue;
    2237                                         }
    2238 
    2239                                         /* Read the input stream and add the content into the output stream */
    2240                                         rc = RTVfsFsStrmAdd(hVfsFssOVADest, pszName, hVfsObj, 0 /*fFlags*/);
    2241                                         if (RT_FAILURE(rc))
    2242                                             RTPrintf("RTVfsFsStrmAdd failed for the %s (%Rrc)", pszName, rc);
    2243 
    2244                                         /* Free resources */
    2245                                         RTVfsObjRelease(hVfsObj);
    2246                                         RTStrFree(pszName);
    2247 
    2248                                         if (RT_FAILURE(rc))
    2249                                         {
    2250                                             RTPrintf("Error writing to new OVA package '%s' (%Rrc)",
    2251                                                      strSignedOVAName.c_str(), rc);
    2252                                             break;
    2253                                         }
    2254                                     }
    2255 
    2256                                     /* Dont' forget */
    2257                                     RTVfsFsStrmRelease(hVfsFssOVASrc);
    2258                                 }
    2259                                 else
    2260                                     RTPrintf("Error reading the OVA file '%s' (%Rrc)", strApplianceFullPath.c_str(), rc);
    2261                             }
    2262                             else
    2263                                 RTPrintf("Error opening the OVA file '%s' (%Rrc)", strApplianceFullPath.c_str(), rc);
    2264 
    2265                             /*
    2266                              * Now add the digest signature into new OVA package
    2267                              */
    2268                             if (RT_SUCCESS(rc))
    2269                             {
    2270                                 /* Add only if no cetificate or the flag fReSign was set and certificate is presented */
    2271                                 if ( !fCertPresence || (fCertPresence && fReSign) )
    2272                                 {
    2273                                     size_t cbWritten;
    2274                                     size_t cbRead;
    2275                                     RTFOFF off = RTVfsIoStrmTell(hVfsIosOVFCertificate);
    2276                                     void *pvBuf = RTMemAlloc(off);
    2277                                     size_t cbBuf = off;
    2278 
    2279                                     rc = RTVfsIoStrmReadAt(hVfsIosOVFCertificate, 0, pvBuf, cbBuf,
    2280                                                            true /*fBlocking*/, &cbRead);
    2281                                     if (RT_SUCCESS(rc))
    2282                                     {
    2283                                         RTVFSIOSTREAM hVfsIosSrc;
    2284                                         rc = RTVfsIoStrmFromBuffer(RTFILE_O_READ, pvBuf, cbRead, &hVfsIosSrc);
    2285                                         RTVFSOBJ hVfsObjCert = RTVfsObjFromIoStream(hVfsIosSrc);
    2286                                         RTVfsIoStrmRelease(hVfsIosSrc);
    2287 
    2288                                         RTZipTarFsStreamSetOwner(hVfsFssOVADest, VBOX_VERSION_MAJOR, "vboxovf20");
    2289                                         RTZipTarFsStreamSetGroup(hVfsFssOVADest, VBOX_VERSION_MINOR,
    2290                                                                  "vbox_v" RT_XSTR(VBOX_VERSION_MAJOR) "."
    2291                                                                  RT_XSTR(VBOX_VERSION_MINOR) "."
    2292                                                                  RT_XSTR(VBOX_VERSION_BUILD) "r"
    2293                                                                  RT_XSTR(VBOX_SVN_REV) "\0");
    2294 
    2295                                         /* Write out the certificate into the stream */
    2296                                         rc = RTVfsFsStrmAdd(hVfsFssOVADest, strOVFCertificateName.c_str(),
    2297                                                             hVfsObjCert, 0 /*fFlags*/);
    2298                                         if (RT_FAILURE(rc))
    2299                                             RTPrintf("RTVfsFsStrmAdd failed for the %s (%Rrc)",
    2300                                                      strOVFCertificateName.c_str(), rc);
    2301 
    2302                                         /* Dont' forget */
    2303                                         RTVfsObjRelease(hVfsObjCert);
    2304 
    2305                                         /* Save the OVA certificate file next to the original OVA package */
    2306                                         if (fOutCert)
    2307                                         {
    2308                                             Utf8Str strCertificateFileFullPath(strAppliancePath);
    2309                                             strCertificateFileFullPath.append(RTPATH_DELIMITER).
    2310                                                                        append(strOVFCertificateName.c_str());
    2311 
    2312                                             RTVFSIOSTREAM hVfsIosCertFile;
    2313                                             rc = RTVfsIoStrmOpenNormal(strCertificateFileFullPath.c_str(),
    2314                                                                        RTFILE_O_CREATE_REPLACE |
    2315                                                                        RTFILE_O_WRITE |
    2316                                                                        RTFILE_O_DENY_NONE,
    2317                                                                        &hVfsIosCertFile);
    2318                                             if (RT_SUCCESS(rc))
    2319                                             {
    2320                                                 /* Write out the certificate into the file */
    2321                                                 rc = RTVfsIoStrmWrite(hVfsIosCertFile, pvBuf,
    2322                                                                       cbBuf, true /*fBlocking*/, &cbWritten);
    2323                                                 if (RT_FAILURE(rc))
    2324                                                     RTPrintf("Error writing the certificate file '%s' (%Rrc)",
    2325                                                              strCertificateFileFullPath.c_str(), rc);
    2326 
    2327                                                 /* Dont' forget */
    2328                                                 RTVfsIoStrmFlush(hVfsIosCertFile);
    2329                                                 RTVfsIoStrmRelease(hVfsIosCertFile);
    2330                                             }
    2331                                             else
    2332                                                 RTPrintf("Error opening the certificate file '%s' (%Rrc)",
    2333                                                          strCertificateFileFullPath.c_str(), rc);
    2334                                         }
    2335                                     }
    2336                                     else
    2337                                         RTPrintf("Error writing the certificate file '%s' (%Rrc)",
    2338                                                  strOVFCertificateName.c_str(), rc);
    2339 
    2340                                     /* Dont' forget */
    2341                                     RTMemFree(pvBuf);
    2342                                 }
    2343                             }
    2344 
    2345                             /* Dont' forget */
    2346                             RTVfsFsStrmRelease(hVfsFssOVADest);
    2347                         }
    2348                         else
    2349                             RTPrintf("Failed create TAR creator for '%s' (%Rrc)", strSignedOVAName.c_str(), rc);
    2350                     }
    2351                     else
    2352                         RTPrintf("Error opening new OVA signed package '%s'\n", strSignedOVAName.c_str());
    2353 
    2354                     /* Dont' forget */
    2355                      RTVfsIoStrmRelease(hVfsIosOVFCertificate);
     2251                    rc = updateTheOvaSignature(pszOva, strSignatureName.c_str(), hVfsFileSignature, fIsSigned);
    23562252                }
    2357                 else
    2358                     RTPrintf("Error signing the digest of manifest: %Rrc", rc);
    23592253            }
    23602254            else
    2361                 RTPrintf("Error updating the digest: %Rrc", rc);
     2255                rc = RTMsgErrorRc(VERR_ALREADY_EXISTS,
     2256                                  "The OVA is already signed! (Use the --force option to force re-signing it.)");
    23622257        }
    2363         else
    2364             RTPrintf("Error digest creation: %Rrc", rc);
    2365 
    2366         /* Don't forget */
    2367         RTCrDigestRelease(hDigest);
    23682258        RTCrKeyRelease(hPrivateKey);
    23692259    }
    23702260    else
    23712261        RTPrintf("Error reading the private key from %s: %Rrc%#RTeim", pszPrivateKey, rc, &ErrInfo.Core);
    2372 
    2373     /* Dont' forget */
    2374     if (RT_SUCCESS(rc))
    2375         hrc = S_OK;
    2376 
    2377     return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     2262    RTCrX509Certificate_Delete(&Certificate);
     2263
     2264    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    23782265}
    23792266
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