Make ephemeral server key available
When using cipher algorithms with forward secrecy an ephemeral key is used to generate the symmetric session key. Beside the SSL certificate's key, this ephemeral key is of cryptographic interest. The ephemeral key is chosen by the server side - currently statically in the Qt implementation - so it is only of interest on the client side to check it. Therefore the ephemeral key is the null key if the connection is set up in server mode or a cipher without forward secrecy is used. Change-Id: If241247dbb8490a91233ae47f2b38952c6591bf4 Reviewed-by: Markus Goetz (Woboq GmbH) <markus@woboq.com>bb10
parent
a9e1fc29ca
commit
73ad2bf32f
|
|
@ -730,6 +730,23 @@ int QSslConfiguration::sessionTicketLifeTimeHint() const
|
|||
return d->sslSessionTicketLifeTimeHint;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.7
|
||||
|
||||
Returns the ephemeral server key used for cipher algorithms
|
||||
with forward secrecy, e.g. DHE-RSA-AES128-SHA.
|
||||
|
||||
The ephemeral key is only available when running in client mode, i.e.
|
||||
QSslSocket::SslClientMode. When running in server mode or using a
|
||||
cipher algorithm without forward secrecy a null key is returned.
|
||||
The ephemeral server key will be set before emitting the encrypted()
|
||||
signal.
|
||||
*/
|
||||
QSslKey QSslConfiguration::ephemeralServerKey() const
|
||||
{
|
||||
return d->ephemeralServerKey;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ public:
|
|||
void setSessionTicket(const QByteArray &sessionTicket);
|
||||
int sessionTicketLifeTimeHint() const;
|
||||
|
||||
QSslKey ephemeralServerKey() const;
|
||||
|
||||
// EC settings
|
||||
QVector<QSslEllipticCurve> ellipticCurves() const;
|
||||
void setEllipticCurves(const QVector<QSslEllipticCurve> &curves);
|
||||
|
|
|
|||
|
|
@ -113,6 +113,8 @@ public:
|
|||
QByteArray sslSession;
|
||||
int sslSessionTicketLifeTimeHint;
|
||||
|
||||
QSslKey ephemeralServerKey;
|
||||
|
||||
QList<QByteArray> nextAllowedProtocols;
|
||||
QByteArray nextNegotiatedProtocol;
|
||||
QSslConfiguration::NextProtocolNegotiationStatus nextProtocolNegotiationStatus;
|
||||
|
|
|
|||
|
|
@ -1566,6 +1566,14 @@ void QSslSocketBackendPrivate::continueHandshake()
|
|||
}
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x1000100fL ...
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
if (q_SSLeay() >= 0x10002000L && mode == QSslSocket::SslClientMode) {
|
||||
EVP_PKEY *key;
|
||||
if (q_SSL_get_server_tmp_key(ssl, &key))
|
||||
configuration.ephemeralServerKey = QSslKey(key, QSsl::PublicKey);
|
||||
}
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L ...
|
||||
|
||||
connectionEncrypted = true;
|
||||
emit q->encrypted();
|
||||
if (autoStartHandshake && pendingClose) {
|
||||
|
|
|
|||
|
|
@ -483,6 +483,9 @@ size_t q_EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
|
|||
int q_EC_curve_nist2nid(const char *name);
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
#endif // OPENSSL_NO_EC
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
#define q_SSL_get_server_tmp_key(ssl, key) q_SSL_ctrl((ssl), SSL_CTRL_GET_SERVER_TMP_KEY, 0, (char *)key)
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
||||
// PKCS#12 support
|
||||
int q_PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,8 @@ private slots:
|
|||
#ifndef QT_NO_OPENSSL
|
||||
void simplePskConnect_data();
|
||||
void simplePskConnect();
|
||||
void ephemeralServerKey_data();
|
||||
void ephemeralServerKey();
|
||||
#endif
|
||||
|
||||
static void exitLoop()
|
||||
|
|
@ -3344,6 +3346,40 @@ void tst_QSslSocket::simplePskConnect()
|
|||
QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
|
||||
QCOMPARE(disconnectedSpy.count(), 1);
|
||||
}
|
||||
|
||||
void tst_QSslSocket::ephemeralServerKey_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cipher");
|
||||
QTest::addColumn<bool>("emptyKey");
|
||||
|
||||
QTest::newRow("NonForwardSecrecyCipher") << "RC4-SHA" << true;
|
||||
QTest::newRow("ForwardSecrecyCipher") << "ECDHE-RSA-AES256-SHA" << (QSslSocket::sslLibraryVersionNumber() < 0x10002000L);
|
||||
}
|
||||
|
||||
void tst_QSslSocket::ephemeralServerKey()
|
||||
{
|
||||
QFETCH_GLOBAL(bool, setProxy);
|
||||
if (!QSslSocket::supportsSsl() || setProxy)
|
||||
return;
|
||||
|
||||
QFETCH(QString, cipher);
|
||||
QFETCH(bool, emptyKey);
|
||||
SslServer server;
|
||||
server.config.setCiphers(QList<QSslCipher>() << QSslCipher(cipher));
|
||||
QVERIFY(server.listen());
|
||||
QSslSocketPtr client = newSocket();
|
||||
socket = client.data();
|
||||
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
|
||||
QSignalSpy spy(client.data(), &QSslSocket::encrypted);
|
||||
|
||||
client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
|
||||
spy.wait();
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
QVERIFY(server.config.ephemeralServerKey().isNull());
|
||||
QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey);
|
||||
}
|
||||
|
||||
#endif // QT_NO_OPENSSL
|
||||
|
||||
#endif // QT_NO_SSL
|
||||
|
|
|
|||
Loading…
Reference in New Issue