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>
This commit is contained in:
parent
9f416fad36
commit
0eaac0a3a9
@ -210,6 +210,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
|
|||||||
d->privateKey == other.d->privateKey &&
|
d->privateKey == other.d->privateKey &&
|
||||||
d->sessionCipher == other.d->sessionCipher &&
|
d->sessionCipher == other.d->sessionCipher &&
|
||||||
d->sessionProtocol == other.d->sessionProtocol &&
|
d->sessionProtocol == other.d->sessionProtocol &&
|
||||||
|
d->preSharedKeyIdentityHint == other.d->preSharedKeyIdentityHint &&
|
||||||
d->ciphers == other.d->ciphers &&
|
d->ciphers == other.d->ciphers &&
|
||||||
d->ellipticCurves == other.d->ellipticCurves &&
|
d->ellipticCurves == other.d->ellipticCurves &&
|
||||||
d->caCertificates == other.d->caCertificates &&
|
d->caCertificates == other.d->caCertificates &&
|
||||||
@ -260,6 +261,7 @@ bool QSslConfiguration::isNull() const
|
|||||||
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
|
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
|
||||||
d->sslSession.isNull() &&
|
d->sslSession.isNull() &&
|
||||||
d->sslSessionTicketLifeTimeHint == -1 &&
|
d->sslSessionTicketLifeTimeHint == -1 &&
|
||||||
|
d->preSharedKeyIdentityHint.isNull() &&
|
||||||
d->nextAllowedProtocols.isEmpty() &&
|
d->nextAllowedProtocols.isEmpty() &&
|
||||||
d->nextNegotiatedProtocol.isNull() &&
|
d->nextNegotiatedProtocol.isNull() &&
|
||||||
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone);
|
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone);
|
||||||
@ -809,6 +811,32 @@ QVector<QSslEllipticCurve> QSslConfiguration::supportedEllipticCurves()
|
|||||||
return QSslSocketPrivate::supportedEllipticCurves();
|
return QSslSocketPrivate::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
|
\since 5.3
|
||||||
|
|
||||||
|
@ -141,6 +141,9 @@ public:
|
|||||||
void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
|
void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
|
||||||
static QVector<QSslEllipticCurve> supportedEllipticCurves();
|
static QVector<QSslEllipticCurve> supportedEllipticCurves();
|
||||||
|
|
||||||
|
QByteArray preSharedKeyIdentityHint() const;
|
||||||
|
void setPreSharedKeyIdentityHint(const QByteArray &hint);
|
||||||
|
|
||||||
static QSslConfiguration defaultConfiguration();
|
static QSslConfiguration defaultConfiguration();
|
||||||
static void setDefaultConfiguration(const QSslConfiguration &configuration);
|
static void setDefaultConfiguration(const QSslConfiguration &configuration);
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ public:
|
|||||||
peerSessionShared(false),
|
peerSessionShared(false),
|
||||||
sslOptions(QSslConfigurationPrivate::defaultSslOptions),
|
sslOptions(QSslConfigurationPrivate::defaultSslOptions),
|
||||||
sslSessionTicketLifeTimeHint(-1),
|
sslSessionTicketLifeTimeHint(-1),
|
||||||
|
preSharedKeyIdentityHint(),
|
||||||
nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone)
|
nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -121,6 +122,8 @@ public:
|
|||||||
|
|
||||||
QSslKey ephemeralServerKey;
|
QSslKey ephemeralServerKey;
|
||||||
|
|
||||||
|
QByteArray preSharedKeyIdentityHint;
|
||||||
|
|
||||||
QList<QByteArray> nextAllowedProtocols;
|
QList<QByteArray> nextAllowedProtocols;
|
||||||
QByteArray nextNegotiatedProtocol;
|
QByteArray nextNegotiatedProtocol;
|
||||||
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
|
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
|
||||||
|
@ -344,6 +344,11 @@ init_context:
|
|||||||
}
|
}
|
||||||
#endif // OPENSSL_NO_EC
|
#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();
|
const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves();
|
||||||
if (!qcurves.isEmpty()) {
|
if (!qcurves.isEmpty()) {
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_EC)
|
||||||
|
@ -915,6 +915,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
|
|||||||
d->configuration.privateKey = configuration.privateKey();
|
d->configuration.privateKey = configuration.privateKey();
|
||||||
d->configuration.ciphers = configuration.ciphers();
|
d->configuration.ciphers = configuration.ciphers();
|
||||||
d->configuration.ellipticCurves = configuration.ellipticCurves();
|
d->configuration.ellipticCurves = configuration.ellipticCurves();
|
||||||
|
d->configuration.preSharedKeyIdentityHint = configuration.preSharedKeyIdentityHint();
|
||||||
d->configuration.caCertificates = configuration.caCertificates();
|
d->configuration.caCertificates = configuration.caCertificates();
|
||||||
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
|
d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
|
||||||
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
|
d->configuration.peerVerifyMode = configuration.peerVerifyMode();
|
||||||
|
@ -201,6 +201,15 @@ static unsigned int q_ssl_psk_client_callback(SSL *ssl,
|
|||||||
Q_ASSERT(d);
|
Q_ASSERT(d);
|
||||||
return d->tlsPskClientCallback(hint, identity, max_identity_len, psk, max_psk_len);
|
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
|
#endif
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
@ -436,8 +445,12 @@ bool QSslSocketBackendPrivate::initSslContext()
|
|||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
|
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
|
||||||
// Set the client callback for PSK
|
// Set the client callback for PSK
|
||||||
if (q_SSLeay() >= 0x10001000L && mode == QSslSocket::SslClientMode)
|
if (q_SSLeay() >= 0x10001000L) {
|
||||||
q_SSL_set_psk_client_callback(ssl, &q_ssl_psk_client_callback);
|
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
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1260,6 +1273,31 @@ unsigned int QSslSocketBackendPrivate::tlsPskClientCallback(const char *hint,
|
|||||||
return pskLength;
|
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
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
|
void QSslSocketBackendPrivate::fetchCaRootForCert(const QSslCertificate &cert)
|
||||||
|
@ -143,6 +143,7 @@ public:
|
|||||||
bool checkSslErrors();
|
bool checkSslErrors();
|
||||||
void storePeerCertificates();
|
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 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
|
#ifdef Q_OS_WIN
|
||||||
void fetchCaRootForCert(const QSslCertificate &cert);
|
void fetchCaRootForCert(const QSslCertificate &cert);
|
||||||
void _q_caRootLoaded(QSslCertificate,QSslCertificate) Q_DECL_OVERRIDE;
|
void _q_caRootLoaded(QSslCertificate,QSslCertificate) Q_DECL_OVERRIDE;
|
||||||
|
@ -300,6 +300,8 @@ DEFINEFUNC2(void *, SSL_get_ex_data, const SSL *ssl, ssl, int idx, idx, return N
|
|||||||
#endif
|
#endif
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
|
#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_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
|
#endif
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
#ifndef OPENSSL_NO_SSL2
|
#ifndef OPENSSL_NO_SSL2
|
||||||
@ -901,6 +903,8 @@ bool q_resolveOpenSslSymbols()
|
|||||||
#endif
|
#endif
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
|
#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_PSK)
|
||||||
RESOLVEFUNC(SSL_set_psk_client_callback)
|
RESOLVEFUNC(SSL_set_psk_client_callback)
|
||||||
|
RESOLVEFUNC(SSL_set_psk_server_callback)
|
||||||
|
RESOLVEFUNC(SSL_CTX_use_psk_identity_hint)
|
||||||
#endif
|
#endif
|
||||||
RESOLVEFUNC(SSL_write)
|
RESOLVEFUNC(SSL_write)
|
||||||
#ifndef OPENSSL_NO_SSL2
|
#ifndef OPENSSL_NO_SSL2
|
||||||
|
@ -376,6 +376,9 @@ void *q_SSL_get_ex_data(const SSL *ssl, int idx);
|
|||||||
#ifndef OPENSSL_NO_PSK
|
#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);
|
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);
|
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
|
#endif // OPENSSL_NO_PSK
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||||
#ifndef OPENSSL_NO_SSL2
|
#ifndef OPENSSL_NO_SSL2
|
||||||
|
@ -230,6 +230,7 @@ private slots:
|
|||||||
void ephemeralServerKey_data();
|
void ephemeralServerKey_data();
|
||||||
void ephemeralServerKey();
|
void ephemeralServerKey();
|
||||||
void allowedProtocolNegotiation();
|
void allowedProtocolNegotiation();
|
||||||
|
void pskServer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void exitLoop()
|
static void exitLoop()
|
||||||
@ -3036,8 +3037,12 @@ class PskProvider : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool m_server;
|
||||||
|
QByteArray m_identity;
|
||||||
|
QByteArray m_psk;
|
||||||
|
|
||||||
explicit PskProvider(QObject *parent = 0)
|
explicit PskProvider(QObject *parent = 0)
|
||||||
: QObject(parent)
|
: QObject(parent), m_server(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3056,7 +3061,11 @@ public slots:
|
|||||||
{
|
{
|
||||||
QVERIFY(authenticator);
|
QVERIFY(authenticator);
|
||||||
QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT);
|
QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT);
|
||||||
QVERIFY(authenticator->maximumIdentityLength() > 0);
|
if (m_server)
|
||||||
|
QCOMPARE(authenticator->maximumIdentityLength(), 0);
|
||||||
|
else
|
||||||
|
QVERIFY(authenticator->maximumIdentityLength() > 0);
|
||||||
|
|
||||||
QVERIFY(authenticator->maximumPreSharedKeyLength() > 0);
|
QVERIFY(authenticator->maximumPreSharedKeyLength() > 0);
|
||||||
|
|
||||||
if (!m_identity.isEmpty()) {
|
if (!m_identity.isEmpty()) {
|
||||||
@ -3069,12 +3078,61 @@ public slots:
|
|||||||
QCOMPARE(authenticator->preSharedKey(), m_psk);
|
QCOMPARE(authenticator->preSharedKey(), m_psk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
QByteArray m_identity;
|
|
||||||
QByteArray m_psk;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PskServer : public QTcpServer
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PskServer()
|
||||||
|
: socket(0),
|
||||||
|
config(QSslConfiguration::defaultConfiguration()),
|
||||||
|
ignoreSslErrors(true),
|
||||||
|
peerVerifyMode(QSslSocket::AutoVerifyPeer),
|
||||||
|
protocol(QSsl::TlsV1_0),
|
||||||
|
m_pskProvider()
|
||||||
|
{
|
||||||
|
m_pskProvider.m_server = true;
|
||||||
|
}
|
||||||
|
QSslSocket *socket;
|
||||||
|
QSslConfiguration config;
|
||||||
|
bool ignoreSslErrors;
|
||||||
|
QSslSocket::PeerVerifyMode peerVerifyMode;
|
||||||
|
QSsl::SslProtocol protocol;
|
||||||
|
QString ciphers;
|
||||||
|
PskProvider m_pskProvider;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void incomingConnection(qintptr socketDescriptor)
|
||||||
|
{
|
||||||
|
socket = new QSslSocket(this);
|
||||||
|
socket->setSslConfiguration(config);
|
||||||
|
socket->setPeerVerifyMode(peerVerifyMode);
|
||||||
|
socket->setProtocol(protocol);
|
||||||
|
if (ignoreSslErrors)
|
||||||
|
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
||||||
|
|
||||||
|
if (!ciphers.isEmpty()) {
|
||||||
|
socket->setCiphers(ciphers);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
|
||||||
|
QVERIFY(!socket->peerAddress().isNull());
|
||||||
|
QVERIFY(socket->peerPort() != 0);
|
||||||
|
QVERIFY(!socket->localAddress().isNull());
|
||||||
|
QVERIFY(socket->localPort() != 0);
|
||||||
|
|
||||||
|
connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, &m_pskProvider, &PskProvider::providePsk);
|
||||||
|
|
||||||
|
socket->startServerEncryption();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
void ignoreErrorSlot()
|
||||||
|
{
|
||||||
|
socket->ignoreSslErrors();
|
||||||
|
}
|
||||||
|
};
|
||||||
void tst_QSslSocket::simplePskConnect_data()
|
void tst_QSslSocket::simplePskConnect_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<PskConnectTestType>("pskTestType");
|
QTest::addColumn<PskConnectTestType>("pskTestType");
|
||||||
@ -3415,6 +3473,90 @@ void tst_QSslSocket::allowedProtocolNegotiation()
|
|||||||
#endif // OPENSSL_VERSION_NUMBER
|
#endif // OPENSSL_VERSION_NUMBER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QSslSocket::pskServer()
|
||||||
|
{
|
||||||
|
QFETCH_GLOBAL(bool, setProxy);
|
||||||
|
if (!QSslSocket::supportsSsl() || setProxy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSslSocket socket;
|
||||||
|
this->socket = &socket;
|
||||||
|
|
||||||
|
QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
|
||||||
|
QVERIFY(connectedSpy.isValid());
|
||||||
|
|
||||||
|
QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
|
||||||
|
QVERIFY(disconnectedSpy.isValid());
|
||||||
|
|
||||||
|
QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted()));
|
||||||
|
QVERIFY(connectionEncryptedSpy.isValid());
|
||||||
|
|
||||||
|
QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
|
||||||
|
QVERIFY(pskAuthenticationRequiredSpy.isValid());
|
||||||
|
|
||||||
|
connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(disconnected()), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(exitLoop()));
|
||||||
|
connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop()));
|
||||||
|
|
||||||
|
// force a PSK cipher w/o auth
|
||||||
|
socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH);
|
||||||
|
|
||||||
|
PskProvider provider;
|
||||||
|
provider.setIdentity(PSK_CLIENT_IDENTITY);
|
||||||
|
provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
|
||||||
|
connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
|
||||||
|
socket.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||||
|
|
||||||
|
PskServer server;
|
||||||
|
server.m_pskProvider.setIdentity(provider.m_identity);
|
||||||
|
server.m_pskProvider.setPreSharedKey(provider.m_psk);
|
||||||
|
server.config.setPreSharedKeyIdentityHint(PSK_SERVER_IDENTITY_HINT);
|
||||||
|
QVERIFY(server.listen());
|
||||||
|
|
||||||
|
// Start connecting
|
||||||
|
socket.connectToHost(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
|
||||||
|
enterLoop(5);
|
||||||
|
|
||||||
|
// Entered connected state
|
||||||
|
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||||||
|
QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
|
||||||
|
QVERIFY(!socket.isEncrypted());
|
||||||
|
QCOMPARE(connectedSpy.count(), 1);
|
||||||
|
QCOMPARE(disconnectedSpy.count(), 0);
|
||||||
|
|
||||||
|
// Enter encrypted mode
|
||||||
|
socket.startClientEncryption();
|
||||||
|
QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
|
||||||
|
QVERIFY(!socket.isEncrypted());
|
||||||
|
QCOMPARE(connectionEncryptedSpy.count(), 0);
|
||||||
|
|
||||||
|
// Start handshake.
|
||||||
|
enterLoop(10);
|
||||||
|
|
||||||
|
// We must get the PSK signal in all cases
|
||||||
|
QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
|
||||||
|
|
||||||
|
QCOMPARE(connectionEncryptedSpy.count(), 1);
|
||||||
|
QVERIFY(socket.isEncrypted());
|
||||||
|
QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
|
||||||
|
|
||||||
|
// check writing
|
||||||
|
socket.write("Hello from Qt TLS/PSK!");
|
||||||
|
QVERIFY(socket.waitForBytesWritten());
|
||||||
|
|
||||||
|
// disconnect
|
||||||
|
socket.disconnectFromHost();
|
||||||
|
enterLoop(10);
|
||||||
|
|
||||||
|
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
|
||||||
|
QCOMPARE(disconnectedSpy.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // QT_NO_OPENSSL
|
#endif // QT_NO_OPENSSL
|
||||||
|
|
||||||
#endif // QT_NO_SSL
|
#endif // QT_NO_SSL
|
||||||
|
Loading…
x
Reference in New Issue
Block a user