summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Smith <git@kismith.co.uk>2014-08-27 14:16:15 (GMT)
committerKevin Smith <kevin.smith@isode.com>2015-06-10 20:29:05 (GMT)
commitb2093a372874aefb4f56f66a70a96f78d6cbbaec (patch)
treeab779a4cc7950339d2c2cb0261ae6a08df84c645
parentb6b0695643f932827add43b9de0e09ed74eb6799 (diff)
downloadswift-b2093a372874aefb4f56f66a70a96f78d6cbbaec.zip
swift-b2093a372874aefb4f56f66a70a96f78d6cbbaec.tar.bz2
Add ability to limit SChannel to TLS 1.0
Some servers have very restrictive TLS stacks that respond badly to a bug in the SChannel TLS implementation, meaning that TLS has to be limited to 1.0. Add ClientOptions.tlsOptions. This is a method of passing options into the TLS stack. It's currently only used for the TLS 1.0 workaround in SChannel, but we might reasonably expose other options in the future, such as limiting cypher suites. Disables use of SSLv3 for SChannel Also updates the coding style in SchannelContext a bit. Test-Information: Compiles on both OS X and Windows(SChannel). OS X doesn't show the new option. Windows shows it, and remembers it between logins. Not tested against a server requiring 1.0 only, but a previous hack with the same approach was tested. Change-Id: I1e7854d43811fd173f21f98d4dc3915fc7a4b322
-rw-r--r--Swift/Controllers/MainController.cpp8
-rw-r--r--Swift/QtUI/QtConnectionSettings.ui7
-rw-r--r--Swift/QtUI/QtConnectionSettingsWindow.cpp8
-rw-r--r--Swiften/Client/ClientOptions.h7
-rw-r--r--Swiften/Client/CoreClient.cpp5
-rw-r--r--Swiften/Component/CoreComponent.cpp14
-rw-r--r--Swiften/Network/BOSHConnectionPool.cpp8
-rw-r--r--Swiften/Network/BOSHConnectionPool.h6
-rw-r--r--Swiften/Network/TLSConnection.cpp4
-rw-r--r--Swiften/Network/TLSConnection.h4
-rw-r--r--Swiften/Network/TLSConnectionFactory.cpp4
-rw-r--r--Swiften/Network/TLSConnectionFactory.h4
-rw-r--r--Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp11
-rw-r--r--Swiften/Session/BOSHSessionStream.cpp7
-rw-r--r--Swiften/Session/BOSHSessionStream.h11
-rw-r--r--Swiften/Session/BasicSessionStream.cpp10
-rw-r--r--Swiften/Session/BasicSessionStream.h5
-rw-r--r--Swiften/StreamStack/TLSLayer.cpp4
-rw-r--r--Swiften/StreamStack/TLSLayer.h3
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp2
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContextFactory.h2
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp197
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.h31
-rw-r--r--Swiften/TLS/Schannel/SchannelContextFactory.cpp10
-rw-r--r--Swiften/TLS/Schannel/SchannelContextFactory.h10
-rw-r--r--Swiften/TLS/TLSContextFactory.h3
-rw-r--r--Swiften/TLS/TLSOptions.h25
27 files changed, 248 insertions, 162 deletions
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 328d837..c6b6dfc 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -398,7 +398,7 @@ void MainController::handleConnected() {
398 userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle()); 398 userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle());
399 userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle()); 399 userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle());
400 adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow()); 400 adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow());
401 401
402 chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1)); 402 chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1));
403 } 403 }
404 loginWindow_->setIsLoggingIn(false); 404 loginWindow_->setIsLoggingIn(false);
@@ -410,7 +410,7 @@ void MainController::handleConnected() {
410 discoInfoRequest->send(); 410 discoInfoRequest->send();
411 411
412 client_->getVCardManager()->requestOwnVCard(); 412 client_->getVCardManager()->requestOwnVCard();
413 413
414 rosterController_->setJID(boundJID_); 414 rosterController_->setJID(boundJID_);
415 rosterController_->setEnabled(true); 415 rosterController_->setEnabled(true);
416 rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted()); 416 rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted());
@@ -841,10 +841,11 @@ std::string MainController::serializeClientOptions(const ClientOptions& options)
841 SERIALIZE_URL(boshHTTPConnectProxyURL); 841 SERIALIZE_URL(boshHTTPConnectProxyURL);
842 SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthID); 842 SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthID);
843 SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthPassword); 843 SERIALIZE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
844 SERIALIZE_BOOL(tlsOptions.schannelTLS1_0Workaround);
844 return result; 845 return result;
845} 846}
846 847
847#define CHECK_PARSE_LENGTH if (i >= segments.size()) {return result;} 848#define CHECK_PARSE_LENGTH if (i >= segments.size()) {return result;}
848#define PARSE_INT_RAW(defaultValue) CHECK_PARSE_LENGTH intVal = defaultValue; try {intVal = boost::lexical_cast<int>(segments[i]);} catch(const boost::bad_lexical_cast&) {};i++; 849#define PARSE_INT_RAW(defaultValue) CHECK_PARSE_LENGTH intVal = defaultValue; try {intVal = boost::lexical_cast<int>(segments[i]);} catch(const boost::bad_lexical_cast&) {};i++;
849#define PARSE_STRING_RAW CHECK_PARSE_LENGTH stringVal = byteArrayToString(Base64::decode(segments[i]));i++; 850#define PARSE_STRING_RAW CHECK_PARSE_LENGTH stringVal = byteArrayToString(Base64::decode(segments[i]));i++;
850 851
@@ -888,6 +889,7 @@ ClientOptions MainController::parseClientOptions(const std::string& optionString
888 PARSE_URL(boshHTTPConnectProxyURL); 889 PARSE_URL(boshHTTPConnectProxyURL);
889 PARSE_SAFE_STRING(boshHTTPConnectProxyAuthID); 890 PARSE_SAFE_STRING(boshHTTPConnectProxyAuthID);
890 PARSE_SAFE_STRING(boshHTTPConnectProxyAuthPassword); 891 PARSE_SAFE_STRING(boshHTTPConnectProxyAuthPassword);
892 PARSE_BOOL(tlsOptions.schannelTLS1_0Workaround, false);
891 893
892 return result; 894 return result;
893} 895}
diff --git a/Swift/QtUI/QtConnectionSettings.ui b/Swift/QtUI/QtConnectionSettings.ui
index 2dc46d1..cce60fe 100644
--- a/Swift/QtUI/QtConnectionSettings.ui
+++ b/Swift/QtUI/QtConnectionSettings.ui
@@ -136,6 +136,13 @@
136 </widget> 136 </widget>
137 </item> 137 </item>
138 <item> 138 <item>
139 <widget class="QCheckBox" name="manual_forceTLS1_0">
140 <property name="text">
141 <string>Limit encryption to TLS 1.0</string>
142 </property>
143 </widget>
144 </item>
145 <item>
139 <spacer name="verticalSpacer_2"> 146 <spacer name="verticalSpacer_2">
140 <property name="orientation"> 147 <property name="orientation">
141 <enum>Qt::Vertical</enum> 148 <enum>Qt::Vertical</enum>
diff --git a/Swift/QtUI/QtConnectionSettingsWindow.cpp b/Swift/QtUI/QtConnectionSettingsWindow.cpp
index a3598fa..7b5003a 100644
--- a/Swift/QtUI/QtConnectionSettingsWindow.cpp
+++ b/Swift/QtUI/QtConnectionSettingsWindow.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2012 Isode Limited. 2 * Copyright (c) 2012-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -67,6 +67,7 @@ QtConnectionSettingsWindow::QtConnectionSettingsWindow(const ClientOptions& opti
67 isDefault &= options.proxyType == defaults.proxyType; 67 isDefault &= options.proxyType == defaults.proxyType;
68 isDefault &= options.manualProxyHostname == defaults.manualProxyHostname; 68 isDefault &= options.manualProxyHostname == defaults.manualProxyHostname;
69 isDefault &= options.manualProxyPort == defaults.manualProxyPort; 69 isDefault &= options.manualProxyPort == defaults.manualProxyPort;
70 isDefault &= options.tlsOptions.schannelTLS1_0Workaround == defaults.tlsOptions.schannelTLS1_0Workaround;
70 if (isDefault) { 71 if (isDefault) {
71 ui.connectionMethod->setCurrentIndex(0); 72 ui.connectionMethod->setCurrentIndex(0);
72 } 73 }
@@ -88,6 +89,7 @@ QtConnectionSettingsWindow::QtConnectionSettingsWindow(const ClientOptions& opti
88 ui.manual_manualProxyHost->setText(P2QSTRING(options.manualProxyHostname)); 89 ui.manual_manualProxyHost->setText(P2QSTRING(options.manualProxyHostname));
89 ui.manual_manualProxyPort->setText(P2QSTRING(boost::lexical_cast<std::string>(options.manualProxyPort))); 90 ui.manual_manualProxyPort->setText(P2QSTRING(boost::lexical_cast<std::string>(options.manualProxyPort)));
90 } 91 }
92 ui.manual_forceTLS1_0->setChecked(options.tlsOptions.schannelTLS1_0Workaround);
91 } 93 }
92 } else { 94 } else {
93 ui.connectionMethod->setCurrentIndex(2); 95 ui.connectionMethod->setCurrentIndex(2);
@@ -100,6 +102,9 @@ QtConnectionSettingsWindow::QtConnectionSettingsWindow(const ClientOptions& opti
100 } 102 }
101 } 103 }
102 } 104 }
105#ifndef HAVE_SCHANNEL
106 ui.manual_forceTLS1_0->hide();
107#endif
103} 108}
104 109
105void QtConnectionSettingsWindow::handleProxyTypeChanged(int index) { 110void QtConnectionSettingsWindow::handleProxyTypeChanged(int index) {
@@ -129,6 +134,7 @@ ClientOptions QtConnectionSettingsWindow::getOptions() {
129 options.useTLS = static_cast<ClientOptions::UseTLS>(ui.manual_useTLS->currentIndex()); 134 options.useTLS = static_cast<ClientOptions::UseTLS>(ui.manual_useTLS->currentIndex());
130 options.useStreamCompression = ui.manual_allowCompression->isChecked(); 135 options.useStreamCompression = ui.manual_allowCompression->isChecked();
131 options.allowPLAINWithoutTLS = ui.manual_allowPLAINWithoutTLS->isChecked(); 136 options.allowPLAINWithoutTLS = ui.manual_allowPLAINWithoutTLS->isChecked();
137 options.tlsOptions.schannelTLS1_0Workaround = ui.manual_forceTLS1_0->isChecked();
132 if (ui.manual_manualHost->isChecked()) { 138 if (ui.manual_manualHost->isChecked()) {
133 options.manualHostname = Q2PSTRING(ui.manual_manualHostName->text()); 139 options.manualHostname = Q2PSTRING(ui.manual_manualHostName->text());
134 try { 140 try {
diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h
index 4aac609..25393e4 100644
--- a/Swiften/Client/ClientOptions.h
+++ b/Swiften/Client/ClientOptions.h
@@ -11,6 +11,8 @@
11#include <Swiften/Base/API.h> 11#include <Swiften/Base/API.h>
12#include <Swiften/Base/URL.h> 12#include <Swiften/Base/URL.h>
13#include <Swiften/Base/SafeString.h> 13#include <Swiften/Base/SafeString.h>
14#include <Swiften/TLS/TLSOptions.h>
15
14 16
15namespace Swift { 17namespace Swift {
16 class HTTPTrafficFilter; 18 class HTTPTrafficFilter;
@@ -145,5 +147,10 @@ namespace Swift {
145 * proxy initialization to be customized. 147 * proxy initialization to be customized.
146 */ 148 */
147 boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter; 149 boost::shared_ptr<HTTPTrafficFilter> httpTrafficFilter;
150
151 /**
152 * Options passed to the TLS stack
153 */
154 TLSOptions tlsOptions;
148 }; 155 };
149} 156}
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 842488d..c91e5c5 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -138,7 +138,8 @@ void CoreClient::connect(const ClientOptions& o) {
138 host, 138 host,
139 options.boshHTTPConnectProxyURL, 139 options.boshHTTPConnectProxyURL,
140 options.boshHTTPConnectProxyAuthID, 140 options.boshHTTPConnectProxyAuthID,
141 options.boshHTTPConnectProxyAuthPassword)); 141 options.boshHTTPConnectProxyAuthPassword,
142 options.tlsOptions));
142 sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1)); 143 sessionStream_->onDataRead.connect(boost::bind(&CoreClient::handleDataRead, this, _1));
143 sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1)); 144 sessionStream_->onDataWritten.connect(boost::bind(&CoreClient::handleDataWritten, this, _1));
144 bindSessionToStream(); 145 bindSessionToStream();
@@ -189,7 +190,7 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio
189 connection_ = connection; 190 connection_ = connection;
190 191
191 assert(!sessionStream_); 192 assert(!sessionStream_);
192 sessionStream_ = boost::make_shared<BasicSessionStream>(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getTLSContextFactory(), networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory()); 193 sessionStream_ = boost::make_shared<BasicSessionStream>(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), networkFactories->getTLSContextFactory(), networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory(), options.tlsOptions);
193 if (certificate_ && !certificate_->isNull()) { 194 if (certificate_ && !certificate_->isNull()) {
194 sessionStream_->setTLSCertificate(certificate_); 195 sessionStream_->setTLSCertificate(certificate_);
195 } 196 }
diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp
index 23b7759..358b0c6 100644
--- a/Swiften/Component/CoreComponent.cpp
+++ b/Swiften/Component/CoreComponent.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2010-2013 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -9,14 +9,16 @@
9#include <boost/bind.hpp> 9#include <boost/bind.hpp>
10#include <iostream> 10#include <iostream>
11 11
12#include <Swiften/Base/IDGenerator.h>
12#include <Swiften/Component/ComponentSession.h> 13#include <Swiften/Component/ComponentSession.h>
14#include <Swiften/Component/ComponentSessionStanzaChannel.h>
13#include <Swiften/Network/Connector.h> 15#include <Swiften/Network/Connector.h>
14#include <Swiften/Network/NetworkFactories.h> 16#include <Swiften/Network/NetworkFactories.h>
15#include <Swiften/TLS/PKCS12Certificate.h>
16#include <Swiften/Session/BasicSessionStream.h>
17#include <Swiften/Queries/IQRouter.h> 17#include <Swiften/Queries/IQRouter.h>
18#include <Swiften/Base/IDGenerator.h> 18#include <Swiften/Session/BasicSessionStream.h>
19#include <Swiften/Component/ComponentSessionStanzaChannel.h> 19#include <Swiften/TLS/PKCS12Certificate.h>
20#include <Swiften/TLS/TLSOptions.h>
21
20 22
21namespace Swift { 23namespace Swift {
22 24
@@ -63,7 +65,7 @@ void CoreComponent::handleConnectorFinished(boost::shared_ptr<Connection> connec
63 connection_ = connection; 65 connection_ = connection;
64 66
65 assert(!sessionStream_); 67 assert(!sessionStream_);
66 sessionStream_ = boost::shared_ptr<BasicSessionStream>(new BasicSessionStream(ComponentStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), NULL, networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory())); 68 sessionStream_ = boost::shared_ptr<BasicSessionStream>(new BasicSessionStream(ComponentStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), NULL, networkFactories->getTimerFactory(), networkFactories->getXMLParserFactory(), TLSOptions()));
67 sessionStream_->onDataRead.connect(boost::bind(&CoreComponent::handleDataRead, this, _1)); 69 sessionStream_->onDataRead.connect(boost::bind(&CoreComponent::handleDataRead, this, _1));
68 sessionStream_->onDataWritten.connect(boost::bind(&CoreComponent::handleDataWritten, this, _1)); 70 sessionStream_->onDataWritten.connect(boost::bind(&CoreComponent::handleDataWritten, this, _1));
69 71
diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp
index 56f7d12..c037b34 100644
--- a/Swiften/Network/BOSHConnectionPool.cpp
+++ b/Swiften/Network/BOSHConnectionPool.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2011 Isode Limited. 2 * Copyright (c) 2011-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -17,7 +17,7 @@
17#include <Swiften/Network/CachingDomainNameResolver.h> 17#include <Swiften/Network/CachingDomainNameResolver.h>
18 18
19namespace Swift { 19namespace Swift {
20BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* realResolver, ConnectionFactory* connectionFactoryParameter, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword) : 20BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* realResolver, ConnectionFactory* connectionFactoryParameter, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions) :
21 boshURL(boshURL), 21 boshURL(boshURL),
22 connectionFactory(connectionFactoryParameter), 22 connectionFactory(connectionFactoryParameter),
23 xmlParserFactory(parserFactory), 23 xmlParserFactory(parserFactory),
@@ -31,13 +31,13 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r
31 31
32 if (!boshHTTPConnectProxyURL.isEmpty()) { 32 if (!boshHTTPConnectProxyURL.isEmpty()) {
33 if (boshHTTPConnectProxyURL.getScheme() == "https") { 33 if (boshHTTPConnectProxyURL.getScheme() == "https") {
34 connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); 34 connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions);
35 myConnectionFactories.push_back(connectionFactory); 35 myConnectionFactories.push_back(connectionFactory);
36 } 36 }
37 connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); 37 connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword);
38 } 38 }
39 if (boshURL.getScheme() == "https") { 39 if (boshURL.getScheme() == "https") {
40 connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory); 40 connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions);
41 myConnectionFactories.push_back(connectionFactory); 41 myConnectionFactories.push_back(connectionFactory);
42 } 42 }
43 resolver = new CachingDomainNameResolver(realResolver, eventLoop); 43 resolver = new CachingDomainNameResolver(realResolver, eventLoop);
diff --git a/Swiften/Network/BOSHConnectionPool.h b/Swiften/Network/BOSHConnectionPool.h
index 570ba4b..d845a3d 100644
--- a/Swiften/Network/BOSHConnectionPool.h
+++ b/Swiften/Network/BOSHConnectionPool.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2011 Isode Limited. 2 * Copyright (c) 2011-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -12,6 +12,8 @@
12#include <Swiften/Base/API.h> 12#include <Swiften/Base/API.h>
13#include <Swiften/Base/SafeString.h> 13#include <Swiften/Base/SafeString.h>
14#include <Swiften/Network/BOSHConnection.h> 14#include <Swiften/Network/BOSHConnection.h>
15#include <Swiften/TLS/TLSOptions.h>
16
15 17
16namespace Swift { 18namespace Swift {
17 class HTTPConnectProxiedConnectionFactory; 19 class HTTPConnectProxiedConnectionFactory;
@@ -21,7 +23,7 @@ namespace Swift {
21 23
22 class SWIFTEN_API BOSHConnectionPool : public boost::bsignals::trackable { 24 class SWIFTEN_API BOSHConnectionPool : public boost::bsignals::trackable {
23 public: 25 public:
24 BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword); 26 BOSHConnectionPool(const URL& boshURL, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, XMLParserFactory* parserFactory, TLSContextFactory* tlsFactory, TimerFactory* timerFactory, EventLoop* eventLoop, const std::string& to, unsigned long long initialRID, const URL& boshHTTPConnectProxyURL, const SafeString& boshHTTPConnectProxyAuthID, const SafeString& boshHTTPConnectProxyAuthPassword, const TLSOptions& tlsOptions);
25 ~BOSHConnectionPool(); 27 ~BOSHConnectionPool();
26 void write(const SafeByteArray& data); 28 void write(const SafeByteArray& data);
27 void writeFooter(); 29 void writeFooter();
diff --git a/Swiften/Network/TLSConnection.cpp b/Swiften/Network/TLSConnection.cpp
index f0b6fa4..149548a 100644
--- a/Swiften/Network/TLSConnection.cpp
+++ b/Swiften/Network/TLSConnection.cpp
@@ -14,8 +14,8 @@
14 14
15namespace Swift { 15namespace Swift {
16 16
17TLSConnection::TLSConnection(Connection::ref connection, TLSContextFactory* tlsFactory) : connection(connection) { 17TLSConnection::TLSConnection(Connection::ref connection, TLSContextFactory* tlsFactory, const TLSOptions& tlsOptions) : connection(connection) {
18 context = tlsFactory->createTLSContext(); 18 context = tlsFactory->createTLSContext(tlsOptions);
19 context->onDataForNetwork.connect(boost::bind(&TLSConnection::handleTLSDataForNetwork, this, _1)); 19 context->onDataForNetwork.connect(boost::bind(&TLSConnection::handleTLSDataForNetwork, this, _1));
20 context->onDataForApplication.connect(boost::bind(&TLSConnection::handleTLSDataForApplication, this, _1)); 20 context->onDataForApplication.connect(boost::bind(&TLSConnection::handleTLSDataForApplication, this, _1));
21 context->onConnected.connect(boost::bind(&TLSConnection::handleTLSConnectFinished, this, false)); 21 context->onConnected.connect(boost::bind(&TLSConnection::handleTLSConnectFinished, this, false));
diff --git a/Swiften/Network/TLSConnection.h b/Swiften/Network/TLSConnection.h
index ebf2e43..96525ad 100644
--- a/Swiften/Network/TLSConnection.h
+++ b/Swiften/Network/TLSConnection.h
@@ -13,6 +13,8 @@
13#include <Swiften/Base/API.h> 13#include <Swiften/Base/API.h>
14#include <Swiften/Base/SafeByteArray.h> 14#include <Swiften/Base/SafeByteArray.h>
15#include <Swiften/Network/Connection.h> 15#include <Swiften/Network/Connection.h>
16#include <Swiften/TLS/TLSOptions.h>
17
16 18
17namespace Swift { 19namespace Swift {
18 class HostAddressPort; 20 class HostAddressPort;
@@ -22,7 +24,7 @@ namespace Swift {
22 class SWIFTEN_API TLSConnection : public Connection { 24 class SWIFTEN_API TLSConnection : public Connection {
23 public: 25 public:
24 26
25 TLSConnection(Connection::ref connection, TLSContextFactory* tlsFactory); 27 TLSConnection(Connection::ref connection, TLSContextFactory* tlsFactory, const TLSOptions&);
26 virtual ~TLSConnection(); 28 virtual ~TLSConnection();
27 29
28 virtual void listen() {assert(false);} 30 virtual void listen() {assert(false);}
diff --git a/Swiften/Network/TLSConnectionFactory.cpp b/Swiften/Network/TLSConnectionFactory.cpp
index ac0ab8e..cc20b2d 100644
--- a/Swiften/Network/TLSConnectionFactory.cpp
+++ b/Swiften/Network/TLSConnectionFactory.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Swift { 13namespace Swift {
14 14
15TLSConnectionFactory::TLSConnectionFactory(TLSContextFactory* contextFactory, ConnectionFactory* connectionFactory) : contextFactory(contextFactory), connectionFactory(connectionFactory){ 15TLSConnectionFactory::TLSConnectionFactory(TLSContextFactory* contextFactory, ConnectionFactory* connectionFactory, const TLSOptions& o) : contextFactory(contextFactory), connectionFactory(connectionFactory), options_(o) {
16 16
17} 17}
18 18
@@ -22,7 +22,7 @@ TLSConnectionFactory::~TLSConnectionFactory() {
22 22
23 23
24boost::shared_ptr<Connection> TLSConnectionFactory::createConnection() { 24boost::shared_ptr<Connection> TLSConnectionFactory::createConnection() {
25 return boost::make_shared<TLSConnection>(connectionFactory->createConnection(), contextFactory); 25 return boost::make_shared<TLSConnection>(connectionFactory->createConnection(), contextFactory, options_);
26} 26}
27 27
28} 28}
diff --git a/Swiften/Network/TLSConnectionFactory.h b/Swiften/Network/TLSConnectionFactory.h
index 3dfee06..0c67014 100644
--- a/Swiften/Network/TLSConnectionFactory.h
+++ b/Swiften/Network/TLSConnectionFactory.h
@@ -11,18 +11,20 @@
11#include <Swiften/Base/API.h> 11#include <Swiften/Base/API.h>
12#include <Swiften/Network/ConnectionFactory.h> 12#include <Swiften/Network/ConnectionFactory.h>
13#include <Swiften/TLS/TLSContextFactory.h> 13#include <Swiften/TLS/TLSContextFactory.h>
14#include <Swiften/TLS/TLSOptions.h>
14 15
15namespace Swift { 16namespace Swift {
16 class Connection; 17 class Connection;
17 18
18 class SWIFTEN_API TLSConnectionFactory : public ConnectionFactory { 19 class SWIFTEN_API TLSConnectionFactory : public ConnectionFactory {
19 public: 20 public:
20 TLSConnectionFactory(TLSContextFactory* contextFactory, ConnectionFactory* connectionFactory); 21 TLSConnectionFactory(TLSContextFactory* contextFactory, ConnectionFactory* connectionFactory, const TLSOptions&);
21 virtual ~TLSConnectionFactory(); 22 virtual ~TLSConnectionFactory();
22 23
23 virtual boost::shared_ptr<Connection> createConnection(); 24 virtual boost::shared_ptr<Connection> createConnection();
24 private: 25 private:
25 TLSContextFactory* contextFactory; 26 TLSContextFactory* contextFactory;
26 ConnectionFactory* connectionFactory; 27 ConnectionFactory* connectionFactory;
28 TLSOptions options_;
27 }; 29 };
28} 30}
diff --git a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp
index e5ac121..e687517 100644
--- a/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp
+++ b/Swiften/Network/UnitTest/BOSHConnectionPoolTest.cpp
@@ -16,15 +16,16 @@
16#include <boost/lexical_cast.hpp> 16#include <boost/lexical_cast.hpp>
17 17
18#include <Swiften/Base/Algorithm.h> 18#include <Swiften/Base/Algorithm.h>
19#include <Swiften/Network/Connection.h> 19#include <Swiften/EventLoop/DummyEventLoop.h>
20#include <Swiften/Network/ConnectionFactory.h>
21#include <Swiften/Network/BOSHConnection.h> 20#include <Swiften/Network/BOSHConnection.h>
22#include <Swiften/Network/BOSHConnectionPool.h> 21#include <Swiften/Network/BOSHConnectionPool.h>
22#include <Swiften/Network/Connection.h>
23#include <Swiften/Network/ConnectionFactory.h>
24#include <Swiften/Network/DummyTimerFactory.h>
23#include <Swiften/Network/HostAddressPort.h> 25#include <Swiften/Network/HostAddressPort.h>
24#include <Swiften/Network/StaticDomainNameResolver.h> 26#include <Swiften/Network/StaticDomainNameResolver.h>
25#include <Swiften/Network/DummyTimerFactory.h>
26#include <Swiften/EventLoop/DummyEventLoop.h>
27#include <Swiften/Parser/PlatformXMLParserFactory.h> 27#include <Swiften/Parser/PlatformXMLParserFactory.h>
28#include <Swiften/TLS/TLSOptions.h>
28 29
29 30
30 31
@@ -322,7 +323,7 @@ class BOSHConnectionPoolTest : public CppUnit::TestFixture {
322 private: 323 private:
323 324
324 PoolRef createTestling() { 325 PoolRef createTestling() {
325 BOSHConnectionPool* a = new BOSHConnectionPool(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); 326 BOSHConnectionPool* a = new BOSHConnectionPool(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString(""), TLSOptions());
326 PoolRef pool(a); 327 PoolRef pool(a);
327 //FIXME: Remko - why does the above work, but the below fail? 328 //FIXME: Remko - why does the above work, but the below fail?
328 //PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString("")); 329 //PoolRef pool = boost::make_shared<BOSHConnectionPool>(boshURL, resolver, connectionFactory, &parserFactory, static_cast<TLSContextFactory*>(NULL), timerFactory, eventLoop, to, initialRID, URL(), SafeString(""), SafeString(""));
diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp
index eac493e..62942b9 100644
--- a/Swiften/Session/BOSHSessionStream.cpp
+++ b/Swiften/Session/BOSHSessionStream.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2011-2014 Isode Limited. 2 * Copyright (c) 2011-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -39,7 +39,8 @@ BOSHSessionStream::BOSHSessionStream(
39 const std::string& to, 39 const std::string& to,
40 const URL& boshHTTPConnectProxyURL, 40 const URL& boshHTTPConnectProxyURL,
41 const SafeString& boshHTTPConnectProxyAuthID, 41 const SafeString& boshHTTPConnectProxyAuthID,
42 const SafeString& boshHTTPConnectProxyAuthPassword) : 42 const SafeString& boshHTTPConnectProxyAuthPassword,
43 const TLSOptions& tlsOptions) :
43 available(false), 44 available(false),
44 eventLoop(eventLoop), 45 eventLoop(eventLoop),
45 firstHeader(true) { 46 firstHeader(true) {
@@ -49,7 +50,7 @@ BOSHSessionStream::BOSHSessionStream(
49 random.seed(static_cast<unsigned int>(time(NULL))); 50 random.seed(static_cast<unsigned int>(time(NULL)));
50 unsigned long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long long> >(random, dist)(); 51 unsigned long long initialRID = boost::variate_generator<boost::mt19937&, boost::uniform_int<unsigned long long> >(random, dist)();
51 52
52 connectionPool = new BOSHConnectionPool(boshURL, resolver, connectionFactory, xmlParserFactory, tlsContextFactory, timerFactory, eventLoop, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword); 53 connectionPool = new BOSHConnectionPool(boshURL, resolver, connectionFactory, xmlParserFactory, tlsContextFactory, timerFactory, eventLoop, to, initialRID, boshHTTPConnectProxyURL, boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword, tlsOptions);
53 connectionPool->onSessionTerminated.connect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1)); 54 connectionPool->onSessionTerminated.connect(boost::bind(&BOSHSessionStream::handlePoolSessionTerminated, this, _1));
54 connectionPool->onSessionStarted.connect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this)); 55 connectionPool->onSessionStarted.connect(boost::bind(&BOSHSessionStream::handlePoolSessionStarted, this));
55 connectionPool->onXMPPDataRead.connect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1)); 56 connectionPool->onXMPPDataRead.connect(boost::bind(&BOSHSessionStream::handlePoolXMPPDataRead, this, _1));
diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h
index e97436c..436b941 100644
--- a/Swiften/Session/BOSHSessionStream.h
+++ b/Swiften/Session/BOSHSessionStream.h
@@ -9,12 +9,14 @@
9#include <boost/shared_ptr.hpp> 9#include <boost/shared_ptr.hpp>
10 10
11#include <Swiften/Base/API.h> 11#include <Swiften/Base/API.h>
12#include <Swiften/Base/SafeString.h>
13#include <Swiften/Base/SafeByteArray.h> 12#include <Swiften/Base/SafeByteArray.h>
14#include <Swiften/Network/BOSHConnectionPool.h> 13#include <Swiften/Base/SafeString.h>
15#include <Swiften/Session/SessionStream.h>
16#include <Swiften/Elements/StreamType.h> 14#include <Swiften/Elements/StreamType.h>
17#include <Swiften/EventLoop/EventOwner.h> 15#include <Swiften/EventLoop/EventOwner.h>
16#include <Swiften/Network/BOSHConnectionPool.h>
17#include <Swiften/Session/SessionStream.h>
18#include <Swiften/TLS/TLSOptions.h>
19
18 20
19namespace Swift { 21namespace Swift {
20 class TimerFactory; 22 class TimerFactory;
@@ -43,7 +45,8 @@ namespace Swift {
43 const std::string& to, 45 const std::string& to,
44 const URL& boshHTTPConnectProxyURL, 46 const URL& boshHTTPConnectProxyURL,
45 const SafeString& boshHTTPConnectProxyAuthID, 47 const SafeString& boshHTTPConnectProxyAuthID,
46 const SafeString& boshHTTPConnectProxyAuthPassword 48 const SafeString& boshHTTPConnectProxyAuthPassword,
49 const TLSOptions& tlsOptions
47 ); 50 );
48 ~BOSHSessionStream(); 51 ~BOSHSessionStream();
49 52
diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp
index 274d218..43f1c48 100644
--- a/Swiften/Session/BasicSessionStream.cpp
+++ b/Swiften/Session/BasicSessionStream.cpp
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2010-2014 Isode Limited. 2 * Copyright (c) 2010-2015 Isode Limited.
3 * All rights reserved. 3 * All rights reserved.
4 * See the COPYING file for more information. 4 * See the COPYING file for more information.
5 */ 5 */
@@ -27,14 +27,16 @@ BasicSessionStream::BasicSessionStream(
27 PayloadSerializerCollection* payloadSerializers, 27 PayloadSerializerCollection* payloadSerializers,
28 TLSContextFactory* tlsContextFactory, 28 TLSContextFactory* tlsContextFactory,
29 TimerFactory* timerFactory, 29 TimerFactory* timerFactory,
30 XMLParserFactory* xmlParserFactory) : 30 XMLParserFactory* xmlParserFactory,
31 const TLSOptions& tlsOptions) :
31 available(false), 32 available(false),
32 connection(connection), 33 connection(connection),
33 tlsContextFactory(tlsContextFactory), 34 tlsContextFactory(tlsContextFactory),
34 timerFactory(timerFactory), 35 timerFactory(timerFactory),
35 compressionLayer(NULL), 36 compressionLayer(NULL),
36 tlsLayer(NULL), 37 tlsLayer(NULL),
37 whitespacePingLayer(NULL) { 38 whitespacePingLayer(NULL),
39 tlsOptions_(tlsOptions) {
38 xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, streamType); 40 xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, xmlParserFactory, streamType);
39 xmppLayer->onStreamStart.connect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1)); 41 xmppLayer->onStreamStart.connect(boost::bind(&BasicSessionStream::handleStreamStartReceived, this, _1));
40 xmppLayer->onElement.connect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1)); 42 xmppLayer->onElement.connect(boost::bind(&BasicSessionStream::handleElementReceived, this, _1));
@@ -106,7 +108,7 @@ bool BasicSessionStream::supportsTLSEncryption() {
106 108
107void BasicSessionStream::addTLSEncryption() { 109void BasicSessionStream::addTLSEncryption() {
108 assert(available); 110 assert(available);
109 tlsLayer = new TLSLayer(tlsContextFactory); 111 tlsLayer = new TLSLayer(tlsContextFactory, tlsOptions_);
110 if (hasTLSCertificate() && !tlsLayer->setClientCertificate(getTLSCertificate())) { 112 if (hasTLSCertificate() && !tlsLayer->setClientCertificate(getTLSCertificate())) {
111 onClosed(boost::make_shared<SessionStreamError>(SessionStreamError::InvalidTLSCertificateError)); 113 onClosed(boost::make_shared<SessionStreamError>(SessionStreamError::InvalidTLSCertificateError));
112 } 114 }
diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h
index 7832e42..811374a 100644
--- a/Swiften/Session/BasicSessionStream.h
+++ b/Swiften/Session/BasicSessionStream.h
@@ -14,6 +14,7 @@
14#include <Swiften/Session/SessionStream.h> 14#include <Swiften/Session/SessionStream.h>
15#include <Swiften/Elements/StreamType.h> 15#include <Swiften/Elements/StreamType.h>
16#include <Swiften/TLS/TLSError.h> 16#include <Swiften/TLS/TLSError.h>
17#include <Swiften/TLS/TLSOptions.h>
17 18
18namespace Swift { 19namespace Swift {
19 class TLSContextFactory; 20 class TLSContextFactory;
@@ -37,7 +38,8 @@ namespace Swift {
37 PayloadSerializerCollection* payloadSerializers, 38 PayloadSerializerCollection* payloadSerializers,
38 TLSContextFactory* tlsContextFactory, 39 TLSContextFactory* tlsContextFactory,
39 TimerFactory* whitespacePingLayerFactory, 40 TimerFactory* whitespacePingLayerFactory,
40 XMLParserFactory* xmlParserFactory 41 XMLParserFactory* xmlParserFactory,
42 const TLSOptions& tlsOptions
41 ); 43 );
42 ~BasicSessionStream(); 44 ~BasicSessionStream();
43 45
@@ -86,6 +88,7 @@ namespace Swift {
86 TLSLayer* tlsLayer; 88 TLSLayer* tlsLayer;
87 WhitespacePingLayer* whitespacePingLayer; 89 WhitespacePingLayer* whitespacePingLayer;
88 StreamStack* streamStack; 90 StreamStack* streamStack;
91 TLSOptions tlsOptions_;
89 }; 92 };
90 93
91} 94}
diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp
index aebf4a2..15c4101 100644
--- a/Swiften/StreamStack/TLSLayer.cpp
+++ b/Swiften/StreamStack/TLSLayer.cpp
@@ -13,8 +13,8 @@
13 13
14namespace Swift { 14namespace Swift {
15 15
16TLSLayer::TLSLayer(TLSContextFactory* factory) { 16TLSLayer::TLSLayer(TLSContextFactory* factory, const TLSOptions& tlsOptions) {
17 context = factory->createTLSContext(); 17 context = factory->createTLSContext(tlsOptions);
18 context->onDataForNetwork.connect(boost::bind(&TLSLayer::writeDataToChildLayer, this, _1)); 18 context->onDataForNetwork.connect(boost::bind(&TLSLayer::writeDataToChildLayer, this, _1));
19 context->onDataForApplication.connect(boost::bind(&TLSLayer::writeDataToParentLayer, this, _1)); 19 context->onDataForApplication.connect(boost::bind(&TLSLayer::writeDataToParentLayer, this, _1));
20 context->onConnected.connect(onConnected); 20 context->onConnected.connect(onConnected);
diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h
index 089512d..87d69a9 100644
--- a/Swiften/StreamStack/TLSLayer.h
+++ b/Swiften/StreamStack/TLSLayer.h
@@ -15,6 +15,7 @@
15#include <Swiften/TLS/CertificateWithKey.h> 15#include <Swiften/TLS/CertificateWithKey.h>
16#include <Swiften/TLS/CertificateVerificationError.h> 16#include <Swiften/TLS/CertificateVerificationError.h>
17#include <Swiften/TLS/TLSError.h> 17#include <Swiften/TLS/TLSError.h>
18#include <Swiften/TLS/TLSOptions.h>
18 19
19namespace Swift { 20namespace Swift {
20 class TLSContext; 21 class TLSContext;
@@ -22,7 +23,7 @@ namespace Swift {
22 23
23 class SWIFTEN_API TLSLayer : public StreamLayer { 24 class SWIFTEN_API TLSLayer : public StreamLayer {
24 public: 25 public:
25 TLSLayer(TLSContextFactory*); 26 TLSLayer(TLSContextFactory*, const TLSOptions&);
26 ~TLSLayer(); 27 ~TLSLayer();
27 28
28 void connect(); 29 void connect();
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
index 5fbc913..50f6731 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp
@@ -14,7 +14,7 @@ bool OpenSSLContextFactory::canCreate() const {
14 return true; 14 return true;
15} 15}
16 16
17TLSContext* OpenSSLContextFactory::createTLSContext() { 17TLSContext* OpenSSLContextFactory::createTLSContext(const TLSOptions&) {
18 return new OpenSSLContext(); 18 return new OpenSSLContext();
19} 19}
20 20
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
index 8e689b5..bf7f08a 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h
@@ -14,7 +14,7 @@ namespace Swift {
14 class OpenSSLContextFactory : public TLSContextFactory { 14 class OpenSSLContextFactory : public TLSContextFactory {
15 public: 15 public:
16 bool canCreate() const; 16 bool canCreate() const;
17 virtual TLSContext* createTLSContext(); 17 virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions);
18 18
19 // Not supported 19 // Not supported
20 virtual void setCheckCertificateRevocation(bool b); 20 virtual void setCheckCertificateRevocation(bool b);
diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp
index 86b8c18..5f230ec 100644
--- a/Swiften/TLS/Schannel/SchannelContext.cpp
+++ b/Swiften/TLS/Schannel/SchannelContext.cpp
@@ -5,7 +5,7 @@
5 */ 5 */
6 6
7/* 7/*
8 * Copyright (c) 2012 Isode Limited. 8 * Copyright (c) 2012-2015 Isode Limited.
9 * All rights reserved. 9 * All rights reserved.
10 * See the COPYING file for more information. 10 * See the COPYING file for more information.
11 */ 11 */
@@ -21,8 +21,8 @@ namespace Swift {
21 21
22//------------------------------------------------------------------------ 22//------------------------------------------------------------------------
23 23
24SchannelContext::SchannelContext() : m_state(Start), m_secContext(0), m_my_cert_store(NULL), m_cert_store_name("MY"), m_cert_name(), m_smartcard_reader(), checkCertificateRevocation(true) { 24SchannelContext::SchannelContext(bool tls1_0Workaround) : state_(Start), secContext_(0), myCertStore_(NULL), certStoreName_("MY"), certName_(), smartCardReader_(), checkCertificateRevocation_(true), tls1_0Workaround_(tls1_0Workaround) {
25 m_ctxtFlags = ISC_REQ_ALLOCATE_MEMORY | 25 contextFlags_ = ISC_REQ_ALLOCATE_MEMORY |
26 ISC_REQ_CONFIDENTIALITY | 26 ISC_REQ_CONFIDENTIALITY |
27 ISC_REQ_EXTENDED_ERROR | 27 ISC_REQ_EXTENDED_ERROR |
28 ISC_REQ_INTEGRITY | 28 ISC_REQ_INTEGRITY |
@@ -31,19 +31,19 @@ SchannelContext::SchannelContext() : m_state(Start), m_secContext(0), m_my_cert_
31 ISC_REQ_USE_SUPPLIED_CREDS | 31 ISC_REQ_USE_SUPPLIED_CREDS |
32 ISC_REQ_STREAM; 32 ISC_REQ_STREAM;
33 33
34 ZeroMemory(&m_streamSizes, sizeof(m_streamSizes)); 34 ZeroMemory(&streamSizes_, sizeof(streamSizes_));
35} 35}
36 36
37//------------------------------------------------------------------------ 37//------------------------------------------------------------------------
38 38
39SchannelContext::~SchannelContext() { 39SchannelContext::~SchannelContext() {
40 if (m_my_cert_store) CertCloseStore(m_my_cert_store, 0); 40 if (myCertStore_) CertCloseStore(myCertStore_, 0);
41} 41}
42 42
43//------------------------------------------------------------------------ 43//------------------------------------------------------------------------
44 44
45void SchannelContext::determineStreamSizes() { 45void SchannelContext::determineStreamSizes() {
46 QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_STREAM_SIZES, &m_streamSizes); 46 QueryContextAttributes(contextHandle_, SECPKG_ATTR_STREAM_SIZES, &streamSizes_);
47} 47}
48 48
49//------------------------------------------------------------------------ 49//------------------------------------------------------------------------
@@ -51,20 +51,20 @@ void SchannelContext::determineStreamSizes() {
51void SchannelContext::connect() { 51void SchannelContext::connect() {
52 ScopedCertContext pCertContext; 52 ScopedCertContext pCertContext;
53 53
54 m_state = Connecting; 54 state_ = Connecting;
55 55
56 // If a user name is specified, then attempt to find a client 56 // If a user name is specified, then attempt to find a client
57 // certificate. Otherwise, just create a NULL credential. 57 // certificate. Otherwise, just create a NULL credential.
58 if (!m_cert_name.empty()) { 58 if (!certName_.empty()) {
59 if (m_my_cert_store == NULL) { 59 if (myCertStore_ == NULL) {
60 m_my_cert_store = CertOpenSystemStore(0, m_cert_store_name.c_str()); 60 myCertStore_ = CertOpenSystemStore(0, certStoreName_.c_str());
61 if (!m_my_cert_store) { 61 if (!myCertStore_) {
62 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 62 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
63 return; 63 return;
64 } 64 }
65 } 65 }
66 66
67 pCertContext = findCertificateInStore( m_my_cert_store, m_cert_name ); 67 pCertContext = findCertificateInStore( myCertStore_, certName_ );
68 if (pCertContext == NULL) { 68 if (pCertContext == NULL) {
69 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 69 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
70 return; 70 return;
@@ -77,8 +77,13 @@ void SchannelContext::connect() {
77 SCHANNEL_CRED sc = {0}; 77 SCHANNEL_CRED sc = {0};
78 sc.dwVersion = SCHANNEL_CRED_VERSION; 78 sc.dwVersion = SCHANNEL_CRED_VERSION;
79 79
80/////SSL3? 80 if (tls1_0Workaround_) {
81 sc.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; 81 sc.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
82 }
83 else {
84 sc.grbitEnabledProtocols = /*SP_PROT_SSL3_CLIENT | */SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
85 }
86
82 sc.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION; 87 sc.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
83 88
84 if (pCertContext) { 89 if (pCertContext) {
@@ -103,9 +108,9 @@ void SchannelContext::connect() {
103 &sc, 108 &sc,
104 NULL, 109 NULL,
105 NULL, 110 NULL,
106 m_credHandle.Reset(), 111 credHandle_.Reset(),
107 NULL); 112 NULL);
108 113
109 if (status != SEC_E_OK) { 114 if (status != SEC_E_OK) {
110 // We failed to obtain the credentials handle 115 // We failed to obtain the credentials handle
111 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 116 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
@@ -135,17 +140,17 @@ void SchannelContext::connect() {
135 140
136 // Create the initial security context 141 // Create the initial security context
137 status = InitializeSecurityContext( 142 status = InitializeSecurityContext(
138 m_credHandle, 143 credHandle_,
139 NULL, 144 NULL,
140 NULL, 145 NULL,
141 m_ctxtFlags, 146 contextFlags_,
142 0, 147 0,
143 0, 148 0,
144 NULL, 149 NULL,
145 0, 150 0,
146 m_ctxtHandle.Reset(), 151 contextHandle_.Reset(),
147 &outBufferDesc, 152 &outBufferDesc,
148 &m_secContext, 153 &secContext_,
149 NULL); 154 NULL);
150 155
151 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { 156 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
@@ -164,7 +169,7 @@ void SchannelContext::connect() {
164 handleCertError(status); 169 handleCertError(status);
165 } 170 }
166 171
167 m_state = Connected; 172 state_ = Connected;
168 determineStreamSizes(); 173 determineStreamSizes();
169 174
170 onConnected(); 175 onConnected();
@@ -179,7 +184,7 @@ SECURITY_STATUS SchannelContext::validateServerCertificate() {
179 return SEC_E_WRONG_PRINCIPAL; 184 return SEC_E_WRONG_PRINCIPAL;
180 } 185 }
181 186
182 const LPSTR usage[] = 187 const LPSTR usage[] =
183 { 188 {
184 szOID_PKIX_KP_SERVER_AUTH, 189 szOID_PKIX_KP_SERVER_AUTH,
185 szOID_SERVER_GATED_CRYPTO, 190 szOID_SERVER_GATED_CRYPTO,
@@ -193,7 +198,7 @@ SECURITY_STATUS SchannelContext::validateServerCertificate() {
193 chainParams.RequestedUsage.Usage.rgpszUsageIdentifier = const_cast<LPSTR*>(usage); 198 chainParams.RequestedUsage.Usage.rgpszUsageIdentifier = const_cast<LPSTR*>(usage);
194 199
195 DWORD chainFlags = CERT_CHAIN_CACHE_END_CERT; 200 DWORD chainFlags = CERT_CHAIN_CACHE_END_CERT;
196 if (checkCertificateRevocation) { 201 if (checkCertificateRevocation_) {
197 chainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; 202 chainFlags |= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
198 } 203 }
199 204
@@ -246,9 +251,9 @@ SECURITY_STATUS SchannelContext::validateServerCertificate() {
246//------------------------------------------------------------------------ 251//------------------------------------------------------------------------
247 252
248void SchannelContext::appendNewData(const SafeByteArray& data) { 253void SchannelContext::appendNewData(const SafeByteArray& data) {
249 size_t originalSize = m_receivedData.size(); 254 size_t originalSize = receivedData_.size();
250 m_receivedData.resize(originalSize + data.size()); 255 receivedData_.resize(originalSize + data.size());
251 memcpy(&m_receivedData[0] + originalSize, &data[0], data.size()); 256 memcpy(&receivedData_[0] + originalSize, &data[0], data.size());
252} 257}
253 258
254//------------------------------------------------------------------------ 259//------------------------------------------------------------------------
@@ -256,12 +261,12 @@ void SchannelContext::appendNewData(const SafeByteArray& data) {
256void SchannelContext::continueHandshake(const SafeByteArray& data) { 261void SchannelContext::continueHandshake(const SafeByteArray& data) {
257 appendNewData(data); 262 appendNewData(data);
258 263
259 while (!m_receivedData.empty()) { 264 while (!receivedData_.empty()) {
260 SecBuffer inBuffers[2]; 265 SecBuffer inBuffers[2];
261 266
262 // Provide Schannel with the remote host's handshake data 267 // Provide Schannel with the remote host's handshake data
263 inBuffers[0].pvBuffer = (char*)(&m_receivedData[0]); 268 inBuffers[0].pvBuffer = (char*)(&receivedData_[0]);
264 inBuffers[0].cbBuffer = (unsigned long)m_receivedData.size(); 269 inBuffers[0].cbBuffer = (unsigned long)receivedData_.size();
265 inBuffers[0].BufferType = SECBUFFER_TOKEN; 270 inBuffers[0].BufferType = SECBUFFER_TOKEN;
266 271
267 inBuffers[1].pvBuffer = NULL; 272 inBuffers[1].pvBuffer = NULL;
@@ -295,17 +300,17 @@ void SchannelContext::continueHandshake(const SafeByteArray& data) {
295 outBufferDesc.ulVersion = SECBUFFER_VERSION; 300 outBufferDesc.ulVersion = SECBUFFER_VERSION;
296 301
297 SECURITY_STATUS status = InitializeSecurityContext( 302 SECURITY_STATUS status = InitializeSecurityContext(
298 m_credHandle, 303 credHandle_,
299 m_ctxtHandle, 304 contextHandle_,
300 NULL, 305 NULL,
301 m_ctxtFlags, 306 contextFlags_,
302 0, 307 0,
303 0, 308 0,
304 &inBufferDesc, 309 &inBufferDesc,
305 0, 310 0,
306 NULL, 311 NULL,
307 &outBufferDesc, 312 &outBufferDesc,
308 &m_secContext, 313 &secContext_,
309 NULL); 314 NULL);
310 315
311 if (status == SEC_E_INCOMPLETE_MESSAGE) { 316 if (status == SEC_E_INCOMPLETE_MESSAGE) {
@@ -315,16 +320,16 @@ void SchannelContext::continueHandshake(const SafeByteArray& data) {
315 else if (status == SEC_I_CONTINUE_NEEDED) { 320 else if (status == SEC_I_CONTINUE_NEEDED) {
316 SecBuffer* pDataBuffer = &outBuffers[0]; 321 SecBuffer* pDataBuffer = &outBuffers[0];
317 SecBuffer* pExtraBuffer = &inBuffers[1]; 322 SecBuffer* pExtraBuffer = &inBuffers[1];
318 323
319 if (pDataBuffer && pDataBuffer->cbBuffer > 0 && pDataBuffer->pvBuffer != NULL) { 324 if (pDataBuffer && pDataBuffer->cbBuffer > 0 && pDataBuffer->pvBuffer != NULL) {
320 sendDataOnNetwork(pDataBuffer->pvBuffer, pDataBuffer->cbBuffer); 325 sendDataOnNetwork(pDataBuffer->pvBuffer, pDataBuffer->cbBuffer);
321 } 326 }
322 327
323 if (pExtraBuffer->BufferType == SECBUFFER_EXTRA) { 328 if (pExtraBuffer->BufferType == SECBUFFER_EXTRA) {
324 m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer); 329 receivedData_.erase(receivedData_.begin(), receivedData_.end() - pExtraBuffer->cbBuffer);
325 } 330 }
326 else { 331 else {
327 m_receivedData.clear(); 332 receivedData_.clear();
328 } 333 }
329 334
330 break; 335 break;
@@ -336,19 +341,19 @@ void SchannelContext::continueHandshake(const SafeByteArray& data) {
336 } 341 }
337 342
338 SecBuffer* pExtraBuffer = &inBuffers[1]; 343 SecBuffer* pExtraBuffer = &inBuffers[1];
339 344
340 if (pExtraBuffer && pExtraBuffer->cbBuffer > 0) { 345 if (pExtraBuffer && pExtraBuffer->cbBuffer > 0) {
341 m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer); 346 receivedData_.erase(receivedData_.begin(), receivedData_.end() - pExtraBuffer->cbBuffer);
342 } 347 }
343 else { 348 else {
344 m_receivedData.clear(); 349 receivedData_.clear();
345 } 350 }
346 351
347 m_state = Connected; 352 state_ = Connected;
348 determineStreamSizes(); 353 determineStreamSizes();
349 354
350 onConnected(); 355 onConnected();
351 } 356 }
352 else { 357 else {
353 // We failed to initialize the security context 358 // We failed to initialize the security context
354 handleCertError(status); 359 handleCertError(status);
@@ -360,35 +365,35 @@ void SchannelContext::continueHandshake(const SafeByteArray& data) {
360 365
361//------------------------------------------------------------------------ 366//------------------------------------------------------------------------
362 367
363void SchannelContext::handleCertError(SECURITY_STATUS status) 368void SchannelContext::handleCertError(SECURITY_STATUS status)
364{ 369{
365 if (status == SEC_E_UNTRUSTED_ROOT || 370 if (status == SEC_E_UNTRUSTED_ROOT ||
366 status == CERT_E_UNTRUSTEDROOT || 371 status == CERT_E_UNTRUSTEDROOT ||
367 status == CRYPT_E_ISSUER_SERIALNUMBER || 372 status == CRYPT_E_ISSUER_SERIALNUMBER ||
368 status == CRYPT_E_SIGNER_NOT_FOUND || 373 status == CRYPT_E_SIGNER_NOT_FOUND ||
369 status == CRYPT_E_NO_TRUSTED_SIGNER) { 374 status == CRYPT_E_NO_TRUSTED_SIGNER) {
370 m_verificationError = CertificateVerificationError::Untrusted; 375 verificationError_ = CertificateVerificationError::Untrusted;
371 } 376 }
372 else if (status == SEC_E_CERT_EXPIRED || 377 else if (status == SEC_E_CERT_EXPIRED ||
373 status == CERT_E_EXPIRED) { 378 status == CERT_E_EXPIRED) {
374 m_verificationError = CertificateVerificationError::Expired; 379 verificationError_ = CertificateVerificationError::Expired;
375 } 380 }
376 else if (status == CRYPT_E_SELF_SIGNED) { 381 else if (status == CRYPT_E_SELF_SIGNED) {
377 m_verificationError = CertificateVerificationError::SelfSigned; 382 verificationError_ = CertificateVerificationError::SelfSigned;
378 } 383 }
379 else if (status == CRYPT_E_HASH_VALUE || 384 else if (status == CRYPT_E_HASH_VALUE ||
380 status == TRUST_E_CERT_SIGNATURE) { 385 status == TRUST_E_CERT_SIGNATURE) {
381 m_verificationError = CertificateVerificationError::InvalidSignature; 386 verificationError_ = CertificateVerificationError::InvalidSignature;
382 } 387 }
383 else if (status == CRYPT_E_REVOKED) { 388 else if (status == CRYPT_E_REVOKED) {
384 m_verificationError = CertificateVerificationError::Revoked; 389 verificationError_ = CertificateVerificationError::Revoked;
385 } 390 }
386 else if (status == CRYPT_E_NO_REVOCATION_CHECK || 391 else if (status == CRYPT_E_NO_REVOCATION_CHECK ||
387 status == CRYPT_E_REVOCATION_OFFLINE) { 392 status == CRYPT_E_REVOCATION_OFFLINE) {
388 m_verificationError = CertificateVerificationError::RevocationCheckFailed; 393 verificationError_ = CertificateVerificationError::RevocationCheckFailed;
389 } 394 }
390 else { 395 else {
391 m_verificationError = CertificateVerificationError::UnknownError; 396 verificationError_ = CertificateVerificationError::UnknownError;
392 } 397 }
393} 398}
394 399
@@ -416,7 +421,7 @@ void SchannelContext::forwardDataToApplication(const void* pData, size_t dataSiz
416 421
417void SchannelContext::handleDataFromApplication(const SafeByteArray& data) { 422void SchannelContext::handleDataFromApplication(const SafeByteArray& data) {
418 // Don't attempt to send data until we're fully connected 423 // Don't attempt to send data until we're fully connected
419 if (m_state == Connecting) { 424 if (state_ == Connecting) {
420 return; 425 return;
421 } 426 }
422 427
@@ -427,7 +432,7 @@ void SchannelContext::handleDataFromApplication(const SafeByteArray& data) {
427//------------------------------------------------------------------------ 432//------------------------------------------------------------------------
428 433
429void SchannelContext::handleDataFromNetwork(const SafeByteArray& data) { 434void SchannelContext::handleDataFromNetwork(const SafeByteArray& data) {
430 switch (m_state) { 435 switch (state_) {
431 case Connecting: 436 case Connecting:
432 { 437 {
433 // We're still establishing the connection, so continue the handshake 438 // We're still establishing the connection, so continue the handshake
@@ -450,8 +455,8 @@ void SchannelContext::handleDataFromNetwork(const SafeByteArray& data) {
450//------------------------------------------------------------------------ 455//------------------------------------------------------------------------
451 456
452void SchannelContext::indicateError(boost::shared_ptr<TLSError> error) { 457void SchannelContext::indicateError(boost::shared_ptr<TLSError> error) {
453 m_state = Error; 458 state_ = Error;
454 m_receivedData.clear(); 459 receivedData_.clear();
455 onError(error); 460 onError(error);
456} 461}
457 462
@@ -461,20 +466,20 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data) {
461 SecBuffer inBuffers[4] = {0}; 466 SecBuffer inBuffers[4] = {0};
462 467
463 appendNewData(data); 468 appendNewData(data);
464 469
465 while (!m_receivedData.empty()) { 470 while (!receivedData_.empty()) {
466 // 471 //
467 // MSDN: 472 // MSDN:
468 // When using the Schannel SSP with contexts that are not connection oriented, on input, 473 // When using the Schannel SSP with contexts that are not connection oriented, on input,
469 // the structure must contain four SecBuffer structures. Exactly one buffer must be of type 474 // the structure must contain four SecBuffer structures. Exactly one buffer must be of type
470 // SECBUFFER_DATA and contain an encrypted message, which is decrypted in place. The remaining 475 // SECBUFFER_DATA and contain an encrypted message, which is decrypted in place. The remaining
471 // buffers are used for output and must be of type SECBUFFER_EMPTY. For connection-oriented 476 // buffers are used for output and must be of type SECBUFFER_EMPTY. For connection-oriented
472 // contexts, a SECBUFFER_DATA type buffer must be supplied, as noted for nonconnection-oriented 477 // contexts, a SECBUFFER_DATA type buffer must be supplied, as noted for nonconnection-oriented
473 // contexts. Additionally, a second SECBUFFER_TOKEN type buffer that contains a security token 478 // contexts. Additionally, a second SECBUFFER_TOKEN type buffer that contains a security token
474 // must also be supplied. 479 // must also be supplied.
475 // 480 //
476 inBuffers[0].pvBuffer = (char*)(&m_receivedData[0]); 481 inBuffers[0].pvBuffer = (char*)(&receivedData_[0]);
477 inBuffers[0].cbBuffer = (unsigned long)m_receivedData.size(); 482 inBuffers[0].cbBuffer = (unsigned long)receivedData_.size();
478 inBuffers[0].BufferType = SECBUFFER_DATA; 483 inBuffers[0].BufferType = SECBUFFER_DATA;
479 484
480 inBuffers[1].BufferType = SECBUFFER_EMPTY; 485 inBuffers[1].BufferType = SECBUFFER_EMPTY;
@@ -486,22 +491,22 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data) {
486 inBufferDesc.pBuffers = inBuffers; 491 inBufferDesc.pBuffers = inBuffers;
487 inBufferDesc.ulVersion = SECBUFFER_VERSION; 492 inBufferDesc.ulVersion = SECBUFFER_VERSION;
488 493
489 size_t inData = m_receivedData.size(); 494 size_t inData = receivedData_.size();
490 SECURITY_STATUS status = DecryptMessage(m_ctxtHandle, &inBufferDesc, 0, NULL); 495 SECURITY_STATUS status = DecryptMessage(contextHandle_, &inBufferDesc, 0, NULL);
491 496
492 if (status == SEC_E_INCOMPLETE_MESSAGE) { 497 if (status == SEC_E_INCOMPLETE_MESSAGE) {
493 // Wait for more data to arrive 498 // Wait for more data to arrive
494 break; 499 break;
495 } 500 }
496 else if (status == SEC_I_RENEGOTIATE) { 501 else if (status == SEC_I_RENEGOTIATE) {
497 // TODO: Handle renegotiation scenarios 502 // TODO: Handle renegotiation scenarios
498 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 503 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
499 break; 504 break;
500 } 505 }
501 else if (status == SEC_I_CONTEXT_EXPIRED) { 506 else if (status == SEC_I_CONTEXT_EXPIRED) {
502 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 507 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
503 break; 508 break;
504 } 509 }
505 else if (status != SEC_E_OK) { 510 else if (status != SEC_E_OK) {
506 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 511 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
507 break; 512 break;
@@ -524,11 +529,11 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data) {
524 529
525 // If there is extra data left over from the decryption operation, we call DecryptMessage() again 530 // If there is extra data left over from the decryption operation, we call DecryptMessage() again
526 if (pExtraBuffer) { 531 if (pExtraBuffer) {
527 m_receivedData.erase(m_receivedData.begin(), m_receivedData.end() - pExtraBuffer->cbBuffer); 532 receivedData_.erase(receivedData_.begin(), receivedData_.end() - pExtraBuffer->cbBuffer);
528 } 533 }
529 else { 534 else {
530 // We're done 535 // We're done
531 m_receivedData.erase(m_receivedData.begin(), m_receivedData.begin() + inData); 536 receivedData_.erase(receivedData_.begin(), receivedData_.begin() + inData);
532 } 537 }
533 } 538 }
534} 539}
@@ -536,43 +541,43 @@ void SchannelContext::decryptAndProcessData(const SafeByteArray& data) {
536//------------------------------------------------------------------------ 541//------------------------------------------------------------------------
537 542
538void SchannelContext::encryptAndSendData(const SafeByteArray& data) { 543void SchannelContext::encryptAndSendData(const SafeByteArray& data) {
539 if (m_streamSizes.cbMaximumMessage == 0) { 544 if (streamSizes_.cbMaximumMessage == 0) {
540 return; 545 return;
541 } 546 }
542 547
543 SecBuffer outBuffers[4] = {0}; 548 SecBuffer outBuffers[4] = {0};
544 549
545 // Calculate the largest required size of the send buffer 550 // Calculate the largest required size of the send buffer
546 size_t messageBufferSize = (data.size() > m_streamSizes.cbMaximumMessage) 551 size_t messageBufferSize = (data.size() > streamSizes_.cbMaximumMessage)
547 ? m_streamSizes.cbMaximumMessage 552 ? streamSizes_.cbMaximumMessage
548 : data.size(); 553 : data.size();
549 554
550 // Allocate a packet for the encrypted data 555 // Allocate a packet for the encrypted data
551 SafeByteArray sendBuffer; 556 SafeByteArray sendBuffer;
552 sendBuffer.resize(m_streamSizes.cbHeader + messageBufferSize + m_streamSizes.cbTrailer); 557 sendBuffer.resize(streamSizes_.cbHeader + messageBufferSize + streamSizes_.cbTrailer);
553 558
554 size_t bytesSent = 0; 559 size_t bytesSent = 0;
555 do { 560 do {
556 size_t bytesLeftToSend = data.size() - bytesSent; 561 size_t bytesLeftToSend = data.size() - bytesSent;
557 562
558 // Calculate how much of the send buffer we'll be using for this chunk 563 // Calculate how much of the send buffer we'll be using for this chunk
559 size_t bytesToSend = (bytesLeftToSend > m_streamSizes.cbMaximumMessage) 564 size_t bytesToSend = (bytesLeftToSend > streamSizes_.cbMaximumMessage)
560 ? m_streamSizes.cbMaximumMessage 565 ? streamSizes_.cbMaximumMessage
561 : bytesLeftToSend; 566 : bytesLeftToSend;
562 567
563 // Copy the plain text data into the send buffer 568 // Copy the plain text data into the send buffer
564 memcpy(&sendBuffer[0] + m_streamSizes.cbHeader, &data[0] + bytesSent, bytesToSend); 569 memcpy(&sendBuffer[0] + streamSizes_.cbHeader, &data[0] + bytesSent, bytesToSend);
565 570
566 outBuffers[0].pvBuffer = &sendBuffer[0]; 571 outBuffers[0].pvBuffer = &sendBuffer[0];
567 outBuffers[0].cbBuffer = m_streamSizes.cbHeader; 572 outBuffers[0].cbBuffer = streamSizes_.cbHeader;
568 outBuffers[0].BufferType = SECBUFFER_STREAM_HEADER; 573 outBuffers[0].BufferType = SECBUFFER_STREAM_HEADER;
569 574
570 outBuffers[1].pvBuffer = &sendBuffer[0] + m_streamSizes.cbHeader; 575 outBuffers[1].pvBuffer = &sendBuffer[0] + streamSizes_.cbHeader;
571 outBuffers[1].cbBuffer = (unsigned long)bytesToSend; 576 outBuffers[1].cbBuffer = (unsigned long)bytesToSend;
572 outBuffers[1].BufferType = SECBUFFER_DATA; 577 outBuffers[1].BufferType = SECBUFFER_DATA;
573 578
574 outBuffers[2].pvBuffer = &sendBuffer[0] + m_streamSizes.cbHeader + bytesToSend; 579 outBuffers[2].pvBuffer = &sendBuffer[0] + streamSizes_.cbHeader + bytesToSend;
575 outBuffers[2].cbBuffer = m_streamSizes.cbTrailer; 580 outBuffers[2].cbBuffer = streamSizes_.cbTrailer;
576 outBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER; 581 outBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
577 582
578 outBuffers[3].pvBuffer = 0; 583 outBuffers[3].pvBuffer = 0;
@@ -584,7 +589,7 @@ void SchannelContext::encryptAndSendData(const SafeByteArray& data) {
584 outBufferDesc.pBuffers = outBuffers; 589 outBufferDesc.pBuffers = outBuffers;
585 outBufferDesc.ulVersion = SECBUFFER_VERSION; 590 outBufferDesc.ulVersion = SECBUFFER_VERSION;
586 591
587 SECURITY_STATUS status = EncryptMessage(m_ctxtHandle, 0, &outBufferDesc, 0); 592 SECURITY_STATUS status = EncryptMessage(contextHandle_, 0, &outBufferDesc, 0);
588 if (status != SEC_E_OK) { 593 if (status != SEC_E_OK) {
589 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError)); 594 indicateError(boost::make_shared<TLSError>(TLSError::UnknownError));
590 return; 595 return;
@@ -604,14 +609,14 @@ bool SchannelContext::setClientCertificate(CertificateWithKey::ref certificate)
604 return false; 609 return false;
605 } 610 }
606 611
607 userCertificate = capiCertificate; 612 userCertificate_ = capiCertificate;
608 613
609 // We assume that the Certificate Store Name/Certificate Name 614 // We assume that the Certificate Store Name/Certificate Name
610 // are valid at this point 615 // are valid at this point
611 m_cert_store_name = capiCertificate->getCertStoreName(); 616 certStoreName_ = capiCertificate->getCertStoreName();
612 m_cert_name = capiCertificate->getCertName(); 617 certName_ = capiCertificate->getCertName();
613////At the moment this is only useful for logging: 618////At the moment this is only useful for logging:
614 m_smartcard_reader = capiCertificate->getSmartCardReaderName(); 619 smartCardReader_ = capiCertificate->getSmartCardReaderName();
615 620
616 capiCertificate->onCertificateCardRemoved.connect(boost::bind(&SchannelContext::handleCertificateCardRemoved, this)); 621 capiCertificate->onCertificateCardRemoved.connect(boost::bind(&SchannelContext::handleCertificateCardRemoved, this));
617 622
@@ -630,7 +635,7 @@ std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const {
630 ScopedCertContext pServerCert; 635 ScopedCertContext pServerCert;
631 ScopedCertContext pIssuerCert; 636 ScopedCertContext pIssuerCert;
632 ScopedCertContext pCurrentCert; 637 ScopedCertContext pCurrentCert;
633 SECURITY_STATUS status = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset()); 638 SECURITY_STATUS status = QueryContextAttributes(contextHandle_, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset());
634 639
635 if (status != SEC_E_OK) { 640 if (status != SEC_E_OK) {
636 return certificateChain; 641 return certificateChain;
@@ -655,14 +660,14 @@ std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const {
655//------------------------------------------------------------------------ 660//------------------------------------------------------------------------
656 661
657CertificateVerificationError::ref SchannelContext::getPeerCertificateVerificationError() const { 662CertificateVerificationError::ref SchannelContext::getPeerCertificateVerificationError() const {
658 return m_verificationError ? boost::make_shared<CertificateVerificationError>(*m_verificationError) : CertificateVerificationError::ref(); 663 return verificationError_ ? boost::make_shared<CertificateVerificationError>(*verificationError_) : CertificateVerificationError::ref();
659} 664}
660 665
661//------------------------------------------------------------------------ 666//------------------------------------------------------------------------
662 667
663ByteArray SchannelContext::getFinishMessage() const { 668ByteArray SchannelContext::getFinishMessage() const {
664 SecPkgContext_Bindings bindings; 669 SecPkgContext_Bindings bindings;
665 int ret = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_UNIQUE_BINDINGS, &bindings); 670 int ret = QueryContextAttributes(contextHandle_, SECPKG_ATTR_UNIQUE_BINDINGS, &bindings);
666 if (ret == SEC_E_OK) { 671 if (ret == SEC_E_OK) {
667 return createByteArray(((unsigned char*) bindings.Bindings) + bindings.Bindings->dwApplicationDataOffset + 11 /* tls-unique:*/, bindings.Bindings->cbApplicationDataLength - 11); 672 return createByteArray(((unsigned char*) bindings.Bindings) + bindings.Bindings->dwApplicationDataOffset + 11 /* tls-unique:*/, bindings.Bindings->cbApplicationDataLength - 11);
668 } 673 }
@@ -672,7 +677,7 @@ ByteArray SchannelContext::getFinishMessage() const {
672//------------------------------------------------------------------------ 677//------------------------------------------------------------------------
673 678
674void SchannelContext::setCheckCertificateRevocation(bool b) { 679void SchannelContext::setCheckCertificateRevocation(bool b) {
675 checkCertificateRevocation = b; 680 checkCertificateRevocation_ = b;
676} 681}
677 682
678 683
diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h
index 3a068f2..19cc473 100644
--- a/Swiften/TLS/Schannel/SchannelContext.h
+++ b/Swiften/TLS/Schannel/SchannelContext.h
@@ -37,7 +37,7 @@ namespace Swift
37 typedef boost::shared_ptr<SchannelContext> sp_t; 37 typedef boost::shared_ptr<SchannelContext> sp_t;
38 38
39 public: 39 public:
40 SchannelContext(); 40 SchannelContext(bool tls1_0Workaround);
41 41
42 ~SchannelContext(); 42 ~SchannelContext();
43 43
@@ -86,23 +86,24 @@ namespace Swift
86 86
87 }; 87 };
88 88
89 SchannelState m_state; 89 SchannelState state_;
90 boost::optional<CertificateVerificationError> m_verificationError; 90 boost::optional<CertificateVerificationError> verificationError_;
91 91
92 ULONG m_secContext; 92 ULONG secContext_;
93 ScopedCredHandle m_credHandle; 93 ScopedCredHandle credHandle_;
94 ScopedCtxtHandle m_ctxtHandle; 94 ScopedCtxtHandle contextHandle_;
95 DWORD m_ctxtFlags; 95 DWORD contextFlags_;
96 SecPkgContext_StreamSizes m_streamSizes; 96 SecPkgContext_StreamSizes streamSizes_;
97 97
98 std::vector<char> m_receivedData; 98 std::vector<char> receivedData_;
99 99
100 HCERTSTORE m_my_cert_store; 100 HCERTSTORE myCertStore_;
101 std::string m_cert_store_name; 101 std::string certStoreName_;
102 std::string m_cert_name; 102 std::string certName_;
103////Not needed, most likely 103////Not needed, most likely
104 std::string m_smartcard_reader; //Can be empty string for non SmartCard certificates 104 std::string smartCardReader_; //Can be empty string for non SmartCard certificates
105 boost::shared_ptr<CAPICertificate> userCertificate; 105 boost::shared_ptr<CAPICertificate> userCertificate_;
106 bool checkCertificateRevocation; 106 bool checkCertificateRevocation_;
107 bool tls1_0Workaround_;
107 }; 108 };
108} 109}
diff --git a/Swiften/TLS/Schannel/SchannelContextFactory.cpp b/Swiften/TLS/Schannel/SchannelContextFactory.cpp
index 8b0044c..6e83b0d 100644
--- a/Swiften/TLS/Schannel/SchannelContextFactory.cpp
+++ b/Swiften/TLS/Schannel/SchannelContextFactory.cpp
@@ -4,6 +4,12 @@
4 * See Documentation/Licenses/BSD-simplified.txt for more information. 4 * See Documentation/Licenses/BSD-simplified.txt for more information.
5 */ 5 */
6 6
7/*
8 * Copyright (c) 2015 Isode Limited.
9 * All rights reserved.
10 * See the COPYING file for more information.
11 */
12
7#include "Swiften/TLS/Schannel/SchannelContextFactory.h" 13#include "Swiften/TLS/Schannel/SchannelContextFactory.h"
8#include "Swiften/TLS/Schannel/SchannelContext.h" 14#include "Swiften/TLS/Schannel/SchannelContext.h"
9 15
@@ -16,8 +22,8 @@ bool SchannelContextFactory::canCreate() const {
16 return true; 22 return true;
17} 23}
18 24
19TLSContext* SchannelContextFactory::createTLSContext() { 25TLSContext* SchannelContextFactory::createTLSContext(const TLSOptions& tlsOptions) {
20 SchannelContext* context = new SchannelContext(); 26 SchannelContext* context = new SchannelContext(tlsOptions.schannelTLS1_0Workaround);
21 context->setCheckCertificateRevocation(checkCertificateRevocation); 27 context->setCheckCertificateRevocation(checkCertificateRevocation);
22 return context; 28 return context;
23} 29}
diff --git a/Swiften/TLS/Schannel/SchannelContextFactory.h b/Swiften/TLS/Schannel/SchannelContextFactory.h
index 9dc835c..789d15f 100644
--- a/Swiften/TLS/Schannel/SchannelContextFactory.h
+++ b/Swiften/TLS/Schannel/SchannelContextFactory.h
@@ -4,9 +4,15 @@
4 * See Documentation/Licenses/BSD-simplified.txt for more information. 4 * See Documentation/Licenses/BSD-simplified.txt for more information.
5 */ 5 */
6 6
7/*
8 * Copyright (c) 2015 Isode Limited.
9 * All rights reserved.
10 * See the COPYING file for more information.
11 */
12
7#pragma once 13#pragma once
8 14
9#include "Swiften/TLS/TLSContextFactory.h" 15#include <Swiften/TLS/TLSContextFactory.h>
10 16
11namespace Swift { 17namespace Swift {
12 class SchannelContextFactory : public TLSContextFactory { 18 class SchannelContextFactory : public TLSContextFactory {
@@ -14,7 +20,7 @@ namespace Swift {
14 SchannelContextFactory(); 20 SchannelContextFactory();
15 21
16 bool canCreate() const; 22 bool canCreate() const;
17 virtual TLSContext* createTLSContext(); 23 virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions);
18 24
19 virtual void setCheckCertificateRevocation(bool b); 25 virtual void setCheckCertificateRevocation(bool b);
20 26
diff --git a/Swiften/TLS/TLSContextFactory.h b/Swiften/TLS/TLSContextFactory.h
index 10c5577..90da4a1 100644
--- a/Swiften/TLS/TLSContextFactory.h
+++ b/Swiften/TLS/TLSContextFactory.h
@@ -7,6 +7,7 @@
7#pragma once 7#pragma once
8 8
9#include <Swiften/Base/API.h> 9#include <Swiften/Base/API.h>
10#include <Swiften/TLS/TLSOptions.h>
10 11
11namespace Swift { 12namespace Swift {
12 class TLSContext; 13 class TLSContext;
@@ -17,7 +18,7 @@ namespace Swift {
17 18
18 virtual bool canCreate() const = 0; 19 virtual bool canCreate() const = 0;
19 20
20 virtual TLSContext* createTLSContext() = 0; 21 virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions) = 0;
21 virtual void setCheckCertificateRevocation(bool b) = 0; 22 virtual void setCheckCertificateRevocation(bool b) = 0;
22 }; 23 };
23} 24}
diff --git a/Swiften/TLS/TLSOptions.h b/Swiften/TLS/TLSOptions.h
new file mode 100644
index 0000000..ca84829
--- /dev/null
+++ b/Swiften/TLS/TLSOptions.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (c) 2015 Isode Limited.
3 * All rights reserved.
4 * See the COPYING file for more information.
5 */
6
7#pragma once
8
9namespace Swift {
10
11 struct TLSOptions {
12 TLSOptions() : schannelTLS1_0Workaround(false) {
13
14 }
15
16 /**
17 * A bug in the Windows SChannel TLS stack, combined with
18 * overly-restrictive server stacks means it's sometimes necessary to
19 * not use TLS>1.0. This option has no effect unless compiled on
20 * Windows against SChannel (OpenSSL users are unaffected).
21 */
22 bool schannelTLS1_0Workaround;
23
24 };
25}