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

时间:2014-05-06 11:22:36

标签: c++ qt ssl boost

我有以下三个文件: 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错误:主机名与此证书的任何有效主机都不匹配。 当我用cert切换ca时,它花了更长时间才能失败,但我没有收到任何错误。

3 个答案:

答案 0 :(得分:1)

  1. 创建密钥和证书。我在 Linux 控制台中使用下一个命令:
<块引用>

openssl genrsa 2048 > server.key

<块引用>

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

当openssl问你常用名时请输入localhost,其他可以空白。

2.0。创建 qt 项目 ssl_client 并将下一个代码添加到 ma​​in.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 并将下一个代码添加到 ma​​in.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 );
}
  1. 为每个项目添加 QT += network 到 *.pro 文件

  2. 构建ssl_serverssl_client项目

  3. 复制server.keyserver.certssl_server项目的bin目录

  4. 只复制server.certssl_client项目的bin目录

  5. 先运行 ssl_server,然后运行 ​​ssl_client,您可以在 ssl_server 的控制台中看到下一个结果:

start listening "192.168.31.46" on port 8000

encrypted

"hello world!"

答案 1 :(得分:0)

这是一个示例SSL客户端和服务器,它使用server.key和server.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 );
}

您应该为您的应用程序生成server.key和server.crt文件。

答案 2 :(得分:0)

我有同样的任务:BOOST的SSL服务器:ASIO, Qt的SSL客户端 5.8。对于服务器端,我使用了给定的示例。 对于Qt客户端,我有很长时间尝试,但同时发现了一个解决方案 - 连接加密但不完整的同行识别。 这是一段代码剪辑 - 对不起q&amp; 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;
}