diff options
Diffstat (limited to 'Swiften/Client/ClientSession.cpp')
-rw-r--r-- | Swiften/Client/ClientSession.cpp | 78 |
1 files changed, 46 insertions, 32 deletions
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 70f0398..500299a 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -1,4 +1,4 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2014 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. @@ -38,6 +38,8 @@ #include <Swiften/Elements/ResourceBind.h> #include <Swiften/SASL/PLAINClientAuthenticator.h> +#include <Swiften/SASL/EXTERNALClientAuthenticator.h> #include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> #include <Swiften/SASL/DIGESTMD5ClientAuthenticator.h> +#include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Session/SessionStream.h> #include <Swiften/TLS/CertificateTrustChecker.h> @@ -48,12 +50,19 @@ #endif +#define CHECK_STATE_OR_RETURN(a) \ + if (!checkState(a)) { return; } + namespace Swift { ClientSession::ClientSession( const JID& jid, - boost::shared_ptr<SessionStream> stream) : + boost::shared_ptr<SessionStream> stream, + IDNConverter* idnConverter, + CryptoProvider* crypto) : localJID(jid), state(Initial), stream(stream), + idnConverter(idnConverter), + crypto(crypto), allowPLAINOverNonTLS(false), useStreamCompression(true), @@ -101,9 +110,9 @@ void ClientSession::sendStanza(boost::shared_ptr<Stanza> stanza) { void ClientSession::handleStreamStart(const ProtocolHeader&) { - checkState(WaitingForStreamStart); + CHECK_STATE_OR_RETURN(WaitingForStreamStart); state = Negotiating; } -void ClientSession::handleElement(boost::shared_ptr<Element> element) { +void ClientSession::handleElement(boost::shared_ptr<ToplevelElement> element) { if (boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element)) { if (stanzaAckResponder_) { @@ -162,9 +171,9 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else { - std::cerr << "Warning: Got invalid ack from server" << std::endl; + SWIFT_LOG(warning) << "Got invalid ack from server"; } } else { - std::cerr << "Warning: Ignoring ack" << std::endl; + SWIFT_LOG(warning) << "Ignoring ack"; } } @@ -182,7 +191,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (StreamFeatures* streamFeatures = dynamic_cast<StreamFeatures*>(element.get())) { - if (!checkState(Negotiating)) { - return; - } + CHECK_STATE_OR_RETURN(Negotiating); if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption() && useTLS != NeverUseTLS) { @@ -200,4 +207,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { if (stream->hasTLSCertificate()) { if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { + authenticator = new EXTERNALClientAuthenticator(); state = Authenticating; stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); @@ -208,4 +216,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { + authenticator = new EXTERNALClientAuthenticator(); state = Authenticating; stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); @@ -214,12 +223,12 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { std::ostringstream s; ByteArray finishMessage; - bool plus = stream->isTLSEncrypted() && streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1-PLUS"); - if (plus) { + bool plus = streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1-PLUS"); + if (stream->isTLSEncrypted()) { finishMessage = stream->getTLSFinishMessage(); plus &= !finishMessage.empty(); } s << boost::uuids::random_generator()(); - SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus); - if (plus) { + SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), plus, idnConverter, crypto); + if (!finishMessage.empty()) { scramAuthenticator->setTLSChannelBindingData(finishMessage); } @@ -233,9 +242,9 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { onNeedCredentials(); } - else if (streamFeatures->hasAuthenticationMechanism("DIGEST-MD5") && DIGESTMD5ClientAuthenticator::canBeUsed()) { + else if (streamFeatures->hasAuthenticationMechanism("DIGEST-MD5") && crypto->isMD5AllowedForCrypto()) { std::ostringstream s; s << boost::uuids::random_generator()(); // FIXME: Host should probably be the actual host - authenticator = new DIGESTMD5ClientAuthenticator(localJID.getDomain(), s.str()); + authenticator = new DIGESTMD5ClientAuthenticator(localJID.getDomain(), s.str(), crypto); state = WaitingForCredentials; onNeedCredentials(); @@ -262,5 +271,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (boost::dynamic_pointer_cast<Compressed>(element)) { - checkState(Compressing); + CHECK_STATE_OR_RETURN(Compressing); state = WaitingForStreamStart; stream->addZLibCompression(); @@ -285,5 +294,5 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (AuthChallenge* challenge = dynamic_cast<AuthChallenge*>(element.get())) { - checkState(Authenticating); + CHECK_STATE_OR_RETURN(Authenticating); assert(authenticator); if (authenticator->setChallenge(challenge->getValue())) { @@ -295,8 +304,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { - checkState(Authenticating); - if (authenticator && !authenticator->setChallenge(authSuccess->getValue())) { - delete authenticator; - authenticator = NULL; + CHECK_STATE_OR_RETURN(Authenticating); + assert(authenticator); + if (!authenticator->setChallenge(authSuccess->getValue())) { finishSession(Error::ServerVerificationFailedError); } @@ -310,10 +318,8 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (dynamic_cast<AuthFailure*>(element.get())) { - delete authenticator; - authenticator = NULL; finishSession(Error::AuthenticationFailedError); } else if (dynamic_cast<TLSProceed*>(element.get())) { - checkState(WaitingForEncrypt); + CHECK_STATE_OR_RETURN(WaitingForEncrypt); state = Encrypting; stream->addTLSEncryption(); @@ -362,4 +368,5 @@ bool ClientSession::checkState(State state) { void ClientSession::sendCredentials(const SafeByteArray& password) { assert(WaitingForCredentials); + assert(authenticator); state = Authenticating; authenticator->setCredentials(localJID.getNode(), password); @@ -368,24 +375,24 @@ void ClientSession::sendCredentials(const SafeByteArray& password) { void ClientSession::handleTLSEncrypted() { - checkState(Encrypting); + CHECK_STATE_OR_RETURN(Encrypting); - Certificate::ref certificate = stream->getPeerCertificate(); + std::vector<Certificate::ref> certificateChain = stream->getPeerCertificateChain(); boost::shared_ptr<CertificateVerificationError> verificationError = stream->getPeerCertificateVerificationError(); if (verificationError) { - checkTrustOrFinish(certificate, verificationError); + checkTrustOrFinish(certificateChain, verificationError); } else { - ServerIdentityVerifier identityVerifier(localJID); - if (identityVerifier.certificateVerifies(certificate)) { + ServerIdentityVerifier identityVerifier(localJID, idnConverter); + if (!certificateChain.empty() && identityVerifier.certificateVerifies(certificateChain[0])) { continueAfterTLSEncrypted(); } else { - checkTrustOrFinish(certificate, boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidServerIdentity)); + checkTrustOrFinish(certificateChain, boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidServerIdentity)); } } } -void ClientSession::checkTrustOrFinish(Certificate::ref certificate, boost::shared_ptr<CertificateVerificationError> error) { - if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificate)) { +void ClientSession::checkTrustOrFinish(const std::vector<Certificate::ref>& certificateChain, boost::shared_ptr<CertificateVerificationError> error) { + if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificateChain)) { continueAfterTLSEncrypted(); } @@ -441,8 +448,15 @@ void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) { error_ = error; } + else { + SWIFT_LOG(warning) << "Session finished twice"; + } assert(stream->isOpen()); if (stanzaAckResponder_) { stanzaAckResponder_->handleAckRequestReceived(); } + if (authenticator) { + delete authenticator; + authenticator = NULL; + } stream->writeFooter(); stream->close(); |