From: Manuel Nickschas Date: Sat, 28 Nov 2009 20:00:29 +0000 (+0100) Subject: Make SSL work again for CoreConnection X-Git-Tag: 0.6-beta1~151 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=e4491717487ddbff71b9b5a59d7b4cba3eb67629 Make SSL work again for CoreConnection This reintroduces and improves SSL support, and comes complete with new shiny dialogs. --- diff --git a/src/client/coreconnection.cpp b/src/client/coreconnection.cpp index 0b342ed5..a60fae38 100644 --- a/src/client/coreconnection.cpp +++ b/src/client/coreconnection.cpp @@ -103,6 +103,16 @@ void CoreConnection::resetConnection() { setProgressMaximum(-1); // disable setState(Disconnected); emit connectionMsg(tr("Disconnected from core.")); + emit encrypted(false); +} + +bool CoreConnection::isEncrypted() const { +#ifndef HAVE_SSL + return false; +#else + QSslSocket *sock = qobject_cast(_socket); + return isConnected() && sock && sock->isEncrypted(); +#endif } void CoreConnection::socketStateChanged(QAbstractSocket::SocketState socketState) { @@ -164,15 +174,6 @@ void CoreConnection::setState(ConnectionState state) { } } -void CoreConnection::setWarningsHandler(const char *slot) { - resetWarningsHandler(); - connect(this, SIGNAL(handleIgnoreWarnings(bool)), this, slot); -} - -void CoreConnection::resetWarningsHandler() { - disconnect(this, SIGNAL(handleIgnoreWarnings(bool)), this, 0); -} - void CoreConnection::coreSocketError(QAbstractSocket::SocketError) { qDebug() << "coreSocketError" << _socket << _socket->errorString(); emit connectionError(_socket->errorString()); @@ -289,13 +290,24 @@ void CoreConnection::connectToCurrentAccount() { return; } + CoreAccountSettings s; + Q_ASSERT(!_socket); #ifdef HAVE_SSL QSslSocket *sock = new QSslSocket(Client::instance()); + // make sure the warning is shown if we happen to connect without SSL support later + s.setAccountValue("ShowNoClientSslWarning", true); #else if(_account.useSsl()) { - emit connectionError(tr("This client is built without SSL Support!
Disable the usage of SSL in the account settings.")); - return; + if(s.accountValue("ShowNoClientSslWarning", true).toBool()) { + bool accepted = false; + emit handleNoSslInClient(&accepted); + if(!accepted) { + emit connectionError(tr("Unencrypted connection canceled")); + return; + } + s.setAccountValue("ShowNoClientSslWarning", false); + } } QTcpSocket *sock = new QTcpSocket(Client::instance()); #endif @@ -355,27 +367,86 @@ void CoreConnection::clientInitAck(const QVariantMap &msg) { #endif _coreMsgBuffer = msg; + #ifdef HAVE_SSL + CoreAccountSettings s; if(currentAccount().useSsl()) { if(msg["SupportSsl"].toBool()) { + // Make sure the warning is shown next time we don't have SSL in the core + s.setAccountValue("ShowNoCoreSslWarning", true); + QSslSocket *sslSocket = qobject_cast(_socket); Q_ASSERT(sslSocket); - connect(sslSocket, SIGNAL(encrypted()), this, SLOT(sslSocketEncrypted())); - connect(sslSocket, SIGNAL(sslErrors(const QList &)), this, SLOT(sslErrors(const QList &))); - + connect(sslSocket, SIGNAL(encrypted()), SLOT(sslSocketEncrypted())); + connect(sslSocket, SIGNAL(sslErrors(const QList &)), SLOT(sslErrors())); sslSocket->startClientEncryption(); } else { - emit connectionError(tr("The Quassel Core you are trying to connect to does not support SSL!
If you want to connect anyways, disable the usage of SSL in the account settings.")); - disconnectFromCore(); + if(s.accountValue("ShowNoCoreSslWarning", true).toBool()) { + bool accepted = false; + emit handleNoSslInCore(&accepted); + if(!accepted) { + emit connectionError(tr("Unencrypted connection canceled")); + disconnectFromCore(); + return; + } + s.setAccountValue("ShowNoCoreSslWarning", false); + s.setAccountValue("SslCert", QString()); + } + connectionReady(); } return; } #endif // if we use SSL we wait for the next step until every SSL warning has been cleared connectionReady(); +} +#ifdef HAVE_SSL + +void CoreConnection::sslSocketEncrypted() { + QSslSocket *socket = qobject_cast(sender()); + Q_ASSERT(socket); + + if(!socket->sslErrors().count()) { + // Cert is valid, so we don't want to store it as known + // That way, a warning will appear in case it becomes invalid at some point + CoreAccountSettings s; + s.setAccountValue("SSLCert", QString()); + } + + emit encrypted(true); + connectionReady(); +} + +void CoreConnection::sslErrors() { + QSslSocket *socket = qobject_cast(sender()); + Q_ASSERT(socket); + + CoreAccountSettings s; + QByteArray knownDigest = s.accountValue("SslCert").toByteArray(); + + if(knownDigest != socket->peerCertificate().digest()) { + bool accepted = false; + bool permanently = false; + emit handleSslErrors(socket, &accepted, &permanently); + + if(!accepted) { + emit connectionError(tr("Unencrypted connection canceled")); + disconnectFromCore(); + return; + } + + if(permanently) + s.setAccountValue("SslCert", socket->peerCertificate().digest()); + else + s.setAccountValue("SslCert", QString()); + } + + socket->ignoreSslErrors(); } +#endif /* HAVE_SSL */ + void CoreConnection::connectionReady() { if(!_coreMsgBuffer["Configured"].toBool()) { // start wizard @@ -384,7 +455,6 @@ void CoreConnection::connectionReady() { loginToCore(); } _coreMsgBuffer.clear(); - resetWarningsHandler(); } void CoreConnection::loginToCore(const QString &prevError) { diff --git a/src/client/coreconnection.h b/src/client/coreconnection.h index f1afab9f..2ef7d1a9 100644 --- a/src/client/coreconnection.h +++ b/src/client/coreconnection.h @@ -58,20 +58,25 @@ public: inline bool isConnected() const; inline CoreAccount currentAccount() const; + bool isEncrypted() const; + inline int progressMinimum() const; inline int progressMaximum() const; inline int progressValue() const; inline QString progressText() const; +#ifdef HAVE_SSL + inline const QSslSocket *sslSocket() const; +#endif + public slots: bool connectToCore(AccountId = 0); void reconnectToCore(); void disconnectFromCore(); -// void useInternalCore(); - signals: void stateChanged(CoreConnection::ConnectionState); + void encrypted(bool isEncrypted = true); void synchronized(); void connectionError(const QString &errorMsg); @@ -87,10 +92,13 @@ signals: void startInternalCore(); void connectToInternalCore(SignalProxy *proxy); - // This signal MUST be handled synchronously! + // These signals MUST be handled synchronously! void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage = QString()); - - void handleIgnoreWarnings(bool permanently); + void handleNoSslInClient(bool *accepted); + void handleNoSslInCore(bool *accepted); +#ifdef HAVE_SSL + void handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently); +#endif private slots: void connectToCurrentAccount(); @@ -111,8 +119,6 @@ private slots: void internalSessionStateReceived(const QVariant &packedState); void sessionStateReceived(const QVariantMap &state); - void setWarningsHandler(const char *slot); - void resetWarningsHandler(); void resetConnection(); void connectionReady(); //void doCoreSetup(const QVariant &setupData); @@ -130,6 +136,11 @@ private slots: void setState(QAbstractSocket::SocketState socketState); void setState(ConnectionState state); +#ifdef HAVE_SSL + void sslSocketEncrypted(); + void sslErrors(); +#endif + private: CoreAccountModel *_model; CoreAccount _account; @@ -162,4 +173,8 @@ bool CoreConnection::isConnected() const { return state() >= Connected; } CoreAccount CoreConnection::currentAccount() const { return _account; } CoreAccountModel *CoreConnection::accountModel() const { return _model; } +#ifdef HAVE_SSL +const QSslSocket *CoreConnection::sslSocket() const { return qobject_cast(_socket); } +#endif + #endif diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index ed467cd4..c7792107 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -95,6 +95,10 @@ # include "knotificationbackend.h" #endif /* HAVE_KDE */ +#ifdef HAVE_SSL +# include "sslinfodlg.h" +#endif + #ifdef HAVE_INDICATEQT #include "indicatornotificationbackend.h" #endif @@ -159,6 +163,11 @@ void MainWin::init() { connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showChannelList(NetworkId)), SLOT(showChannelList(NetworkId))); connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showIgnoreList(QString)), SLOT(showIgnoreList(QString))); connect(Client::coreConnection(), SIGNAL(userAuthenticationRequired(CoreAccount *, bool *, QString)), SLOT(userAuthenticationRequired(CoreAccount *, bool *, QString))); + connect(Client::coreConnection(), SIGNAL(handleNoSslInClient(bool*)), SLOT(handleNoSslInClient(bool *))); + connect(Client::coreConnection(), SIGNAL(handleNoSslInCore(bool*)), SLOT(handleNoSslInCore(bool *))); +#ifdef HAVE_SSL + connect(Client::coreConnection(), SIGNAL(handleSslErrors(const QSslSocket *, bool *, bool *)), SLOT(handleSslErrors(const QSslSocket *, bool *, bool *))); +#endif // Setup Dock Areas setDockNestingEnabled(true); @@ -832,6 +841,70 @@ void MainWin::startInternalCore() { } +void MainWin::userAuthenticationRequired(CoreAccount *account, bool *valid, const QString &errorMessage) { + Q_UNUSED(errorMessage) + CoreConnectAuthDlg dlg(account, this); + *valid = (dlg.exec() == QDialog::Accepted); +} + +void MainWin::handleNoSslInClient(bool *accepted) { + QMessageBox box(QMessageBox::Warning, tr("Unencrypted Connection"), tr("Your client does not support SSL encryption"), + QMessageBox::Ignore|QMessageBox::Cancel, this); + box.setInformativeText(tr("Sensitive data, like passwords, will be transmitted unencrypted to your Quassel core.")); + box.setDefaultButton(QMessageBox::Ignore); + *accepted = box.exec() == QMessageBox::Ignore; +} + +void MainWin::handleNoSslInCore(bool *accepted) { + QMessageBox box(QMessageBox::Warning, tr("Unencrypted Connection"), tr("Your core does not support SSL encryption"), + QMessageBox::Ignore|QMessageBox::Cancel, this); + box.setInformativeText(tr("Sensitive data, like passwords, will be transmitted unencrypted to your Quassel core.")); + box.setDefaultButton(QMessageBox::Ignore); + *accepted = box.exec() == QMessageBox::Ignore; + +} + +#ifdef HAVE_SSL + +void MainWin::handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently) { + QString errorString = "
    "; + foreach(const QSslError error, socket->sslErrors()) + errorString += QString("
  • %1
  • ").arg(error.errorString()); + errorString += "
"; + + QMessageBox box(QMessageBox::Warning, + tr("Untrusted Security Certificate"), + tr("The SSL certificate provided by the core at %1 is untrusted for the following reasons:").arg(socket->peerName()), + QMessageBox::Cancel, this); + box.setInformativeText(errorString); + box.addButton(tr("Continue"), QMessageBox::AcceptRole); + box.setDefaultButton(box.addButton(tr("Show Certificate"), QMessageBox::HelpRole)); + + QMessageBox::ButtonRole role; + do { + box.exec(); + role = box.buttonRole(box.clickedButton()); + if(role == QMessageBox::HelpRole) { + SslInfoDlg dlg(socket, this); + dlg.exec(); + } + } while(role == QMessageBox::HelpRole); + + *accepted = role == QMessageBox::AcceptRole; + if(*accepted) { + QMessageBox box2(QMessageBox::Warning, + tr("Untrusted Security Certificate"), + tr("Would you like to accept this certificate forever without being prompted?"), + 0, this); + box2.setDefaultButton(box2.addButton(tr("Current Session Only"), QMessageBox::NoRole)); + box2.addButton(tr("Forever"), QMessageBox::YesRole); + box2.exec(); + *permanently = box2.buttonRole(box2.clickedButton()) == QMessageBox::YesRole; + } +} + +#endif /* HAVE_SSL */ + void MainWin::showCoreConnectionDlg() { CoreConnectDlg dlg(this); if(dlg.exec() == QDialog::Accepted) { @@ -841,12 +914,6 @@ void MainWin::showCoreConnectionDlg() { } } -void MainWin::userAuthenticationRequired(CoreAccount *account, bool *valid, const QString &errorMessage) { - Q_UNUSED(errorMessage) - CoreConnectAuthDlg dlg(account, this); - *valid = (dlg.exec() == QDialog::Accepted); -} - void MainWin::showChannelList(NetworkId netId) { ChannelListDlg *channelListDlg = new ChannelListDlg(); diff --git a/src/qtui/mainwin.h b/src/qtui/mainwin.h index d14a7c63..5f15fa55 100644 --- a/src/qtui/mainwin.h +++ b/src/qtui/mainwin.h @@ -119,8 +119,6 @@ class MainWin void messagesInserted(const QModelIndex &parent, int start, int end); void showAboutDlg(); void showChannelList(NetworkId netId = NetworkId()); - void startInternalCore(); - void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage); void showCoreConnectionDlg(); void showCoreInfoDlg(); void showAwayLog(); @@ -130,6 +128,14 @@ class MainWin #ifdef HAVE_KDE void showShortcutsDlg(); #endif + void startInternalCore(); + void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage); + void handleNoSslInClient(bool *accepted); + void handleNoSslInCore(bool *accepted); +#ifdef HAVE_SSL + void handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently); +#endif + void on_actionConfigureNetworks_triggered(); void on_actionConfigureViews_triggered(); void on_actionLockLayout_toggled(bool lock);