Changeset 84151 in vbox for trunk/src/VBox/Frontends/VBoxManage
- Timestamp:
- May 5, 2020 7:25:25 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp
r84145 r84151 1788 1788 1789 1789 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 */ 1805 static 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 */ 1921 static 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 */ 1934 static 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 */ 1945 static 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 */ 2062 static 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 */ 1790 2074 RTEXITCODE handleSignAppliance(HandlerArg *arg) 1791 2075 { … … 1803 2087 { "--intermediate-cert-file", 'i', RTGETOPT_REQ_STRING }, 1804 2088 { "--force", 'f', RTGETOPT_REQ_NOTHING }, 1805 { "--out-cert", 'O', RTGETOPT_REQ_NOTHING }, 2089 { "--verbose", 'v', RTGETOPT_REQ_NOTHING }, 2090 { "--quiet", 'q', RTGETOPT_REQ_NOTHING }, 1806 2091 { "--dry-run", 'D', RTGETOPT_REQ_NOTHING }, 1807 2092 }; … … 1819 2104 const char *apszIntermediateCerts[32]; 1820 2105 bool fReSign = false; 1821 1822 bool fOutCert = false; 2106 unsigned iVerbosity = 1; 2107 1823 2108 bool fDryRun = false; 1824 2109 … … 1872 2157 break; 1873 2158 1874 1875 case 'O': 1876 fOutCert = true; 2159 case 'v': 2160 iVerbosity++; 2161 break; 2162 2163 case 'q': 2164 iVerbosity = 0; 1877 2165 break; 1878 2166 … … 1895 2183 /* Required paramaters: */ 1896 2184 if (!pszOva || !*pszOva) 1897 return RTMsgErrorExit(RTEXITCODE_ FAILURE, "No OVA file was specified!");2185 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No OVA file was specified!"); 1898 2186 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!"); 1900 2188 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!"); 1902 2190 1903 2191 /* Check that input files exists before we commence: */ 1904 2192 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); 1906 2194 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); 1908 2196 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); 1910 2198 1911 2199 /* 1912 * 2200 * Read the certificate and private key. 1913 2201 */ 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)); 1974 2212 if (RT_SUCCESS(rc)) 1975 2213 { 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."); 1990 2216 1991 2217 /* 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. 1996 2219 */ 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); 2011 2224 if (RT_SUCCESS(rc)) 2012 2225 { 2013 rc = RTCrDigestUpdate(hDigest, strManifestData.c_str(), strManifestData.length());2014 if ( RT_SUCCESS(rc))2226 bool const fIsSigned = strSignatureName.isNotEmpty(); 2227 if (!fIsSigned || fReSign) 2015 2228 { 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()) 2035 2241 { 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 { 2056 2248 /* 2057 * Preparing the digest signature according to OVF2.0 standard. 2058 * Only SHA1 and SHA256 are supported for now. 2249 * Update the OVA. 2059 2250 */ 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); 2356 2252 } 2357 else2358 RTPrintf("Error signing the digest of manifest: %Rrc", rc);2359 2253 } 2360 2254 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.)"); 2362 2257 } 2363 else2364 RTPrintf("Error digest creation: %Rrc", rc);2365 2366 /* Don't forget */2367 RTCrDigestRelease(hDigest);2368 2258 RTCrKeyRelease(hPrivateKey); 2369 2259 } 2370 2260 else 2371 2261 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; 2378 2265 } 2379 2266
Note:
See TracChangeset
for help on using the changeset viewer.