VirtualBox

Changeset 84312 in vbox


Ignore:
Timestamp:
May 14, 2020 5:46:45 PM (5 years ago)
Author:
vboxsync
Message:

Main/ApplianceImport: Read the PKCS7/CMS signature when present. Implemented the basic validation, but the certificate trust stuff is still left to be done. bugref:9699

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/ApplianceImpl.h

    r84153 r84312  
    172172    HRESULT i_readSignatureFile(TaskOVF *pTask, RTVFSIOSTREAM hIosCert, const char *pszSubFileNm);
    173173    HRESULT i_readTailProcessing(TaskOVF *pTask);
     174    HRESULT i_readTailProcessingSignedData(PRTERRINFOSTATIC pErrInfo);
     175    HRESULT i_readTailProcessingGetManifestData(void **ppvData, size_t *pcbData);
    174176    HRESULT i_gettingCloudData(TaskCloud *pTask);
    175177
  • trunk/src/VBox/Main/include/ApplianceImplPrivate.h

    r84153 r84312  
    3434#include <iprt/vfs.h>
    3535#include <iprt/crypto/x509.h>
     36#include <iprt/crypto/pkcs7.h>
    3637
    3738////////////////////////////////////////////////////////////////////////////////
     
    6465};
    6566
    66 // opaque private instance data of Appliance class
     67/**
     68 * opaque private instance data of Appliance class
     69 */
    6770struct Appliance::Data
    6871{
     
    8689      , cbSignedDigest(0)
    8790      , enmSignedDigestType(RTDIGESTTYPE_INVALID)
     91      , fContentInfoLoaded(false)
     92      , fContentInfoValid(false)
     93      , fContentInfoSameCert(false)
     94      , fContentInfoValidSignature(false)
    8895      , fExportISOImages(false)
    8996      , pReader(NULL)
     
    94101      , m_cPwProvided(0)
    95102    {
     103        RT_ZERO(SignerCert);
     104        RT_ZERO(ContentInfo);
    96105    }
    97106
     
    138147            fSignerCertLoaded = false;
    139148        }
     149        RT_ZERO(SignerCert);
    140150        enmSignedDigestType      = RTDIGESTTYPE_INVALID;
    141151        fCertificateIsSelfSigned = false;
     
    148158        ptrCertificateInfo.setNull();
    149159        strCertError.setNull();
     160        if (fContentInfoLoaded)
     161        {
     162            RTCrPkcs7ContentInfo_Delete(&ContentInfo);
     163            fContentInfoLoaded = false;
     164        }
     165        RT_ZERO(ContentInfo);
    150166    }
    151167
     
    204220     *  successfully loaded certificate. */
    205221    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;
    206241    /** @} */
    207242
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r84265 r84312  
    26522652    /*
    26532653     * Parse the signing certificate. Unlike the manifest parser we use below,
    2654      * this API ignores parse of the file that aren't relevant.
     2654     * this API ignores parts of the file that aren't relevant.
    26552655     */
    26562656    RTERRINFOSTATIC StaticErrInfo;
     
    26812681            pszSplit = (char *)pvSignature + cbSignature;
    26822682        }
     2683        char const chSaved = *pszSplit;
    26832684        *pszSplit = '\0';
    26842685
     
    27582759        else
    27592760            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        }
    27602777    }
    27612778    else if (vrc == VERR_NOT_FOUND || vrc == VERR_EOF)
     
    27842801     * Parse and validate the signature file.
    27852802     *
    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.
    27892814     */
    27902815    if (m->pbSignedDigest)
     
    28372862
    28382863        /*
     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        /*
    28392872         * Validate the certificate.
    28402873         *
    2841          * We don't fail here on if we cannot validate the certificate, we postpone
     2874         * We don't fail here if we cannot validate the certificate, we postpone
    28422875         * that till the import stage, so that we can allow the user to ignore it.
    28432876         *
     
    28702903        Assert(m->fCertificateIsSelfSigned == RTCrX509Certificate_IsSelfSigned(&m->SignerCert));
    28712904
    2872         HRESULT hrc2 = S_OK;
     2905        hrc2 = S_OK;
    28732906        if (m->fCertificateIsSelfSigned)
    28742907        {
     
    29042937            else
    29052938            {
    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);
    29112943            }
    29122944        }
     
    30363068}
    30373069
     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 */
     3084HRESULT 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 */
     3115HRESULT 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}
    30383190
    30393191
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