Документация
ОС Аврора 5.0.1

ssltest.cpp

В приведённом ниже коде показано, как создать SSL-клиент.

/*
 Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com>
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include <QtCrypto>
 
#include <QCoreApplication>
#include <QTcpSocket>
 
#ifdef QT_STATICPLUGIN
#include "import_plugins.h"
#endif
 
char exampleCA_cert[] =
    "-----BEGIN CERTIFICATE-----\n"
    "MIICSzCCAbSgAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRMwEQYDVQQDEwpFeGFt\n"
    "cGxlIENBMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwHhcNMDYw\n"
    "MzE1MDY1ODMyWhcNMDYwNDE1MDY1ODMyWjA4MRMwEQYDVQQDEwpFeGFtcGxlIENB\n"
    "MQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwgZ8wDQYJKoZIhvcN\n"
    "AQEBBQADgY0AMIGJAoGBAL6ULdOxmpeZ+G/ypV12eNO4qnHSVIPTrYPkQuweXqPy\n"
    "atwGFheG+hLVsNIh9GGOS0tCe7a3hBBKN0BJg1ppfk2x39cDx7hefYqjBuZvp/0O\n"
    "8Ja3qlQiJLezITZKLxMBrsibcvcuH8zpfUdys2yaN+YGeqNfjQuoNN3Byl1TwuGJ\n"
    "AgMBAAGjZTBjMB0GA1UdDgQWBBSQKCUCLNM7uKrAt5o7qv/yQm6qEzASBgNVHRMB\n"
    "Af8ECDAGAQEBAgEIMB4GA1UdEQQXMBWBE2V4YW1wbGVAZXhhbXBsZS5jb20wDgYD\n"
    "VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAAh+SIeT1Ao5qInw8oMSoTdO\n"
    "lQ6h67ec/Jk5KmK4OoskuimmHI0Sp0C5kOCLehXbsVWW8pXsNC2fv0d2HkdaSUcX\n"
    "hwLzqgyZXd4mupIYlaOTZhuHDwWPCAOZS4LVsi2tndTRHKCP12441JjNKhmZRhkR\n"
    "u5zzD60nWgM9dKTaxuZM\n"
    "-----END CERTIFICATE-----\n";
 
void showCertInfo(const QCA::Certificate &cert)
{
    printf("-- Сертификат --\n");
    printf(" CN: %s\n", qPrintable(cert.commonName()));
    printf(" Действителен с: %s, until %s\n",
           qPrintable(cert.notValidBefore().toString()),
           qPrintable(cert.notValidAfter().toString()));
    printf(" PEM:\n%s\n", qPrintable(cert.toPEM()));
}
 
static QString validityToString(QCA::Validity v)
{
    QString s;
    switch (v) {
    case QCA::ValidityGood:
        s = QStringLiteral("Подтверждён");
        break;
    case QCA::ErrorRejected:
        s = QStringLiteral("Корневой ЦС отклоняет назначение сертификата");
        break;
    case QCA::ErrorUntrusted:
        s = QStringLiteral("Сертификат не является доверенным для заданного назначения");
        break;
    case QCA::ErrorSignatureFailed:
        s = QStringLiteral("Неверная подпись");
        break;
    case QCA::ErrorInvalidCA:
        s = QStringLiteral("Недействительный сертификат ЦС");
        break;
    case QCA::ErrorInvalidPurpose:
        s = QStringLiteral("Недопустимое назначение сертификата");
        break;
    case QCA::ErrorSelfSigned:
        s = QStringLiteral("Сертификат самоподписанный");
        break;
    case QCA::ErrorRevoked:
        s = QStringLiteral("Сертификат отозван");
        break;
    case QCA::ErrorPathLengthExceeded:
        s = QStringLiteral("Превышена максимальная длина цепочки сертификатов");
        break;
    case QCA::ErrorExpired:
        s = QStringLiteral("Срок действия сертификата истёк");
        break;
    case QCA::ErrorExpiredCA:
        s = QStringLiteral("Срок действия ЦС истёк");
        break;
    case QCA::ErrorValidityUnknown:
    default:
        s = QStringLiteral("Общая ошибка проверки сертификата");
        break;
    }
    return s;
}
 
class SecureTest : public QObject
{
    Q_OBJECT
public:
    SecureTest()
    {
        sock_done = false;
        ssl_done  = false;
 
        sock = new QTcpSocket;
        connect(sock, &QTcpSocket::connected, this, &SecureTest::sock_connected);
        connect(sock, &QTcpSocket::readyRead, this, &SecureTest::sock_readyRead);
        connect(sock, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &SecureTest::sock_error);
 
        ssl = new QCA::TLS;
        connect(ssl, &QCA::TLS::certificateRequested, this, &SecureTest::ssl_certificateRequested);
        connect(ssl, &QCA::TLS::handshaken, this, &SecureTest::ssl_handshaken);
        connect(ssl, &QCA::TLS::readyRead, this, &SecureTest::ssl_readyRead);
        connect(ssl, &QCA::TLS::readyReadOutgoing, this, &SecureTest::ssl_readyReadOutgoing);
        connect(ssl, &QCA::TLS::closed, this, &SecureTest::ssl_closed);
        connect(ssl, &QCA::TLS::error, this, &SecureTest::ssl_error);
    }
 
    ~SecureTest() override
    {
        delete ssl;
        delete sock;
    }
 
    void start(const QString &_host)
    {
        int n = _host.indexOf(QLatin1Char(':'));
        int port;
        if (n != -1) {
            host = _host.mid(0, n);
            port = _host.midRef(n + 1).toInt();
        } else {
            host = _host;
            port = 443;
        }
 
        printf("Попытка %s:%d…\n", qPrintable(host), port);
        sock->connectToHost(host, port);
    }
 
Q_SIGNALS:
    void quit();
 
private Q_SLOTS:
    void sock_connected()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        printf("Подключено, начинается рукопожатие TLS…\n");
 
        QCA::CertificateCollection rootCerts = QCA::systemStore();
 
        // Сертификат добавляется, чтобы показать работу, и чтобы он взаимодействовал
        // с примером сервера.
        rootCerts.addCertificate(QCA::Certificate::fromPEM(QString::fromLatin1(exampleCA_cert)));
 
        if (!QCA::haveSystemStore())
            printf("Предупреждение: корневых сертификатов нет\n");
        else
            ssl->setTrustedCertificates(rootCerts);
 
        ssl->startClient(host);
    }
 
    void sock_readyRead()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        ssl->writeIncoming(sock->readAll());
    }
 
    void sock_connectionClosed()
    {
        printf("\nСоединение закрыто.\n");
        sock_done = true;
 
        if (ssl_done && sock_done)
            emit quit();
    }
 
    void sock_error(QAbstractSocket::SocketError x)
    {
        if (x == QAbstractSocket::RemoteHostClosedError) {
            sock_connectionClosed();
            return 0;
        }
 
        printf("\nОшибка сокета.\n");
        emit quit();
    }
 
    void ssl_handshaken()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        QCA::TLS::IdentityResult r = ssl->peerIdentityResult();
 
        printf("Успешное установление соединения SSL с использованием %s (%i из %i битов)\n",
               qPrintable(ssl->cipherSuite()),
               ssl->cipherBits(),
               ssl->cipherMaxBits());
        if (r != QCA::TLS::NoCertificate) {
            cert = ssl->peerCertificateChain().primary();
            if (!cert.isNull())
                showCertInfo(cert);
        }
 
        QString str = QStringLiteral("Идентификация второго участника: ");
        if (r == QCA::TLS::Valid)
            str += QStringLiteral("Действителен");
        else if (r == QCA::TLS::HostMismatch)
            str += QStringLiteral("Ошибка: неверный сертификат");
        else if (r == QCA::TLS::InvalidCertificate)
            str += QStringLiteral("Ошибка: недопустимый сертификат.\n -> Причина: ") +
                validityToString(ssl->peerCertificateValidity());
        else
            str += QStringLiteral("Ошибка: нет сертификата");
        printf("%s\n", qPrintable(str));
 
        ssl->continueAfterStep();
 
        printf("Попытка запроса GET.\n");
        QString req = QStringLiteral("GET / HTTP/1.0\nHost: ") + host + QStringLiteral("\n\n");
        ssl->write(req.toLatin1());
    }
 
    void ssl_certificateRequested()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        printf("Сервер запросил сертификат клиента.\n");
        QList<QCA::CertificateInfoOrdered> issuerList = ssl->issuerList();
        if (!issuerList.isEmpty()) {
            printf("Разрешённые издатели:\n");
            foreach (QCA::CertificateInfoOrdered i, issuerList)
                printf("  %s\n", qPrintable(i.toString()));
        }
 
        ssl->continueAfterStep();
    }
 
    void ssl_readyRead()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        QByteArray a = ssl->read();
        printf("%s", a.data());
    }
 
    void ssl_readyReadOutgoing()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        sock->write(ssl->readOutgoing());
    }
 
    void ssl_closed()
    {
        printf("Сеанс SSL закрыт.\n");
        ssl_done = true;
 
        if (ssl_done && sock_done)
            emit quit();
    }
 
    void ssl_error()
    {
        
        QCA::TLS *ssl = SecureTest::ssl;
 
        int x = ssl->errorCode();
        if (x == QCA::TLS::ErrorHandshake) {
            printf("Ошибка установления соединения SSL!\n");
            emit quit();
        } else {
            printf("Ошибка SSL!\n");
            emit quit();
        }
    }
 
private:
    QString          host;
    QTcpSocket *     sock;
    QCA::TLS *       ssl;
    QCA::Certificate cert;
    bool             sock_done, ssl_done;
};
 
#include "ssltest.moc"
 
int main(int argc, char **argv)
{
    QCA::Initializer init;
 
    QCoreApplication app(argc, argv);
    QString          host = argc > 1 ? QString::fromLocal8Bit(argv[1]) : QStringLiteral("andbit.net");
 
    if (!QCA::isSupported("tls")) {
        printf("TLS не поддерживается!\n");
        return 1;
    }
 
    SecureTest *s = new SecureTest;
    QObject::connect(s, &SecureTest::quit, &app, &QCoreApplication::quit);
    s->start(host);
    app.exec();
    delete s;
 
    return 0;
}

Мы используем cookies для персонализации сайта и его более удобного использования. Вы можете запретить cookies в настройках браузера.

Пожалуйста ознакомьтесь с политикой использования cookies.