2014-08-31 3 views
1

Я пишу ssl-прокси-сервер с использованием Qt. Вот пример кода:Ошибка соединения SSL с сервером ssl, написанным на Qt 5.2.1

# 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 на /usr/local/share/ca-certificates и запустил sudo update-ca-certificates. Но когда я пытаюсь подключиться к прокси-серверу с помощью третьих сторон приложения, где мой сервер используется в качестве прокси-сервера 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 бит)

Спасибо заранее,

ответ

2

... 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"

+1

Очень ценный ответ! – c1tru55