Add support for finding the version of SSL/TLS in use.

Previously we allowed you to specify which version(s) you wanted to use,
but did not provide access to the version that was actually negotiated.

[ChangeLog][QtNetwork][QSslSocket] Add support for finding the version
of SSL/TLS in use by a connection.

Task-number: QTBUG-28471
Change-Id: I6d50d2bc9f1ce7f98192e67992178fe7e41c0575
Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
This commit is contained in:
Richard J. Moore 2014-03-10 13:00:08 +00:00 committed by The Qt Project
parent 8f17d622b0
commit 233a2f37bf
10 changed files with 61 additions and 1 deletions

View File

@ -208,6 +208,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const
d->localCertificateChain == other.d->localCertificateChain &&
d->privateKey == other.d->privateKey &&
d->sessionCipher == other.d->sessionCipher &&
d->sessionProtocol == other.d->sessionProtocol &&
d->ciphers == other.d->ciphers &&
d->caCertificates == other.d->caCertificates &&
d->protocol == other.d->protocol &&
@ -511,6 +512,18 @@ QSslCipher QSslConfiguration::sessionCipher() const
return d->sessionCipher;
}
/*!
Returns the socket's SSL/TLS protocol or UnknownProtocol if the
connection isn't encrypted. The socket's protocol for the session
is set during the handshake phase.
\sa protocol(), setProtocol()
*/
QSsl::SslProtocol QSslConfiguration::sessionProtocol() const
{
return d->sessionProtocol;
}
/*!
Returns the \l {QSslKey} {SSL key} assigned to this connection or
a null key if none has been assigned yet.

View File

@ -109,6 +109,7 @@ public:
QSslCertificate peerCertificate() const;
QList<QSslCertificate> peerCertificateChain() const;
QSslCipher sessionCipher() const;
QSsl::SslProtocol sessionProtocol() const;
// Private keys, for server sockets
QSslKey privateKey() const;

View File

@ -81,7 +81,8 @@ class QSslConfigurationPrivate: public QSharedData
{
public:
QSslConfigurationPrivate()
: protocol(QSsl::SecureProtocols),
: sessionProtocol(QSsl::UnknownProtocol),
protocol(QSsl::SecureProtocols),
peerVerifyMode(QSslSocket::AutoVerifyPeer),
peerVerifyDepth(0),
allowRootCertOnDemandLoading(true),
@ -98,6 +99,7 @@ public:
QSslKey privateKey;
QSslCipher sessionCipher;
QSsl::SslProtocol sessionProtocol;
QList<QSslCipher> ciphers;
QList<QSslCertificate> caCertificates;

View File

@ -878,6 +878,7 @@ QSslConfiguration QSslSocket::sslConfiguration() const
QSslConfigurationPrivate *copy = new QSslConfigurationPrivate(d->configuration);
copy->ref.store(0); // the QSslConfiguration constructor refs up
copy->sessionCipher = d->sessionCipher();
copy->sessionProtocol = d->sessionProtocol();
return QSslConfiguration(copy);
}
@ -1072,6 +1073,20 @@ QSslCipher QSslSocket::sessionCipher() const
return d->sessionCipher();
}
/*!
Returns the socket's SSL/TLS protocol or UnknownProtocol if the
connection isn't encrypted. The socket's protocol for the session
is set during the handshake phase.
\sa protocol(), setProtocol()
*/
QSsl::SslProtocol QSslSocket::sessionProtocol() const
{
Q_D(const QSslSocket);
return d->sessionProtocol();
}
/*!
Sets the socket's private \l {QSslKey} {key} to \a key. The
private key and the local \l {QSslCertificate} {certificate} are
@ -2095,6 +2110,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->localCertificateChain = global->localCertificateChain;
ptr->privateKey = global->privateKey;
ptr->sessionCipher = global->sessionCipher;
ptr->sessionProtocol = global->sessionProtocol;
ptr->ciphers = global->ciphers;
ptr->caCertificates = global->caCertificates;
ptr->protocol = global->protocol;

View File

@ -140,6 +140,7 @@ public:
QSslCertificate peerCertificate() const;
QList<QSslCertificate> peerCertificateChain() const;
QSslCipher sessionCipher() const;
QSsl::SslProtocol sessionProtocol() const;
// Private keys, for server sockets.
void setPrivateKey(const QSslKey &key);

View File

@ -1428,6 +1428,28 @@ QSslCipher QSslSocketBackendPrivate::sessionCipher() const
return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
}
QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const
{
if (!ssl)
return QSsl::UnknownProtocol;
int ver = q_SSL_version(ssl);
switch (ver) {
case 0x2:
return QSsl::SslV2;
case 0x300:
return QSsl::SslV3;
case 0x301:
return QSsl::TlsV1_0;
case 0x302:
return QSsl::TlsV1_1;
case 0x303:
return QSsl::TlsV1_2;
}
return QSsl::UnknownProtocol;
}
void QSslSocketBackendPrivate::continueHandshake()
{
Q_Q(QSslSocket);

View File

@ -131,6 +131,7 @@ public:
void disconnectFromHost();
void disconnected();
QSslCipher sessionCipher() const;
QSsl::SslProtocol sessionProtocol() const;
void continueHandshake();
bool checkSslErrors();
#ifdef Q_OS_WIN

View File

@ -238,6 +238,7 @@ DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, retu
#else
DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
#endif
DEFINEFUNC(int, SSL_version, const SSL *a, a, return 0, return)
DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return 0, return)
DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return 0, return)
@ -739,6 +740,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(SSL_free)
RESOLVEFUNC(SSL_get_ciphers)
RESOLVEFUNC(SSL_get_current_cipher)
RESOLVEFUNC(SSL_version)
RESOLVEFUNC(SSL_get_error)
RESOLVEFUNC(SSL_get_peer_cert_chain)
RESOLVEFUNC(SSL_get_peer_certificate)

View File

@ -329,6 +329,7 @@ const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
#else
SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
#endif
int q_SSL_version(const SSL *a);
int q_SSL_get_error(SSL *a, int b);
STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
X509 *q_SSL_get_peer_certificate(SSL *a);

View File

@ -190,6 +190,7 @@ public:
virtual void disconnectFromHost() = 0;
virtual void disconnected() = 0;
virtual QSslCipher sessionCipher() const = 0;
virtual QSsl::SslProtocol sessionProtocol() const = 0;
virtual void continueHandshake() = 0;
Q_AUTOTEST_EXPORT static bool rootCertOnDemandLoadingSupported();