VirtualBox

Ignore:
Timestamp:
Apr 16, 2013 12:34:38 PM (12 years ago)
Author:
vboxsync
Message:

FE/Qt: Network-manager: SSL ca certificate handling integration; Update-manager: New-version notifier will now use HTTPs to check for updates.

File:
1 edited

Legend:

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

    r45551 r45569  
    77
    88/*
    9  * Copyright (C) 2012 Oracle Corporation
     9 * Copyright (C) 2012-2013 Oracle Corporation
    1010 *
    1111 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1818 */
    1919
     20/* Qt includes: */
     21#include <QDir>
     22#include <QFile>
     23#include <QThread>
     24#include <QSslCertificate>
     25
    2026/* GUI includes: */
    2127#include "UINetworkReply.h"
     
    2531
    2632/* Other VBox includes; */
     33#include <iprt/initterm.h>
     34#include <iprt/http.h>
    2735#include <iprt/err.h>
    28 #include <iprt/http.h>
    29 #include <iprt/stream.h>
    30 #include <iprt/initterm.h>
    31 #include <iprt/mem.h>
    3236
    3337/* Our network-reply thread: */
     
    5256private:
    5357
    54     /* Private API: HTTP stuff: */
     58    /* Helpers: HTTP stuff: */
    5559    int applyProxyRules();
     60    int applyHttpsCertificates();
    5661    int applyRawHeaders();
    5762    int performMainRequest();
    5863
    59     /* Helper: Thread runner: */
     64    /* Helper: Main thread runner: */
    6065    void run();
     66
     67    /* Static helper: File stuff: */
     68    static QString fullCertificateFileName();
    6169
    6270    /* Static helpers: HTTP stuff: */
    6371    static int abort(RTHTTP pHttp);
    6472    static int applyProxyRules(RTHTTP pHttp, const QString &strHostName, int iPort);
     73    static int applyCertificates(RTHTTP pHttp, const QString &strFullCertificateFileName);
    6574    static int applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
    6675    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);
    6784
    6885    /* Variables: */
     
    7188    RTHTTP m_pHttp;
    7289    QByteArray m_reply;
     90    static const QString m_strCertificateFileName;
    7391};
     92
     93/* static */
     94const QString UINetworkReplyPrivateThread::m_strCertificateFileName = QString("vbox-ssl-cacertificate.crt");
    7495
    7596UINetworkReplyPrivateThread::UINetworkReplyPrivateThread(const QNetworkRequest &request)
     
    82103void UINetworkReplyPrivateThread::abort()
    83104{
    84     /* Call for HTTP abort: */
     105    /* Call for abort: */
    85106    abort(m_pHttp);
    86107}
     
    99120}
    100121
     122int 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
    101146int UINetworkReplyPrivateThread::applyRawHeaders()
    102147{
     
    122167
    123168    /* 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();
    147187
    148188    /* Destroy HTTP object: */
     
    152192        m_pHttp = 0;
    153193    }
     194}
     195
     196/* static */
     197QString UINetworkReplyPrivateThread::fullCertificateFileName()
     198{
     199    const QDir homeDir(QDir::toNativeSeparators(vboxGlobal().virtualBox().GetHomeFolder()));
     200    return QDir::toNativeSeparators(homeDir.absoluteFilePath(m_strCertificateFileName));
    154201}
    155202
     
    172219        return VERR_INVALID_POINTER;
    173220
    174     /* Assign HTTP proxy: */
     221    /* Apply HTTP proxy: */
    175222    return RTHttpSetProxy(pHttp,
    176223                          strHostName.toAscii().constData(),
     
    180227
    181228/* static */
     229int 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 */
    182240int UINetworkReplyPrivateThread::applyRawHeaders(RTHTTP pHttp, const QList<QByteArray> &headers, const QNetworkRequest &request)
    183241{
     
    198256    const char **ppFormattedHeaders = formattedHeaderPointers.data();
    199257
    200     /* Assign HTTP headers: */
     258    /* Apply HTTP headers: */
    201259    return RTHttpSetHeaders(pHttp, formattedHeaderPointers.size(), ppFormattedHeaders);
    202260}
     
    219277}
    220278
     279/* static */
     280int 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 */
     318int 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 */
     341int 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 */
     361int 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 */
     381int 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 */
     409int 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 */
     437int 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 */
     478int 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
    221486
    222487/* Our network-reply object: */
     
    272537            case QNetworkReply::HostNotFoundError:
    273538                return tr("Host not found");
    274                 break;
    275539            case QNetworkReply::ContentAccessDenied:
    276540                return tr("Content access denied");
    277                 break;
    278541            case QNetworkReply::ProtocolFailure:
    279542                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");
    281547            default:
    282548                return tr("Unknown reason");
     
    310576            case VERR_HTTP_BAD_REQUEST:
    311577                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;
    312584                break;
    313585            default:
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