From 4a6950af0f324091553f7ab7271de45721b8667f Mon Sep 17 00:00:00 2001
From: Tobias Markmann <tm@ayena.de>
Date: Fri, 23 Oct 2015 16:31:09 +0200
Subject: Add support for OS X Secure Transport TLS backend

Added integration tests for certificate validation and
revocation behavior checking.

Test-Information:

Tested client login over TLS against Prosody and M-Link.
Verified client certificate authentication works against
M-Link.

Change-Id: I6ad870f17adbf279f3bac913a3076909308a0021

diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index 4ead554..3fd093b 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -506,12 +506,18 @@ conf.Finish()
 if env["qt"] :
 	env["QTDIR"] = env["qt"]
 
+# Check for OS X Secure Transport
+if not env.get("openssl_force_bundled", False) and env["PLATFORM"] == "darwin" and env["target"] == "native"  :
+	env["HAVE_SECURETRANSPORT"] = True
+else :
+	env["HAVE_SECURETRANSPORT"] = False
+
 # OpenSSL
 openssl_env = conf_env.Clone()
 if env.get("openssl_force_bundled", False) or env["target"] in ("iphone-device", "iphone-simulator", "xcode", "android") :
 	env["OPENSSL_BUNDLED"] = True
 	env["HAVE_OPENSSL"] = True
-else :
+elif not env["HAVE_SECURETRANSPORT"] :
 	use_openssl = bool(env["openssl"])
 	openssl_prefix = ""
 	if isinstance(env["openssl"], str) :
@@ -716,6 +722,6 @@ print "  Projects: " + ' '.join(env["PROJECTS"])
 print ""
 print "  XML Parsers: " + ' '.join(parsers)
 
-print "  TLS Support: " + (env.get("HAVE_OPENSSL",0) and "OpenSSL" or env.get("HAVE_SCHANNEL", 0) and "Schannel" or "Disabled")
+print "  TLS Support: " + (env.get("HAVE_OPENSSL",0) and "OpenSSL" or env.get("HAVE_SECURETRANSPORT",0) and "Secure Transport" or env.get("HAVE_SCHANNEL", 0) and "Schannel" or "Disabled")
 print "  DNSSD Support: " + (env.get("HAVE_BONJOUR") and "Bonjour" or (env.get("HAVE_AVAHI") and "Avahi" or "Disabled"))
 print
diff --git a/Swift/SConscript b/Swift/SConscript
index 31b0b94..bf19873 100644
--- a/Swift/SConscript
+++ b/Swift/SConscript
@@ -5,7 +5,7 @@ Import("env")
 SConscript("Controllers/SConscript")
 
 if env["SCONS_STAGE"] == "build" :
-	if not GetOption("help") and not env.get("HAVE_OPENSSL", 0) and not env.get("HAVE_SCHANNEL", 0) :
+	if not GetOption("help") and not env.get("HAVE_OPENSSL", 0) and not env.get("HAVE_SCHANNEL", 0) and not env.get("HAVE_SECURETRANSPORT", 0):
 		print "Error: Swift requires OpenSSL support, and OpenSSL was not found."
 		if "Swift" in env["PROJECTS"] :
 			env["PROJECTS"].remove("Swift")
diff --git a/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp b/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp
index 575c75e..a53a0cf 100644
--- a/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp
+++ b/Swiften/Crypto/UnitTest/CryptoProviderTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -17,7 +17,7 @@
 #ifdef HAVE_OPENSSL_CRYPTO_PROVIDER
 #include <Swiften/Crypto/OpenSSLCryptoProvider.h>
 #endif
-#ifdef HAVE_OPENSSL_CRYPTO_PROVIDER
+#ifdef HAVE_COMMONCRYPTO_CRYPTO_PROVIDER
 #include <Swiften/Crypto/CommonCryptoCryptoProvider.h>
 #endif
 #include <Swiften/Crypto/Hash.h>
diff --git a/Swiften/Network/TLSConnection.cpp b/Swiften/Network/TLSConnection.cpp
index 149548a..c69547d 100644
--- a/Swiften/Network/TLSConnection.cpp
+++ b/Swiften/Network/TLSConnection.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Isode Limited.
+ * Copyright (c) 2011-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
@@ -66,6 +66,10 @@ HostAddressPort TLSConnection::getLocalAddress() const {
 	return connection->getLocalAddress();
 }
 
+TLSContext* TLSConnection::getTLSContext() const {
+	return context;
+}
+
 void TLSConnection::handleRawConnectFinished(bool error) {
 	connection->onConnectFinished.disconnect(boost::bind(&TLSConnection::handleRawConnectFinished, this, _1));
 	if (error) {
diff --git a/Swiften/Network/TLSConnection.h b/Swiften/Network/TLSConnection.h
index 96525ad..a037eb1 100644
--- a/Swiften/Network/TLSConnection.h
+++ b/Swiften/Network/TLSConnection.h
@@ -6,16 +6,15 @@
 
 #pragma once
 
-#include <boost/shared_ptr.hpp>
 #include <boost/enable_shared_from_this.hpp>
-#include <Swiften/Base/boost_bsignals.h>
+#include <boost/shared_ptr.hpp>
 
 #include <Swiften/Base/API.h>
 #include <Swiften/Base/SafeByteArray.h>
+#include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/Network/Connection.h>
 #include <Swiften/TLS/TLSOptions.h>
 
-
 namespace Swift {
 	class HostAddressPort;
 	class TLSContextFactory;
@@ -34,6 +33,8 @@ namespace Swift {
 
 			virtual HostAddressPort getLocalAddress() const;
 
+			TLSContext* getTLSContext() const;
+
 		private:
 			void handleRawConnectFinished(bool error);
 			void handleRawDisconnected(const boost::optional<Error>& error);
@@ -42,6 +43,7 @@ namespace Swift {
 			void handleTLSConnectFinished(bool error);
 			void handleTLSDataForNetwork(const SafeByteArray& data);
 			void handleTLSDataForApplication(const SafeByteArray& data);
+
 		private:
 			TLSContext* context;
 			Connection::ref connection;
diff --git a/Swiften/QA/TLSTest/CertificateErrorTest.cpp b/Swiften/QA/TLSTest/CertificateErrorTest.cpp
new file mode 100644
index 0000000..d7c2c55
--- /dev/null
+++ b/Swiften/QA/TLSTest/CertificateErrorTest.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+ /*
+	This file uses http://www.tls-o-matic.com/ to test the currently configured TLS backend for correct certificate validation behavior.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include <Swiften/Base/Log.h>
+#include <Swiften/EventLoop/DummyEventLoop.h>
+#include <Swiften/IDN/PlatformIDNConverter.h>
+#include <Swiften/IDN/IDNConverter.h>
+#include <Swiften/Network/BoostConnectionFactory.h>
+#include <Swiften/Network/BoostIOServiceThread.h>
+#include <Swiften/Network/HostAddressPort.h>
+#include <Swiften/Network/PlatformDomainNameResolver.h>
+#include <Swiften/Network/TLSConnection.h>
+#include <Swiften/Network/TLSConnectionFactory.h>
+#include <Swiften/TLS/CertificateVerificationError.h>
+#include <Swiften/TLS/PlatformTLSFactories.h>
+#include <Swiften/TLS/TLSContext.h>
+#include <Swiften/TLS/TLSContextFactory.h>
+
+using namespace Swift;
+
+class CertificateErrorTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(CertificateErrorTest);
+
+		// These test require the TLS-O-Matic testing CA to be trusted. For more info see https://www.tls-o-matic.com/https/test1 .
+		CPPUNIT_TEST(testTLS_O_MaticTrusted);
+		CPPUNIT_TEST(testTLS_O_MaticCertificateFromTheFuture);
+		CPPUNIT_TEST(testTLS_O_MaticCertificateFromThePast);
+		CPPUNIT_TEST(testTLS_O_MaticCertificateFromUnknownCA);
+		CPPUNIT_TEST(testTLS_O_MaticCertificateWrongPurpose);
+
+#if !defined(HAVE_OPENSSL)
+		// Our OpenSSL backend does not support revocation. We excluded it from the revocation tests.
+		CPPUNIT_TEST(testRevokedCertificateRevocationDisabled);
+		CPPUNIT_TEST(testRevokedCertificateRevocationEnabled);
+#endif
+
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void setUp() {
+			SWIFT_LOG(debug) << std::endl << std::endl;
+			eventLoop_ = new DummyEventLoop();
+			boostIOServiceThread_ = new BoostIOServiceThread();
+			boostIOService_ = boost::make_shared<boost::asio::io_service>();
+			connectionFactory_ = new BoostConnectionFactory(boostIOServiceThread_->getIOService(), eventLoop_);
+			idnConverter_ = PlatformIDNConverter::create();
+			domainNameResolver_ = new PlatformDomainNameResolver(idnConverter_, eventLoop_),
+
+			tlsFactories_ = new PlatformTLSFactories();
+			tlsContextFactory_ = tlsFactories_->getTLSContextFactory();
+			
+			tlsContextFactory_->setCheckCertificateRevocation(false);
+
+			tlsConnectionFactory_ = new TLSConnectionFactory(tlsContextFactory_, connectionFactory_, TLSOptions());
+
+			connectFinished_ = false;
+			connectFinishedWithError_ = false;
+		}
+
+		void tearDown() {
+			delete tlsConnectionFactory_;
+			delete tlsFactories_;
+
+			delete domainNameResolver_;
+			delete idnConverter_;
+			delete connectionFactory_;
+			delete boostIOServiceThread_;
+			while (eventLoop_->hasEvents()) {
+				eventLoop_->processEvents();
+			}
+			delete eventLoop_;
+		}
+
+		HostAddress resolveName(const std::string& name) {
+			boost::shared_ptr<DomainNameAddressQuery> query = domainNameResolver_->createAddressQuery(name);
+			query->onResult.connect(boost::bind(&CertificateErrorTest::handleAddressQueryResult, this, _1, _2));
+			lastResoverResult_ = HostAddress();
+			resolvingDone_ = false;
+			
+			query->run();
+			while(!resolvingDone_) {
+				eventLoop_->processEvents();
+			}
+
+			return lastResoverResult_;
+		}
+
+		void connectToServer(boost::shared_ptr<TLSConnection> connection, const std::string& hostname, int port) {
+			Log::setLogLevel(Log::debug);
+			connection->onConnectFinished.connect(boost::bind(&CertificateErrorTest::handleConnectFinished, this, _1));
+
+			HostAddress address = resolveName(hostname);
+
+			connection->connect(HostAddressPort(address, port));
+
+			while (!connectFinished_) {
+				eventLoop_->processEvents();
+			}
+		}
+
+		void testTLS_O_MaticTrusted() {
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "test1.tls-o-matic.com", 443);
+	
+			CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::ref(), context->getPeerCertificateVerificationError());
+		}
+
+		void testTLS_O_MaticCertificateFromTheFuture() {
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "test5.tls-o-matic.com", 405);
+
+			CPPUNIT_ASSERT_EQUAL(true, connectFinishedWithError_);
+			CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::NotYetValid, context->getPeerCertificateVerificationError()->getType());
+		}
+
+		void testTLS_O_MaticCertificateFromThePast() {
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "test6.tls-o-matic.com", 406);
+
+			CPPUNIT_ASSERT_EQUAL(true, connectFinishedWithError_);
+			CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Expired, context->getPeerCertificateVerificationError()->getType());
+		}
+
+		void testTLS_O_MaticCertificateFromUnknownCA() {
+			Log::setLogLevel(Log::debug);
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "test7.tls-o-matic.com", 407);
+
+			CPPUNIT_ASSERT_EQUAL(true, connectFinishedWithError_);
+			CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Untrusted, context->getPeerCertificateVerificationError()->getType());
+		}
+
+		// test14.tls-o-matic.com:414
+		void testTLS_O_MaticCertificateWrongPurpose() {
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "test14.tls-o-matic.com", 414);
+
+			CPPUNIT_ASSERT_EQUAL(true, connectFinishedWithError_);
+			CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::InvalidPurpose, context->getPeerCertificateVerificationError()->getType());
+		}
+
+		void testRevokedCertificateRevocationDisabled() {
+			tlsContextFactory_->setCheckCertificateRevocation(false);
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "revoked.grc.com", 443);
+
+			CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+			CPPUNIT_ASSERT(!context->getPeerCertificateVerificationError());
+		}
+
+		void testRevokedCertificateRevocationEnabled() {
+			tlsContextFactory_->setCheckCertificateRevocation(true);
+			boost::shared_ptr<TLSConnection> connection = boost::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+			TLSContext* context = connection->getTLSContext();
+
+			connectToServer(connection, "revoked.grc.com", 443);
+
+			CPPUNIT_ASSERT_EQUAL(true, connectFinishedWithError_);
+			CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Revoked, context->getPeerCertificateVerificationError()->getType());
+		}
+
+	private:
+		void handleAddressQueryResult(const std::vector<HostAddress>& address, boost::optional<DomainNameResolveError> /* error */) {
+			if (address.size() > 0) {
+				lastResoverResult_ = address[0];
+			}
+			resolvingDone_ = true;
+		}
+
+		void handleConnectFinished(bool error) {
+			connectFinished_ = true;
+			connectFinishedWithError_ = error;
+		}
+	
+	private:
+		BoostIOServiceThread* boostIOServiceThread_;
+		boost::shared_ptr<boost::asio::io_service> boostIOService_;
+		DummyEventLoop* eventLoop_;
+		ConnectionFactory* connectionFactory_;
+		PlatformTLSFactories* tlsFactories_;
+		TLSContextFactory* tlsContextFactory_;
+		TLSConnectionFactory* tlsConnectionFactory_;
+		
+		IDNConverter* idnConverter_;
+		DomainNameResolver* domainNameResolver_;
+		HostAddress lastResoverResult_;
+		bool resolvingDone_;
+
+		bool connectFinished_;
+		bool connectFinishedWithError_;
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CertificateErrorTest);
diff --git a/Swiften/QA/TLSTest/SConscript b/Swiften/QA/TLSTest/SConscript
index 18f6998..c597ab1 100644
--- a/Swiften/QA/TLSTest/SConscript
+++ b/Swiften/QA/TLSTest/SConscript
@@ -12,5 +12,6 @@ if env["TEST"] :
 	
 	tester = myenv.Program("TLSTest", [
 			"CertificateTest.cpp",
+			"CertificateErrorTest.cpp"
 		])
 	myenv.Test(tester, "system")
diff --git a/Swiften/SConscript b/Swiften/SConscript
index 9216b39..9b82434 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -563,7 +563,7 @@ if env["SCONS_STAGE"] == "build" :
 				continue
 
 			# Library-specific files
-			if file.endswith("_Private.h") or file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("MacOSX") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file == "ICUConverter.h" or file == "UnboundDomainNameResolver.h" :
+			if file.endswith("_Private.h") or file.startswith("Schannel") or file.startswith("CAPI") or file.startswith("MacOSX") or file.startswith("SecureTransport") or file.startswith("Windows") or file.endswith("_Windows.h") or file.startswith("SQLite") or file == "ICUConverter.h" or file == "UnboundDomainNameResolver.h" :
 				continue
 
 			# Specific headers we don't want to globally include
diff --git a/Swiften/TLS/Certificate.h b/Swiften/TLS/Certificate.h
index a39126c..00d618e 100644
--- a/Swiften/TLS/Certificate.h
+++ b/Swiften/TLS/Certificate.h
@@ -1,14 +1,16 @@
 /*
- * Copyright (c) 2010-2013 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
 
 #pragma once
 
+#include <string>
+#include <vector>
+
 #include <boost/shared_ptr.hpp>
 
-#include <string>
 #include <Swiften/Base/API.h>
 #include <Swiften/Base/ByteArray.h>
 
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h
index 73e4322..73fe75c 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h
@@ -1,25 +1,26 @@
 /*
- * Copyright (c) 2010 Isode Limited.
+ * Copyright (c) 2010-2015 Isode Limited.
  * All rights reserved.
  * See the COPYING file for more information.
  */
 
 #pragma once
 
-#include <openssl/ssl.h>
-#include <Swiften/Base/boost_bsignals.h>
 #include <boost/noncopyable.hpp>
 
-#include <Swiften/TLS/TLSContext.h>
+#include <openssl/ssl.h>
+
 #include <Swiften/Base/ByteArray.h>
+#include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/TLS/CertificateWithKey.h>
+#include <Swiften/TLS/TLSContext.h>
 
 namespace Swift {
 
 	class OpenSSLContext : public TLSContext, boost::noncopyable {
 		public:
 			OpenSSLContext();
-			~OpenSSLContext();
+			virtual ~OpenSSLContext();
 
 			void connect();
 			bool setClientCertificate(CertificateWithKey::ref cert);
diff --git a/Swiften/TLS/PlatformTLSFactories.cpp b/Swiften/TLS/PlatformTLSFactories.cpp
index 2492840..588e0e1 100644
--- a/Swiften/TLS/PlatformTLSFactories.cpp
+++ b/Swiften/TLS/PlatformTLSFactories.cpp
@@ -18,6 +18,10 @@
 	#include <Swiften/TLS/Schannel/SchannelContextFactory.h>
 	#include <Swiften/TLS/Schannel/SchannelCertificateFactory.h>
 #endif
+#ifdef HAVE_SECURETRANSPORT
+	#include <Swiften/TLS/SecureTransport/SecureTransportContextFactory.h>
+	#include <Swiften/TLS/SecureTransport/SecureTransportCertificateFactory.h>
+#endif
 
 namespace Swift {
 
@@ -30,6 +34,10 @@ PlatformTLSFactories::PlatformTLSFactories() : contextFactory(NULL), certificate
 	contextFactory = new SchannelContextFactory();
 	certificateFactory = new SchannelCertificateFactory();
 #endif
+#ifdef HAVE_SECURETRANSPORT
+	contextFactory = new SecureTransportContextFactory();
+	certificateFactory = new SecureTransportCertificateFactory();
+#endif	
 }
 
 PlatformTLSFactories::~PlatformTLSFactories() {
diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript
index fb327b9..f5eb053 100644
--- a/Swiften/TLS/SConscript
+++ b/Swiften/TLS/SConscript
@@ -27,6 +27,14 @@ elif myenv.get("HAVE_SCHANNEL", 0) :
 			"Schannel/SchannelContextFactory.cpp",
 		])
 	myenv.Append(CPPDEFINES = "HAVE_SCHANNEL")
+elif myenv.get("HAVE_SECURETRANSPORT", 0) :
+	#swiften_env.Append(LIBS = ["Winscard"])
+	objects += myenv.StaticObject([
+			"SecureTransport/SecureTransportContext.mm",
+			"SecureTransport/SecureTransportCertificate.mm",
+			"SecureTransport/SecureTransportContextFactory.cpp",
+		])
+	myenv.Append(CPPDEFINES = "HAVE_SECURETRANSPORT")
 
 objects += myenv.SwiftenObject(["PlatformTLSFactories.cpp"])
 
diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h
index 36a3f0c..be30a7c 100644
--- a/Swiften/TLS/Schannel/SchannelContext.h
+++ b/Swiften/TLS/Schannel/SchannelContext.h
@@ -39,7 +39,7 @@ namespace Swift
 	public:
 		SchannelContext(bool tls1_0Workaround);
 
-		~SchannelContext();
+		virtual ~SchannelContext();
 
 		//
 		// TLSContext
diff --git a/Swiften/TLS/SecureTransport/SecureTransportCertificate.h b/Swiften/TLS/SecureTransport/SecureTransportCertificate.h
new file mode 100644
index 0000000..b8d3728
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportCertificate.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <boost/type_traits.hpp>
+
+#include <Security/SecCertificate.h>
+
+#include <Swiften/TLS/Certificate.h>
+
+namespace Swift {
+
+class SecureTransportCertificate : public Certificate {
+public:
+	SecureTransportCertificate(SecCertificateRef certificate);
+	SecureTransportCertificate(const ByteArray& der);
+	virtual ~SecureTransportCertificate();
+
+	virtual std::string getSubjectName() const;
+	virtual std::vector<std::string> getCommonNames() const;
+	virtual std::vector<std::string> getSRVNames() const;
+	virtual std::vector<std::string> getDNSNames() const;
+	virtual std::vector<std::string> getXMPPAddresses() const;
+
+	virtual ByteArray toDER() const;
+
+private:
+	void parse();
+	typedef boost::remove_pointer<SecCertificateRef>::type SecCertificate;
+
+private:
+	boost::shared_ptr<SecCertificate> certificateHandle_;
+	std::string subjectName_;
+	std::vector<std::string> commonNames_;
+	std::vector<std::string> srvNames_;
+	std::vector<std::string> dnsNames_;
+	std::vector<std::string> xmppAddresses_;
+};
+
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm
new file mode 100644
index 0000000..3b4e00f
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportCertificate.mm
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/TLS/SecureTransport/SecureTransportCertificate.h>
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Cocoa/Cocoa.h>
+#include <Security/Security.h>
+
+#include <Swiften/Base/Log.h>
+
+namespace {
+
+template <typename T, typename S>
+T bridge_cast(S source) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+	return (__bridge T)(source);
+#pragma clang diagnostic pop
+}
+
+}
+
+namespace Swift {
+
+SecureTransportCertificate::SecureTransportCertificate(SecCertificateRef certificate) {
+	assert(certificate);
+	CFRetain(certificate);
+	certificateHandle_ = boost::shared_ptr<SecCertificate>(certificate, CFRelease);
+	parse();
+}
+
+
+SecureTransportCertificate::SecureTransportCertificate(const ByteArray& der) {
+	CFDataRef derData = CFDataCreateWithBytesNoCopy(NULL, der.data(), static_cast<CFIndex>(der.size()), NULL); 
+	SecCertificateRef certificate = SecCertificateCreateWithData(NULL, derData);
+	if (certificate) {
+		certificateHandle_ = boost::shared_ptr<SecCertificate>(certificate, CFRelease);
+		parse();
+	}
+}
+
+SecureTransportCertificate::~SecureTransportCertificate() {
+
+}
+
+#define NS2STDSTRING(a) (a == nil ? std::string() : std::string([a cStringUsingEncoding:NSUTF8StringEncoding]))
+
+
+void SecureTransportCertificate::parse() {
+	assert(certificateHandle_);
+	CFErrorRef error = NULL;
+
+	// The SecCertificateCopyValues function is not part of the iOS Secure Transport API.
+	CFDictionaryRef valueDict = SecCertificateCopyValues(certificateHandle_.get(), 0, &error);
+	if (error) {
+		CFRelease(error);
+	}
+	else {
+		// Handle subject.
+		CFStringRef subject = SecCertificateCopySubjectSummary(certificateHandle_.get());
+		if (subject) {
+			NSString* subjectStr = bridge_cast<NSString*>(subject);
+			subjectName_ = NS2STDSTRING(subjectStr);
+			CFRelease(subject);
+		}
+
+		// Handle a single Common Name.
+		CFStringRef commonName;
+		OSStatus error = SecCertificateCopyCommonName(certificateHandle_.get(), &commonName);
+		if (!error) {
+			NSString* commonNameStr = bridge_cast<NSString*>(commonName);
+			commonNames_.push_back(NS2STDSTRING(commonNameStr));
+			CFRelease(commonName);
+		}
+
+		// Handle Subject Alternative Names
+		NSDictionary* certDict = bridge_cast<NSDictionary*>(valueDict);
+		NSDictionary* subjectAltNamesDict = certDict[@"2.5.29.17"][@"value"];
+
+		for (NSDictionary* entry in subjectAltNamesDict) {
+			if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_XMPPADDR_OID]]) {
+				xmppAddresses_.push_back(NS2STDSTRING(entry[@"value"]));
+			}
+			else if ([entry[@"label"] isEqualToString:[NSString stringWithUTF8String:ID_ON_DNSSRV_OID]]) {
+				srvNames_.push_back(NS2STDSTRING(entry[@"value"]));
+			}
+			else if ([entry[@"label"] isEqualToString:@"DNS Name"]) {
+				dnsNames_.push_back(NS2STDSTRING(entry[@"value"]));
+			}
+		}
+		CFRelease(valueDict);
+	}
+}
+
+std::string SecureTransportCertificate::getSubjectName() const {
+	return subjectName_;
+}
+
+std::vector<std::string> SecureTransportCertificate::getCommonNames() const {
+	return commonNames_;
+}
+
+std::vector<std::string> SecureTransportCertificate::getSRVNames() const {
+	return srvNames_;
+}
+
+std::vector<std::string> SecureTransportCertificate::getDNSNames() const {
+	return dnsNames_;
+}
+
+std::vector<std::string> SecureTransportCertificate::getXMPPAddresses() const {
+	return xmppAddresses_;
+}
+
+ByteArray SecureTransportCertificate::toDER() const {
+	ByteArray der;
+	if (certificateHandle_) {
+		CFDataRef derData = SecCertificateCopyData(certificateHandle_.get());
+		if (derData) {
+			try {
+				size_t dataSize = boost::numeric_cast<size_t>(CFDataGetLength(derData));
+				der.resize(dataSize);
+				CFDataGetBytes(derData, CFRangeMake(0,CFDataGetLength(derData)), der.data());
+			} catch (...) {
+			}
+			CFRelease(derData);
+		}
+	}
+	return der;
+}
+
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportCertificateFactory.h b/Swiften/TLS/SecureTransport/SecureTransportCertificateFactory.h
new file mode 100644
index 0000000..1f86541
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportCertificateFactory.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/TLS/CertificateFactory.h>
+#include <Swiften/TLS/SecureTransport/SecureTransportCertificate.h>
+
+namespace Swift {
+	
+class SecureTransportCertificateFactory : public CertificateFactory {
+	public:
+		virtual Certificate* createCertificateFromDER(const ByteArray& der) {
+			return new SecureTransportCertificate(der);
+		}
+	};
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContext.h b/Swiften/TLS/SecureTransport/SecureTransportContext.h
new file mode 100644
index 0000000..aa17c66
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportContext.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Security/SecureTransport.h>
+
+#include <Swiften/TLS/TLSContext.h>
+
+namespace Swift {
+
+class SecureTransportContext : public TLSContext {
+	public:
+		SecureTransportContext(bool checkCertificateRevocation);
+		virtual ~SecureTransportContext();
+
+		virtual void connect();
+
+		virtual bool setClientCertificate(CertificateWithKey::ref cert);
+
+		virtual void handleDataFromNetwork(const SafeByteArray&);
+		virtual void handleDataFromApplication(const SafeByteArray&);
+
+		virtual std::vector<Certificate::ref> getPeerCertificateChain() const;
+		virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const;
+
+		virtual ByteArray getFinishMessage() const;
+	
+	private:
+		static OSStatus SSLSocketReadCallback(SSLConnectionRef connection, void *data, size_t *dataLength); 
+		static OSStatus SSLSocketWriteCallback(SSLConnectionRef connection, const void *data, size_t *dataLength);
+
+	private:
+		enum State { None, Handshake, HandshakeDone, Error};
+		static std::string stateToString(State state);
+		void setState(State newState);
+
+		static boost::shared_ptr<TLSError> nativeToTLSError(OSStatus error);
+		boost::shared_ptr<CertificateVerificationError> CSSMErrorToVerificationError(OSStatus resultCode);
+
+		void processHandshake();
+		void verifyServerCertificate();
+
+		void fatalError(boost::shared_ptr<TLSError> error, boost::shared_ptr<CertificateVerificationError> certificateError);
+
+	private:
+		boost::shared_ptr<SSLContext> sslContext_;
+		SafeByteArray readingBuffer_;
+		State state_;
+		CertificateVerificationError::ref verificationError_;
+		CertificateWithKey::ref clientCertificate_;
+		bool checkCertificateRevocation_;
+};
+
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContext.mm b/Swiften/TLS/SecureTransport/SecureTransportContext.mm
new file mode 100644
index 0000000..7f44f7d
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportContext.mm
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/TLS/SecureTransport/SecureTransportContext.h>
+
+#include <boost/type_traits.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <Swiften/Base/Algorithm.h>
+#include <Swiften/Base/Log.h>
+#include <Swiften/TLS/SecureTransport/SecureTransportCertificate.h>
+#include <Swiften/TLS/PKCS12Certificate.h>
+#include <Swiften/TLS/CertificateWithKey.h>
+
+#include <Cocoa/Cocoa.h>
+
+#import <Security/SecCertificate.h>
+#import <Security/SecImportExport.h>
+
+namespace {
+	typedef boost::remove_pointer<CFArrayRef>::type CFArray;
+	typedef boost::remove_pointer<SecTrustRef>::type SecTrust;
+}
+
+template <typename T, typename S>
+T bridge_cast(S source) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+	return (__bridge T)(source);
+#pragma clang diagnostic pop
+}
+
+namespace Swift {
+
+namespace {
+
+	
+CFArrayRef getClientCertificateChainAsCFArrayRef(CertificateWithKey::ref key) {
+	boost::shared_ptr<PKCS12Certificate> pkcs12 = boost::dynamic_pointer_cast<PKCS12Certificate>(key);
+	if (!key) {
+		return NULL;
+	}
+
+	SafeByteArray safePassword = pkcs12->getPassword();
+	CFIndex passwordSize = 0;
+	try {
+		passwordSize = boost::numeric_cast<CFIndex>(safePassword.size());
+	} catch (...) {
+		return NULL;
+	}
+
+	CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, 0);
+
+	OSStatus securityError = errSecSuccess;
+	CFStringRef password = CFStringCreateWithBytes(kCFAllocatorDefault, safePassword.data(), passwordSize, kCFStringEncodingUTF8, false);
+	const void* keys[] = { kSecImportExportPassphrase };
+	const void* values[] = { password };
+
+	CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
+
+	CFArrayRef items = NULL;
+	CFDataRef pkcs12Data = bridge_cast<CFDataRef>([NSData dataWithBytes: static_cast<const void *>(pkcs12->getData().data()) length:pkcs12->getData().size()]);
+	securityError = SecPKCS12Import(pkcs12Data, options, &items);
+	NSArray* nsItems = bridge_cast<NSArray*>(items);
+
+	switch(securityError) {
+		case errSecSuccess:
+			break;
+		case errSecAuthFailed:
+			// Password did not work for decoding the certificate.
+		case errSecDecode:
+			// Other decoding error.
+		default:
+			CFRelease(certChain);
+			CFRelease(items);
+			CFRelease(options);
+			certChain = NULL;
+	}
+
+	if (certChain) {
+		CFArrayAppendValue(certChain, nsItems[0][@"identity"]);
+
+		for (CFIndex index = 0; index < CFArrayGetCount(bridge_cast<CFArrayRef>(nsItems[0][@"chain"])); index++) {
+			CFArrayAppendValue(certChain, CFArrayGetValueAtIndex(bridge_cast<CFArrayRef>(nsItems[0][@"chain"]), index));
+		}
+	}
+	return certChain;
+}
+
+}
+
+SecureTransportContext::SecureTransportContext(bool checkCertificateRevocation) : state_(None), checkCertificateRevocation_(checkCertificateRevocation) {
+	sslContext_ = boost::shared_ptr<SSLContext>(SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType), CFRelease);
+
+	OSStatus error = noErr;
+	// set IO callbacks
+	error = SSLSetIOFuncs(sslContext_.get(), &SecureTransportContext::SSLSocketReadCallback, &SecureTransportContext::SSLSocketWriteCallback);
+	if (error != noErr) {
+		SWIFT_LOG(error) << "Unable to set IO functions to SSL context." << std::endl;
+		sslContext_.reset();
+	}
+
+	error = SSLSetConnection(sslContext_.get(), this);
+	if (error != noErr) {
+		SWIFT_LOG(error) << "Unable to set connection to SSL context." << std::endl;
+		sslContext_.reset();
+	}
+
+
+	error = SSLSetSessionOption(sslContext_.get(), kSSLSessionOptionBreakOnServerAuth, true);
+	if (error != noErr) {
+		SWIFT_LOG(error) << "Unable to set kSSLSessionOptionBreakOnServerAuth on session." << std::endl;
+		sslContext_.reset();
+	}
+}
+
+SecureTransportContext::~SecureTransportContext() {
+	if (sslContext_) {
+		SSLClose(sslContext_.get());
+	}
+}
+
+std::string SecureTransportContext::stateToString(State state) {
+	std::string returnValue;
+	switch(state) {
+		case Handshake:
+			returnValue = "Handshake";
+			break;
+		case HandshakeDone:
+			returnValue = "HandshakeDone";
+			break;
+		case None:
+			returnValue = "None";
+			break;
+		case Error:
+			returnValue = "Error";
+			break;
+	}
+	return returnValue;
+}
+
+void SecureTransportContext::setState(State newState) {
+	SWIFT_LOG(debug) << "Switch state from " << stateToString(state_) << " to " << stateToString(newState) << "." << std::endl;
+	state_ = newState;
+}
+
+void SecureTransportContext::connect() {
+	SWIFT_LOG_ASSERT(state_ == None, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+	if (clientCertificate_) {
+		CFArrayRef certs = getClientCertificateChainAsCFArrayRef(clientCertificate_);
+		if (certs) {
+			boost::shared_ptr<CFArray> certRefs(certs, CFRelease);
+			OSStatus result = SSLSetCertificate(sslContext_.get(), certRefs.get());
+			if (result != noErr) {
+				SWIFT_LOG(error) << "SSLSetCertificate failed with error " << result << "." << std::endl;
+			}
+		}
+	}
+	processHandshake();
+}
+
+void SecureTransportContext::processHandshake() {
+	SWIFT_LOG_ASSERT(state_ == None || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+	OSStatus error = SSLHandshake(sslContext_.get());
+	if (error == errSSLWouldBlock) {
+		setState(Handshake);
+	}
+	else if (error == noErr) {
+		SWIFT_LOG(debug) << "TLS handshake successful." << std::endl;
+		setState(HandshakeDone);
+		onConnected();
+	}
+	else if (error == errSSLPeerAuthCompleted) {
+		SWIFT_LOG(debug) << "Received server certificate. Start verification." << std::endl;
+		setState(Handshake);
+		verifyServerCertificate();
+	}
+	else {
+		SWIFT_LOG(debug) << "Error returned from SSLHandshake call is " << error << "." << std::endl;
+		fatalError(nativeToTLSError(error), boost::make_shared<CertificateVerificationError>());
+	}
+}
+
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+void SecureTransportContext::verifyServerCertificate() {
+	SecTrustRef trust = NULL;
+	OSStatus error = SSLCopyPeerTrust(sslContext_.get(), &trust);
+	if (error != noErr) {
+		fatalError(boost::make_shared<TLSError>(), boost::make_shared<CertificateVerificationError>());
+		return;
+	}
+	boost::shared_ptr<SecTrust> trustRef = boost::shared_ptr<SecTrust>(trust, CFRelease);
+
+	if (checkCertificateRevocation_) {
+		error = SecTrustSetOptions(trust, kSecTrustOptionRequireRevPerCert | kSecTrustOptionFetchIssuerFromNet);
+		if (error != noErr) {
+			fatalError(boost::make_shared<TLSError>(), boost::make_shared<CertificateVerificationError>());
+			return;
+		}
+	}
+
+	SecTrustResultType trustResult;
+	error = SecTrustEvaluate(trust, &trustResult);
+	if (error != errSecSuccess) {
+		fatalError(boost::make_shared<TLSError>(), boost::make_shared<CertificateVerificationError>());
+		return;
+	}
+
+	OSStatus cssmResult = 0;
+	switch(trustResult) {
+		case kSecTrustResultUnspecified:
+			SWIFT_LOG(warning) << "Successful implicit validation. Result unspecified." << std::endl;
+			break;
+		case kSecTrustResultProceed:
+			SWIFT_LOG(warning) << "Validation resulted in explicitly trusted." << std::endl;
+			break;
+		case kSecTrustResultRecoverableTrustFailure:
+			SWIFT_LOG(warning) << "recoverable trust failure" << std::endl;
+			error = SecTrustGetCssmResultCode(trust, &cssmResult);
+			if (error == errSecSuccess) {
+				verificationError_ = CSSMErrorToVerificationError(cssmResult);
+				if (cssmResult == CSSMERR_TP_VERIFY_ACTION_FAILED || cssmResult == CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK ) {
+					// Find out the reason why the verification failed.
+					CFArrayRef certChain;
+					CSSM_TP_APPLE_EVIDENCE_INFO* statusChain;
+					error = SecTrustGetResult(trustRef.get(), &trustResult, &certChain, &statusChain);
+					if (error == errSecSuccess) {
+						boost::shared_ptr<CFArray> certChainRef = boost::shared_ptr<CFArray>(certChain, CFRelease);
+						for (CFIndex index = 0; index < CFArrayGetCount(certChainRef.get()); index++) {
+							for (CFIndex n = 0; n < statusChain[index].NumStatusCodes; n++) {
+								// Even though Secure Transport reported CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK on the whole certificate
+								// chain, the actual cause can be that a revocation check for a specific cert returned CSSMERR_TP_CERT_REVOKED.
+								if (!verificationError_ || verificationError_->getType() == CertificateVerificationError::RevocationCheckFailed) {
+									verificationError_ = CSSMErrorToVerificationError(statusChain[index].StatusCodes[n]);
+								}
+							}
+						}
+					}
+					else {
+
+					}
+				}
+			}
+			else {
+				verificationError_ = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::UnknownError);
+			}
+			break;
+		case kSecTrustResultOtherError:
+			verificationError_ = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::UnknownError);
+			break;
+		default:
+			SWIFT_LOG(warning) << "Unhandled trust result " << trustResult << "." << std::endl;
+			break;
+	}
+	
+	if (verificationError_) {
+		setState(Error);
+		SSLClose(sslContext_.get());
+		sslContext_.reset();
+		onError(boost::make_shared<TLSError>());
+	}
+	else {
+		// proceed with handshake
+		processHandshake();
+	}
+}
+
+#pragma clang diagnostic pop
+
+bool SecureTransportContext::setClientCertificate(CertificateWithKey::ref cert) {
+	CFArrayRef nativeClientChain = getClientCertificateChainAsCFArrayRef(cert);
+	if (nativeClientChain) {
+		clientCertificate_ = cert;
+		CFRelease(nativeClientChain);
+		return true;
+	}
+	else {
+		return false;
+	}
+}
+
+void SecureTransportContext::handleDataFromNetwork(const SafeByteArray& data) {
+	SWIFT_LOG(debug) << std::endl;
+	SWIFT_LOG_ASSERT(state_ == HandshakeDone || state_ == Handshake, error) << "current state '" << stateToString(state_) << " invalid." << std::endl;
+
+	append(readingBuffer_, data);
+
+	size_t bytesRead = 0;
+	OSStatus error = noErr;
+	SafeByteArray applicationData;
+
+	switch(state_) {
+		case None:
+			assert(false && "Invalid state 'None'.");
+			break;
+		case Handshake:
+			processHandshake();
+			break;
+		case HandshakeDone:
+			while (error == noErr) {
+				applicationData.resize(readingBuffer_.size());
+				error = SSLRead(sslContext_.get(), applicationData.data(), applicationData.size(), &bytesRead);
+				if (error == noErr) {
+					// Read successful.
+				}
+				else if (error == errSSLWouldBlock) {
+					// Secure Transport does not want more data.
+					break;
+				}
+				else {
+					SWIFT_LOG(error) << "SSLRead failed with error " << error << ", read bytes: " << bytesRead << "." << std::endl;
+					fatalError(boost::make_shared<TLSError>(), boost::make_shared<CertificateVerificationError>());
+					return;
+				}
+
+				if (bytesRead > 0) {
+					applicationData.resize(bytesRead);
+					onDataForApplication(applicationData);
+				}
+				else {
+					break;	
+				}
+			}
+			break;
+		case Error:
+			SWIFT_LOG(debug) << "Igoring received data in error state." << std::endl;
+			break;
+	}
+}
+
+
+void SecureTransportContext::handleDataFromApplication(const SafeByteArray& data) {
+	size_t processedBytes = 0;
+	OSStatus error = SSLWrite(sslContext_.get(), data.data(), data.size(), &processedBytes);
+	switch(error) {
+		case errSSLWouldBlock:
+			SWIFT_LOG(warning) << "Unexpected because the write callback does not block." << std::endl;
+			return;
+		case errSSLClosedGraceful:
+		case noErr:
+			return;
+		default:
+			SWIFT_LOG(warning) << "SSLWrite returned error code: " << error << ", processed bytes: " << processedBytes << std::endl;
+			fatalError(boost::make_shared<TLSError>(), boost::shared_ptr<CertificateVerificationError>());
+	}
+}
+
+std::vector<Certificate::ref> SecureTransportContext::getPeerCertificateChain() const {
+	std::vector<Certificate::ref> peerCertificateChain;
+
+	if (sslContext_) {
+			typedef boost::remove_pointer<SecTrustRef>::type SecTrust;
+			boost::shared_ptr<SecTrust> securityTrust;
+
+			SecTrustRef secTrust = NULL;;
+			OSStatus error = SSLCopyPeerTrust(sslContext_.get(), &secTrust);
+			if (error == noErr) {
+				securityTrust = boost::shared_ptr<SecTrust>(secTrust, CFRelease);
+
+				CFIndex chainSize = SecTrustGetCertificateCount(securityTrust.get());
+				for (CFIndex n = 0; n < chainSize; n++) {
+					SecCertificateRef certificate = SecTrustGetCertificateAtIndex(securityTrust.get(), n);
+					if (certificate) {
+						peerCertificateChain.push_back(boost::make_shared<SecureTransportCertificate>(certificate));
+					}
+				}
+			}
+			else {
+				SWIFT_LOG(warning) << "Failed to obtain peer trust structure; error = " << error << "." << std::endl;
+			}
+	}
+
+	return peerCertificateChain;
+}
+
+CertificateVerificationError::ref SecureTransportContext::getPeerCertificateVerificationError() const {
+	return verificationError_;
+}
+
+ByteArray SecureTransportContext::getFinishMessage() const {
+	SWIFT_LOG(warning) << "Access to TLS handshake finish message is not part of OS X Secure Transport APIs." << std::endl;
+	return ByteArray();
+}
+
+/**
+ *	This I/O callback simulates an asynchronous read to the read buffer of the context. If it is empty, it returns errSSLWouldBlock; else
+ *  the data within the buffer is returned.
+ */
+OSStatus SecureTransportContext::SSLSocketReadCallback(SSLConnectionRef connection, void *data, size_t *dataLength) {
+	SecureTransportContext* context = const_cast<SecureTransportContext*>(static_cast<const SecureTransportContext*>(connection));
+	OSStatus retValue = noErr;
+
+	if (context->readingBuffer_.size() < *dataLength) {
+		// Would block because Secure Transport is trying to read more data than there currently is available in the buffer.
+		*dataLength = 0;
+		retValue = errSSLWouldBlock;
+	}
+	else {
+		size_t bufferLen = *dataLength;
+		size_t copyToBuffer = bufferLen < context->readingBuffer_.size() ? bufferLen : context->readingBuffer_.size();
+
+		memcpy(data, context->readingBuffer_.data(), copyToBuffer);
+			
+		context->readingBuffer_ = SafeByteArray(context->readingBuffer_.data() + copyToBuffer, context->readingBuffer_.data() + context->readingBuffer_.size());
+		*dataLength = copyToBuffer;
+	}
+	return retValue;
+}
+
+OSStatus SecureTransportContext::SSLSocketWriteCallback(SSLConnectionRef connection, const void *data, size_t *dataLength) {
+	SecureTransportContext* context = const_cast<SecureTransportContext*>(static_cast<const SecureTransportContext*>(connection));
+	OSStatus retValue = noErr;
+	
+	SafeByteArray safeData;
+	safeData.resize(*dataLength);
+	memcpy(safeData.data(), data, safeData.size());
+	
+	context->onDataForNetwork(safeData);
+	return retValue;
+}
+
+boost::shared_ptr<TLSError> SecureTransportContext::nativeToTLSError(OSStatus /* error */) {
+	boost::shared_ptr<TLSError> swiftenError;
+	swiftenError = boost::make_shared<TLSError>();
+	return swiftenError;
+}
+
+boost::shared_ptr<CertificateVerificationError> SecureTransportContext::CSSMErrorToVerificationError(OSStatus resultCode) {
+	boost::shared_ptr<CertificateVerificationError> error;
+	switch(resultCode) {
+		case CSSMERR_TP_NOT_TRUSTED:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_NOT_TRUSTED" << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::Untrusted);
+			break;
+		case CSSMERR_TP_CERT_NOT_VALID_YET:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_NOT_VALID_YET" << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::NotYetValid);
+			break;
+		case CSSMERR_TP_CERT_EXPIRED:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_EXPIRED" << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::Expired);
+			break;
+		case CSSMERR_TP_CERT_REVOKED:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_CERT_REVOKED" << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::Revoked);
+			break;
+		case CSSMERR_TP_VERIFY_ACTION_FAILED:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_TP_VERIFY_ACTION_FAILED" << std::endl;
+			break;
+		case CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK" << std::endl;
+			if (checkCertificateRevocation_) {
+				error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed);
+			}
+			break;
+		case CSSMERR_APPLETP_OCSP_UNAVAILABLE:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_OCSP_UNAVAILABLE" << std::endl;
+			if (checkCertificateRevocation_) {
+				error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::RevocationCheckFailed);
+			}
+			break;
+		case CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE:
+			SWIFT_LOG(debug) << "CSSM result code: CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE" << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidPurpose);
+			break;
+		default:
+			SWIFT_LOG(warning) << "unhandled CSSM error: " << resultCode << ", CSSM_TP_BASE_TP_ERROR: " << CSSM_TP_BASE_TP_ERROR << std::endl;
+			error = boost::make_shared<CertificateVerificationError>(CertificateVerificationError::UnknownError);
+			break;
+	}
+	return error;
+}
+
+void SecureTransportContext::fatalError(boost::shared_ptr<TLSError> error, boost::shared_ptr<CertificateVerificationError> certificateError) {
+	setState(Error);
+	if (sslContext_) {
+		SSLClose(sslContext_.get());
+	}
+	verificationError_ = certificateError;
+	onError(error);
+}
+
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp
new file mode 100644
index 0000000..eb761e9
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#include <Swiften/TLS/SecureTransport/SecureTransportContextFactory.h>
+
+#include <Swiften/Base/Log.h>
+#include <Swiften/TLS/SecureTransport/SecureTransportContext.h>
+
+namespace Swift {
+
+SecureTransportContextFactory::SecureTransportContextFactory() : checkCertificateRevocation_(true), disconnectOnCardRemoval_(true) {
+
+}
+
+SecureTransportContextFactory::~SecureTransportContextFactory() {
+
+}
+
+bool SecureTransportContextFactory::canCreate() const {
+	return true;
+}
+
+TLSContext* SecureTransportContextFactory::createTLSContext(const TLSOptions& /* tlsOptions */) {
+	return new SecureTransportContext(checkCertificateRevocation_);
+}
+
+void SecureTransportContextFactory::setCheckCertificateRevocation(bool b) {
+	checkCertificateRevocation_ = b;
+}
+
+void SecureTransportContextFactory::setDisconnectOnCardRemoval(bool b) {
+	disconnectOnCardRemoval_ = b;
+	if (disconnectOnCardRemoval_) {
+		SWIFT_LOG(warning) << "Smart cards have not been tested yet" << std::endl;
+	}
+}
+
+}
diff --git a/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h
new file mode 100644
index 0000000..f490768
--- /dev/null
+++ b/Swiften/TLS/SecureTransport/SecureTransportContextFactory.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
+ */
+
+#pragma once
+
+#include <Swiften/TLS/TLSContextFactory.h>
+
+namespace Swift {
+
+class SecureTransportContextFactory : public TLSContextFactory {
+	public:
+		SecureTransportContextFactory();
+		virtual ~SecureTransportContextFactory();
+
+		virtual bool canCreate() const;
+
+		virtual TLSContext* createTLSContext(const TLSOptions& tlsOptions);
+		virtual void setCheckCertificateRevocation(bool b);
+		virtual void setDisconnectOnCardRemoval(bool b);
+
+	private:
+		bool checkCertificateRevocation_;
+		bool disconnectOnCardRemoval_;
+};
+
+}
-- 
cgit v0.10.2-6-g49f6