From bd26defd9bdddf8619a8d6ce1c6cb90b28c27d88 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Wed, 15 Oct 2014 15:13:47 +0200 Subject: QSslSocket: introduce support for TLS PSK (client side) [ChangeLog][QtNetwork][QSslSocket] It is now possible to use TLS PSK ciphersuites in client sockets. Task-number: QTBUG-39077 Change-Id: I5523a2be33d46230c6f4106c322fab8a5afa37b4 Reviewed-by: Richard J. Moore --- src/network/ssl/qsslpresharedkeyauthenticator.cpp | 291 ++++++++++++++++++++++ src/network/ssl/qsslpresharedkeyauthenticator.h | 101 ++++++++ src/network/ssl/qsslpresharedkeyauthenticator_p.h | 65 +++++ src/network/ssl/qsslsocket.cpp | 22 ++ src/network/ssl/qsslsocket.h | 2 + src/network/ssl/qsslsocket_openssl.cpp | 68 +++++ src/network/ssl/qsslsocket_openssl_p.h | 4 + src/network/ssl/qsslsocket_openssl_symbols.cpp | 16 ++ src/network/ssl/qsslsocket_openssl_symbols_p.h | 9 + src/network/ssl/ssl.pri | 3 + 10 files changed, 581 insertions(+) create mode 100644 src/network/ssl/qsslpresharedkeyauthenticator.cpp create mode 100644 src/network/ssl/qsslpresharedkeyauthenticator.h create mode 100644 src/network/ssl/qsslpresharedkeyauthenticator_p.h (limited to 'src/network') 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 + +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 +#include +#include +#include + +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 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 + +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 &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 #include @@ -72,6 +74,8 @@ #include #include // for loading the security lib for the CA store +#include + 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(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 > 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 { -- cgit v1.2.3