summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}