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
m4_define(x_packagename, libpcscxx)
m4_define(x_major, 2)
m4_define(x_major, 3)
m4_define(x_minor, 0)
PACKAGENAME=x_packagename
MAJOR=x_major
@ -94,7 +94,12 @@ AC_CHECK_PROG(have_dot, dot, yes, no)
PKG_PROG_PKG_CONFIG
# 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,
[AS_HELP_STRING([--enable-pedantic],

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

@ -21,13 +21,10 @@
#include <iostream>
#include <iomanip>
pcsc::Connection c;
pcsc::Connection::Strings readers;
void list() {
pcsc::Connection c;
pcsc::Connection::Strings readers(c.scan());
pcsc::Connection::Strings readers(pcsc::Connection::scan());
std::cout<<"Found "<<readers.size()<<" readers"
<<(readers.size()?":":".")<<std::endl;
int i(0);
@ -39,7 +36,7 @@ void list() {
int main(int argc, char** argv) try {
int reader(0);
std::string pin;
std::string path("3f005015");
std::string path("3f00");
std::string id("8888");
std::string data("Hallo Welt");
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::param(data, "text"))
);
pcsc::Connection c;
pcsc::Connection::Strings readers(c.scan());
pcsc::Connection::Strings readers(pcsc::Connection::scan());
if (reader<0 || readers.size()<reader) {
std::cerr<<"reader not found: "<<reader<<std::endl;
return 1;
}
cardos::Commands cmd(c.reader(readers[reader]));
//cardos::BerValues d(cmd.directory(path));
cardos::Commands cmd(pcsc::Connection::reader(readers[reader]));
cardos::Dir d(cmd, 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::cout<<"HEX:"<<std::endl<<crypto::readable(res)<<std::endl;
//std::cout<<"BER:"<<std::endl<<cardos::BerValues(res).print()<<std::endl;
if (!pin.size()) {
std::cout<<"PIN: ";
std::cin>>pin;
}
if (pin.size()) cmd.logonTransport(pin);
cmd.phaseControl();
cmd.createBinary(path, id, data);
cmd.phaseControl();
// if (!pin.size()) {
// std::cout<<"PIN: ";
// std::cin>>pin;
// }
// if (pin.size()) cmd.logonTransport(pin);
// cmd.phaseControl();
// cmd.createBinary(path, id, data);
// cmd.phaseControl();
return 0;
} catch (std::exception& x) {
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
cardos_demo_SOURCES = cardos-demo.cxx
suisse_id_demo_SOURCES = suisse-id-demo.cxx
create_files_demo_SOURCES = create-files-demo.cxx
# moc_suisse-id-demo.cxx
suisse_id_demo_CXXFLAGS = ${QT_CFLAGS}
suisse_id_demo_LDADD = ${QT_LIBS}
suisse_id_demo_CXXFLAGS = ${QT_NETWORK_CFLAGS} -fPIC
suisse_id_demo_LDADD = ${QT_NETWORK_LIBS}
create_files_demo_SOURCES = create-files-demo.cxx
%_ui.hxx: %.ui
uic -o $@ $<
moc_%.cxx: %.hxx
moc -o $@ $<
CLEANFILES = moc_suisse-id-demo.cxx
CLEANFILES = ${BUILT_SOURCES}
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>
int main(int, char const*const*const argv) try {
pcsc::Connection c;
pcsc::Connection::Strings reader(c.scan());
pcsc::Connection::Strings reader(pcsc::Connection::scan());
std::cout<<"Library-Version: "<<pcsc::version()<<std::endl;
std::cout<<"Suche PCSC-Reader ..."<<std::endl;
if (!reader.size()) std::cout<<"Keine gefunden."<<std::endl;
for (pcsc::Connection::Strings::const_iterator it(reader.begin());
it!=reader.end(); ++it) {
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<<"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 {
public:
@ -262,6 +264,10 @@ namespace cardos {
return _value;
}
std::string hex() {
return crypto::hex(_value);
}
unsigned long ulong() {
return crypto::ulongFromBinary(_value);
}
@ -346,6 +352,7 @@ namespace cardos {
};
//============================================================================
/// Store a sequence of BerValue
class BerValues: public std::vector<BerValue> {
public:
@ -401,12 +408,7 @@ namespace cardos {
}
};
//@}
//============================================================================
/// @addtogroup cardoslib
//@{
/// Implements CardOS V4.4 commands.
/** Directly sends CardOS V4.4 commands to a smart card using APDUs. */
class Commands {
@ -422,12 +424,12 @@ namespace cardos {
Commands() {}
/// Initialize with given smart card reader.
Commands(mrw::Shared<pcsc::Connection::Reader> reader):
Commands(pcsc::shared_ptr<pcsc::Connection::Reader>::t reader):
_reader(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;
}
@ -941,10 +943,13 @@ namespace cardos {
};
//! 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,
ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path);
return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode));
}
@ -1529,9 +1534,215 @@ namespace cardos {
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
# include <iostream>
# define CRYPTOLOG(X) { \
std::string file(__FILE__); \
std::string line(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type pos(file.rfind('/')); \
if (pos!=std::string::npos) file=file.substr(pos+1); \
std::string spc1(18>file.size()?std::string(18-file.size(), ' ') \
:std::string()); \
std::string spc2(4>line.size()?std::string(4-line.size(), ' ') \
:std::string()); \
std::clog<<"CRYPTO: "<<spc1<<file<<':'<<spc2<<line<<" -- "<<X \
std::string __C_FILE__(__FILE__); \
std::string __C_LINE__(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type __LOC_POS__(__C_FILE__.rfind('/')); \
if (__LOC_POS__!=std::string::npos) \
__C_FILE__=__C_FILE__.substr(__LOC_POS__+1); \
std::string __LOC_SPC1__(18>__C_FILE__.size() \
?std::string(18-__C_FILE__.size(), ' ') \
:std::string()); \
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; \
}
# endif
@ -58,15 +62,19 @@
# else
# include <iostream>
# define CRYPTOLOG_VERBOSE(X) { \
std::string file(__FILE__); \
std::string line(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type pos(file.rfind('/')); \
if (pos!=std::string::npos) file=file.substr(pos+1); \
std::string spc1(18>file.size()?std::string(18-file.size(), ' ') \
:std::string()); \
std::string spc2(4>line.size()?std::string(4-line.size(), ' ') \
:std::string()); \
std::clog<<"CRYPTO: "<<spc1<<file<<':'<<spc2<<line<<" -- "<<X \
std::string __C_FILE__(__FILE__); \
std::string __C_LINE__(CRYPTOLOG_QUOTE(__LINE__)); \
std::string::size_type __LOC_POS__(__C_FILE__.rfind('/')); \
if (__LOC_POS__!=std::string::npos) \
__C_FILE__=__C_FILE__.substr(__LOC_POS__+1); \
std::string __LOC_SPC1__(18>__C_FILE__.size() \
?std::string(18-__C_FILE__.size(), ' ') \
:std::string()); \
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; \
}
# endif
@ -168,7 +176,7 @@ namespace crypto {
inline std::string toBinary(unsigned long data, int bytes=2) {
std::string res(0, bytes);
for (int i(0); i<bytes; ++i) {
res[bytes-i-1] = data&0xff;
res[i] = data&0xff;
data>>=8;
}
return res;
@ -177,9 +185,8 @@ namespace crypto {
/// convert integer from binary of given size
inline unsigned long ulongFromBinary(const std::string& data) {
unsigned long res(0);
for (std::string::const_reverse_iterator it(data.rbegin());
it!=data.rend(); ++it)
(res<<=8)+=(unsigned)*it;
for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it)
(res<<=8)+=(unsigned long)(unsigned char)*it;
return res;
}

@ -10,6 +10,8 @@ include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx \
openssl-engine.hxx suisseid.hxx cardos.hxx
#certimport.hxx
noinst_HEADERS = cardgui.hxx cardgui-model.hxx
if !MINGW32
if MAC
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
bin_PROGRAMS = cardgui
lib_LTLIBRARIES = libpcscxx.la
libpcscxx_la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx version.cxx \
openssl-engine.cxx
#moc_certimport.cxx
libpcscxx_la_LDFLAGS = -version-info ${LIB_VERSION}
#libpcscxx_la_CXXFLAGS = ${QT_CFLAGS}
libpcscxx_la_LIBADD = -lssl -lcrypto
# ${QT_LIBS}
if MINGW32
libpcscxx_la_LIBADD += -lgdi32 -lws2_32
else
@ -47,15 +49,25 @@ libpcscxx_la_LIBADD += -lpcsclite
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
versiontest_SOURCES = versiontest.cxx
%_ui.hxx: %.ui
uic -o $@ $<
moc_%.cxx: %.hxx
moc -o $@ $<
clean-local:
-rm -r ${QMAKE_TARGET}.app
CLEANFILES = ${MOC_FILES}
CLEANFILES = ${MOC_FILES} ${BUILT_SOURCES}
DISTCLEANFILES = $(pkgconfig_DATA)
MAINTAINERCLEANFILES = makefile.in

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project
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
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project
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
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

@ -5,6 +5,8 @@
This product includes software developed by the OpenSSL Project
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
// 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 <mrw/shared.hxx>
#include <string>
#ifdef WIN32
@ -205,7 +204,8 @@ namespace pcsc {
/*! @note Please note that the Reader is required in the
destructor und must therefore live longer than the
Transaction instance. */
Transaction(mrw::Shared<Reader> r): _reader(r), _running(true) {
Transaction(shared_ptr<Reader>::t r):
_reader(r), _running(true) {
CRYPTOLOG("log");
_reader->beginTransaction();
}
@ -222,7 +222,7 @@ namespace pcsc {
_running = false;
}
private:
mrw::Shared<Reader> _reader;
shared_ptr<Reader>::t _reader;
bool _running;
};
@ -424,7 +424,7 @@ namespace pcsc {
friend class Connection;
//! 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 protocol=SCARD_PROTOCOL_T1):
name(nm), _connection(c) {
@ -441,7 +441,7 @@ namespace pcsc {
//...........................................................variables
private:
mrw::Shared<Connection> _connection;
shared_ptr<Connection>::t _connection;
SCARDHANDLE _id;
DWORD _state;
DWORD _protocol;
@ -461,160 +461,108 @@ namespace pcsc {
//................................................................methods
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)
~Connection() {
// connection is closed, when _connectionlifetime is destructed
if (--connectionlifetimecounter()==0) {
CRYPTOLOG("Delete Connection");
delete connectionlifetime();
connectionlifetime()=0;
}
CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter());
CRYPTOLOG("Close Connection id="<<_id);
_state = SCardReleaseContext(_id);
if (!std::uncaught_exception()) check("smartcard release context");
}
//! Scans for available readers from a specified list of 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;
std::string grp(join(groups));
std::string grp(c.join(groups));
DWORD num(0);
if (!check(SCardListReaders(_connectionlifetime->id(),
groups.size()?strconv(grp).data():0, 0,
&num),
"smartcard get size of readers of groups "+grp))
if (!c.check(SCardListReaders(c._id,
groups.size()?strconv(grp).data():0, 0,
&num),
"smartcard get size of readers of groups "+grp))
return res;
CRYPTOLOG("size of readers: "<<num);
if (!num) return res;
std::auto_ptr<char_t> nm(new char_t[num]);
if (!check(SCardListReaders(_connectionlifetime->id(),
groups.size()?strconv(grp).data():0,
nm.get(), &num),
"smartcard list reader names of groups "+grp))
if (!c.check(SCardListReaders(c._id,
groups.size()?strconv(grp).data():0,
nm.get(), &num),
"smartcard list reader names of groups "+grp))
return res;
CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res;
CRYPTOLOG("list of readers: "
<<crypto::readable(std::string(nm.get(), num-1)));
return res = split(strconv(string(nm.get(), num-1)));
<<crypto::readable(std::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.
/*! @param atr full or partial ATR to match to the reader's 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;
pcsc::Connection::Strings readers(scan());
pcsc::Connection::Strings readers(c.scan());
for (pcsc::Connection::Strings::const_iterator it(readers.begin());
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);
return res;
}
//! @c false if last operation was not successful
operator bool() const {
return *_connectionlifetime;
//! 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. */
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
private:
mrw::Shared<Reader> newreader(const std::string& name) {
return new Reader(name, *this);
}
//! 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);
}
//! Opens a connection (establishes a smartcard context)
/*! The errorhandling is defined with the @c exceptions flag:
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command. */
bool check(const std::string& context="") {
return _connectionlifetime->check(context);
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):
_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.
Strings split(const std::string& in) {
static Strings split(const std::string& in) {
Strings res;
for (std::string::size_type pos(0); pos<in.size() && in[pos]!=0;
pos+=res.rbegin()->size()+1)
@ -623,7 +571,7 @@ namespace pcsc {
}
//! 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;
if (in.size()) {
for (Strings::const_iterator it(in.begin());
@ -634,498 +582,433 @@ namespace pcsc {
return res;
}
//! Connection id
SCARDCONTEXT id() {
return _connectionlifetime->id();
operator bool() const {
#ifdef WIN32
return (_state>>30&3)==0;
#else
return _state==SCARD_S_SUCCESS;
#endif
}
//! @c true if exceptions are thrown
bool exc() {
return _connectionlifetime->exc();
//! 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="") {
_state = state;
check(context);
}
//..............................................................variables
private:
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
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command. */
bool check(const std::string& context="") {
if (_exc&&!*this) {
if (context.size()) {
bool check(const std::string& context="") {
if (_exc&&!*this) {
if (context.size()) {
#ifdef SCARD_W_WRONG_CHV
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(context+": "+error());
} else {
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(context+": "+error());
} else {
#endif
throw access_error(context+": "+error());
throw access_error(context+": "+error());
#ifdef SCARD_W_WRONG_CHV
}
}
#endif
} else {
} else {
#ifdef SCARD_W_WRONG_CHV
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(error());
} else {
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(error());
} else {
#endif
throw access_error(error());
throw access_error(error());
#ifdef SCARD_W_WRONG_CHV
}
#endif
}
}
return *this;
#endif
}
//! Get the describing text of the last error
std::string error() const {
std::stringstream ss;
switch (_state) {
}
return *this;
}
//! Get the describing text of the last error
std::string error() const {
std::stringstream ss;
switch (_state) {
#ifdef SCARD_E_CANCELLED
case SCARD_E_CANCELLED:
ss<<"The action was canceled by an SCardCancel request.";
break;
case SCARD_E_CANCELLED:
ss<<"The action was canceled by an SCardCancel request.";
break;
#endif
#ifdef SCARD_E_CANT_DISPOSE
case SCARD_E_CANT_DISPOSE:
ss<<"The system could not dispose of the media in the requested"
<<" manner.";
break;
case SCARD_E_CANT_DISPOSE:
ss<<"The system could not dispose of the media in the requested"
<<" manner.";
break;
#endif
#ifdef SCARD_E_CARD_UNSUPPORTED
case SCARD_E_CARD_UNSUPPORTED:
ss<<"The smart card does not meet minimal requirements for"
<<" support.";
break;
case SCARD_E_CARD_UNSUPPORTED:
ss<<"The smart card does not meet minimal requirements for"
<<" support.";
break;
#endif
#ifdef SCARD_E_DUPLICATE_READER
case SCARD_E_DUPLICATE_READER:
ss<<"The reader driver did not produce a unique reader name.";
break;
case SCARD_E_DUPLICATE_READER:
ss<<"The reader driver did not produce a unique reader name.";
break;
#endif
#ifdef SCARD_E_INSUFFICIENT_BUFFER
case SCARD_E_INSUFFICIENT_BUFFER:
ss<<"The data buffer for returned data is too small for the"
<<" returned data.";
break;
case SCARD_E_INSUFFICIENT_BUFFER:
ss<<"The data buffer for returned data is too small for the"
<<" returned data.";
break;
#endif
#ifdef SCARD_E_INVALID_ATR
case SCARD_E_INVALID_ATR:
ss<<"An ATR string obtained from the registry is not a valid"
<<" ATR string.";
break;
case SCARD_E_INVALID_ATR:
ss<<"An ATR string obtained from the registry is not a valid"
<<" ATR string.";
break;
#endif
#ifdef SCARD_E_INVALID_HANDLE
case SCARD_E_INVALID_HANDLE:
ss<<"The supplied handle was not valid.";
break;
case SCARD_E_INVALID_HANDLE:
ss<<"The supplied handle was not valid.";
break;
#endif
#ifdef SCARD_E_INVALID_PARAMETER
case SCARD_E_INVALID_PARAMETER:
ss<<"One or more of the supplied parameters could not be properly"
<<" interpreted.";
break;
case SCARD_E_INVALID_PARAMETER:
ss<<"One or more of the supplied parameters could not be properly"
<<" interpreted.";
break;
#endif
#ifdef SCARD_E_INVALID_TARGET
case SCARD_E_INVALID_TARGET:
ss<<"Registry startup information is missing or not valid.";
break;
case SCARD_E_INVALID_TARGET:
ss<<"Registry startup information is missing or not valid.";
break;
#endif
#ifdef SCARD_E_INVALID_VALUE
case SCARD_E_INVALID_VALUE:
ss<<"One or more of the supplied parameters values could not"
<<" be properly interpreted.";
break;
case SCARD_E_INVALID_VALUE:
ss<<"One or more of the supplied parameters values could not"
<<" be properly interpreted.";
break;
#endif
#ifdef SCARD_E_NOT_READY
case SCARD_E_NOT_READY:
ss<<"The reader or smart card is not ready to accept commands.";
break;
case SCARD_E_NOT_READY:
ss<<"The reader or smart card is not ready to accept commands.";
break;
#endif
#ifdef SCARD_E_NOT_TRANSACTED
case SCARD_E_NOT_TRANSACTED:
ss<<"An attempt was made to end a nonexistent transaction.";
break;
case SCARD_E_NOT_TRANSACTED:
ss<<"An attempt was made to end a nonexistent transaction.";
break;
#endif
#ifdef SCARD_E_NO_MEMORY
case SCARD_E_NO_MEMORY:
ss<<"Not enough memory available to complete this command.";
break;
case SCARD_E_NO_MEMORY:
ss<<"Not enough memory available to complete this command.";
break;
#endif
#ifdef SCARD_E_NO_SERVICE
case SCARD_E_NO_SERVICE:
ss<<"The smart card resource manager is not running.";
break;
case SCARD_E_NO_SERVICE:
ss<<"The smart card resource manager is not running.";
break;
#endif
#ifdef SCARD_E_NO_SMARTCARD
case SCARD_E_NO_SMARTCARD:
ss<<"The operation requires a smart card, but no smart card"
<<" is currently in the device.";
break;
case SCARD_E_NO_SMARTCARD:
ss<<"The operation requires a smart card, but no smart card"
<<" is currently in the device.";
break;
#endif
#ifdef SCARD_E_PCI_TOO_SMALL
case SCARD_E_PCI_TOO_SMALL:
ss<<"The PCI receive buffer was too small.";
break;
case SCARD_E_PCI_TOO_SMALL:
ss<<"The PCI receive buffer was too small.";
break;
#endif
#ifdef SCARD_E_PROTO_MISMATCH
case SCARD_E_PROTO_MISMATCH:
ss<<"The requested protocols are incompatible with the protocol"
<<" currently in use with the smart card.";
break;
case SCARD_E_PROTO_MISMATCH:
ss<<"The requested protocols are incompatible with the protocol"
<<" currently in use with the smart card.";
break;
#endif
#ifdef SCARD_E_READER_UNAVAILABLE
case SCARD_E_READER_UNAVAILABLE:
ss<<"The specified reader is not currently available for use.";
break;
case SCARD_E_READER_UNAVAILABLE:
ss<<"The specified reader is not currently available for use.";
break;
#endif
#ifdef SCARD_E_READER_UNSUPPORTED
case SCARD_E_READER_UNSUPPORTED:
ss<<"The reader driver does not meet minimal requirements for"
<<" support.";
break;
case SCARD_E_READER_UNSUPPORTED:
ss<<"The reader driver does not meet minimal requirements for"
<<" support.";
break;
#endif
#ifdef SCARD_E_SERVICE_STOPPED
case SCARD_E_SERVICE_STOPPED:
ss<<"The smart card resource manager has shut down.";
break;
case SCARD_E_SERVICE_STOPPED:
ss<<"The smart card resource manager has shut down.";
break;
#endif
#ifdef SCARD_E_SHARING_VIOLATION
case SCARD_E_SHARING_VIOLATION:
ss<<"The smart card cannot be accessed because of other"
<<" outstanding connections.";
break;
case SCARD_E_SHARING_VIOLATION:
ss<<"The smart card cannot be accessed because of other"
<<" outstanding connections.";
break;
#endif
#ifdef SCARD_E_SYSTEM_CANCELLED
case SCARD_E_SYSTEM_CANCELLED:
ss<<"The action was cancelled by the system, presumably to log"
<<" off or shut down.";
break;
case SCARD_E_SYSTEM_CANCELLED:
ss<<"The action was cancelled by the system, presumably to log"
<<" off or shut down.";
break;
#endif
#ifdef SCARD_E_TIMEOUT
case SCARD_E_TIMEOUT:
ss<<"The user-specified time-out value has expired.";
break;
case SCARD_E_TIMEOUT:
ss<<"The user-specified time-out value has expired.";
break;
#endif
#ifdef SCARD_E_UNKNOWN_CARD
case SCARD_E_UNKNOWN_CARD:
ss<<"The specified smart card name is not recognized.";
break;
case SCARD_E_UNKNOWN_CARD:
ss<<"The specified smart card name is not recognized.";
break;
#endif
#ifdef SCARD_E_UNKNOWN_READER
case SCARD_E_UNKNOWN_READER:
ss<<"The specified reader name is not recognized.";
break;
case SCARD_E_UNKNOWN_READER:
ss<<"The specified reader name is not recognized.";
break;
#endif
#ifdef SCARD_F_COMM_ERROR
case SCARD_F_COMM_ERROR:
ss<<"An internal communications error has been detected.";
break;
case SCARD_F_COMM_ERROR:
ss<<"An internal communications error has been detected.";
break;
#endif
#ifdef SCARD_F_INTERNAL_ERROR
case SCARD_F_INTERNAL_ERROR:
ss<<"An internal consistency check failed.";
break;
case SCARD_F_INTERNAL_ERROR:
ss<<"An internal consistency check failed.";
break;
#endif
#ifdef SCARD_F_UNKNOWN_ERROR
case SCARD_F_UNKNOWN_ERROR:
ss<<"An internal error has been detected, but the source is"
<<" unknown.";
break;
case SCARD_F_UNKNOWN_ERROR:
ss<<"An internal error has been detected, but the source is"
<<" unknown.";
break;
#endif
#ifdef SCARD_F_WAITED_TOO_LONG
case SCARD_F_WAITED_TOO_LONG:
ss<<"An internal consistency timer has expired.";
break;
case SCARD_F_WAITED_TOO_LONG:
ss<<"An internal consistency timer has expired.";
break;
#endif
#ifdef SCARD_S_SUCCESS
case SCARD_S_SUCCESS:
ss<<"No error was encountered.";
break;
case SCARD_S_SUCCESS:
ss<<"No error was encountered.";
break;
#endif
#ifdef SCARD_W_REMOVED_CARD
case SCARD_W_REMOVED_CARD:
ss<<"The smart card has been removed, so that further"
<<" communication is not possible.";
break;
case SCARD_W_REMOVED_CARD:
ss<<"The smart card has been removed, so that further"
<<" communication is not possible.";
break;
#endif
#ifdef SCARD_W_RESET_CARD
case SCARD_W_RESET_CARD:
ss<<"The smart card was reset.";
break;
case SCARD_W_RESET_CARD:
ss<<"The smart card was reset.";
break;
#endif
#ifdef SCARD_W_UNPOWERED_CARD
case SCARD_W_UNPOWERED_CARD:
ss<<"Power has been removed from the smart card, so that"
<<" further communication is not possible.";
break;
case SCARD_W_UNPOWERED_CARD:
ss<<"Power has been removed from the smart card, so that"
<<" further communication is not possible.";
break;
#endif
#ifdef SCARD_W_UNRESPONSIVE_CARD
case SCARD_W_UNRESPONSIVE_CARD:
ss<<"The smart card is not responding to a reset.";
break;
case SCARD_W_UNRESPONSIVE_CARD:
ss<<"The smart card is not responding to a reset.";
break;
#endif
#ifdef SCARD_W_UNSUPPORTED_CARD
case SCARD_W_UNSUPPORTED_CARD:
ss<<"The reader cannot communicate with the smart card,"
<<" due to ATR configuration conflicts.";
break;
case SCARD_W_UNSUPPORTED_CARD:
ss<<"The reader cannot communicate with the smart card,"
<<" due to ATR configuration conflicts.";
break;
#endif
#ifdef SCARD_E_NO_READERS_AVAILABLE
case SCARD_E_NO_READERS_AVAILABLE:
ss<<"No smart card reader is available.";
break;
case SCARD_E_NO_READERS_AVAILABLE:
ss<<"No smart card reader is available.";
break;
#endif
#ifdef ERROR_BROKEN_PIPE
case ERROR_BROKEN_PIPE:
ss<<"The client attempted a smart card operation in a"
<<" remote session, such as a client session running"
<<" on a terminal server, and the operating system in"
<<" use does not support smart card redirection.";
break;
case ERROR_BROKEN_PIPE:
ss<<"The client attempted a smart card operation in a"
<<" remote session, such as a client session running"
<<" on a terminal server, and the operating system in"
<<" use does not support smart card redirection.";
break;
#endif
#ifdef SCARD_E_BAD_SEEK
case SCARD_E_BAD_SEEK:
ss<<"There was an error trying to set the smart card file"
<<" object pointer.";
break;
case SCARD_E_BAD_SEEK:
ss<<"There was an error trying to set the smart card file"
<<" object pointer.";
break;
#endif
#ifdef SCARD_E_CERTIFICATE_UNAVAILABLE
case SCARD_E_CERTIFICATE_UNAVAILABLE:
ss<<"The requested certificate could not be obtained.";
break;
case SCARD_E_CERTIFICATE_UNAVAILABLE:
ss<<"The requested certificate could not be obtained.";
break;
#endif
#ifdef SCARD_E_COMM_DATA_LOST
case SCARD_E_COMM_DATA_LOST:
ss<<"A communications error with the smart card has been detected.";
break;
case SCARD_E_COMM_DATA_LOST:
ss<<"A communications error with the smart card has been detected.";
break;
#endif
#ifdef SCARD_E_DIR_NOT_FOUND
case SCARD_E_DIR_NOT_FOUND:
ss<<"The specified directory does not exist in the smart card.";
break;
case SCARD_E_DIR_NOT_FOUND:
ss<<"The specified directory does not exist in the smart card.";
break;
#endif
#ifdef SCARD_E_FILE_NOT_FOUND
case SCARD_E_FILE_NOT_FOUND:
ss<<"The specified file does not exist in the smart card.";
break;
case SCARD_E_FILE_NOT_FOUND:
ss<<"The specified file does not exist in the smart card.";
break;
#endif
#ifdef SCARD_E_ICC_CREATEORDER
case SCARD_E_ICC_CREATEORDER:
ss<<"The requested order of object creation is not supported.";
break;
case SCARD_E_ICC_CREATEORDER:
ss<<"The requested order of object creation is not supported.";
break;
#endif
#ifdef SCARD_E_ICC_INSTALLATION
case SCARD_E_ICC_INSTALLATION:
ss<<"No primary provider can be found for the smart card.";
break;
case SCARD_E_ICC_INSTALLATION:
ss<<"No primary provider can be found for the smart card.";
break;
#endif
#ifdef SCARD_E_INVALID_CHV
case SCARD_E_INVALID_CHV:
ss<<"The supplied PIN is incorrect.";
break;
case SCARD_E_INVALID_CHV:
ss<<"The supplied PIN is incorrect.";
break;
#endif
#ifdef SCARD_E_NO_ACCESS
case SCARD_E_NO_ACCESS:
ss<<"Access is denied to this file.";
break;
case SCARD_E_NO_ACCESS:
ss<<"Access is denied to this file.";
break;
#endif
#ifdef SCARD_E_NO_DIR
case SCARD_E_NO_DIR:
ss<<"The supplied path does not represent a smart card directory.";
break;
case SCARD_E_NO_DIR:
ss<<"The supplied path does not represent a smart card directory.";
break;
#endif
#ifdef SCARD_E_NO_FILE
case SCARD_E_NO_FILE:
ss<<"The supplied path does not represent a smart card file.";
break;
case SCARD_E_NO_FILE:
ss<<"The supplied path does not represent a smart card file.";
break;
#endif
#ifdef SCARD_E_NO_KEY_CONTAINER
case SCARD_E_NO_KEY_CONTAINER:
ss<<"The requested key container does not exist on the smart card.";
break;
case SCARD_E_NO_KEY_CONTAINER:
ss<<"The requested key container does not exist on the smart card.";
break;
#endif
#ifdef SCARD_E_NO_SUCH_CERTIFICATE
case SCARD_E_NO_SUCH_CERTIFICATE:
ss<<"The requested certificate does not exist.";
break;
case SCARD_E_NO_SUCH_CERTIFICATE:
ss<<"The requested certificate does not exist.";
break;
#endif
#ifdef SCARD_E_SERVER_TOO_BUSY
case SCARD_E_SERVER_TOO_BUSY:
ss<<"The Smart card resource manager is too busy to complete this"
<<" operation.";
break;
case SCARD_E_SERVER_TOO_BUSY:
ss<<"The Smart card resource manager is too busy to complete this"
<<" operation.";
break;
#endif
#ifdef SCARD_E_UNSUPPORTED_FEATURE
case SCARD_E_UNSUPPORTED_FEATURE:
ss<<"This smart card does not support the requested feature.";
break;
case SCARD_E_UNSUPPORTED_FEATURE:
ss<<"This smart card does not support the requested feature.";
break;
#else
#ifdef SCARD_E_UNEXPECTED
case SCARD_E_UNEXPECTED:
ss<<"An unexpected card error has occurred.";
break;
case SCARD_E_UNEXPECTED:
ss<<"An unexpected card error has occurred.";
break;
#endif
#endif
#ifdef SCARD_E_UNKNOWN_RES_MNG
case SCARD_E_UNKNOWN_RES_MNG:
ss<<"An unrecognized error code was returned from a layered"
<<" component.";
break;
case SCARD_E_UNKNOWN_RES_MNG:
ss<<"An unrecognized error code was returned from a layered"
<<" component.";
break;
#endif
#ifdef SCARD_E_WRITE_TOO_MANY
case SCARD_E_WRITE_TOO_MANY:
ss<<"The smartcard does not have enough memory to store the"
<<" information.";
break;
case SCARD_E_WRITE_TOO_MANY:
ss<<"The smartcard does not have enough memory to store the"
<<" information.";
break;
#endif
#ifdef SCARD_P_SHUTDOWN
case SCARD_P_SHUTDOWN:
ss<<"The operation has been aborted to allow the server application"
<<" to exit.";
break;
case SCARD_P_SHUTDOWN:
ss<<"The operation has been aborted to allow the server application"
<<" to exit.";
break;
#endif
#ifdef SCARD_W_CANCELLED_BY_USER
case SCARD_W_CANCELLED_BY_USER:
ss<<"The action was cancelled by the user.";
break;
case SCARD_W_CANCELLED_BY_USER:
ss<<"The action was cancelled by the user.";
break;
#endif
#ifdef SCARD_W_CARD_NOT_AUTHENTICATED
case SCARD_W_CARD_NOT_AUTHENTICATED:
ss<<"No PIN was presented to the smart card.";
break;
case SCARD_W_CARD_NOT_AUTHENTICATED:
ss<<"No PIN was presented to the smart card.";
break;
#endif
#ifdef SCARD_W_CHV_BLOCKED
case SCARD_W_CHV_BLOCKED:
ss<<"The card cannot be accessed because the maximum number"
<<" of PIN entry attempts has been reached.";
break;
case SCARD_W_CHV_BLOCKED:
ss<<"The card cannot be accessed because the maximum number"
<<" of PIN entry attempts has been reached.";
break;
#endif
#ifdef SCARD_W_EOF
case SCARD_W_EOF:
ss<<"The end of the smart card file has been reached.";
break;
case SCARD_W_EOF:
ss<<"The end of the smart card file has been reached.";
break;
#endif
#ifdef SCARD_W_SECURITY_VIOLATION
case SCARD_W_SECURITY_VIOLATION:
ss<<"Access was denied because of a security violation.";
break;
case SCARD_W_SECURITY_VIOLATION:
ss<<"Access was denied because of a security violation.";
break;
#endif
#ifdef SCARD_W_WRONG_CHV
case SCARD_W_WRONG_CHV:
ss<<"The card cannot be accessed because the wrong PIN was"
<<" presented.";
break;
#endif
default:
ss<<"unknown PCSC state=0x"
<<std::hex<<std::setfill('0')<<std::setw(8)<<_state;
switch (_state>>30) {
case 0: ss<<" means SUCCESS"; break;
case 1: ss<<" means INFORMATIONAL"; break;
case 2: ss<<" means WARNING"; break;
case 3: ss<<" means ERROR"; break;
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);
case SCARD_W_WRONG_CHV:
ss<<"The card cannot be accessed because the wrong PIN was"
<<" presented.";
break;
#endif
default:
ss<<"unknown PCSC state=0x"
<<std::hex<<std::setfill('0')<<std::setw(8)<<_state;
switch (_state>>30) {
case 0: ss<<" means SUCCESS"; break;
case 1: ss<<" means INFORMATIONAL"; break;
case 2: ss<<" means WARNING"; break;
case 3: ss<<" means ERROR"; break;
default: ss<<" illegal value";
}
return ss.str();
}
//! set state
void state(long s) {
_state = s;
}
//! @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);
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 instance;
return ss.str();
}
static int& connectionlifetimecounter() {
static int instance(0);
return instance;
//! set state
void state(long s) {
_state = s;
}
//! @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) {
}
Scanner(const pcsc::Connection& pcsc,
const std::string& lib="libcvP11.so"):
_pcsc(pcsc),
_cryptoki(lib) {
}
Scanner(const cryptoki::Library& 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.
/** @return List of detected SuisseID smart cards. */
Cards scan() {
@ -418,20 +406,20 @@ namespace suisseid {
Cards res;
// By now, scan only for PostSuisseID; in future use factory pattern
pcsc::Connection::Strings readers
(_pcsc.getReadersWithAtr("4b53776973735369676e"));
(pcsc::Connection::getReadersWithAtr("4b53776973735369676e"));
for (pcsc::Connection::Strings::iterator reader(readers.begin());
reader!=readers.end(); ++reader) {
cryptoki::SlotList slots(_cryptoki.slotList(true, *reader));
if (slots.size()==1)
res.push_back(dynamic_cast<Card*>
(new Post(_pcsc.reader(*reader), _cryptoki)));
(new Post(pcsc::Connection::reader(*reader),
_cryptoki)));
}
return res;
}
private:
pcsc::Connection _pcsc;
cryptoki::Library _cryptoki;
};

Loading…
Cancel
Save