summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/QA/TLSTest')
-rw-r--r--Swiften/QA/TLSTest/CertificateErrorTest.cpp224
-rw-r--r--Swiften/QA/TLSTest/CertificateTest.cpp225
-rw-r--r--Swiften/QA/TLSTest/SConscript33
-rw-r--r--Swiften/QA/TLSTest/certificateChain.pem49
-rw-r--r--Swiften/QA/TLSTest/privateKey.pem40
5 files changed, 481 insertions, 90 deletions
diff --git a/Swiften/QA/TLSTest/CertificateErrorTest.cpp b/Swiften/QA/TLSTest/CertificateErrorTest.cpp
new file mode 100644
index 0000000..abd004e
--- /dev/null
+++ b/Swiften/QA/TLSTest/CertificateErrorTest.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015-2016 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/IDNConverter.h>
+#include <Swiften/IDN/PlatformIDNConverter.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() {
+ eventLoop_ = new DummyEventLoop();
+ boostIOServiceThread_ = new BoostIOServiceThread();
+ boostIOService_ = std::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) {
+ std::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(std::shared_ptr<TLSConnection> connection, const std::string& hostname, int port) {
+ 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() {
+ std::shared_ptr<TLSConnection> connection = std::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() {
+ std::shared_ptr<TLSConnection> connection = std::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+ TLSContext* context = connection->getTLSContext();
+
+ connectToServer(connection, "test5.tls-o-matic.com", 405);
+
+ CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+ CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+#if defined(HAVE_SCHANNEL)
+ // Windows SChannel API does not differentiate between expired and not yet valid.
+ CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Expired, context->getPeerCertificateVerificationError()->getType());
+#else
+ CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::NotYetValid, context->getPeerCertificateVerificationError()->getType());
+#endif
+ }
+
+ void testTLS_O_MaticCertificateFromThePast() {
+ std::shared_ptr<TLSConnection> connection = std::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+ TLSContext* context = connection->getTLSContext();
+
+ connectToServer(connection, "test6.tls-o-matic.com", 406);
+
+ CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+ CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+ CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Expired, context->getPeerCertificateVerificationError()->getType());
+ }
+
+ void testTLS_O_MaticCertificateFromUnknownCA() {
+ std::shared_ptr<TLSConnection> connection = std::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+ TLSContext* context = connection->getTLSContext();
+
+ connectToServer(connection, "test7.tls-o-matic.com", 407);
+
+ CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+ CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+ CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::Untrusted, context->getPeerCertificateVerificationError()->getType());
+ }
+
+ // test14.tls-o-matic.com:414
+ void testTLS_O_MaticCertificateWrongPurpose() {
+ std::shared_ptr<TLSConnection> connection = std::dynamic_pointer_cast<TLSConnection>(tlsConnectionFactory_->createConnection());
+ TLSContext* context = connection->getTLSContext();
+
+ connectToServer(connection, "test14.tls-o-matic.com", 414);
+
+ CPPUNIT_ASSERT_EQUAL(false, connectFinishedWithError_);
+ CPPUNIT_ASSERT(context->getPeerCertificateVerificationError());
+ CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::InvalidPurpose, context->getPeerCertificateVerificationError()->getType());
+ }
+
+ void testRevokedCertificateRevocationDisabled() {
+ tlsContextFactory_->setCheckCertificateRevocation(false);
+ std::shared_ptr<TLSConnection> connection = std::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);
+ std::shared_ptr<TLSConnection> connection = std::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());
+ 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_;
+ std::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/CertificateTest.cpp b/Swiften/QA/TLSTest/CertificateTest.cpp
index 2fa4c04..463ef9e 100644
--- a/Swiften/QA/TLSTest/CertificateTest.cpp
+++ b/Swiften/QA/TLSTest/CertificateTest.cpp
@@ -1,99 +1,166 @@
/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
+ * Copyright (c) 2010-2016 Isode Limited.
+ * All rights reserved.
+ * See the COPYING file for more information.
*/
-#include <Swiften/Base/ByteArray.h>
+#include <memory>
+
+#include <boost/bind.hpp>
#include <QA/Checker/IO.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
-#include <boost/bind.hpp>
+#include <Swiften/Base/ByteArray.h>
#include <Swiften/TLS/CertificateFactory.h>
-#include "SwifTools/Application/PlatformApplicationPathProvider.h"
+#include <Swiften/TLS/TLSContext.h>
+#include <Swiften/TLS/PlatformTLSFactories.h>
+#include <Swiften/TLS/TLSContextFactory.h>
+
+#include <SwifTools/Application/PlatformApplicationPathProvider.h>
using namespace Swift;
template<typename CERTIFICATE_FACTORY>
class CertificateTest : public CppUnit::TestFixture {
- CPPUNIT_TEST_SUITE(CertificateTest);
- CPPUNIT_TEST(testConstructFromDER);
- CPPUNIT_TEST(testToDER);
- //CPPUNIT_TEST(testGetSubjectName);
- CPPUNIT_TEST(testGetCommonNames);
- CPPUNIT_TEST(testGetSRVNames);
- CPPUNIT_TEST(testGetDNSNames);
- CPPUNIT_TEST(testGetXMPPAddresses);
- CPPUNIT_TEST_SUITE_END();
-
- public:
- void setUp() {
- pathProvider = new PlatformApplicationPathProvider("FileReadBytestreamTest");
- readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt"));
- certificateFactory = new CERTIFICATE_FACTORY();
- }
-
- void tearDown() {
- delete certificateFactory;
- delete pathProvider;
- }
-
- void testConstructFromDER() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getCommonNames()[0]);
- }
-
- void testToDER() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(certificateData, testling->toDER());
- }
+ CPPUNIT_TEST_SUITE(CertificateTest);
+ CPPUNIT_TEST(testConstructFromDER);
+ CPPUNIT_TEST(testToDER);
+ //CPPUNIT_TEST(testGetSubjectName);
+ CPPUNIT_TEST(testGetCommonNames);
+ CPPUNIT_TEST(testGetSRVNames);
+ CPPUNIT_TEST(testGetDNSNames);
+ CPPUNIT_TEST(testGetXMPPAddresses);
+ CPPUNIT_TEST(testCreateCertificateChain);
+ CPPUNIT_TEST(testCreateTlsContext);
+ CPPUNIT_TEST(testCreateTlsContextDisableSystemTAs);
+ CPPUNIT_TEST_SUITE_END();
+
+ public:
+ void setUp() {
+ pathProvider = std::make_unique<PlatformApplicationPathProvider>("FileReadBytestreamTest");
+ readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt"));
+ readByteArrayFromFile(chainData, (pathProvider->getExecutableDir() / "certificateChain.pem"));
+ readByteArrayFromFile(keyData, (pathProvider->getExecutableDir() / "privateKey.pem"));
+ certificateFactory = std::unique_ptr<CertificateFactory>(new CERTIFICATE_FACTORY());
+
+ PlatformTLSFactories* tlsFactories_ = new PlatformTLSFactories();
+ tlsContextFactory_ = tlsFactories_->getTLSContextFactory();
+ }
+
+ void testConstructFromDER() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getCommonNames()[0]);
+ }
+
+ void testToDER() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(certificateData, testling->toDER());
+ }
/*
- void testGetSubjectName() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(std::string("/description=114072-VMk8pdi1aj5kTXxO/C=US/ST=Colorado/L=Denver/O=Peter Saint-Andre/OU=StartCom Trusted Certificate Member/CN=*.jabber.org/emailAddress=hostmaster@jabber.org"), testling->getSubjectName());
- }
- */
-
- void testGetCommonNames() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getCommonNames().size()));
- CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getCommonNames()[0]);
- }
-
- void testGetSRVNames() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getSRVNames().size()));
- CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getSRVNames()[0]);
- }
-
- void testGetDNSNames() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(testling->getDNSNames().size()));
- CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getDNSNames()[0]);
- CPPUNIT_ASSERT_EQUAL(std::string("jabber.org"), testling->getDNSNames()[1]);
- }
-
- void testGetXMPPAddresses() {
- Certificate::ref testling = certificateFactory->createCertificateFromDER(certificateData);
-
- CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getXMPPAddresses().size()));
- CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getXMPPAddresses()[0]);
- }
-
- private:
- PlatformApplicationPathProvider* pathProvider;
- ByteArray certificateData;
- CertificateFactory* certificateFactory;
+ void testGetSubjectName() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData);
+
+ CPPUNIT_ASSERT_EQUAL(std::string("/description=114072-VMk8pdi1aj5kTXxO/C=US/ST=Colorado/L=Denver/O=Peter Saint-Andre/OU=StartCom Trusted Certificate Member/CN=*.jabber.org/emailAddress=hostmaster@jabber.org"), testling->getSubjectName());
+ }
+ */
+
+ void testGetCommonNames() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getCommonNames().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getCommonNames()[0]);
+ }
+
+ void testGetSRVNames() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getSRVNames().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getSRVNames()[0]);
+ }
+
+ void testGetDNSNames() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(testling->getDNSNames().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getDNSNames()[0]);
+ CPPUNIT_ASSERT_EQUAL(std::string("jabber.org"), testling->getDNSNames()[1]);
+ }
+
+ void testGetXMPPAddresses() {
+ Certificate::ref testling = Certificate::ref(certificateFactory->createCertificateFromDER(certificateData));
+
+ CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(testling->getXMPPAddresses().size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("*.jabber.org"), testling->getXMPPAddresses()[0]);
+ }
+
+ void testCreateCertificateChain() {
+ // The input chain contains a 2-certificate chain:
+ // the first certificate has:
+ // a subject of "O=messaging,CN=Mixer Messaging Configuration,CN=badger.isode.net"
+ // an issuer of "O=messaging, CN=New Messaging CA"
+ // the second certificate has:
+ // a subject of "O=messaging, CN=New Messaging CA"
+ // an issuer of "O=messaging, CN=New Messaging CA"
+ // i.e. it is a self-signed certificate
+ std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData);
+ CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size()));
+ CPPUNIT_ASSERT_EQUAL(std::string("Mixer Messaging Configuration"), chain[0]->getCommonNames()[0]);
+ CPPUNIT_ASSERT_EQUAL(std::string("badger.isode.net"), chain[0]->getCommonNames()[1]);
+ CPPUNIT_ASSERT_EQUAL(std::string("New Messaging CA"), chain[1]->getCommonNames()[0]);
+ }
+
+ void testCreateTlsContext() {
+ // Create 2-certificate chain as in previous test
+ std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData);
+ CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size()));
+
+ // Load private key from string
+ PrivateKey::ref key = certificateFactory->createPrivateKey(Swift::createSafeByteArray(keyData));
+ CPPUNIT_ASSERT(key);
+
+ const TLSOptions options;
+ auto context = tlsContextFactory_->createTLSContext(options, TLSContext::Mode::Server);
+ CPPUNIT_ASSERT(context);
+
+ context->setCertificateChain(chain);
+ context->setPrivateKey(key);
+ }
+
+ /**
+ * This test does not actually verify that use of system TAs has been disabled, it just provides
+ * a convenient mechanism for testing via a debugger.
+ **/
+ void testCreateTlsContextDisableSystemTAs() {
+ // Create 2-certificate chain as in previous test
+ std::vector<std::shared_ptr<Certificate>> chain = certificateFactory->createCertificateChain(chainData);
+ CPPUNIT_ASSERT_EQUAL(2,static_cast<int>(chain.size()));
+
+ // Load private key from string
+ PrivateKey::ref key = certificateFactory->createPrivateKey(Swift::createSafeByteArray(keyData));
+ CPPUNIT_ASSERT(key);
+
+ // Turn off use of system TAs
+ TLSOptions options;
+ options.ignoreSystemTrustAnchors = true;
+ auto context = tlsContextFactory_->createTLSContext(options, TLSContext::Mode::Server);
+ CPPUNIT_ASSERT(context);
+
+ context->setCertificateChain(chain);
+ context->setPrivateKey(key);
+ }
+ private:
+ std::unique_ptr<PlatformApplicationPathProvider> pathProvider;
+ ByteArray certificateData;
+ ByteArray chainData;
+ ByteArray keyData;
+ std::unique_ptr<CertificateFactory> certificateFactory;
+ TLSContextFactory* tlsContextFactory_;
};
#ifdef HAVE_OPENSSL
diff --git a/Swiften/QA/TLSTest/SConscript b/Swiften/QA/TLSTest/SConscript
index 18f6998..81e2471 100644
--- a/Swiften/QA/TLSTest/SConscript
+++ b/Swiften/QA/TLSTest/SConscript
@@ -3,14 +3,25 @@ import os
Import("env")
if env["TEST"] :
- myenv = env.Clone()
- myenv.MergeFlags(myenv["CHECKER_FLAGS"])
- myenv.MergeFlags(myenv["SWIFTOOLS_FLAGS"])
- myenv.MergeFlags(myenv["SWIFTEN_FLAGS"])
- myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"])
- myenv.MergeFlags(myenv["CPPUNIT_FLAGS"])
-
- tester = myenv.Program("TLSTest", [
- "CertificateTest.cpp",
- ])
- myenv.Test(tester, "system")
+ myenv = env.Clone()
+ myenv.MergeFlags(myenv["CHECKER_FLAGS"])
+ myenv.MergeFlags(myenv["SWIFTOOLS_FLAGS"])
+ myenv.MergeFlags(myenv["SWIFTEN_FLAGS"])
+ myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"])
+ myenv.MergeFlags(myenv["CPPUNIT_FLAGS"])
+ myenv.MergeFlags(myenv["GOOGLETEST_FLAGS"])
+
+ if myenv.get("HAVE_OPENSSL", 0) :
+ myenv.Append(CPPDEFINES = "HAVE_OPENSSL")
+ myenv.MergeFlags(myenv["OPENSSL_FLAGS"])
+ elif myenv.get("HAVE_SCHANNEL", 0) :
+ myenv.Append(CPPDEFINES = "HAVE_SCHANNEL")
+ elif myenv.get("HAVE_SECURETRANSPORT", 0) :
+ myenv.Append(CPPDEFINES = "HAVE_SECURETRANSPORT")
+
+ tester = myenv.Program("TLSTest", [
+ "CertificateTest.cpp",
+ # Reenable if either http://www.tls-o-matic.com/ is fixed or we have setup a replacement.
+ #"CertificateErrorTest.cpp"
+ ])
+ myenv.Test(tester, "system")
diff --git a/Swiften/QA/TLSTest/certificateChain.pem b/Swiften/QA/TLSTest/certificateChain.pem
new file mode 100644
index 0000000..cb3c0fb
--- /dev/null
+++ b/Swiften/QA/TLSTest/certificateChain.pem
@@ -0,0 +1,49 @@
+-----BEGIN CERTIFICATE-----
+MIIFFTCCA/2gAwIBAgIKXmMION+1bnZpIzANBgkqhkiG9w0BAQsFADAvMRIwEAYD
+VQQKEwltZXNzYWdpbmcxGTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwHhcNMTkw
+NzI5MTAxMjMxWhcNMjAwNzI5MTAxMjMxWjBXMRIwEAYDVQQKEwltZXNzYWdpbmcx
+JjAkBgNVBAMTHU1peGVyIE1lc3NhZ2luZyBDb25maWd1cmF0aW9uMRkwFwYDVQQD
+ExBiYWRnZXIuaXNvZGUubmV0MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC
+AYEAt42TMYe9oO4K6XmvST4kiy4cG+nmVDCtZRfAfF/A+1GQXTZ8OfLbPF5noLIF
+f1Jj6fBDA2HiKoLQWfNnIklNEzgPbOREuAuCe660sW1JzJFr5O5qYyf6bHKkYmRr
+CGHJ3G5kkXZOW3MhczPNHrTIUSL7lYLMZAcyWStkhgBy7lBuYtgDEXbdRH8OGgly
+XC39AAU93y7ynw6W3SorU6h9cwvS0Ho8KVemCXoE38WLeSrIw1ks+Kf1YQopg9O3
+2SkXp6Z9elG5Wk5Rh0L0H2XHnAvmodr9TW6rtrPkJZfLL+NfcnGtI6QKnvL8EhYG
+d+XiPOV8jyGAFRC1Be72wlF29Rw20zdoD3kAdeqBLWfL8H9mnQpebEIDj8Lmahub
++W4uuUqCG8NuY43lGJzJni9CFWvhD7ss1yVGz84zqRHu5iXNDncWH2luJT1gXvFW
+6mxcfe+AwSiZ8PrhDQZBfTyx7ob4Ozdc1d59XTPyckj2msnCo2ayg+jKaViDd4vz
+nNwhAgMBAAGjggGJMIIBhTAbBgNVHREEFDASghBiYWRnZXIuaXNvZGUubmV0MA4G
+A1UdDwEB/wQEAwIF4DAMBgNVHRMBAf8EAjAAMHQGA1UdHwRtMGswaaBnoGWGY2xk
+YXA6Ly9kaWFib2xvLmlzb2RlLm5ldDoxOTM4OS9jbj1OZXclMjBNZXNzYWdpbmcl
+MjBDQSxvPW1lc3NhZ2luZz9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFy
+eTCBkQYIKwYBBQUHAQEEgYQwgYEwfwYIKwYBBQUHMAKGc2xkYXA6Ly9kaWFib2xv
+Lmlzb2RlLm5ldDoxOTM4OS9jbj1OZXclMjBNZXNzYWdpbmclMjBDQSxvPW1lc3Nh
+Z2luZz9jQUNlcnRpZmljYXRlO2JpbmFyeSxjcm9zc0NlcnRpZmljYXRlUGFpcjti
+aW5hcnkwHQYDVR0OBBYEFFjf69BczlDoKiSBSvxCr9sy0OJ2MB8GA1UdIwQYMBaA
+FJvoU0Lwg8vVCEmEMoKy29zFo/Y7MA0GCSqGSIb3DQEBCwUAA4IBAQCS4zLVH98S
+Cl4gsmTkxM+lBsdzQ18ymA6p9ZRXGmJ405C9rN7um9XnbWwOHO6ach7zie2GxWLp
+KOYKjX/5Pjt7mPwG8eKepPAxDenzKw5TocjscR9VxBsym0oEkWHPQG+xSqySQGUw
+/5QoGy6v06yE8CZ7BKHPh91Jy7IjIDBxWaEtTAPyuH4i4DnsmA0/xSrJ7ez6g399
+YgqDnBInC63bYv5IDD1CmEr/0boBWpsOf50OC6JVhaPLAldwTAxLSOMBJ4q4onXC
+ZqDHY3EMRtwYEffNg9ZorXJwLmU3Lq/R3B9lC22XNPDFj/bZ5RpwVFtuN5HfeZzO
+aPbNoa0Nf+QB
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAgygAwIBAgIKSm7KkUZOigMk9zANBgkqhkiG9w0BAQsFADAvMRIwEAYD
+VQQKEwltZXNzYWdpbmcxGTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwHhcNMTYw
+MTI2MTU1MTU2WhcNMjYwMTI2MTU1MTU2WjAvMRIwEAYDVQQKEwltZXNzYWdpbmcx
+GTAXBgNVBAMTEE5ldyBNZXNzYWdpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDgcuX1s8EvO8GDHx7vSW9oeDnLUBx5E48Vb2qcJVc34ik1j6ZV
+d8/+tzmyy/BskFbaOJ0KD5XYOoI8TJtu28lASWZj1vAEZkfrDdBbKeb1BQhShMt2
+ICgzp7l4ubwd6rqCGHpD/f12RVhSlU3y6TniaK62a9RwJOpL/wvnCcJLPjaTw8om
+EY62EyUP+FymUbo3Rb3aWLM7avHl1/32pyzUgRzvZR63hlMHnlE5Sgc84j9KMwJH
+k+mCyXIGPc+yhL33ljR63Eoiqynyk0HPU6pWai1WKuSv6zMDPwnNaJA3VpLNUHsd
+eVe1GyOmPFePnhRPZYfC+Dk8lxDUmZfNFKZlAgMBAAGjQjBAMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSb6FNC8IPL1QhJhDKCstvc
+xaP2OzANBgkqhkiG9w0BAQsFAAOCAQEApgA5oupwTS2Ylt9mhS/TDX9wzR0DqnC5
+t9skgU9B/1MnzgqEMKGmuhRBiqDyr0jsPegBFI/CpTdIpakpSUrIvBTZADzkrkI+
+3k2jnpEv0vodaFIHQonDysq5h4bXsCSdSprdhiUa1GKFtnJ92Ro/2Uaw5UcqFPCg
+7kj7RmRVlAIynUAT81cefQww0HBFPN9SdBEpp6YP4P1u1x8GV0Bfq93r4G5jkiHN
+dA6xejk7RZK4mTH+K2aFpWoHCqMr7RAzV5UiXis4cFAmtv+5K/G7eazNx0Y+ODo4
+fweh+xW+dOXuP1lzW4DzwhEf/8tgFgI0jIvscPgdgHY7t9SQRJPYQQ==
+-----END CERTIFICATE-----
diff --git a/Swiften/QA/TLSTest/privateKey.pem b/Swiften/QA/TLSTest/privateKey.pem
new file mode 100644
index 0000000..5769000
--- /dev/null
+++ b/Swiften/QA/TLSTest/privateKey.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQDu1QdEBrcWj+D/
+rkmh++QSu2f0qlJ6Re8dEBtbqpxLiyYZ5IeaLts9szXabfSTchdJr/d0IyHfHQFS
+MGXDphKRaNnV5r//XuojUtorPyGe0DnZR2mp8S9adD7WxNjQLSQabr8PPPW8jrTx
+eJyIvYToLs9lx1IIDcr/3ZTuhBe2FK3Q173M5GF36Jb4yKWLPIfJ6auZjO5G9LZF
+3o2vVWxfc7ESnXvf3sAcWQPR08/ud0vLa3W3A8dC0XGk4BbE32cxvSuzWPHZd257
+HiHIW5pKLZXSMTu7fVNzBzDlo8BYQ5kad1ic+hhyIHBwTUO0Hz3EYP+9FG3TNG84
+65K9EeN3/Qw2P9468GHWAXqlzKFiIGikxYHGwvGd0CdegHtZ/TwIgVvpIDp6XB6U
+ez/TYPEiMCqX8TCIQi8FU3obEouMoPMHKM8vzQdSItZtPn6gD16M4xKdMm6fbvCD
+1okdcrWQnZo72pp8cfpS87KhP5z1ec9B/Wqysh4nrO35v8LXH60CAwEAAQKCAYEA
+jPDUJ9XaqAriWaBtvZTbpB5KG72DjLrGgB0oN/E36PDF3FPbniZ2pTOj3TI0OesD
+SS351uSAsZz5UZpUA6B2pq78llllBnvpqkzTiN/ppEH3UXzuIya8riGZj758wGVT
+P/II+CIeVlbU+wcVQTCuRSKSq9pzU2NoX5RQtmznXUFYzbzzOf2wc0WkCk7GOqPO
+8l3eMXBUkTUKd7L9Y/ICUVYBsh2To6pdLp1tPp9DvtNRvEq/HfCx34GgEg9YAHhg
+1rcPhh71M+TLYHznl5r/Jm1kIVrP3zyr1Bm5DDgZLE3GTN/oFumgXQyFCPyslup1
+gdZzS6W+fbeKxoPzjPOhzHVUxVZ/yqJH1xa1gs4ECQ4QXxdnr7yY1H5k5S8dabO5
+bEvXP+tH95HcAtAbvoRt+NC+xIJ39d6X7X2c4TPLoMIxDxmbEOCi9sg+4Ws+7E2s
+a/01fTZFT+lzuGBdp9Zz/tltDrwfYD0V+Q7qO0o/nJPINI+alAWlqQia00ZyZr4V
+AoHBAPxwCls99/LUzY7IJc0TV3ukk3sFi3rt58u8BE4+RaCtmgPMDj1l+EnaY9RW
+IOj91ECZ8+a23elNPZOkXKuYuJmJIpjOogOMM8r+Q4WF87xoRcdcjPh+PBat66HZ
++8mbm0VQ98cjxs0/kTRRayzz7UG9Onf1PhFfnw55sbMGItVssRDi9lRZJdSRU+CC
+qyAt8TUEH0lo+8AKbRn7xW4VHiD0hmLKDi4F713QLCPgmNlPQ/C60FTIRYS18gzK
+ARhuzwKBwQDyM9YiiFFQ3irGKtbj9W3bDHNmMl9YOHMYVXJAvh83Zcp80qRsShtw
+n3mV3vcVI+KNeZtKFUrJIYNTspNBP/w8U4lGGW+7tAt0dd0WY9m3ygnZg0GOHoaC
+uUusGicZR7FgbYlJzCiRhFhWcFyh0VOrm/k7OjznAvwfWbRKrlLvQdrWrLj7dyN3
+8n9lArq9ZxXJLpBXDUJ1R+F+hPIIIRKeYF2ULUFNE0U9Pj7SVTT7L7jPMWKnrVJh
+U4/hVAEHyMMCgcB4hCTtmpAdZmscl4E0ft9tMA0Y1nTYo2veYEzN7fzf0QGOfoTt
+2xjGaXTvko7zrPsAPH+szfDzyOR08Cst4SOAaXAS89N1TiIL74fc3y6V7FIj85N5
+rwqQ6UdtZdxHS/q9BQLGF9Z5drej+proQywqDmUzj+mp8bTF/GNRzMQkkFeYcEKZ
+0lW1PgyFStzX6BcX8HffXDeUX2Xm2cRP4dUYdqUR1NUgM8UrTI9GMZvHY4hUDVwY
+neRSj2qXoHkVaRECgcEArilkM9S+VF5Nd85aU/WqFzeuy7AxK2j8KmVXEQMlw1oo
+7vUxUsU/Ug77CTAZkFQLlxv49J629kZo/wiMJwFxyZdwQL4NwHXJPud6IZ2Pcz+P
+MZ/WxfFhXCMOLSVpNB5/iA18CVsLWQhH1XBay+mQNvijkVlhbeSRk6GXqZQNAwrh
+6Divk/Opx5jSzrnVulikK9SV6mMYhOk5VxcWS44sq0I0SFb6fAf9Y/qchfbLcExy
+olqqzFQvxtilv6v+SbCtAoHBAOXPUQ7VVuQZo4HA+CaQRYgQjGMxo4jeGiqrUAaX
+b+MpUjU7VxiSrfH3wFxCuMfW7dfQJKp7BAG8PCNzP1eW3+LhPkRSPAT0nwk/bQ5E
+N/n6NBqwsJFoTqueS0qDVdPichwKGvnIrraHSVeMeHZNv+TQdMjmTJ5AfBNCal9b
+7EPTFQO0Tj4GAB77fVRzewyVB+qXccoD2Gts9aWbY9FVGyhkvRenL7CcbgrzLZvt
+php/1crfbWtZ/3Nwz6L8LEdZHA==
+-----END PRIVATE KEY-----