summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swift/QtUI/QtLoginWindow.cpp4
-rw-r--r--Swift/QtUI/QtLoginWindow.h5
-rw-r--r--Swift/QtUI/QtSwift.cpp2
-rw-r--r--Swift/QtUI/QtUIFactory.cpp4
-rw-r--r--Swift/QtUI/QtUIFactory.h4
-rw-r--r--Swift/QtUI/SConscript3
-rw-r--r--Swiften/TLS/CAPICertificate.cpp184
-rw-r--r--Swiften/TLS/CAPICertificate.h25
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.cpp18
-rw-r--r--Swiften/TLS/Schannel/SchannelContext.h6
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
};
}