SSL: add support for the Next Protocol Negotiation extension

... which is needed to negotiate the SPDY protocol.

[ChangeLog][QtNetwork][QSslConfiguration] Added support for the Next
Protocol Negotiation (NPN) TLS extension.

Task-number: QTBUG-33208

Change-Id: I3c945f9b7e2d2ffb0814bfdd3e87de1dae6c20ef
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
This commit is contained in:
Peter Hartmann 2013-08-28 10:56:24 +02:00 committed by The Qt Project
parent df62c31807
commit 42cfb5fe4d
12 changed files with 426 additions and 3 deletions

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -52,6 +53,9 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
|QSsl::SslOptionDisableCompression
|QSsl::SslOptionDisableSessionPersistence;
const char QSslConfiguration::NextProtocolSpdy3_0[] = "spdy/3";
const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
/*!
\class QSslConfiguration
\brief The QSslConfiguration class holds the configuration and state of an SSL connection
@ -112,6 +116,33 @@ const QSsl::SslOptions QSslConfigurationPrivate::defaultSslOptions = QSsl::SslOp
QSslSocket::sslConfiguration(), QSslSocket::setSslConfiguration()
*/
/*!
\enum QSslConfiguration::NextProtocolNegotiationStatus
Describes the status of the Next Protocol Negotiation (NPN).
\value NextProtocolNegotiationNone No application protocol
has been negotiated (yet).
\value NextProtocolNegotiationNegotiated A next protocol
has been negotiated (see nextNegotiatedProtocol()).
\value NextProtocolNegotiationUnsupported The client and
server could not agree on a common next application protocol.
*/
/*!
\variable QSslConfiguration::NextProtocolSpdy3_0
\brief The value used for negotiating SPDY 3.0 during the Next
Protocol Negotiation.
*/
/*!
\variable QSslConfiguration::NextProtocolHttp1_1
\brief The value used for negotiating HTTP 1.1 during the Next
Protocol Negotiation.
*/
/*!
Constructs an empty SSL configuration. This configuration contains
no valid settings and the state will be empty. isNull() will
@ -185,7 +216,10 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->allowRootCertOnDemandLoading == other.d->allowRootCertOnDemandLoading &&
d->sslOptions == other.d->sslOptions &&
d->sslSession == other.d->sslSession &&
d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint;
d->sslSessionTicketLifeTimeHint == other.d->sslSessionTicketLifeTimeHint &&
d->nextAllowedProtocols == other.d->nextAllowedProtocols &&
d->nextNegotiatedProtocol == other.d->nextNegotiatedProtocol &&
d->nextProtocolNegotiationStatus == other.d->nextProtocolNegotiationStatus;
}
/*!
@ -221,7 +255,10 @@ bool QSslConfiguration::isNull() const
d->peerCertificateChain.count() == 0 &&
d->sslOptions == QSslConfigurationPrivate::defaultSslOptions &&
d->sslSession.isNull() &&
d->sslSessionTicketLifeTimeHint == -1);
d->sslSessionTicketLifeTimeHint == -1 &&
d->nextAllowedProtocols.isEmpty() &&
d->nextNegotiatedProtocol.isNull() &&
d->nextProtocolNegotiationStatus == QSslConfiguration::NextProtocolNegotiationNone);
}
/*!
@ -652,6 +689,71 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
return d->sslSessionTicketLifeTimeHint;
}
/*!
\since 5.3
This function returns the protocol negotiated with the server
if the Next Protocol Negotiation (NPN) TLS extension was enabled.
In order for the NPN extension to be enabled, setAllowedNextProtocols()
needs to be called explicitly before connecting to the server.
If no protocol could be negotiated or the extension was not enabled,
this function returns a QByteArray which is null.
\sa setAllowedNextProtocols(), nextProtocolNegotiationStatus()
*/
QByteArray QSslConfiguration::nextNegotiatedProtocol() const
{
return d->nextNegotiatedProtocol;
}
/*!
\since 5.3
This function sets the allowed \a protocols to be negotiated with the
server through the Next Protocol Negotiation (NPN) TLS extension; each
element in \a protocols must define one allowed protocol.
The function must be called explicitly before connecting to send the NPN
extension in the SSL handshake.
Whether or not the negotiation succeeded can be queried through
nextProtocolNegotiationStatus().
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), allowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
*/
void QSslConfiguration::setAllowedNextProtocols(QList<QByteArray> protocols)
{
d->nextAllowedProtocols = protocols;
}
/*!
\since 5.3
This function returns the allowed protocols to be negotiated with the
server through the Next Protocol Negotiation (NPN) TLS extension, as set
by setAllowedNextProtocols().
\sa nextNegotiatedProtocol(), nextProtocolNegotiationStatus(), setAllowedNextProtocols(), QSslConfiguration::NextProtocolSpdy3_0, QSslConfiguration::NextProtocolHttp1_1
*/
QList<QByteArray> QSslConfiguration::allowedNextProtocols() const
{
return d->nextAllowedProtocols;
}
/*!
\since 5.3
This function returns the status of the Next Protocol Negotiation (NPN).
If the feature has not been enabled through setAllowedNextProtocols(),
this function returns NextProtocolNegotiationNone.
The status will be set before emitting the encrypted() signal.
\sa setAllowedNextProtocols(), allowedNextProtocols(), nextNegotiatedProtocol(), QSslConfiguration::NextProtocolNegotiationStatus
*/
QSslConfiguration::NextProtocolNegotiationStatus QSslConfiguration::nextProtocolNegotiationStatus() const
{
return d->nextProtocolNegotiationStatus;
}
/*!
Returns the default SSL configuration to be used in new SSL
connections.

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -131,6 +132,21 @@ public:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);
enum NextProtocolNegotiationStatus {
NextProtocolNegotiationNone,
NextProtocolNegotiationNegotiated,
NextProtocolNegotiationUnsupported
};
void setAllowedNextProtocols(QList<QByteArray> protocols);
QList<QByteArray> allowedNextProtocols() const;
QByteArray nextNegotiatedProtocol() const;
NextProtocolNegotiationStatus nextProtocolNegotiationStatus() const;
static const char NextProtocolSpdy3_0[];
static const char NextProtocolHttp1_1[];
private:
friend class QSslSocket;
friend class QSslConfigurationPrivate;

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -86,7 +87,8 @@ public:
allowRootCertOnDemandLoading(true),
peerSessionShared(false),
sslOptions(QSslConfigurationPrivate::defaultSslOptions),
sslSessionTicketLifeTimeHint(-1)
sslSessionTicketLifeTimeHint(-1),
nextProtocolNegotiationStatus(QSslConfiguration::NextProtocolNegotiationNone)
{ }
QSslCertificate peerCertificate;
@ -114,6 +116,10 @@ public:
QByteArray sslSession;
int sslSessionTicketLifeTimeHint;
QList<QByteArray> nextAllowedProtocols;
QByteArray nextNegotiatedProtocol;
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
// in qsslsocket.cpp:
static QSslConfiguration defaultConfiguration();
static void setDefaultConfiguration(const QSslConfiguration &configuration);

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -263,6 +264,45 @@ init_context:
return sslContext;
}
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
static int next_proto_cb(SSL *, unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen, void *arg)
{
QSslContext::NPNContext *ctx = reinterpret_cast<QSslContext::NPNContext *>(arg);
// comment out to debug:
// QList<QByteArray> supportedVersions;
// for (unsigned int i = 0; i < inlen; ) {
// QByteArray version(reinterpret_cast<const char *>(&in[i+1]), in[i]);
// supportedVersions << version;
// i += in[i] + 1;
// }
int proto = q_SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len);
switch (proto) {
case OPENSSL_NPN_UNSUPPORTED:
ctx->status = QSslConfiguration::NextProtocolNegotiationNone;
break;
case OPENSSL_NPN_NEGOTIATED:
ctx->status = QSslConfiguration::NextProtocolNegotiationNegotiated;
break;
case OPENSSL_NPN_NO_OVERLAP:
ctx->status = QSslConfiguration::NextProtocolNegotiationUnsupported;
break;
default:
qWarning("OpenSSL sent unknown NPN status");
}
return SSL_TLSEXT_ERR_OK;
}
QSslContext::NPNContext QSslContext::npnContext() const
{
return m_npnContext;
}
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
// Needs to be deleted by caller
SSL* QSslContext::createSsl()
{
@ -283,6 +323,26 @@ SSL* QSslContext::createSsl()
session = 0;
}
}
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
QList<QByteArray> protocols = sslConfiguration.d->nextAllowedProtocols;
if (!protocols.isEmpty()) {
m_supportedNPNVersions.clear();
for (int a = 0; a < protocols.count(); ++a) {
if (protocols.at(a).size() > 255) {
qWarning() << "TLS NPN extension" << protocols.at(a)
<< "is too long and will be truncated to 255 characters.";
protocols[a] = protocols.at(a).left(255);
}
m_supportedNPNVersions.append(protocols.at(a).size()).append(protocols.at(a));
}
m_npnContext.data = reinterpret_cast<unsigned char *>(m_supportedNPNVersions.data());
m_npnContext.len = m_supportedNPNVersions.count();
m_npnContext.status = QSslConfiguration::NextProtocolNegotiationNone;
q_SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &m_npnContext);
}
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
return ssl;
}

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -72,6 +73,21 @@ public:
QByteArray sessionASN1() const;
void setSessionASN1(const QByteArray &sessionASN1);
int sessionTicketLifeTimeHint() const;
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
// must be public because we want to use it from an OpenSSL callback
struct NPNContext {
NPNContext() : data(0),
len(0),
status(QSslConfiguration::NextProtocolNegotiationNone)
{ }
unsigned char *data;
unsigned short len;
QSslConfiguration::NextProtocolNegotiationStatus status;
};
NPNContext npnContext() const;
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
protected:
QSslContext();
@ -84,6 +100,10 @@ private:
QSslError::SslError errorCode;
QString errorStr;
QSslConfiguration sslConfiguration;
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
QByteArray m_supportedNPNVersions;
NPNContext m_npnContext;
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
};
#endif // QT_NO_SSL

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -905,6 +906,9 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
d->configuration.sslOptions = configuration.d->sslOptions;
d->configuration.sslSession = configuration.sessionTicket();
d->configuration.sslSessionTicketLifeTimeHint = configuration.sessionTicketLifeTimeHint();
d->configuration.nextAllowedProtocols = configuration.allowedNextProtocols();
d->configuration.nextNegotiatedProtocol = configuration.nextNegotiatedProtocol();
d->configuration.nextProtocolNegotiationStatus = configuration.nextProtocolNegotiationStatus();
// if the CA certificates were set explicitly (either via
// QSslConfiguration::setCaCertificates() or QSslSocket::setCaCertificates(),

View File

@ -1486,6 +1486,15 @@ void QSslSocketBackendPrivate::continueHandshake()
}
}
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
const unsigned char *proto;
unsigned int proto_len;
q_SSL_get0_next_proto_negotiated(ssl, &proto, &proto_len);
QByteArray nextProtocol(reinterpret_cast<const char *>(proto), proto_len);
configuration.nextNegotiatedProtocol = nextProtocol;
configuration.nextProtocolNegotiationStatus = sslContextPointer->npnContext().status;
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
connectionEncrypted = true;
emit q->encrypted();
if (autoStartHandshake && pendingClose) {

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -346,6 +347,20 @@ DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, SSLeay_version, int a, a, return 0, return)
DEFINEFUNC2(int, i2d_SSL_SESSION, SSL_SESSION *in, in, unsigned char **pp, pp, return 0, return)
DEFINEFUNC3(SSL_SESSION *, d2i_SSL_SESSION, SSL_SESSION **a, a, const unsigned char **pp, pp, long length, length, return 0, return)
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
DEFINEFUNC6(int, SSL_select_next_proto, unsigned char **out, out, unsigned char *outlen, outlen,
const unsigned char *in, in, unsigned int inlen, inlen,
const unsigned char *client, client, unsigned int client_len, client_len,
return -1, return)
DEFINEFUNC3(void, SSL_CTX_set_next_proto_select_cb, SSL_CTX *s, s,
int (*cb) (SSL *ssl, unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen, void *arg), cb,
void *arg, arg, return, DUMMYARG)
DEFINEFUNC3(void, SSL_get0_next_proto_negotiated, const SSL *s, s,
const unsigned char **data, data, unsigned *len, len, return, DUMMYARG)
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
#define RESOLVEFUNC(func) \
if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \
@ -815,6 +830,11 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSLeay_version)
RESOLVEFUNC(i2d_SSL_SESSION)
RESOLVEFUNC(d2i_SSL_SESSION)
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
RESOLVEFUNC(SSL_select_next_proto)
RESOLVEFUNC(SSL_CTX_set_next_proto_select_cb)
RESOLVEFUNC(SSL_get0_next_proto_negotiated)
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
symbolsResolved = true;
delete libs.first;

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@ -473,6 +474,20 @@ const char *q_SSLeay_version(int type);
int q_i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp);
SSL_SESSION *q_d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length);
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
int q_SSL_select_next_proto(unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
const unsigned char *client, unsigned int client_len);
void q_SSL_CTX_set_next_proto_select_cb(SSL_CTX *s,
int (*cb) (SSL *ssl, unsigned char **out,
unsigned char *outlen,
const unsigned char *in,
unsigned int inlen, void *arg),
void *arg);
void q_SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
unsigned *len);
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
// Helper function
class QDateTime;
QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);

View File

@ -25,6 +25,7 @@ qnetworkreply \
qpainfo \
qscreen \
qssloptions \
qsslsocket \
qtabletevent \
qtexteditlist \
qtbug-8933 \

View File

@ -0,0 +1,164 @@
/****************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtNetwork/qsslconfiguration.h>
#include <QtNetwork/qsslsocket.h>
#include <QtTest/QtTest>
#ifndef QT_NO_SSL
Q_DECLARE_METATYPE(QSslConfiguration::NextProtocolNegotiationStatus)
#endif
class tst_QSslSocket : public QObject
{
Q_OBJECT
#ifndef QT_NO_SSL
private slots:
void nextProtocolNegotiation_data();
void nextProtocolNegotiation();
#endif // QT_NO_SSL
};
#ifndef QT_NO_SSL
void tst_QSslSocket::nextProtocolNegotiation_data()
{
QTest::addColumn<bool>("setConfiguration");
QTest::addColumn<QString>("host");
QTest::addColumn<QList<QByteArray> >("allowedProtocols");
QTest::addColumn<QByteArray>("expectedProtocol");
QTest::addColumn<QSslConfiguration::NextProtocolNegotiationStatus>("expectedStatus");
QList<QString> hosts = QList<QString>()
<< QStringLiteral("www.google.com")
<< QStringLiteral("www.facebook.com")
<< QStringLiteral("www.twitter.com")
<< QStringLiteral("graph.facebook.com")
<< QStringLiteral("api.twitter.com");
foreach (QString host, hosts) {
QByteArray tag = host.toLocal8Bit();
tag.append("-none");
QTest::newRow(tag)
<< false
<< host
<< QList<QByteArray>()
<< QByteArray()
<< QSslConfiguration::NextProtocolNegotiationNone;
tag = host.toLocal8Bit();
tag.append("-none-explicit");
QTest::newRow(tag)
<< true
<< host
<< QList<QByteArray>()
<< QByteArray()
<< QSslConfiguration::NextProtocolNegotiationNone;
tag = host.toLocal8Bit();
tag.append("-http/1.1");
QTest::newRow(tag)
<< true
<< host
<< (QList<QByteArray>() << QSslConfiguration::NextProtocolHttp1_1)
<< QByteArray(QSslConfiguration::NextProtocolHttp1_1)
<< QSslConfiguration::NextProtocolNegotiationNegotiated;
tag = host.toLocal8Bit();
tag.append("-spdy/3");
QTest::newRow(tag)
<< true
<< host
<< (QList<QByteArray>() << QSslConfiguration::NextProtocolSpdy3_0)
<< QByteArray(QSslConfiguration::NextProtocolSpdy3_0)
<< QSslConfiguration::NextProtocolNegotiationNegotiated;
tag = host.toLocal8Bit();
tag.append("-spdy/3-and-http/1.1");
QTest::newRow(tag)
<< true
<< host
<< (QList<QByteArray>() << QSslConfiguration::NextProtocolSpdy3_0 << QSslConfiguration::NextProtocolHttp1_1)
<< QByteArray(QSslConfiguration::NextProtocolSpdy3_0)
<< QSslConfiguration::NextProtocolNegotiationNegotiated;
}
}
void tst_QSslSocket::nextProtocolNegotiation()
{
if (!QSslSocket::supportsSsl())
return;
QSslSocket socket;
QFETCH(bool, setConfiguration);
if (setConfiguration) {
QSslConfiguration conf = socket.sslConfiguration();
QFETCH(QList<QByteArray>, allowedProtocols);
conf.setAllowedNextProtocols(allowedProtocols);
socket.setSslConfiguration(conf);
}
QFETCH(QString, host);
socket.connectToHostEncrypted(host, 443);
socket.ignoreSslErrors();
QVERIFY(socket.waitForEncrypted(10000));
QFETCH(QByteArray, expectedProtocol);
QCOMPARE(socket.sslConfiguration().nextNegotiatedProtocol(), expectedProtocol);
QFETCH(QSslConfiguration::NextProtocolNegotiationStatus, expectedStatus);
QCOMPARE(socket.sslConfiguration().nextProtocolNegotiationStatus(), expectedStatus);
socket.disconnectFromHost();
QVERIFY(socket.waitForDisconnected());
}
#endif // QT_NO_SSL
QTEST_MAIN(tst_QSslSocket)
#include "main.moc"

View File

@ -0,0 +1,6 @@
CONFIG += testcase
SOURCES += main.cpp
QT = core network testlib
TARGET = tst_qsslsocket