在QT中创建成功的SSL握手的正确方法是什么?

What is the correct way to create succesfull SSL handshake in QT?

本文关键字:方法 是什么 SSL QT 创建 成功      更新时间:2023-10-16

我有以下三个文件:key。pem cert。pem ca。pem和创建到服务器的SSL连接的工作代码。它是使用boost库创建的。

工作升压代码:

ssl::context ctx(io_service, ssl::context::sslv23);
ctx.set_password_callback(password_callback);
ctx.load_verify_file("ca.pem");
ctx.set_verify_mode(ssl::context_base::verify_peer);
ctx.use_certificate_file("cert.pem", ssl::context::pem);
ctx.use_private_key_file("key.pem", ssl::context::pem);

我必须使用Qt5和它的QSslSocket重写这个客户端代码。

到目前为止,我创建了这个代码(有许多小的变化-切换文件,更改密码编码):

    QSslSocket ssl;
    QList<QSslCertificate> certy = QSslCertificate::fromPath("C:\ssltest\cert.pem");
    ssl.setCaCertificates(certy);
    ssl.setLocalCertificate(QString("C:\ssltest\ca.pem"));
   ssl.setPrivateKey(QString("C:\ssltest\key.pem"),QSsl::Rsa,QSsl::Pem,QString("password").toUtf8());

    ssl.connectToHostEncrypted(QString("192.168.90.41"),6500);
    if(ssl.waitForEncrypted()){
        cout << "SSL handsake succesful!" << endl;
    } else {
        cout << "Something went terribly wrong!" << endl;
    }

但是我的Qt代码不能实现成功的SSL握手(TCP连接是成功的)。我做错了什么?

我立即得到这个SSL错误:主机名与此证书的任何有效主机不匹配。

当我切换ca和cert时,它失败需要更长的时间,但我没有得到任何错误

  1. 创建密钥和证书。我在Linux控制台中使用next命令:

openssl genrsa 2048>server.key

openssl req -new -x509 -nodes -sha256 -days 365 -key server. shKey out server.cert

当openssl询问您的通用名时请输入localhost,其他可以是blanc。

2.0。创建qt项目ssl_client并添加下一个代码到main.c

#include <QCoreApplication>
#include "ssl_client.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ssl_client client(8000);
    return a.exec();
}

2.1。使用下一个代码

创建ssl_client.h
#include <QtNetwork>
class ssl_client : public QObject
{
    Q_OBJECT
public:
    ssl_client(quint16 port);
private:
    void setUp();
    QSslSocket socket;
};

2.2。使用下一个代码

创建ssl_client.cpp
#include "ssl_client.h"
ssl_client::ssl_client(quint16 port): socket(this)
{
    setUp();
    socket.connectToHostEncrypted("localhost", port);
    socket.write("hello world!");
}
void ssl_client::setUp(){
    QByteArray cert;
    QFile file_cert("server.cert");
    if(file_cert.open(QIODevice::ReadOnly)){
        cert = file_cert.readAll();
        file_cert.close();
    }
    else{
        qDebug() << file_cert.errorString();
    }
    QSslCertificate ssl_cert(cert);
    QList<QSslCertificate> listCA;
    listCA.append(ssl_cert);
    QSslConfiguration conf;
    conf.setCaCertificates(listCA);
    socket.setSslConfiguration(conf);
}

3.0。创建qt项目ssl_server并添加下一个代码到main.c

#include <QCoreApplication>
#include "ssl_server.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ssl_server server(8000);
    return a.exec();
}

2.1。使用下一个代码

创建ssl_server.h
#include <QtNetwork>
class ssl_server: public QTcpServer
{
    Q_OBJECT
public:
    ssl_server(quint16 port);
protected:
    void incomingConnection(qintptr socketDescriptor) override;
private slots:
    void ready();
    void printData();
private:
    void setUp();
    QSslSocket serverSocket;
};

2.2。使用下一个代码

创建ssl_server.cpp
#include "ssl_server.h"
ssl_server::ssl_server(quint16 port): QTcpServer(), serverSocket(this)
{
    if (!this->listen(QHostAddress::LocalHost, port)) {
        qDebug() << "start listen port" << port << "failed";
        this->close();
        return;
    }
    else{
        foreach (const QNetworkInterface &netInterface, QNetworkInterface::allInterfaces()) {
            QNetworkInterface::InterfaceFlags flags = netInterface.flags();
            if( (bool)(flags & QNetworkInterface::IsRunning) && !(bool)(flags & QNetworkInterface::IsLoopBack)){
                foreach (const QNetworkAddressEntry &address, netInterface.addressEntries()) {
                    if(address.ip().protocol() == QAbstractSocket::IPv4Protocol){
                        qDebug() << "start listening " << address.ip().toString() <<  " on port" << port;
                    }
                }
            }
        }
    }
    setUp();
}
void ssl_server::incomingConnection(qintptr socketDescriptor)
 {
     if (serverSocket.setSocketDescriptor(socketDescriptor)) {
         addPendingConnection(&serverSocket);
         serverSocket.startServerEncryption();
     } else {
         serverSocket.close();
     }
 }
void ssl_server::ready(){
    qDebug() << "encrypted";
}
void ssl_server::printData(){
    QByteArray array = serverSocket.read(serverSocket.bytesAvailable());
    qDebug() << array;
}
void ssl_server::setUp(){
    QByteArray key;
    QByteArray cert;
    QFile file_key("server.key");
    if(file_key.open(QIODevice::ReadOnly)) {
        key = file_key.readAll();
        file_key.close();
    }
    else{
        qDebug() << file_key.errorString();
    }
    QFile file_cert("server.cert");
    if(file_cert.open(QIODevice::ReadOnly)){
        cert = file_cert.readAll();
        file_cert.close();
    }
    else{
        qDebug() << file_cert.errorString();
    }
    QSslKey ssl_key(key, QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,"localhost");
    QSslCertificate ssl_cert(cert);
    serverSocket.setLocalCertificate(ssl_cert);
    serverSocket.setPrivateKey(ssl_key);
    connect(&serverSocket, SIGNAL(encrypted()), this, SLOT(ready()));
    connect(&serverSocket, SIGNAL(readyRead()), this, SLOT(printData()) );
    serverSocket.setSocketOption(QAbstractSocket::KeepAliveOption, true );
}
  • 将每个项目的QT += network添加到*。箴文件

  • 构建ssl_serverssl_client项目

  • <
  • 副本strong>服务器。键和服务器。cert to bin目录ssl_server project

  • 只能复制服务器。cert to bin目录ssl_client project

  • 首先运行ssl_server,然后运行ssl_client,您可以在控制台中看到ssl_server:

    的结果。
  • start listening "192.168.31.46" on port 8000

    encrypted

    "hello world!"

    下面是一个使用服务器的SSL客户端和服务器示例。密钥和服务器。CRT文件加密:

    服务器端:

    #include <QtNetwork>
    #include <QMessageBox>
    class server : public QTcpServer
    {
        Q_OBJECT
    public:
        explicit server(QObject *parent = 0);
        ~server();
        QSslSocket server_socket;
    public slots:
    
          void tcpReady();
          void encrypted();
          void sslError( QList<QSslError> errors );
          bool start_listen(int port_no);
    protected:
        void incomingConnection( int descriptor );
    };
    server::server(QObject *parent) :
        QTcpServer(parent)
    {
        server_socket.setProtocol(QSsl::SslV3);
        QByteArray key;
        QByteArray cert;
        QFile file_key("server.key");
        if(file_key.open(QIODevice::ReadOnly))
        {
            key = file_key.readAll();
            file_key.close();
        }
        else
        {
            qDebug() << file_key.errorString();
        }
        QFile file_cert("server.crt");
        if(file_cert.open(QIODevice::ReadOnly))
        {
            cert = file_cert.readAll();
            file_cert.close();
        }
        else
        {
            qDebug() << file_cert.errorString();
        }
    
        QSslKey ssl_key(key, QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,"server");
        QSslCertificate ssl_cert(cert);
        server_socket.addCaCertificate(ssl_cert);
        server_socket.setLocalCertificate(ssl_cert);
        server_socket.setPrivateKey(ssl_key);
    
        connect( &server_socket, SIGNAL(sslErrors(QList<QSslError>)),
                this, SLOT(sslError(QList<QSslError>)) );
        connect(&server_socket,SIGNAL(encrypted()),this,SLOT(encrypted()));
        server_socket.setSocketOption(QAbstractSocket::KeepAliveOption, true );
    }
    server::~server()
    {
        server_socket.disconnectFromHost();
        server_socket.waitForDisconnected();
    }
    void server::tcpReady()
    {
        QByteArray array = server_socket.read( server_socket.bytesAvailable() );
        //...
    }
    void server::encrypted()
    {
        connect( &server_socket, SIGNAL(readyRead()),
                 this, SLOT(tcpReady()) );
        emit connection_established();
    }
    void server::sslError(QList<QSslError> errors)
    {
        QString erroStr="";
        foreach (const QSslError &e, errors)
            erroStr.append(e.errorString()).append("n");
        QMessageBox::warning( (QWidget *)this->parent(), tr("Error"),erroStr );
        server_socket.ignoreSslErrors();
    }
    
    bool server::start_listen(int port_no)
    {
        if( !this->listen( QHostAddress::Any, port_no ) )
        {
            QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Cannot listen to port %1").arg(port_no) );
        }
        else
            return true;
    }
    void server::incomingConnection(int descriptor)
    {
        if(server_socket.state()!=QAbstractSocket::UnconnectedState)
            return;
        if( !server_socket.setSocketDescriptor( descriptor ) )
        {
            QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Socket error!") );
            return;
        }
        else
        {
            server_socket.startServerEncryption();
        }
    }
    

    客户端:

    class Client : public QObject
    {
        Q_OBJECT
    public:
        explicit Client(QObject *parent = 0);
        ~Client();
        QSslSocket client_socket;
    private slots:
        void tcpReady();
        void sslError( QList<QSslError> errors );
        void TCPError( QAbstractSocket::SocketError error );
        void connectToServer();
    };
    
    Client::Client(QObject *parent) :
        QObject(parent)
    {
        client_socket.setProtocol(QSsl::SslV3);
        connect( &client_socket, SIGNAL(error(QAbstractSocket::SocketError)),
                this, SLOT(TCPError(QAbstractSocket::SocketError)) );
        connect( &client_socket, SIGNAL(sslErrors(QList<QSslError>)),
                this, SLOT(sslError(QList<QSslError>)) );
        connect( &client_socket, SIGNAL(readyRead()),
                this, SLOT(tcpReady()) );
    }
    Client::~Client()
    {
    }
    void Client::tcpReady()
    {
        QByteArray array = client_socket.read( client_socket.bytesAvailable() );
        //...
    }
    void Client::sslError(QList<QSslError> errors)
    {
        client_socket.ignoreSslErrors();
    }
    void Client::TCPError(QAbstractSocket::SocketError error)
    {
    }
    
    void Client::connectToServer()
    {
        client_socket.abort();
        client_socket.connectToHostEncrypted("192.168.0.10", 8000 );
    }
    

    您应该生成一个服务器。密钥和服务器。

    我有同样的任务:SSL服务器BOOST:ASIO, SSL客户端Qt 5.8。对于服务器端,我使用了给定的示例。对于Qt客户端,我花了很长时间尝试,但同时找到了一个解决方案-连接加密但不完整的对等识别。下面是一段代码剪辑-抱歉q&d:

    CQtSsl::CQtSsl()
    {
        m_SslSocket = NULL;
        QString SCertificatePath = "ca.pem";
        m_nSslError = -1;
        m_sSslError = "";
        if (QSslSocket::supportsSsl())
        {
            m_nSslError = 0;
            m_sSslError = "SSL is installed.";
        }
        else
        {
            m_nSslError = -101;
            m_sSslError = "Missing SSL installation.";
        }
        QList<QSslCertificate> CertList = QSslCertificate::fromPath(SCertificatePath);
        if (CertList.count() < 1)
        {
            m_nSslError = -11;
            m_sSslError = "No valid CA-Certifacte found: " + SCertificatePath;
        }
        m_caCertificate = CertList.at(0);
        QString sCertInfo = m_caCertificate.toText();
        if (m_nSslError == 0)
        {
            m_SslSocket = new QSslSocket();
            if (!m_SslSocket)
            {
                m_nSslError = -2;
                m_sSslError = "Creation of SSL-Socket failed!";
            }
        }
        if (m_nSslError == 0)
        {
            m_SslSocket->addCaCertificates(SCertificatePath);
        }
        if (m_nSslError == 0)
        {
            QSslConfiguration sslConfig = m_SslSocket->sslConfiguration();
            sslConfig.setPeerVerifyMode(QSslSocket::QueryPeer);
            //sslConfig.setProtocol(QSsl::SslV2);
            sslConfig.setSslOption(QSsl::SslOptionDisableServerNameIndication, true);
            m_SslSocket->setSslConfiguration(sslConfig);
        }
        if (m_nSslError == 0)
        {
            m_nSslError = 0;
            m_sSslError = "Client SSL-Socket established sucessfully.";
        }
    }
    int CQtSsl::Connect1(QString spHost, int npPort)
    {
        if (m_nSslError != 0)
        {
            m_sSslError = "Client SSL-Socket not initialized properly";
            return m_nSslError;
        }
        m_nSslError = -10;
        connect(m_SslSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));
        connect(m_SslSocket, SIGNAL(encrypted()), this, SLOT(connection_encrypted()));
        connect(m_SslSocket, SIGNAL(disconnected()), this, SLOT(connection_disconnected()));
        connect(m_SslSocket, SIGNAL(encrypted()), this, SLOT(ready()));
        connect(m_SslSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>))); 
        connect(m_SslSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
        m_SslSocket->connectToHostEncrypted(spHost, npPort, "client", QIODevice::ReadWrite, QAbstractSocket::IPv4Protocol);
        if (!m_SslSocket->waitForEncrypted())
        {
            QList<QSslError> errList = m_SslSocket->sslErrors();
            QAbstractSocket::SocketError err = m_SslSocket->error();
            m_sSslError = m_SslSocket->errorString() + ".";
            m_sSslError += " Connection failed.";
            m_nSslError = -10;
        }
        m_nSslError = 0;
        return m_nSslError;
    }
    int CQtSsl::Send(QByteArray paBuffer)
    {
        int nReturn = -1;
        if (m_nSslError != 0)
        {
            return m_nSslError;
        }
        bool bEncrypted = m_SslSocket->isEncrypted();
        nReturn = m_SslSocket->write(paBuffer);
        bool bFlush = m_SslSocket->flush();
        return nReturn;
    }
    int CQtSsl::Send(QString spToSend)
    {
        QByteArray aBuffer = spToSend.toUtf8();
        aBuffer.append((char)0);
        return Send(aBuffer);
    }
    void CQtSsl::connection_encrypted()
    {
        int nDebug = 1; // Do something (log...)
    }
    void CQtSsl::connection_disconnected()
    {
        int nDebug = 1; // Do something (log...)
    }
    void CQtSsl::ready()
    {
        int nDebug = 1; // Do something (log...)
    }
    void CQtSsl::readyRead()
    {
        ReadBuffer = m_SslSocket->readAll();
    }
    void sslErrors(QList<QSslError> sslErrors)
    {
        int nDebug = 1; // Do something (log...)
    }
    int CQtSsl::GetLastError()
    {
        return m_nSslError;
    }
    QString CQtSsl::GetLastErrorDesc()
    {
        return m_sSslError;
    }