summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2015-10-19 14:23:42 (GMT)
committerSwift Review <review@swift.im>2015-11-10 18:28:39 (GMT)
commitab651834c9088e34e6e66eb105e0fb855f1572c4 (patch)
tree611d434fedcb69f6698af9dc4696e59fba9d97b7 /Swiften/Network/BOSHConnectionPool.cpp
parent9b090062d0270d556c9253e0ddf767d7c5bbadbf (diff)
downloadswift-ab651834c9088e34e6e66eb105e0fb855f1572c4.zip
swift-ab651834c9088e34e6e66eb105e0fb855f1572c4.tar.bz2
Add support for client certificate authentication in BOSH
This allows to authenticate using SASL EXTERNAL over BOSH using a client TLS certificate for the HTTPS connection of the BOSH channel. The implementation also enforces the HTTPS server certificate of subsequent BOSH connections not to change. This commit also removes TLSConnection and TLSConnectionFactory as no code is using them. Test-Information: Tested against M-Link 16.3v6-0 on Debian 7.9 and Swift on OS X 10.10.5. Verified working client certificate authentication. Verified Swift not falling back to password-based authentication, in case EXTERNAL is not allowed by the server over BOSH or the client certificate is invalid. Change-Id: Ia96bcac27cac9fc9261ed847c82c6328307bfbd1
Diffstat (limited to 'Swiften/Network/BOSHConnectionPool.cpp')
-rw-r--r--Swiften/Network/BOSHConnectionPool.cpp58
1 files changed, 46 insertions, 12 deletions
diff --git a/Swiften/Network/BOSHConnectionPool.cpp b/Swiften/Network/BOSHConnectionPool.cpp
index c23e2de..57c1bcc 100644
--- a/Swiften/Network/BOSHConnectionPool.cpp
+++ b/Swiften/Network/BOSHConnectionPool.cpp
@@ -10,11 +10,11 @@
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
+#include <Swiften/Base/Log.h>
#include <Swiften/Base/SafeString.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Network/CachingDomainNameResolver.h>
#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h>
-#include <Swiften/Network/TLSConnectionFactory.h>
namespace Swift {
BOSHConnectionPool::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, boost::shared_ptr<HTTPTrafficFilter> trafficFilter) :
@@ -27,21 +27,14 @@ BOSHConnectionPool::BOSHConnectionPool(const URL& boshURL, DomainNameResolver* r
to(to),
requestLimit(2),
restartCount(0),
- pendingRestart(false) {
+ pendingRestart(false),
+ tlsContextFactory_(tlsFactory),
+ tlsOptions_(tlsOptions) {
if (!boshHTTPConnectProxyURL.isEmpty()) {
- if (boshHTTPConnectProxyURL.getScheme() == "https") {
- connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions);
- myConnectionFactories.push_back(connectionFactory);
- }
connectionFactory = new HTTPConnectProxiedConnectionFactory(realResolver, connectionFactory, timerFactory, boshHTTPConnectProxyURL.getHost(), URL::getPortOrDefaultPort(boshHTTPConnectProxyURL), boshHTTPConnectProxyAuthID, boshHTTPConnectProxyAuthPassword, trafficFilter);
}
- if (boshURL.getScheme() == "https") {
- connectionFactory = new TLSConnectionFactory(tlsFactory, connectionFactory, tlsOptions);
- myConnectionFactories.push_back(connectionFactory);
- }
resolver = new CachingDomainNameResolver(realResolver, eventLoop);
- createConnection();
}
BOSHConnectionPool::~BOSHConnectionPool() {
@@ -83,11 +76,39 @@ void BOSHConnectionPool::restartStream() {
}
}
+void BOSHConnectionPool::setTLSCertificate(CertificateWithKey::ref certWithKey) {
+ clientCertificate = certWithKey;
+}
+
+bool BOSHConnectionPool::isTLSEncrypted() const {
+ return !pinnedCertificateChain_.empty();
+}
+
+Certificate::ref BOSHConnectionPool::getPeerCertificate() const {
+ Certificate::ref peerCertificate;
+ if (!pinnedCertificateChain_.empty()) {
+ peerCertificate = pinnedCertificateChain_[0];
+ }
+ return peerCertificate;
+}
+
+std::vector<Certificate::ref> BOSHConnectionPool::getPeerCertificateChain() const {
+ return pinnedCertificateChain_;
+}
+
+boost::shared_ptr<CertificateVerificationError> BOSHConnectionPool::getPeerCertificateVerificationError() const {
+ return lastVerificationError_;
+}
+
void BOSHConnectionPool::writeFooter() {
pendingTerminate = true;
tryToSendQueuedData();
}
+void BOSHConnectionPool::open() {
+ createConnection();
+}
+
void BOSHConnectionPool::close() {
if (!sid.empty()) {
writeFooter();
@@ -117,6 +138,13 @@ void BOSHConnectionPool::handleConnectFinished(bool error, BOSHConnection::ref c
*/
}
else {
+ if (connection->getPeerCertificate() && pinnedCertificateChain_.empty()) {
+ pinnedCertificateChain_ = connection->getPeerCertificateChain();
+ }
+ if (!pinnedCertificateChain_.empty()) {
+ lastVerificationError_ = connection->getPeerCertificateVerificationError();
+ }
+
if (sid.empty()) {
connection->startStream(to, rid);
}
@@ -226,7 +254,7 @@ void BOSHConnectionPool::handleConnectionDisconnected(bool/* error*/, BOSHConnec
boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() {
Connector::ref connector = Connector::create(boshURL.getHost(), URL::getPortOrDefaultPort(boshURL), boost::optional<std::string>(), resolver, connectionFactory, timerFactory);
- BOSHConnection::ref connection = BOSHConnection::create(boshURL, connector, xmlParserFactory);
+ BOSHConnection::ref connection = BOSHConnection::create(boshURL, connector, xmlParserFactory, tlsContextFactory_, tlsOptions_);
connection->onXMPPDataRead.connect(boost::bind(&BOSHConnectionPool::handleDataRead, this, _1));
connection->onSessionStarted.connect(boost::bind(&BOSHConnectionPool::handleSessionStarted, this, _1, _2));
connection->onBOSHDataRead.connect(boost::bind(&BOSHConnectionPool::handleBOSHDataRead, this, _1));
@@ -235,6 +263,12 @@ boost::shared_ptr<BOSHConnection> BOSHConnectionPool::createConnection() {
connection->onConnectFinished.connect(boost::bind(&BOSHConnectionPool::handleConnectFinished, this, _1, connection));
connection->onSessionTerminated.connect(boost::bind(&BOSHConnectionPool::handleSessionTerminated, this, _1));
connection->onHTTPError.connect(boost::bind(&BOSHConnectionPool::handleHTTPError, this, _1));
+
+ if (boshURL.getScheme() == "https") {
+ bool success = connection->setClientCertificate(clientCertificate);
+ SWIFT_LOG(debug) << "setClientCertificate, success: " << success << std::endl;
+ }
+
connection->connect();
connections.push_back(connection);
return connection;