VirtualBox

Changeset 57613 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Sep 4, 2015 2:19:44 AM (9 years ago)
Author:
vboxsync
Message:

IPRT,UINetworkReply.cpp: Added RTPathGlob, a set of RTCrStoreCertAddWantedDir/File/Store, a RTCrStoreCertAddWantedFromFishingExpedition, RTCrStoreCertCheckWanted, RTCrStoreCertCount, RTFsIsCaseSensitive and RTFileOpenTemp. Reworked some RTHttp bits and UINetworkReply stuff - this needs testing.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp

    r57581 r57613  
    7272
    7373private:
     74    /** @name Helpers - HTTP stuff
     75     * @{ */
     76    int applyProxyRules();
     77    int applyHttpsCertificates();
     78    int applyRawHeaders();
     79    int performMainRequest();
     80    /** @} */
     81
     82    /* Helper: Main thread runner: */
     83    void run();
     84
    7485    /** Info about wanted certificate. */
    7586    typedef struct CERTINFO
    7687    {
    77         /** The certificate subject name. */
    78         const char *pszSubject;
    79         /** The size of the DER (ASN.1) encoded certificate. */
    80         uint16_t    cbEncoded;
    8188        /** Gives the s_aCerts index this certificate is an alternative edition of,
    8289         * UINT8_MAX if no alternative.  This is a complication caused by VeriSign
     
    8794        /** Set if mandatory. */
    8895        bool        fMandatory;
    89         /** The SHA-1 fingerprint (of the encoded data).   */
    90         uint8_t     abSha1[RTSHA1_HASH_SIZE];
    91         /** The SHA-512 fingerprint (of the encoded data).   */
    92         uint8_t     abSha512[RTSHA512_HASH_SIZE];
    9396        /** Filename in the zip file we download (PEM). */
    9497        const char *pszZipFile;
     
    97100    } CERTINFO;
    98101
    99 
    100     /** @name Helpers - HTTP stuff
    101      * @{ */
    102     int applyProxyRules();
    103     int applyHttpsCertificates();
    104     int applyRawHeaders();
    105     int performMainRequest();
    106     /** @} */
    107 
    108     /* Helper: Main thread runner: */
    109     void run();
    110 
    111102    /** @name Static helpers for HTTP and Certificates handling.
    112103     * @{ */
     
    114105    static int applyProxyRules(RTHTTP hHttp, const QString &strHostName, int iPort);
    115106    static int applyRawHeaders(RTHTTP hHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
    116     static bool allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory);
    117     static uint64_t certEntryFoundMask(uint32_t iCert);
    118     static bool checkCertificatesInFile(const char *pszCaCertFile);
    119     static bool checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates = NULL);
    120     static int downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile);
     107    static unsigned countCertsFound(bool const *pafFoundCerts);
     108    static bool areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory);
     109    static void refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafFoundCerts, const char *pszCaCertFile);
     110    static void downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
     111                                            PRTERRINFOSTATIC pStaticErrInfo);
    121112    static int convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore, void const *pvResponse,
    122                                                         size_t cbResponse, const CERTINFO *pCertInfo);
    123     static int retrieveCertificatesFromSystem(const char *pszCaCertFile);
     113                                                        size_t cbResponse, PCRTCRCERTWANTED pWantedCert);
    124114    /** @} */
    125115
     
    135125
    136126    static const QString s_strCertificateFileName;
    137     static const CERTINFO s_aCerts[3];
     127    static const RTCRCERTWANTED s_aCerts[3];
     128    static const CERTINFO s_CertInfoPcaCls3Gen1Md2;
     129    static const CERTINFO s_CertInfoPcaCls3Gen1Sha1;
     130    static const CERTINFO s_CertInfoPcaCls3Gen5;
     131};
     132
     133/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1 =
     134{
     135    /*.iAlternativeTo =*/   1,
     136    /*.fMandatory     =*/   false,
     137    /*.pszZipFile     =*/
     138    "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
     139    /*.apszUrls[3]    =*/
     140    {
     141        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
     142        "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
     143        NULL,
     144        "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
     145    }
     146};
     147
     148/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2 =
     149{
     150    /*.iAlternativeTo =*/   0,
     151    /*.fMandatory     =*/   false,
     152    /*.pszZipFile     =*/   NULL,
     153    /*.apszUrls[3]    =*/   { NULL, NULL, NULL },
     154};
     155
     156/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5 =
     157{
     158    /*.iAlternativeTo =*/   UINT8_MAX,
     159    /*.fMandatory     =*/   true,
     160    /*.pszZipFile     =*/
     161    "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
     162    /*.apszUrls[3]    =*/
     163    {
     164        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
     165        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
     166        "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
     167        "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
     168    }
    138169};
    139170
     
    141172/**
    142173 * Details on the certificates we are after.
     174 * The pvUser member points to a UINetworkReplyPrivateThread::CERTINFO.
    143175 */
    144 /* static */ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_aCerts[3] =
     176/* static */ const RTCRCERTWANTED UINetworkReplyPrivateThread::s_aCerts[3] =
    145177{
    146178    /*[0] =*/   /* The reissued version with the SHA-1 signature. */
    147179/** @todo r=bird: Why do we need this certificate? Neither update.virtualbox.org nor www.virtualbox.org uses it...  ElCapitan doesn't ship this. */
    148180    {
    149         /*.pszSubject =*/
    150         "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
    151         /*.cbEncoded      =*/   0x240,
    152         /*.iAlternativeTo =*/   1,
    153         /*.fMandatory     =*/   false,
    154         /*.abSha1         =*/
     181        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
     182        /*.cbEncoded         =*/    0x240,
     183        /*.Sha1Fingerprint   =*/    true,
     184        /*.Sha512Fingerprint =*/    true,
     185        /*.abSha1            =*/
    155186        {
    156187            0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
    157188            0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
    158189        },
    159         /*.abSha512       =*/
     190        /*.abSha512          =*/
    160191        {
    161192            0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
     
    168199            0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
    169200        },
    170         /*.pszZipFile     =*/
    171         "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
    172         /*.apszUrls[3]    =*/
    173         {
    174             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
    175             "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
    176             NULL,
    177             "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
    178         },
     201        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1
    179202    },
    180203    /*[1] =*/   /* The original version with the MD2 signature. */
    181204    {
    182         /*.pszSubject     =*/
    183         "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
    184         /*.cbEncoded      =*/   0x240,
    185         /*.iAlternativeTo =*/   0,
    186         /*.fMandatory     =*/   false,
    187         /*.abSha1         =*/
     205        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
     206        /*.cbEncoded         =*/    0x240,
     207        /*.Sha1Fingerprint   =*/    true,
     208        /*.Sha512Fingerprint =*/    true,
     209        /*.abSha1            =*/
    188210        {
    189211            0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45,
    190212            0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2
    191213        },
    192         /*.abSha512       =*/
     214        /*.abSha512          =*/
    193215        {
    194216            0x7c, 0x2f, 0x94, 0x22, 0x5f, 0x67, 0x98, 0x89,
     
    201223            0xc8, 0x0c, 0x5a, 0xe7, 0x8b, 0x33, 0xf2, 0xaa
    202224        },
    203         /*.pszZipFile     =*/ NULL,
    204         /*.apszUrls[3]    =*/ { NULL, NULL, NULL },
     225        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2
    205226    },
    206227    /*[2] =*/
    207228    {
    208         /*.pszSubject =*/
     229        /*.pszSubject        =*/
    209230        "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, "
    210231        "CN=VeriSign Class 3 Public Primary Certification Authority - G5",
    211         /*.cbEncoded      =*/   0x4d7,
    212         /*.iAlternativeTo =*/   UINT8_MAX,
    213         /*.fMandatory     =*/   true,
    214         /*.abSha1         =*/
     232        /*.cbEncoded         =*/    0x4d7,
     233        /*.Sha1Fingerprint   =*/    true,
     234        /*.Sha512Fingerprint =*/    true,
     235        /*.abSha1            =*/
    215236        {
    216237            0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
    217238            0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
    218239        },
    219         /*.abSha512   =*/
     240        /*.abSha512          =*/
    220241        {
    221242            0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
     
    228249            0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
    229250        },
    230         /*.pszZipFile     =*/
    231         "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
    232         /*.apszUrls[3]    =*/
    233         {
    234             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
    235             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
    236             "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
    237             "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
    238         },
     251        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5
    239252    },
    240253};
     
    288301
    289302    /*
    290      * Check that the certificate file is recent and contains the necessary certificates.
     303     * Check the state of our CA certificate file, it's one of the following:
     304     *      - Missing, recreate from scratch (= refresh).
     305     *      - Everything is there and it is less than 28 days old, do nothing.
     306     *      - Everything is there but it's older than 28 days, refresh.
     307     *      - Missing certificates and is older than 1 min, refresh.
     308     *
     309     * Start by creating a store for loading the current state into, as we'll
     310     * be need that for the refresh.
    291311     */
    292     int rc;
    293     if (checkCertificatesInFile(pszCaCertFile))
    294         rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
    295     else
    296     {
     312    RTCRSTORE hCurStore = NIL_RTCRSTORE;
     313    int rc = RTCrStoreCreateInMem(&hCurStore, 256);
     314    if (RT_SUCCESS(rc))
     315    {
     316        bool fRefresh    = true;
     317        bool afCertsFound[RT_ELEMENTS(s_aCerts)];
     318        RT_ZERO(afCertsFound);
     319
    297320        /*
    298          * Need to create/update the CA certificate file.  Try see if the necessary
    299          * certificates are to be found somewhere on the local system, then fall back
    300          * to downloading them.
     321         * Load the file if it exists.
     322         *
     323         * To effect regular updates, we need the modification date of the file,
     324         * so we use RTPathQueryInfoEx here and not RTFileExists.
    301325         */
    302         rc = retrieveCertificatesFromSystem(pszCaCertFile);
    303         if (RT_FAILURE(rc))
    304             rc = downloadCertificates(m_hHttp, pszCaCertFile);
    305 
     326        RTFSOBJINFO Info;
     327        int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
     328        if (   RT_SUCCESS(rc)
     329            && RTFS_IS_FILE(Info.Attr.fMode))
     330        {
     331            RTERRINFOSTATIC StaticErrInfo;
     332            rc = RTCrStoreCertAddFromFile(hCurStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
     333                                          RTErrInfoInitStatic(&StaticErrInfo));
     334            if (RTErrInfoIsSet(&StaticErrInfo.Core))
     335                LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
     336            else
     337                AssertRC(rc);
     338
     339            /*
     340             * Scan the store the for certificates we need, then see what we
     341             * need to do wrt file age.
     342             */
     343            rc = RTCrStoreCertCheckWanted(hCurStore, s_aCerts, RT_ELEMENTS(s_aCerts), afCertsFound);
     344            AssertRC(rc);
     345            RTTIMESPEC RefreshAge;
     346            uint32_t   cSecRefresh = rc == VINF_SUCCESS  ? 28 * RT_SEC_1DAY /* all found */ : 60 /* stuff missing */;
     347            fRefresh = RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&RefreshAge), cSecRefresh)) <= 0;
     348        }
     349
     350        /*
     351         * Refresh the file if necessary.
     352         */
     353        if (fRefresh)
     354            refreshCertificates(m_hHttp, hCurStore, afCertsFound, pszCaCertFile);
     355
     356        RTCrStoreRelease(hCurStore);
     357
     358        /*
     359         * Final verdict.
     360         */
     361        if (areAllCertsFound(afCertsFound, true /*fOnlyMandatory*/))
     362            rc = VINF_SUCCESS;
     363        else
     364            rc = VERR_NOT_FOUND; /** @todo r=bird: Why not try and let RTHttpGet* bitch if the necessary certs are missing? */
     365
     366        /*
     367         * Set our custom CA file.
     368         */
    306369        if (RT_SUCCESS(rc))
    307370            rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
    308371    }
    309 
    310372    return rc;
    311373}
     
    426488
    427489/**
    428  * Checks if the certificates we desire are all present in the given file, and
    429  * that the file is recent enough (not for downloaded certs).
     490 * Counts the number of certificates found in a search result array.
    430491 *
    431  * @returns true if fine, false if not.
    432  * @param   pszCaCertFile   The path to the certificate file.
     492 * @returns Number of wanted certifcates we've found.
     493 * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
     494 *                              each wanted certificate.
    433495 */
    434 /*static*/ bool
    435 UINetworkReplyPrivateThread::checkCertificatesInFile(const char *pszCaCertFile)
    436 {
    437     bool fFoundCerts = false;
    438 
    439     /*
    440      * Check whether the file exists.
    441      */
    442     RTFSOBJINFO Info;
    443     int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
    444     if (   RT_SUCCESS(rc)
    445         && RTFS_IS_FILE(Info.Attr.fMode))
    446     {
    447         /*
    448          * Load the CA certificate file into a store and use
    449          * checkCertificatesInStore to do the real work.
    450          */
    451         RTCRSTORE hStore;
    452         int rc = RTCrStoreCreateInMem(&hStore, 256);
    453         if (RT_SUCCESS(rc))
    454         {
    455             RTERRINFOSTATIC StaticErrInfo;
    456             rc = RTCrStoreCertAddFromFile(hStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
    457                                           RTErrInfoInitStatic(&StaticErrInfo));
    458             if (RTErrInfoIsSet(&StaticErrInfo.Core))
    459                 LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
    460             else
    461                 AssertRC(rc);
    462 
    463             unsigned cCertificates = 0;
    464             fFoundCerts = checkCertificatesInStore(hStore, &cCertificates);
    465 
    466             RTCrStoreRelease(hStore);
    467 
    468             /*
    469              * If there are more than two certificates in the database, we're looking
    470              * at a mirror of the system CA stores.  Refresh our snapshot once every 28 days.
    471              */
    472             RTTIMESPEC MaxAge;
    473             if (   fFoundCerts
    474                 && cCertificates > 2
    475                 && RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&MaxAge), 28 *24*3600)) < 0)
    476                 fFoundCerts = false;
    477         }
    478     }
    479 
    480     return fFoundCerts;
     496/*static*/ unsigned
     497UINetworkReplyPrivateThread::countCertsFound(bool const *pafFoundCerts)
     498{
     499    unsigned cFound = 0;
     500    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     501        cFound += pafFoundCerts[i];
     502    return cFound;
    481503}
    482504
     
    485507 *
    486508 * @returns true if we have, false if we haven't.
    487  * @param   fFoundCerts         The mask of found certificates (see
    488  *                              certEntryFoundMask).
     509 * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
     510 *                              each wanted certificate.
    489511 * @param   fOnlyMandatory      Only require mandatory certificates to be
    490512 *                              present.  If false, all certificates must be
     
    492514 */
    493515/*static*/ bool
    494 UINetworkReplyPrivateThread::allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory)
    495 {
    496     AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
    497 
    498     /* Add non-mandatory flags before comparing. */
    499     if (   fOnlyMandatory
    500         && fFoundCerts != RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1))
     516UINetworkReplyPrivateThread::areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory)
     517{
     518    if (fOnlyMandatory)
     519    {
    501520        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    502             if (!s_aCerts[i].fMandatory)
    503                 fFoundCerts |= RT_BIT_64(i);
    504 
    505     return fFoundCerts == RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1);
    506 }
    507 
    508 /**
    509  * Calculates the 64-bit 'found' mask for a certificate entry.
    510  *
    511  * @returns 64-bit mask.
    512  * @param   iCert               The certificate entry.
    513  */
    514 /*static*/ uint64_t
    515 UINetworkReplyPrivateThread::certEntryFoundMask(uint32_t iCert)
    516 {
    517     Assert(iCert < RT_ELEMENTS(s_aCerts));
    518     uint64_t fMask = RT_BIT_64(iCert);
    519 
     521            if (   !pafFoundCerts[i]
     522                && ((const CERTINFO *)s_aCerts[i].pvUser)->fMandatory)
     523                return false;
     524    }
     525    else
     526        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     527            if (!pafFoundCerts[i])
     528                return false;
     529    return true;
     530}
     531
     532/*static*/ void
     533UINetworkReplyPrivateThread::refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafOldFoundCerts,
     534                                                 const char *pszCaCertFile)
     535{
    520536    /*
    521      * Tedium: Also mark certificates that this is an alternative to, we only need
    522      *         the public key once.
     537     * Collect the standard assortment of SSL certificates.
    523538     */
    524     uint8_t iAlt = s_aCerts[iCert].iAlternativeTo;
    525     if (iAlt != UINT8_MAX)
    526     {
    527         unsigned cMax = 10;
    528         do
    529         {
    530             Assert(iAlt < RT_ELEMENTS(s_aCerts));
    531             Assert(cMax > 1);
    532             Assert(strcmp(s_aCerts[iAlt].pszSubject, s_aCerts[iCert].pszSubject) == 0);
    533             fMask |= RT_BIT_64(iAlt);
    534             iAlt = s_aCerts[iAlt].iAlternativeTo;
    535         } while (iAlt != iCert && cMax-- > 0);
    536     }
    537 
    538     return fMask;
    539 }
    540 
    541 /**
    542  * Checks if the certificates we desire are all present in the given store.
    543  *
    544  * @returns true if present, false if not.
    545  * @param   hStore              The store to examine.
    546  * @param   pcCertificates      Where to return the number of certificates in
    547  *                              the store. Optional.
    548  */
    549 /* static */ bool
    550 UINetworkReplyPrivateThread::checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates /* = NULL*/)
    551 {
    552     if (pcCertificates)
    553         *pcCertificates = 0;
    554 
    555     /*
    556      * Enumerate the store, checking for the certificates we need.
    557      */
    558     RTCRSTORECERTSEARCH Search;
    559     int rc = RTCrStoreCertFindAll(hStore, &Search);
     539    uint32_t  cHint = RTCrStoreCertCount(hOldStore);
     540    RTCRSTORE hNewStore;
     541    int rc = RTCrStoreCreateInMem(&hNewStore, cHint > 32 && cHint < _32K ? cHint + 16 : 256);
    560542    if (RT_SUCCESS(rc))
    561543    {
    562         uint64_t      fFoundCerts   = 0;
    563         unsigned      cCertificates = 0;
    564         PCRTCRCERTCTX pCertCtx;
    565         while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
    566         {
    567             if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
    568                 && pCertCtx->cbEncoded > 0
    569                 && pCertCtx->pCert)
     544        RTERRINFOSTATIC StaticErrInfo;
     545        rc = RTHttpGatherCaCertsInStore(hNewStore, 0 /*fFlags*/, RTErrInfoInitStatic(&StaticErrInfo));
     546        if (RTErrInfoIsSet(&StaticErrInfo.Core))
     547            LogRel(("refreshCertificates/#1: %s\n", StaticErrInfo.Core.pszMsg));
     548        else
     549            AssertLogRelRC(rc);
     550
     551        if (RT_SUCCESS(rc))
     552        {
     553            /*
     554             * Check and see what we've got.  If we haven't got all we desire,
     555             * try add it from the previous store.
     556             */
     557            bool afNewFoundCerts[RT_ELEMENTS(s_aCerts)];
     558            RT_ZERO(afNewFoundCerts); /* paranoia */
     559
     560            rc = RTCrStoreCertCheckWanted(hNewStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
     561            AssertLogRelRC(rc);
     562            Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
     563            if (rc != VINF_SUCCESS)
    570564            {
    571                 cCertificates++;
    572 
    573                 /*
    574                  * It is a X.509 certificate.  Check if it matches any of those we're looking for.
    575                  */
    576                 for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    577                     if (   pCertCtx->cbEncoded == s_aCerts[i].cbEncoded
    578                         && RTCrX509Name_MatchWithString(&pCertCtx->pCert->TbsCertificate.Subject, s_aCerts[i].pszSubject))
    579                     {
    580                         if (RTSha1Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha1))
    581                         {
    582                             if (RTSha512Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha512))
    583                             {
    584                                 fFoundCerts |= certEntryFoundMask(i);
    585                                 break;
    586                             }
    587                         }
    588                     }
     565                rc = RTCrStoreCertAddWantedFromStore(hNewStore,
     566                                                     RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     567                                                     hOldStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
     568                AssertLogRelRC(rc);
     569                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
    589570            }
    590             RTCrCertCtxRelease(pCertCtx);
     571
     572            /*
     573             * If that didn't help, seek out certificates in more obscure places,
     574             * like java, mozilla and mutt.
     575             */
     576            if (rc != VINF_SUCCESS)
     577            {
     578                rc = RTCrStoreCertAddWantedFromFishingExpedition(hNewStore,
     579                                                                 RTCRCERTCTX_F_ADD_IF_NOT_FOUND
     580                                                                 | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     581                                                                 s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts,
     582                                                                 RTErrInfoInitStatic(&StaticErrInfo));
     583                if (RTErrInfoIsSet(&StaticErrInfo.Core))
     584                    LogRel(("refreshCertificates/#2: %s\n", StaticErrInfo.Core.pszMsg));
     585                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
     586            }
     587
     588            /*
     589             * If that didn't help, try download the certificates.
     590             */
     591            if (rc != VINF_SUCCESS)
     592                downloadMissingCertificates(hNewStore, afNewFoundCerts, hHttp, &StaticErrInfo);
     593
     594            /*
     595             * If we've got the same or better hit rate than the old store,
     596             * replace the CA certs file.
     597             */
     598            if (   areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/)
     599                || (   countCertsFound(afNewFoundCerts) >= countCertsFound(pafOldFoundCerts)
     600                    &&    areAllCertsFound(afNewFoundCerts, true /*fOnlyMandatory*/)
     601                       >= areAllCertsFound(pafOldFoundCerts, true /*fOnlyMandatory*/) ) )
     602            {
     603                rc = RTCrStoreCertExportAsPem(hNewStore, 0 /*fFlags*/, pszCaCertFile);
     604                if (RT_SUCCESS(rc))
     605                    memcpy(pafOldFoundCerts, afNewFoundCerts, sizeof(afNewFoundCerts));
     606                else
     607                    RT_ZERO(pafOldFoundCerts);
     608            }
    591609        }
    592         int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2);
    593 
    594         /*
    595          * Set the certificate count.
    596          */
    597         if (pcCertificates)
    598             *pcCertificates = cCertificates;
    599 
    600         /*
    601          * Did we locate all of them?
    602          */
    603         if (allCertsFound(fFoundCerts, true /* fOnlyMandatory */)) /** @todo combine the two certificate retrieval approaches */
    604             return true;
    605     }
    606     AssertRC(rc);
    607     return false;
    608 }
    609 
    610 /*static*/ int
    611 UINetworkReplyPrivateThread::downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile)
    612 {
    613     /*
    614      * Prepare temporary certificate store.
    615      */
    616     RTCRSTORE hStore;
    617     int rc = RTCrStoreCreateInMem(&hStore, RT_ELEMENTS(s_aCerts));
    618     AssertRCReturn(rc, rc);
    619 
    620     /*
    621      * Accounts for certificates we've downloaded, verified and added to the store.
    622      */
    623     uint64_t fFoundCerts = 0;
    624     AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
     610        RTCrStoreRelease(hNewStore);
     611    }
     612}
     613
     614/*static*/ void
     615UINetworkReplyPrivateThread::downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
     616                                                         PRTERRINFOSTATIC pStaticErrInfo)
     617{
     618    int rc;
    625619
    626620    /*
     
    640634        {
    641635            for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    642                 if (s_aCerts[i].pszZipFile)
     636                if (!pafNewFoundCerts[i])
    643637                {
    644                     void  *pvFile;
    645                     size_t cbFile;
    646                     rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, s_aCerts[i].pszZipFile);
    647                     if (RT_SUCCESS(rc))
     638                    CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
     639                    if (pInfo->pszZipFile)
    648640                    {
    649                         rc = convertVerifyAndAddPemCertificateToStore(hStore, pvFile, cbFile, &s_aCerts[i]);
    650                         RTMemFree(pvFile);
     641                        void  *pvFile;
     642                        size_t cbFile;
     643                        rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, pInfo->pszZipFile);
    651644                        if (RT_SUCCESS(rc))
    652                             fFoundCerts |= certEntryFoundMask(i);
     645                        {
     646                            rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvFile, cbFile, &s_aCerts[i]);
     647                            RTMemFree(pvFile);
     648                            if (RT_SUCCESS(rc))
     649                            {
     650                                /*
     651                                 * Successfully added. Mark it as found and return if we've got them all.
     652                                 */
     653                                pafNewFoundCerts[i] = true;
     654                                if (areAllCertsFound(pafNewFoundCerts, false /* fOnlyMandatory */))
     655                                {
     656                                    RTHttpFreeResponse(pvRootsZip);
     657                                    return;
     658                                }
     659                            }
     660                        }
    653661                    }
    654662                }
    655663            RTHttpFreeResponse(pvRootsZip);
    656             if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
    657                 break;
    658664        }
    659665    }
    660666
    661667    /*
    662      * Fallback: Try download certificates separately.
     668     * Try download certificates separately.
    663669     */
    664     if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
    665         for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    666             if (!(fFoundCerts & RT_BIT_64(i)))
    667                 for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(s_aCerts[i].apszUrls); i++)
    668                     if (s_aCerts[i].apszUrls[iUrl])
     670    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     671        if (!pafNewFoundCerts[i])
     672        {
     673            CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
     674            for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(pInfo->apszUrls); i++)
     675                if (pInfo->apszUrls[iUrl])
     676                {
     677                    void  *pvResponse;
     678                    size_t cbResponse;
     679                    rc = RTHttpGetBinary(hHttp, pInfo->apszUrls[iUrl], &pvResponse, &cbResponse);
     680                    if (RT_SUCCESS(rc))
    669681                    {
    670                         void  *pvResponse;
    671                         size_t cbResponse;
    672                         rc = RTHttpGetBinary(hHttp, s_aCerts[i].apszUrls[iUrl], &pvResponse, &cbResponse);
     682                        rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvResponse, cbResponse, &s_aCerts[i]);
     683                        RTHttpFreeResponse(pvResponse);
    673684                        if (RT_SUCCESS(rc))
    674685                        {
    675                             rc = convertVerifyAndAddPemCertificateToStore(hStore, pvResponse, cbResponse, &s_aCerts[i]);
    676                             RTHttpFreeResponse(pvResponse);
    677                             if (RT_SUCCESS(rc))
    678                             {
    679                                 fFoundCerts |= certEntryFoundMask(i);
    680                                 break;
    681                             }
     686                            pafNewFoundCerts[i] = true;
     687                            break;
    682688                        }
    683689                    }
    684 
    685     /*
    686      * See if we've got the certificates we want, save it we do.
    687      */
    688     if (allCertsFound(fFoundCerts, true /*fOnlyMandatory*/))
    689         rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaCertFile);
    690     else if (RT_SUCCESS(rc))
    691         rc = VERR_NOT_FOUND;
    692 
    693     RTCrStoreRelease(hStore);
    694     return rc;
     690                }
     691        }
    695692}
    696693
     
    703700 * @param   pvResponse          The raw PEM certificate file bytes.
    704701 * @param   cbResponse          The number of bytes.
    705  * @param   pCertInfo           The certificate info (we use hashes and encoded
     702 * @param   pWantedCert         The certificate info (we use hashes and encoded
    706703 *                              size).
    707704 */
     
    709706UINetworkReplyPrivateThread::convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore,
    710707                                                                      void const *pvResponse, size_t cbResponse,
    711                                                                       const CERTINFO *pCertInfo)
     708                                                                      PCRTCRCERTWANTED pWantedCert)
    712709{
    713710    /*
     
    730727        rc = VERR_NOT_FOUND;
    731728        for (PCRTCRPEMSECTION pCur = pSectionHead; pCur; pCur = pCur->pNext)
    732             if (pCur->cbData == pCertInfo->cbEncoded)
     729            if (pCur->cbData == pWantedCert->cbEncoded)
    733730            {
    734                 if (   RTSha1Check(pCur->pbData, pCur->cbData, pCertInfo->abSha1)
    735                     && RTSha512Check(pCur->pbData, pCur->cbData, pCertInfo->abSha512))
     731                if (   RTSha1Check(pCur->pbData, pCur->cbData, pWantedCert->abSha1)
     732                    && RTSha512Check(pCur->pbData, pCur->cbData, pWantedCert->abSha512))
    736733                {
    737734                    /*
     
    754751            else
    755752                LogRel(("convertVerifyAndAddPemCertificateToStore: cbData=%#zx expected %#zx\n",
    756                         pCur->cbData, pCertInfo->cbEncoded));
     753                        pCur->cbData, pWantedCert->cbEncoded));
    757754
    758755        RTCrPemFreeSections(pSectionHead);
     
    760757    return rc;
    761758}
    762 
    763 /**
    764  * Tries to retrieve an up to date list of certificates from the system that
    765  * includes the necessary certs.
    766  *
    767  * @returns IPRT status code, success indicating that we've found what we need.
    768  * @param   pszCaCertFile           Where to store the certificates.
    769  */
    770 /*static*/ int
    771 UINetworkReplyPrivateThread::retrieveCertificatesFromSystem(const char *pszCaCertFile)
    772 {
    773     /*
    774      * Duplicate the user and system stores.
    775      */
    776     RTERRINFOSTATIC StaticErrInfo;
    777     RTCRSTORE hUserStore;
    778     int rc = RTCrStoreCreateSnapshotById(&hUserStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES,
    779                                          RTErrInfoInitStatic(&StaticErrInfo));
    780     if (RT_FAILURE(rc))
    781         hUserStore = NIL_RTCRSTORE;
    782     if (RTErrInfoIsSet(&StaticErrInfo.Core))
    783         LogRel(("retrieveCertificatesFromSystem/#1: %s\n", StaticErrInfo.Core.pszMsg));
    784 
    785     RTCRSTORE hSystemStore;
    786     rc = RTCrStoreCreateSnapshotById(&hSystemStore, RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES,
    787                                      RTErrInfoInitStatic(&StaticErrInfo));
    788     if (RT_FAILURE(rc))
    789         hUserStore = NIL_RTCRSTORE;
    790     if (RTErrInfoIsSet(&StaticErrInfo.Core))
    791         LogRel(("retrieveCertificatesFromSystem/#2: %s\n", StaticErrInfo.Core.pszMsg));
    792 
    793     /*
    794      * Merge the two.
    795      */
    796     int rc2 = RTCrStoreCertAddFromStore(hUserStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
    797                                         hSystemStore);
    798     AssertRC(rc2);
    799     RTCrStoreRelease(hSystemStore);
    800     hSystemStore = NIL_RTCRSTORE;
    801 
    802     /*
    803      * See if we've got the certificates we want, save it we do.
    804      */
    805     if (checkCertificatesInStore(hUserStore))
    806         rc = RTCrStoreCertExportAsPem(hUserStore, 0 /*fFlags*/, pszCaCertFile);
    807     else
    808         rc = VERR_NOT_FOUND;
    809     RTCrStoreRelease(hUserStore);
    810     return rc;
    811 }
    812 
    813759
    814760
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