Changeset 57613 in vbox for trunk/src/VBox/Frontends
- Timestamp:
- Sep 4, 2015 2:19:44 AM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
r57581 r57613 72 72 73 73 private: 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 74 85 /** Info about wanted certificate. */ 75 86 typedef struct CERTINFO 76 87 { 77 /** The certificate subject name. */78 const char *pszSubject;79 /** The size of the DER (ASN.1) encoded certificate. */80 uint16_t cbEncoded;81 88 /** Gives the s_aCerts index this certificate is an alternative edition of, 82 89 * UINT8_MAX if no alternative. This is a complication caused by VeriSign … … 87 94 /** Set if mandatory. */ 88 95 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];93 96 /** Filename in the zip file we download (PEM). */ 94 97 const char *pszZipFile; … … 97 100 } CERTINFO; 98 101 99 100 /** @name Helpers - HTTP stuff101 * @{ */102 int applyProxyRules();103 int applyHttpsCertificates();104 int applyRawHeaders();105 int performMainRequest();106 /** @} */107 108 /* Helper: Main thread runner: */109 void run();110 111 102 /** @name Static helpers for HTTP and Certificates handling. 112 103 * @{ */ … … 114 105 static int applyProxyRules(RTHTTP hHttp, const QString &strHostName, int iPort); 115 106 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); 121 112 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); 124 114 /** @} */ 125 115 … … 135 125 136 126 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 } 138 169 }; 139 170 … … 141 172 /** 142 173 * Details on the certificates we are after. 174 * The pvUser member points to a UINetworkReplyPrivateThread::CERTINFO. 143 175 */ 144 /* static */ const UINetworkReplyPrivateThread::CERTINFOUINetworkReplyPrivateThread::s_aCerts[3] =176 /* static */ const RTCRCERTWANTED UINetworkReplyPrivateThread::s_aCerts[3] = 145 177 { 146 178 /*[0] =*/ /* The reissued version with the SHA-1 signature. */ 147 179 /** @todo r=bird: Why do we need this certificate? Neither update.virtualbox.org nor www.virtualbox.org uses it... ElCapitan doesn't ship this. */ 148 180 { 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 =*/ 155 186 { 156 187 0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55, 157 188 0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b 158 189 }, 159 /*.abSha512 =*/190 /*.abSha512 =*/ 160 191 { 161 192 0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2, … … 168 199 0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99 169 200 }, 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 179 202 }, 180 203 /*[1] =*/ /* The original version with the MD2 signature. */ 181 204 { 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 =*/ 188 210 { 189 211 0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45, 190 212 0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2 191 213 }, 192 /*.abSha512 =*/214 /*.abSha512 =*/ 193 215 { 194 216 0x7c, 0x2f, 0x94, 0x22, 0x5f, 0x67, 0x98, 0x89, … … 201 223 0xc8, 0x0c, 0x5a, 0xe7, 0x8b, 0x33, 0xf2, 0xaa 202 224 }, 203 /*.pszZipFile =*/ NULL, 204 /*.apszUrls[3] =*/ { NULL, NULL, NULL }, 225 /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2 205 226 }, 206 227 /*[2] =*/ 207 228 { 208 /*.pszSubject =*/229 /*.pszSubject =*/ 209 230 "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, " 210 231 "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 =*/ 215 236 { 216 237 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58, 217 238 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5 218 239 }, 219 /*.abSha512 =*/240 /*.abSha512 =*/ 220 241 { 221 242 0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d, … … 228 249 0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01 229 250 }, 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 239 252 }, 240 253 }; … … 288 301 289 302 /* 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. 291 311 */ 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 297 320 /* 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. 301 325 */ 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 */ 306 369 if (RT_SUCCESS(rc)) 307 370 rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile); 308 371 } 309 310 372 return rc; 311 373 } … … 426 488 427 489 /** 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. 430 491 * 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. 433 495 */ 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 497 UINetworkReplyPrivateThread::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; 481 503 } 482 504 … … 485 507 * 486 508 * @returns true if we have, false if we haven't. 487 * @param fFoundCerts The mask of found certificates (see488 * certEntryFoundMask).509 * @param pafFoundCerts Array parallel to s_aCerts with the status of 510 * each wanted certificate. 489 511 * @param fOnlyMandatory Only require mandatory certificates to be 490 512 * present. If false, all certificates must be … … 492 514 */ 493 515 /*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)) 516 UINetworkReplyPrivateThread::areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory) 517 { 518 if (fOnlyMandatory) 519 { 501 520 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 533 UINetworkReplyPrivateThread::refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafOldFoundCerts, 534 const char *pszCaCertFile) 535 { 520 536 /* 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. 523 538 */ 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); 560 542 if (RT_SUCCESS(rc)) 561 543 { 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) 570 564 { 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*/)); 589 570 } 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 } 591 609 } 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 615 UINetworkReplyPrivateThread::downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp, 616 PRTERRINFOSTATIC pStaticErrInfo) 617 { 618 int rc; 625 619 626 620 /* … … 640 634 { 641 635 for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++) 642 if ( s_aCerts[i].pszZipFile)636 if (!pafNewFoundCerts[i]) 643 637 { 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) 648 640 { 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); 651 644 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 } 653 661 } 654 662 } 655 663 RTHttpFreeResponse(pvRootsZip); 656 if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))657 break;658 664 } 659 665 } 660 666 661 667 /* 662 * Fallback:Try download certificates separately.668 * Try download certificates separately. 663 669 */ 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)) 669 681 { 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); 673 684 if (RT_SUCCESS(rc)) 674 685 { 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; 682 688 } 683 689 } 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 } 695 692 } 696 693 … … 703 700 * @param pvResponse The raw PEM certificate file bytes. 704 701 * @param cbResponse The number of bytes. 705 * @param p CertInfoThe certificate info (we use hashes and encoded702 * @param pWantedCert The certificate info (we use hashes and encoded 706 703 * size). 707 704 */ … … 709 706 UINetworkReplyPrivateThread::convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore, 710 707 void const *pvResponse, size_t cbResponse, 711 const CERTINFO *pCertInfo)708 PCRTCRCERTWANTED pWantedCert) 712 709 { 713 710 /* … … 730 727 rc = VERR_NOT_FOUND; 731 728 for (PCRTCRPEMSECTION pCur = pSectionHead; pCur; pCur = pCur->pNext) 732 if (pCur->cbData == p CertInfo->cbEncoded)729 if (pCur->cbData == pWantedCert->cbEncoded) 733 730 { 734 if ( RTSha1Check(pCur->pbData, pCur->cbData, p CertInfo->abSha1)735 && RTSha512Check(pCur->pbData, pCur->cbData, p CertInfo->abSha512))731 if ( RTSha1Check(pCur->pbData, pCur->cbData, pWantedCert->abSha1) 732 && RTSha512Check(pCur->pbData, pCur->cbData, pWantedCert->abSha512)) 736 733 { 737 734 /* … … 754 751 else 755 752 LogRel(("convertVerifyAndAddPemCertificateToStore: cbData=%#zx expected %#zx\n", 756 pCur->cbData, p CertInfo->cbEncoded));753 pCur->cbData, pWantedCert->cbEncoded)); 757 754 758 755 RTCrPemFreeSections(pSectionHead); … … 760 757 return rc; 761 758 } 762 763 /**764 * Tries to retrieve an up to date list of certificates from the system that765 * 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*/ int771 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 else808 rc = VERR_NOT_FOUND;809 RTCrStoreRelease(hUserStore);810 return rc;811 }812 813 759 814 760
Note:
See TracChangeset
for help on using the changeset viewer.