Changeset 45569 in vbox for trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
- Timestamp:
- Apr 16, 2013 12:34:38 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
r45551 r45569 7 7 8 8 /* 9 * Copyright (C) 2012 Oracle Corporation9 * Copyright (C) 2012-2013 Oracle Corporation 10 10 * 11 11 * This file is part of VirtualBox Open Source Edition (OSE), as … … 18 18 */ 19 19 20 /* Qt includes: */ 21 #include <QDir> 22 #include <QFile> 23 #include <QThread> 24 #include <QSslCertificate> 25 20 26 /* GUI includes: */ 21 27 #include "UINetworkReply.h" … … 25 31 26 32 /* Other VBox includes; */ 33 #include <iprt/initterm.h> 34 #include <iprt/http.h> 27 35 #include <iprt/err.h> 28 #include <iprt/http.h>29 #include <iprt/stream.h>30 #include <iprt/initterm.h>31 #include <iprt/mem.h>32 36 33 37 /* Our network-reply thread: */ … … 52 56 private: 53 57 54 /* Private API: HTTP stuff: */58 /* Helpers: HTTP stuff: */ 55 59 int applyProxyRules(); 60 int applyHttpsCertificates(); 56 61 int applyRawHeaders(); 57 62 int performMainRequest(); 58 63 59 /* Helper: Thread runner: */64 /* Helper: Main thread runner: */ 60 65 void run(); 66 67 /* Static helper: File stuff: */ 68 static QString fullCertificateFileName(); 61 69 62 70 /* Static helpers: HTTP stuff: */ 63 71 static int abort(RTHTTP pHttp); 64 72 static int applyProxyRules(RTHTTP pHttp, const QString &strHostName, int iPort); 73 static int applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName); 65 74 static int applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request); 66 75 static int performGetRequest(RTHTTP pHttp, const QNetworkRequest &request, QByteArray &reply); 76 static int checkCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName); 77 static int downloadCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName); 78 static int downloadCertificatePca3G5(RTHTTP pHttp, QFile &file); 79 static int downloadCertificatePca3(RTHTTP pHttp, QFile &file); 80 static int verifyCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate); 81 static int verifyCertificatePca3(RTHTTP pHttp, QByteArray &certificate); 82 static int verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512); 83 static int saveCertificate(QFile &file, const QByteArray &certificate); 67 84 68 85 /* Variables: */ … … 71 88 RTHTTP m_pHttp; 72 89 QByteArray m_reply; 90 static const QString m_strCertificateFileName; 73 91 }; 92 93 /* static */ 94 const QString UINetworkReplyPrivateThread::m_strCertificateFileName = QString("vbox-ssl-cacertificate.crt"); 74 95 75 96 UINetworkReplyPrivateThread::UINetworkReplyPrivateThread(const QNetworkRequest &request) … … 82 103 void UINetworkReplyPrivateThread::abort() 83 104 { 84 /* Call for HTTPabort: */105 /* Call for abort: */ 85 106 abort(m_pHttp); 86 107 } … … 99 120 } 100 121 122 int UINetworkReplyPrivateThread::applyHttpsCertificates() 123 { 124 /* Prepare variables: */ 125 const QString strFullCertificateFileName(fullCertificateFileName()); 126 int rc = VINF_SUCCESS; 127 128 /* Check certificates if present: */ 129 if (QFile::exists(strFullCertificateFileName)) 130 rc = checkCertificates(m_pHttp, strFullCertificateFileName); 131 else 132 rc = VERR_FILE_NOT_FOUND; 133 134 /* Download certificates if necessary: */ 135 if (!RT_SUCCESS(rc)) 136 rc = downloadCertificates(m_pHttp, strFullCertificateFileName); 137 138 /* Apply certificates: */ 139 if (RT_SUCCESS(rc)) 140 rc = applyCertificates(m_pHttp, strFullCertificateFileName); 141 142 /* Return result-code: */ 143 return rc; 144 } 145 101 146 int UINetworkReplyPrivateThread::applyRawHeaders() 102 147 { … … 122 167 123 168 /* Create HTTP object: */ 124 m_iError = RTHttpCreate(&m_pHttp); 125 126 /* Was HTTP created? */ 127 if (RT_SUCCESS(m_iError) && m_pHttp) 128 { 129 /* Simulate try-catch block: */ 130 do 131 { 132 /* Apply proxy-rules: */ 133 m_iError = applyProxyRules(); 134 if (!RT_SUCCESS(m_iError)) 135 break; 136 137 /* Assign raw headers: */ 138 m_iError = applyRawHeaders(); 139 if (!RT_SUCCESS(m_iError)) 140 break; 141 142 /* Perform main request: */ 143 m_iError = performMainRequest(); 144 } 145 while (0); 146 } 169 if (RT_SUCCESS(m_iError)) 170 m_iError = RTHttpCreate(&m_pHttp); 171 172 /* Apply proxy-rules: */ 173 if (RT_SUCCESS(m_iError)) 174 m_iError = applyProxyRules(); 175 176 /* Apply https-certificates: */ 177 if (RT_SUCCESS(m_iError)) 178 m_iError = applyHttpsCertificates(); 179 180 /* Assign raw-headers: */ 181 if (RT_SUCCESS(m_iError)) 182 m_iError = applyRawHeaders(); 183 184 /* Perform main request: */ 185 if (RT_SUCCESS(m_iError)) 186 m_iError = performMainRequest(); 147 187 148 188 /* Destroy HTTP object: */ … … 152 192 m_pHttp = 0; 153 193 } 194 } 195 196 /* static */ 197 QString UINetworkReplyPrivateThread::fullCertificateFileName() 198 { 199 const QDir homeDir(QDir::toNativeSeparators(vboxGlobal().virtualBox().GetHomeFolder())); 200 return QDir::toNativeSeparators(homeDir.absoluteFilePath(m_strCertificateFileName)); 154 201 } 155 202 … … 172 219 return VERR_INVALID_POINTER; 173 220 174 /* A ssignHTTP proxy: */221 /* Apply HTTP proxy: */ 175 222 return RTHttpSetProxy(pHttp, 176 223 strHostName.toAscii().constData(), … … 180 227 181 228 /* static */ 229 int UINetworkReplyPrivateThread::applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName) 230 { 231 /* Make sure HTTP is created: */ 232 if (!pHttp) 233 return VERR_INVALID_POINTER; 234 235 /* Apply HTTPs certificates: */ 236 return RTHttpSetCAFile(pHttp, strFullCertificateFileName.toAscii().constData()); 237 } 238 239 /* static */ 182 240 int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request) 183 241 { … … 198 256 const char **ppFormattedHeaders = formattedHeaderPointers.data(); 199 257 200 /* A ssignHTTP headers: */258 /* Apply HTTP headers: */ 201 259 return RTHttpSetHeaders(pHttp, formattedHeaderPointers.size(), ppFormattedHeaders); 202 260 } … … 219 277 } 220 278 279 /* static */ 280 int UINetworkReplyPrivateThread::checkCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName) 281 { 282 /* Open certificates file: */ 283 QFile file(strFullCertificateFileName); 284 bool fFileOpened = file.open(QIODevice::ReadOnly); 285 int rc = fFileOpened ? VINF_SUCCESS : VERR_OPEN_FAILED; 286 287 /* Read certificates file: */ 288 if (RT_SUCCESS(rc)) 289 { 290 /* Parse the file content: */ 291 QByteArray data(file.readAll()); 292 QList<QSslCertificate> certificates = QSslCertificate::fromData(data); 293 if (certificates.size() != 2) 294 rc = VERR_FILE_IO_ERROR; 295 296 /* Verify certificates: */ 297 if (RT_SUCCESS(rc)) 298 { 299 QByteArray certificate = certificates.first().toPem(); 300 rc = verifyCertificatePca3G5(pHttp, certificate); 301 } 302 if (RT_SUCCESS(rc)) 303 { 304 QByteArray certificate = certificates.last().toPem(); 305 rc = verifyCertificatePca3(pHttp, certificate); 306 } 307 } 308 309 /* Close certificates file: */ 310 if (fFileOpened) 311 file.close(); 312 313 /* Return result-code: */ 314 return rc; 315 } 316 317 /* static */ 318 int UINetworkReplyPrivateThread::downloadCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName) 319 { 320 /* Open certificates file: */ 321 QFile file(strFullCertificateFileName); 322 bool fFileOpened = file.open(QIODevice::WriteOnly); 323 int rc = fFileOpened ? VINF_SUCCESS : VERR_OPEN_FAILED; 324 325 /* Download PCA-3G5 certificate: */ 326 if (RT_SUCCESS(rc)) 327 rc = downloadCertificatePca3G5(pHttp, file); 328 /* Download PCA-3 certificate: */ 329 if (RT_SUCCESS(rc)) 330 rc = downloadCertificatePca3(pHttp, file); 331 332 /* Close certificates file: */ 333 if (fFileOpened) 334 file.close(); 335 336 /* Return result-code: */ 337 return rc; 338 } 339 340 /* static */ 341 int UINetworkReplyPrivateThread::downloadCertificatePca3G5(RTHTTP pHttp, QFile &file) 342 { 343 /* Receive certificate: */ 344 QByteArray certificate; 345 const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem")); 346 int rc = performGetRequest(pHttp, address, certificate); 347 348 /* Verify certificate: */ 349 if (RT_SUCCESS(rc)) 350 rc = verifyCertificatePca3G5(pHttp, certificate); 351 352 /* Save certificate: */ 353 if (RT_SUCCESS(rc)) 354 rc = saveCertificate(file, certificate); 355 356 /* Return result-code: */ 357 return rc; 358 } 359 360 /* static */ 361 int UINetworkReplyPrivateThread::downloadCertificatePca3(RTHTTP pHttp, QFile &file) 362 { 363 /* Receive certificate: */ 364 QByteArray certificate; 365 const QNetworkRequest address(QUrl("http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem")); 366 int rc = performGetRequest(pHttp, address, certificate); 367 368 /* Verify certificate: */ 369 if (RT_SUCCESS(rc)) 370 rc = verifyCertificatePca3(pHttp, certificate); 371 372 /* Save certificate: */ 373 if (RT_SUCCESS(rc)) 374 rc = saveCertificate(file, certificate); 375 376 /* Return result-code: */ 377 return rc; 378 } 379 380 /* static */ 381 int UINetworkReplyPrivateThread::verifyCertificatePca3G5(RTHTTP pHttp, QByteArray &certificate) 382 { 383 /* PCA 3G5 secure hash algorithm 1: */ 384 const char baSha1PCA3G5[] = 385 { 386 0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58, 387 0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5 388 }; 389 /* PCA 3G5 secure hash algorithm 512: */ 390 const char baSha512PCA3G5[] = 391 { 392 0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d, 393 0xe3, 0x17, 0xb3, 0xcf, 0xed, 0x61, 0xae, 0x5c, 394 0x5d, 0x3e, 0xde, 0xa1, 0x41, 0x35, 0xb2, 0xdf, 395 0x60, 0xe2, 0x61, 0xfe, 0x3a, 0xc1, 0x66, 0xa3, 396 0x3c, 0x88, 0x54, 0x04, 0x4f, 0x1d, 0x13, 0x46, 397 0xe3, 0x8c, 0x06, 0x92, 0x9d, 0x70, 0x54, 0xc3, 398 0x44, 0xeb, 0x2c, 0x74, 0x25, 0x9e, 0x5d, 0xfb, 399 0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01 400 }; 401 QByteArray pca3G5sha1 = QByteArray::fromRawData(baSha1PCA3G5, sizeof(baSha1PCA3G5)); 402 QByteArray pca3G5sha512 = QByteArray::fromRawData(baSha512PCA3G5, sizeof(baSha512PCA3G5)); 403 404 /* Verify certificate: */ 405 return verifyCertificate(pHttp, certificate, pca3G5sha1, pca3G5sha512); 406 } 407 408 /* static */ 409 int UINetworkReplyPrivateThread::verifyCertificatePca3(RTHTTP pHttp, QByteArray &certificate) 410 { 411 /* PCA 3 secure hash algorithm 1: */ 412 const char baSha1PCA3[] = 413 { 414 0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55, 415 0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b 416 }; 417 /* PCA 3 secure hash algorithm 512: */ 418 const char baSha512PCA3[] = 419 { 420 0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2, 421 0xce, 0xc8, 0xaf, 0xe3, 0xd6, 0x22, 0x54, 0x20, 422 0x74, 0x67, 0x6e, 0xa5, 0x19, 0xb7, 0x62, 0x1e, 423 0xc1, 0x2f, 0xd5, 0x08, 0xf4, 0x64, 0xc4, 0xc6, 424 0xbb, 0xc2, 0xf2, 0x35, 0xe7, 0xbe, 0x32, 0x0b, 425 0xde, 0xb2, 0xfc, 0x44, 0x92, 0x5b, 0x8b, 0x9b, 426 0x77, 0xa5, 0x40, 0x22, 0x18, 0x12, 0xcb, 0x3d, 427 0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99 428 }; 429 QByteArray pca3sha1 = QByteArray::fromRawData(baSha1PCA3, sizeof(baSha1PCA3)); 430 QByteArray pca3sha512 = QByteArray::fromRawData(baSha512PCA3, sizeof(baSha512PCA3)); 431 432 /* Verify certificate: */ 433 return verifyCertificate(pHttp, certificate, pca3sha1, pca3sha512); 434 } 435 436 /* static */ 437 int UINetworkReplyPrivateThread::verifyCertificate(RTHTTP pHttp, QByteArray &certificate, const QByteArray &sha1, const QByteArray &sha512) 438 { 439 /* Make sure HTTP is created: */ 440 if (!pHttp) 441 return VERR_INVALID_POINTER; 442 443 /* Create digest: */ 444 uint8_t *abSha1; 445 size_t cbSha1; 446 uint8_t *abSha512; 447 size_t cbSha512; 448 int rc = RTHttpCertDigest(pHttp, certificate.data(), certificate.size(), 449 &abSha1, &cbSha1, &abSha512, &cbSha512); 450 451 /* Verify digest: */ 452 if (cbSha1 != (size_t)sha1.size()) 453 { 454 rc = VERR_HTTP_CACERT_WRONG_FORMAT; 455 } 456 else if (memcmp(sha1.constData(), abSha1, cbSha1)) 457 { 458 rc = VERR_HTTP_CACERT_WRONG_FORMAT; 459 } 460 if (cbSha512 != (size_t)sha512.size()) 461 { 462 rc = VERR_HTTP_CACERT_WRONG_FORMAT; 463 } 464 else if (memcmp(sha512.constData(), abSha512, cbSha512)) 465 { 466 rc = VERR_HTTP_CACERT_WRONG_FORMAT; 467 } 468 469 /* Cleanup digest: */ 470 RTMemFree(abSha1); 471 RTMemFree(abSha512); 472 473 /* Return result-code: */ 474 return rc; 475 } 476 477 /* static */ 478 int UINetworkReplyPrivateThread::saveCertificate(QFile &file, const QByteArray &certificate) 479 { 480 /* Save certificate: */ 481 QSslCertificate formattedCertificate = QSslCertificate::fromData(certificate).first(); 482 int rc = file.write(formattedCertificate.toPem()) != -1 ? VINF_SUCCESS : VERR_WRITE_ERROR; 483 return rc; 484 } 485 221 486 222 487 /* Our network-reply object: */ … … 272 537 case QNetworkReply::HostNotFoundError: 273 538 return tr("Host not found"); 274 break;275 539 case QNetworkReply::ContentAccessDenied: 276 540 return tr("Content access denied"); 277 break;278 541 case QNetworkReply::ProtocolFailure: 279 542 return tr("Protocol failure"); 280 break; 543 case QNetworkReply::AuthenticationRequiredError: 544 return tr("Wrong SSL certificate format"); 545 case QNetworkReply::SslHandshakeFailedError: 546 return tr("SSL authentication failed"); 281 547 default: 282 548 return tr("Unknown reason"); … … 310 576 case VERR_HTTP_BAD_REQUEST: 311 577 m_error = QNetworkReply::ProtocolFailure; 578 break; 579 case VERR_HTTP_CACERT_WRONG_FORMAT: 580 m_error = QNetworkReply::AuthenticationRequiredError; 581 break; 582 case VERR_HTTP_CACERT_CANNOT_AUTHENTICATE: 583 m_error = QNetworkReply::SslHandshakeFailedError; 312 584 break; 313 585 default:
Note:
See TracChangeset
for help on using the changeset viewer.