From 91b828a6e94f15c675e03baff4d45a7feb939eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Wed, 10 Nov 2010 22:02:12 +0100 Subject: Added server identity check. diff --git a/.project b/.project index 8ad2b97..17363c7 100644 --- a/.project +++ b/.project @@ -18,7 +18,7 @@ org.eclipse.cdt.make.core.autoBuildTarget - dist=1 Swift + check=1 QA org.eclipse.cdt.make.core.buildArguments @@ -54,7 +54,7 @@ org.eclipse.cdt.make.core.fullBuildTarget - dist=1 Swift + check=1 QA org.eclipse.cdt.make.core.stopOnError 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 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 identityError(new CertificateVerificationError(CertificateVerificationError::InvalidServerIdentity)); + checkTrustOrFinish(certificate, identityError); } } - else { +} + +void ClientSession::checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr 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); void ack(unsigned int handledStanzasCount); void continueAfterTLSEncrypted(); + void checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr 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(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 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 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(sessionFinishedError)->getType()); + } + void testAuthenticate() { boost::shared_ptr 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 getPeerCertificateVerificationError() const { @@ -429,6 +456,7 @@ class ClientSessionTest : public CppUnit::TestFixture { bool sessionFinishedReceived; bool needCredentials; boost::shared_ptr 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 +#include +#include + +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/IDN/SConscript b/Swiften/IDN/SConscript new file mode 100644 index 0000000..bfdb42c --- /dev/null +++ b/Swiften/IDN/SConscript @@ -0,0 +1,10 @@ +Import("swiften_env") + +myenv = swiften_env.Clone() +myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) + +objects = myenv.StaticObject([ + "StringPrep.cpp", + "IDNA.cpp", + ]) +swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/IDN/StringPrep.cpp b/Swiften/IDN/StringPrep.cpp new file mode 100644 index 0000000..d9e061e --- /dev/null +++ b/Swiften/IDN/StringPrep.cpp @@ -0,0 +1,39 @@ +/* + * 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/StringPrep.h" + +#include +#include + +namespace Swift { + +static const int MAX_STRINGPREP_SIZE = 1024; + +const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { + switch(profile) { + case StringPrep::NamePrep: return stringprep_nameprep; break; + case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; break; + case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; break; + case StringPrep::SASLPrep: return stringprep_saslprep; break; + } + assert(false); + return 0; +} + +String StringPrep::getPrepared(const String& s, Profile profile) { + + std::vector input(s.getUTF8String().begin(), s.getUTF8String().end()); + input.resize(MAX_STRINGPREP_SIZE); + if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast(0), getLibIDNProfile(profile)) == 0) { + return String(&input[0]); + } + else { + return ""; + } +} + +} diff --git a/Swiften/IDN/StringPrep.h b/Swiften/IDN/StringPrep.h new file mode 100644 index 0000000..3b27efa --- /dev/null +++ b/Swiften/IDN/StringPrep.h @@ -0,0 +1,23 @@ +/* + * 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 StringPrep { + public: + enum Profile { + NamePrep, + XMPPNodePrep, + XMPPResourcePrep, + SASLPrep, + }; + + static String getPrepared(const String& s, Profile profile); + }; +} 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 #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 - 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 createServiceQuery(const String& name) = 0; virtual boost::shared_ptr 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 #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 PlatformDomainNameResolver::createServiceQuery(const String& name) { - return boost::shared_ptr(new PlatformDomainNameServiceQuery(getNormalized(name), eventLoop)); + return boost::shared_ptr(new PlatformDomainNameServiceQuery(IDNA::getEncoded(name), eventLoop)); } boost::shared_ptr PlatformDomainNameResolver::createAddressQuery(const String& name) { - return boost::shared_ptr(new AddressQuery(getNormalized(name), eventLoop)); + return boost::shared_ptr(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/StringPrep/SConscript b/Swiften/StringPrep/SConscript deleted file mode 100644 index 480d81a..0000000 --- a/Swiften/StringPrep/SConscript +++ /dev/null @@ -1,9 +0,0 @@ -Import("swiften_env") - -myenv = swiften_env.Clone() -myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) - -objects = myenv.StaticObject([ - "StringPrep.cpp" - ]) -swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/StringPrep/StringPrep.cpp b/Swiften/StringPrep/StringPrep.cpp deleted file mode 100644 index ea084a5..0000000 --- a/Swiften/StringPrep/StringPrep.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/StringPrep/StringPrep.h" - -#include -#include - -namespace Swift { - -static const int MAX_STRINGPREP_SIZE = 1024; - -const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { - switch(profile) { - case StringPrep::NamePrep: return stringprep_nameprep; break; - case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; break; - case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; break; - case StringPrep::SASLPrep: return stringprep_saslprep; break; - } - assert(false); - return 0; -} - -String StringPrep::getPrepared(const String& s, Profile profile) { - - std::vector input(s.getUTF8String().begin(), s.getUTF8String().end()); - input.resize(MAX_STRINGPREP_SIZE); - if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast(0), getLibIDNProfile(profile)) == 0) { - return String(&input[0]); - } - else { - return ""; - } -} - -} diff --git a/Swiften/StringPrep/StringPrep.h b/Swiften/StringPrep/StringPrep.h deleted file mode 100644 index 3b27efa..0000000 --- a/Swiften/StringPrep/StringPrep.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 StringPrep { - public: - enum Profile { - NamePrep, - XMPPNodePrep, - XMPPResourcePrep, - SASLPrep, - }; - - static String getPrepared(const String& s, Profile profile); - }; -} 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 dnsNames = certificate->getDNSNames(); + foreach (const String& dnsName, dnsNames) { + if (matchesDomain(dnsName)) { + return true; + } + } + hasSAN |= !dnsNames.empty(); + + // SRV names + std::vector 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 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 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 + +#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 ref; + + void setSubjectName(const String& name) { + subjectName = name; + } + + String getSubjectName() const { + return subjectName; + } + + std::vector 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 getSRVNames() const { + return srvNames; + } + + std::vector getDNSNames() const { + return dnsNames; + } + + std::vector getXMPPAddresses() const { + return xmppAddresses; + } + + ByteArray toDER() const { + return ByteArray(); + } + + private: + void parse(); + + private: + String subjectName; + std::vector commonNames; + std::vector dnsNames; + std::vector xmppAddresses; + std::vector 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 +#include +#include + +#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); -- cgit v0.10.2-6-g49f6