Add support for explicit TLS 1.1 and 1.2
authorBrendan Long <b.long@cablelabs.com>
Thu, 16 Aug 2012 23:14:04 +0000 (17:14 -0600)
committerQt by Nokia <qt-info@nokia.com>
Wed, 29 Aug 2012 12:22:54 +0000 (14:22 +0200)
Add SslProtocol enums TlsV1_1 and TlsV1_2 and use the appropriate OpenSSL
methods when they're selected (TLSv1_1_client_method, TLSv1_2_client_method,
TLSv1_1_server_method and TLSv1_2_server_method). This allows us to
explicitly use TLS 1.1 or 1.2.

Task-number: QTBUG-26866
Change-Id: I159da548546fa746c20e9e96bc0e5b785e4e761b
Reviewed-by: Richard J. Moore <rich@kde.org>
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
src/network/ssl/qssl.cpp
src/network/ssl/qssl.h
src/network/ssl/qsslsocket_openssl.cpp
src/network/ssl/qsslsocket_openssl_symbols.cpp
src/network/ssl/qsslsocket_openssl_symbols_p.h
tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp

index 932b7c9..c6f708b 100644 (file)
@@ -118,6 +118,8 @@ QT_BEGIN_NAMESPACE
     \value SslV2 SSLv2
     \value TlsV1_0 TLSv1.0
     \value TlsV1 Obsolete, means the same as TlsV1_0
+    \value TlsV1_1 TLSv1.1
+    \value TlsV1_2 TLSv1.2
     \value UnknownProtocol The cipher's protocol cannot be determined.
     \value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1.0. This
     value is used by QSslSocket only.
index 7387b02..ab43fe0 100644 (file)
@@ -84,6 +84,8 @@ namespace QSsl {
 #if QT_DEPRECATED_SINCE(5,0)
         TlsV1 = TlsV1_0,
 #endif
+        TlsV1_1,
+        TlsV1_2,
         AnyProtocol,
         TlsV1SslV3,
         SecureProtocols,
index a23e3fa..250ff0f 100644 (file)
@@ -197,6 +197,10 @@ QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *ciph
             ciph.d->protocol = QSsl::SslV2;
         else if (protoString == QLatin1String("TLSv1"))
             ciph.d->protocol = QSsl::TlsV1_0;
+        else if (protoString == QLatin1String("TLSv1.1"))
+            ciph.d->protocol = QSsl::TlsV1_1;
+        else if (protoString == QLatin1String("TLSv1.2"))
+            ciph.d->protocol = QSsl::TlsV1_2;
 
         if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))
             ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3);
@@ -318,6 +322,20 @@ init_context:
     case QSsl::TlsV1_0:
         ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());
         break;
+    case QSsl::TlsV1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+        ctx = q_SSL_CTX_new(client ? q_TLSv1_1_client_method() : q_TLSv1_1_server_method());
+#else
+        ctx = 0; // TLS 1.1 not supported by the system, but chosen deliberately -> error
+#endif
+        break;
+    case QSsl::TlsV1_2:
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+        ctx = q_SSL_CTX_new(client ? q_TLSv1_2_client_method() : q_TLSv1_2_server_method());
+#else
+        ctx = 0; // TLS 1.2 not supported by the system, but chosen deliberately -> error
+#endif
+        break;
     }
     if (!ctx) {
         // After stopping Flash 10 the SSL library looses its ciphers. Try re-adding them
@@ -473,6 +491,8 @@ init_context:
 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
     if ((configuration.protocol == QSsl::TlsV1SslV3 ||
         configuration.protocol == QSsl::TlsV1_0 ||
+        configuration.protocol == QSsl::TlsV1_1 ||
+        configuration.protocol == QSsl::TlsV1_2 ||
         configuration.protocol == QSsl::SecureProtocols ||
         configuration.protocol == QSsl::AnyProtocol) &&
         client && q_SSLeay() >= 0x00090806fL) {
index 152cac5..2fe7100 100644 (file)
@@ -236,12 +236,20 @@ DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0
 DEFINEFUNC(const SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return 0, return)
 DEFINEFUNC(const SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return 0, return)
 DEFINEFUNC(const SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+DEFINEFUNC(const SSL_METHOD *, TLSv1_1_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, TLSv1_2_client_method, DUMMYARG, DUMMYARG, return 0, return)
+#endif
 #ifndef OPENSSL_NO_SSL2
 DEFINEFUNC(const SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return 0, return)
 #endif
 DEFINEFUNC(const SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return 0, return)
 DEFINEFUNC(const SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return 0, return)
 DEFINEFUNC(const SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+DEFINEFUNC(const SSL_METHOD *, TLSv1_1_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, TLSv1_2_server_method, DUMMYARG, DUMMYARG, return 0, return)
+#endif
 #else
 DEFINEFUNC(SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return)
 DEFINEFUNC(SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return 0, return)
@@ -678,12 +686,20 @@ bool q_resolveOpenSslSymbols()
     RESOLVEFUNC(SSLv3_client_method)
     RESOLVEFUNC(SSLv23_client_method)
     RESOLVEFUNC(TLSv1_client_method)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+    RESOLVEFUNC(TLSv1_1_client_method)
+    RESOLVEFUNC(TLSv1_2_client_method)
+#endif
 #ifndef OPENSSL_NO_SSL2
     RESOLVEFUNC(SSLv2_server_method)
 #endif
     RESOLVEFUNC(SSLv3_server_method)
     RESOLVEFUNC(SSLv23_server_method)
     RESOLVEFUNC(TLSv1_server_method)
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+    RESOLVEFUNC(TLSv1_1_server_method)
+    RESOLVEFUNC(TLSv1_2_server_method)
+#endif
     RESOLVEFUNC(X509_NAME_entry_count)
     RESOLVEFUNC(X509_NAME_get_entry)
     RESOLVEFUNC(X509_NAME_ENTRY_get_data)
index 447afe0..6e2ec42 100644 (file)
@@ -338,19 +338,27 @@ const SSL_METHOD *q_SSLv2_client_method();
 const SSL_METHOD *q_SSLv3_client_method();
 const SSL_METHOD *q_SSLv23_client_method();
 const SSL_METHOD *q_TLSv1_client_method();
+const SSL_METHOD *q_TLSv1_1_client_method();
+const SSL_METHOD *q_TLSv1_2_client_method();
 const SSL_METHOD *q_SSLv2_server_method();
 const SSL_METHOD *q_SSLv3_server_method();
 const SSL_METHOD *q_SSLv23_server_method();
 const SSL_METHOD *q_TLSv1_server_method();
+const SSL_METHOD *q_TLSv1_1_server_method();
+const SSL_METHOD *q_TLSv1_2_server_method();
 #else
 SSL_METHOD *q_SSLv2_client_method();
 SSL_METHOD *q_SSLv3_client_method();
 SSL_METHOD *q_SSLv23_client_method();
 SSL_METHOD *q_TLSv1_client_method();
+SSL_METHOD *q_TLSv1_1_client_method();
+SSL_METHOD *q_TLSv1_2_client_method();
 SSL_METHOD *q_SSLv2_server_method();
 SSL_METHOD *q_SSLv3_server_method();
 SSL_METHOD *q_SSLv23_server_method();
 SSL_METHOD *q_TLSv1_server_method();
+SSL_METHOD *q_TLSv1_1_server_method();
+SSL_METHOD *q_TLSv1_2_server_method();
 #endif
 int q_SSL_write(SSL *a, const void *b, int c);
 int q_X509_cmp(X509 *a, X509 *b);
index 725dc2a..350d4c4 100644 (file)
@@ -808,7 +808,7 @@ void tst_QSslSocket::protocol()
 
     QCOMPARE(socket->protocol(), QSsl::SecureProtocols);
     {
-        // Fluke allows SSLv3.
+        // qt-test-server allows SSLv3.
         socket->setProtocol(QSsl::SslV3);
         QCOMPARE(socket->protocol(), QSsl::SslV3);
         socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
@@ -824,7 +824,7 @@ void tst_QSslSocket::protocol()
         socket->abort();
     }
     {
-        // Fluke allows TLSV1.
+        // qt-test-server allows TLSV1.
         socket->setProtocol(QSsl::TlsV1_0);
         QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
         socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
@@ -839,9 +839,43 @@ void tst_QSslSocket::protocol()
         QCOMPARE(socket->protocol(), QSsl::TlsV1_0);
         socket->abort();
     }
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+    {
+        // qt-test-server probably doesn't allow TLSV1.1
+        socket->setProtocol(QSsl::TlsV1_1);
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+        socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
+        QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString()));
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+        socket->abort();
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+        socket->connectToHost(QtNetworkSettings::serverName(), 443);
+        QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
+        socket->startClientEncryption();
+        QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString()));
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_1);
+        socket->abort();
+    }
+    {
+        // qt-test-server probably doesn't allows TLSV1.2
+        socket->setProtocol(QSsl::TlsV1_2);
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
+        socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
+        QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString()));
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
+        socket->abort();
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
+        socket->connectToHost(QtNetworkSettings::serverName(), 443);
+        QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString()));
+        socket->startClientEncryption();
+        QVERIFY2(socket->waitForEncrypted(), qPrintable(socket->errorString()));
+        QCOMPARE(socket->protocol(), QSsl::TlsV1_2);
+        socket->abort();
+    }
+#endif
 #ifndef OPENSSL_NO_SSL2
     {
-        // Fluke allows SSLV2.
+        // qt-test-server allows SSLV2.
         socket->setProtocol(QSsl::SslV2);
         QCOMPARE(socket->protocol(), QSsl::SslV2);
         socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
@@ -857,7 +891,7 @@ void tst_QSslSocket::protocol()
     }
 #endif
     {
-        // Fluke allows SSLV3, so it allows AnyProtocol.
+        // qt-test-server allows SSLV3, so it allows AnyProtocol.
         socket->setProtocol(QSsl::AnyProtocol);
         QCOMPARE(socket->protocol(), QSsl::AnyProtocol);
         socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
@@ -873,7 +907,7 @@ void tst_QSslSocket::protocol()
         socket->abort();
     }
     {
-        // Fluke allows SSLV3, so it allows NoSslV2
+        // qt-test-server allows SSLV3, so it allows NoSslV2
         socket->setProtocol(QSsl::TlsV1SslV3);
         QCOMPARE(socket->protocol(), QSsl::TlsV1SslV3);
         socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443);