summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndré Klitzing <aklitzing@gmail.com>2016-03-23 12:27:11 +0100
committerAndré Klitzing <aklitzing@gmail.com>2016-05-02 20:33:00 +0000
commit0eaac0a3a95f8a74c06d062d3aa7928cbb09d493 (patch)
tree8b30219461b612a4cb934fd4334fee27d0eb3238 /src
parent9f416fad366f24436204a67b6571024d7bebe98f (diff)
Add support for PSK on server side
[ChangeLog][QtNetwork][QSslSocket] TLS PSK ciphers are possible in server sockets. Task-number: QTBUG-39077 Change-Id: Iaa854a6f50242deae5492f2e4759c727488995f5 Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src')
-rw-r--r--src/network/ssl/qsslconfiguration.cpp28
-rw-r--r--src/network/ssl/qsslconfiguration.h3
-rw-r--r--src/network/ssl/qsslconfiguration_p.h3
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp5
-rw-r--r--src/network/ssl/qsslsocket.cpp1
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp42
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h1
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp4
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h3
9 files changed, 88 insertions, 2 deletions
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 1fff2c31dd..1eb253d202 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -210,6 +210,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->privateKey == other.d->privateKey &&
d->sessionCipher == other.d->sessionCipher &&
d->sessionProtocol == other.d->sessionProtocol &&
+ d->preSharedKeyIdentityHint == other.d->preSharedKeyIdentityHint &&
d->ciphers == other.d->ciphers &&
d->ellipticCurves == other.d->ellipticCurves &&
d->caCertificates == other.d->caCertificates &&
@@ -260,6 +261,7 @@ bool QSslConfiguration::isNull() const
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
d->sslSession.isNull() &&
d->sslSessionTicketLifeTimeHint == -1 &&
+ d->preSharedKeyIdentityHint.isNull() &&
d->nextAllowedProtocols.isEmpty() &&
d->nextNegotiatedProtocol.isNull() &&
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone);
@@ -810,6 +812,32 @@ QVector<QSslEllipticCurve> QSslConfiguration::supportedEllipticCurves()
}
/*!
+ \since 5.8
+
+ Returns the identity hint.
+
+ \sa setPreSharedKeyIdentityHint()
+*/
+QByteArray QSslConfiguration::preSharedKeyIdentityHint() const
+{
+ return d->preSharedKeyIdentityHint;
+}
+
+/*!
+ \since 5.8
+
+ Sets the identity hint for a preshared key authentication. This will affect the next
+ initiated handshake; calling this function on an already-encrypted socket
+ will not affect the socket's identity hint.
+
+ The identity hint is used in QSslSocket::SslServerMode only!
+*/
+void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint)
+{
+ d->preSharedKeyIdentityHint = hint;
+}
+
+/*!
\since 5.3
This function returns the protocol negotiated with the server
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index f0754d7ef5..1f39e1a06f 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -141,6 +141,9 @@ public:
void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
static QVector<QSslEllipticCurve> supportedEllipticCurves();
+ QByteArray preSharedKeyIdentityHint() const;
+ void setPreSharedKeyIdentityHint(const QByteArray &hint);
+
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
index 093c9d6598..113954d7d1 100644
--- a/src/network/ssl/qsslconfiguration_p.h
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -88,6 +88,7 @@ public:
peerSessionShared(false),
sslOptions(QSslConfigurationPrivate::defaultSslOptions),
sslSessionTicketLifeTimeHint(-1),
+ preSharedKeyIdentityHint(),
nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone)
{ }
@@ -121,6 +122,8 @@ public:
QSslKey ephemeralServerKey;
+ QByteArray preSharedKeyIdentityHint;
+
QList<QByteArray> nextAllowedProtocols;
QByteArray nextNegotiatedProtocol;
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
index b24fdad1f9..0db7e10409 100644
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ b/src/network/ssl/qsslcontext_openssl.cpp
@@ -344,6 +344,11 @@ init_context:
}
#endif // OPENSSL_NO_EC
+#ifndef OPENSSL_NO_PSK
+ if (!client)
+ q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData());
+#endif // OPENSSL_NO_PSK
+
const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves();
if (!qcurves.isEmpty()) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index bbc62c47ff..82df861859 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -915,6 +915,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
d->configuration.privateKey = configuration.privateKey();
d->configuration.ciphers = configuration.ciphers();
d->configuration.ellipticCurves = configuration.ellipticCurves();
+ d->configuration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
d->configuration.caCertificates = configuration.caCertificates();
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
index 5c0c8674cd..5cbd2af323 100644
--- a/src/network/ssl/qsslsocket_openssl.cpp
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -201,6 +201,15 @@ static unsigned int q_ssl_psk_client_callback(SSL *ssl,
Q_ASSERT(d);
return d->tlsPskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
}
+
+static unsigned int q_ssl_psk_server_callback(SSL *ssl,
+ const char *identity,
+ 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->tlsPskServerCallback(identity, psk, max_psk_len);
+}
#endif
} // extern "C"
@@ -436,8 +445,12 @@ bool QSslSocketBackendPrivate::initSslContext()
#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);
+ if (q_SSLeay() >= 0x10001000L) {
+ if (mode == QSslSocket::SslClientMode)
+ q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
+ else if (mode == QSslSocket::SslServerMode)
+ q_SSL_set_psk_server_callback(ssl, &q_ssl_psk_server_callback);
+ }
#endif
return true;
@@ -1260,6 +1273,31 @@ unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint,
return pskLength;
}
+unsigned int QSslSocketBackendPrivate::tlsPskServerCallback(const char *identity,
+ unsigned char *psk, unsigned int max_psk_len)
+{
+ QSslPreSharedKeyAuthenticator authenticator;
+
+ // Fill in some read-only fields (for the user)
+ authenticator.d->identityHint = configuration.preSharedKeyIdentityHint;
+ authenticator.d->identity = identity;
+ authenticator.d->maximumIdentityLength = 0; // user cannot set an identity
+ 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 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 0674c05d71..c6572315f0 100644
--- a/src/network/ssl/qsslsocket_openssl_p.h
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -143,6 +143,7 @@ public:
bool checkSslErrors();
void storePeerCertificates();
unsigned int tlsPskClientCallback(const char *hint, char *identity, unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len);
+ unsigned int tlsPskServerCallback(const char *identity, unsigned char *psk, unsigned int max_psk_len);
#ifdef Q_OS_WIN
void fetchCaRootForCert(const QSslCertificate &cert);
void _q_caRootLoaded(QSslCertificate,QSslCertificate) Q_DECL_OVERRIDE;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 05b7e2da7f..f625fd3e96 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -300,6 +300,8 @@ DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return N
#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)
+DEFINEFUNC2(void, SSL_set_psk_server_callback, SSL* ssl, ssl, q_psk_server_callback_t callback, callback, return, DUMMYARG)
+DEFINEFUNC2(int, SSL_CTX_use_psk_identity_hint, SSL_CTX* ctx, ctx, const char *hint, hint, return 0, return)
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2
@@ -901,6 +903,8 @@ bool q_resolveOpenSslSymbols()
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
RESOLVEFUNC(SSL_set_psk_client_callback)
+ RESOLVEFUNC(SSL_set_psk_server_callback)
+ RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
#endif
RESOLVEFUNC(SSL_write)
#ifndef OPENSSL_NO_SSL2
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index 5a6c934d1a..45e4380580 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -376,6 +376,9 @@ void *q_SSL_get_ex_data(const SSL *ssl, int idx);
#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);
+typedef unsigned int (*q_psk_server_callback_t)(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len);
+void q_SSL_set_psk_server_callback(SSL *ssl, q_psk_server_callback_t callback);
+int q_SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
#endif // OPENSSL_NO_PSK
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#ifndef OPENSSL_NO_SSL2