/* * Copyright (c) 2010-2016 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include #include #include namespace Swift { ServerIdentityVerifier::ServerIdentityVerifier(const JID& jid, IDNConverter* idnConverter, bool checkServer) : domainValid(false), checkServer_(checkServer) { domain = jid.getDomain(); boost::optional domainResult = idnConverter->getIDNAEncoded(domain); if (!!domainResult) { encodedDomain = *domainResult; domainValid = true; } } bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { bool hasSAN = false; if (certificate == nullptr) { return false; } // DNS names std::vector dnsNames = certificate->getDNSNames(); for (const auto& dnsName : dnsNames) { if (matchesDomain(dnsName)) { return true; } } hasSAN |= !dnsNames.empty(); std::string prefix = (checkServer_) ? "_xmpp-server." : "_xmpp-client."; // SRV names std::vector 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, prefix) && matchesDomain(srvName.substr(prefix.size(), srvName.npos))) { return true; } } hasSAN |= !srvNames.empty(); // XmppAddr std::vector xmppAddresses = certificate->getXMPPAddresses(); for (const auto& 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(); for (const auto& commonName : commonNames) { if (matchesDomain(commonName)) { return true; } } } return false; } bool ServerIdentityVerifier::matchesDomain(const std::string& s) const { if (!domainValid) { return false; } if (boost::starts_with(s, "*.")) { std::string matchString(s.substr(2, s.npos)); std::string matchDomain = encodedDomain; size_t dotIndex = matchDomain.find('.'); if (dotIndex != matchDomain.npos) { matchDomain = matchDomain.substr(dotIndex + 1, matchDomain.npos); } return boost::iequals(matchString, matchDomain); } else { return boost::iequals(s, encodedDomain); } } bool ServerIdentityVerifier::matchesAddress(const std::string& s) const { return boost::iequals(s, domain); } }