From 959a42d21fd70ea002da9afa7482194e8b6097e1 Mon Sep 17 00:00:00 2001
From: Tim Costen <tim.costen@isode.com>
Date: Tue, 5 Nov 2019 13:37:28 +0000
Subject: Handle xmpp-server SRV records

Update ServerIdentityVerifier with new boolean parameter
(defaulting to false) to its constructor. Use this to determine
whether to check for SRV records which start with "_xmpp-client."
(the default, for backwards compatibility), or "_xmpp-server.".

JIRA: SWIFT-424

Bug:

Release-notes:

Manual:

Test-information:
Added a couple of new unit tests to check operation when this parameter
is set true. All ServerIdentityVerifier unit tests run as before.

Change-Id: Icb1fee31b436292cd6b5e61bc86482d700e40332

diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp
index 226e94b..da116e5 100644
--- a/Swiften/TLS/ServerIdentityVerifier.cpp
+++ b/Swiften/TLS/ServerIdentityVerifier.cpp
@@ -12,7 +12,7 @@
 
 namespace Swift {
 
-ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter) : domainValid(false) {
+ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer) : domainValid(false), checkServer_(checkServer) {
     domain = jid.getDomain();
     boost::optional<std::string> domainResult = idnConverter->getIDNAEncoded(domain);
     if (!!domainResult) {
@@ -36,12 +36,14 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) {
     }
     hasSAN |= !dnsNames.empty();
 
+    std::string prefix = (checkServer_) ? "_xmpp-server." : "_xmpp-client.";
+
     // SRV names
     std::vector<std::string> srvNames = certificate->getSRVNames();
     for (const auto& 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 (boost::starts_with(srvName, "_xmpp-client.") && matchesDomain(srvName.substr(std::string("_xmpp-client.").size(), srvName.npos))) {
+        if (boost::starts_with(srvName, prefix) && matchesDomain(srvName.substr(prefix.size(), srvName.npos))) {
             return true;
         }
     }
diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h
index f40c683..f2cf46f 100644
--- a/Swiften/TLS/ServerIdentityVerifier.h
+++ b/Swiften/TLS/ServerIdentityVerifier.h
@@ -18,7 +18,7 @@ namespace Swift {
 
     class SWIFTEN_API ServerIdentityVerifier {
         public:
-            ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter);
+            ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer=false);
 
             bool certificateVerifies(Certificate::ref);
 
@@ -30,5 +30,6 @@ namespace Swift {
             std::string domain;
             std::string encodedDomain;
             bool domainValid;
+            bool checkServer_;
     };
 }
diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
index 30fe423..7379b69 100644
--- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
+++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp
@@ -35,6 +35,8 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
         CPPUNIT_TEST(testCertificateVerifies_WithMatchingInternationalXmppAddr);
         CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithoutSAN);
         CPPUNIT_TEST(testCertificateVerifies_WithMatchingCNWithSAN);
+        CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithServerExpected);
+        CPPUNIT_TEST(testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected);
         CPPUNIT_TEST_SUITE_END();
 
     public:
@@ -131,6 +133,24 @@ class ServerIdentityVerifierTest : public CppUnit::TestFixture {
             CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
         }
 
+        void testCertificateVerifies_WithMatchingSRVNameWithServerExpected() {
+            // Server-mode test which gets cert with "xmpp-server" SRV name
+            ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true);
+            SimpleCertificate::ref certificate(new SimpleCertificate());
+            certificate->addSRVName("_xmpp-server.bar.com");
+
+            CPPUNIT_ASSERT(testling.certificateVerifies(certificate));
+        }
+
+        void testCertificateVerifies_WithMatchingSRVNameWithClientUnexpected() {
+            // Server-mode test which gets cert with "xmpp-client" SRV name
+            ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get(), true);
+            SimpleCertificate::ref certificate(new SimpleCertificate());
+            certificate->addSRVName("_xmpp-client.bar.com");
+
+            CPPUNIT_ASSERT(!testling.certificateVerifies(certificate));
+        }
+
         void testCertificateVerifies_WithMatchingXmppAddr() {
             ServerIdentityVerifier testling(JID("foo@bar.com/baz"), idnConverter.get());
             SimpleCertificate::ref certificate(new SimpleCertificate());
-- 
cgit v0.10.2-6-g49f6