c++ - 在 Qt 5.2.1 上编写的 SSL 服务器的 SSL 握手失败

标签 c++ qt ssl proxy man-in-the-middle

我正在使用 Qt 编写 ssl 代理服务器。这是代码示例:

# header
class SslProxyServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit SslProxyServer(quint16 port, QObject *parent = 0);

private slots:
    void onEncrypted();
    void onReadyRead();
    void onSslErrors(QList<QSslError> sslErrors);
    void onModeChanged(QSslSocket::SslMode sslMode);
    void onStateChanged(QAbstractSocket::SocketState socketState);
    void onError(QAbstractSocket::SocketError socketError);

protected:
    void incomingConnection(qintptr socketDescriptor);
};

# source
SslProxyServer::SslProxyServer(quint16 port, QObject *parent) : QTcpServer(parent)
{
    if (!listen(QHostAddress::Any, port)) {
        qDebug() << "Unable to start tcp server";
        return;
    }
    if (m_tcpServer->isListening()) {
        qDebug() << "Listening port" << m_tcpServer->serverPort();
    } else {
        qDebug() << "Not listening";
    }
}

void SslProxyServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "incomingConnection";

    QSslSocket *serverSocket = new QSslSocket(this);
    if (serverSocket->setSocketDescriptor(socketDescriptor)) {
        connect(serverSocket, SIGNAL(encrypted()), this, SLOT(onEncrypted()));
        connect(serverSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
        connect(serverSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(onSslErrors(QList<QSslError>)));
        connect(serverSocket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(onModeChanged(QSslSocket::SslMode)));
        connect(serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
        connect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));

        QSslConfiguration sslConfiguration = serverSocket->sslConfiguration();

        // ...
        QSslCertificate cert(&certFile, QSsl::Pem);
        QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem);
        sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
        sslConfiguration.setLocalCertificate(cert); // set domain cert
        sslConfiguration.setPrivateKey(key); // set domain key
        sslConfiguration.setProtocol(QSsl::AnyProtocol);
        // ...
        QSslCertificate caCert(&caCertFile, QSsl::Pem);
        sslConfiguration.setCaCertificates(QList<QSslCertificate>() << caCert); // add ca cert

        serverSocket->setSslConfiguration(sslConfiguration);

        serverSocket->startServerEncryption();
    } else {
        qDebug() << "Cannot set socket descriptor";
        delete serverSocket;
    }
}

void SslProxyServer::onEncrypted()
{
    qDebug() << "onEncrypted";
}

void SslProxyServer::onReadyRead()
{
    qDebug() << "onReadyRead";
}

void SslProxyServer::onSslErrors(QList<QSslError> sslErrors)
{
    qDebug() << "onSslErrors";
}

void SslProxyServer::onModeChanged(QSslSocket::SslMode sslMode)
{
    qDebug() << "onModeChanged(" << (int) sslMode << ")";
}

void SslProxyServer::onStateChanged(QAbstractSocket::SocketState socketState)
{
    qDebug() << "onStateChanged(" << (int) socketState << ")";
}

void SslProxyServer::onError(QAbstractSocket::SocketError socketError)
{
    qDebug() << "onError(" << (int) socketError << ")";

    QSslSocket *serverSocket = qobject_cast<QSslSocket *>(sender());
    qDebug() << serverSocket->errorString();
}

我已经生成了带有私钥的 CA 自签名证书,以及我用我的 CA 证书签署的特定域的另一个证书。在我将 CA 证书复制到 /usr/local/share/ca-certificates 并运行 sudo update-ca-certificates 之后。但是当我尝试使用 3rd 方应用程序连接到我的代理服务器时,我的服务器用作 https 代理,我在下一个输出中收到 QAbstractSocket::SslHandshakeFailedError 错误:

Listening port 8888 
incomingConnection 
onModeChanged( 2 ) 
onError( 13 ) 
"Error during SSL handshake: error:1407609B:SSL routines:SSL23_GET_CLIENT_HELLO:https proxy request" 
onStateChanged( 0 ) 

所以它甚至不会进入 onReadyRead 槽。 当我尝试使用 openssl 命令测试我的服务器时:openssl s_client -connect 127.0.0.1:8888 -debug - 它已成功连接到我的服务器。输出包含下一行:

verify error:num=19:self signed certificate in certificate chain
verify return:0
No client certificate CA names sent
---
SSL handshake has read 2667 bytes and written 439 bytes
Verify return code: 19 (self signed certificate in certificate chain)
---

但我可以将数据发送到我的服务器并在我的 onReadyRead 插槽中查看其原始值。

关于我的环境的一些信息: 操作系统:Ubuntu 12.04 x86_64 Qt:5.2.1(GCC 4.6.1,64 位)

提前致谢

最佳答案

... when I try to connect to my proxy server using 3rd-party app, where my server used as https proxy

... When I try to test my server using openssl command: openssl s_client -connect 127.0.0.1:8888 -debug - it is successfully connected to my server.

这些是不同的东西。使用 openssl 命令建立一个 TCP 连接,然后立即升级到 SSL。但是,https 代理的工作方式不同:它首先建立 TCP 连接,然后发出 HTTP CONNECT 命令,只有在从代理获得成功响应后,它才会将连接升级到 SSL,例如

- client to server
> CONNECT ip:port HTTP/1.0\r\n
> \r\n
- followed by server to client
< HTTP/1.0 200 connection established\r\n
< \r\n
... SSL handshake ...

并且因为客户端像它应该的那样发送 https 代理请求,但是您期望 SSL 握手立即开始(即您期望 ClientHello 消息),这失败了:

"Error during SSL handshake: error:1407609B:SSL routines:SSL23_GET_CLIENT_HELLO:https proxy request"

关于c++ - 在 Qt 5.2.1 上编写的 SSL 服务器的 SSL 握手失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25592467/

相关文章:

c++ - 在哪里可以找到 __sync_add_and_fetch_8?

c++ - 将文件中的 0.0 读入 double Arr?

c++ - 在 Visual Studio 中调试 64 位转储

c++ - CRTP 自动注册工厂(静态初始化顺序失败)

c++ - 如何在Qt中以跨平台的方式获取设置存储路径?

ssl - 使用 SSL 运行 CouchDB 停止工作

c++ - Qt 和 OpenGL 如何渲染 PVR

qt - 如何在Qt中自定义 ListView

java - 使用 Maven 和 Java 11 通过 SSL 进行 HTTP Get 请求

ssl - Neo4j 和 LetsEncrypt