QSslSocket: add and set the TLSv1.3-specific PSK callback

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>
This commit is contained in:
Mårten Nordheim 2018-12-13 15:39:26 +01:00
parent 515c6e7639
commit d8efc8d718
4 changed files with 65 additions and 11 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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()));