diff options
author | Tobias Markmann <tm@ayena.de> | 2012-05-04 21:39:30 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2012-05-11 19:29:38 (GMT) |
commit | 0f91f88ac69644fb7e7bdbf601b7e098194490fa (patch) | |
tree | e66ca4acbf869c82bba607ca9c394a47615c6e6e /Swift | |
parent | 15ed4a079a8bbe3cc9ee2ca47233be7b890464ec (diff) | |
download | swift-0f91f88ac69644fb7e7bdbf601b7e098194490fa.zip swift-0f91f88ac69644fb7e7bdbf601b7e098194490fa.tar.bz2 |
Showing stream encryption status in the roster header. Provide native certificate viewers on click.
Native viewers for Windows and Mac OS X are implemented.
Added TODOs to OpenSSL based TLS interface related to CRL and OCSP.
Resolves: #167
License: This patch is BSD-licensed, see http://www.opensource.org/licenses/bsd-license.php
Diffstat (limited to 'Swift')
-rw-r--r-- | Swift/Controllers/MainController.cpp | 8 | ||||
-rw-r--r-- | Swift/Controllers/MainController.h | 1 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/MainWindow.h | 5 | ||||
-rw-r--r-- | Swift/Controllers/UnitTest/MockMainWindow.h | 2 | ||||
-rw-r--r-- | Swift/QtUI/CocoaUIHelpers.h | 20 | ||||
-rw-r--r-- | Swift/QtUI/CocoaUIHelpers.mm | 43 | ||||
-rw-r--r-- | Swift/QtUI/QtMainWindow.cpp | 26 | ||||
-rw-r--r-- | Swift/QtUI/QtMainWindow.h | 3 | ||||
-rw-r--r-- | Swift/QtUI/QtRosterHeader.cpp | 19 | ||||
-rw-r--r-- | Swift/QtUI/QtRosterHeader.h | 4 | ||||
-rw-r--r-- | Swift/QtUI/SConscript | 2 | ||||
-rw-r--r-- | Swift/QtUI/WinUIHelpers.cpp | 61 | ||||
-rw-r--r-- | Swift/QtUI/WinUIHelpers.h | 20 |
13 files changed, 212 insertions, 2 deletions
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 @@ -72,6 +72,7 @@ #include <Swiften/FileTransfer/FileTransferManager.h> #include <Swiften/Client/ClientXMLTracer.h> #include <Swift/Controllers/SettingConstants.h> +#include <Swiften/Client/StanzaChannel.h> namespace Swift { @@ -285,6 +286,7 @@ void MainController::handleConnected() { 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_); @@ -327,6 +329,7 @@ void MainController::handleConnected() { 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. */ @@ -417,6 +420,11 @@ void MainController::handleInputIdleChanged(bool idle) { } } +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()) { 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 @@ -103,6 +103,7 @@ namespace Swift { void handlePurgeSavedLoginRequest(const std::string& username); void sendPresence(boost::shared_ptr<Presence> presence); void handleInputIdleChanged(bool); + void handleShowCertificateRequest(); void logout(); void signOut(); void setReconnectTimer(); 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 @@ -10,7 +10,7 @@ #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> @@ -35,9 +35,12 @@ namespace Swift { 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 @@ -22,6 +22,8 @@ namespace Swift { 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 @@ -34,6 +34,13 @@ #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 { @@ -48,6 +55,7 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr 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 @@ -153,6 +161,10 @@ void QtMainWindow::handleToggleRequestDeliveryReceipts(bool enabled) { settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, enabled); } +void QtMainWindow::handleShowCertificateInfo() { + onShowCertificateRequest(); +} + QtEventWindow* QtMainWindow::getEventWindow() { return eventWindow_; } @@ -256,6 +268,20 @@ 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); 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 @@ -45,6 +45,8 @@ namespace Swift { 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); @@ -64,6 +66,7 @@ namespace Swift { void handleEditProfileRequest(); void handleTabChanged(int index); void handleToggleRequestDeliveryReceipts(bool enabled); + void handleShowCertificateInfo(); private: SettingsProvider* settings_; 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 @@ -45,14 +45,27 @@ QtRosterHeader::QtRosterHeader(SettingsProvider* settings, QWidget* parent) : QW 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(); } @@ -72,6 +85,10 @@ 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; 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 @@ -11,6 +11,7 @@ #include <QPixmap> #include <QSize> #include <QToolBar> +#include <QToolButton> #include <string> #include "Swiften/Elements/StatusShow.h" @@ -37,9 +38,11 @@ namespace Swift { 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); @@ -50,6 +53,7 @@ namespace Swift { 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 @@ -161,6 +161,7 @@ if env["PLATFORM"] == "win32" : # 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" @@ -174,6 +175,7 @@ if env["PLATFORM"] == "posix" : if env["PLATFORM"] == "darwin" : sources += ["CocoaApplicationActivateHelper.mm"] + sources += ["CocoaUIHelpers.mm"] if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" : swiftProgram = myenv.Program("Swift", sources) 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); +}; + +} + |