diff options
author | Remko Tronçon <git@el-tramo.be> | 2010-11-07 20:07:06 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2010-11-07 21:27:17 (GMT) |
commit | a594eb3fef7e047d1eca7959d7734d4d10fd1eb7 (patch) | |
tree | f0c75a890caf231e18c963e6485d8c3fcf418324 /Swiften/Client | |
parent | 8cfb6d8f3492dd4180429f37dfb463b2fa48b0b8 (diff) | |
download | swift-contrib-a594eb3fef7e047d1eca7959d7734d4d10fd1eb7.zip swift-contrib-a594eb3fef7e047d1eca7959d7734d4d10fd1eb7.tar.bz2 |
Refactoring certificates & certificate checking.
Diffstat (limited to 'Swiften/Client')
-rw-r--r-- | Swiften/Client/Client.cpp | 9 | ||||
-rw-r--r-- | Swiften/Client/Client.h | 4 | ||||
-rw-r--r-- | Swiften/Client/ClientError.h | 14 | ||||
-rw-r--r-- | Swiften/Client/ClientSession.cpp | 20 | ||||
-rw-r--r-- | Swiften/Client/ClientSession.h | 10 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.cpp | 43 | ||||
-rw-r--r-- | Swiften/Client/CoreClient.h | 34 | ||||
-rw-r--r-- | Swiften/Client/UnitTest/ClientSessionTest.cpp | 4 |
8 files changed, 76 insertions, 62 deletions
diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 18cff9a..3b2c102 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -23,6 +23,7 @@ #include "Swiften/Disco/ClientDiscoManager.h" #include "Swiften/Client/NickResolver.h" #include "Swiften/Presence/SubscriptionManager.h" +#include "Swiften/TLS/BlindCertificateTrustChecker.h" namespace Swift { @@ -53,9 +54,13 @@ Client::Client(EventLoop* eventLoop, const JID& jid, const String& password, Sto entityCapsManager = new EntityCapsManager(capsManager, getStanzaChannel()); nickResolver = new NickResolver(jid.toBare(), roster, vcardManager, mucRegistry); + + blindCertificateTrustChecker = new BlindCertificateTrustChecker(); } Client::~Client() { + delete blindCertificateTrustChecker; + delete nickResolver; delete entityCapsManager; @@ -116,4 +121,8 @@ EntityCapsProvider* Client::getEntityCapsProvider() const { return entityCapsManager; } +void Client::setAlwaysTrustCertificates() { + setCertificateTrustChecker(blindCertificateTrustChecker); +} + } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index a6cf059..1a6700e 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -10,6 +10,7 @@ namespace Swift { class SoftwareVersionResponder; + class BlindCertificateTrustChecker; class XMPPRoster; class XMPPRosterImpl; class MUCManager; @@ -126,6 +127,8 @@ namespace Swift { return discoManager; } + void setAlwaysTrustCertificates(); + public: /** * This signal is emitted when a JID changes presence. @@ -156,5 +159,6 @@ namespace Swift { SubscriptionManager* subscriptionManager; MUCManager* mucManager; ClientDiscoManager* discoManager; + BlindCertificateTrustChecker* blindCertificateTrustChecker; }; } diff --git a/Swiften/Client/ClientError.h b/Swiften/Client/ClientError.h index 6ac8a6d..1c775e4 100644 --- a/Swiften/Client/ClientError.h +++ b/Swiften/Client/ClientError.h @@ -25,7 +25,19 @@ namespace Swift { SessionStartError, TLSError, ClientCertificateLoadError, - ClientCertificateError + ClientCertificateError, + + // Certificate verification errors + UnknownCertificateError, + CertificateExpiredError, + CertificateNotYetValidError, + CertificateSelfSignedError, + CertificateRejectedError, + CertificateUntrustedError, + InvalidCertificatePurposeError, + CertificatePathLengthExceededError, + InvalidCertificateSignatureError, + InvalidCAError, }; ClientError(Type type = UnknownError) : type_(type) {} diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index 7170a20..a199a84 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -11,7 +11,6 @@ #include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_generators.hpp> -#include "Swiften/TLS/SecurityError.h" #include "Swiften/Elements/ProtocolHeader.h" #include "Swiften/Elements/StreamFeatures.h" #include "Swiften/Elements/StartTLSRequest.h" @@ -37,6 +36,7 @@ #include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" #include "Swiften/SASL/DIGESTMD5ClientAuthenticator.h" #include "Swiften/Session/SessionStream.h" +#include "Swiften/TLS/CertificateTrustChecker.h" namespace Swift { @@ -50,7 +50,8 @@ ClientSession::ClientSession( needSessionStart(false), needResourceBind(false), needAcking(false), - authenticator(NULL) { + authenticator(NULL), + certificateTrustChecker(NULL) { } ClientSession::~ClientSession() { @@ -323,19 +324,18 @@ void ClientSession::sendCredentials(const String& password) { stream->writeElement(boost::shared_ptr<AuthRequest>(new AuthRequest(authenticator->getName(), authenticator->getResponse()))); } -void ClientSession::continueAfterSecurityError() { - checkState(WaitingForContinueAfterSecurityError); - continueAfterTLSEncrypted(); -} - void ClientSession::handleTLSEncrypted() { checkState(Encrypting); Certificate::ref certificate = stream->getPeerCertificate(); - boost::optional<CertificateVerificationError> verificationError = stream->getPeerCertificateVerificationError(); + boost::shared_ptr<CertificateVerificationError> verificationError = stream->getPeerCertificateVerificationError(); if (verificationError) { - state = WaitingForContinueAfterSecurityError; - onSecurityError(SecurityError(*verificationError)); + if (certificateTrustChecker && certificateTrustChecker->isCertificateTrusted(certificate, localJID.getDomain())) { + continueAfterTLSEncrypted(); + } + else { + finishSession(verificationError); + } } else { continueAfterTLSEncrypted(); diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index b14a6ec..6acd9a3 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -20,7 +20,7 @@ namespace Swift { class ClientAuthenticator; - class SecurityError; + class CertificateTrustChecker; class ClientSession : public boost::enable_shared_from_this<ClientSession> { public: @@ -31,7 +31,6 @@ namespace Swift { Compressing, WaitingForEncrypt, Encrypting, - WaitingForContinueAfterSecurityError, WaitingForCredentials, Authenticating, EnablingSessionManagement, @@ -83,11 +82,13 @@ namespace Swift { void sendCredentials(const String& password); void sendStanza(boost::shared_ptr<Stanza>); - void continueAfterSecurityError(); + + void setCertificateTrustChecker(CertificateTrustChecker* checker) { + certificateTrustChecker = checker; + } public: boost::signal<void ()> onNeedCredentials; - boost::signal<void (const SecurityError&)> onSecurityError; boost::signal<void ()> onInitialized; boost::signal<void (boost::shared_ptr<Swift::Error>)> onFinished; boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaReceived; @@ -132,5 +133,6 @@ namespace Swift { ClientAuthenticator* authenticator; boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; + CertificateTrustChecker* certificateTrustChecker; }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 4202483..7bde017 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -12,6 +12,7 @@ #include "Swiften/Network/BoostIOServiceThread.h" #include "Swiften/Client/ClientSession.h" #include "Swiften/TLS/PlatformTLSContextFactory.h" +#include "Swiften/TLS/CertificateVerificationError.h" #include "Swiften/Network/Connector.h" #include "Swiften/Network/BoostConnectionFactory.h" #include "Swiften/Network/BoostTimerFactory.h" @@ -23,7 +24,7 @@ namespace Swift { -CoreClient::CoreClient(EventLoop* eventLoop, const JID& jid, const String& password) : resolver_(eventLoop), jid_(jid), password_(password), eventLoop(eventLoop), disconnectRequested_(false), ignoreSecurityErrors(true) { +CoreClient::CoreClient(EventLoop* eventLoop, const JID& jid, const String& password) : resolver_(eventLoop), jid_(jid), password_(password), eventLoop(eventLoop), disconnectRequested_(false), certificateTrustChecker(NULL) { stanzaChannel_ = new ClientSessionStanzaChannel(); stanzaChannel_->onMessageReceived.connect(boost::ref(onMessageReceived)); stanzaChannel_->onPresenceReceived.connect(boost::ref(onPresenceReceived)); @@ -90,10 +91,10 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio sessionStream_->initialize(); session_ = ClientSession::create(jid_, sessionStream_); + session_->setCertificateTrustChecker(certificateTrustChecker); stanzaChannel_->setSession(session_); session_->onFinished.connect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); session_->onNeedCredentials.connect(boost::bind(&CoreClient::handleNeedCredentials, this)); - session_->onSecurityError.connect(boost::bind(&CoreClient::handleSecurityError, this, _1)); session_->start(); } } @@ -115,7 +116,6 @@ void CoreClient::setCertificate(const String& certificate) { } void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) { - session_->onSecurityError.disconnect(boost::bind(&CoreClient::handleSecurityError, this, _1)); session_->onFinished.disconnect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); session_->onNeedCredentials.disconnect(boost::bind(&CoreClient::handleNeedCredentials, this)); session_.reset(); @@ -180,6 +180,30 @@ void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) { break; } } + else if (boost::shared_ptr<CertificateVerificationError> verificationError = boost::dynamic_pointer_cast<CertificateVerificationError>(error)) { + switch(verificationError->getType()) { + case CertificateVerificationError::UnknownError: + clientError = ClientError(ClientError::UnknownCertificateError); + case CertificateVerificationError::Expired: + clientError = ClientError(ClientError::CertificateExpiredError); + case CertificateVerificationError::NotYetValid: + clientError = ClientError(ClientError::CertificateNotYetValidError); + case CertificateVerificationError::SelfSigned: + clientError = ClientError(ClientError::CertificateSelfSignedError); + case CertificateVerificationError::Rejected: + clientError = ClientError(ClientError::CertificateRejectedError); + case CertificateVerificationError::Untrusted: + clientError = ClientError(ClientError::CertificateUntrustedError); + case CertificateVerificationError::InvalidPurpose: + clientError = ClientError(ClientError::InvalidCertificatePurposeError); + case CertificateVerificationError::PathLengthExceeded: + clientError = ClientError(ClientError::CertificatePathLengthExceededError); + case CertificateVerificationError::InvalidSignature: + clientError = ClientError(ClientError::InvalidCertificateSignatureError); + case CertificateVerificationError::InvalidCA: + clientError = ClientError(ClientError::InvalidCAError); + } + } actualError = boost::optional<ClientError>(clientError); } onDisconnected(actualError); @@ -216,17 +240,8 @@ bool CoreClient::isActive() const { return session_ || connector_; } -void CoreClient::handleSecurityError(const SecurityError& error) { - if (ignoreSecurityErrors) { - session_->continueAfterSecurityError(); - } - else { - onSecurityError(error); - } -} - -void CoreClient::continueAfterSecurityError() { - session_->continueAfterSecurityError(); +void CoreClient::setCertificateTrustChecker(CertificateTrustChecker* checker) { + certificateTrustChecker = checker; } } diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index 3176a51..780201d 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -32,7 +32,7 @@ namespace Swift { class ClientSession; class BasicSessionStream; class EventLoop; - class SecurityError; + class CertificateTrustChecker; /** * The central class for communicating with an XMPP server. @@ -72,14 +72,6 @@ namespace Swift { void connect(const String& host); /** - * Instructs the client to continue initializing the session - * after a security error has occurred (and as such ignoring the error) - * - * \see onSecurityError - */ - void continueAfterSecurityError(); - - /** * Sends a message. */ void sendMessage(Message::ref); @@ -140,29 +132,10 @@ namespace Swift { return stanzaChannel_; } - /** - * Sets whether security errors should be ignored or not. - * - * If this is set to 'true', onSecurityError will not be called when a security - * error occurs, and connecting will continue. - * - * Defaults to true. - */ - void setIgnoreSecurityErrors(bool b) { - ignoreSecurityErrors = b; - } + void setCertificateTrustChecker(CertificateTrustChecker*); public: /** - * Emitted when an error occurred while establishing a secure connection. - * - * If the error is to be ignored, call continueAfterSecurityError(), otherwise call - * finish(). - * This signal is not emitted when setIgnoreSecurityErrors() is set to true. - */ - boost::signal<void (const SecurityError&)> onSecurityError; - - /** * Emitted when the client was disconnected from the network. * * If the connection was due to a non-recoverable error, the type @@ -217,7 +190,6 @@ namespace Swift { void handleNeedCredentials(); void handleDataRead(const String&); void handleDataWritten(const String&); - void handleSecurityError(const SecurityError& securityError); private: PlatformDomainNameResolver resolver_; @@ -237,6 +209,6 @@ namespace Swift { boost::shared_ptr<ClientSession> session_; String certificate_; bool disconnectRequested_; - bool ignoreSecurityErrors; + CertificateTrustChecker* certificateTrustChecker; }; } diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 43a8bf3..11e4992 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -287,8 +287,8 @@ class ClientSessionTest : public CppUnit::TestFixture { return Certificate::ref(); } - virtual boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const { - return boost::optional<CertificateVerificationError>(); + virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const { + return boost::shared_ptr<CertificateVerificationError>(); } virtual void addZLibCompression() { |