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:
parent
515c6e7639
commit
d8efc8d718
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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()));
|
||||
|
Loading…
Reference in New Issue
Block a user