客户端应用程序如何使用Qt中的自签名证书连接到SSL服务器?

问题描述:

我想与具有ssl和端口995的POP3服务器与我的客户端应用程序
进行通信,服务器的证书是自签名的,并且在运行应用程序时收到的错误是:

I want to communicate with a POP3 server with ssl and port 995 with my client app the certificate of server is self-signed and while running the app the error that received is:


证书是自签名和不可信的

The certificate is self-signed, and untrusted

代码是:

socket = new QSslSocket(this);
QFile certfile("D:\\hani\\cert\\localhost.localdomain.pem");
Q_ASSERT(certfile.open(QIODevice::ReadOnly));
QList<QSslCertificate> certList;
QSslCertificate cert(&certfile,QSsl::Pem);
certList.append(cert);
socket->addCaCertificate(cert);
socket->setCaCertificates(certList);
QList<QSslCertificate> serverCert = socket->caCertificates();

我能做什么?

不要让我重复一遍,不要调用 ignoreSslErrors()。它完全违反了SSL / TLS的目的。有 个特殊情况可以安全地调用,但这个(自签名证书)不是特殊情况。

DO NOT, let me repeat, DO NOT call ignoreSslErrors(). It completely defeats the purpose of SSL/TLS. There are very special cases where it can be called safely, but this (self-signed certificate) is not a special case.

最小代码,准备运行,说明如何安全地 接受服务器自签名证书。

The following minimal code, ready to run, shows how to securely accept a server self-signed certificate. Do not shortcut it.

驱动程序:

int main(int argc, char** argv) {
    QCoreApplication app(argc, argv);
    QTextStream log(stdout);
    DummyClient dummy(log);
    QObject::connect(&dummy, SIGNAL(done()), &app, SLOT(quit()));
    return app.exec();
}

DummyClient

/*
 * Show how to safely authenticate a TLS server which uses a self-signed certificate.
 * Warning: No error handling to keep the code short.
 */
class DummyClient : public QObject {
    Q_OBJECT
public:
    DummyClient(QTextStream& log)
        : _log(log),
          _sock(new QSslSocket(this)) {
        connect(_sock, SIGNAL(encrypted()), this, SLOT(onEncrypted()));
        connect(_sock, SIGNAL(sslErrors(QList<QSslError>)),
                this, SLOT(onSslErrors(QList<QSslError>)));
        connect(_sock, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(onErrors(QAbstractSocket::SocketError)));

        // Trust store: which CAs or self-signed certs we are going to trust.
        //
        // We use setCaCertificates() instead than QSslSocket::addCaCertificates()
        // because we don't want to trust the ~200 default CAs.
        QList<QSslCertificate> trustedCas = QSslCertificate::fromPath("server-cert.pem");
        if (trustedCas.empty()) {
            qFatal("Error: no trusted Cas");
        }
        _sock->setCaCertificates(trustedCas);

        bool mutualAuth = false;
        if (mutualAuth) {
            // Our identity
            _sock->setPrivateKey("client-key.pem");
            _sock->setLocalCertificate("client-cert.pem");
        }

        _log << "Connecting" << endl;
        // Note: serverName must match the cert CN or alternative name.
        Qstring serverName = "myserver.example.org";
        _sock->connectToHostEncrypted(serverName, 995);
    }

signals:
    void done();

private slots:
    void onEncrypted() {
        _log << "onEncrypted" << endl;

        /* Everything is good. Start communicating. */

        emit done();
    }

    void onSslErrors(QList<QSslError> errors) {
        QSslError first = errors.takeFirst();
        _log << "onSslErrors: " << first.errorString() << endl;

        /* Something went wrong in the TLS handshake. Inform the user and quit! */

        emit done();
    }

    void onErrors(QAbstractSocket::SocketError) {
        _log << "onErrors: " << _sock->errorString() << endl;
        emit done();
    }

private:
    QTextStream& _log;
    QSslSocket* _sock;
};