summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.cpp291
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.h101
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator_p.h65
-rw-r--r--src/network/ssl/qsslsocket.cpp22
-rw-r--r--src/network/ssl/qsslsocket.h2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp68
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h4
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp16
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h9
-rw-r--r--src/network/ssl/ssl.pri3
10 files changed, 581 insertions, 0 deletions
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.cpp b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
new file mode 100644
index 0000000000..3b109c580a
--- /dev/null
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslpresharedkeyauthenticator.h"
+#include "qsslpresharedkeyauthenticator_p.h"
+
+#include <QSharedData>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+*/
+QSslPreSharedKeyAuthenticatorPrivate::QSslPreSharedKeyAuthenticatorPrivate()
+ : maximumIdentityLength(0),
+ maximumPreSharedKeyLength(0)
+{
+}
+
+/*!
+ \class QSslPreSharedKeyAuthenticator
+
+ \brief The QSslPreSharedKeyAuthenticator class provides authentication data for pre
+ shared keys (PSK) ciphersuites.
+
+ \inmodule QtNetwork
+
+ \reentrant
+
+ \ingroup network
+ \ingroup ssl
+ \ingroup shared
+
+ \since 5.5
+
+ The QSslPreSharedKeyAuthenticator class is used by an SSL socket to provide
+ the required authentication data in a pre shared key (PSK) ciphersuite.
+
+ In a PSK handshake, the client must derive a key, which must match the key
+ set on the server. The exact algorithm of deriving the key depends on the
+ application; however, for this purpose, the server may send an \e{identity
+ hint} to the client. This hint, combined with other information (for
+ instance a passphrase), is then used by the client to construct the shared
+ key.
+
+ The QSslPreSharedKeyAuthenticator provides means to client applications for
+ completing the PSK handshake. The client application needs to connect a
+ slot to the QSslSocket::preSharedKeyAuthenticationRequired() signal:
+
+ \code
+
+ connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired,
+ this, &AuthManager::handlePreSharedKeyAuthentication);
+
+ \endcode
+
+ The signal carries a QSslPreSharedKeyAuthenticator object containing the
+ identity hint the server sent to the client, and which must be filled with the
+ corresponding client identity and the derived key:
+
+ \code
+
+ void AuthManager::handlePreSharedKeyAuthentication(QSslPreSharedKeyAuthenticator *authenticator)
+ {
+ authenticator->setIdentity("My Qt App");
+
+ const QByteArray key = deriveKey(authenticator->identityHint(), passphrase);
+ authenticator->setPreSharedKey(key);
+ }
+
+ \endcode
+
+ \note PSK ciphersuites are supported only when using OpenSSL 1.0.1 (or
+ greater) as the SSL backend.
+
+ \sa QSslSocket
+*/
+
+/*!
+ Constructs a default QSslPreSharedKeyAuthenticator object.
+
+ The identity hint, the identity and the key will be initialized to empty
+ byte arrays; the maximum length for both the identity and the key will be
+ initialized to 0.
+*/
+QSslPreSharedKeyAuthenticator::QSslPreSharedKeyAuthenticator()
+ : d(new QSslPreSharedKeyAuthenticatorPrivate)
+{
+}
+
+/*!
+ Destroys the QSslPreSharedKeyAuthenticator object.
+*/
+QSslPreSharedKeyAuthenticator::~QSslPreSharedKeyAuthenticator()
+{
+}
+
+/*!
+ Constructs a QSslPreSharedKeyAuthenticator object as a copy of \a authenticator.
+
+ \sa operator=()
+*/
+QSslPreSharedKeyAuthenticator::QSslPreSharedKeyAuthenticator(const QSslPreSharedKeyAuthenticator &authenticator)
+ : d(authenticator.d)
+{
+}
+
+/*!
+ Assigns the QSslPreSharedKeyAuthenticator object \a authenticator to this object,
+ and returns a reference to the copy.
+*/
+QSslPreSharedKeyAuthenticator &QSslPreSharedKeyAuthenticator::operator=(const QSslPreSharedKeyAuthenticator &authenticator)
+{
+ d = authenticator.d;
+ return *this;
+}
+
+/*!
+ \fn QSslPreSharedKeyAuthenticator &QSslPreSharedKeyAuthenticator::operator=(QSslPreSharedKeyAuthenticator &&authenticator)
+
+ Move-assigns the the QSslPreSharedKeyAuthenticator object \a authenticator to this
+ object, and returns a reference to the moved instance.
+*/
+
+/*!
+ \fn void QSslPreSharedKeyAuthenticator::swap(QSslPreSharedKeyAuthenticator &authenticator)
+
+ Swaps the QSslPreSharedKeyAuthenticator object \a authenticator with this object.
+ This operation is very fast and never fails.
+*/
+
+/*!
+ Returns the PSK identity hint as provided by the server. The interpretation
+ of this hint is left to the application.
+*/
+QByteArray QSslPreSharedKeyAuthenticator::identityHint() const
+{
+ return d->identityHint;
+}
+
+/*!
+ Sets the PSK client identity (to be advised to the server) to \a identity.
+
+ \note it is possible to set an identity whose length is greater than
+ maximumIdentityLength(); in this case, only the first maximumIdentityLength()
+ bytes will be actually sent to the server.
+
+ \sa identity(), maximumIdentityLength()
+*/
+void QSslPreSharedKeyAuthenticator::setIdentity(const QByteArray &identity)
+{
+ d->identity = identity;
+}
+
+/*!
+ Returns the PSK client identity.
+
+ \sa setIdentity()
+*/
+QByteArray QSslPreSharedKeyAuthenticator::identity() const
+{
+ return d->identity;
+}
+
+
+/*!
+ Returns the maximum length, in bytes, of the PSK client identity.
+
+ \note it is possible to set an identity whose length is greater than
+ maximumIdentityLength(); in this case, only the first maximumIdentityLength()
+ bytes will be actually sent to the server.
+
+ \sa setIdentity()
+*/
+int QSslPreSharedKeyAuthenticator::maximumIdentityLength() const
+{
+ return d->maximumIdentityLength;
+}
+
+
+/*!
+ Sets the pre shared key to \a preSharedKey.
+
+ \note it is possible to set a key whose length is greater than the
+ maximumPreSharedKeyLength(); in this case, only the first
+ maximumPreSharedKeyLength() bytes will be actually sent to the server.
+
+ \sa preSharedKey(), maximumPreSharedKeyLength(), QByteArray::fromHex()
+*/
+void QSslPreSharedKeyAuthenticator::setPreSharedKey(const QByteArray &preSharedKey)
+{
+ d->preSharedKey = preSharedKey;
+}
+
+/*!
+ Returns the pre shared key.
+
+ \sa setPreSharedKey()
+*/
+QByteArray QSslPreSharedKeyAuthenticator::preSharedKey() const
+{
+ return d->preSharedKey;
+}
+
+/*!
+ Returns the maximum length, in bytes, of the pre shared key.
+
+ \note it is possible to set a key whose length is greater than the
+ maximumPreSharedKeyLength(); in this case, only the first
+ maximumPreSharedKeyLength() bytes will be actually sent to the server.
+
+ \sa setPreSharedKey()
+*/
+int QSslPreSharedKeyAuthenticator::maximumPreSharedKeyLength() const
+{
+ return d->maximumPreSharedKeyLength;
+}
+
+/*!
+ \relates QSslPreSharedKeyAuthenticator
+ \since 5.5
+
+ Returns true if the authenticator object \a lhs is equal to \a rhs; false
+ otherwise.
+
+ Two authenticator objects are equal if and only if they have the same
+ identity hint, identity, pre shared key, maximum length for the identity
+ and maximum length for the pre shared key.
+
+ \sa operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+*/
+bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+{
+ return ((lhs.d == rhs.d) ||
+ (lhs.d->identityHint == rhs.d->identityHint &&
+ lhs.d->identity == rhs.d->identity &&
+ lhs.d->maximumIdentityLength == rhs.d->maximumIdentityLength &&
+ lhs.d->preSharedKey == rhs.d->preSharedKey &&
+ lhs.d->maximumPreSharedKeyLength == rhs.d->maximumPreSharedKeyLength));
+}
+
+/*!
+ \fn bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+ \relates QSslPreSharedKeyAuthenticator
+ \since 5.5
+
+ Returns true if the authenticator object \a lhs is different than \a rhs;
+ false otherwise.
+
+ \sa operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+*/
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h
new file mode 100644
index 0000000000..cf2cd4989a
--- /dev/null
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_H
+#define QSSLPRESHAREDKEYAUTHENTICATOR_H
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QString>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QMetaType>
+
+QT_BEGIN_NAMESPACE
+
+class QSslPreSharedKeyAuthenticatorPrivate;
+
+class Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator
+{
+public:
+ QSslPreSharedKeyAuthenticator();
+ ~QSslPreSharedKeyAuthenticator();
+ QSslPreSharedKeyAuthenticator(const QSslPreSharedKeyAuthenticator &authenticator);
+ QSslPreSharedKeyAuthenticator &operator=(const QSslPreSharedKeyAuthenticator &authenticator);
+
+#ifdef Q_COMPILER_RVALUE_REFS
+ inline QSslPreSharedKeyAuthenticator &operator=(QSslPreSharedKeyAuthenticator &&authenticator)
+ { d.swap(authenticator.d); return *this; }
+#endif
+
+ void swap(QSslPreSharedKeyAuthenticator &authenticator)
+ {
+ d.swap(authenticator.d);
+ }
+
+ QByteArray identityHint() const;
+
+ void setIdentity(const QByteArray &identity);
+ QByteArray identity() const;
+ int maximumIdentityLength() const;
+
+ void setPreSharedKey(const QByteArray &preSharedKey);
+ QByteArray preSharedKey() const;
+ int maximumPreSharedKeyLength() const;
+
+private:
+ friend Q_NETWORK_EXPORT bool operator==(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs);
+ friend class QSslSocketBackendPrivate;
+
+ QSharedDataPointer<QSslPreSharedKeyAuthenticatorPrivate> d;
+};
+
+inline bool operator!=(const QSslPreSharedKeyAuthenticator &lhs, const QSslPreSharedKeyAuthenticator &rhs)
+{
+ return !operator==(lhs, rhs);
+}
+
+Q_DECLARE_SHARED(QSslPreSharedKeyAuthenticator)
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator)
+Q_DECLARE_METATYPE(QSslPreSharedKeyAuthenticator*)
+
+#endif // QSSLPRESHAREDKEYAUTHENTICATOR_H
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator_p.h b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
new file mode 100644
index 0000000000..9b933a1b1f
--- /dev/null
+++ b/src/network/ssl/qsslpresharedkeyauthenticator_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSSLPRESHAREDKEYAUTHENTICATOR_P_H
+#define QSSLPRESHAREDKEYAUTHENTICATOR_P_H
+
+#include <QSharedData>
+
+QT_BEGIN_NAMESPACE
+
+class QSslPreSharedKeyAuthenticatorPrivate : public QSharedData
+{
+public:
+ QSslPreSharedKeyAuthenticatorPrivate();
+
+ QByteArray identityHint;
+
+ QByteArray identity;
+ int maximumIdentityLength;
+
+ QByteArray preSharedKey;
+ int maximumPreSharedKeyLength;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLPRESHAREDKEYAUTHENTICATOR_P_H
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 3838e70310..98972f526a 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -281,6 +281,28 @@
\sa peerVerifyError()
*/
+/*!
+ \fn void QSslSocket::preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator)
+ \since 5.5
+
+ QSslSocket emits this signal when it 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 socket and must not be
+ deleted by the application.
+
+ \sa QSslPreSharedKeyAuthenticator
+*/
+
#include "qssl_p.h"
#include "qsslsocket.h"
#include "qsslcipher.h"
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index f5ab1527dc..16ae97e49e 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -52,6 +52,7 @@ class QSslCipher;
class QSslCertificate;
class QSslConfiguration;
class QSslEllipticCurve;
+class QSslPreSharedKeyAuthenticator;
class QSslSocketPrivate;
class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket
@@ -199,6 +200,7 @@ Q_SIGNALS:
void sslErrors(const QList<QSslError> &errors);
void modeChanged(QSslSocket::SslMode newMode);
void encryptedBytesWritten(qint64 totalBytes);
+ void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
protected:
qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE;
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index bf348f6f9f..509db38672 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -58,6 +58,8 @@
#include "qsslcipher_p.h"
#include "qsslkey_p.h"
#include "qsslellipticcurve.h"
+#include "qsslpresharedkeyauthenticator.h"
+#include "qsslpresharedkeyauthenticator_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qdebug.h>
@@ -72,6 +74,8 @@
#include <QtCore/qvarlengtharray.h>
#include <QLibrary> // for loading the security lib for the CA store
+#include <string.h>
+
QT_BEGIN_NAMESPACE
#if defined(Q_OS_MACX)
@@ -89,6 +93,10 @@ bool QSslSocketPrivate::s_libraryLoaded = false;
bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+int QSslSocketBackendPrivate::s_indexForSSLExtraData = -1;
+#endif
+
/* \internal
From OpenSSL's thread(3) manual page:
@@ -181,6 +189,18 @@ static unsigned long id_function()
{
return (quintptr)QThread::currentThreadId();
}
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+static unsigned int q_ssl_psk_client_callback(SSL *ssl,
+ const char *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
+ Q_ASSERT(d);
+ return d->tlsPskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
+}
+#endif
} // extern "C"
QSslSocketBackendPrivate::QSslSocketBackendPrivate()
@@ -390,6 +410,18 @@ bool QSslSocketBackendPrivate::initSslContext()
else
q_SSL_set_accept_state(ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ // Save a pointer to this object into the SSL structure.
+ if (q_SSLeay() >= 0x10001000L)
+ q_SSL_set_ex_data(ssl, s_indexForSSLExtraData, this);
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+ // Set the client callback for PSK
+ if (q_SSLeay() >= 0x10001000L && mode == QSslSocket::SslClientMode)
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
+#endif
+
return true;
}
@@ -443,6 +475,11 @@ bool QSslSocketPrivate::ensureLibraryLoaded()
q_SSL_load_error_strings();
q_OpenSSL_add_all_algorithms();
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ if (q_SSLeay() >= 0x10001000L)
+ QSslSocketBackendPrivate::s_indexForSSLExtraData = q_SSL_get_ex_new_index(0L, NULL, NULL, NULL, NULL);
+#endif
+
// Initialize OpenSSL's random seed.
if (!q_RAND_status()) {
struct {
@@ -1262,6 +1299,37 @@ bool QSslSocketBackendPrivate::checkSslErrors()
return true;
}
+unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ QSslPreSharedKeyAuthenticator authenticator;
+
+ // Fill in some read-only fields (for the user)
+ if (hint)
+ authenticator.d->identityHint = QByteArray::fromRawData(hint, int(::strlen(hint))); // it's NUL terminated, but do not include the NUL
+
+ authenticator.d->maximumIdentityLength = int(max_identity_len) - 1; // needs to be NUL terminated
+ authenticator.d->maximumPreSharedKeyLength = int(max_psk_len);
+
+ // Let the client provide the remaining bits...
+ Q_Q(QSslSocket);
+ emit q->preSharedKeyAuthenticationRequired(&authenticator);
+
+ // No PSK set? Return now to make the handshake fail
+ if (authenticator.preSharedKey().isEmpty())
+ return 0;
+
+ // Copy data back into OpenSSL
+ const int identityLength = qMin(authenticator.identity().length(), authenticator.maximumIdentityLength());
+ ::memcpy(identity, authenticator.identity().constData(), identityLength);
+ identity[identityLength] = 0;
+
+ const int pskLength = qMin(authenticator.preSharedKey().length(), authenticator.maximumPreSharedKeyLength());
+ ::memcpy(psk, authenticator.preSharedKey().constData(), pskLength);
+ return pskLength;
+}
+
#ifdef Q_OS_WIN
void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
index 69634ceab5..7fbccff802 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -114,6 +114,9 @@ public:
BIO *writeBio;
SSL_SESSION *session;
QList<QPair<int, int> > errorList;
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ static int s_indexForSSLExtraData; // index used in SSL_get_ex_data to get the matching QSslSocketBackendPrivate
+#endif
// Platform specific functions
void startClientEncryption() Q_DECL_OVERRIDE;
@@ -126,6 +129,7 @@ public:
QSsl::SslProtocol sessionProtocol() const Q_DECL_OVERRIDE;
void continueHandshake() Q_DECL_OVERRIDE;
bool checkSslErrors();
+ unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
#ifdef Q_OS_WIN
void fetchCaRootForCert(const QSslCertificate &cert);
void _q_caRootLoaded(QSslCertificate,QSslCertificate);
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index a2f8c7f592..2f022bd6e4 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -290,6 +290,14 @@ DEFINEFUNC2(int, SSL_set_session, SSL* to, to, SSL_SESSION *session, session, re
DEFINEFUNC(void, SSL_SESSION_free, SSL_SESSION *ses, ses, return, DUMMYARG)
DEFINEFUNC(SSL_SESSION*, SSL_get1_session, SSL *ssl, ssl, return 0, return)
DEFINEFUNC(SSL_SESSION*, SSL_get_session, const SSL *ssl, ssl, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+DEFINEFUNC5(int, SSL_get_ex_new_index, long argl, argl, void *argp, argp, CRYPTO_EX_new *new_func, new_func, CRYPTO_EX_dup *dup_func, dup_func, CRYPTO_EX_free *free_func, free_func, return -1, return)
+DEFINEFUNC3(int, SSL_set_ex_data, SSL *ssl, ssl, int idx, idx, void *arg, arg, return 0, return)
+DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return NULL, return)
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+DEFINEFUNC2(void, SSL_set_psk_client_callback, SSL* ssl, ssl, q_psk_client_callback_t callback, callback, return, DUMMYARG)
+#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2
DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return)
@@ -854,6 +862,14 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_SESSION_free)
RESOLVEFUNC(SSL_get1_session)
RESOLVEFUNC(SSL_get_session)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ RESOLVEFUNC(SSL_get_ex_new_index)
+ RESOLVEFUNC(SSL_set_ex_data)
+ RESOLVEFUNC(SSL_get_ex_data)
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
+ RESOLVEFUNC(SSL_set_psk_client_callback)
+#endif
RESOLVEFUNC(SSL_write)
#ifndef OPENSSL_NO_SSL2
RESOLVEFUNC(SSLv2_client_method)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index f2cc8a87fc..53b3ffde1b 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -374,6 +374,15 @@ int q_SSL_set_session(SSL *to, SSL_SESSION *session);
void q_SSL_SESSION_free(SSL_SESSION *ses);
SSL_SESSION *q_SSL_get1_session(SSL *ssl);
SSL_SESSION *q_SSL_get_session(const SSL *ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+int q_SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int q_SSL_set_ex_data(SSL *ssl, int idx, void *arg);
+void *q_SSL_get_ex_data(const SSL *ssl, int idx);
+#endif
+#ifndef OPENSSL_NO_PSK
+typedef unsigned int (*q_psk_client_callback_t)(SSL *ssl, const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
+void q_SSL_set_psk_client_callback(SSL *ssl, q_psk_client_callback_t callback);
+#endif // OPENSSL_NO_PSK
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const SSL_METHOD *q_SSLv2_client_method();
const SSL_METHOD *q_SSLv3_client_method();
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 961e29c062..210606a1a0 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -15,6 +15,8 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslkey_p.h \
ssl/qsslsocket.h \
ssl/qsslsocket_p.h \
+ ssl/qsslpresharedkeyauthenticator.h \
+ ssl/qsslpresharedkeyauthenticator_p.h \
ssl/qsslcertificateextension.h \
ssl/qsslcertificateextension_p.h
SOURCES += ssl/qasn1element.cpp \
@@ -26,6 +28,7 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslkey_p.cpp \
ssl/qsslerror.cpp \
ssl/qsslsocket.cpp \
+ ssl/qsslpresharedkeyauthenticator.cpp \
ssl/qsslcertificateextension.cpp
winrt {