diff options
| author | Remko Tronçon <git@el-tramo.be> | 2010-11-10 21:02:12 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2010-11-11 12:50:12 (GMT) | 
| commit | 91b828a6e94f15c675e03baff4d45a7feb939eb9 (patch) | |
| tree | 2ca432e79b05b58235b0f791fc8e4a6dd0e96db7 | |
| parent | 2fec654b2345ba974b843a0868d580f9c12fdfea (diff) | |
| download | swift-91b828a6e94f15c675e03baff4d45a7feb939eb9.zip swift-91b828a6e94f15c675e03baff4d45a7feb939eb9.tar.bz2 | |
Added server identity check.
21 files changed, 456 insertions, 30 deletions
| @@ -18,7 +18,7 @@  				</dictionary>  				<dictionary>  					<key>org.eclipse.cdt.make.core.autoBuildTarget</key> -					<value>dist=1 Swift</value> +					<value>check=1 QA</value>  				</dictionary>  				<dictionary>  					<key>org.eclipse.cdt.make.core.buildArguments</key> @@ -54,7 +54,7 @@  				</dictionary>  				<dictionary>  					<key>org.eclipse.cdt.make.core.fullBuildTarget</key> -					<value>dist=1 Swift</value> +					<value>check=1 QA</value>  				</dictionary>  				<dictionary>  					<key>org.eclipse.cdt.make.core.stopOnError</key> diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index a199a84..9e6db5d 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -37,6 +37,7 @@  #include "Swiften/SASL/DIGESTMD5ClientAuthenticator.h"  #include "Swiften/Session/SessionStream.h"  #include "Swiften/TLS/CertificateTrustChecker.h" +#include "Swiften/TLS/ServerIdentityVerifier.h"  namespace Swift { @@ -330,16 +331,27 @@ void ClientSession::handleTLSEncrypted() {  	Certificate::ref certificate = stream->getPeerCertificate();  	boost::shared_ptr<CertificateVerificationError> verificationError = stream->getPeerCertificateVerificationError();  	if (verificationError) { -		if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificate, localJID.getDomain())) { +		checkTrustOrFinish(certificate, verificationError); +	} +	else { +		ServerIdentityVerifier identityVerifier(localJID); +		if (identityVerifier.certificateVerifies(certificate)) {  			continueAfterTLSEncrypted();  		}  		else { -			finishSession(verificationError); +			boost::shared_ptr<CertificateVerificationError> identityError(new CertificateVerificationError(CertificateVerificationError::InvalidServerIdentity)); +			checkTrustOrFinish(certificate, identityError);  		}  	} -	else { +} + +void ClientSession::checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr<CertificateVerificationError> error) { +	if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificate, localJID.getDomain())) {  		continueAfterTLSEncrypted();  	} +	else { +		finishSession(error); +	}  }  void ClientSession::continueAfterTLSEncrypted() { diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 6acd9a3..20573a0 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -121,6 +121,7 @@ namespace Swift {  			void handleStanzaAcked(boost::shared_ptr<Stanza> stanza);  			void ack(unsigned int handledStanzasCount);  			void continueAfterTLSEncrypted(); +			void checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr<CertificateVerificationError> error);  		private:  			JID localJID; diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 11e4992..74f3376 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -24,6 +24,8 @@  #include "Swiften/Elements/EnableStreamManagement.h"  #include "Swiften/Elements/IQ.h"  #include "Swiften/Elements/ResourceBind.h" +#include "Swiften/TLS/SimpleCertificate.h" +#include "Swiften/TLS/BlindCertificateTrustChecker.h"  using namespace Swift; @@ -33,6 +35,7 @@ class ClientSessionTest : public CppUnit::TestFixture {  		CPPUNIT_TEST(testStartTLS);  		CPPUNIT_TEST(testStartTLS_ServerError);  		CPPUNIT_TEST(testStartTLS_ConnectError); +		CPPUNIT_TEST(testStartTLS_InvalidIdentity);  		CPPUNIT_TEST(testAuthenticate);  		CPPUNIT_TEST(testAuthenticate_Unauthorized);  		CPPUNIT_TEST(testAuthenticate_NoValidAuthMechanisms); @@ -57,6 +60,11 @@ class ClientSessionTest : public CppUnit::TestFixture {  			server = boost::shared_ptr<MockSessionStream>(new MockSessionStream());  			sessionFinishedReceived = false;  			needCredentials = false; +			blindCertificateTrustChecker = new BlindCertificateTrustChecker(); +		} + +		void tearDown() { +			delete blindCertificateTrustChecker;  		}  		void testStart_Error() { @@ -71,6 +79,7 @@ class ClientSessionTest : public CppUnit::TestFixture {  		void testStartTLS() {  			boost::shared_ptr<ClientSession> session(createSession()); +			session->setCertificateTrustChecker(blindCertificateTrustChecker);  			session->start();  			server->receiveStreamStart();  			server->sendStreamStart(); @@ -116,6 +125,24 @@ class ClientSessionTest : public CppUnit::TestFixture {  			CPPUNIT_ASSERT(sessionFinishedError);  		} +		void testStartTLS_InvalidIdentity() { +			boost::shared_ptr<ClientSession> session(createSession()); +			session->start(); +			server->receiveStreamStart(); +			server->sendStreamStart(); +			server->sendStreamFeaturesWithStartTLS(); +			server->receiveStartTLS(); +			CPPUNIT_ASSERT(!server->tlsEncrypted); +			server->sendTLSProceed(); +			CPPUNIT_ASSERT(server->tlsEncrypted); +			server->onTLSEncrypted(); + +			CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState()); +			CPPUNIT_ASSERT(sessionFinishedReceived); +			CPPUNIT_ASSERT(sessionFinishedError); +			CPPUNIT_ASSERT_EQUAL(CertificateVerificationError::InvalidServerIdentity, boost::dynamic_pointer_cast<CertificateVerificationError>(sessionFinishedError)->getType()); +		} +  		void testAuthenticate() {  			boost::shared_ptr<ClientSession> session(createSession());  			session->start(); @@ -284,7 +311,7 @@ class ClientSessionTest : public CppUnit::TestFixture {  				}  				virtual Certificate::ref getPeerCertificate() const { -					return Certificate::ref(); +					return Certificate::ref(new SimpleCertificate());  				}  				virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const { @@ -429,6 +456,7 @@ class ClientSessionTest : public CppUnit::TestFixture {  		bool sessionFinishedReceived;  		bool needCredentials;  		boost::shared_ptr<Error> sessionFinishedError; +		BlindCertificateTrustChecker* blindCertificateTrustChecker;  };  CPPUNIT_TEST_SUITE_REGISTRATION(ClientSessionTest); diff --git a/Swiften/IDN/IDNA.cpp b/Swiften/IDN/IDNA.cpp new file mode 100644 index 0000000..a21ca63 --- /dev/null +++ b/Swiften/IDN/IDNA.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/IDN/IDNA.h" + +#include <stringprep.h> +#include <vector> +#include <idna.h> + +namespace Swift { + +String IDNA::getEncoded(const String& domain) { +	char* output; +	if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) { +		String result(output); +		free(output); +		return result; +	} +	else { +		return domain; +	} +} + +} diff --git a/Swiften/IDN/IDNA.h b/Swiften/IDN/IDNA.h new file mode 100644 index 0000000..cc4144b --- /dev/null +++ b/Swiften/IDN/IDNA.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Base/String.h" + +namespace Swift { +	class IDNA { +		public: +			static String getEncoded(const String& s); +	}; +} diff --git a/Swiften/StringPrep/SConscript b/Swiften/IDN/SConscript index 480d81a..bfdb42c 100644 --- a/Swiften/StringPrep/SConscript +++ b/Swiften/IDN/SConscript @@ -4,6 +4,7 @@ myenv = swiften_env.Clone()  myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"])  objects = myenv.StaticObject([ -			"StringPrep.cpp" +			"StringPrep.cpp", +			"IDNA.cpp",  		])  swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/StringPrep/StringPrep.cpp b/Swiften/IDN/StringPrep.cpp index ea084a5..d9e061e 100644 --- a/Swiften/StringPrep/StringPrep.cpp +++ b/Swiften/IDN/StringPrep.cpp @@ -4,7 +4,7 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#include "Swiften/StringPrep/StringPrep.h" +#include "Swiften/IDN/StringPrep.h"  #include <stringprep.h>  #include <vector> diff --git a/Swiften/StringPrep/StringPrep.h b/Swiften/IDN/StringPrep.h index 3b27efa..3b27efa 100644 --- a/Swiften/StringPrep/StringPrep.h +++ b/Swiften/IDN/StringPrep.h diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index f89ba29..cf5317e 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -9,7 +9,7 @@  #include <iostream>  #include "Swiften/JID/JID.h" -#include "Swiften/StringPrep/StringPrep.h" +#include "Swiften/IDN/StringPrep.h"  namespace Swift { diff --git a/Swiften/Network/DomainNameResolver.cpp b/Swiften/Network/DomainNameResolver.cpp index 854b97f..96c5165 100644 --- a/Swiften/Network/DomainNameResolver.cpp +++ b/Swiften/Network/DomainNameResolver.cpp @@ -6,23 +6,9 @@  #include "Swiften/Network/DomainNameResolver.h" -#include <idna.h> -  namespace Swift {  DomainNameResolver::~DomainNameResolver() {  } -String DomainNameResolver::getNormalized(const String& domain) { -	char* output; -	if (idna_to_ascii_8z(domain.getUTF8Data(), &output, 0) == IDNA_SUCCESS) { -		String result(output); -		free(output); -		return result; -	} -	else { -		return domain; -	} -} -  } diff --git a/Swiften/Network/DomainNameResolver.h b/Swiften/Network/DomainNameResolver.h index 4f8829c..cf9d521 100644 --- a/Swiften/Network/DomainNameResolver.h +++ b/Swiften/Network/DomainNameResolver.h @@ -21,8 +21,5 @@ namespace Swift {  			virtual boost::shared_ptr<DomainNameServiceQuery> createServiceQuery(const String& name) = 0;  			virtual boost::shared_ptr<DomainNameAddressQuery> createAddressQuery(const String& name) = 0; - -		protected: -			static String getNormalized(const String& domain);  	};  } diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp index 44c87e0..3f72466 100644 --- a/Swiften/Network/PlatformDomainNameResolver.cpp +++ b/Swiften/Network/PlatformDomainNameResolver.cpp @@ -18,6 +18,7 @@  #include <algorithm>  #include "Swiften/Base/String.h" +#include "Swiften/IDN/IDNA.h"  #include "Swiften/Network/HostAddress.h"  #include "Swiften/EventLoop/EventLoop.h"  #include "Swiften/Network/HostAddressPort.h" @@ -95,11 +96,11 @@ PlatformDomainNameResolver::PlatformDomainNameResolver(EventLoop* eventLoop) : e  }  boost::shared_ptr<DomainNameServiceQuery> PlatformDomainNameResolver::createServiceQuery(const String& name) { -	return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(getNormalized(name), eventLoop)); +	return boost::shared_ptr<DomainNameServiceQuery>(new PlatformDomainNameServiceQuery(IDNA::getEncoded(name), eventLoop));  }  boost::shared_ptr<DomainNameAddressQuery> PlatformDomainNameResolver::createAddressQuery(const String& name) { -	return boost::shared_ptr<DomainNameAddressQuery>(new AddressQuery(getNormalized(name), eventLoop)); +	return boost::shared_ptr<DomainNameAddressQuery>(new AddressQuery(IDNA::getEncoded(name), eventLoop));  }  } diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp index 5d0ee9a..551afd5 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -14,7 +14,7 @@  #include "Swiften/StringCodecs/Base64.h"  #include "Swiften/StringCodecs/HMACSHA1.h"  #include "Swiften/StringCodecs/PBKDF2.h" -#include "Swiften/StringPrep/StringPrep.h" +#include "Swiften/IDN/StringPrep.h"  namespace Swift { diff --git a/Swiften/SConscript b/Swiften/SConscript index df34e8b..1f762cb 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -125,7 +125,7 @@ if env["SCONS_STAGE"] == "build" :  	SConscript(dirs = [  			"Avatars",  			"Base", -			"StringPrep", +			"IDN",  			"SASL",  			"TLS",  			"EventLoop", @@ -266,6 +266,7 @@ if env["SCONS_STAGE"] == "build" :  			File("StringCodecs/UnitTest/HexifyTest.cpp"),  			File("StringCodecs/UnitTest/HMACSHA1Test.cpp"),  			File("StringCodecs/UnitTest/PBKDF2Test.cpp"), +			File("TLS/UnitTest/ServerIdentityVerifierTest.cpp"),  			File("VCards/UnitTest/VCardManagerTest.cpp"),  		]) diff --git a/Swiften/TLS/CertificateVerificationError.h b/Swiften/TLS/CertificateVerificationError.h index f1bd091..807df03 100644 --- a/Swiften/TLS/CertificateVerificationError.h +++ b/Swiften/TLS/CertificateVerificationError.h @@ -22,6 +22,7 @@ namespace Swift {  				PathLengthExceeded,  				InvalidSignature,  				InvalidCA, +				InvalidServerIdentity,  			};  			CertificateVerificationError(Type type = UnknownError) : type(type) {} diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript index f83e383..43f7db6 100644 --- a/Swiften/TLS/SConscript +++ b/Swiften/TLS/SConscript @@ -4,6 +4,7 @@ objects = swiften_env.StaticObject([  			"Certificate.cpp",  			"CertificateFactory.cpp",  			"CertificateTrustChecker.cpp", +			"ServerIdentityVerifier.cpp",  			"TLSContext.cpp",  			"TLSContextFactory.cpp",  		]) diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp new file mode 100644 index 0000000..05efd31 --- /dev/null +++ b/Swiften/TLS/ServerIdentityVerifier.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/TLS/ServerIdentityVerifier.h" + +#include "Swiften/Base/foreach.h" +#include "Swiften/IDN/IDNA.h" + +namespace Swift { + +ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid) { +	domain = jid.getDomain(); +	encodedDomain = IDNA::getEncoded(domain); +} + +bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { +	bool hasSAN = false; + +	// DNS names +	std::vector<String> dnsNames = certificate->getDNSNames(); +	foreach (const String& dnsName, dnsNames) { +		if (matchesDomain(dnsName)) { +			return true; +		} +	} +	hasSAN |= !dnsNames.empty(); + +	// SRV names +	std::vector<String> srvNames = certificate->getSRVNames(); +	foreach (const String& srvName, srvNames) { +		// Only match SRV names that begin with the service; this isn't required per +		// spec, but we're being purist about this. +		if (srvName.beginsWith("_xmpp-client.") && matchesDomain(srvName.getSubstring(String("_xmpp-client.").getUTF8Size(), srvName.npos()))) { +			return true; +		} +	} +	hasSAN |= !srvNames.empty(); + +	// XmppAddr +	std::vector<String> xmppAddresses = certificate->getXMPPAddresses(); +	foreach (const String& xmppAddress, xmppAddresses) { +		if (matchesAddress(xmppAddress)) { +			return true; +		} +	} +	hasSAN |= !xmppAddresses.empty(); + +	// CommonNames. Only check this if there was no SAN (according to spec). +	if (!hasSAN) { +		std::vector<String> commonNames = certificate->getCommonNames(); +		foreach (const String& commonName, commonNames) { +			if (matchesDomain(commonName)) { +				return true; +			} +		} +	} + +	return false; +} + +bool ServerIdentityVerifier::matchesDomain(const String& s) { +	if (s.beginsWith("*.")) { +		String matchString(s.getSubstring(2, s.npos())); +		String matchDomain = encodedDomain; +		int dotIndex = matchDomain.find('.'); +		if (dotIndex >= 0) { +			matchDomain = matchDomain.getSubstring(dotIndex + 1, matchDomain.npos()); +		} +		return matchString == matchDomain; +	} +	else { +		return s == encodedDomain; +	} +} + +bool ServerIdentityVerifier::matchesAddress(const String& s) { +	return s == domain; +} + +} diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h new file mode 100644 index 0000000..a001a5e --- /dev/null +++ b/Swiften/TLS/ServerIdentityVerifier.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" +#include "Swiften/TLS/Certificate.h" + +namespace Swift { +	class ServerIdentityVerifier { +		public: +			ServerIdentityVerifier(const JID& jid); + +			bool certificateVerifies(Certificate::ref); + +		private: +			bool matchesDomain(const String&); +			bool matchesAddress(const String&); + +		private: +			String domain; +			String encodedDomain; +	}; +} diff --git a/Swiften/TLS/SimpleCertificate.h b/Swiften/TLS/SimpleCertificate.h new file mode 100644 index 0000000..2db8291 --- /dev/null +++ b/Swiften/TLS/SimpleCertificate.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/TLS/Certificate.h" + +namespace Swift { +	class SimpleCertificate : public Certificate { +		public: +			typedef boost::shared_ptr<SimpleCertificate> ref; + +			void setSubjectName(const String& name) { +				subjectName = name; +			} + +			String getSubjectName() const { +				return subjectName; +			} + +			std::vector<String> getCommonNames() const { +				return commonNames; +			} + +			void addCommonName(const String& name) { +				commonNames.push_back(name); +			} + +			void addSRVName(const String& name) { +				srvNames.push_back(name); +			} + +			void addDNSName(const String& name) { +				dnsNames.push_back(name); +			} + +			void addXMPPAddress(const String& addr) { +				xmppAddresses.push_back(addr); +			} + +			std::vector<String> getSRVNames() const { +				return srvNames; +			} + +			std::vector<String> getDNSNames() const { +				return dnsNames; +			} + +			std::vector<String> getXMPPAddresses() const { +				return xmppAddresses; +			} + +			ByteArray toDER() const { +				return ByteArray(); +			} + +		private: +			void parse(); + +		private: +			String subjectName; +			std::vector<String> commonNames; +			std::vector<String> dnsNames; +			std::vector<String> xmppAddresses; +			std::vector<String> srvNames; +	}; +} diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp new file mode 100644 index 0000000..a7fdbad --- /dev/null +++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Base/ByteArray.h" + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <vector> + +#include "Swiften/TLS/ServerIdentityVerifier.h" +#include "Swiften/TLS/SimpleCertificate.h" + +using namespace Swift; + +class ServerIdentityVerifierTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(ServerIdentityVerifierTest); +		CPPUNIT_TEST(testCertificateVerifies_WithoutMatchingDNSName); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingDNSName); +		CPPUNIT_TEST(testCertificateVerifies_WithSecondMatchingDNSName); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingInternationalDNSName); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingDNSNameWithWildcard); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingDNSNameWithWildcardMatchingNoComponents); +		CPPUNIT_TEST(testCertificateVerifies_WithDNSNameWithWildcardMatchingTwoComponents); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithoutService); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithService); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithServiceAndWildcard); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithDifferentService); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingXmppAddr); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingXmppAddrWithWildcard); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingInternationalXmppAddr); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithoutSAN); +		CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithMatchingSAN); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void testCertificateVerifies_WithoutMatchingDNSName() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("foo.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingDNSName() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithSecondMatchingDNSName() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("foo.com"); +			certificate->addDNSName("bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingInternationalDNSName() { +			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7on.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("xn--tronon-zua.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingDNSNameWithWildcard() { +			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("*.bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingDNSNameWithWildcardMatchingNoComponents() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("*.bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithDNSNameWithWildcardMatchingTwoComponents() { +			ServerIdentityVerifier testling(JID("foo@xmpp.im.bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addDNSName("*.bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingSRVNameWithoutService() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addSRVName("bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingSRVNameWithService() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addSRVName("_xmpp-client.bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingSRVNameWithServiceAndWildcard() { +			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addSRVName("_xmpp-client.*.bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingSRVNameWithDifferentService() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addSRVName("_xmpp-server.bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingXmppAddr() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addXMPPAddress("bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingXmppAddrWithWildcard() { +			ServerIdentityVerifier testling(JID("foo@im.bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addXMPPAddress("*.bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingInternationalXmppAddr() { +			ServerIdentityVerifier testling(JID("foo@tron\xc3\xa7.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addXMPPAddress("tron\xc3\xa7.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingCNWithoutSAN() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addCommonName("bar.com"); + +			CPPUNIT_ASSERT(testling.certificateVerifies(certificate)); +		} + +		void testCertificateVerifies_WithMatchingCNWithMatchingSAN() { +			ServerIdentityVerifier testling(JID("foo@bar.com/baz")); +			SimpleCertificate::ref certificate(new SimpleCertificate()); +			certificate->addSRVName("foo.com"); +			certificate->addCommonName("bar.com"); + +			CPPUNIT_ASSERT(!testling.certificateVerifies(certificate)); +		} +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ServerIdentityVerifierTest); | 
 Swift
 Swift