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  	};  } | 
 Swift
 Swift