From 0192630f55bb62bd7cf3a1dc29c6c0624ca7759c Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Fri, 7 Nov 2014 11:13:12 +0100 Subject: QNetworkAccessManager: introduce support for TLS PSK Expose the same kind of TLS PSK client support we already have set in place for QSslSocket. [ChangeLog][QtNetwork][QNetworkAccessManager] It is now possible to use TLS PSK ciphersuites when using HTTPS (or similar protocols working over SSL). Change-Id: I56a048e9f4f841f886758c781af2867d18538a3e Reviewed-by: Richard J. Moore --- .../access/qhttpnetworkconnectionchannel.cpp | 26 +++++++++++++++ .../access/qhttpnetworkconnectionchannel_p.h | 1 + src/network/access/qhttpnetworkreply_p.h | 1 + src/network/access/qhttpthreaddelegate.cpp | 10 ++++++ src/network/access/qhttpthreaddelegate_p.h | 2 ++ src/network/access/qnetworkaccessmanager.cpp | 37 ++++++++++++++++++++++ src/network/access/qnetworkaccessmanager.h | 3 ++ src/network/access/qnetworkaccessmanager_p.h | 1 + src/network/access/qnetworkreply.cpp | 22 +++++++++++++ src/network/access/qnetworkreply.h | 2 ++ src/network/access/qnetworkreplyhttpimpl.cpp | 9 ++++++ src/network/access/qnetworkreplyhttpimpl_p.h | 2 ++ 12 files changed, 116 insertions(+) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index d24fb159e2..d2a13220b9 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -147,6 +147,9 @@ void QHttpNetworkConnectionChannel::init() QObject::connect(sslSocket, SIGNAL(sslErrors(QList)), this, SLOT(_q_sslErrors(QList)), Qt::DirectConnection); + QObject::connect(sslSocket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), + this, SLOT(_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), + Qt::DirectConnection); QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), Qt::DirectConnection); @@ -1035,6 +1038,29 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList &errors) connection->d_func()->resumeConnection(); } +void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) +{ + connection->d_func()->pauseConnection(); + + if (pendingEncrypt && !reply) + connection->d_func()->dequeueRequest(socket); + + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP) { + if (reply) + emit reply->preSharedKeyAuthenticationRequired(authenticator); + } else { + QList spdyPairs = spdyRequestsToSend.values(); + for (int a = 0; a < spdyPairs.count(); ++a) { + // emit SSL errors for all replies + QHttpNetworkReply *currentReply = spdyPairs.at(a).second; + Q_ASSERT(currentReply); + emit currentReply->preSharedKeyAuthenticationRequired(authenticator); + } + } + + connection->d_func()->resumeConnection(); +} + void QHttpNetworkConnectionChannel::_q_encryptedBytesWritten(qint64 bytes) { Q_UNUSED(bytes); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 692c0e6a94..05331dc196 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -189,6 +189,7 @@ public: #ifndef QT_NO_SSL void _q_encrypted(); // start sending request (https) void _q_sslErrors(const QList &errors); // ssl errors from the socket + void _q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*); // tls-psk auth necessary void _q_encryptedBytesWritten(qint64 bytes); // proceed sending #endif diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 7a13358a4b..5c772b5912 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -138,6 +138,7 @@ public: Q_SIGNALS: void encrypted(); void sslErrors(const QList &errors); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); #endif Q_SIGNALS: diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index e31f23c18c..c8c7be43fa 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -371,6 +371,8 @@ void QHttpThreadDelegate::startRequest() #ifndef QT_NO_SSL connect(httpReply,SIGNAL(encrypted()), this, SLOT(encryptedSlot())); connect(httpReply,SIGNAL(sslErrors(QList)), this, SLOT(sslErrorsSlot(QList))); + connect(httpReply,SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), + this, SLOT(preSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator*))); #endif // In the asynchronous HTTP case we can just forward those signals @@ -675,6 +677,14 @@ void QHttpThreadDelegate::sslErrorsSlot(const QList &errors) if (!specificErrors.isEmpty()) httpReply->ignoreSslErrors(specificErrors); } + +void QHttpThreadDelegate::preSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *authenticator) +{ + if (!httpReply) + return; + + emit preSharedKeyAuthenticationRequired(authenticator); +} #endif void QHttpThreadDelegate::synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *a) diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index b1367fec0c..0ace0e6418 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -131,6 +131,7 @@ signals: void encrypted(); void sslErrors(const QList &, bool *, QList *); void sslConfigurationChanged(const QSslConfiguration); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *); #endif void downloadMetaData(QList >, int, QString, bool, QSharedPointer, qint64, bool); @@ -161,6 +162,7 @@ protected slots: #ifndef QT_NO_SSL void encryptedSlot(); void sslErrorsSlot(const QList &errors); + void preSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *authenticator); #endif void synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *); diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 52d56fb071..c661854a3a 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -416,6 +416,29 @@ static void ensureInitialized() QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors() */ +/*! + \fn void QNetworkAccessManager::preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator) + \since 5.5 + + This signal is emitted if the SSL/TLS handshake negotiates a PSK + ciphersuite, and therefore a PSK authentication is then required. + The \a reply object is the QNetworkReply that is negotiating + such ciphersuites. + + When using PSK, the client must send to the server a valid identity and a + valid pre shared key, in order for the SSL handshake to continue. + Applications can provide this information in a slot connected to this + signal, by filling in the passed \a authenticator object according to their + needs. + + \note Ignoring this signal, or failing to provide the required credentials, + will cause the handshake to fail, and therefore the connection to be aborted. + + \note The \a authenticator object is owned by the reply and must not be + deleted by the application. + + \sa QSslPreSharedKeyAuthenticator +*/ /*! Constructs a QNetworkAccessManager object that is the center of @@ -434,6 +457,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent) #ifndef QT_NO_SSL qRegisterMetaType >(); qRegisterMetaType(); + qRegisterMetaType(); #endif qRegisterMetaType > >(); #ifndef QT_NO_HTTP @@ -1328,6 +1352,18 @@ void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList &err #endif } +void QNetworkAccessManagerPrivate::_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) +{ +#ifndef QT_NO_SSL + Q_Q(QNetworkAccessManager); + QNetworkReply *reply = qobject_cast(q->sender()); + if (reply) + emit q->preSharedKeyAuthenticationRequired(reply, authenticator); +#else + Q_UNUSED(authenticator); +#endif +} + QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply) { Q_Q(QNetworkAccessManager); @@ -1338,6 +1374,7 @@ QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply) * avoid getting a connection error. */ q->connect(reply, SIGNAL(encrypted()), SLOT(_q_replyEncrypted())); q->connect(reply, SIGNAL(sslErrors(QList)), SLOT(_q_replySslErrors(QList))); + q->connect(reply, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), SLOT(_q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*))); #endif #ifndef QT_NO_BEARERMANAGEMENT activeReplyCount++; diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 9241ff36fb..581ed3cec3 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -37,6 +37,7 @@ #include #ifndef QT_NO_SSL #include +#include #endif QT_BEGIN_NAMESPACE @@ -145,6 +146,7 @@ Q_SIGNALS: #ifndef QT_NO_SSL void encrypted(QNetworkReply *reply); void sslErrors(QNetworkReply *reply, const QList &errors); + void preSharedKeyAuthenticationRequired(QNetworkReply *reply, QSslPreSharedKeyAuthenticator *authenticator); #endif #ifndef QT_NO_BEARERMANAGEMENT @@ -169,6 +171,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_replyFinished()) Q_PRIVATE_SLOT(d_func(), void _q_replyEncrypted()) Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList)) + Q_PRIVATE_SLOT(d_func(), void _q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)) #ifndef QT_NO_BEARERMANAGEMENT Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index f75884da38..0a839242ef 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -91,6 +91,7 @@ public: void _q_replyFinished(); void _q_replyEncrypted(); void _q_replySslErrors(const QList &errors); + void _q_replyPreSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); QNetworkReply *postProcess(QNetworkReply *reply); void createCookieJar() const; diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 1710af723f..67407cd500 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -253,6 +253,28 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() sslConfiguration(), ignoreSslErrors() */ +/*! + \fn void QNetworkReply::preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) + \since 5.5 + + This signal is emitted if the SSL/TLS handshake negotiates a PSK + ciphersuite, and therefore a PSK authentication is then required. + + When using PSK, the client must send to the server a valid identity and a + valid pre shared key, in order for the SSL handshake to continue. + Applications can provide this information in a slot connected to this + signal, by filling in the passed \a authenticator object according to their + needs. + + \note Ignoring this signal, or failing to provide the required credentials, + will cause the handshake to fail, and therefore the connection to be aborted. + + \note The \a authenticator object is owned by the reply and must not be + deleted by the application. + + \sa QSslPreSharedKeyAuthenticator +*/ + /*! \fn void QNetworkReply::metaDataChanged() diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h index 453116ea0e..a354577cd5 100644 --- a/src/network/access/qnetworkreply.h +++ b/src/network/access/qnetworkreply.h @@ -49,6 +49,7 @@ class QVariant; class QAuthenticator; class QSslConfiguration; class QSslError; +class QSslPreSharedKeyAuthenticator; class QNetworkReplyPrivate; class Q_NETWORK_EXPORT QNetworkReply: public QIODevice @@ -150,6 +151,7 @@ Q_SIGNALS: #ifndef QT_NO_SSL void encrypted(); void sslErrors(const QList &errors); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); #endif void uploadProgress(qint64 bytesSent, qint64 bytesTotal); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index e7c1b61d4d..e82f3fe833 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -844,6 +844,9 @@ void QNetworkReplyHttpImplPrivate::postRequest() QObject::connect(delegate, SIGNAL(sslErrors(QList,bool*,QList*)), q, SLOT(replySslErrors(QList,bool*,QList*)), Qt::BlockingQueuedConnection); + QObject::connect(delegate, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), + q, SLOT(replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator*)), + Qt::BlockingQueuedConnection); #endif // This signal we will use to start the request. QObject::connect(q, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest())); @@ -1263,6 +1266,12 @@ void QNetworkReplyHttpImplPrivate::replySslConfigurationChanged(const QSslConfig // Receiving the used SSL configuration from the HTTP thread this->sslConfiguration = sslConfiguration; } + +void QNetworkReplyHttpImplPrivate::replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *authenticator) +{ + Q_Q(QNetworkReplyHttpImpl); + emit q->preSharedKeyAuthenticationRequired(authenticator); +} #endif // Coming from QNonContiguousByteDeviceThreadForwardImpl in HTTP thread diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 73349f4e7a..d0d97c74ad 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -113,6 +113,7 @@ public: Q_PRIVATE_SLOT(d_func(), void replyEncrypted()) Q_PRIVATE_SLOT(d_func(), void replySslErrors(const QList &, bool *, QList *)) Q_PRIVATE_SLOT(d_func(), void replySslConfigurationChanged(const QSslConfiguration&)) + Q_PRIVATE_SLOT(d_func(), void replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *)) #endif #ifndef QT_NO_NETWORKPROXY Q_PRIVATE_SLOT(d_func(), void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth)) @@ -275,6 +276,7 @@ public: void replyEncrypted(); void replySslErrors(const QList &, bool *, QList *); void replySslConfigurationChanged(const QSslConfiguration&); + void replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator *); #endif #ifndef QT_NO_NETWORKPROXY void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); -- cgit v1.2.3