diff options
-rw-r--r-- | Swift/QtUI/QtLoginWindow.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtLoginWindow.h | 5 | ||||
-rw-r--r-- | Swift/QtUI/QtSwift.cpp | 2 | ||||
-rw-r--r-- | Swift/QtUI/QtUIFactory.cpp | 4 | ||||
-rw-r--r-- | Swift/QtUI/QtUIFactory.h | 4 | ||||
-rw-r--r-- | Swift/QtUI/SConscript | 3 | ||||
-rw-r--r-- | Swiften/TLS/CAPICertificate.cpp | 184 | ||||
-rw-r--r-- | Swiften/TLS/CAPICertificate.h | 25 | ||||
-rw-r--r-- | Swiften/TLS/Schannel/SchannelContext.cpp | 18 | ||||
-rw-r--r-- | Swiften/TLS/Schannel/SchannelContext.h | 6 |
10 files changed, 241 insertions, 14 deletions
diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp index dc6001b..7612720 100644 --- a/Swift/QtUI/QtLoginWindow.cpp +++ b/Swift/QtUI/QtLoginWindow.cpp @@ -49,7 +49,7 @@ namespace Swift{ -QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings) : QMainWindow(), settings_(settings) { +QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings, TimerFactory* timerFactory) : QMainWindow(), settings_(settings), timerFactory_(timerFactory) { uiEventStream_ = uiEventStream; setWindowTitle("Swift"); @@ -351,7 +351,7 @@ void QtLoginWindow::loginClicked() { std::string certificateString = Q2PSTRING(certificateFile_); #if defined(HAVE_SCHANNEL) if (isCAPIURI(certificateString)) { - certificate = boost::make_shared<CAPICertificate>(certificateString); + certificate = boost::make_shared<CAPICertificate>(certificateString, timerFactory_); } else { certificate = boost::make_shared<PKCS12Certificate>(certificateString, createSafeByteArray(Q2PSTRING(password_->text()))); } diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h index dcd7c18..1add2f4 100644 --- a/Swift/QtUI/QtLoginWindow.h +++ b/Swift/QtUI/QtLoginWindow.h @@ -25,6 +25,8 @@ class QComboBox; namespace Swift { class SettingsProvider; + class TimerFactory; + class QtLoginWindow : public QMainWindow, public LoginWindow { Q_OBJECT public: @@ -35,7 +37,7 @@ namespace Swift { }; public: - QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings); + QtLoginWindow(UIEventStream* uiEventStream, SettingsProvider* settings, TimerFactory* timerFactory); void morphInto(MainWindow *mainWindow); virtual void loggedOut(); @@ -98,5 +100,6 @@ namespace Swift { SettingsProvider* settings_; QAction* xmlConsoleAction_; QAction* fileTransferOverviewAction_; + TimerFactory* timerFactory_; }; } diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 9dabf21..60f93cc 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -172,7 +172,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa // Don't add the first tray (see note above) systemTrays_.push_back(new QtSystemTray()); } - QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, startMinimized); + QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, networkFactories_.getTimerFactory(), startMinimized); uiFactories_.push_back(uiFactory); MainController* mainController = new MainController( &clientMainThreadCaller_, diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp index c686442..a8b693d 100644 --- a/Swift/QtUI/QtUIFactory.cpp +++ b/Swift/QtUI/QtUIFactory.cpp @@ -30,7 +30,7 @@ namespace Swift { -QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized) : settings(settings), qtOnlySettings(qtOnlySettings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized) { +QtUIFactory::QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, bool startMinimized) : settings(settings), qtOnlySettings(qtOnlySettings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), timerFactory_(timerFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized) { chatFontSize = settings->getSetting(QtUISettingConstants::CHATWINDOW_FONT_SIZE); } @@ -60,7 +60,7 @@ MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) { } LoginWindow* QtUIFactory::createLoginWindow(UIEventStream* eventStream) { - loginWindow = new QtLoginWindow(eventStream, settings); + loginWindow = new QtLoginWindow(eventStream, settings, timerFactory_); if (netbookSplitter) { netbookSplitter->insertWidget(0, loginWindow); } diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h index c9e2f2e..8b8e3ce 100644 --- a/Swift/QtUI/QtUIFactory.h +++ b/Swift/QtUI/QtUIFactory.h @@ -23,11 +23,12 @@ namespace Swift { class QtChatTheme; class QtChatWindowFactory; class QtChatWindow; + class TimerFactory; class QtUIFactory : public QObject, public UIFactory { Q_OBJECT public: - QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized); + QtUIFactory(SettingsProviderHierachy* settings, QtSettingsProvider* qtOnlySettings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, TimerFactory* timerFactory, bool startMinimized); virtual XMLConsoleWidget* createXMLConsoleWidget(); virtual MainWindow* createMainWindow(UIEventStream* eventStream); @@ -57,6 +58,7 @@ namespace Swift { QtMainWindow* lastMainWindow; QtLoginWindow* loginWindow; std::vector<QPointer<QtChatWindow> > chatWindows; + TimerFactory* timerFactory_; bool startMinimized; int chatFontSize; }; diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 8d7697a..0622cc6 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -40,7 +40,8 @@ if myenv.get("HAVE_SNARL", False) : myenv.UseFlags(myenv["SNARL_FLAGS"]) myenv.Append(CPPDEFINES = ["HAVE_SNARL"]) if env["PLATFORM"] == "win32" : - myenv.Append(LIBS = ["cryptui"]) + myenv.Append(LIBS = ["cryptui"]) + myenv.Append(LIBS = ["Winscard"]) myenv.UseFlags(myenv["PLATFORM_FLAGS"]) myenv.Tool("qt4", toolpath = ["#/BuildTools/SCons/Tools"]) diff --git a/Swiften/TLS/CAPICertificate.cpp b/Swiften/TLS/CAPICertificate.cpp index 0dc3009..b33ebcf 100644 --- a/Swiften/TLS/CAPICertificate.cpp +++ b/Swiften/TLS/CAPICertificate.cpp @@ -5,9 +5,11 @@ */ #pragma once +#include <Swiften/Network/TimerFactory.h> #include <Swiften/TLS/CAPICertificate.h> #include <Swiften/StringCodecs/Hexify.h> +#include <boost/bind.hpp> #include <boost/algorithm/string/predicate.hpp> // Size of the SHA1 hash @@ -15,15 +17,39 @@ namespace Swift { -CAPICertificate::CAPICertificate(const std::string& capiUri) - : valid_(false), uri_(capiUri), certStoreHandle_(0), certStore_(), certName_() { + +CAPICertificate::CAPICertificate(const std::string& capiUri, TimerFactory* timerFactory) + : valid_(false), + uri_(capiUri), + certStoreHandle_(0), + scardContext_(0), + cardHandle_(0), + certStore_(), + certName_(), + smartCardReaderName_(), + timerFactory_(timerFactory) { + setUri(capiUri); } CAPICertificate::~CAPICertificate() { + if (smartCardTimer_) { + smartCardTimer_->stop(); + smartCardTimer_->onTick.disconnect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this)); + smartCardTimer_.reset(); + } + if (certStoreHandle_) { CertCloseStore(certStoreHandle_, 0); } + + if (cardHandle_) { + (void) SCardDisconnect(cardHandle_, SCARD_LEAVE_CARD); + } + + if (scardContext_) { + SCardReleaseContext(scardContext_); + } } bool CAPICertificate::isNull() const { @@ -38,6 +64,10 @@ const std::string& CAPICertificate::getCertName() const { return certName_; } +const std::string& CAPICertificate::getSmartCardReaderName() const { + return smartCardReaderName_; +} + PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::string &certName) { PCCERT_CONTEXT pCertContext = NULL; @@ -170,6 +200,30 @@ void CAPICertificate::setUri (const std::string& capiUri) { return; } + + char smartcard_reader[1024]; + DWORD buflen; + + buflen = sizeof(smartcard_reader); + if (!CryptGetProvParam(hprov, PP_SMARTCARD_READER, (BYTE *)&smartcard_reader, &buflen, 0)) { + DWORD error; + + error = GetLastError(); + smartCardReaderName_ = ""; + } else { + LONG lRet; + + smartCardReaderName_ = smartcard_reader; + + lRet = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &scardContext_); + if (SCARD_S_SUCCESS == lRet) { + // Initiate monitoring for smartcard ejection + smartCardTimer_ = timerFactory_->createTimer(SMARTCARD_EJECTION_CHECK_FREQ); + } else { + ///Need to handle an error here + } + } + if (!CryptGetUserKey(hprov, pinfo->dwKeySpec, &key)) { CryptReleaseContext(hprov, 0); free(pinfo); @@ -180,7 +234,133 @@ void CAPICertificate::setUri (const std::string& capiUri) { CryptReleaseContext(hprov, 0); free(pinfo); + if (smartCardTimer_) { + smartCardTimer_->onTick.connect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this)); + smartCardTimer_->start(); + } + valid_ = true; } +static void smartcard_check_status (SCARDCONTEXT hContext, + const char * pReader, + SCARDHANDLE hCardHandle, // Can be 0 on the first call + SCARDHANDLE * newCardHandle, // The handle returned + DWORD * pdwState) { + LONG lReturn; + DWORD dwAP; + char szReader[200]; + DWORD cch = sizeof(szReader); + BYTE bAttr[32]; + DWORD cByte = 32; + + if (hCardHandle == 0) { + lReturn = SCardConnect(hContext, + pReader, + SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, + &hCardHandle, + &dwAP); + if ( SCARD_S_SUCCESS != lReturn ) { + hCardHandle = 0; + if (SCARD_E_NO_SMARTCARD == lReturn || SCARD_W_REMOVED_CARD == lReturn) { + *pdwState = SCARD_ABSENT; + } else { + *pdwState = SCARD_UNKNOWN; + } + goto done; + } + } + + lReturn = SCardStatus(hCardHandle, + szReader, // Unfortunately we can't use NULL here + &cch, + pdwState, + NULL, + (LPBYTE)&bAttr, + &cByte); + + if ( SCARD_S_SUCCESS != lReturn ) { + if (SCARD_E_NO_SMARTCARD == lReturn || SCARD_W_REMOVED_CARD == lReturn) { + *pdwState = SCARD_ABSENT; + } else { + *pdwState = SCARD_UNKNOWN; + } + } + +done: + if (newCardHandle == NULL) { + (void) SCardDisconnect(hCardHandle, SCARD_LEAVE_CARD); + hCardHandle = 0; + } else { + *newCardHandle = hCardHandle; + } +} + +bool CAPICertificate::checkIfSmartCardPresent () { + + DWORD dwState; + + if (!smartCardReaderName_.empty()) { + smartcard_check_status (scardContext_, + smartCardReaderName_.c_str(), + cardHandle_, + &cardHandle_, + &dwState); +////DEBUG + switch ( dwState ) { + case SCARD_ABSENT: + printf("Card absent.\n"); + break; + case SCARD_PRESENT: + printf("Card present.\n"); + break; + case SCARD_SWALLOWED: + printf("Card swallowed.\n"); + break; + case SCARD_POWERED: + printf("Card has power.\n"); + break; + case SCARD_NEGOTIABLE: + printf("Card reset and waiting PTS negotiation.\n"); + break; + case SCARD_SPECIFIC: + printf("Card has specific communication protocols set.\n"); + break; + default: + printf("Unknown or unexpected card state.\n"); + break; + } + + + + switch ( dwState ) { + case SCARD_ABSENT: + return false; + + case SCARD_PRESENT: + case SCARD_SWALLOWED: + case SCARD_POWERED: + case SCARD_NEGOTIABLE: + case SCARD_SPECIFIC: + return true; + + default: + return false; + } + } else { + return false; + } +} + +void CAPICertificate::handleSmartCardTimerTick() { + + if (checkIfSmartCardPresent() == false) { + smartCardTimer_->stop(); + onCertificateCardRemoved(); + } else { + smartCardTimer_->start(); + } +} + } diff --git a/Swiften/TLS/CAPICertificate.h b/Swiften/TLS/CAPICertificate.h index 4204a6b..c8c00fe 100644 --- a/Swiften/TLS/CAPICertificate.h +++ b/Swiften/TLS/CAPICertificate.h @@ -6,17 +6,26 @@ #pragma once +#include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/SafeByteArray.h> #include <Swiften/TLS/CertificateWithKey.h> +#include <Swiften/Network/Timer.h> #define SECURITY_WIN32 #include <Windows.h> #include <WinCrypt.h> +#include <Winscard.h> + +/* In ms */ +#define SMARTCARD_EJECTION_CHECK_FREQ 1000 namespace Swift { + class TimerFactory; + class CAPICertificate : public Swift::CertificateWithKey { public: - CAPICertificate(const std::string& capiUri); +////Allow timerFactory to be NULL? + CAPICertificate(const std::string& capiUri, TimerFactory* timerFactory); virtual ~CAPICertificate(); @@ -26,18 +35,32 @@ namespace Swift { const std::string& getCertName() const; + const std::string& getSmartCardReaderName() const; + + public: + boost::signal<void ()> onCertificateCardRemoved; + private: void setUri (const std::string& capiUri); + void handleSmartCardTimerTick(); + + bool checkIfSmartCardPresent(); + private: bool valid_; std::string uri_; HCERTSTORE certStoreHandle_; + SCARDCONTEXT scardContext_; + SCARDHANDLE cardHandle_; /* Parsed components of the uri_ */ std::string certStore_; std::string certName_; + std::string smartCardReaderName_; + boost::shared_ptr<Timer> smartCardTimer_; + TimerFactory* timerFactory_; }; PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::string &certName); diff --git a/Swiften/TLS/Schannel/SchannelContext.cpp b/Swiften/TLS/Schannel/SchannelContext.cpp index 4f8f36f..8e952ea 100644 --- a/Swiften/TLS/Schannel/SchannelContext.cpp +++ b/Swiften/TLS/Schannel/SchannelContext.cpp @@ -4,8 +4,10 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "Swiften/TLS/Schannel/SchannelContext.h" -#include "Swiften/TLS/Schannel/SchannelCertificate.h" +#include <boost/bind.hpp> + +#include <Swiften/TLS/Schannel/SchannelContext.h> +#include <Swiften/TLS/Schannel/SchannelCertificate.h> #include <Swiften/TLS/CAPICertificate.h> #include <WinHTTP.h> // For SECURITY_FLAG_IGNORE_CERT_CN_INVALID @@ -19,6 +21,7 @@ SchannelContext::SchannelContext() , m_my_cert_store(NULL) , m_cert_store_name("MY") , m_cert_name() +, m_smartcard_reader() { m_ctxtFlags = ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | @@ -639,10 +642,21 @@ bool SchannelContext::setClientCertificate(CertificateWithKey::ref certificate) // are valid at this point m_cert_store_name = capiCertificate->getCertStoreName(); m_cert_name = capiCertificate->getCertName(); +////At the moment this is only useful for logging: + m_smartcard_reader = capiCertificate->getSmartCardReaderName(); + + capiCertificate->onCertificateCardRemoved.connect(boost::bind(&SchannelContext::handleCertificateCardRemoved, this)); + return true; } //------------------------------------------------------------------------ +void SchannelContext::handleCertificateCardRemoved() { + //ToDo: Might want to log the reason ("certificate card ejected") + indicateError(); +} + +//------------------------------------------------------------------------ Certificate::ref SchannelContext::getPeerCertificate() const { diff --git a/Swiften/TLS/Schannel/SchannelContext.h b/Swiften/TLS/Schannel/SchannelContext.h index 70b0694..bce7415 100644 --- a/Swiften/TLS/Schannel/SchannelContext.h +++ b/Swiften/TLS/Schannel/SchannelContext.h @@ -10,7 +10,7 @@ #include "Swiften/TLS/TLSContext.h" #include "Swiften/TLS/Schannel/SchannelUtil.h" -#include <Swiften/TLS/CertificateWithKey.h> +#include "Swiften/TLS/CertificateWithKey.h" #include "Swiften/Base/ByteArray.h" #define SECURITY_WIN32 @@ -62,6 +62,8 @@ namespace Swift void appendNewData(const SafeByteArray& data); SECURITY_STATUS validateServerCertificate(); + void handleCertificateCardRemoved(); + private: enum SchannelState { @@ -86,5 +88,7 @@ namespace Swift HCERTSTORE m_my_cert_store; std::string m_cert_store_name; std::string m_cert_name; +////Not needed, most likely + std::string m_smartcard_reader; //Can be empty string for non SmartCard certificates }; } |