summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/TLS/CAPICertificate.cpp')
-rw-r--r--Swiften/TLS/CAPICertificate.cpp184
1 files changed, 182 insertions, 2 deletions
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();
+ }
+}
+
}