summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Client/ClientSession.cpp')
-rw-r--r--Swiften/Client/ClientSession.cpp78
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();