VirtualBox

Changeset 84340 in vbox


Ignore:
Timestamp:
May 18, 2020 5:37:30 PM (5 years ago)
Author:
vboxsync
Message:

Main/Appliance: Implemented verifying PKCS#7/CMS signing certificates. Needs proper testing, though. bugref:9699

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

Legend:

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

    r84312 r84340  
    172172    HRESULT i_readSignatureFile(TaskOVF *pTask, RTVFSIOSTREAM hIosCert, const char *pszSubFileNm);
    173173    HRESULT i_readTailProcessing(TaskOVF *pTask);
     174    HRESULT i_readTailProcessingGetManifestData(void **ppvData, size_t *pcbData);
    174175    HRESULT i_readTailProcessingSignedData(PRTERRINFOSTATIC pErrInfo);
    175     HRESULT i_readTailProcessingGetManifestData(void **ppvData, size_t *pcbData);
     176    HRESULT i_readTailProcessingVerifySelfSignedOvfCert(TaskOVF *pTask, RTCRSTORE hTrustedCerts, PRTERRINFOSTATIC pErrInfo);
     177    HRESULT i_readTailProcessingVerifyIssuedOvfCert(TaskOVF *pTask, RTCRSTORE hTrustedStore, PRTERRINFOSTATIC pErrInfo);
     178    HRESULT i_readTailProcessingVerifyContentInfoCerts(void const *pvData, size_t cbData,
     179                                                       RTCRSTORE hTrustedStore, PRTERRINFOSTATIC pErrInfo);
     180    HRESULT i_readTailProcessingVerifyAnalyzeSignerInfo(void const *pvData, size_t cbData, RTCRSTORE hTrustedStore,
     181                                                        uint32_t iSigner, PRTTIMESPEC pNow, int vrc,
     182                                                        PRTERRINFOSTATIC pErrInfo, PRTCRSTORE phTrustedStore2);
     183    HRESULT i_readTailProcessingVerifyContentInfoFailOne(const char *pszSignature, int vrc, PRTERRINFOSTATIC pErrInfo);
     184
    176185    HRESULT i_gettingCloudData(TaskCloud *pTask);
    177 
    178186    /** @}  */
    179187
  • trunk/src/VBox/Main/include/ApplianceImplPrivate.h

    r84312 r84340  
    9090      , enmSignedDigestType(RTDIGESTTYPE_INVALID)
    9191      , fContentInfoLoaded(false)
    92       , fContentInfoValid(false)
     92      , fContentInfoOkay(false)
    9393      , fContentInfoSameCert(false)
    9494      , fContentInfoValidSignature(false)
     
    231231    /** Set if the ContentInfo member contains usable data. */
    232232    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. */
     233    /** Set by read() if the ContentInfo member checked out okay (says nothing about
     234     *  the signature or certificates within it). */
     235    bool                fContentInfoOkay;
     236    /** Set by read() if the ContentInfo member is using the SignerCert too. */
    237237    bool                fContentInfoSameCert;
    238     /** Set if the ContentInfo member contains a valid signature (not saying
    239      * anything about valid signing certificates). */
     238    /** Set by read() if the ContentInfo member contains valid signatures (not
     239     * saying anything about valid signing certificates). */
    240240    bool                fContentInfoValidSignature;
     241    /** Set by read() if we've already verified the signed data signature(s). */
     242    bool                fContentInfoDoneVerification;
     243
     244    bool                fContentInfoVerifiedOkay;
    241245    /** @} */
    242246
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r84312 r84340  
    29032903        Assert(m->fCertificateIsSelfSigned == RTCrX509Certificate_IsSelfSigned(&m->SignerCert));
    29042904
     2905        /* We'll always needs the trusted cert store. */
    29052906        hrc2 = S_OK;
    2906         if (m->fCertificateIsSelfSigned)
    2907         {
    2908             /*
    2909              * It's a self signed certificate.  We assume the frontend will
    2910              * present this fact to the user and give a choice whether this
    2911              * is acceptible.  But, first make sure it makes internal sense.
    2912              */
    2913             m->fCertificateMissingPath = true; /** @todo need to check if the certificate is trusted by the system! */
    2914             vrc = RTCrX509Certificate_VerifySignatureSelfSigned(&m->SignerCert, RTErrInfoInitStatic(&StaticErrInfo));
    2915             if (RT_SUCCESS(vrc))
    2916             {
    2917                 m->fCertificateValid = true;
    2918 
    2919                 /* Check whether the certificate is currently valid, just warn if not. */
    2920                 RTTIMESPEC Now;
    2921                 if (RTCrX509Validity_IsValidAtTimeSpec(&m->SignerCert.TbsCertificate.Validity, RTTimeNow(&Now)))
     2907        RTCRSTORE hTrustedCerts;
     2908        vrc = RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(&hTrustedCerts, RTErrInfoInitStatic(&StaticErrInfo));
     2909        if (RT_SUCCESS(vrc))
     2910        {
     2911            /* If we don't have a PKCS7/CMS signature or if it uses a different
     2912               certificate, we try our best to validate the OVF certificate. */
     2913            if (!m->fContentInfoOkay || !m->fContentInfoSameCert)
     2914            {
     2915                if (m->fCertificateIsSelfSigned)
     2916                    hrc2 = i_readTailProcessingVerifySelfSignedOvfCert(pTask, hTrustedCerts, &StaticErrInfo);
     2917                else
     2918                    hrc2 = i_readTailProcessingVerifyIssuedOvfCert(pTask, hTrustedCerts, &StaticErrInfo);
     2919            }
     2920
     2921            /* If there is a PKCS7/CMS signature, we always verify its certificates. */
     2922            if (m->fContentInfoOkay)
     2923            {
     2924                void  *pvData = NULL;
     2925                size_t cbData = 0;
     2926                HRESULT hrc3 = i_readTailProcessingGetManifestData(&pvData, &cbData);
     2927                if (SUCCEEDED(hrc3))
    29222928                {
    2923                     m->fCertificateValidTime = true;
    2924                     i_addWarning(tr("A self signed certificate was used to sign '%s'"), pTask->locInfo.strPath.c_str());
     2929                    hrc3 = i_readTailProcessingVerifyContentInfoCerts(pvData, cbData, hTrustedCerts, &StaticErrInfo);
     2930                    RTMemTmpFree(pvData);
    29252931                }
    2926                 else
    2927                     i_addWarning(tr("Self signed certificate used to sign '%s' is not currently valid"),
    2928                                  pTask->locInfo.strPath.c_str());
    2929 
    2930                 /* Just warn if it's not a CA. Self-signed certificates are
    2931                    hardly trustworthy to start with without the user's consent. */
    2932                 if (   !m->SignerCert.TbsCertificate.T3.pBasicConstraints
    2933                     || !m->SignerCert.TbsCertificate.T3.pBasicConstraints->CA.fValue)
    2934                     i_addWarning(tr("Self signed certificate used to sign '%s' is not marked as certificate authority (CA)"),
    2935                                  pTask->locInfo.strPath.c_str());
    2936             }
    2937             else
    2938             {
    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);
    2943             }
     2932                if (FAILED(hrc3) && SUCCEEDED(hrc2))
     2933                    hrc2 = hrc3;
     2934            }
     2935            RTCrStoreRelease(hTrustedCerts);
    29442936        }
    29452937        else
    2946         {
    2947             /*
    2948              * The certificate is not self-signed.  Use the system certificate
    2949              * stores to try build a path that validates successfully.
    2950              */
    2951             RTCRX509CERTPATHS hCertPaths;
    2952             vrc = RTCrX509CertPathsCreate(&hCertPaths, &m->SignerCert);
    2953             if (RT_SUCCESS(vrc))
    2954             {
    2955                 /* Get trusted certificates from the system and add them to the path finding mission. */
    2956                 RTCRSTORE hTrustedCerts;
    2957                 vrc = RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(&hTrustedCerts,
    2958                                                                                RTErrInfoInitStatic(&StaticErrInfo));
    2959                 if (RT_SUCCESS(vrc))
    2960                 {
    2961                     vrc = RTCrX509CertPathsSetTrustedStore(hCertPaths, hTrustedCerts);
    2962                     if (RT_FAILURE(vrc))
    2963                         hrc2 = setErrorBoth(E_FAIL, vrc, tr("RTCrX509CertPathsSetTrustedStore failed (%Rrc)"), vrc);
    2964                     RTCrStoreRelease(hTrustedCerts);
    2965                 }
    2966                 else
    2967                     hrc2 = setErrorBoth(E_FAIL, vrc,
    2968                                         tr("Failed to query trusted CAs and Certificates from the system and for the current user (%Rrc, %s)"),
    2969                                         vrc, StaticErrInfo.Core.pszMsg);
    2970 
    2971                 /* Add untrusted intermediate certificates. */
    2972                 if (RT_SUCCESS(vrc))
    2973                 {
    2974                     /// @todo RTCrX509CertPathsSetUntrustedStore(hCertPaths, hAdditionalCerts);
    2975                     /// By scanning for additional certificates in the .cert file?  It would be
    2976                     /// convenient to be able to supply intermediate certificates for the user,
    2977                     /// right?  Or would that be unacceptable as it may weaken security?
    2978                     ///
    2979                     /// Anyway, we should look for intermediate certificates on the system, at
    2980                     /// least.
    2981                 }
    2982                 if (RT_SUCCESS(vrc))
    2983                 {
    2984                     /*
    2985                      * Do the building and verification of certificate paths.
    2986                      */
    2987                     vrc = RTCrX509CertPathsBuild(hCertPaths, RTErrInfoInitStatic(&StaticErrInfo));
    2988                     if (RT_SUCCESS(vrc))
    2989                     {
    2990                         vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(&StaticErrInfo));
    2991                         if (RT_SUCCESS(vrc))
    2992                         {
    2993                             /*
    2994                              * Mark the certificate as good.
    2995                              */
    2996                             /** @todo check the certificate purpose? If so, share with self-signed. */
    2997                             m->fCertificateValid = true;
    2998                             m->fCertificateMissingPath = false;
    2999 
    3000                             /*
    3001                              * We add a warning if the certificate path isn't valid at the current
    3002                              * time.  Since the time is only considered during path validation and we
    3003                              * can repeat the validation process (but not building), it's easy to check.
    3004                              */
    3005                             RTTIMESPEC Now;
    3006                             vrc = RTCrX509CertPathsSetValidTimeSpec(hCertPaths, RTTimeNow(&Now));
    3007                             if (RT_SUCCESS(vrc))
    3008                             {
    3009                                 vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(&StaticErrInfo));
    3010                                 if (RT_SUCCESS(vrc))
    3011                                     m->fCertificateValidTime = true;
    3012                                 else
    3013                                     i_addWarning(tr("The certificate used to sign '%s' (or a certificate in the path) is not currently valid (%Rrc)"),
    3014                                                  pTask->locInfo.strPath.c_str(), vrc);
    3015                             }
    3016                             else
    3017                                 hrc2 = setErrorVrc(vrc, "RTCrX509CertPathsSetValidTimeSpec failed: %Rrc", vrc);
    3018                         }
    3019                         else if (vrc == VERR_CR_X509_CPV_NO_TRUSTED_PATHS)
    3020                         {
    3021                             m->fCertificateValid = true;
    3022                             i_addWarning(tr("No trusted certificate paths"));
    3023 
    3024                             /* Add another warning if the pathless certificate is not valid at present. */
    3025                             RTTIMESPEC Now;
    3026                             if (RTCrX509Validity_IsValidAtTimeSpec(&m->SignerCert.TbsCertificate.Validity, RTTimeNow(&Now)))
    3027                                 m->fCertificateValidTime = true;
    3028                             else
    3029                                 i_addWarning(tr("The certificate used to sign '%s' is not currently valid"),
    3030                                              pTask->locInfo.strPath.c_str());
    3031                         }
    3032                         else
    3033                             hrc2 = setErrorBoth(E_FAIL, vrc, tr("Certificate path validation failed (%Rrc, %s)"),
    3034                                                 vrc, StaticErrInfo.Core.pszMsg);
    3035                     }
    3036                     else
    3037                         hrc2 = setErrorBoth(E_FAIL, vrc, tr("Certificate path building failed (%Rrc, %s)"),
    3038                                             vrc, StaticErrInfo.Core.pszMsg);
    3039                 }
    3040                 RTCrX509CertPathsRelease(hCertPaths);
    3041             }
    3042             else
    3043                 hrc2 = setErrorVrc(vrc, tr("RTCrX509CertPathsCreate failed: %Rrc"), vrc);
    3044         }
     2938            hrc2 = setErrorBoth(E_FAIL, vrc,
     2939                                tr("Failed to query trusted CAs and Certificates from the system and for the current user (%Rrc%RTeim)"),
     2940                                vrc, &StaticErrInfo.Core);
    30452941
    30462942        /* Merge statuses from signature and certificate validation, prefering the signature one. */
     
    30542950    if (m->fSignerCertLoaded)
    30552951    {
     2952        /** @todo PKCS7/CMS certs too */
    30562953        m->ptrCertificateInfo.createObject();
    30572954        m->ptrCertificateInfo->initCertificate(&m->SignerCert,
     
    30672964    return S_OK;
    30682965}
    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 //}
    30772966
    30782967/**
     
    31153004HRESULT Appliance::i_readTailProcessingSignedData(PRTERRINFOSTATIC pErrInfo)
    31163005{
    3117     m->fContentInfoValid          = false;
     3006    m->fContentInfoOkay           = false;
    31183007    m->fContentInfoSameCert       = false;
    31193008    m->fContentInfoValidSignature = false;
     
    31403029    else
    31413030    {
    3142         m->fContentInfoValid = true;
     3031        m->fContentInfoOkay = true;
    31433032
    31443033        /*
     
    31883077    return hrc;
    31893078}
     3079
     3080
     3081/**
     3082 * Worker for i_readTailProcessing that verifies a self signed certificate when
     3083 * no PKCS\#7/CMS signature using the same certificate is present.
     3084 */
     3085HRESULT Appliance::i_readTailProcessingVerifySelfSignedOvfCert(TaskOVF *pTask, RTCRSTORE hTrustedStore, PRTERRINFOSTATIC pErrInfo)
     3086{
     3087    /*
     3088     * It's a self signed certificate.  We assume the frontend will
     3089     * present this fact to the user and give a choice whether this
     3090     * is acceptable.  But, first make sure it makes internal sense.
     3091     */
     3092    m->fCertificateMissingPath = true;
     3093    PCRTCRCERTCTX pCertCtx = RTCrStoreCertByIssuerAndSerialNo(hTrustedStore, &m->SignerCert.TbsCertificate.Issuer,
     3094                                                              &m->SignerCert.TbsCertificate.SerialNumber);
     3095    if (pCertCtx)
     3096    {
     3097        if (pCertCtx->pCert && RTCrX509Certificate_Compare(pCertCtx->pCert, &m->SignerCert) == 0)
     3098            m->fCertificateMissingPath = true;
     3099        RTCrCertCtxRelease(pCertCtx);
     3100    }
     3101
     3102    int vrc = RTCrX509Certificate_VerifySignatureSelfSigned(&m->SignerCert, RTErrInfoInitStatic(pErrInfo));
     3103    if (RT_SUCCESS(vrc))
     3104    {
     3105        m->fCertificateValid = true;
     3106
     3107        /* Check whether the certificate is currently valid, just warn if not. */
     3108        RTTIMESPEC Now;
     3109        m->fCertificateValidTime = RTCrX509Validity_IsValidAtTimeSpec(&m->SignerCert.TbsCertificate.Validity, RTTimeNow(&Now));
     3110        if (m->fCertificateValidTime)
     3111        {
     3112            m->fCertificateValidTime = true;
     3113            i_addWarning(tr("A self signed certificate was used to sign '%s'"), pTask->locInfo.strPath.c_str());
     3114        }
     3115        else
     3116            i_addWarning(tr("Self signed certificate used to sign '%s' is not currently valid"),
     3117                         pTask->locInfo.strPath.c_str());
     3118    }
     3119    else
     3120    {
     3121        m->strCertError.printfNoThrow(tr("Verification of the self signed certificate failed (%Rrc%#RTeim)"),
     3122                                      vrc, &pErrInfo->Core);
     3123        i_addWarning(tr("Verification of the self signed certificate used to sign '%s' failed (%Rrc)%RTeim"),
     3124                     pTask->locInfo.strPath.c_str(), vrc, &pErrInfo->Core);
     3125    }
     3126
     3127    /* Just warn if it's not a CA. Self-signed certificates are
     3128       hardly trustworthy to start with without the user's consent. */
     3129    if (   !m->SignerCert.TbsCertificate.T3.pBasicConstraints
     3130        || !m->SignerCert.TbsCertificate.T3.pBasicConstraints->CA.fValue)
     3131        i_addWarning(tr("Self signed certificate used to sign '%s' is not marked as certificate authority (CA)"),
     3132                     pTask->locInfo.strPath.c_str());
     3133
     3134    return S_OK;
     3135}
     3136
     3137/**
     3138 * Worker for i_readTailProcessing that verfies a non-self-issued OVF
     3139 * certificate when no PKCS\#7/CMS signature using the same certificate is
     3140 * present.
     3141 */
     3142HRESULT Appliance::i_readTailProcessingVerifyIssuedOvfCert(TaskOVF *pTask, RTCRSTORE hTrustedStore, PRTERRINFOSTATIC pErrInfo)
     3143{
     3144    /*
     3145     * The certificate is not self-signed.  Use the system certificate
     3146     * stores to try build a path that validates successfully.
     3147     */
     3148    HRESULT hrc = S_OK;
     3149    RTCRX509CERTPATHS hCertPaths;
     3150    int vrc = RTCrX509CertPathsCreate(&hCertPaths, &m->SignerCert);
     3151    if (RT_SUCCESS(vrc))
     3152    {
     3153        /* Get trusted certificates from the system and add them to the path finding mission. */
     3154        vrc = RTCrX509CertPathsSetTrustedStore(hCertPaths, hTrustedStore);
     3155        if (RT_FAILURE(vrc))
     3156            hrc = setErrorBoth(E_FAIL, vrc, tr("RTCrX509CertPathsSetTrustedStore failed (%Rrc)"), vrc);
     3157
     3158        /* Add untrusted intermediate certificates. */
     3159        if (RT_SUCCESS(vrc))
     3160        {
     3161            /// @todo RTCrX509CertPathsSetUntrustedStore(hCertPaths, hAdditionalCerts);
     3162            /// We should look for intermediate certificates on the system, at least.
     3163        }
     3164        if (RT_SUCCESS(vrc))
     3165        {
     3166            /*
     3167             * Do the building and verification of certificate paths.
     3168             */
     3169            vrc = RTCrX509CertPathsBuild(hCertPaths, RTErrInfoInitStatic(pErrInfo));
     3170            if (RT_SUCCESS(vrc))
     3171            {
     3172                vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(pErrInfo));
     3173                if (RT_SUCCESS(vrc))
     3174                {
     3175                    /*
     3176                     * Mark the certificate as good.
     3177                     */
     3178                    /** @todo check the certificate purpose? If so, share with self-signed. */
     3179                    m->fCertificateValid = true;
     3180                    m->fCertificateMissingPath = false;
     3181
     3182                    /*
     3183                     * We add a warning if the certificate path isn't valid at the current
     3184                     * time.  Since the time is only considered during path validation and we
     3185                     * can repeat the validation process (but not building), it's easy to check.
     3186                     */
     3187                    RTTIMESPEC Now;
     3188                    vrc = RTCrX509CertPathsSetValidTimeSpec(hCertPaths, RTTimeNow(&Now));
     3189                    if (RT_SUCCESS(vrc))
     3190                    {
     3191                        vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(pErrInfo));
     3192                        if (RT_SUCCESS(vrc))
     3193                            m->fCertificateValidTime = true;
     3194                        else
     3195                            i_addWarning(tr("The certificate used to sign '%s' (or a certificate in the path) is not currently valid (%Rrc)"),
     3196                                         pTask->locInfo.strPath.c_str(), vrc);
     3197                    }
     3198                    else
     3199                        hrc = setErrorVrc(vrc, "RTCrX509CertPathsSetValidTimeSpec failed: %Rrc", vrc);
     3200                }
     3201                else if (vrc == VERR_CR_X509_CPV_NO_TRUSTED_PATHS)
     3202                {
     3203                    m->fCertificateValid = true;
     3204                    i_addWarning(tr("No trusted certificate paths"));
     3205
     3206                    /* Add another warning if the pathless certificate is not valid at present. */
     3207                    RTTIMESPEC Now;
     3208                    if (RTCrX509Validity_IsValidAtTimeSpec(&m->SignerCert.TbsCertificate.Validity, RTTimeNow(&Now)))
     3209                        m->fCertificateValidTime = true;
     3210                    else
     3211                        i_addWarning(tr("The certificate used to sign '%s' is not currently valid"),
     3212                                     pTask->locInfo.strPath.c_str());
     3213                }
     3214                else
     3215                    hrc = setErrorBoth(E_FAIL, vrc, tr("Certificate path validation failed (%Rrc%RTeim)"), vrc, &pErrInfo->Core);
     3216            }
     3217            else
     3218                hrc = setErrorBoth(E_FAIL, vrc, tr("Certificate path building failed (%Rrc%RTeim)"), vrc, &pErrInfo->Core);
     3219        }
     3220        RTCrX509CertPathsRelease(hCertPaths);
     3221    }
     3222    else
     3223        hrc = setErrorVrc(vrc, tr("RTCrX509CertPathsCreate failed: %Rrc"), vrc);
     3224    return hrc;
     3225}
     3226
     3227/**
     3228 * Helper for i_readTailProcessingVerifySignerInfo that reports a verfication
     3229 * failure.
     3230 *
     3231 * @returns S_OK
     3232 */
     3233HRESULT Appliance::i_readTailProcessingVerifyContentInfoFailOne(const char *pszSignature, int vrc, PRTERRINFOSTATIC pErrInfo)
     3234{
     3235    i_addWarning(tr("%s verification failed: %Rrc%RTeim"), pszSignature, vrc, &pErrInfo->Core);
     3236    if (m->strCertError.isEmpty())
     3237        m->strCertError.printfNoThrow(tr("%s verification failed: %Rrc%RTeim"), pszSignature, vrc, &pErrInfo->Core);
     3238    return S_OK;
     3239}
     3240
     3241/**
     3242 * Worker for i_readTailProcessingVerifyContentInfoCerts that analyzes why the
     3243 * standard verification of a signer info entry failed (@a vrc & @a pErrInfo).
     3244 *
     3245 * There are a couple of things we might want try to investigate deeper here:
     3246 *      1. Untrusted signing certificate, often self-signed.
     3247 *      2. Untrusted timstamp signing certificate.
     3248 *      3. Certificate not valid at the current time and there isn't a
     3249 *         timestamp counter signature.
     3250 *
     3251 * That said, it is difficult to get an accurate fix and report on the
     3252 * issues here since there are a number of error sources, so just try identify
     3253 * the more typical cases.
     3254 *
     3255 * @note Caller cleans up *phTrustedStore2 if not NIL.
     3256 */
     3257HRESULT Appliance::i_readTailProcessingVerifyAnalyzeSignerInfo(void const *pvData, size_t cbData, RTCRSTORE hTrustedStore,
     3258                                                               uint32_t iSigner, PRTTIMESPEC pNow, int vrc,
     3259                                                               PRTERRINFOSTATIC pErrInfo, PRTCRSTORE phTrustedStore2)
     3260{
     3261    PRTCRPKCS7SIGNEDDATA const pSignedData = m->ContentInfo.u.pSignedData;
     3262    PRTCRPKCS7SIGNERINFO const pSigner     = pSignedData->SignerInfos.papItems[iSigner];
     3263
     3264    /*
     3265     * Error/warning message prefix:
     3266     */
     3267    const char *pszSignature;
     3268    if (iSigner == 0 && m->fContentInfoSameCert)
     3269        pszSignature = tr("OVF & PKCS#7/CMS signature");
     3270    else
     3271        pszSignature = tr("PKCS#7/CMS signature");
     3272    char szSignatureBuf[64];
     3273    if (pSignedData->SignerInfos.cItems > 1)
     3274    {
     3275        RTStrPrintf(szSignatureBuf, sizeof(szSignatureBuf), tr("%s #%u"), pszSignature, iSigner + 1);
     3276        pszSignature = szSignatureBuf;
     3277    }
     3278
     3279    /*
     3280     * Don't try handle weird stuff:
     3281     */
     3282    /** @todo Are there more statuses we can deal with here? */
     3283    if (   vrc != VERR_CR_X509_CPV_NOT_VALID_AT_TIME
     3284        && vrc != VERR_CR_X509_NO_TRUST_ANCHOR)
     3285        return i_readTailProcessingVerifyContentInfoFailOne(pszSignature, vrc, pErrInfo);
     3286
     3287    /*
     3288     * Find the signing certificate.
     3289     * We require the certificate to be included in the signed data here.
     3290     */
     3291    PCRTCRX509CERTIFICATE pSigningCert;
     3292    pSigningCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates,
     3293                                                                       &pSigner->IssuerAndSerialNumber.Name,
     3294                                                                       &pSigner->IssuerAndSerialNumber.SerialNumber);
     3295    if (!pSigningCert)
     3296    {
     3297        i_addWarning(tr("PKCS#7/CMS signature #%u does not include the signing certificate"), iSigner + 1);
     3298        if (m->strCertError.isEmpty())
     3299            m->strCertError.printfNoThrow(tr("PKCS#7/CMS signature #%u does not include the signing certificate"), iSigner + 1);
     3300        return S_OK;
     3301    }
     3302
     3303    PCRTCRCERTCTX const pCertCtxTrusted = RTCrStoreCertByIssuerAndSerialNo(hTrustedStore, &pSigner->IssuerAndSerialNumber.Name,
     3304                                                                           &pSigner->IssuerAndSerialNumber.SerialNumber);
     3305    bool const          fSelfSigned     = RTCrX509Certificate_IsSelfSigned(pSigningCert);
     3306
     3307    /*
     3308     * Add warning about untrusted self-signed certificate:
     3309     */
     3310    if (fSelfSigned && !pCertCtxTrusted)
     3311        i_addWarning(tr("%s: Untrusted self-signed certificate"), pszSignature);
     3312
     3313    /*
     3314     * Start by eliminating signing time issues (2 + 3) first as primary problem.
     3315     * Keep the error info and status for later failures.
     3316     */
     3317    char szTime[RTTIME_STR_LEN];
     3318    RTTIMESPEC Now2 = *pNow;
     3319    vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo, RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED
     3320                                                    | RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
     3321                                                    | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner), NIL_RTCRSTORE,
     3322                                                    hTrustedStore, &Now2, NULL, NULL,
     3323                                                    pvData, cbData, RTErrInfoInitStatic(pErrInfo));
     3324    if (RT_SUCCESS(vrc))
     3325    {
     3326        /* Okay, is it an untrusted time signing certificate or just signing time in general? */
     3327        RTTIMESPEC Now3 = *pNow;
     3328        vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo, RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED
     3329                                                        | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
     3330                                                        | RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
     3331                                                        | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner), NIL_RTCRSTORE,
     3332                                                        hTrustedStore, &Now3, NULL, NULL, pvData, cbData, NULL);
     3333        if (RT_SUCCESS(vrc))
     3334            i_addWarning(tr("%s: Untrusted timestamp (%s)"), pszSignature, RTTimeSpecToString(&Now3, szTime, sizeof(szTime)));
     3335        else
     3336            i_addWarning(tr("%s: Not valid at current time, but validates fine for untrusted signing time (%s)"),
     3337                         pszSignature, RTTimeSpecToString(&Now2, szTime, sizeof(szTime)));
     3338        return S_OK;
     3339    }
     3340
     3341    /* If we've got a trusted signing certificate (unlikely, but whatever), we can stop already.
     3342       If we haven't got a self-signed certificate, stop too as messaging becomes complicated otherwise. */
     3343    if (pCertCtxTrusted || !fSelfSigned)
     3344        return i_readTailProcessingVerifyContentInfoFailOne(pszSignature, vrc, pErrInfo);
     3345
     3346    int const vrcErrInfo = vrc;
     3347
     3348    /*
     3349     * Create a new trust store that includes the signing certificate
     3350     * to see what that changes.
     3351     */
     3352    vrc = RTCrStoreCreateInMemEx(phTrustedStore2, 1, hTrustedStore);
     3353    AssertRCReturn(vrc, setErrorVrc(vrc, "RTCrStoreCreateInMemEx"));
     3354    vrc = RTCrStoreCertAddX509(*phTrustedStore2, 0, (PRTCRX509CERTIFICATE)pSigningCert, NULL);
     3355    AssertRCReturn(vrc, setErrorVrc(vrc, "RTCrStoreCertAddX509/%u", iSigner));
     3356
     3357    vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo,
     3358                                                    RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
     3359                                                    | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner), NIL_RTCRSTORE,
     3360                                                    *phTrustedStore2, pNow, NULL, NULL, pvData, cbData, NULL);
     3361    if (RT_SUCCESS(vrc))
     3362    {
     3363        if (!fSelfSigned)
     3364            i_readTailProcessingVerifyContentInfoFailOne(pszSignature, vrcErrInfo, pErrInfo);
     3365        return S_OK;
     3366    }
     3367
     3368    /*
     3369     * Time problems too?  Repeat what we did above, but with the modified trust store.
     3370     */
     3371    Now2 = *pNow;
     3372    vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo, RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED
     3373                                                    | RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
     3374                                                    | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner), NIL_RTCRSTORE,
     3375                                                    *phTrustedStore2, pNow, NULL, NULL, pvData, cbData, NULL);
     3376    if (RT_SUCCESS(vrc))
     3377    {
     3378        /* Okay, is it an untrusted time signing certificate or just signing time in general? */
     3379        RTTIMESPEC Now3 = *pNow;
     3380        vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo, RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED
     3381                                                        | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
     3382                                                        | RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
     3383                                                        | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner), NIL_RTCRSTORE,
     3384                                                        *phTrustedStore2, &Now3, NULL, NULL, pvData, cbData, NULL);
     3385        if (RT_SUCCESS(vrc))
     3386            i_addWarning(tr("%s: Untrusted timestamp (%s)"), pszSignature, RTTimeSpecToString(&Now3, szTime, sizeof(szTime)));
     3387        else
     3388            i_addWarning(tr("%s: Not valid at current time, but validates fine for untrusted signing time (%s)"),
     3389                         pszSignature, RTTimeSpecToString(&Now2, szTime, sizeof(szTime)));
     3390    }
     3391    else
     3392        i_readTailProcessingVerifyContentInfoFailOne(pszSignature, vrcErrInfo, pErrInfo);
     3393
     3394    return S_OK;
     3395}
     3396
     3397/**
     3398 * Verify the signing certificates used to sign the PKCS\#7/CMS signature.
     3399 *
     3400 * ASSUMES that we've previously verified the PKCS\#7/CMS stuff in
     3401 * trust-all-certs-without-question mode and it's just the certificate
     3402 * validation that can fail now.
     3403 */
     3404HRESULT Appliance::i_readTailProcessingVerifyContentInfoCerts(void const *pvData, size_t cbData,
     3405                                                              RTCRSTORE hTrustedStore, PRTERRINFOSTATIC pErrInfo)
     3406{
     3407    /*
     3408     * Just do a run and see what happens (note we've already verified
     3409     * the data signatures, which just leaves certificates and paths).
     3410     */
     3411    RTTIMESPEC Now;
     3412    int vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo,
     3413                                                        RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY,
     3414                                                        NIL_RTCRSTORE /*hAdditionalCerts*/, hTrustedStore,
     3415                                                        RTTimeNow(&Now), NULL /*pfnVerifyCert*/, NULL /*pvUser*/,
     3416                                                        pvData, cbData, RTErrInfoInitStatic(pErrInfo));
     3417    if (RT_SUCCESS(vrc))
     3418        m->fContentInfoVerifiedOkay = true;
     3419    else
     3420    {
     3421        /*
     3422         * Deal with each of the signatures separately to try figure out
     3423         * more exactly what's going wrong.
     3424         */
     3425        uint32_t             cVerifiedOkay = 0;
     3426        PRTCRPKCS7SIGNEDDATA pSignedData   = m->ContentInfo.u.pSignedData;
     3427        for (uint32_t iSigner = 0; iSigner < pSignedData->SignerInfos.cItems; iSigner++)
     3428        {
     3429            vrc = RTCrPkcs7VerifySignedDataWithExternalData(&m->ContentInfo,
     3430                                                            RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
     3431                                                            | RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(iSigner),
     3432                                                            NIL_RTCRSTORE /*hAdditionalCerts*/, hTrustedStore,
     3433                                                            &Now, NULL /*pfnVerifyCert*/, NULL /*pvUser*/,
     3434                                                            pvData, cbData, RTErrInfoInitStatic(pErrInfo));
     3435            if (RT_SUCCESS(vrc))
     3436                cVerifiedOkay++;
     3437            else
     3438            {
     3439                RTCRSTORE hTrustedStore2 = NIL_RTCRSTORE;
     3440                HRESULT hrc = i_readTailProcessingVerifyAnalyzeSignerInfo(pvData, cbData, hTrustedStore, iSigner, &Now,
     3441                                                                          vrc, pErrInfo, &hTrustedStore2);
     3442                RTCrStoreRelease(hTrustedStore2);
     3443                if (FAILED(hrc))
     3444                    return hrc;
     3445            }
     3446        }
     3447
     3448        if (   pSignedData->SignerInfos.cItems > 1
     3449            && pSignedData->SignerInfos.cItems != cVerifiedOkay)
     3450            i_addWarning(tr("%u out of %u PKCS#7/CMS signatures verfified okay"),
     3451                         cVerifiedOkay, pSignedData->SignerInfos.cItems);
     3452    }
     3453
     3454    return S_OK;
     3455}
     3456
    31903457
    31913458
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