summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften')
-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
4 files changed, 227 insertions, 6 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();
+ }
+}
+
}
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
};
}