summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-11-10 21:02:12 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-11-11 12:50:12 (GMT)
commit91b828a6e94f15c675e03baff4d45a7feb939eb9 (patch)
tree2ca432e79b05b58235b0f791fc8e4a6dd0e96db7
parent2fec654b2345ba974b843a0868d580f9c12fdfea (diff)
downloadswift-91b828a6e94f15c675e03baff4d45a7feb939eb9.zip
swift-91b828a6e94f15c675e03baff4d45a7feb939eb9.tar.bz2
Added server identity check.
-rw-r--r--.project4
-rw-r--r--Swiften/Client/ClientSession.cpp18
-rw-r--r--Swiften/Client/ClientSession.h1
-rw-r--r--Swiften/Client/UnitTest/ClientSessionTest.cpp30
-rw-r--r--Swiften/IDN/IDNA.cpp27
-rw-r--r--Swiften/IDN/IDNA.h16
-rw-r--r--Swiften/IDN/SConscript (renamed from Swiften/StringPrep/SConscript)3
-rw-r--r--Swiften/IDN/StringPrep.cpp (renamed from Swiften/StringPrep/StringPrep.cpp)2
-rw-r--r--Swiften/IDN/StringPrep.h (renamed from Swiften/StringPrep/StringPrep.h)0
-rw-r--r--Swiften/JID/JID.cpp2
-rw-r--r--Swiften/Network/DomainNameResolver.cpp14
-rw-r--r--Swiften/Network/DomainNameResolver.h3
-rw-r--r--Swiften/Network/PlatformDomainNameResolver.cpp5
-rw-r--r--Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp2
-rw-r--r--Swiften/SConscript3
-rw-r--r--Swiften/TLS/CertificateVerificationError.h1
-rw-r--r--Swiften/TLS/SConscript1
-rw-r--r--Swiften/TLS/ServerIdentityVerifier.cpp83
-rw-r--r--Swiften/TLS/ServerIdentityVerifier.h30
-rw-r--r--Swiften/TLS/SimpleCertificate.h71
-rw-r--r--Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp170
21 files changed, 456 insertions, 30 deletions
diff --git a/.project b/.project
index 8ad2b97..17363c7 100644
--- a/.project
+++ b/.project
@@ -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);