cleanup of connection management, new major version number 3, use static connection methods; refs #26, refs #28, refs #29

master
Marc Wäckerlin 11 years ago
parent 08784114fb
commit e2dc8a3595
  1. 9
      configure.in
  2. 5
      doc/examples/cardos-demo.cxx
  3. 35
      doc/examples/create-files-demo.cxx
  4. 11
      doc/examples/makefile.am
  5. 88
      doc/examples/moc_cardgui-model.cxx
  6. 5
      doc/examples/pcsc-demo.cxx
  7. 122
      src/cardgui-model.hxx
  8. 20
      src/cardgui.cxx
  9. 108
      src/cardgui.hxx
  10. 103
      src/cardgui.ui
  11. 229
      src/cardos.hxx
  12. 51
      src/cryptaux.hxx
  13. 18
      src/makefile.am
  14. 2
      src/openssl-engine.cxx
  15. 2
      src/openssl-engine.hxx
  16. 2
      src/openssl.hxx
  17. 30
      src/password.hxx
  18. 101
      src/password.ui
  19. 829
      src/pcsc.hxx
  20. 18
      src/suisseid.hxx

@ -22,7 +22,7 @@ TST_DIR=
DOC_DIR=doc DOC_DIR=doc
m4_define(x_packagename, libpcscxx) m4_define(x_packagename, libpcscxx)
m4_define(x_major, 2) m4_define(x_major, 3)
m4_define(x_minor, 0) m4_define(x_minor, 0)
PACKAGENAME=x_packagename PACKAGENAME=x_packagename
MAJOR=x_major MAJOR=x_major
@ -94,7 +94,12 @@ AC_CHECK_PROG(have_dot, dot, yes, no)
PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG
# libraries # libraries
PKG_CHECK_MODULES([QT], [QtNetwork]) PKG_CHECK_MODULES([QT_GUI], [QtCore QtGui QtWidgets],
[AC_DEFINE([HAVE_QTGUI], [1], [Use QtGui])],
[PKG_CHECK_MODULES([QT_GUI], [Qt5Core Qt5Gui Qt5Widgets])])
PKG_CHECK_MODULES([QT_NETWORK], [QtNetwork],
[AC_DEFINE([HAVE_QTNETWORK], [1], [Use QtNetwork])],
[PKG_CHECK_MODULES([QT_NETWORK], [Qt5Network])])
AC_ARG_ENABLE(pedantic, AC_ARG_ENABLE(pedantic,
[AS_HELP_STRING([--enable-pedantic], [AS_HELP_STRING([--enable-pedantic],

@ -93,7 +93,7 @@ class Commands: public cardos::Commands {
} }
void listReader() { void listReader() {
_readers = _c.scan(); _readers = pcsc::Connection::scan();
std::cout<<"Found "<<_readers.size()<<" readers" std::cout<<"Found "<<_readers.size()<<" readers"
<<(_readers.size()?":":".")<<std::endl; <<(_readers.size()?":":".")<<std::endl;
int i(0); int i(0);
@ -107,7 +107,7 @@ class Commands: public cardos::Commands {
if (_readers.size()<0) return; if (_readers.size()<0) return;
int num(-1); int num(-1);
if (std::cin>>num && num>=0 && num<_readers.size()) { if (std::cin>>num && num>=0 && num<_readers.size()) {
_reader = _c.reader(_readers[num]); _reader = pcsc::Connection::reader(_readers[num]);
std::cout<<"Active Reader: "<<_readers[num]<<std::endl; std::cout<<"Active Reader: "<<_readers[num]<<std::endl;
} else throw std::runtime_error("no valid reader selected"); } else throw std::runtime_error("no valid reader selected");
} }
@ -153,7 +153,6 @@ class Commands: public cardos::Commands {
private: private:
pcsc::Connection _c;
pcsc::Connection::Strings _readers; pcsc::Connection::Strings _readers;
cardos::BerValues _ber; cardos::BerValues _ber;

@ -21,13 +21,10 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
pcsc::Connection c;
pcsc::Connection::Strings readers; pcsc::Connection::Strings readers;
void list() { void list() {
pcsc::Connection c; pcsc::Connection::Strings readers(pcsc::Connection::scan());
pcsc::Connection::Strings readers(c.scan());
std::cout<<"Found "<<readers.size()<<" readers" std::cout<<"Found "<<readers.size()<<" readers"
<<(readers.size()?":":".")<<std::endl; <<(readers.size()?":":".")<<std::endl;
int i(0); int i(0);
@ -39,7 +36,7 @@ void list() {
int main(int argc, char** argv) try { int main(int argc, char** argv) try {
int reader(0); int reader(0);
std::string pin; std::string pin;
std::string path("3f005015"); std::string path("3f00");
std::string id("8888"); std::string id("8888");
std::string data("Hallo Welt"); std::string data("Hallo Welt");
mrw::args::parse(argc, argv, "Write data to card.", mrw::args::parse(argc, argv, "Write data to card.",
@ -64,27 +61,29 @@ int main(int argc, char** argv) try {
mrw::args::decl::param_list() mrw::args::decl::param_list()
<<mrw::args::param(data, "text")) <<mrw::args::param(data, "text"))
); );
pcsc::Connection c; pcsc::Connection::Strings readers(pcsc::Connection::scan());
pcsc::Connection::Strings readers(c.scan());
if (reader<0 || readers.size()<reader) { if (reader<0 || readers.size()<reader) {
std::cerr<<"reader not found: "<<reader<<std::endl; std::cerr<<"reader not found: "<<reader<<std::endl;
return 1; return 1;
} }
cardos::Commands cmd(c.reader(readers[reader])); cardos::Commands cmd(pcsc::Connection::reader(readers[reader]));
//cardos::BerValues d(cmd.directory(path)); cardos::Dir d(cmd, path);
//cardos::BerValues d(cmd.readBerFile(path)); //cardos::BerValues d(cmd.readBerFile(path));
//std::cout<<d.print()<<std::endl; //cardos::BerValues d(cmd.directory(path));
std::cout<<"-----------------------------------------------------"<<std::endl
<<d.print()<<std::endl
<<"-----------------------------------------------------"<<std::endl;
//std::string res(cmd.readBinary(path)); //std::string res(cmd.readBinary(path));
//std::cout<<"HEX:"<<std::endl<<crypto::readable(res)<<std::endl; //std::cout<<"HEX:"<<std::endl<<crypto::readable(res)<<std::endl;
//std::cout<<"BER:"<<std::endl<<cardos::BerValues(res).print()<<std::endl; //std::cout<<"BER:"<<std::endl<<cardos::BerValues(res).print()<<std::endl;
if (!pin.size()) { // if (!pin.size()) {
std::cout<<"PIN: "; // std::cout<<"PIN: ";
std::cin>>pin; // std::cin>>pin;
} // }
if (pin.size()) cmd.logonTransport(pin); // if (pin.size()) cmd.logonTransport(pin);
cmd.phaseControl(); // cmd.phaseControl();
cmd.createBinary(path, id, data); // cmd.createBinary(path, id, data);
cmd.phaseControl(); // cmd.phaseControl();
return 0; return 0;
} catch (std::exception& x) { } catch (std::exception& x) {
std::cerr<<"ERROR: "<<x.what()<<std::endl; std::cerr<<"ERROR: "<<x.what()<<std::endl;

@ -36,13 +36,16 @@ openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx
openssl_engine_demo_SOURCES = openssl-engine-demo.cxx openssl_engine_demo_SOURCES = openssl-engine-demo.cxx
cardos_demo_SOURCES = cardos-demo.cxx cardos_demo_SOURCES = cardos-demo.cxx
suisse_id_demo_SOURCES = suisse-id-demo.cxx suisse_id_demo_SOURCES = suisse-id-demo.cxx
create_files_demo_SOURCES = create-files-demo.cxx
# moc_suisse-id-demo.cxx # moc_suisse-id-demo.cxx
suisse_id_demo_CXXFLAGS = ${QT_CFLAGS} suisse_id_demo_CXXFLAGS = ${QT_NETWORK_CFLAGS} -fPIC
suisse_id_demo_LDADD = ${QT_LIBS} suisse_id_demo_LDADD = ${QT_NETWORK_LIBS}
create_files_demo_SOURCES = create-files-demo.cxx
%_ui.hxx: %.ui
uic -o $@ $<
moc_%.cxx: %.hxx moc_%.cxx: %.hxx
moc -o $@ $< moc -o $@ $<
CLEANFILES = moc_suisse-id-demo.cxx CLEANFILES = ${BUILT_SOURCES}
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -0,0 +1,88 @@
/****************************************************************************
** Meta object code from reading C++ file 'cardgui-model.hxx'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.0.2)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "cardgui-model.hxx"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'cardgui-model.hxx' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.0.2. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
QT_BEGIN_MOC_NAMESPACE
struct qt_meta_stringdata_CardGuiModel_t {
QByteArrayData data[1];
char stringdata[14];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
offsetof(qt_meta_stringdata_CardGuiModel_t, stringdata) + ofs \
- idx * sizeof(QByteArrayData) \
)
static const qt_meta_stringdata_CardGuiModel_t qt_meta_stringdata_CardGuiModel = {
{
QT_MOC_LITERAL(0, 0, 12)
},
"CardGuiModel\0"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_CardGuiModel[] = {
// content:
7, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount
0 // eod
};
void CardGuiModel::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
}
const QMetaObject CardGuiModel::staticMetaObject = {
{ &QAbstractItemModel::staticMetaObject, qt_meta_stringdata_CardGuiModel.data,
qt_meta_data_CardGuiModel, qt_static_metacall, 0, 0}
};
const QMetaObject *CardGuiModel::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *CardGuiModel::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_CardGuiModel.stringdata))
return static_cast<void*>(const_cast< CardGuiModel*>(this));
return QAbstractItemModel::qt_metacast(_clname);
}
int CardGuiModel::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QAbstractItemModel::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}
QT_END_MOC_NAMESPACE

@ -3,15 +3,14 @@
#include <iostream> #include <iostream>
int main(int, char const*const*const argv) try { int main(int, char const*const*const argv) try {
pcsc::Connection c; pcsc::Connection::Strings reader(pcsc::Connection::scan());
pcsc::Connection::Strings reader(c.scan());
std::cout<<"Library-Version: "<<pcsc::version()<<std::endl; std::cout<<"Library-Version: "<<pcsc::version()<<std::endl;
std::cout<<"Suche PCSC-Reader ..."<<std::endl; std::cout<<"Suche PCSC-Reader ..."<<std::endl;
if (!reader.size()) std::cout<<"Keine gefunden."<<std::endl; if (!reader.size()) std::cout<<"Keine gefunden."<<std::endl;
for (pcsc::Connection::Strings::const_iterator it(reader.begin()); for (pcsc::Connection::Strings::const_iterator it(reader.begin());
it!=reader.end(); ++it) { it!=reader.end(); ++it) {
std::cout<<"Reader: "<<*it<<std::endl; std::cout<<"Reader: "<<*it<<std::endl;
pcsc::Connection::Reader::Status s(c.reader(*it)->status()); pcsc::Connection::Reader::Status s(pcsc::Connection::reader(*it)->status());
std::cout<<"Status = "<<s.state<<std::endl; std::cout<<"Status = "<<s.state<<std::endl;
std::cout<<"ATR = "<<crypto::hex(s.atr)<<std::endl; std::cout<<"ATR = "<<crypto::hex(s.atr)<<std::endl;
} }

@ -0,0 +1,122 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef CARDGUI_MODEL_HXX
#define CARDGUI_MODEL_HXX
#include <cardos.hxx>
#include <QtCore/QAbstractItemModel>
#include <QtGui/QFont>
class CardGuiModel: public QAbstractItemModel {
Q_OBJECT;
public:
CardGuiModel(cardos::Commands& cmd, const std::string& path):
_rootItem(cmd, path) {
}
QVariant data(const QModelIndex &index, int role) const {
if (!index.isValid()) return QVariant();
cardos::Object* o(static_cast<cardos::Object*>(index.internalPointer()));
switch (role) {
case Qt::TextAlignmentRole:
return Qt::AlignTop;
case Qt::FontRole:
if (index.column() == 2) {
QFont f("Monospaced");
f.setStyleHint(QFont::TypeWriter);
return f;
} else return QVariant();
case Qt::DisplayRole:
switch (index.column()) {
case 0: return QString::fromStdString(o->logicalName());
case 1: return QString::fromStdString(o->name());
case 3: return QString::fromStdString(o->contentInfo());
case 2: if (o->content().size())
return QString::fromStdString(crypto::readable(o->content()));
default: return QVariant();
}
default: return QVariant();
}
}
Qt::ItemFlags flags(const QModelIndex &index) const {
if (!index.isValid()) return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const {
if (orientation!=Qt::Horizontal || role!=Qt::DisplayRole)
return QVariant();
switch (section) {
case 0: return "Object";
case 1: return "ID";
case 3: return "Logical Content";
case 2: return "Binary Content";
default: return QVariant();
}
}
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const {
if (!hasIndex(row, column, parent)) return QModelIndex();
const cardos::Object* parentItem(0);
if (!parent.isValid())
parentItem = &_rootItem;
else
parentItem = static_cast<cardos::Object*>(parent.internalPointer());
if (row<parentItem->size())
return
createIndex(row, column, &(*parentItem->children().at(row)));
return QModelIndex();
}
std::pair<const cardos::Object*, int> scan(const cardos::Object& o,
const cardos::Object* c) const {
int i(0);
for (cardos::Object::Children::const_iterator it(o.children().begin());
it!=o.children().end(); ++it, ++i) {
if (it->get()==c) return std::make_pair(&o, i);
std::pair<const cardos::Object*, int> res(scan(**it, c));
if (res.first) return res;
}
return std::make_pair((const cardos::Object*)0, 0);
}
QModelIndex parent(const QModelIndex &index) const {
if (!index.isValid()) return QModelIndex();
cardos::Object* childItem
(static_cast<cardos::Object*>(index.internalPointer()));
if (childItem==&_rootItem) return QModelIndex();
std::pair<const cardos::Object*, int>
parentItem(scan(_rootItem, childItem));
if (!parentItem.first) return QModelIndex();
return createIndex(parentItem.second, 0,
const_cast<cardos::Object*>(parentItem.first));
}
int rowCount(const QModelIndex &parent = QModelIndex()) const {
if (parent.isValid() && parent.internalPointer())
return static_cast<cardos::Object*>(parent.internalPointer())->size();
else
return _rootItem.size();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const {
return 4;
}
protected:
cardos::Dir _rootItem;
};
#endif

@ -0,0 +1,20 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <cardgui.hxx>
#include <mrw/vector.hxx>
#include <mrw/args.hxx>
#include <QApplication>
int main(int argc, char** argv) {
QApplication app(argc, argv);
CardGui win;
win.show();
return app.exec();
}

@ -0,0 +1,108 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef CARDGUI_HXX
#define CARDGUI_HXX
#include <cardgui-model.hxx>
#include <cardgui_ui.hxx>
#include <password.hxx>
#include <QtCore/QProcess>
#include <QtWidgets/QMessageBox>
class CardGui: public QMainWindow, protected Ui_CardGui {
Q_OBJECT;
public:
CardGui(QWidget* p=0):
QMainWindow(p), _pwd(this) {
setupUi(this);
on__rescan_clicked();
}
void resizeEvent(QResizeEvent* event) {
QMainWindow::resizeEvent(event);
if (_tree->model())
for (int i = 0; i < _tree->model()->columnCount(); ++i)
_tree->resizeColumnToContents(i);
}
public Q_SLOTS:
void on__rescan_clicked(bool=true) {
static bool inRescan(false);
if (inRescan) return;
inRescan = true;
try {
delete _tree->model();
_tree->setModel(0);
_card->clear();
pcsc::Connection::Strings readers(pcsc::Connection::scan());
for (pcsc::Connection::Strings::iterator r(readers.begin());
r!=readers.end(); ++r)
_card->addItem(QString::fromStdString(*r));
} catch (...) {
}
inRescan = false;
}
void on__card_currentIndexChanged(int) {
on__reload_clicked();
}
void on__reload_clicked(bool=true) {
try {
delete _tree->model();
_tree->setModel(0);
cardos::Commands cmd(pcsc::Connection::reader
(_card->currentText().toStdString()));
_tree->setModel(new CardGuiModel(cmd, "3f00"));
} catch (...) {
on__rescan_clicked();
}
}
void on__actionRestartPCSCD_triggered() {
delete _tree->model();
_tree->setModel(0);
if (_pwd.exec()) {
_p.start("sudo -S service pcscd restart");
_p.write((_pwd.password()+"\n").toUtf8());
_p.closeWriteChannel();
if (!_p.waitForFinished())
QMessageBox::warning(this, tr("Restarting PCSC Daemon failed"),
tr("<html><p>Restarting PCSC daemon"
" failed with message:</p>"
"\n<pre>%1</pre></html>")
.arg(QString::fromUtf8
(_p.readAll()+"\n"+
_p.readAllStandardOutput()+"\n"+
_p.readAllStandardError())));
else
QMessageBox::information(this, tr("Restarted PCSC Daemon"),
tr("<html><p>Restarted PCSC daemon"
" with message:</p>"
"\n<pre>%1</pre></html>")
.arg(QString::fromUtf8
(_p.readAll()+"\n"+
_p.readAllStandardOutput()+"\n"+
_p.readAllStandardError())));
}
on__reload_clicked();
}
protected:
Password _pwd;
QProcess _p;
};
#endif

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CardGui</class>
<widget class="QMainWindow" name="CardGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1349</width>
<height>878</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>CardOS V4.4</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTreeView" name="_tree">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="_rescan">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>rescan for cards</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="_card"/>
</item>
<item>
<widget class="QPushButton" name="_reload">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>reload card info</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1349</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="_actionRestartPCSCD"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="_actionRestartPCSCD">
<property name="text">
<string>Restart PCSCD</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

@ -124,6 +124,8 @@ namespace cardos {
//@} //@}
//============================================================================ //============================================================================
/// @addtogroup cardoslib
//@{
class BerValue { class BerValue {
public: public:
@ -262,6 +264,10 @@ namespace cardos {
return _value; return _value;
} }
std::string hex() {
return crypto::hex(_value);
}
unsigned long ulong() { unsigned long ulong() {
return crypto::ulongFromBinary(_value); return crypto::ulongFromBinary(_value);
} }
@ -346,6 +352,7 @@ namespace cardos {
}; };
//============================================================================
/// Store a sequence of BerValue /// Store a sequence of BerValue
class BerValues: public std::vector<BerValue> { class BerValues: public std::vector<BerValue> {
public: public:
@ -401,12 +408,7 @@ namespace cardos {
} }
}; };
//@}
//============================================================================ //============================================================================
/// @addtogroup cardoslib
//@{
/// Implements CardOS V4.4 commands. /// Implements CardOS V4.4 commands.
/** Directly sends CardOS V4.4 commands to a smart card using APDUs. */ /** Directly sends CardOS V4.4 commands to a smart card using APDUs. */
class Commands { class Commands {
@ -422,12 +424,12 @@ namespace cardos {
Commands() {} Commands() {}
/// Initialize with given smart card reader. /// Initialize with given smart card reader.
Commands(mrw::Shared<pcsc::Connection::Reader> reader): Commands(pcsc::shared_ptr<pcsc::Connection::Reader>::t reader):
_reader(reader) { _reader(reader) {
} }
/// Set smart card reader. /// Set smart card reader.
void reader(mrw::Shared<pcsc::Connection::Reader> reader) { void reader(pcsc::shared_ptr<pcsc::Connection::Reader>::t reader) {
_reader = reader; _reader = reader;
} }
@ -941,10 +943,13 @@ namespace cardos {
}; };
//! Read a record oriented file //! Read a record oriented file
std::string readRecord(unsigned char record = 0, std::string readRecord(const std::string& path = std::string(),
unsigned char record = 0,
unsigned char sfi = 0, unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) { ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log"); CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode)); return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode));
} }
@ -1529,9 +1534,215 @@ namespace cardos {
protected: protected:
mrw::Shared<pcsc::Connection::Reader> _reader; pcsc::shared_ptr<pcsc::Connection::Reader>::t _reader;
}; };
//============================================================================
/// Represents a CardOS Filesystem Object
class Object {
public:
typedef pcsc::shared_ptr<Object>::t Child;
typedef std::vector<Child> Children;
public:
Object(const std::string& path): _path(path) {}
virtual ~Object() {}
virtual const std::string& path() const {
return _path;
}
virtual std::string name() const {
return _path;
}
virtual std::string logicalName() const {
switch (crypto::ulongFromBinary(crypto::hexToBin(name()))) {
case 0x3f00: return "Masterfile";
case 0x5649: return "Version Info";
case 0x2F02: return "Global Definition Object";
case 0x5015: return "PKCS#15";
case 0x5032: return "Token Info";
case 0x5600: return "File System Version";
case 0x4404: return "Certificate Definition";
case 0x4304: return "Certificates";
case 0x4401: return "Public Key Definition";
case 0x5075: return "Public Keys";
case 0x4408: return "Authentication Object Definition";
case 0x5031: return "Object Definition";
case 0x4407: return "Data Object Definition";
case 0x4444: return "Data Objects";
case 0x4400: return "Private Key Definition";
case 0x5072: return "Private Keys";
case 0x1fff: return "SigG";
case 0xfe15: return "Transport Protection State";
case 0xc100: return "Public Key";
default:
switch (crypto::ulongFromBinary(crypto::hexToBin(name()))&0xff00) {
case 0x4b00: return "Private Key "+name().substr(2);
case 0x5500: return "Public Key "+name().substr(2);
default: return type();
}
}
}
virtual const std::string& content() const {
const static std::string c;
return c;
}
virtual const std::string& contentInfo() const {
const static std::string c;
return c;
}
virtual std::string print(int indent=0, int=4) const {
return std::string(indent, ' ')+type()+": "+name();
}
virtual bool isFile() const {
return false;
}
virtual bool isDir() const {
return false;
}
virtual bool hasChildren() const {
return _children.size();
}
virtual Children::size_type size() const {
return _children.size();
}
virtual const Children& children() const {
return _children;
}
virtual std::string type() const = 0;
protected:
std::string _path;
Children _children;
};
//============================================================================
/// Represents a File on a Smart Card
class File: public Object {
public:
File(Commands& cmd, const std::string& path, const std::string& file):
Object(path), _file(file) {
CRYPTOLOG("new file "<<file<<" at "<<path);
try {
_content = cmd.readBinary(path+file);
try {
_contentInfo = cardos::BerValues(_content).print();
} catch (...) {
}
} catch (std::exception& x) {
_contentInfo = x.what();
}
}
File(const std::string& path, const std::string& file):
Object(path), _file(file) {
CRYPTOLOG("new file "<<file<<" at "<<path);
}
std::string name() const {
return _file;
}
const std::string& content() const {
return _content;
}
const std::string& contentInfo() const {
return _contentInfo;
}
bool isFile() const {
return true;
}
std::string type() const {
return "File";
}
protected:
std::string _file;
std::string _content;
std::string _contentInfo;
};
//============================================================================
/// Represents a Link on a Smart Card
class Link: public File {
public:
Link(Commands& cmd, const std::string& path, const std::string& file):
File(cmd, path, file) {
CRYPTOLOG("new link "<<file<<" at "<<path);
}
std::string type() const {
return "Link";
}
};
//============================================================================
/// Represents a Counter on a Smart Card
class Counter: public File {
public:
Counter(Commands& cmd, const std::string& path, const std::string& file):
File(path, file) {
CRYPTOLOG("new counter "<<file<<" at "<<path);
try {
_content = cmd.readRecord(path+file);
std::stringstream s;
s<<crypto::ulongFromBinary(_content);
_contentInfo = s.str();
} catch (std::exception& x) {
_contentInfo = x.what();
}
}
std::string type() const {
return "Counter";
}
};
//============================================================================
/// Represents a Directory on a Smart Card
class Dir: public Object {
public:
Dir(Commands& cmd, const std::string& path): Object(path) {
CRYPTOLOG("new directory path="<<path);
setup(cmd);
}
std::string name() const {
return _path.substr(_path.size()-4);
}
bool isDir() const {
return true;
}
std::string print(int indent=0, int step=4) const {
std::string res(std::string(indent, ' ')+type()+": "+name());
for (Children::const_iterator it(_children.begin());
it!=_children.end(); ++it)
res+='\n'+(*it)->print(indent+step, step);
return res;
}
std::string type() const {
return "Directory";
}
protected:
void setup(Commands& cmd) {
_children.clear();
BerValues i(cmd.directory(_path));
CRYPTOLOG("Found Structure: "<<i.print());
for (BerValues::iterator it(i.begin()); it!=i.end(); ++it) {
CRYPTOLOG(" -> Value: "<<it->print());
if (it->size()<2) continue; // empty dir
switch ((*it)[0].ulong()) {
case 0x38:
_children.push_back(Child(new Dir(cmd, _path+(*it)[1].hex())));
break;
case 0x01:
_children.push_back(Child(new File(cmd, _path, (*it)[1].hex())));
break;
case 0x05:
_children.push_back(Child(new Link(cmd, _path, (*it)[1].hex())));
break;
case 0x06:
_children.push_back(Child(new Counter(cmd, _path, (*it)[1].hex())));
break;
default: // unknown
throw runtime_error("unknown object: "+it->print());
}
}
}
};
//@} //@}
} }

@ -36,15 +36,19 @@
# else # else
# include <iostream> # include <iostream>
# define CRYPTOLOG(X) { \ # define CRYPTOLOG(X) { \
std::string file(__FILE__); \ std::string __C_FILE__(__FILE__); \
std::string line(CRYPTOLOG_QUOTE(__LINE__)); \ std::string __C_LINE__(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type pos(file.rfind('/')); \ std::string::size_type __LOC_POS__(__C_FILE__.rfind('/')); \
if (pos!=std::string::npos) file=file.substr(pos+1); \ if (__LOC_POS__!=std::string::npos) \
std::string spc1(18>file.size()?std::string(18-file.size(), ' ') \ __C_FILE__=__C_FILE__.substr(__LOC_POS__+1); \
:std::string()); \ std::string __LOC_SPC1__(18>__C_FILE__.size() \
std::string spc2(4>line.size()?std::string(4-line.size(), ' ') \ ?std::string(18-__C_FILE__.size(), ' ') \
:std::string()); \ :std::string()); \
std::clog<<"CRYPTO: "<<spc1<<file<<':'<<spc2<<line<<" -- "<<X \ std::string __LOC_SPC2__(4>__C_LINE__.size() \
?std::string(4-__C_LINE__.size(), ' ') \
:std::string()); \
std::clog<<"CRYPTO: "<<__LOC_SPC1__<<__C_FILE__ \
<<':'<<__LOC_SPC2__<<__C_LINE__<<" -- "<<X \
<<CRYPTOLOG_END; \ <<CRYPTOLOG_END; \
} }
# endif # endif
@ -58,15 +62,19 @@
# else # else
# include <iostream> # include <iostream>
# define CRYPTOLOG_VERBOSE(X) { \ # define CRYPTOLOG_VERBOSE(X) { \
std::string file(__FILE__); \ std::string __C_FILE__(__FILE__); \
std::string line(CRYPTOLOG_QUOTE(__LINE__)); \ std::string __C_LINE__(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type pos(file.rfind('/')); \ std::string::size_type __LOC_POS__(__C_FILE__.rfind('/')); \
if (pos!=std::string::npos) file=file.substr(pos+1); \ if (__LOC_POS__!=std::string::npos) \
std::string spc1(18>file.size()?std::string(18-file.size(), ' ') \ __C_FILE__=__C_FILE__.substr(__LOC_POS__+1); \
:std::string()); \ std::string __LOC_SPC1__(18>__C_FILE__.size() \
std::string spc2(4>line.size()?std::string(4-line.size(), ' ') \ ?std::string(18-__C_FILE__.size(), ' ') \
:std::string()); \ :std::string()); \
std::clog<<"CRYPTO: "<<spc1<<file<<':'<<spc2<<line<<" -- "<<X \ std::string __LOC_SPC2__(4>__C_LINE__.size() \
?std::string(4-__C_LINE__.size(), ' ') \
:std::string()); \
std::clog<<"CRYPTO: "<<__LOC_SPC1__<<__C_FILE__<<':' \
<<__LOC_SPC2__<<__C_LINE__<<" -- "<<X \
<<CRYPTOLOG_END; \ <<CRYPTOLOG_END; \
} }
# endif # endif
@ -168,7 +176,7 @@ namespace crypto {
inline std::string toBinary(unsigned long data, int bytes=2) { inline std::string toBinary(unsigned long data, int bytes=2) {
std::string res(0, bytes); std::string res(0, bytes);
for (int i(0); i<bytes; ++i) { for (int i(0); i<bytes; ++i) {
res[bytes-i-1] = data&0xff; res[i] = data&0xff;
data>>=8; data>>=8;
} }
return res; return res;
@ -177,9 +185,8 @@ namespace crypto {
/// convert integer from binary of given size /// convert integer from binary of given size
inline unsigned long ulongFromBinary(const std::string& data) { inline unsigned long ulongFromBinary(const std::string& data) {
unsigned long res(0); unsigned long res(0);
for (std::string::const_reverse_iterator it(data.rbegin()); for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it)
it!=data.rend(); ++it) (res<<=8)+=(unsigned long)(unsigned char)*it;
(res<<=8)+=(unsigned)*it;
return res; return res;
} }

@ -10,6 +10,8 @@ include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx \
openssl-engine.hxx suisseid.hxx cardos.hxx openssl-engine.hxx suisseid.hxx cardos.hxx
#certimport.hxx #certimport.hxx
noinst_HEADERS = cardgui.hxx cardgui-model.hxx
if !MINGW32 if !MINGW32
if MAC if MAC
AM_CPPFLAGS += -I/opt/local/include -I/Library/OpenSC/include AM_CPPFLAGS += -I/opt/local/include -I/Library/OpenSC/include
@ -29,15 +31,15 @@ pkgconfig2_DATA = $(pkgconfig_DATA)
EXTRA_DIST = $(pkgconfig_DATA).in ${top_srcdir}/src/*.doc EXTRA_DIST = $(pkgconfig_DATA).in ${top_srcdir}/src/*.doc
bin_PROGRAMS = cardgui
lib_LTLIBRARIES = libpcscxx.la lib_LTLIBRARIES = libpcscxx.la
libpcscxx_la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx version.cxx \ libpcscxx_la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx version.cxx \
openssl-engine.cxx openssl-engine.cxx
#moc_certimport.cxx #moc_certimport.cxx
libpcscxx_la_LDFLAGS = -version-info ${LIB_VERSION} libpcscxx_la_LDFLAGS = -version-info ${LIB_VERSION}
#libpcscxx_la_CXXFLAGS = ${QT_CFLAGS}
libpcscxx_la_LIBADD = -lssl -lcrypto libpcscxx_la_LIBADD = -lssl -lcrypto
# ${QT_LIBS}
if MINGW32 if MINGW32
libpcscxx_la_LIBADD += -lgdi32 -lws2_32 libpcscxx_la_LIBADD += -lgdi32 -lws2_32
else else
@ -47,15 +49,25 @@ libpcscxx_la_LIBADD += -lpcsclite
endif endif
endif endif
cardgui_SOURCES = cardgui.cxx
nodist_cardgui_SOURCES = cardgui_ui.hxx password_ui.hxx \
moc_cardgui.cxx moc_password.cxx moc_cardgui-model.cxx
BUILT_SOURCES = ${nodist_cardgui_SOURCES}
cardgui_CXXFLAGS = ${QT_GUI_CFLAGS} -fPIC
cardgui_LDADD = ${QT_GUI_LIBS} libpcscxx.la ${libpcscxx_la_LIBADD}
noinst_PROGRAMS = versiontest noinst_PROGRAMS = versiontest
versiontest_SOURCES = versiontest.cxx versiontest_SOURCES = versiontest.cxx
%_ui.hxx: %.ui
uic -o $@ $<
moc_%.cxx: %.hxx moc_%.cxx: %.hxx
moc -o $@ $< moc -o $@ $<
clean-local: clean-local:
-rm -r ${QMAKE_TARGET}.app -rm -r ${QMAKE_TARGET}.app
CLEANFILES = ${MOC_FILES} CLEANFILES = ${MOC_FILES} ${BUILT_SOURCES}
DISTCLEANFILES = $(pkgconfig_DATA) DISTCLEANFILES = $(pkgconfig_DATA)
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/) for use in the OpenSSL Toolkit (http://www.openssl.org/)
This product includes cryptographic software written by
Eric Young (eay@cryptsoft.com)
*/ */
// 1 2 3 4 5 6 7 8 // 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 // 45678901234567890123456789012345678901234567890123456789012345678901234567890

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/) for use in the OpenSSL Toolkit (http://www.openssl.org/)
This product includes cryptographic software written by
Eric Young (eay@cryptsoft.com)
*/ */
// 1 2 3 4 5 6 7 8 // 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 // 45678901234567890123456789012345678901234567890123456789012345678901234567890

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/) for use in the OpenSSL Toolkit (http://www.openssl.org/)
This product includes cryptographic software written by
Eric Young (eay@cryptsoft.com)
*/ */
// 1 2 3 4 5 6 7 8 // 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 // 45678901234567890123456789012345678901234567890123456789012345678901234567890

@ -0,0 +1,30 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef PASSWORD_HXX
#define PASSWORD_HXX
#include <password_ui.hxx>
class Password: public QDialog, protected Ui_Password {
Q_OBJECT;
public:
Password(QWidget* p=0):
QDialog(p) {
setupUi(this);
}
QString password() {
return _pwd->text();
}
};
#endif

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Password</class>
<widget class="QDialog" name="Password">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>152</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Your password is required to restart PCSC daemon. Please anter your user password and make sure, you are allowed to sudo on this host.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="_pwd">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Password</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Password</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

@ -12,7 +12,6 @@
#include <cryptaux.hxx> #include <cryptaux.hxx>
#include <mrw/shared.hxx>
#include <string> #include <string>
#ifdef WIN32 #ifdef WIN32
@ -205,7 +204,8 @@ namespace pcsc {
/*! @note Please note that the Reader is required in the /*! @note Please note that the Reader is required in the
destructor und must therefore live longer than the destructor und must therefore live longer than the
Transaction instance. */ Transaction instance. */
Transaction(mrw::Shared<Reader> r): _reader(r), _running(true) { Transaction(shared_ptr<Reader>::t r):
_reader(r), _running(true) {
CRYPTOLOG("log"); CRYPTOLOG("log");
_reader->beginTransaction(); _reader->beginTransaction();
} }
@ -222,7 +222,7 @@ namespace pcsc {
_running = false; _running = false;
} }
private: private:
mrw::Shared<Reader> _reader; shared_ptr<Reader>::t _reader;
bool _running; bool _running;
}; };
@ -424,7 +424,7 @@ namespace pcsc {
friend class Connection; friend class Connection;
//! Establishes a connection to the given named cardreader //! Establishes a connection to the given named cardreader
Reader(const std::string& nm, const Connection& c, Reader(const std::string& nm, shared_ptr<Connection>::t c,
DWORD mode=SCARD_SHARE_SHARED, DWORD mode=SCARD_SHARE_SHARED,
DWORD protocol=SCARD_PROTOCOL_T1): DWORD protocol=SCARD_PROTOCOL_T1):
name(nm), _connection(c) { name(nm), _connection(c) {
@ -441,7 +441,7 @@ namespace pcsc {
//...........................................................variables //...........................................................variables
private: private:
mrw::Shared<Connection> _connection; shared_ptr<Connection>::t _connection;
SCARDHANDLE _id; SCARDHANDLE _id;
DWORD _state; DWORD _state;
DWORD _protocol; DWORD _protocol;
@ -461,160 +461,108 @@ namespace pcsc {
//................................................................methods //................................................................methods
public: public:
//! Opens a connection (establishes a smartcard context)
/*! The errorhandling is defined with the @c exceptions flag:
Using exceptions:
@code
try {
pcsc::Connection c; // standard with exceptions
pcsc::Connection::Strings r(c.scan());
} catch (std::exception& x) {
std::cout<<"Error with message: "<<x.what()<<std::endl;
}
@endcode
Without exceptions:
@code
pcsc::Connection c(SYSTEM, false);
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl;
pcsc::Connection::Strings r(c.scan());
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl;
@endcode
Recommendation: Use exceptions!
@param s defines the scope of the connection
@param exceptions
- @c true: class throws exceptions in case of an error
- @c false: no exceptions, check your instance after each
operation */
Connection(Scope s=USER, bool exceptions=true):
_connectionlifetime(connectionlifetime(s, exceptions)) {
++connectionlifetimecounter();
CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter());
check("establish smartcard context");
}
Connection(const Connection& o) {
++connectionlifetimecounter();
*this = o;
}
//! Closes the connection (releases the smartcard context) //! Closes the connection (releases the smartcard context)
~Connection() { ~Connection() {
// connection is closed, when _connectionlifetime is destructed CRYPTOLOG("Close Connection id="<<_id);
if (--connectionlifetimecounter()==0) { _state = SCardReleaseContext(_id);
CRYPTOLOG("Delete Connection"); if (!std::uncaught_exception()) check("smartcard release context");
delete connectionlifetime();
connectionlifetime()=0;
}
CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter());
} }
//! Scans for available readers from a specified list of groups. //! Scans for available readers from a specified list of groups.
/*! Defaults to all groups. */ /*! Defaults to all groups. */
Strings scan(const Strings& groups = Strings()) { static Strings scan(const Strings& groups = Strings(),
Scope s=USER, bool exceptions=true) {
Connection c(s, exceptions);
Strings res; Strings res;
std::string grp(join(groups)); std::string grp(c.join(groups));
DWORD num(0); DWORD num(0);
if (!check(SCardListReaders(_connectionlifetime->id(), if (!c.check(SCardListReaders(c._id,
groups.size()?strconv(grp).data():0, 0, groups.size()?strconv(grp).data():0, 0,
&num), &num),
"smartcard get size of readers of groups "+grp)) "smartcard get size of readers of groups "+grp))
return res; return res;
CRYPTOLOG("size of readers: "<<num); CRYPTOLOG("size of readers: "<<num);
if (!num) return res; if (!num) return res;
std::auto_ptr<char_t> nm(new char_t[num]); std::auto_ptr<char_t> nm(new char_t[num]);
if (!check(SCardListReaders(_connectionlifetime->id(), if (!c.check(SCardListReaders(c._id,
groups.size()?strconv(grp).data():0, groups.size()?strconv(grp).data():0,
nm.get(), &num), nm.get(), &num),
"smartcard list reader names of groups "+grp)) "smartcard list reader names of groups "+grp))
return res; return res;
CRYPTOLOG("got all readers, size is "<<num); CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res; if (!num) return res;
CRYPTOLOG("list of readers: " CRYPTOLOG("list of readers: "
<<crypto::readable(std::string(nm.get(), num-1))); <<crypto::readable(std::string(nm.get(), num-1)));
return res = split(strconv(string(nm.get(), num-1))); return res = c.split(strconv(string(nm.get(), num-1)));
} }
//! Get a reader, open a connection if not already open.
/*! First use scan() to get a list of readers, then open a
connection to the reader, then access it. */
mrw::Shared<Reader> reader(const std::string& name) {
return _connectionlifetime->reader(name, this);
}
// //! Close connection of a named reader.
// /*! If you access the same reader through raeder() later, the
// connection will be reestablished. */
// void close(const std::string& s) {
// }
/// Reset and reestablish the connection.
/** @note You must remove all readers that have been returned by
@ref reader(), if you have assigned them to a variable
and stored them. Otherwise the connections will remain
open and next access should probably fail.
@begincode
{
mrw::Shared<Reader> r(c.reader(name));
// use r
c.reset(); // now r is invalid
// either reassign r:
r = c.reader(name);
// or simply reset it
r.reset();
}
// or clenaup by leaving the context of r
@endcode */
void reset() {
_connectionlifetime->reset();
}
//! Find all readers with a given ATR. //! Find all readers with a given ATR.
/*! @param atr full or partial ATR to match to the reader's ATR /*! @param atr full or partial ATR to match to the reader's ATR
@returns list of readers that contain @c atr in their ATR */ @returns list of readers that contain @c atr in their ATR */
Strings getReadersWithAtr(const std::string& atr) { static Strings getReadersWithAtr(const std::string& atr,
Scope s=USER, bool exceptions=true) {
Connection c(s, exceptions);
Strings res; Strings res;
pcsc::Connection::Strings readers(scan()); pcsc::Connection::Strings readers(c.scan());
for (pcsc::Connection::Strings::const_iterator it(readers.begin()); for (pcsc::Connection::Strings::const_iterator it(readers.begin());
it!=readers.end(); ++it) it!=readers.end(); ++it)
if (crypto::hex(reader(*it)->status().atr).find(atr)!=string::npos) if (crypto::hex(c.reader(*it)->status().atr).find(atr)!=string::npos)
res.push_back(*it); res.push_back(*it);
return res; return res;
} }
//! @c false if last operation was not successful //! Get a reader, open a connection if not already open.
operator bool() const { /*! First use scan() to get a list of readers, then open a
return *_connectionlifetime; connection to the reader, then access it. */
static shared_ptr<Reader>::t reader(const std::string& name,
Scope s=USER, bool exceptions=true) {
CRYPTOLOG("get reader: "<<name);
return shared_ptr<Reader>::t
(new Reader(name,
shared_ptr<Connection>::t
(new Connection(s, exceptions))));
} }
//................................................................methods //................................................................methods
private: private:
mrw::Shared<Reader> newreader(const std::string& name) { //! Opens a connection (establishes a smartcard context)
return new Reader(name, *this); /*! The errorhandling is defined with the @c exceptions flag:
}
//! Sets state and throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command. */
bool check(long state, const std::string& context="") {
_connectionlifetime->state(state);
return check(context);
}
//! Throws an exception if neccessary. Using exceptions:
/*! @throw access_error if it is instanciated for exceptions and @code
an error occured in the last command. */ try {
bool check(const std::string& context="") { pcsc::Connection c; // standard with exceptions
return _connectionlifetime->check(context); pcsc::Connection::Strings r(c.scan());
} catch (std::exception& x) {
std::cout<<"Error with message: "<<x.what()<<std::endl;
}
@endcode
Without exceptions:
@code
pcsc::Connection c(SYSTEM, false);
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl;
pcsc::Connection::Strings r(c.scan());
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl;
@endcode
Recommendation: Use exceptions!
@param s defines the scope of the connection
@param exceptions
- @c true: class throws exceptions in case of an error
- @c false: no exceptions, check your instance after each
operation */
Connection(Scope s=USER, bool exceptions=true):
_exc(exceptions), _id(0), _s(s),
_state(SCardEstablishContext(s, 0, 0, &_id)) {
CRYPTOLOG("Open Connection id="<<_id);
check("establish smartcard context");
} }
//! Splits a buffer with 0 separators into a vector of strings. //! Splits a buffer with 0 separators into a vector of strings.
Strings split(const std::string& in) { static Strings split(const std::string& in) {
Strings res; Strings res;
for (std::string::size_type pos(0); pos<in.size() && in[pos]!=0; for (std::string::size_type pos(0); pos<in.size() && in[pos]!=0;
pos+=res.rbegin()->size()+1) pos+=res.rbegin()->size()+1)
@ -623,7 +571,7 @@ namespace pcsc {
} }
//! Joins a vector of strings into a buffer with 0 separators. //! Joins a vector of strings into a buffer with 0 separators.
std::string join(const Strings& in) { static std::string join(const Strings& in) {
std::string res; std::string res;
if (in.size()) { if (in.size()) {
for (Strings::const_iterator it(in.begin()); for (Strings::const_iterator it(in.begin());
@ -634,498 +582,433 @@ namespace pcsc {
return res; return res;
} }
//! Connection id operator bool() const {
SCARDCONTEXT id() { #ifdef WIN32
return _connectionlifetime->id(); return (_state>>30&3)==0;
#else
return _state==SCARD_S_SUCCESS;
#endif
} }
//! @c true if exceptions are thrown //! Throws an exception if neccessary.
bool exc() { /*! @throw access_error if it is instanciated for exceptions and
return _connectionlifetime->exc(); an error occured in the last command. */
bool check(long state, const std::string& context="") {
_state = state;
check(context);
} }
//..............................................................variables //! Throws an exception if neccessary.
private: /*! @throw access_error if it is instanciated for exceptions and
class ConnectionLifetime {
public:
//! opens connection that is closed on destruction
ConnectionLifetime(Scope s, bool exc):
_exc(exc), _id(0), _s(s),
_state(SCardEstablishContext(s, 0, 0, &_id)) {
CRYPTOLOG("Open Connection");
check("establish smartcard context");
}
//! Closes the connection (releases the smartcard context)
~ConnectionLifetime() {
CRYPTOLOG("Close Connection");
_state = SCardReleaseContext(_id);
if (!std::uncaught_exception()) check("smartcard release context");
}
//! @c false if last operation was not successful
operator bool() const {
#ifdef WIN32
return (_state>>30&3)==0;
#else
return _state==SCARD_S_SUCCESS;
#endif
}
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command. */ an error occured in the last command. */
bool check(const std::string& context="") { bool check(const std::string& context="") {
if (_exc&&!*this) { if (_exc&&!*this) {
if (context.size()) { if (context.size()) {
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
if (_state==SCARD_W_WRONG_CHV) { if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(context+": "+error()); throw wrong_pin(context+": "+error());
} else { } else {
#endif #endif
throw access_error(context+": "+error()); throw access_error(context+": "+error());
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
} }
#endif #endif
} else { } else {
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
if (_state==SCARD_W_WRONG_CHV) { if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(error()); throw wrong_pin(error());
} else { } else {
#endif #endif
throw access_error(error()); throw access_error(error());
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
}
#endif
}
} }
return *this; #endif
} }
}
//! Get the describing text of the last error return *this;
std::string error() const { }
std::stringstream ss;
switch (_state) { //! Get the describing text of the last error
std::string error() const {
std::stringstream ss;
switch (_state) {
#ifdef SCARD_E_CANCELLED #ifdef SCARD_E_CANCELLED
case SCARD_E_CANCELLED: case SCARD_E_CANCELLED:
ss<<"The action was canceled by an SCardCancel request."; ss<<"The action was canceled by an SCardCancel request.";
break; break;
#endif #endif
#ifdef SCARD_E_CANT_DISPOSE #ifdef SCARD_E_CANT_DISPOSE
case SCARD_E_CANT_DISPOSE: case SCARD_E_CANT_DISPOSE:
ss<<"The system could not dispose of the media in the requested" ss<<"The system could not dispose of the media in the requested"
<<" manner."; <<" manner.";
break; break;
#endif #endif
#ifdef SCARD_E_CARD_UNSUPPORTED #ifdef SCARD_E_CARD_UNSUPPORTED
case SCARD_E_CARD_UNSUPPORTED: case SCARD_E_CARD_UNSUPPORTED:
ss<<"The smart card does not meet minimal requirements for" ss<<"The smart card does not meet minimal requirements for"
<<" support."; <<" support.";
break; break;
#endif #endif
#ifdef SCARD_E_DUPLICATE_READER #ifdef SCARD_E_DUPLICATE_READER
case SCARD_E_DUPLICATE_READER: case SCARD_E_DUPLICATE_READER:
ss<<"The reader driver did not produce a unique reader name."; ss<<"The reader driver did not produce a unique reader name.";
break; break;
#endif #endif
#ifdef SCARD_E_INSUFFICIENT_BUFFER #ifdef SCARD_E_INSUFFICIENT_BUFFER
case SCARD_E_INSUFFICIENT_BUFFER: case SCARD_E_INSUFFICIENT_BUFFER:
ss<<"The data buffer for returned data is too small for the" ss<<"The data buffer for returned data is too small for the"
<<" returned data."; <<" returned data.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_ATR #ifdef SCARD_E_INVALID_ATR
case SCARD_E_INVALID_ATR: case SCARD_E_INVALID_ATR:
ss<<"An ATR string obtained from the registry is not a valid" ss<<"An ATR string obtained from the registry is not a valid"
<<" ATR string."; <<" ATR string.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_HANDLE #ifdef SCARD_E_INVALID_HANDLE
case SCARD_E_INVALID_HANDLE: case SCARD_E_INVALID_HANDLE:
ss<<"The supplied handle was not valid."; ss<<"The supplied handle was not valid.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_PARAMETER #ifdef SCARD_E_INVALID_PARAMETER
case SCARD_E_INVALID_PARAMETER: case SCARD_E_INVALID_PARAMETER:
ss<<"One or more of the supplied parameters could not be properly" ss<<"One or more of the supplied parameters could not be properly"
<<" interpreted."; <<" interpreted.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_TARGET #ifdef SCARD_E_INVALID_TARGET
case SCARD_E_INVALID_TARGET: case SCARD_E_INVALID_TARGET:
ss<<"Registry startup information is missing or not valid."; ss<<"Registry startup information is missing or not valid.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_VALUE #ifdef SCARD_E_INVALID_VALUE
case SCARD_E_INVALID_VALUE: case SCARD_E_INVALID_VALUE:
ss<<"One or more of the supplied parameters values could not" ss<<"One or more of the supplied parameters values could not"
<<" be properly interpreted."; <<" be properly interpreted.";
break; break;
#endif #endif
#ifdef SCARD_E_NOT_READY #ifdef SCARD_E_NOT_READY
case SCARD_E_NOT_READY: case SCARD_E_NOT_READY:
ss<<"The reader or smart card is not ready to accept commands."; ss<<"The reader or smart card is not ready to accept commands.";
break; break;
#endif #endif
#ifdef SCARD_E_NOT_TRANSACTED #ifdef SCARD_E_NOT_TRANSACTED
case SCARD_E_NOT_TRANSACTED: case SCARD_E_NOT_TRANSACTED:
ss<<"An attempt was made to end a nonexistent transaction."; ss<<"An attempt was made to end a nonexistent transaction.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_MEMORY #ifdef SCARD_E_NO_MEMORY
case SCARD_E_NO_MEMORY: case SCARD_E_NO_MEMORY:
ss<<"Not enough memory available to complete this command."; ss<<"Not enough memory available to complete this command.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_SERVICE #ifdef SCARD_E_NO_SERVICE
case SCARD_E_NO_SERVICE: case SCARD_E_NO_SERVICE:
ss<<"The smart card resource manager is not running."; ss<<"The smart card resource manager is not running.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_SMARTCARD #ifdef SCARD_E_NO_SMARTCARD
case SCARD_E_NO_SMARTCARD: case SCARD_E_NO_SMARTCARD:
ss<<"The operation requires a smart card, but no smart card" ss<<"The operation requires a smart card, but no smart card"
<<" is currently in the device."; <<" is currently in the device.";
break; break;
#endif #endif
#ifdef SCARD_E_PCI_TOO_SMALL #ifdef SCARD_E_PCI_TOO_SMALL
case SCARD_E_PCI_TOO_SMALL: case SCARD_E_PCI_TOO_SMALL:
ss<<"The PCI receive buffer was too small."; ss<<"The PCI receive buffer was too small.";
break; break;
#endif #endif
#ifdef SCARD_E_PROTO_MISMATCH #ifdef SCARD_E_PROTO_MISMATCH
case SCARD_E_PROTO_MISMATCH: case SCARD_E_PROTO_MISMATCH:
ss<<"The requested protocols are incompatible with the protocol" ss<<"The requested protocols are incompatible with the protocol"
<<" currently in use with the smart card."; <<" currently in use with the smart card.";
break; break;
#endif #endif
#ifdef SCARD_E_READER_UNAVAILABLE #ifdef SCARD_E_READER_UNAVAILABLE
case SCARD_E_READER_UNAVAILABLE: case SCARD_E_READER_UNAVAILABLE:
ss<<"The specified reader is not currently available for use."; ss<<"The specified reader is not currently available for use.";
break; break;
#endif #endif
#ifdef SCARD_E_READER_UNSUPPORTED #ifdef SCARD_E_READER_UNSUPPORTED
case SCARD_E_READER_UNSUPPORTED: case SCARD_E_READER_UNSUPPORTED:
ss<<"The reader driver does not meet minimal requirements for" ss<<"The reader driver does not meet minimal requirements for"
<<" support."; <<" support.";
break; break;
#endif #endif
#ifdef SCARD_E_SERVICE_STOPPED #ifdef SCARD_E_SERVICE_STOPPED
case SCARD_E_SERVICE_STOPPED: case SCARD_E_SERVICE_STOPPED:
ss<<"The smart card resource manager has shut down."; ss<<"The smart card resource manager has shut down.";
break; break;
#endif #endif
#ifdef SCARD_E_SHARING_VIOLATION #ifdef SCARD_E_SHARING_VIOLATION
case SCARD_E_SHARING_VIOLATION: case SCARD_E_SHARING_VIOLATION:
ss<<"The smart card cannot be accessed because of other" ss<<"The smart card cannot be accessed because of other"
<<" outstanding connections."; <<" outstanding connections.";
break; break;
#endif #endif
#ifdef SCARD_E_SYSTEM_CANCELLED #ifdef SCARD_E_SYSTEM_CANCELLED
case SCARD_E_SYSTEM_CANCELLED: case SCARD_E_SYSTEM_CANCELLED:
ss<<"The action was cancelled by the system, presumably to log" ss<<"The action was cancelled by the system, presumably to log"
<<" off or shut down."; <<" off or shut down.";
break; break;
#endif #endif
#ifdef SCARD_E_TIMEOUT #ifdef SCARD_E_TIMEOUT
case SCARD_E_TIMEOUT: case SCARD_E_TIMEOUT:
ss<<"The user-specified time-out value has expired."; ss<<"The user-specified time-out value has expired.";
break; break;
#endif #endif
#ifdef SCARD_E_UNKNOWN_CARD #ifdef SCARD_E_UNKNOWN_CARD
case SCARD_E_UNKNOWN_CARD: case SCARD_E_UNKNOWN_CARD:
ss<<"The specified smart card name is not recognized."; ss<<"The specified smart card name is not recognized.";
break; break;
#endif #endif
#ifdef SCARD_E_UNKNOWN_READER #ifdef SCARD_E_UNKNOWN_READER
case SCARD_E_UNKNOWN_READER: case SCARD_E_UNKNOWN_READER:
ss<<"The specified reader name is not recognized."; ss<<"The specified reader name is not recognized.";
break; break;
#endif #endif
#ifdef SCARD_F_COMM_ERROR #ifdef SCARD_F_COMM_ERROR
case SCARD_F_COMM_ERROR: case SCARD_F_COMM_ERROR:
ss<<"An internal communications error has been detected."; ss<<"An internal communications error has been detected.";
break; break;
#endif #endif
#ifdef SCARD_F_INTERNAL_ERROR #ifdef SCARD_F_INTERNAL_ERROR
case SCARD_F_INTERNAL_ERROR: case SCARD_F_INTERNAL_ERROR:
ss<<"An internal consistency check failed."; ss<<"An internal consistency check failed.";
break; break;
#endif #endif
#ifdef SCARD_F_UNKNOWN_ERROR #ifdef SCARD_F_UNKNOWN_ERROR
case SCARD_F_UNKNOWN_ERROR: case SCARD_F_UNKNOWN_ERROR:
ss<<"An internal error has been detected, but the source is" ss<<"An internal error has been detected, but the source is"
<<" unknown."; <<" unknown.";
break; break;
#endif #endif
#ifdef SCARD_F_WAITED_TOO_LONG #ifdef SCARD_F_WAITED_TOO_LONG
case SCARD_F_WAITED_TOO_LONG: case SCARD_F_WAITED_TOO_LONG:
ss<<"An internal consistency timer has expired."; ss<<"An internal consistency timer has expired.";
break; break;
#endif #endif
#ifdef SCARD_S_SUCCESS #ifdef SCARD_S_SUCCESS
case SCARD_S_SUCCESS: case SCARD_S_SUCCESS:
ss<<"No error was encountered."; ss<<"No error was encountered.";
break; break;
#endif #endif
#ifdef SCARD_W_REMOVED_CARD #ifdef SCARD_W_REMOVED_CARD
case SCARD_W_REMOVED_CARD: case SCARD_W_REMOVED_CARD:
ss<<"The smart card has been removed, so that further" ss<<"The smart card has been removed, so that further"
<<" communication is not possible."; <<" communication is not possible.";
break; break;
#endif #endif
#ifdef SCARD_W_RESET_CARD #ifdef SCARD_W_RESET_CARD
case SCARD_W_RESET_CARD: case SCARD_W_RESET_CARD:
ss<<"The smart card was reset."; ss<<"The smart card was reset.";
break; break;
#endif #endif
#ifdef SCARD_W_UNPOWERED_CARD #ifdef SCARD_W_UNPOWERED_CARD
case SCARD_W_UNPOWERED_CARD: case SCARD_W_UNPOWERED_CARD:
ss<<"Power has been removed from the smart card, so that" ss<<"Power has been removed from the smart card, so that"
<<" further communication is not possible."; <<" further communication is not possible.";
break; break;
#endif #endif
#ifdef SCARD_W_UNRESPONSIVE_CARD #ifdef SCARD_W_UNRESPONSIVE_CARD
case SCARD_W_UNRESPONSIVE_CARD: case SCARD_W_UNRESPONSIVE_CARD:
ss<<"The smart card is not responding to a reset."; ss<<"The smart card is not responding to a reset.";
break; break;
#endif #endif
#ifdef SCARD_W_UNSUPPORTED_CARD #ifdef SCARD_W_UNSUPPORTED_CARD
case SCARD_W_UNSUPPORTED_CARD: case SCARD_W_UNSUPPORTED_CARD:
ss<<"The reader cannot communicate with the smart card," ss<<"The reader cannot communicate with the smart card,"
<<" due to ATR configuration conflicts."; <<" due to ATR configuration conflicts.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_READERS_AVAILABLE #ifdef SCARD_E_NO_READERS_AVAILABLE
case SCARD_E_NO_READERS_AVAILABLE: case SCARD_E_NO_READERS_AVAILABLE:
ss<<"No smart card reader is available."; ss<<"No smart card reader is available.";
break; break;
#endif #endif
#ifdef ERROR_BROKEN_PIPE #ifdef ERROR_BROKEN_PIPE
case ERROR_BROKEN_PIPE: case ERROR_BROKEN_PIPE:
ss<<"The client attempted a smart card operation in a" ss<<"The client attempted a smart card operation in a"
<<" remote session, such as a client session running" <<" remote session, such as a client session running"
<<" on a terminal server, and the operating system in" <<" on a terminal server, and the operating system in"
<<" use does not support smart card redirection."; <<" use does not support smart card redirection.";
break; break;
#endif #endif
#ifdef SCARD_E_BAD_SEEK #ifdef SCARD_E_BAD_SEEK
case SCARD_E_BAD_SEEK: case SCARD_E_BAD_SEEK:
ss<<"There was an error trying to set the smart card file" ss<<"There was an error trying to set the smart card file"
<<" object pointer."; <<" object pointer.";
break; break;
#endif #endif
#ifdef SCARD_E_CERTIFICATE_UNAVAILABLE #ifdef SCARD_E_CERTIFICATE_UNAVAILABLE
case SCARD_E_CERTIFICATE_UNAVAILABLE: case SCARD_E_CERTIFICATE_UNAVAILABLE:
ss<<"The requested certificate could not be obtained."; ss<<"The requested certificate could not be obtained.";
break; break;
#endif #endif
#ifdef SCARD_E_COMM_DATA_LOST #ifdef SCARD_E_COMM_DATA_LOST
case SCARD_E_COMM_DATA_LOST: case SCARD_E_COMM_DATA_LOST:
ss<<"A communications error with the smart card has been detected."; ss<<"A communications error with the smart card has been detected.";
break; break;
#endif #endif
#ifdef SCARD_E_DIR_NOT_FOUND #ifdef SCARD_E_DIR_NOT_FOUND
case SCARD_E_DIR_NOT_FOUND: case SCARD_E_DIR_NOT_FOUND:
ss<<"The specified directory does not exist in the smart card."; ss<<"The specified directory does not exist in the smart card.";
break; break;
#endif #endif
#ifdef SCARD_E_FILE_NOT_FOUND #ifdef SCARD_E_FILE_NOT_FOUND
case SCARD_E_FILE_NOT_FOUND: case SCARD_E_FILE_NOT_FOUND:
ss<<"The specified file does not exist in the smart card."; ss<<"The specified file does not exist in the smart card.";
break; break;
#endif #endif
#ifdef SCARD_E_ICC_CREATEORDER #ifdef SCARD_E_ICC_CREATEORDER
case SCARD_E_ICC_CREATEORDER: case SCARD_E_ICC_CREATEORDER:
ss<<"The requested order of object creation is not supported."; ss<<"The requested order of object creation is not supported.";
break; break;
#endif #endif
#ifdef SCARD_E_ICC_INSTALLATION #ifdef SCARD_E_ICC_INSTALLATION
case SCARD_E_ICC_INSTALLATION: case SCARD_E_ICC_INSTALLATION:
ss<<"No primary provider can be found for the smart card."; ss<<"No primary provider can be found for the smart card.";
break; break;
#endif #endif
#ifdef SCARD_E_INVALID_CHV #ifdef SCARD_E_INVALID_CHV
case SCARD_E_INVALID_CHV: case SCARD_E_INVALID_CHV:
ss<<"The supplied PIN is incorrect."; ss<<"The supplied PIN is incorrect.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_ACCESS #ifdef SCARD_E_NO_ACCESS
case SCARD_E_NO_ACCESS: case SCARD_E_NO_ACCESS:
ss<<"Access is denied to this file."; ss<<"Access is denied to this file.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_DIR #ifdef SCARD_E_NO_DIR
case SCARD_E_NO_DIR: case SCARD_E_NO_DIR:
ss<<"The supplied path does not represent a smart card directory."; ss<<"The supplied path does not represent a smart card directory.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_FILE #ifdef SCARD_E_NO_FILE
case SCARD_E_NO_FILE: case SCARD_E_NO_FILE:
ss<<"The supplied path does not represent a smart card file."; ss<<"The supplied path does not represent a smart card file.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_KEY_CONTAINER #ifdef SCARD_E_NO_KEY_CONTAINER
case SCARD_E_NO_KEY_CONTAINER: case SCARD_E_NO_KEY_CONTAINER:
ss<<"The requested key container does not exist on the smart card."; ss<<"The requested key container does not exist on the smart card.";
break; break;
#endif #endif
#ifdef SCARD_E_NO_SUCH_CERTIFICATE #ifdef SCARD_E_NO_SUCH_CERTIFICATE
case SCARD_E_NO_SUCH_CERTIFICATE: case SCARD_E_NO_SUCH_CERTIFICATE:
ss<<"The requested certificate does not exist."; ss<<"The requested certificate does not exist.";
break; break;
#endif #endif
#ifdef SCARD_E_SERVER_TOO_BUSY #ifdef SCARD_E_SERVER_TOO_BUSY
case SCARD_E_SERVER_TOO_BUSY: case SCARD_E_SERVER_TOO_BUSY:
ss<<"The Smart card resource manager is too busy to complete this" ss<<"The Smart card resource manager is too busy to complete this"
<<" operation."; <<" operation.";
break; break;
#endif #endif
#ifdef SCARD_E_UNSUPPORTED_FEATURE #ifdef SCARD_E_UNSUPPORTED_FEATURE
case SCARD_E_UNSUPPORTED_FEATURE: case SCARD_E_UNSUPPORTED_FEATURE:
ss<<"This smart card does not support the requested feature."; ss<<"This smart card does not support the requested feature.";
break; break;
#else #else
#ifdef SCARD_E_UNEXPECTED #ifdef SCARD_E_UNEXPECTED
case SCARD_E_UNEXPECTED: case SCARD_E_UNEXPECTED:
ss<<"An unexpected card error has occurred."; ss<<"An unexpected card error has occurred.";
break; break;
#endif #endif
#endif #endif
#ifdef SCARD_E_UNKNOWN_RES_MNG #ifdef SCARD_E_UNKNOWN_RES_MNG
case SCARD_E_UNKNOWN_RES_MNG: case SCARD_E_UNKNOWN_RES_MNG:
ss<<"An unrecognized error code was returned from a layered" ss<<"An unrecognized error code was returned from a layered"
<<" component."; <<" component.";
break; break;
#endif #endif
#ifdef SCARD_E_WRITE_TOO_MANY #ifdef SCARD_E_WRITE_TOO_MANY
case SCARD_E_WRITE_TOO_MANY: case SCARD_E_WRITE_TOO_MANY:
ss<<"The smartcard does not have enough memory to store the" ss<<"The smartcard does not have enough memory to store the"
<<" information."; <<" information.";
break; break;
#endif #endif
#ifdef SCARD_P_SHUTDOWN #ifdef SCARD_P_SHUTDOWN
case SCARD_P_SHUTDOWN: case SCARD_P_SHUTDOWN:
ss<<"The operation has been aborted to allow the server application" ss<<"The operation has been aborted to allow the server application"
<<" to exit."; <<" to exit.";
break; break;
#endif #endif
#ifdef SCARD_W_CANCELLED_BY_USER #ifdef SCARD_W_CANCELLED_BY_USER
case SCARD_W_CANCELLED_BY_USER: case SCARD_W_CANCELLED_BY_USER:
ss<<"The action was cancelled by the user."; ss<<"The action was cancelled by the user.";
break; break;
#endif #endif
#ifdef SCARD_W_CARD_NOT_AUTHENTICATED #ifdef SCARD_W_CARD_NOT_AUTHENTICATED
case SCARD_W_CARD_NOT_AUTHENTICATED: case SCARD_W_CARD_NOT_AUTHENTICATED:
ss<<"No PIN was presented to the smart card."; ss<<"No PIN was presented to the smart card.";
break; break;
#endif #endif
#ifdef SCARD_W_CHV_BLOCKED #ifdef SCARD_W_CHV_BLOCKED
case SCARD_W_CHV_BLOCKED: case SCARD_W_CHV_BLOCKED:
ss<<"The card cannot be accessed because the maximum number" ss<<"The card cannot be accessed because the maximum number"
<<" of PIN entry attempts has been reached."; <<" of PIN entry attempts has been reached.";
break; break;
#endif #endif
#ifdef SCARD_W_EOF #ifdef SCARD_W_EOF
case SCARD_W_EOF: case SCARD_W_EOF:
ss<<"The end of the smart card file has been reached."; ss<<"The end of the smart card file has been reached.";
break; break;
#endif #endif
#ifdef SCARD_W_SECURITY_VIOLATION #ifdef SCARD_W_SECURITY_VIOLATION
case SCARD_W_SECURITY_VIOLATION: case SCARD_W_SECURITY_VIOLATION:
ss<<"Access was denied because of a security violation."; ss<<"Access was denied because of a security violation.";
break; break;
#endif #endif
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
case SCARD_W_WRONG_CHV: case SCARD_W_WRONG_CHV:
ss<<"The card cannot be accessed because the wrong PIN was" ss<<"The card cannot be accessed because the wrong PIN was"
<<" presented."; <<" presented.";
break; break;
#endif #endif
default: default:
ss<<"unknown PCSC state=0x" ss<<"unknown PCSC state=0x"
<<std::hex<<std::setfill('0')<<std::setw(8)<<_state; <<std::hex<<std::setfill('0')<<std::setw(8)<<_state;
switch (_state>>30) { switch (_state>>30) {
case 0: ss<<" means SUCCESS"; break; case 0: ss<<" means SUCCESS"; break;
case 1: ss<<" means INFORMATIONAL"; break; case 1: ss<<" means INFORMATIONAL"; break;
case 2: ss<<" means WARNING"; break; case 2: ss<<" means WARNING"; break;
case 3: ss<<" means ERROR"; break; case 3: ss<<" means ERROR"; break;
default: ss<<" illegal value"; default: ss<<" illegal value";
}
ss<<" C="<<(_state>>29&1);
ss<<" R="<<(_state>>28&1);
ss<<" Facility=0x"<<std::hex<<std::setfill('0')<<std::setw(3)
<<(_state>>16&0xfff);
ss<<" Code=0x"<<std::hex<<std::setfill('0')<<std::setw(4)
<<(_state&0xffff);
} }
return ss.str(); ss<<" C="<<(_state>>29&1);
} ss<<" R="<<(_state>>28&1);
//! set state ss<<" Facility=0x"<<std::hex<<std::setfill('0')<<std::setw(3)
void state(long s) { <<(_state>>16&0xfff);
_state = s; ss<<" Code=0x"<<std::hex<<std::setfill('0')<<std::setw(4)
} <<(_state&0xffff);
//! @returns state
long state() {
return _state;
}
//! @returns connection id
SCARDCONTEXT id() {
return _id;
}
bool exc() {
return _exc;
}
//! Get a reader, open a connection if not already open.
/*! First use scan() to get a list of readers, then open a
connection to the reader, then access it. */
mrw::Shared<Reader> reader(const std::string& name, Connection* c) {
CRYPTOLOG("get reader: "<<name<<" from "<<(void*)&_readers);
if (_readers.find(name)==_readers.end())
_readers.insert(std::make_pair(name, c->newreader(name)));
return _readers.find(name)->second;
}
/// Cleans up the readers, resets the context.
void reset() {
_readers.clear();
_state = SCardReleaseContext(_id);
check("smartcard release context");
_state = SCardEstablishContext(_s, 0, 0, &_id);
check("establish smartcard context");
}
private:
bool _exc;
SCARDCONTEXT _id;
Scope _s;
long _state;
//! Readers are closed when the last shared object is destructed
std::map<std::string, mrw::Shared<Reader> > _readers;
};
//! Connection is closed when the last shared object is destructed
/*! Handling the connection lifetime in a separate shared object
allows to copy connections and still make sure, that the
lifetime of the connection is as long as all copied opbjects
live. */
static ConnectionLifetime*&
connectionlifetime(Scope s=USER, bool exc=true) {
static ConnectionLifetime* instance(0);
if (instance==0) {
CRYPTOLOG("New Connection");
instance = new ConnectionLifetime(s, exc);
} }
return instance; return ss.str();
} }
//! set state
static int& connectionlifetimecounter() { void state(long s) {
static int instance(0); _state = s;
return instance; }
//! @returns state
long state() {
return _state;
}
//! @returns connection id
SCARDCONTEXT id() {
return _id;
} }
bool exc() {
return _exc;
}
private:
ConnectionLifetime* _connectionlifetime; bool _exc;
SCARDCONTEXT _id;
Scope _s;
long _state;
}; };

@ -395,22 +395,10 @@ namespace suisseid {
_cryptoki(lib) { _cryptoki(lib) {
} }
Scanner(const pcsc::Connection& pcsc,
const std::string& lib="libcvP11.so"):
_pcsc(pcsc),
_cryptoki(lib) {
}
Scanner(const cryptoki::Library& cryptoki): Scanner(const cryptoki::Library& cryptoki):
_cryptoki(cryptoki) { _cryptoki(cryptoki) {
} }
Scanner(const pcsc::Connection& pcsc,
const cryptoki::Library& cryptoki):
_pcsc(pcsc),
_cryptoki(cryptoki) {
}
/// Scan for available known SuisseID cards on the system. /// Scan for available known SuisseID cards on the system.
/** @return List of detected SuisseID smart cards. */ /** @return List of detected SuisseID smart cards. */
Cards scan() { Cards scan() {
@ -418,20 +406,20 @@ namespace suisseid {
Cards res; Cards res;
// By now, scan only for PostSuisseID; in future use factory pattern // By now, scan only for PostSuisseID; in future use factory pattern
pcsc::Connection::Strings readers pcsc::Connection::Strings readers
(_pcsc.getReadersWithAtr("4b53776973735369676e")); (pcsc::Connection::getReadersWithAtr("4b53776973735369676e"));
for (pcsc::Connection::Strings::iterator reader(readers.begin()); for (pcsc::Connection::Strings::iterator reader(readers.begin());
reader!=readers.end(); ++reader) { reader!=readers.end(); ++reader) {
cryptoki::SlotList slots(_cryptoki.slotList(true, *reader)); cryptoki::SlotList slots(_cryptoki.slotList(true, *reader));
if (slots.size()==1) if (slots.size()==1)
res.push_back(dynamic_cast<Card*> res.push_back(dynamic_cast<Card*>
(new Post(_pcsc.reader(*reader), _cryptoki))); (new Post(pcsc::Connection::reader(*reader),
_cryptoki)));
} }
return res; return res;
} }
private: private:
pcsc::Connection _pcsc;
cryptoki::Library _cryptoki; cryptoki::Library _cryptoki;
}; };

Loading…
Cancel
Save