2015-10-18 735 views
3

我有一个与QTcpSocket一起工作的客户端 - 服务器应用程序。现在我想使用加密的SSL连接,因此我试图切换到QSslSocket。但是我无法建立与服务器的连接。 这里是为客户端的代码:Qt与QSslSocket没有正确连接

ConnectionHandler::ConnectionHandler(QString ip, int port, QObject *parent) : QObject(parent) { 
// connect(this->socket, SIGNAL(connected()), this, SLOT(connected())); 
    connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected())); 
    connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady())); 
    connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(SSLerrorOccured(const QList<QSslError> &))); 
    connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); 
    connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); 

    this->ip = ip; 
    this->port = port; 
} 


void ConnectionHandler::socketStateChanged(QAbstractSocket::SocketState state) { 
    qDebug() << state; 
} 


void ConnectionHandler::socketError(QAbstractSocket::SocketError) { 
    qDebug() << this->socket->errorString(); 
} 


void ConnectionHandler::encryptedReady() { 
    qDebug() << "READY"; 

} 


void ConnectionHandler::SSLerrorOccured(const QList<QSslError> &) { 
    qDebug() << "EEROR"; 
} 


void ConnectionHandler::connectToServer() { 
// this->socket->connectToHost(this->ip, this->port); 
    this->socket->connectToHostEncrypted(this->ip, this->port); 

    if (!this->socket->waitForConnected(5000)) { 
    this->socket->close(); 
    this->errorMsg = this->socket->errorString(); 
    } 
} 


void ConnectionHandler::connected() { 
qDebug() << "connected"; 
    this->connectedHostAddress = this->socket->peerAddress().toString(); 
    this->connectionEstablished = true; 
    this->localIP = this->socket->localAddress().toString(); 
    this->localPort = this->socket->localPort(); 
} 

在这里,一个用于服务器:

ClientHandler::ClientHandler() { 
    this->socket->setProtocol(QSsl::SslV3); 
    this->socket->setSocketOption(QAbstractSocket::KeepAliveOption, true); 
} 

void ClientHandler::run() { 
    if (!this->fd) 
    return; 

    connect(this->socket, SIGNAL(readyRead()), this, SLOT(readyRead())); 
    connect(this->socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection); 
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(encryptedReady())); 
    connect(this->socket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrorOccured(const QList<QSslError> &))); 
    connect(this->socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); 
    connect(this->socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(socketStateChanged(QAbstractSocket::SocketState))); 

    if (!this->socket->setSocketDescriptor(this->fd)) { 
    emit error(socket->error()); 
    return; 
    } else { 
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(ready())); 
    this->socket->startServerEncryption(); 
    } 

    this->peerIP = socket->peerAddress().toString(); 
    QString tmp; 
    tmp.append(QString("%1").arg(socket->peerPort())); 
    this->peerPort = tmp; 

    QHostInfo::lookupHost(this->peerIP, this, SLOT(lookedUp(QHostInfo))); 
} 


void ClientHandler::socketStateChanged(QAbstractSocket::SocketState state) { 
    qDebug() << state; 
} 


void ClientHandler::socketError(QAbstractSocket::SocketError) { 
    qDebug() << this->socket->errorString(); 
} 


void ClientHandler::setFileDescriptor(int fd) { 
    this->fd = fd; 
} 

void ClientHandler::ready() { 
    qDebug() << "READY"; 
} 

void ClientHandler::sslErrorOccured(const QList<QSslError> &) { 
    qDebug() << "EEROR"; 
} 


void ClientHandler::encryptedReady() { 
    qDebug() << "READY"; 

} 

为我接收客户端的输出为:

QAbstractSocket::HostLookupState 
    QAbstractSocket::ConnectingState 
    QAbstractSocket::ConnectedState 
    "The remote host closed the connection" 
    QAbstractSocket::ClosingState 
    QAbstractSocket::UnconnectedState 

和服务器:

QAbstractSocket::ConnectedState 
    "Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher" 
    QAbstractSocket::UnconnectedState 

有谁知道如何解决这个问题?

回答

4

我认为使用非加密套接字一切都很好。所以我们只关注与QSslSocket详细说明的特性。如果需要,我可以分享更大的作品或工作代码。这里还有一个关于SSL证书的大故事,我会在这里简单介绍一下。

首先让我们检查你的客户一些外部SSL的HTTP服务器上,例如:

socket->connectToHostEncrypted("gmail.com", 443); 

应该使用默认SSL协议立即开展工作(没有任何setProtocol())。在信号encrypted()上,您可以编写HTTP GET标头,并在readyRead()上回复。

现在尝试设置socket->setProtocol(QSsl::SslV3);"gmail.com"。预期结果:

sslErrorOccured: ("The host name did not match any of the valid hosts for this certificate") 

注意,它不是error()信号,而是可以通过客户端可以忽略证书问题sslErrors()信号通知。

因此,为了简单起见,我们使用默认的SSL协议而不使用setProtocol()

由于客户端处于工作状态,我们可以移动到服务器。您在第一级SSL认证挑战中被打断。要开始通过服务器初始化SSL连接,您必须至少提供私人加密密钥和公共证书。那是你的错误:

"Error during SSL handshake: error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher" 

在完美的情况下,你的证书应该由认证授权公司签名。在这种情况下,任何拥有此类根证书列表的客户端都能够检查您的证书是否有效。但是,该服务已付款,可能需要几周时间。我们可以从自签名证书开始。

你可以找到各种食谱生成证书,例如:"How to create a self-signed SSL Certificate which can be used for testing purposes or internal usage"

简短摘录:

#Step 1: Generate a Private Key 
openssl genrsa -des3 -out server.key 1024 

#Step 2: Generate a CSR (Certificate Signing Request) 
#Common Name (eg, your name or your server's hostname) []:example.com 
openssl req -new -key server.key -out server.csr 

#Step 3: Remove Passphrase from Key 
cp server.key server.key.org 
openssl rsa -in server.key.org -out server.key 

#Step 4: Generating a Self-Signed Certificate 
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt 

现在有server.keyserver.crt文件。这些文件应该由服务器QSslSocketstartServerEncryption()前通过:

socket->setPrivateKey("c:/test/ssl/cert/server.key", QSsl::Rsa); 
    socket->setLocalCertificate("c:/test/ssl/cert/server.crt"); 

现在服务器可以启动SSL连接。您可以使用浏览器进行测试。通常,浏览器会发出连接不可信的警报。这是因为证书是自签名的,并且无法防止“中间人”攻击。但是,您可以要求浏览器继续该连接。因此,在服务器端,您将在信号readyRead()上获得HTTP GET标头。

尝试连接Qt客户端到该服务器。现在的错误是由客户提出:

sslErrorOccured: ("The certificate is self-signed, and untrusted") 

服务器在error()说:“远程主机关闭了连接”。客户端提出了SSL证书错误,但与浏览器一样,我们可以继续使用该连接。把socket->ignoreSslErrors()sslErrors()信号处理程序:

void Client::sslErrorOccured(const QList<QSslError> & error) { 
    qDebug() << "sslErrorOccured:" << error; 
    socket->ignoreSslErrors(error); 
} 

就是这样。当然,您的客户端不应该接受来自所有服务器的所有SSL证书错误,因为这样的错误意味着连接不安全并且可能被黑客入侵。这只是为了测试。对象QSslError包含证书数据,因此您的客户端可能只接受来自服务器的一个特定自签名证书,并忽略所有其他此类错误。 也可以创建自己的“授权根证书”,您可以手动写入系统。然后,该证书可用于签署您的服务器证书。你的客户端会认为它是可信的连接,因为它可以通过系统根证书来验证它。

请注意,您也可能会遇到与OpenSSL库有关的问题。在Linux或OS X上,OpenSSL采用默认设置,但对于Windows,应该手动安装。一些OpenSSL的编译可能已经存在于Windows系统PATH中,例如CMake有一些有限的OpenSSL库。但是一般来说,对于Windows,您应该将OpenSSL与您的应用程序一起部署。

+0

正如所描述的,thx如此多的一切现在工作! – wasp256