2017-04-07 164 views
1

Qt的版本: 5.8.0Qt的C++ SSL/TLS服務器與Python客戶端

Python版本: 2.7.13

OpenSSL的版本:的OpenSSL 1.0.1c

操作系統: Windows 10

我正在嘗試創建一個SSL/TLS服務器usin g Qt C++和用Python編寫的客戶端。我正在使用Qt附帶的示例項目sslechoserver。對於Python客戶端的示例,我使用的是我從此Python文檔獲得的一個:https://docs.python.org/2/library/ssl.html。我複製了上述服務器示例中的證書,並將其放在Python腳本旁邊,並指定在我嘗試的測試腳本中。

我也曾經嘗試過各種Python客戶端的例子我已經在互聯網上找到(像這裏:https://carlo-hamalainen.net/blog/2013/1/24/python-ssl-socket-echo-test-with-self-signed-certificate),但沒有一個能夠完全連接到Qt的回聲服務器(它從來沒有打印出來客戶端連接:像它當我使用Qt附帶的示例時)。上面鏈接中的客戶端可以使用來自同一鏈接的Python服務器,所以我知道它仍然適用於某些東西。

Qt的C++服務器代碼

sslechoserver.cpp

/**************************************************************************** 
** 
** Copyright (C) 2016 Kurt Pattyn <[email protected]>. 
** Contact: https://www.qt.io/licensing/ 
** 
** This file is part of the QtWebSockets module of the Qt Toolkit. 
** 
** $QT_BEGIN_LICENSE:BSD$ 
** Commercial License Usage 
** Licensees holding valid commercial Qt licenses may use this file in 
** accordance with the commercial license agreement provided with the 
** Software or, alternatively, in accordance with the terms contained in 
** a written agreement between you and The Qt Company. For licensing terms 
** and conditions see https://www.qt.io/terms-conditions. For further 
** information use the contact form at https://www.qt.io/contact-us. 
** 
** BSD License Usage 
** Alternatively, you may use this file under the terms of the BSD license 
** as follows: 
** 
** "Redistribution and use in source and binary forms, with or without 
** modification, are permitted provided that the following conditions are 
** met: 
** * Redistributions of source code must retain the above copyright 
**  notice, this list of conditions and the following disclaimer. 
** * Redistributions in binary form must reproduce the above copyright 
**  notice, this list of conditions and the following disclaimer in 
**  the documentation and/or other materials provided with the 
**  distribution. 
** * Neither the name of The Qt Company Ltd nor the names of its 
**  contributors may be used to endorse or promote products derived 
**  from this software without specific prior written permission. 
** 
** 
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 
** 
** $QT_END_LICENSE$ 
** 
****************************************************************************/ 
#include "sslechoserver.h" 
#include "QtWebSockets/QWebSocketServer" 
#include "QtWebSockets/QWebSocket" 
#include <QtCore/QDebug> 
#include <QtCore/QFile> 
#include <QtNetwork/QSslCertificate> 
#include <QtNetwork/QSslKey> 

QT_USE_NAMESPACE 

//! [constructor] 
SslEchoServer::SslEchoServer(quint16 port, QObject *parent) : 
    QObject(parent), 
    m_pWebSocketServer(Q_NULLPTR) 
{ 
    m_pWebSocketServer = new QWebSocketServer(QStringLiteral("SSL Echo Server"), 
               QWebSocketServer::SecureMode, 
               this); 
    QSslConfiguration sslConfiguration; 
    QFile certFile(QStringLiteral(":/localhost.cert")); 
    QFile keyFile(QStringLiteral(":/localhost.key")); 
    certFile.open(QIODevice::ReadOnly); 
    keyFile.open(QIODevice::ReadOnly); 
    QSslCertificate certificate(&certFile, QSsl::Pem); 
    QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); 
    certFile.close(); 
    keyFile.close(); 
    sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); 
    sslConfiguration.setLocalCertificate(certificate); 
    sslConfiguration.setPrivateKey(sslKey); 
    sslConfiguration.setProtocol(QSsl::TlsV1SslV3); 
// sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater); 
    m_pWebSocketServer->setSslConfiguration(sslConfiguration); 

    if (m_pWebSocketServer->listen(QHostAddress::Any, port)) 
    { 
     qDebug() << "SSL Echo Server listening on port" << port; 
     connect(m_pWebSocketServer, &QWebSocketServer::newConnection, 
       this, &SslEchoServer::onNewConnection); 
     connect(m_pWebSocketServer, &QWebSocketServer::sslErrors, 
       this, &SslEchoServer::onSslErrors); 
    } 
} 
//! [constructor] 

SslEchoServer::~SslEchoServer() 
{ 
    m_pWebSocketServer->close(); 
    qDeleteAll(m_clients.begin(), m_clients.end()); 
} 

//! [onNewConnection] 
void SslEchoServer::onNewConnection() 
{ 
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); 

    qDebug() << "Client connected:" << pSocket->peerName() << pSocket->origin(); 

    connect(pSocket, &QWebSocket::textMessageReceived, this, &SslEchoServer::processTextMessage); 
    connect(pSocket, &QWebSocket::binaryMessageReceived, 
      this, &SslEchoServer::processBinaryMessage); 
    connect(pSocket, &QWebSocket::disconnected, this, &SslEchoServer::socketDisconnected); 

    m_clients << pSocket; 
} 
//! [onNewConnection] 

//! [processTextMessage] 
void SslEchoServer::processTextMessage(QString message) 
{ 
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender()); 
    if (pClient) 
    { 
     pClient->sendTextMessage(message); 
    } 
} 
//! [processTextMessage] 

//! [processBinaryMessage] 
void SslEchoServer::processBinaryMessage(QByteArray message) 
{ 
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender()); 
    if (pClient) 
    { 
     pClient->sendBinaryMessage(message); 
    } 
} 
//! [processBinaryMessage] 

//! [socketDisconnected] 
void SslEchoServer::socketDisconnected() 
{ 
    qDebug() << "Client disconnected"; 
    QWebSocket *pClient = qobject_cast<QWebSocket *>(sender()); 
    if (pClient) 
    { 
     m_clients.removeAll(pClient); 
     pClient->deleteLater(); 
    } 
} 

void SslEchoServer::onSslErrors(const QList<QSslError> &) 
{ 
    qDebug() << "Ssl errors occurred"; 
} 
//! [socketDisconnected] 

sslechoserver.h

/**************************************************************************** 
** 
** Copyright (C) 2016 Kurt Pattyn <[email protected]>. 
** Contact: https://www.qt.io/licensing/ 
** 
** This file is part of the QtWebSockets module of the Qt Toolkit. 
** 
** $QT_BEGIN_LICENSE:BSD$ 
** Commercial License Usage 
** Licensees holding valid commercial Qt licenses may use this file in 
** accordance with the commercial license agreement provided with the 
** Software or, alternatively, in accordance with the terms contained in 
** a written agreement between you and The Qt Company. For licensing terms 
** and conditions see https://www.qt.io/terms-conditions. For further 
** information use the contact form at https://www.qt.io/contact-us. 
** 
** BSD License Usage 
** Alternatively, you may use this file under the terms of the BSD license 
** as follows: 
** 
** "Redistribution and use in source and binary forms, with or without 
** modification, are permitted provided that the following conditions are 
** met: 
** * Redistributions of source code must retain the above copyright 
**  notice, this list of conditions and the following disclaimer. 
** * Redistributions in binary form must reproduce the above copyright 
**  notice, this list of conditions and the following disclaimer in 
**  the documentation and/or other materials provided with the 
**  distribution. 
** * Neither the name of The Qt Company Ltd nor the names of its 
**  contributors may be used to endorse or promote products derived 
**  from this software without specific prior written permission. 
** 
** 
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 
** 
** $QT_END_LICENSE$ 
** 
****************************************************************************/ 
#ifndef SSLECHOSERVER_H 
#define SSLECHOSERVER_H 

#include <QtCore/QObject> 
#include <QtCore/QList> 
#include <QtCore/QByteArray> 
#include <QtNetwork/QSslError> 

QT_FORWARD_DECLARE_CLASS(QWebSocketServer) 
QT_FORWARD_DECLARE_CLASS(QWebSocket) 

class SslEchoServer : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit SslEchoServer(quint16 port, QObject *parent = Q_NULLPTR); 
    virtual ~SslEchoServer(); 

private Q_SLOTS: 
    void onNewConnection(); 
    void processTextMessage(QString message); 
    void processBinaryMessage(QByteArray message); 
    void socketDisconnected(); 
    void onSslErrors(const QList<QSslError> &errors); 

private: 
    QWebSocketServer *m_pWebSocketServer; 
    QList<QWebSocket *> m_clients; 
}; 

#endif //SSLECHOSERVER_H 

的main.cpp

/**************************************************************************** 
** 
** Copyright (C) 2016 Kurt Pattyn <[email protected]>. 
** Contact: https://www.qt.io/licensing/ 
** 
** This file is part of the QtWebSockets module of the Qt Toolkit. 
** 
** $QT_BEGIN_LICENSE:BSD$ 
** Commercial License Usage 
** Licensees holding valid commercial Qt licenses may use this file in 
** accordance with the commercial license agreement provided with the 
** Software or, alternatively, in accordance with the terms contained in 
** a written agreement between you and The Qt Company. For licensing terms 
** and conditions see https://www.qt.io/terms-conditions. For further 
** information use the contact form at https://www.qt.io/contact-us. 
** 
** BSD License Usage 
** Alternatively, you may use this file under the terms of the BSD license 
** as follows: 
** 
** "Redistribution and use in source and binary forms, with or without 
** modification, are permitted provided that the following conditions are 
** met: 
** * Redistributions of source code must retain the above copyright 
**  notice, this list of conditions and the following disclaimer. 
** * Redistributions in binary form must reproduce the above copyright 
**  notice, this list of conditions and the following disclaimer in 
**  the documentation and/or other materials provided with the 
**  distribution. 
** * Neither the name of The Qt Company Ltd nor the names of its 
**  contributors may be used to endorse or promote products derived 
**  from this software without specific prior written permission. 
** 
** 
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 
** 
** $QT_END_LICENSE$ 
** 
****************************************************************************/ 
#include <QtCore/QCoreApplication> 
#include "sslechoserver.h" 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    SslEchoServer server(1234); 

    Q_UNUSED(server); 

    return a.exec(); 
} 

Python客戶端代碼(只是我嘗試者之一)

import socket, ssl 

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) 
context.verify_mode = ssl.CERT_REQUIRED 
context.check_hostname = True 
context.load_verify_locations("localhost.cert") 
# context.load_default_certs() 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
ssl_sock = context.wrap_socket(s, server_hostname='localhost') 
ssl_sock.connect(('localhost', 1234)) 

回答

0

原來我不得不讓我的Python客戶端連接使用WSS。我從https://pypi.python.org/pypi/websocket-client安裝了Websocket(0.40),並使用下面的示例腳本。我用Python 3.6.1,但我認爲2.7.x也可能工作。

import websocket 
import time 
import ssl 

if __name__ == "__main__": 
    websocket.enableTrace(True) 
    ws = websocket.WebSocket(sslopt={"ca_certs": "localhost.cert", 
             "cert_reqs": ssl.CERT_REQUIRED}) 
    ws.connect("wss://localhost:1234") 
    print ("Sending 'Hello, World'...") 
    ws.send("Hello, World") 
    print ("Sent") 
    print ("Receiving...") 
    result = ws.recv() 
    print ("Received '%s'" % result) 
    ws.close()