summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--BuildTools/SCons/SConscript.boot2
-rw-r--r--Swift/Controllers/MainController.cpp8
-rw-r--r--Swift/Controllers/MainController.h1
-rw-r--r--Swift/Controllers/UIInterfaces/MainWindow.h5
-rw-r--r--Swift/Controllers/UnitTest/MockMainWindow.h2
-rw-r--r--Swift/QtUI/CocoaUIHelpers.h20
-rw-r--r--Swift/QtUI/CocoaUIHelpers.mm43
-rw-r--r--Swift/QtUI/QtMainWindow.cpp26
-rw-r--r--Swift/QtUI/QtMainWindow.h3
-rw-r--r--Swift/QtUI/QtRosterHeader.cpp19
-rw-r--r--Swift/QtUI/QtRosterHeader.h4
-rw-r--r--Swift/QtUI/SConscript2
-rw-r--r--Swift/QtUI/WinUIHelpers.cpp61
-rw-r--r--Swift/QtUI/WinUIHelpers.h20
-rw-r--r--Swiften/Client/ClientSession.h4
-rw-r--r--Swiften/Client/ClientSessionStanzaChannel.cpp7
-rw-r--r--Swiften/Client/ClientSessionStanzaChannel.h1
-rw-r--r--Swiften/Client/CoreClient.cpp4
-rw-r--r--Swiften/Client/CoreClient.h5
-rw-r--r--Swiften/Client/DummyStanzaChannel.h4
-rw-r--r--Swiften/Client/StanzaChannel.h2
-rw-r--r--Swiften/Client/UnitTest/ClientSessionTest.cpp4
-rw-r--r--Swiften/Component/ComponentSessionStanzaChannel.h5
-rw-r--r--Swiften/Component/UnitTest/ComponentSessionTest.cpp4
-rw-r--r--Swiften/Session/BOSHSessionStream.cpp4
-rw-r--r--Swiften/Session/BOSHSessionStream.h1
-rw-r--r--Swiften/Session/BasicSessionStream.cpp4
-rw-r--r--Swiften/Session/BasicSessionStream.h2
-rw-r--r--Swiften/Session/SessionStream.h1
-rw-r--r--Swiften/StreamStack/TLSLayer.cpp4
-rw-r--r--Swiften/StreamStack/TLSLayer.h1
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.cpp18
-rw-r--r--Swiften/TLS/OpenSSL/OpenSSLContext.h1
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp29
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.h1
-rw-r--r--Swiften/TLS/TLSContext.h1
36 files changed, 320 insertions, 3 deletions
diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot
index a3a5c6d..098df0a 100644
--- a/BuildTools/SCons/SConscript.boot
+++ b/BuildTools/SCons/SConscript.boot
@@ -209,19 +209,19 @@ if env.get("coverage", 0) :
if env["PLATFORM"] == "win32" :
env.Append(LIBS = ["user32", "crypt32", "dnsapi", "iphlpapi", "ws2_32", "wsock32", "Advapi32"])
env.Append(CCFLAGS = ["/EHsc", "/nologo"])
# FIXME: We should find a decent solution for MSVS 10
if int(env["MSVS_VERSION"].split(".")[0]) < 10 :
env["LINKCOM"] = [env["LINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']
env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] :
- env.Append(FRAMEWORKS = ["IOKit", "AppKit", "SystemConfiguration"])
+ env.Append(FRAMEWORKS = ["IOKit", "AppKit", "SystemConfiguration", "Security", "SecurityInterface"])
# Testing
env["TEST_TYPE"] = env["test"]
if "check" in ARGUMENTS :
env["TEST_TYPE"] = "unit"
env["checker_report"] = ARGUMENTS.get("checker_report", False)
env["TEST"] = (env["TEST_TYPE"] != "none") or env.GetOption("clean")
if env.get("valgrind", 0) :
env["TEST_RUNNER"] = "valgrind --suppressions=QA/valgrind.supp -q --leak-check=full --track-origins=yes "
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 7bd89cb..40b4ded 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -66,18 +66,19 @@
#include <Swift/Controllers/ProfileController.h>
#include <Swift/Controllers/ContactEditController.h>
#include <Swift/Controllers/XMPPURIController.h>
#include "Swift/Controllers/AdHocManager.h"
#include <SwifTools/Idle/IdleDetector.h>
#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
#include <Swiften/FileTransfer/FileTransferManager.h>
#include <Swiften/Client/ClientXMLTracer.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swiften/Client/StanzaChannel.h>
namespace Swift {
static const std::string CLIENT_NAME = "Swift";
static const std::string CLIENT_NODE = "http://swift.im";
MainController::MainController(
EventLoop* eventLoop,
@@ -279,18 +280,19 @@ void MainController::handleConnected() {
profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);
srand(time(NULL));
int randomPort = 10000 + rand() % 10000;
client_->getFileTransferManager()->startListeningOnPort(randomPort);
ftOverview_ = new FileTransferOverview(client_->getFileTransferManager());
fileTransferListController_->setFileTransferOverview(ftOverview_);
rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_);
rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2));
rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this));
+ rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this));
contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_);
chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_);
client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1));
chatsManager_->setAvatarManager(client_->getAvatarManager());
eventWindowController_ = new EventWindowController(eventController_, uiFactory_);
@@ -321,18 +323,19 @@ void MainController::handleConnected() {
client_->requestRoster();
GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter());
discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
discoInfoRequest->send();
client_->getVCardManager()->requestOwnVCard();
rosterController_->setEnabled(true);
+ rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted());
profileController_->setAvailable(true);
contactEditController_->setAvailable(true);
/* Send presence later to catch all the incoming presences. */
sendPresence(statusTracker_->getNextPresence());
/* Enable chats last of all, so rejoining MUCs has the right sent presence */
chatsManager_->setOnline(true);
}
@@ -411,18 +414,23 @@ void MainController::handleInputIdleChanged(bool idle) {
if (statusTracker_->goAutoUnAway()) {
if (client_ && client_->isAvailable()) {
sendPresence(statusTracker_->getNextPresence());
}
}
}
}
}
+void MainController::handleShowCertificateRequest() {
+ std::vector<Certificate::ref> chain = client_->getStanzaChannel()->getPeerCertificateChain();
+ rosterController_->getWindow()->openCertificateDialog(chain);
+}
+
void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificatePath, CertificateWithKey::ref certificate, bool remember, bool loginAutomatically) {
jid_ = JID(username);
if (!jid_.isValid() || jid_.getNode().empty()) {
loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'"));
loginWindow_->setIsLoggingIn(false);
} else {
loginWindow_->setMessage("");
loginWindow_->setIsLoggingIn(true);
profileSettings_ = new ProfileSettingsProvider(username, settings_);
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 14de4eb..eeba9f3 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -97,18 +97,19 @@ namespace Swift {
void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText);
void handleDisconnected(const boost::optional<ClientError>& error);
void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, ErrorPayload::ref);
void handleEventQueueLengthChange(int count);
void handleVCardReceived(const JID& j, VCard::ref vCard);
void handleSettingChanged(const std::string& settingPath);
void handlePurgeSavedLoginRequest(const std::string& username);
void sendPresence(boost::shared_ptr<Presence> presence);
void handleInputIdleChanged(bool);
+ void handleShowCertificateRequest();
void logout();
void signOut();
void setReconnectTimer();
void resetPendingReconnects();
void resetCurrentError();
void performLoginFromCachedCredentials();
void reconnectAfterError();
void setManagersOffline();
diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h
index 93584e7..23328b4 100644
--- a/Swift/Controllers/UIInterfaces/MainWindow.h
+++ b/Swift/Controllers/UIInterfaces/MainWindow.h
@@ -4,19 +4,19 @@
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <string>
#include "Swiften/JID/JID.h"
#include "Swiften/Elements/StatusShow.h"
#include "Swiften/Elements/DiscoItems.h"
-
+#include "Swiften/TLS/Certificate.h"
#include "Swiften/Base/boost_bsignals.h"
#include <boost/shared_ptr.hpp>
namespace Swift {
class Roster;
class MainWindow {
public:
MainWindow(bool candelete = true) : canDelete_(candelete) {}
@@ -29,17 +29,20 @@ namespace Swift {
virtual void setMyNick(const std::string& name) = 0;
virtual void setMyJID(const JID& jid) = 0;
virtual void setMyAvatarPath(const std::string& path) = 0;
virtual void setMyStatusText(const std::string& status) = 0;
virtual void setMyStatusType(StatusShow::Type type) = 0;
/** Must be able to cope with NULL to clear the roster */
virtual void setRosterModel(Roster* roster) = 0;
virtual void setConnecting() = 0;
virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0;
+ virtual void setStreamEncryptionStatus(bool tlsInPlaceAndValid) = 0;
+ virtual void openCertificateDialog(const std::vector<Certificate::ref>& chain) = 0;
boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest;
boost::signal<void ()> onSignOutRequest;
+ boost::signal<void ()> onShowCertificateRequest;
private:
bool canDelete_;
};
}
diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h
index f773062..be1a932 100644
--- a/Swift/Controllers/UnitTest/MockMainWindow.h
+++ b/Swift/Controllers/UnitTest/MockMainWindow.h
@@ -16,13 +16,15 @@ namespace Swift {
virtual ~MockMainWindow() {};
virtual void setRosterModel(Roster* roster) {this->roster = roster;};
virtual void setMyNick(const std::string& /*name*/) {};;
virtual void setMyJID(const JID& /*jid*/) {};;
virtual void setMyAvatarPath(const std::string& /*path*/) {};
virtual void setMyStatusText(const std::string& /*status*/) {};
virtual void setMyStatusType(StatusShow::Type /*type*/) {};
virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {};
virtual void setConnecting() {};
+ virtual void setStreamEncryptionStatus(bool /*tlsInPlaceAndValid*/) {}
+ virtual void openCertificateDialog(const std::vector<Certificate::ref>& /*chain*/) {}
Roster* roster;
};
}
diff --git a/Swift/QtUI/CocoaUIHelpers.h b/Swift/QtUI/CocoaUIHelpers.h
new file mode 100644
index 0000000..25da0e3
--- /dev/null
+++ b/Swift/QtUI/CocoaUIHelpers.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/TLS/Certificate.h>
+#include <QWidget>
+
+namespace Swift {
+
+class CocoaUIHelpers {
+public:
+ static void displayCertificateChainAsSheet(QWidget* parent, const std::vector<Certificate::ref>& chain);
+};
+
+}
+
diff --git a/Swift/QtUI/CocoaUIHelpers.mm b/Swift/QtUI/CocoaUIHelpers.mm
new file mode 100644
index 0000000..3cb62f3
--- /dev/null
+++ b/Swift/QtUI/CocoaUIHelpers.mm
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "CocoaUIHelpers.h"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/type_traits.hpp>
+
+#include <Cocoa/Cocoa.h>
+
+#include <Security/Security.h>
+#include <SecurityInterface/SFCertificatePanel.h>
+
+#include <Swiften/Base/foreach.h>
+
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+namespace Swift {
+
+void CocoaUIHelpers::displayCertificateChainAsSheet(QWidget* parent, const std::vector<Certificate::ref>& chain) {
+ NSWindow* parentWindow = [((NSView*)parent->winId()) window];
+ NSMutableArray* certificates = [[NSMutableArray alloc] init];
+ foreach(Certificate::ref cert, chain) {
+ // convert chain to SecCertificateRef
+ ByteArray certAsDER = cert->toDER();
+ boost::shared_ptr<boost::remove_pointer<CFDataRef>::type> certData(CFDataCreate(NULL, certAsDER.data(), certAsDER.size()), CFRelease);
+ boost::shared_ptr<OpaqueSecCertificateRef> macCert(SecCertificateCreateWithData(NULL, certData.get()), CFRelease);
+
+ // add to NSMutable array
+ [certificates addObject: (id)macCert.get()];
+ }
+
+
+ SFCertificatePanel* panel = [[SFCertificatePanel alloc] init];
+ //[panel setPolicies:(id)policies.get()];
+ [panel beginSheetForWindow:parentWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL certificates:certificates showGroup:YES];
+ [certificates release];
+}
+
+}
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 9a3ce6b..547f22b 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -28,32 +28,40 @@
#include <Roster/QtRosterWidget.h>
#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swiften/Base/Platform.h>
+
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+#include <Swift/QtUI/CocoaUIHelpers.h>
+#elif defined(SWIFTEN_PLATFORM_WINDOWS)
+#include <Swift/QtUI/WinUIHelpers.h>
+#endif
namespace Swift {
QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStream, QtLoginWindow::QtMenus loginMenus) : QWidget(), MainWindow(false), loginMenus_(loginMenus) {
uiEventStream_ = uiEventStream;
settings_ = settings;
setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this);
mainLayout->setContentsMargins(0,0,0,0);
mainLayout->setSpacing(0);
meView_ = new QtRosterHeader(settings, this);
mainLayout->addWidget(meView_);
connect(meView_, SIGNAL(onChangeStatusRequest(StatusShow::Type, const QString&)), this, SLOT(handleStatusChanged(StatusShow::Type, const QString&)));
connect(meView_, SIGNAL(onEditProfileRequest()), this, SLOT(handleEditProfileRequest()));
+ connect(meView_, SIGNAL(onShowCertificateInfo()), this, SLOT(handleShowCertificateInfo()));
tabs_ = new QtTabWidget(this);
#if QT_VERSION >= 0x040500
tabs_->setDocumentMode(true);
#endif
tabs_->setTabPosition(QTabWidget::South);
mainLayout->addWidget(tabs_);
contactsTabWidget_ = new QWidget(this);
contactsTabWidget_->setContentsMargins(0, 0, 0, 0);
@@ -147,18 +155,22 @@ QtMainWindow::~QtMainWindow() {
void QtMainWindow::handleTabChanged(int index) {
settings_->storeSetting(QtUISettingConstants::CURRENT_ROSTER_TAB, index);
}
void QtMainWindow::handleToggleRequestDeliveryReceipts(bool enabled) {
settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, enabled);
}
+void QtMainWindow::handleShowCertificateInfo() {
+ onShowCertificateRequest();
+}
+
QtEventWindow* QtMainWindow::getEventWindow() {
return eventWindow_;
}
QtChatListWindow* QtMainWindow::getChatListWindow() {
return chatListWindow_;
}
void QtMainWindow::setRosterModel(Roster* roster) {
@@ -250,18 +262,32 @@ void QtMainWindow::setMyStatusText(const std::string& status) {
void QtMainWindow::setMyStatusType(StatusShow::Type type) {
meView_->setStatusType(type);
}
void QtMainWindow::setConnecting() {
meView_->setConnecting();
}
+void QtMainWindow::setStreamEncryptionStatus(bool tlsInPlaceAndValid) {
+ meView_->setStreamEncryptionStatus(tlsInPlaceAndValid);
+}
+
+void QtMainWindow::openCertificateDialog(const std::vector<Certificate::ref>& chain) {
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+ CocoaUIHelpers::displayCertificateChainAsSheet(this, chain);
+#elif defined(SWIFTEN_PLATFORM_WINDOWS)
+ WinUIHelpers::displayCertificateChainAsSheet(this,chain);
+#else
+#pragma message ("No certificate dialog available on this platform.")
+#endif
+}
+
void QtMainWindow::handleAdHocActionTriggered(bool /*checked*/) {
QAction* action = qobject_cast<QAction*>(sender());
assert(action);
DiscoItems::Item command = serverAdHocCommands_[serverAdHocCommandActions_.indexOf(action)];
uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestAdHocUIEvent(command)));
}
void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) {
serverAdHocCommands_ = commands;
diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h
index bef483d..c725d08 100644
--- a/Swift/QtUI/QtMainWindow.h
+++ b/Swift/QtUI/QtMainWindow.h
@@ -39,18 +39,20 @@ namespace Swift {
QtMainWindow(SettingsProvider*, UIEventStream* eventStream, QtLoginWindow::QtMenus loginMenus);
virtual ~QtMainWindow();
std::vector<QMenu*> getMenus() {return menus_;}
void setMyNick(const std::string& name);
void setMyJID(const JID& jid);
void setMyAvatarPath(const std::string& path);
void setMyStatusText(const std::string& status);
void setMyStatusType(StatusShow::Type type);
void setConnecting();
+ void setStreamEncryptionStatus(bool tlsInPlaceAndValid);
+ void openCertificateDialog(const std::vector<Certificate::ref>& chain);
QtEventWindow* getEventWindow();
QtChatListWindow* getChatListWindow();
void setRosterModel(Roster* roster);
void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands);
private slots:
void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage);
void handleSettingChanged(const std::string& settingPath);
void handleShowOfflineToggled(bool);
void handleJoinMUCAction();
@@ -58,18 +60,19 @@ namespace Swift {
void handleEditProfileAction();
void handleAddUserActionTriggered(bool checked);
void handleChatUserActionTriggered(bool checked);
void handleAdHocActionTriggered(bool checked);
void handleEventCountUpdated(int count);
void handleChatCountUpdated(int count);
void handleEditProfileRequest();
void handleTabChanged(int index);
void handleToggleRequestDeliveryReceipts(bool enabled);
+ void handleShowCertificateInfo();
private:
SettingsProvider* settings_;
QtLoginWindow::QtMenus loginMenus_;
std::vector<QMenu*> menus_;
QtRosterWidget* treeWidget_;
QtRosterHeader* meView_;
QAction* addUserAction_;
QAction* editUserAction_;
diff --git a/Swift/QtUI/QtRosterHeader.cpp b/Swift/QtUI/QtRosterHeader.cpp
index 98e75c2..2bce222 100644
--- a/Swift/QtUI/QtRosterHeader.cpp
+++ b/Swift/QtUI/QtRosterHeader.cpp
@@ -39,26 +39,39 @@ QtRosterHeader::QtRosterHeader(SettingsProvider* settings, QWidget* parent) : QW
avatarLabel_->setScaledContents(false);
topLayout->addWidget(avatarLabel_);
connect(avatarLabel_, SIGNAL(clicked()), this, SIGNAL(onEditProfileRequest()));
QVBoxLayout* rightLayout = new QVBoxLayout();
rightLayout->setSpacing(4);
rightLayout->setContentsMargins(4,0,0,0);
topLayout->addLayout(rightLayout);
+ QHBoxLayout* nameAndSecurityLayout = new QHBoxLayout();
+ nameAndSecurityLayout->setContentsMargins(4,0,0,0);
+
nameWidget_ = new QtNameWidget(settings, this);
connect(nameWidget_, SIGNAL(onChangeNickRequest()), this, SIGNAL(onEditProfileRequest()));
- rightLayout->addWidget(nameWidget_);
+ nameAndSecurityLayout->addWidget(nameWidget_);
+
+ securityInfoButton_ = new QToolButton(this);
+
+ securityInfoButton_->setStyleSheet("border: none; hover: {border: 1px} pressed {border: 1px}");
+ // TODO: replace with a more appropriate icon
+ securityInfoButton_->setIcon(QIcon(":/icons/certificate.png"));
+ connect(securityInfoButton_, SIGNAL(clicked()), this, SIGNAL(onShowCertificateInfo()));
+ nameAndSecurityLayout->addWidget(securityInfoButton_);
+ rightLayout->addLayout(nameAndSecurityLayout);
statusWidget_ = new QtStatusWidget(this);
connect(statusWidget_, SIGNAL(onChangeStatusRequest(StatusShow::Type, const QString&)), this, SLOT(handleChangeStatusRequest(StatusShow::Type, const QString&)));
rightLayout->addWidget(statusWidget_);
+
show();
}
void QtRosterHeader::handleChangeStatusRequest(StatusShow::Type type, const QString& text) {
emit onChangeStatusRequest(type, text);
}
void QtRosterHeader::setStatusText(const QString& statusMessage) {
statusWidget_->setStatusText(statusMessage);
@@ -66,18 +79,22 @@ void QtRosterHeader::setStatusText(const QString& statusMessage) {
void QtRosterHeader::setStatusType(StatusShow::Type type) {
statusWidget_->setStatusType(type);
}
void QtRosterHeader::setConnecting() {
statusWidget_->setConnecting();
}
+void QtRosterHeader::setStreamEncryptionStatus(bool tlsInPlace) {
+ securityInfoButton_->setVisible(tlsInPlace);
+}
+
void QtRosterHeader::setAvatar(const QString& path) {
QString scaledAvatarPath = QtScaledAvatarCache(avatarSize_).getScaledAvatarPath(path);
QPixmap avatar;
if (QFileInfo(scaledAvatarPath).exists()) {
avatar.load(scaledAvatarPath);
}
else {
avatar = QPixmap(":/icons/avatar.png").scaled(avatarSize_, avatarSize_, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
diff --git a/Swift/QtUI/QtRosterHeader.h b/Swift/QtUI/QtRosterHeader.h
index 050460c..1132ee3 100644
--- a/Swift/QtUI/QtRosterHeader.h
+++ b/Swift/QtUI/QtRosterHeader.h
@@ -5,18 +5,19 @@
*/
#pragma once
#include <QWidget>
#include <QLabel>
#include <QPixmap>
#include <QSize>
#include <QToolBar>
+#include <QToolButton>
#include <string>
#include "Swiften/Elements/StatusShow.h"
#include "QtTextEdit.h"
class QHBoxLayout;
namespace Swift {
@@ -31,25 +32,28 @@ namespace Swift {
QtRosterHeader(SettingsProvider* settings, QWidget* parent = NULL);
void setAvatar(const QString& path);
void setJID(const QString& jid);
void setNick(const QString& nick);
void setStatusText(const QString& statusMessage);
void setStatusType(StatusShow::Type type);
void setConnecting();
+ void setStreamEncryptionStatus(bool tlsInPlace);
signals:
void onChangeStatusRequest(StatusShow::Type showType, const QString &statusMessage);
void onEditProfileRequest();
+ void onShowCertificateInfo();
private slots:
void handleChangeStatusRequest(StatusShow::Type type, const QString &statusMessage);
private:
QString name_;
QtClickableLabel* avatarLabel_;
QtNameWidget* nameWidget_;
QtTextEdit* statusEdit_;
QToolBar* toolBar_;
QtStatusWidget* statusWidget_;
+ QToolButton* securityInfoButton_;
static const int avatarSize_;
};
}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index f944b43..4c53313 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -155,31 +155,33 @@ version_match = re.match("(\d+)\.(\d+).*", myenv["SWIFT_VERSION"])
myenv["SWIFT_VERSION_MAJOR"] = int(version_match.group(1)) if version_match else 0
myenv["SWIFT_VERSION_MINOR"] = int(version_match.group(2)) if version_match else 0
if env["PLATFORM"] == "win32" :
res = myenv.RES("#/Swift/resources/Windows/Swift.rc")
# For some reason, SCons isn't picking up the dependency correctly
# Adding it explicitly until i figure out why
myenv.Depends(res, "../Controllers/BuildVersion.h")
sources += [
+ "WinUIHelpers.cpp",
"CAPICertificateSelector.cpp",
"WindowsNotifier.cpp",
"#/Swift/resources/Windows/Swift.res"
]
if env["PLATFORM"] == "posix" :
sources += [
"FreeDesktopNotifier.cpp",
"QtDBUSURIHandler.cpp",
]
if env["PLATFORM"] == "darwin" :
sources += ["CocoaApplicationActivateHelper.mm"]
+ sources += ["CocoaUIHelpers.mm"]
if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" :
swiftProgram = myenv.Program("Swift", sources)
else :
swiftProgram = myenv.Program("swift", sources)
if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" :
openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp")
else :
diff --git a/Swift/QtUI/WinUIHelpers.cpp b/Swift/QtUI/WinUIHelpers.cpp
new file mode 100644
index 0000000..edd1120
--- /dev/null
+++ b/Swift/QtUI/WinUIHelpers.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include "WinUIHelpers.h"
+
+#include <windows.h>
+#include <Wincrypt.h>
+#include <cryptuiapi.h>
+#pragma comment(lib, "cryptui.lib")
+
+#include <boost/shared_ptr.hpp>
+
+#include <Swiften/Base/foreach.h>
+
+namespace Swift {
+
+void WinUIHelpers::displayCertificateChainAsSheet(QWidget* parent, const std::vector<Certificate::ref>& chain) {
+ if (chain.empty()) {
+ return;
+ }
+
+ // create certificate store to store the certificate chain in
+ HCERTSTORE chainStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL);
+ if (!chainStore) {
+ return;
+ }
+
+ ByteArray certAsDER = chain[0]->toDER();
+ boost::shared_ptr<const CERT_CONTEXT> certificate_chain;
+ {
+ PCCERT_CONTEXT certChain;
+ BOOL ok = CertAddCertificateContextToStore(chainStore, CertCreateCertificateContext(X509_ASN_ENCODING, certAsDER.data(), certAsDER.size()), CERT_STORE_ADD_ALWAYS, &certChain);
+ // maybe free the cert contex we created
+ if (!ok || !certChain) {
+ return;
+ }
+ certificate_chain.reset(certChain, CertFreeCertificateContext);
+ }
+
+ for (size_t i = 1; i < chain.size(); ++i) {
+ ByteArray certAsDER = chain[i]->toDER();
+ CertAddCertificateContextToStore(chainStore, CertCreateCertificateContext(X509_ASN_ENCODING, certAsDER.data(), certAsDER.size()), CERT_STORE_ADD_ALWAYS, NULL);
+ }
+
+ CRYPTUI_VIEWCERTIFICATE_STRUCT viewDialogProperties = { 0 };
+ viewDialogProperties.dwSize = sizeof(viewDialogProperties);
+ viewDialogProperties.hwndParent = parent->winId();
+ viewDialogProperties.dwFlags = CRYPTUI_DISABLE_EDITPROPERTIES | CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_REVOCATION_CHECKING;
+ viewDialogProperties.pCertContext = certificate_chain.get();
+ viewDialogProperties.cStores = 1;
+ viewDialogProperties.rghStores = &chainStore;
+ BOOL properties_changed;
+
+ // blocking call that shows modal certificate dialog
+ BOOL rv = ::CryptUIDlgViewCertificate(&viewDialogProperties, &properties_changed);
+}
+
+}
diff --git a/Swift/QtUI/WinUIHelpers.h b/Swift/QtUI/WinUIHelpers.h
new file mode 100644
index 0000000..d34d236
--- /dev/null
+++ b/Swift/QtUI/WinUIHelpers.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2012 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <Swiften/TLS/Certificate.h>
+#include <QWidget>
+
+namespace Swift {
+
+class WinUIHelpers {
+public:
+ static void displayCertificateChainAsSheet(QWidget* parent, const std::vector<Certificate::ref>& chain);
+};
+
+}
+
diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h
index 2205c8d..b67b23d 100644
--- a/Swiften/Client/ClientSession.h
+++ b/Swiften/Client/ClientSession.h
@@ -92,18 +92,22 @@ namespace Swift {
bool getStreamManagementEnabled() const {
return stanzaAckRequester_;
}
bool getRosterVersioningSupported() const {
return rosterVersioningSupported;
}
+ std::vector<Certificate::ref> getPeerCertificateChain() const {
+ return stream->getPeerCertificateChain();
+ }
+
const JID& getLocalJID() const {
return localJID;
}
void start();
void finish();
bool isFinished() const {
return getState() == Finished;
diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp
index 5dc0a42..8d85953 100644
--- a/Swiften/Client/ClientSessionStanzaChannel.cpp
+++ b/Swiften/Client/ClientSessionStanzaChannel.cpp
@@ -76,18 +76,25 @@ void ClientSessionStanzaChannel::handleStanza(boost::shared_ptr<Stanza> stanza)
bool ClientSessionStanzaChannel::getStreamManagementEnabled() const {
if (session) {
return session->getStreamManagementEnabled();
}
return false;
}
+std::vector<Certificate::ref> ClientSessionStanzaChannel::getPeerCertificateChain() const {
+ if (session) {
+ return session->getPeerCertificateChain();
+ }
+ return std::vector<Certificate::ref>();
+}
+
void ClientSessionStanzaChannel::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) {
onStanzaAcked(stanza);
}
void ClientSessionStanzaChannel::handleSessionInitialized() {
onAvailableChanged(true);
}
diff --git a/Swiften/Client/ClientSessionStanzaChannel.h b/Swiften/Client/ClientSessionStanzaChannel.h
index 47fb50e..2743a16 100644
--- a/Swiften/Client/ClientSessionStanzaChannel.h
+++ b/Swiften/Client/ClientSessionStanzaChannel.h
@@ -21,18 +21,19 @@ namespace Swift {
*/
class ClientSessionStanzaChannel : public StanzaChannel {
public:
void setSession(boost::shared_ptr<ClientSession> session);
void sendIQ(boost::shared_ptr<IQ> iq);
void sendMessage(boost::shared_ptr<Message> message);
void sendPresence(boost::shared_ptr<Presence> presence);
bool getStreamManagementEnabled() const;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const;
bool isAvailable() const {
return session && session->getState() == ClientSession::Initialized;
}
private:
std::string getNewIQID();
void send(boost::shared_ptr<Stanza> stanza);
void handleSessionFinished(boost::shared_ptr<Error> error);
diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp
index 8a922ba..36e27eb 100644
--- a/Swiften/Client/CoreClient.cpp
+++ b/Swiften/Client/CoreClient.cpp
@@ -354,18 +354,22 @@ void CoreClient::handleStanzaAcked(Stanza::ref stanza) {
bool CoreClient::isAvailable() const {
return stanzaChannel_->isAvailable();
}
bool CoreClient::getStreamManagementEnabled() const {
return stanzaChannel_->getStreamManagementEnabled();
}
+bool CoreClient::isStreamEncrypted() const {
+ return sessionStream_->isTLSEncrypted();
+}
+
StanzaChannel* CoreClient::getStanzaChannel() const {
return stanzaChannel_;
}
const JID& CoreClient::getJID() const {
if (session_) {
return session_->getLocalJID();
}
else {
diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h
index cafc634..985bf7f 100644
--- a/Swiften/Client/CoreClient.h
+++ b/Swiften/Client/CoreClient.h
@@ -121,18 +121,23 @@ namespace Swift {
* Checks whether stream management is enabled.
*
* If stream management is enabled, onStanzaAcked will be
* emitted when a stanza is received by the server.
*
* \see onStanzaAcked
*/
bool getStreamManagementEnabled() const;
+ /**
+ * Checks whether stream encryption (TLS) is currently active.
+ */
+ bool isStreamEncrypted() const;
+
StanzaChannel* getStanzaChannel() const;
/**
* Sets the certificate trust checker.
*
* This checker will be called when the server sends a
* TLS certificate that does not validate. If the trust checker
* says the certificate is trusted, then connecting will proceed;
* if not, the connection will end with an error.
diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h
index c2f3919..5cdedba 100644
--- a/Swiften/Client/DummyStanzaChannel.h
+++ b/Swiften/Client/DummyStanzaChannel.h
@@ -73,13 +73,17 @@ namespace Swift {
}
template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) {
if (sentStanzas.size() <= index) {
return boost::shared_ptr<T>();
}
return boost::dynamic_pointer_cast<T>(sentStanzas[index]);
}
+ std::vector<Certificate::ref> getPeerCertificateChain() const {
+ return std::vector<Certificate::ref>();
+ }
+
std::vector<boost::shared_ptr<Stanza> > sentStanzas;
bool available_;
};
}
diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h
index f1d76e0..5e85d3c 100644
--- a/Swiften/Client/StanzaChannel.h
+++ b/Swiften/Client/StanzaChannel.h
@@ -6,24 +6,26 @@
#pragma once
#include <Swiften/Base/boost_bsignals.h>
#include <boost/shared_ptr.hpp>
#include <Swiften/Queries/IQChannel.h>
#include <Swiften/Elements/Message.h>
#include <Swiften/Elements/Presence.h>
+#include <Swiften/TLS/Certificate.h>
namespace Swift {
class StanzaChannel : public IQChannel {
public:
virtual void sendMessage(boost::shared_ptr<Message>) = 0;
virtual void sendPresence(boost::shared_ptr<Presence>) = 0;
virtual bool isAvailable() const = 0;
virtual bool getStreamManagementEnabled() const = 0;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0;
boost::signal<void (bool /* isAvailable */)> onAvailableChanged;
boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived;
boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived;
boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked;
};
}
diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp
index 6793643..d1ca70a 100644
--- a/Swiften/Client/UnitTest/ClientSessionTest.cpp
+++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp
@@ -393,18 +393,22 @@ class ClientSessionTest : public CppUnit::TestFixture {
virtual ByteArray getTLSFinishMessage() const {
return ByteArray();
}
virtual Certificate::ref getPeerCertificate() const {
return Certificate::ref(new SimpleCertificate());
}
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const {
+ return std::vector<Certificate::ref>();
+ }
+
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const {
return boost::shared_ptr<CertificateVerificationError>();
}
virtual bool supportsZLibCompression() {
return true;
}
virtual void addZLibCompression() {
diff --git a/Swiften/Component/ComponentSessionStanzaChannel.h b/Swiften/Component/ComponentSessionStanzaChannel.h
index 45f90b5..4e133b8 100644
--- a/Swiften/Component/ComponentSessionStanzaChannel.h
+++ b/Swiften/Component/ComponentSessionStanzaChannel.h
@@ -25,18 +25,23 @@ namespace Swift {
void sendIQ(boost::shared_ptr<IQ> iq);
void sendMessage(boost::shared_ptr<Message> message);
void sendPresence(boost::shared_ptr<Presence> presence);
bool getStreamManagementEnabled() const {
return false;
}
+ std::vector<Certificate::ref> getPeerCertificateChain() const {
+ // TODO: actually implement this method
+ return std::vector<Certificate::ref>();
+ }
+
bool isAvailable() const {
return session && session->getState() == ComponentSession::Initialized;
}
private:
std::string getNewIQID();
void send(boost::shared_ptr<Stanza> stanza);
void handleSessionFinished(boost::shared_ptr<Error> error);
void handleStanza(boost::shared_ptr<Stanza> stanza);
diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
index da9ca7d..238d0b0 100644
--- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp
+++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp
@@ -132,18 +132,22 @@ class ComponentSessionTest : public CppUnit::TestFixture {
virtual ByteArray getTLSFinishMessage() const {
return ByteArray();
}
virtual Certificate::ref getPeerCertificate() const {
return Certificate::ref();
}
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const {
+ return std::vector<Certificate::ref>();
+ }
+
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const {
return boost::shared_ptr<CertificateVerificationError>();
}
virtual bool supportsZLibCompression() {
return true;
}
virtual void addZLibCompression() {
diff --git a/Swiften/Session/BOSHSessionStream.cpp b/Swiften/Session/BOSHSessionStream.cpp
index 237a394..6f15b84 100644
--- a/Swiften/Session/BOSHSessionStream.cpp
+++ b/Swiften/Session/BOSHSessionStream.cpp
@@ -123,18 +123,22 @@ void BOSHSessionStream::addTLSEncryption() {
bool BOSHSessionStream::isTLSEncrypted() {
return false;
}
Certificate::ref BOSHSessionStream::getPeerCertificate() const {
return Certificate::ref();
}
+std::vector<Certificate::ref> BOSHSessionStream::getPeerCertificateChain() const {
+ return std::vector<Certificate::ref>();
+}
+
boost::shared_ptr<CertificateVerificationError> BOSHSessionStream::getPeerCertificateVerificationError() const {
return boost::shared_ptr<CertificateVerificationError>();
}
ByteArray BOSHSessionStream::getTLSFinishMessage() const {
return ByteArray();
}
bool BOSHSessionStream::supportsZLibCompression() {
diff --git a/Swiften/Session/BOSHSessionStream.h b/Swiften/Session/BOSHSessionStream.h
index 497d391..99851b5 100644
--- a/Swiften/Session/BOSHSessionStream.h
+++ b/Swiften/Session/BOSHSessionStream.h
@@ -55,18 +55,19 @@ namespace Swift {
virtual void writeData(const std::string& data);
virtual bool supportsZLibCompression();
virtual void addZLibCompression();
virtual bool supportsTLSEncryption();
virtual void addTLSEncryption();
virtual bool isTLSEncrypted();
virtual Certificate::ref getPeerCertificate() const;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const;
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
virtual ByteArray getTLSFinishMessage() const;
virtual void setWhitespacePingEnabled(bool);
virtual void resetXMPPParser();
private:
void handleXMPPError();
diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp
index b49ffc9..cbe85ab 100644
--- a/Swiften/Session/BasicSessionStream.cpp
+++ b/Swiften/Session/BasicSessionStream.cpp
@@ -123,18 +123,22 @@ void BasicSessionStream::addTLSEncryption() {
bool BasicSessionStream::isTLSEncrypted() {
return tlsLayer;
}
Certificate::ref BasicSessionStream::getPeerCertificate() const {
return tlsLayer->getPeerCertificate();
}
+std::vector<Certificate::ref> BasicSessionStream::getPeerCertificateChain() const {
+ return tlsLayer->getPeerCertificateChain();
+}
+
boost::shared_ptr<CertificateVerificationError> BasicSessionStream::getPeerCertificateVerificationError() const {
return tlsLayer->getPeerCertificateVerificationError();
}
ByteArray BasicSessionStream::getTLSFinishMessage() const {
return tlsLayer->getContext()->getFinishMessage();
}
bool BasicSessionStream::supportsZLibCompression() {
diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h
index e1f32f4..084a191 100644
--- a/Swiften/Session/BasicSessionStream.h
+++ b/Swiften/Session/BasicSessionStream.h
@@ -49,18 +49,20 @@ namespace Swift {
virtual void writeData(const std::string& data);
virtual bool supportsZLibCompression();
virtual void addZLibCompression();
virtual bool supportsTLSEncryption();
virtual void addTLSEncryption();
virtual bool isTLSEncrypted();
virtual Certificate::ref getPeerCertificate() const;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const;
+
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
virtual ByteArray getTLSFinishMessage() const;
virtual void setWhitespacePingEnabled(bool);
virtual void resetXMPPParser();
private:
void handleConnectionFinished(const boost::optional<Connection::Error>& error);
diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h
index 32cb6b6..4735d5f 100644
--- a/Swiften/Session/SessionStream.h
+++ b/Swiften/Session/SessionStream.h
@@ -61,18 +61,19 @@ namespace Swift {
void setTLSCertificate(CertificateWithKey::ref cert) {
certificate = cert;
}
virtual bool hasTLSCertificate() {
return certificate && !certificate->isNull();
}
virtual Certificate::ref getPeerCertificate() const = 0;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0;
virtual boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const = 0;
virtual ByteArray getTLSFinishMessage() const = 0;
boost::signal<void (const ProtocolHeader&)> onStreamStartReceived;
boost::signal<void (boost::shared_ptr<Element>)> onElementReceived;
boost::signal<void (boost::shared_ptr<Error>)> onClosed;
boost::signal<void ()> onTLSEncrypted;
boost::signal<void (const SafeByteArray&)> onDataRead;
diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp
index 6d416bc..86221ea 100644
--- a/Swiften/StreamStack/TLSLayer.cpp
+++ b/Swiften/StreamStack/TLSLayer.cpp
@@ -39,14 +39,18 @@ void TLSLayer::handleDataRead(const SafeByteArray& data) {
bool TLSLayer::setClientCertificate(CertificateWithKey::ref certificate) {
return context->setClientCertificate(certificate);
}
Certificate::ref TLSLayer::getPeerCertificate() const {
return context->getPeerCertificate();
}
+std::vector<Certificate::ref> TLSLayer::getPeerCertificateChain() const {
+ return context->getPeerCertificateChain();
+}
+
boost::shared_ptr<CertificateVerificationError> TLSLayer::getPeerCertificateVerificationError() const {
return context->getPeerCertificateVerificationError();
}
}
diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h
index ce0c89b..24978e0 100644
--- a/Swiften/StreamStack/TLSLayer.h
+++ b/Swiften/StreamStack/TLSLayer.h
@@ -20,18 +20,19 @@ namespace Swift {
class TLSLayer : public StreamLayer {
public:
TLSLayer(TLSContextFactory*);
~TLSLayer();
void connect();
bool setClientCertificate(CertificateWithKey::ref cert);
Certificate::ref getPeerCertificate() const;
+ std::vector<Certificate::ref> getPeerCertificateChain() const;
boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
void writeData(const SafeByteArray& data);
void handleDataRead(const SafeByteArray& data);
TLSContext* getContext() const {
return context;
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
index 8c03052..58a8d05 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp
@@ -33,18 +33,24 @@ static const int SSL_READ_BUFFERSIZE = 8192;
void freeX509Stack(STACK_OF(X509)* stack) {
sk_X509_free(stack);
}
OpenSSLContext::OpenSSLContext() : state_(Start), context_(0), handle_(0), readBIO_(0), writeBIO_(0) {
ensureLibraryInitialized();
context_ = SSL_CTX_new(TLSv1_client_method());
+ // TODO: implement CRL checking
+ // TODO: download CRL (HTTP transport)
+ // TODO: cache CRL downloads for configurable time period
+
+ // TODO: implement OCSP support
+ // TODO: handle OCSP stapling see https://www.rfc-editor.org/rfc/rfc4366.txt
// Load system certs
#if defined(SWIFTEN_PLATFORM_WINDOWS)
X509_STORE* store = SSL_CTX_get_cert_store(context_);
HCERTSTORE systemStore = CertOpenSystemStore(0, "ROOT");
if (systemStore) {
PCCERT_CONTEXT certContext = NULL;
while (true) {
certContext = CertFindCertificateInStore(systemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, certContext);
if (!certContext) {
@@ -230,18 +236,30 @@ Certificate::ref OpenSSLContext::getPeerCertificate() const {
boost::shared_ptr<X509> x509Cert(SSL_get_peer_certificate(handle_), X509_free);
if (x509Cert) {
return boost::make_shared<OpenSSLCertificate>(x509Cert);
}
else {
return Certificate::ref();
}
}
+std::vector<Certificate::ref> OpenSSLContext::getPeerCertificateChain() const {
+ std::vector<Certificate::ref> result;
+ STACK_OF(X509)* chain = SSL_get_peer_cert_chain(handle_);
+ for (int i = 0; i < sk_X509_num(chain); ++i) {
+ boost::shared_ptr<X509> x509Cert(X509_dup(sk_X509_value(chain, i)), X509_free);
+
+ Certificate::ref cert = boost::make_shared<OpenSSLCertificate>(x509Cert);
+ result.push_back(cert);
+ }
+ return result;
+}
+
boost::shared_ptr<CertificateVerificationError> OpenSSLContext::getPeerCertificateVerificationError() const {
int verifyResult = SSL_get_verify_result(handle_);
if (verifyResult != X509_V_OK) {
return boost::make_shared<CertificateVerificationError>(getVerificationErrorTypeForResult(verifyResult));
}
else {
return boost::shared_ptr<CertificateVerificationError>();
}
}
diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h
index d8d0d2f..cee4f79 100644
--- a/Swiften/TLS/OpenSSL/OpenSSLContext.h
+++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h
@@ -22,18 +22,19 @@ namespace Swift {
~OpenSSLContext();
void connect();
bool setClientCertificate(CertificateWithKey::ref cert);
void handleDataFromNetwork(const SafeByteArray&);
void handleDataFromApplication(const SafeByteArray&);
Certificate::ref getPeerCertificate() const;
+ std::vector<Certificate::ref> getPeerCertificateChain() const;
boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
virtual ByteArray getFinishMessage() const;
private:
static void ensureLibraryInitialized();
static CertificateVerificationError::Type getVerificationErrorTypeForResult(int);
diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp
index 641568d..997d760 100644
--- a/Swiften/TLS/Schannel/SchannelContext.cpp
+++ b/Swiften/TLS/Schannel/SchannelContext.cpp
@@ -627,18 +627,47 @@ void SchannelContext::handleCertificateCardRemoved() {
Certificate::ref SchannelContext::getPeerCertificate() const {
ScopedCertContext pServerCert;
SECURITY_STATUS status = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset());
return status == SEC_E_OK ? boost::make_shared<SchannelCertificate>(pServerCert) : SchannelCertificate::ref();
}
//------------------------------------------------------------------------
+std::vector<Certificate::ref> SchannelContext::getPeerCertificateChain() const {
+ std::vector<Certificate::ref> certificateChain;
+ ScopedCertContext pServerCert;
+ ScopedCertContext pIssuerCert;
+ ScopedCertContext pCurrentCert;
+ SECURITY_STATUS status = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, pServerCert.Reset());
+
+ if (status != SEC_E_OK) {
+ return certificateChain;
+ }
+ certificateChain.push_back(boost::make_shared<SchannelCertificate>(pServerCert));
+
+ pCurrentCert = pServerCert;
+ while(pCurrentCert.GetPointer()) {
+ DWORD dwVerificationFlags = 0;
+ pIssuerCert = CertGetIssuerCertificateFromStore(pServerCert->hCertStore, pCurrentCert, NULL, &dwVerificationFlags );
+ if (!(*pIssuerCert.GetPointer())) {
+ break;
+ }
+ certificateChain.push_back(boost::make_shared<SchannelCertificate>(pIssuerCert));
+
+ pCurrentCert = pIssuerCert;
+ pIssuerCert = NULL;
+ }
+ return certificateChain;
+}
+
+//------------------------------------------------------------------------
+
CertificateVerificationError::ref SchannelContext::getPeerCertificateVerificationError() const {
return m_verificationError ? boost::make_shared<CertificateVerificationError>(*m_verificationError) : CertificateVerificationError::ref();
}
//------------------------------------------------------------------------
ByteArray SchannelContext::getFinishMessage() const {
SecPkgContext_Bindings bindings;
int ret = QueryContextAttributes(m_ctxtHandle, SECPKG_ATTR_UNIQUE_BINDINGS, &bindings);
diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h
index 587d0e7..2d65a8a 100644
--- a/Swiften/TLS/Schannel/SchannelContext.h
+++ b/Swiften/TLS/Schannel/SchannelContext.h
@@ -45,18 +45,19 @@ namespace Swift
// TLSContext
//
virtual void connect();
virtual bool setClientCertificate(CertificateWithKey::ref cert);
virtual void handleDataFromNetwork(const SafeByteArray& data);
virtual void handleDataFromApplication(const SafeByteArray& data);
virtual Certificate::ref getPeerCertificate() const;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const;
virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const;
virtual ByteArray getFinishMessage() const;
virtual void setCheckCertificateRevocation(bool b);
private:
void determineStreamSizes();
void continueHandshake(const SafeByteArray& data);
diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h
index 5640fe1..388f8ee 100644
--- a/Swiften/TLS/TLSContext.h
+++ b/Swiften/TLS/TLSContext.h
@@ -23,18 +23,19 @@ namespace Swift {
virtual void connect() = 0;
virtual bool setClientCertificate(CertificateWithKey::ref cert) = 0;
virtual void handleDataFromNetwork(const SafeByteArray&) = 0;
virtual void handleDataFromApplication(const SafeByteArray&) = 0;
virtual Certificate::ref getPeerCertificate() const = 0;
+ virtual std::vector<Certificate::ref> getPeerCertificateChain() const = 0;
virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const = 0;
virtual ByteArray getFinishMessage() const = 0;
public:
boost::signal<void (const SafeByteArray&)> onDataForNetwork;
boost::signal<void (const SafeByteArray&)> onDataForApplication;
boost::signal<void (boost::shared_ptr<TLSError>)> onError;
boost::signal<void ()> onConnected;