summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2010-11-07 20:07:06 (GMT)
committerRemko Tronçon <git@el-tramo.be>2010-11-07 21:27:17 (GMT)
commita594eb3fef7e047d1eca7959d7734d4d10fd1eb7 (patch)
treef0c75a890caf231e18c963e6485d8c3fcf418324 /Swiften
parent8cfb6d8f3492dd4180429f37dfb463b2fa48b0b8 (diff)
downloadswift-a594eb3fef7e047d1eca7959d7734d4d10fd1eb7.zip
swift-a594eb3fef7e047d1eca7959d7734d4d10fd1eb7.tar.bz2
Refactoring certificates & certificate checking.
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Client/Client.cpp9
-rw-r--r--Swiften/Client/Client.h4
-rw-r--r--Swiften/Client/ClientError.h14
-rw-r--r--Swiften/Client/ClientSession.cpp20
-rw-r--r--Swiften/Client/ClientSession.h10
-rw-r--r--Swiften/Client/CoreClient.cpp43
-rw-r--r--Swiften/Client/CoreClient.h34
-rw-r--r--Swiften/Client/UnitTest/ClientSessionTest.cpp4
-rw-r--r--Swiften/Component/UnitTest/ComponentSessionTest.cpp4
-rw-r--r--Swiften/Examples/SendMessage/SendMessage.cpp1
-rw-r--r--Swiften/QA/ClientTest/ClientTest.cpp1
-rw-r--r--Swiften/Session/BasicSessionStream.cpp2
-rw-r--r--Swiften/Session/BasicSessionStream.h2
-rw-r--r--Swiften/Session/SessionStream.h2
-rw-r--r--Swiften/StreamStack/TLSLayer.cpp2
-rw-r--r--Swiften/StreamStack/TLSLayer.h2
-rw-r--r--Swiften/TLS/BlindCertificateTrustChecker.h18
-rw-r--r--Swiften/TLS/Certificate.cpp17
-rw-r--r--Swiften/TLS/Certificate.h48
-rw-r--r--Swiften/TLS/CertificateTrustChecker.cpp14
-rw-r--r--Swiften/TLS/CertificateTrustChecker.h21
-rw-r--r--Swiften/TLS/CertificateVerificationError.h4
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp65
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLCertificate.h60
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.cpp57
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.h2
-rw-r--r--Swiften/TLS/SConscript4
-rw-r--r--Swiften/TLS/SecurityError.cpp31
-rw-r--r--Swiften/TLS/SecurityError.h42
-rw-r--r--Swiften/TLS/TLSContext.cpp3
-rw-r--r--Swiften/TLS/TLSContext.h7
31 files changed, 305 insertions, 242 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() {
diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
index b6b57dd..4fe8e87 100644
--- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp
+++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
@@ -127,8 +127,8 @@ class ComponentSessionTest : 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() {
diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp
index fe020aa..567a351 100644
--- a/Swiften/Examples/SendMessage/SendMessage.cpp
+++ b/Swiften/Examples/SendMessage/SendMessage.cpp
@@ -58,6 +58,7 @@ int main(int argc, char* argv[]) {
}
client = new Swift::Client(&eventLoop, JID(jid), String(argv[argi++]));
+ client->setAlwaysTrustCertificates();
recipient = JID(argv[argi++]);
messageBody = std::string(argv[argi++]);
diff --git a/Swiften/QA/ClientTest/ClientTest.cpp b/Swiften/QA/ClientTest/ClientTest.cpp
index 4e48339..dd63056 100644
--- a/Swiften/QA/ClientTest/ClientTest.cpp
+++ b/Swiften/QA/ClientTest/ClientTest.cpp
@@ -58,6 +58,7 @@ int main(int, char**) {
client = new Swift::Client(&eventLoop, JID(jid), String(pass));
ClientXMLTracer* tracer = new ClientXMLTracer(client);
client->onConnected.connect(&handleConnected);
+ client->setAlwaysTrustCertificates();
client->connect();
{
diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp
index 65a241c..32424bc 100644
--- a/Swiften/Session/BasicSessionStream.cpp
+++ b/Swiften/Session/BasicSessionStream.cpp
@@ -89,7 +89,7 @@ Certificate::ref BasicSessionStream::getPeerCertificate() const {
return tlsLayer->getPeerCertificate();
}
-boost::optional<CertificateVerificationError> BasicSessionStream::getPeerCertificateVerificationError() const {
+boost::shared_ptr<CertificateVerificationError> BasicSessionStream::getPeerCertificateVerificationError() const {
return tlsLayer->getPeerCertificateVerificationError();
}
diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h
index 8addeb6..fbaa937 100644
--- a/Swiften/Session/BasicSessionStream.h
+++ b/Swiften/Session/BasicSessionStream.h
@@ -53,7 +53,7 @@ namespace Swift {
virtual void addTLSEncryption();
virtual bool isTLSEncrypted();
virtual Certificate::ref getPeerCertificate() const;
- virtual boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const;
+ virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
virtual void setWhitespacePingEnabled(bool);
diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h
index 1bf9090..d648f91 100644
--- a/Swiften/Session/SessionStream.h
+++ b/Swiften/Session/SessionStream.h
@@ -61,7 +61,7 @@ namespace Swift {
}
virtual Certificate::ref getPeerCertificate() const = 0;
- virtual boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const = 0;
+ virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const = 0;
boost::signal<void (const ProtocolHeader&)> onStreamStartReceived;
boost::signal<void (boost::shared_ptr<Element>)> onElementReceived;
diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp
index dd6660f..8cb06fc 100644
--- a/Swiften/StreamStack/TLSLayer.cpp
+++ b/Swiften/StreamStack/TLSLayer.cpp
@@ -42,7 +42,7 @@ Certificate::ref TLSLayer::getPeerCertificate() const {
return context->getPeerCertificate();
}
-boost::optional<CertificateVerificationError> TLSLayer::getPeerCertificateVerificationError() const {
+boost::shared_ptr<CertificateVerificationError> TLSLayer::getPeerCertificateVerificationError() const {
return context->getPeerCertificateVerificationError();
}
diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h
index 6fb825f..a69f789 100644
--- a/Swiften/StreamStack/TLSLayer.h
+++ b/Swiften/StreamStack/TLSLayer.h
@@ -25,7 +25,7 @@ namespace Swift {
bool setClientCertificate(const PKCS12Certificate&);
Certificate::ref getPeerCertificate() const;
- boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const;
+ boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
void writeData(const ByteArray& data);
void handleDataRead(const ByteArray& data);
diff --git a/Swiften/TLS/BlindCertificateTrustChecker.h b/Swiften/TLS/BlindCertificateTrustChecker.h
new file mode 100644
index 0000000..26a7f94
--- /dev/null
+++ b/Swiften/TLS/BlindCertificateTrustChecker.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include "Swiften/TLS/CertificateTrustChecker.h"
+
+namespace Swift {
+ class BlindCertificateTrustChecker : public CertificateTrustChecker {
+ public:
+ virtual bool isCertificateTrusted(Certificate::ref, const String&) {
+ return true;
+ }
+ };
+}
diff --git a/Swiften/TLS/Certificate.cpp b/Swiften/TLS/Certificate.cpp
new file mode 100644
index 0000000..7d61b22
--- /dev/null
+++ b/Swiften/TLS/Certificate.cpp
@@ -0,0 +1,17 @@
+/*
+ * 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/Certificate.h"
+
+namespace Swift {
+
+const char* Certificate::ID_ON_XMPPADDR_OID = "1.3.6.1.5.5.7.8.5";
+const char* Certificate::ID_ON_DNSSRV_OID = "1.3.6.1.5.5.7.8.7";
+
+Certificate::~Certificate() {
+}
+
+}
diff --git a/Swiften/TLS/Certificate.h b/Swiften/TLS/Certificate.h
index 21ea0bd..3a812a8 100644
--- a/Swiften/TLS/Certificate.h
+++ b/Swiften/TLS/Certificate.h
@@ -15,42 +15,16 @@ namespace Swift {
public:
typedef boost::shared_ptr<Certificate> ref;
- const String& getCommonName() const {
- return commonName;
- }
-
- void setCommonName(const String& commonName) {
- this->commonName = commonName;
- }
-
- const std::vector<String>& getSRVNames() const {
- return srvNames;
- }
-
- void addSRVName(const String& name) {
- srvNames.push_back(name);
- }
-
- const std::vector<String>& getDNSNames() const {
- return dnsNames;
- }
-
- void addDNSName(const String& name) {
- dnsNames.push_back(name);
- }
-
- const std::vector<String>& getXMPPAddresses() const {
- return xmppAddresses;
- }
-
- void addXMPPAddress(const String& addr) {
- xmppAddresses.push_back(addr);
- }
-
- private:
- String commonName;
- std::vector<String> dnsNames;
- std::vector<String> xmppAddresses;
- std::vector<String> srvNames;
+ virtual ~Certificate();
+
+ virtual String getCommonName() const = 0;
+ virtual std::vector<String> getSRVNames() const = 0;
+ virtual std::vector<String> getDNSNames() const = 0;
+ virtual std::vector<String> getXMPPAddresses() const = 0;
+
+ protected:
+ static const char* ID_ON_XMPPADDR_OID;
+ static const char* ID_ON_DNSSRV_OID;
+
};
}
diff --git a/Swiften/TLS/CertificateTrustChecker.cpp b/Swiften/TLS/CertificateTrustChecker.cpp
new file mode 100644
index 0000000..f4f921d
--- /dev/null
+++ b/Swiften/TLS/CertificateTrustChecker.cpp
@@ -0,0 +1,14 @@
+/*
+ * 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/CertificateTrustChecker.h"
+
+namespace Swift {
+
+CertificateTrustChecker::~CertificateTrustChecker() {
+}
+
+}
diff --git a/Swiften/TLS/CertificateTrustChecker.h b/Swiften/TLS/CertificateTrustChecker.h
new file mode 100644
index 0000000..070c4bb
--- /dev/null
+++ b/Swiften/TLS/CertificateTrustChecker.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/TLS/Certificate.h"
+
+namespace Swift {
+ class CertificateTrustChecker {
+ public:
+ virtual ~CertificateTrustChecker();
+
+ virtual bool isCertificateTrusted(Certificate::ref certificate, const String& domain) = 0;
+ };
+}
diff --git a/Swiften/TLS/CertificateVerificationError.h b/Swiften/TLS/CertificateVerificationError.h
index 76b4aff..f1bd091 100644
--- a/Swiften/TLS/CertificateVerificationError.h
+++ b/Swiften/TLS/CertificateVerificationError.h
@@ -6,8 +6,10 @@
#pragma once
+#include "Swiften/Base/Error.h"
+
namespace Swift {
- class CertificateVerificationError {
+ class CertificateVerificationError : public Error {
public:
enum Type {
UnknownError,
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp
new file mode 100644
index 0000000..5d9aac2
--- /dev/null
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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/OpenSSL/OpenSSLCertificate.h"
+
+#include <openssl/x509v3.h>
+
+#include "Swiften/Base/ByteArray.h"
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+namespace Swift {
+
+OpenSSLCertificate::OpenSSLCertificate(boost::shared_ptr<X509> cert) : cert(cert) {
+ // Common name
+ X509_NAME* subjectName = X509_get_subject_name(cert.get());
+ if (subjectName) {
+ int cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1);
+ if (cnLoc != -1) {
+ X509_NAME_ENTRY* cnEntry = X509_NAME_get_entry(subjectName, cnLoc);
+ ASN1_STRING* cnData = X509_NAME_ENTRY_get_data(cnEntry);
+ setCommonName(ByteArray(cnData->data, cnData->length).toString());
+ }
+ }
+
+ // subjectAltNames
+ int subjectAltNameLoc = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1);
+ if(subjectAltNameLoc != -1) {
+ X509_EXTENSION* extension = X509_get_ext(cert.get(), subjectAltNameLoc);
+ boost::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free);
+ boost::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free);
+ boost::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free);
+ for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) {
+ GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i);
+ if (generalName->type == GEN_OTHERNAME) {
+ OTHERNAME* otherName = generalName->d.otherName;
+ if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) {
+ // XmppAddr
+ if (otherName->value->type != V_ASN1_UTF8STRING) {
+ continue;
+ }
+ ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string;
+ addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString());
+ }
+ else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) {
+ // SRVName
+ if (otherName->value->type != V_ASN1_IA5STRING) {
+ continue;
+ }
+ ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string;
+ addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString());
+ }
+ }
+ else if (generalName->type == GEN_DNS) {
+ // DNSName
+ addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString());
+ }
+ }
+ }
+}
+
+}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h
new file mode 100644
index 0000000..4708120
--- /dev/null
+++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#pragma once
+
+#include <boost/shared_ptr.hpp>
+#include <openssl/ssl.h>
+
+#include "Swiften/Base/String.h"
+#include "Swiften/TLS/Certificate.h"
+
+namespace Swift {
+ class OpenSSLCertificate : public Certificate {
+ public:
+ OpenSSLCertificate(boost::shared_ptr<X509>);
+
+ String getCommonName() const {
+ return commonName;
+ }
+
+ std::vector<String> getSRVNames() const {
+ return srvNames;
+ }
+
+ std::vector<String> getDNSNames() const {
+ return dnsNames;
+ }
+
+ std::vector<String> getXMPPAddresses() const {
+ return xmppAddresses;
+ }
+
+ private:
+ void addSRVName(const String& name) {
+ srvNames.push_back(name);
+ }
+
+ void addDNSName(const String& name) {
+ dnsNames.push_back(name);
+ }
+
+ void addXMPPAddress(const String& addr) {
+ xmppAddresses.push_back(addr);
+ }
+
+ void setCommonName(const String& commonName) {
+ this->commonName = commonName;
+ }
+
+ private:
+ boost::shared_ptr<X509> cert;
+ String commonName;
+ std::vector<String> dnsNames;
+ std::vector<String> xmppAddresses;
+ std::vector<String> srvNames;
+ };
+}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
index c78d5a1..41c98c1 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
@@ -7,9 +7,9 @@
#include <vector>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
-#include <openssl/x509v3.h>
#include "Swiften/TLS/OpenSSL/OpenSSLContext.h"
+#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h"
#include "Swiften/TLS/PKCS12Certificate.h"
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -166,67 +166,20 @@ bool OpenSSLContext::setClientCertificate(const PKCS12Certificate& certificate)
Certificate::ref OpenSSLContext::getPeerCertificate() const {
boost::shared_ptr<X509> x509Cert(SSL_get_peer_certificate(handle_), X509_free);
if (x509Cert) {
- Certificate::ref certificate(new Certificate());
-
- // Common name
- X509_NAME* subjectName = X509_get_subject_name(x509Cert.get());
- if (subjectName) {
- int cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1);
- if (cnLoc != -1) {
- X509_NAME_ENTRY* cnEntry = X509_NAME_get_entry(subjectName, cnLoc);
- ASN1_STRING* cnData = X509_NAME_ENTRY_get_data(cnEntry);
- certificate->setCommonName(ByteArray(cnData->data, cnData->length).toString());
- }
- }
-
- // subjectAltNames
- int subjectAltNameLoc = X509_get_ext_by_NID(x509Cert.get(), NID_subject_alt_name, -1);
- if(subjectAltNameLoc != -1) {
- X509_EXTENSION* extension = X509_get_ext(x509Cert.get(), subjectAltNameLoc);
- boost::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free);
- boost::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free);
- boost::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free);
- for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) {
- GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i);
- if (generalName->type == GEN_OTHERNAME) {
- OTHERNAME* otherName = generalName->d.otherName;
- if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) {
- // XmppAddr
- if (otherName->value->type != V_ASN1_UTF8STRING) {
- continue;
- }
- ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string;
- certificate->addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString());
- }
- else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) {
- // SRVName
- if (otherName->value->type != V_ASN1_IA5STRING) {
- continue;
- }
- ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string;
- certificate->addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString());
- }
- }
- else if (generalName->type == GEN_DNS) {
- // DNSName
- certificate->addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString());
- }
- }
- }
- return certificate;
+ return Certificate::ref(new OpenSSLCertificate(x509Cert));
}
else {
return Certificate::ref();
}
}
-boost::optional<CertificateVerificationError> OpenSSLContext::getPeerCertificateVerificationError() const {
+boost::shared_ptr<CertificateVerificationError> OpenSSLContext::getPeerCertificateVerificationError() const {
int verifyResult = SSL_get_verify_result(handle_);
if (verifyResult != X509_V_OK) {
- return CertificateVerificationError(getVerificationErrorTypeForResult(verifyResult));
+ return boost::shared_ptr<CertificateVerificationError>(new CertificateVerificationError(getVerificationErrorTypeForResult(verifyResult)));
}
else {
- return boost::optional<CertificateVerificationError>();
+ return boost::shared_ptr<CertificateVerificationError>();
}
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h
index 31141a5..9cb287d 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h
@@ -28,7 +28,7 @@ namespace Swift {
void handleDataFromApplication(const ByteArray&);
Certificate::ref getPeerCertificate() const;
- boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const;
+ boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
private:
static void ensureLibraryInitialized();
diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript
index b84dbc0..bb33239 100644
--- a/Swiften/TLS/SConscript
+++ b/Swiften/TLS/SConscript
@@ -1,14 +1,16 @@
Import("swiften_env")
objects = swiften_env.StaticObject([
+ "Certificate.cpp",
+ "CertificateTrustChecker.cpp",
"TLSContext.cpp",
"TLSContextFactory.cpp",
- "SecurityError.cpp",
])
if swiften_env.get("HAVE_OPENSSL", 0) :
objects += swiften_env.StaticObject([
"OpenSSL/OpenSSLContext.cpp",
+ "OpenSSL/OpenSSLCertificate.cpp",
"OpenSSL/OpenSSLContextFactory.cpp",
])
diff --git a/Swiften/TLS/SecurityError.cpp b/Swiften/TLS/SecurityError.cpp
deleted file mode 100644
index 03aadf0..0000000
--- a/Swiften/TLS/SecurityError.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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/SecurityError.h"
-#include "Swiften/TLS/CertificateVerificationError.h"
-
-namespace Swift {
-
-SecurityError::SecurityError(Type type) : type(type) {
-}
-
-SecurityError::SecurityError(const CertificateVerificationError& verificationError) {
- type = UnknownError;
- switch(verificationError.getType()) {
- case CertificateVerificationError::UnknownError: type = UnknownError;
- case CertificateVerificationError::Expired: type = Expired;
- case CertificateVerificationError::NotYetValid: type = NotYetValid;
- case CertificateVerificationError::SelfSigned: type = SelfSigned;
- case CertificateVerificationError::Rejected: type = Rejected;
- case CertificateVerificationError::Untrusted: type = Untrusted;
- case CertificateVerificationError::InvalidPurpose: type = InvalidPurpose;
- case CertificateVerificationError::PathLengthExceeded: type = PathLengthExceeded;
- case CertificateVerificationError::InvalidSignature: type = InvalidSignature;
- case CertificateVerificationError::InvalidCA: type = InvalidCA;
- }
-}
-
-}
diff --git a/Swiften/TLS/SecurityError.h b/Swiften/TLS/SecurityError.h
deleted file mode 100644
index 55ac7d5..0000000
--- a/Swiften/TLS/SecurityError.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * Licensed under the GNU General Public License v3.
- * See Documentation/Licenses/GPLv3.txt for more information.
- */
-
-#pragma once
-
-namespace Swift {
- class CertificateVerificationError;
-
- class SecurityError {
- public:
- enum Type {
- // From CertificateVerificationError
- UnknownError,
- Expired,
- NotYetValid,
- SelfSigned,
- Rejected,
- Untrusted,
- InvalidPurpose,
- PathLengthExceeded,
- InvalidSignature,
- InvalidCA,
-
- // Identity verification
- InvalidIdentity,
- };
-
- SecurityError(Type type);
- SecurityError(const CertificateVerificationError& verificationError);
-
-
- Type getType() const {
- return type;
- }
-
- private:
- Type type;
- };
-}
diff --git a/Swiften/TLS/TLSContext.cpp b/Swiften/TLS/TLSContext.cpp
index 67fa903..008bfc0 100644
--- a/Swiften/TLS/TLSContext.cpp
+++ b/Swiften/TLS/TLSContext.cpp
@@ -8,9 +8,6 @@
namespace Swift {
-const char* TLSContext::ID_ON_XMPPADDR_OID = "1.3.6.1.5.5.7.8.5";
-const char* TLSContext::ID_ON_DNSSRV_OID = "1.3.6.1.5.5.7.8.7";
-
TLSContext::~TLSContext() {
}
diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h
index 2d05100..47f2697 100644
--- a/Swiften/TLS/TLSContext.h
+++ b/Swiften/TLS/TLSContext.h
@@ -7,6 +7,7 @@
#pragma once
#include "Swiften/Base/boost_bsignals.h"
+#include <boost/shared_ptr.hpp>
#include "Swiften/Base/ByteArray.h"
#include "Swiften/TLS/Certificate.h"
@@ -27,11 +28,7 @@ namespace Swift {
virtual void handleDataFromApplication(const ByteArray&) = 0;
virtual Certificate::ref getPeerCertificate() const = 0;
- virtual boost::optional<CertificateVerificationError> getPeerCertificateVerificationError() const = 0;
-
- protected:
- static const char* ID_ON_XMPPADDR_OID;
- static const char* ID_ON_DNSSRV_OID;
+ virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const = 0;
public:
boost::signal<void (const ByteArray&)> onDataForNetwork;