Changeset 84312 in vbox
- Timestamp:
- May 14, 2020 5:46:45 PM (5 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/include/ApplianceImpl.h
r84153 r84312 172 172 HRESULT i_readSignatureFile(TaskOVF *pTask, RTVFSIOSTREAM hIosCert, const char *pszSubFileNm); 173 173 HRESULT i_readTailProcessing(TaskOVF *pTask); 174 HRESULT i_readTailProcessingSignedData(PRTERRINFOSTATIC pErrInfo); 175 HRESULT i_readTailProcessingGetManifestData(void **ppvData, size_t *pcbData); 174 176 HRESULT i_gettingCloudData(TaskCloud *pTask); 175 177 -
trunk/src/VBox/Main/include/ApplianceImplPrivate.h
r84153 r84312 34 34 #include <iprt/vfs.h> 35 35 #include <iprt/crypto/x509.h> 36 #include <iprt/crypto/pkcs7.h> 36 37 37 38 //////////////////////////////////////////////////////////////////////////////// … … 64 65 }; 65 66 66 // opaque private instance data of Appliance class 67 /** 68 * opaque private instance data of Appliance class 69 */ 67 70 struct Appliance::Data 68 71 { … … 86 89 , cbSignedDigest(0) 87 90 , enmSignedDigestType(RTDIGESTTYPE_INVALID) 91 , fContentInfoLoaded(false) 92 , fContentInfoValid(false) 93 , fContentInfoSameCert(false) 94 , fContentInfoValidSignature(false) 88 95 , fExportISOImages(false) 89 96 , pReader(NULL) … … 94 101 , m_cPwProvided(0) 95 102 { 103 RT_ZERO(SignerCert); 104 RT_ZERO(ContentInfo); 96 105 } 97 106 … … 138 147 fSignerCertLoaded = false; 139 148 } 149 RT_ZERO(SignerCert); 140 150 enmSignedDigestType = RTDIGESTTYPE_INVALID; 141 151 fCertificateIsSelfSigned = false; … … 148 158 ptrCertificateInfo.setNull(); 149 159 strCertError.setNull(); 160 if (fContentInfoLoaded) 161 { 162 RTCrPkcs7ContentInfo_Delete(&ContentInfo); 163 fContentInfoLoaded = false; 164 } 165 RT_ZERO(ContentInfo); 150 166 } 151 167 … … 204 220 * successfully loaded certificate. */ 205 221 ComObjPtr<Certificate> ptrCertificateInfo; 222 223 /** The PKCS\#7/CMS signed data signing manifest, optional VBox extension. 224 * This contains at least one signature using the same certificate as above 225 * (SignerCert), but should preferrably use a different digest. The PKCS\#7/CMS 226 * format is a lot more versatile, allow multiple signatures using different 227 * digests and certificates, optionally with counter signed timestamps. 228 * Additional intermediate certificates can also be shipped, helping to bridge 229 * the gap to a trusted root certificate installed on the recieving system. */ 230 RTCRPKCS7CONTENTINFO ContentInfo; 231 /** Set if the ContentInfo member contains usable data. */ 232 bool fContentInfoLoaded; 233 /** Set if the ContentInfo member validated okay (says nothing about the 234 * signature or certificates within it). */ 235 bool fContentInfoValid; 236 /** Set if the ContentInfo member is using the SignerCert too. */ 237 bool fContentInfoSameCert; 238 /** Set if the ContentInfo member contains a valid signature (not saying 239 * anything about valid signing certificates). */ 240 bool fContentInfoValidSignature; 206 241 /** @} */ 207 242 -
trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp
r84265 r84312 2652 2652 /* 2653 2653 * Parse the signing certificate. Unlike the manifest parser we use below, 2654 * this API ignores par seof the file that aren't relevant.2654 * this API ignores parts of the file that aren't relevant. 2655 2655 */ 2656 2656 RTERRINFOSTATIC StaticErrInfo; … … 2681 2681 pszSplit = (char *)pvSignature + cbSignature; 2682 2682 } 2683 char const chSaved = *pszSplit; 2683 2684 *pszSplit = '\0'; 2684 2685 … … 2758 2759 else 2759 2760 hrc = E_OUTOFMEMORY; 2761 2762 /* 2763 * Look for the additional for PKCS#7/CMS signature we produce when we sign stuff. 2764 */ 2765 if (SUCCEEDED(hrc)) 2766 { 2767 *pszSplit = chSaved; 2768 vrc = RTCrPkcs7_ReadFromBuffer(&m->ContentInfo, pvSignature, cbSignature, RTCRPKCS7_READ_F_PEM_ONLY, 2769 &g_RTAsn1DefaultAllocator, NULL /*pfCmsLabeled*/, 2770 RTErrInfoInitStatic(&StaticErrInfo), pszSubFileNm); 2771 if (RT_SUCCESS(vrc)) 2772 m->fContentInfoLoaded = true; 2773 else if (vrc != VERR_NOT_FOUND) 2774 hrc = setErrorVrc(vrc, tr("Error reading the PKCS#7/CMS signature from '%s' for '%s' (%Rrc): %s"), 2775 pszSubFileNm, pTask->locInfo.strPath.c_str(), vrc, StaticErrInfo.Core.pszMsg); 2776 } 2760 2777 } 2761 2778 else if (vrc == VERR_NOT_FOUND || vrc == VERR_EOF) … … 2784 2801 * Parse and validate the signature file. 2785 2802 * 2786 * The signature file has two parts, manifest part and a PEM encoded 2787 * certificate. The former contains an entry for the manifest file with a 2788 * digest that is encrypted with the certificate in the latter part. 2803 * The signature file nominally has two parts, manifest part and a PEM 2804 * encoded certificate. The former contains an entry for the manifest file 2805 * with a digest that is encrypted with the certificate in the latter part. 2806 * 2807 * When an appliance is signed by VirtualBox, a PKCS#7/CMS signedData part 2808 * is added by default, supplying more info than the bits mandated by the 2809 * OVF specs. We will validate both the signedData and the standard OVF 2810 * signature. Another requirement is that the first signedData signer 2811 * uses the same certificate as the regular OVF signature, allowing us to 2812 * only do path building for the signedData with the additional info it 2813 * ships with. 2789 2814 */ 2790 2815 if (m->pbSignedDigest) … … 2837 2862 2838 2863 /* 2864 * If we have a PKCS#7/CMS signature, validate it and check that the 2865 * certificate matches the first signerInfo entry. 2866 */ 2867 HRESULT hrc2 = i_readTailProcessingSignedData(&StaticErrInfo); 2868 if (FAILED(hrc2) && SUCCEEDED(hrc)) 2869 hrc = hrc2; 2870 2871 /* 2839 2872 * Validate the certificate. 2840 2873 * 2841 * We don't fail here onif we cannot validate the certificate, we postpone2874 * We don't fail here if we cannot validate the certificate, we postpone 2842 2875 * that till the import stage, so that we can allow the user to ignore it. 2843 2876 * … … 2870 2903 Assert(m->fCertificateIsSelfSigned == RTCrX509Certificate_IsSelfSigned(&m->SignerCert)); 2871 2904 2872 HRESULThrc2 = S_OK;2905 hrc2 = S_OK; 2873 2906 if (m->fCertificateIsSelfSigned) 2874 2907 { … … 2904 2937 else 2905 2938 { 2906 try { m->strCertError = Utf8StrFmt(tr("Verification of the self signed certificate failed (%Rrc, %s)"), 2907 vrc, StaticErrInfo.Core.pszMsg); } 2908 catch (...) { AssertFailed(); } 2909 i_addWarning(tr("Verification of the self signed certificate used to sign '%s' failed (%Rrc): %s"), 2910 pTask->locInfo.strPath.c_str(), vrc, StaticErrInfo.Core.pszMsg); 2939 m->strCertError.printfNoThrow(tr("Verification of the self signed certificate failed (%Rrc%#RTeim)"), 2940 vrc, &StaticErrInfo.Core); 2941 i_addWarning(tr("Verification of the self signed certificate used to sign '%s' failed (%Rrc)%RTeim"), 2942 pTask->locInfo.strPath.c_str(), vrc, &StaticErrInfo.Core); 2911 2943 } 2912 2944 } … … 3036 3068 } 3037 3069 3070 ///** @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK, Dummy.} */ 3071 //static DECLCALLBACK(int) applianceVerifyCertDummyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, 3072 // uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo) 3073 //{ 3074 // RT_NOREF(pCert, hCertPaths, fFlags, pvUser, pErrInfo); 3075 // return VINF_SUCCESS; 3076 //} 3077 3078 /** 3079 * Reads hMemFileTheirManifest into a memory buffer so it can be passed to 3080 * RTCrPkcs7VerifySignedDataWithExternalData. 3081 * 3082 * Use RTMemTmpFree to free the memory. 3083 */ 3084 HRESULT Appliance::i_readTailProcessingGetManifestData(void **ppvData, size_t *pcbData) 3085 { 3086 uint64_t cbData; 3087 int vrc = RTVfsFileQuerySize(m->hMemFileTheirManifest, &cbData); 3088 AssertRCReturn(vrc, setErrorVrc(vrc, "RTVfsFileQuerySize")); 3089 3090 void *pvData = RTMemTmpAllocZ((size_t)cbData); 3091 AssertPtrReturn(pvData, E_OUTOFMEMORY); 3092 3093 vrc = RTVfsFileReadAt(m->hMemFileTheirManifest, 0, pvData, (size_t)cbData, NULL); 3094 AssertRCReturnStmt(vrc, RTMemTmpFree(pvData), setErrorVrc(vrc, "RTVfsFileReadAt")); 3095 3096 *pcbData = (size_t)cbData; 3097 *ppvData = pvData; 3098 return S_OK; 3099 } 3100 3101 /** 3102 * Worker for i_readTailProcessing that validates the signedData. 3103 * 3104 * If we have a PKCS#7/CMS signature: 3105 * - validate it 3106 * - check that the OVF certificate matches the first signerInfo entry 3107 * - verify the signature, but leave the certificate path validation for 3108 * later. 3109 * 3110 * @param pErrInfo Static error info buffer (not for returning, just for 3111 * avoiding wasting stack). 3112 * @returns COM status. 3113 * @throws Nothing! 3114 */ 3115 HRESULT Appliance::i_readTailProcessingSignedData(PRTERRINFOSTATIC pErrInfo) 3116 { 3117 m->fContentInfoValid = false; 3118 m->fContentInfoSameCert = false; 3119 m->fContentInfoValidSignature = false; 3120 3121 if (!m->fContentInfoLoaded) 3122 return S_OK; 3123 3124 /* 3125 * Validate it. 3126 */ 3127 HRESULT hrc = S_OK; 3128 PCRTCRPKCS7SIGNEDDATA pSignedData = m->ContentInfo.u.pSignedData; 3129 if (!RTCrPkcs7ContentInfo_IsSignedData(&m->ContentInfo)) 3130 i_addWarning(tr("Invalid PKCS#7/CMS type: %s, expected %s (signedData)"), 3131 m->ContentInfo.ContentType.szObjId, RTCRPKCS7SIGNEDDATA_OID); 3132 else if (RTAsn1ObjId_CompareWithString(&pSignedData->ContentInfo.ContentType, RTCR_PKCS7_DATA_OID) != 0) 3133 i_addWarning(tr("Invalid PKCS#7/CMS inner type: %s, expected %s (data)"), 3134 pSignedData->ContentInfo.ContentType.szObjId, RTCR_PKCS7_DATA_OID); 3135 else if (RTAsn1OctetString_IsPresent(&pSignedData->ContentInfo.Content)) 3136 i_addWarning(tr("Invalid PKCS#7/CMS data: embedded (%u bytes), expected external"), 3137 pSignedData->ContentInfo.Content.Asn1Core.cb); 3138 else if (pSignedData->SignerInfos.cItems == 0) 3139 i_addWarning(tr("Invalid PKCS#7/CMS: No signers")); 3140 else 3141 { 3142 m->fContentInfoValid = true; 3143 3144 /* 3145 * Same certificate as the OVF signature? 3146 */ 3147 PCRTCRPKCS7SIGNERINFO pSignerInfo = pSignedData->SignerInfos.papItems[0]; 3148 if ( RTCrX509Name_Compare(&pSignerInfo->IssuerAndSerialNumber.Name, &m->SignerCert.TbsCertificate.Issuer) == 0 3149 && RTAsn1Integer_Compare(&pSignerInfo->IssuerAndSerialNumber.SerialNumber, 3150 &m->SignerCert.TbsCertificate.SerialNumber) == 0) 3151 m->fContentInfoSameCert = true; 3152 else 3153 i_addWarning(tr("Invalid PKCS#7/CMS: Using a different certificate")); 3154 3155 /* 3156 * Then perform a validation of the signatures, but first without 3157 * validating the certificate trust paths yet. 3158 */ 3159 RTCRSTORE hTrustedCerts = NIL_RTCRSTORE; 3160 int vrc = RTCrStoreCreateInMem(&hTrustedCerts, 1); 3161 AssertRCReturn(vrc, setErrorVrc(vrc, tr("RTCrStoreCreateInMem failed: %Rrc"), vrc)); 3162 3163 vrc = RTCrStoreCertAddX509(hTrustedCerts, 0, &m->SignerCert, RTErrInfoInitStatic(pErrInfo)); 3164 if (RT_SUCCESS(vrc)) 3165 { 3166 void *pvData = NULL; 3167 size_t cbData = 0; 3168 hrc = i_readTailProcessingGetManifestData(&pvData, &cbData); 3169 if (SUCCEEDED(hrc)) 3170 { 3171 RTTIMESPEC Now; 3172 vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo, RTCRPKCS7VERIFY_SD_F_TRUST_ALL_CERTS, 3173 NIL_RTCRSTORE /*hAdditionalCerts*/, hTrustedCerts, 3174 RTTimeNow(&Now), NULL /*pfnVerifyCert*/, NULL /*pvUser*/, 3175 pvData, cbData, RTErrInfoInitStatic(pErrInfo)); 3176 if (RT_SUCCESS(vrc)) 3177 m->fContentInfoValidSignature = true; 3178 else 3179 i_addWarning(tr("Failed to validate PKCS#7/CMS signature: %Rrc%RTeim"), vrc, &pErrInfo->Core); 3180 RTMemTmpFree(pvData); 3181 } 3182 } 3183 else 3184 hrc = setErrorVrc(vrc, tr("RTCrStoreCertAddX509 failed: %Rrc%RTeim"), vrc, &pErrInfo->Core); 3185 RTCrStoreRelease(hTrustedCerts); 3186 } 3187 3188 return hrc; 3189 } 3038 3190 3039 3191
Note:
See TracChangeset
for help on using the changeset viewer.