diff options
Diffstat (limited to 'Swiften/TLS/ServerIdentityVerifier.cpp')
-rw-r--r-- | Swiften/TLS/ServerIdentityVerifier.cpp | 83 |
1 files changed, 83 insertions, 0 deletions
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; +} + +} |