summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2018-12-13 15:39:26 +0100
committerMårten Nordheim <marten.nordheim@qt.io>2019-06-12 22:59:14 +0200
commitd8efc8d718e3b3a0464f321e740541f5b221a5d6 (patch)
tree61e4b038291b990871c01f1747408b2311030e9e
parent515c6e7639a7df647cfcc8b639e258864aaaa4af (diff)
QSslSocket: add and set the TLSv1.3-specific PSK callbackv5.12.4
If this callback is not set then OpenSSL will call the callback used for <= TLS 1.2 unconditionally when connecting. If using PSK it will call it again later once the preshared key is needed. We don't currently handle the TLSv1.3 PSK, but we definitely should. But for now we can work around it - when psk_use_session_callback is called we simply change the PSK callback to a dummy function whose only purpose is to restore the old callback. This is mostly done to keep behavior the same as it is now for users (and to keep our tests running). Later we can add a new signal and handle this new feature properly. Task-number: QTBUG-67463 Change-Id: I4aca4ae73ec4be7c4f82a85e8864de103f35a834 Reviewed-by: Simo Fält <simo.falt@qt.io>
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp56
-rw-r--r--src/network/ssl/qsslsocket_openssl11_symbols_p.h6
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp2
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp12
4 files changed, 65 insertions, 11 deletions
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index b5b098502d..c8bc6e069a 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -136,6 +136,55 @@ static unsigned int q_ssl_psk_server_callback(SSL *ssl,
Q_ASSERT(d);
return d->tlsPskServerCallback(identity, psk, max_psk_len);
}
+
+#ifdef TLS1_3_VERSION
+#ifndef OPENSSL_NO_PSK
+static unsigned int q_ssl_psk_restore_client(SSL *ssl,
+ const char *hint,
+ char *identity, unsigned int max_identity_len,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ Q_UNUSED(hint);
+ Q_UNUSED(identity);
+ Q_UNUSED(max_identity_len);
+ Q_UNUSED(psk);
+ Q_UNUSED(max_psk_len);
+
+#ifdef QT_DEBUG
+ QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
+ Q_ASSERT(d);
+ Q_ASSERT(d->mode == QSslSocket::SslClientMode);
+#endif
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
+
+ return 0;
+}
+#endif // !OPENSSL_NO_PSK
+
+static int q_ssl_psk_use_session_callback(SSL *ssl, const EVP_MD *md, const unsigned char **id,
+ size_t *idlen, SSL_SESSION **sess)
+{
+ Q_UNUSED(ssl);
+ Q_UNUSED(md);
+ Q_UNUSED(id);
+ Q_UNUSED(idlen);
+ Q_UNUSED(sess);
+
+#ifndef OPENSSL_NO_PSK
+#ifdef QT_DEBUG
+ QSslSocketBackendPrivate *d = reinterpret_cast<QSslSocketBackendPrivate *>(q_SSL_get_ex_data(ssl, QSslSocketBackendPrivate::s_indexForSSLExtraData));
+ Q_ASSERT(d);
+ Q_ASSERT(d->mode == QSslSocket::SslClientMode);
+#endif
+
+ // Temporarily rebind the psk because it will be called next. The function will restore it.
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_restore_client);
+#endif
+
+ return 1; // need to return 1 or else "the connection setup fails."
+}
+#endif // TLS1_3_VERSION
+
#endif
} // extern "C"
@@ -411,6 +460,13 @@ bool QSslSocketBackendPrivate::initSslContext()
q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback);
}
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10101006L
+ // Set the client callback for TLSv1.3 PSK
+ if (mode == QSslSocket::SslClientMode
+ && QSslSocket::sslLibraryBuildVersionNumber() >= 0x10101006L) {
+ q_SSL_set_psk_use_session_callback(ssl, &q_ssl_psk_use_session_callback);
+ }
+#endif // openssl version >= 0x10101006L
return true;
}
diff --git a/src/network/ssl/qsslsocket_openssl11_symbols_p.h b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
index fae007e12d..ec7e7ea1b8 100644
--- a/src/network/ssl/qsslsocket_openssl11_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl11_symbols_p.h
@@ -178,4 +178,10 @@ void q_BIO_set_shutdown(BIO *a, int shut);
#define q_SSL_CTX_set_max_proto_version(ctx, version) \
q_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, version, nullptr)
+extern "C" {
+typedef int (*q_SSL_psk_use_session_cb_func_t)(SSL *, const EVP_MD *, const unsigned char **, size_t *,
+ SSL_SESSION **);
+}
+void q_SSL_set_psk_use_session_callback(SSL *s, q_SSL_psk_use_session_cb_func_t);
+
#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 299df6b685..6a5ab91669 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -163,6 +163,7 @@ DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
#ifdef TLS1_3_VERSION
DEFINEFUNC2(int, SSL_CTX_set_ciphersuites, SSL_CTX *ctx, ctx, const char *str, str, return 0, return)
+DEFINEFUNC2(void, SSL_set_psk_use_session_callback, SSL *ssl, ssl, q_SSL_psk_use_session_cb_func_t callback, callback, return, DUMMYARG)
#endif
DEFINEFUNC3(size_t, SSL_get_client_random, SSL *a, a, unsigned char *out, out, size_t outlen, outlen, return 0, return)
DEFINEFUNC3(size_t, SSL_SESSION_get_master_key, const SSL_SESSION *ses, ses, unsigned char *out, out, size_t outlen, outlen, return 0, return)
@@ -980,6 +981,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_CTX_set_options)
#ifdef TLS1_3_VERSION
RESOLVEFUNC(SSL_CTX_set_ciphersuites)
+ RESOLVEFUNC(SSL_set_psk_use_session_callback)
#endif // TLS 1.3 or OpenSSL > 1.1.1
RESOLVEFUNC(SSL_get_client_random)
RESOLVEFUNC(SSL_SESSION_get_master_key)
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index e569a5e9c2..307e3d82bd 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -3550,12 +3550,7 @@ protected:
socket = new QSslSocket(this);
socket->setSslConfiguration(config);
socket->setPeerVerifyMode(peerVerifyMode);
- if (QSslSocket::sslLibraryVersionNumber() > 0x10101000L) {
- // FIXME. With OpenSSL 1.1.1 and TLS 1.3 PSK auto-test is broken.
- socket->setProtocol(QSsl::TlsV1_2);
- } else {
- socket->setProtocol(protocol);
- }
+ socket->setProtocol(protocol);
if (ignoreSslErrors)
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
@@ -3935,11 +3930,6 @@ void tst_QSslSocket::pskServer()
return;
QSslSocket socket;
-#ifdef TLS1_3_VERSION
- // FIXME: with OpenSSL 1.1.1 (thus TLS 1.3) test is known to fail
- // due to the different PSK mechanism (?) - to be investigated ASAP.
- socket.setProtocol(QSsl::TlsV1_2);
-#endif
this->socket = &socket;
QSignalSpy connectedSpy(&socket, SIGNAL(connected()));