2013-10-21 07:10:46 +00:00
|
|
|
/*! @file
|
|
|
|
|
|
|
|
@id $Id$
|
|
|
|
*/
|
|
|
|
// 1 2 3 4 5 6 7 8
|
|
|
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
|
|
|
|
|
|
|
|
#ifndef __SUISSEID_HXX__
|
|
|
|
#define __SUISSEID_HXX__
|
|
|
|
|
|
|
|
#include <cardos.hxx>
|
|
|
|
#include <cryptoki.hxx>
|
|
|
|
#include <pcsc.hxx>
|
|
|
|
#include <mrw/vector.hxx>
|
|
|
|
#include <mrw/shared.hxx>
|
|
|
|
|
2014-01-31 13:32:31 +00:00
|
|
|
/*! @defgroup gsuisseid C++ library to access SuisseID smart cards
|
2013-10-21 07:10:46 +00:00
|
|
|
|
|
|
|
This library allows access to the Swiss digital identity cards
|
|
|
|
(SuisseID).
|
|
|
|
|
|
|
|
You need to include @ref suisseid.hxx, then start with class @ref
|
|
|
|
suisseid::Scanner to scan for a list of SuisseID cards on the system.
|
|
|
|
|
|
|
|
@see http://www.suisseid.ch
|
2014-01-31 13:32:31 +00:00
|
|
|
@see http://postsuisseid.ch
|
|
|
|
|
|
|
|
*/
|
2013-10-21 07:10:46 +00:00
|
|
|
//@{
|
2014-01-27 13:48:05 +00:00
|
|
|
/*! @defgroup suisseidlib SuisseID Library */
|
|
|
|
/*! @defgroup suisseidtypes SuisseID C++ Types and Auxiliary */
|
2014-01-28 07:58:21 +00:00
|
|
|
/*! @defgroup suisseidconsts SuisseID C++ Constants */
|
2014-01-27 13:48:05 +00:00
|
|
|
/*! @defgroup suisseidexceptions SuisseID Exceptions */
|
2014-01-31 13:32:31 +00:00
|
|
|
/** @example suisse-id-demo.cxx
|
|
|
|
|
|
|
|
Usage of @ref gsuisseid This is a comprehensive example how you
|
|
|
|
can access a SuisseID and access to certificates on that card.
|
|
|
|
|
|
|
|
First implement a status cycle, here for @c std::cin and @c
|
|
|
|
std::cout as user interface in the @c suisse-id-demo.hxx header
|
|
|
|
file:
|
|
|
|
|
|
|
|
@include suisse-id-demo.hxx
|
|
|
|
|
|
|
|
Then instanciate and use this class from your code: */
|
2014-01-27 13:48:05 +00:00
|
|
|
//@}
|
|
|
|
|
2014-01-31 13:32:31 +00:00
|
|
|
/// @ref gsuisseid @copydoc gsuisseid
|
2013-10-21 07:10:46 +00:00
|
|
|
namespace suisseid {
|
|
|
|
|
2014-01-27 13:48:05 +00:00
|
|
|
|
2013-10-23 13:33:32 +00:00
|
|
|
/** @page init Initialize Card and Check Status
|
|
|
|
|
|
|
|
An idea on how the smart card status could be evaluated is the
|
|
|
|
following state machine:
|
|
|
|
|
|
|
|
@dot
|
|
|
|
digraph {
|
|
|
|
transportState
|
|
|
|
[URL="\ref cardos::Commands::transportState"];
|
|
|
|
transportPinRetries
|
|
|
|
[URL="\ref cardos::Commands::transportPinRetries"];
|
|
|
|
pkcs15PinRetries
|
|
|
|
[URL="\ref cardos::Commands::pkcs15PinRetries"];
|
|
|
|
sigGPinRetries
|
|
|
|
[URL="\ref cardos::Commands::sigGPinRetries"];
|
|
|
|
pukRetries
|
|
|
|
[URL="\ref cardos::Commands::pukRetries"];
|
|
|
|
changePin
|
|
|
|
[URL="\ref cardos::Commands::changePin"];
|
|
|
|
broken [label="replace card"];
|
|
|
|
|
|
|
|
start -> transportState;
|
|
|
|
transportPinRetries -> broken [label="-1"];
|
|
|
|
certsValid -> broken [label="false"];
|
|
|
|
pukRetries -> broken [label="-1"];
|
|
|
|
sigGPinRetries -> broken [label="-1"];
|
|
|
|
transportState -> transportPinRetries [label="true"];
|
|
|
|
transportPinRetries -> changePin [label=">-1"];
|
|
|
|
changePin -> transportState;
|
|
|
|
transportState -> haveCerts [label="false"];
|
|
|
|
haveCerts -> installCerts [label="false"];
|
|
|
|
installCerts -> transportState;
|
|
|
|
haveCerts -> certsValid [label="true"];
|
|
|
|
certsValid -> pkcs15PinRetries [label="true"];
|
|
|
|
pkcs15PinRetries -> sigGPinRetries [label=">-1"];
|
|
|
|
pkcs15PinRetries -> pukRetries [label="-1"];
|
|
|
|
pukRetries -> changePin [label=">-1"];
|
|
|
|
sigGPinRetries -> valid [label=">-1"];
|
|
|
|
{valid broken} -> end;
|
|
|
|
|
|
|
|
{rank=same; valid broken}
|
|
|
|
{rank=same; transportPinRetries haveCerts}
|
|
|
|
{rank=same; certsValid installCerts changePin}
|
|
|
|
}
|
|
|
|
@enddot
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2014-01-27 13:48:05 +00:00
|
|
|
//============================================================================
|
|
|
|
/*! @addtogroup suisseidexceptions */
|
|
|
|
//@{
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class exception: public std::exception {
|
|
|
|
public:
|
|
|
|
exception(const std::string& reason) throw():
|
|
|
|
_what("suisseid: "+reason) {
|
|
|
|
CRYPTOLOG("ERROR: "<<what());
|
|
|
|
}
|
|
|
|
~exception() throw() {}
|
|
|
|
const char* what() const throw() {
|
|
|
|
return _what.c_str();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string _what;
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class no_certfound: public exception {
|
|
|
|
public:
|
|
|
|
no_certfound(const std::string& label) throw():
|
|
|
|
exception("no certificate with label \""+label+"\" found") {}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class no_auth: public exception {
|
|
|
|
public:
|
|
|
|
no_auth() throw():
|
|
|
|
exception("no authentication certificate found") {}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class no_digsig: public exception {
|
|
|
|
public:
|
|
|
|
no_digsig() throw():
|
|
|
|
exception("no digital signature certificate found") {}
|
|
|
|
};
|
2014-02-27 12:57:44 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class slot_not_found: public exception {
|
|
|
|
public:
|
|
|
|
slot_not_found(const std::string& name) throw():
|
|
|
|
exception("matching cryptoki slot for "+name+" not found") {}
|
|
|
|
};
|
2014-01-27 13:48:05 +00:00
|
|
|
//@}
|
|
|
|
|
|
|
|
/*! @addtogroup suisseidtypes */
|
|
|
|
//@{
|
|
|
|
/// DER encoded binary certificate
|
|
|
|
typedef std::string Certificate;
|
2014-01-22 15:14:36 +00:00
|
|
|
/// List of DER encoded binary certificates
|
2014-01-27 13:48:05 +00:00
|
|
|
typedef std::vector<Certificate> Certificates;
|
|
|
|
//@}
|
2014-01-28 07:58:21 +00:00
|
|
|
|
|
|
|
/*! @addtogroup suisseidconsts */
|
|
|
|
//@{
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Label of the key for digital signature certificate.
|
|
|
|
const std::string NON_REP = "SwissSign_nonRep ";
|
|
|
|
/// Label of the key for authentication certificate
|
|
|
|
const std::string DIG_SIG = "SwissSign_digSig ";
|
|
|
|
/// Label of the key required for getting the certificates
|
|
|
|
const std::string DATA_ENC = "SwissSign_dataEnc ";
|
2014-01-28 07:58:21 +00:00
|
|
|
//@}
|
2014-01-27 13:48:05 +00:00
|
|
|
|
|
|
|
/*! @addtogroup suisseidlib */
|
|
|
|
//@{
|
2014-01-22 15:14:36 +00:00
|
|
|
|
2013-10-21 07:10:46 +00:00
|
|
|
//! Represents a SuisseID Card
|
|
|
|
/*! This is the parent class for special classes for the respecive
|
|
|
|
SuisseID providers. */
|
|
|
|
class Card: public cardos::Commands {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Status of the card's certificates
|
|
|
|
/** @note by now, only @c MISSING and @c VALID is supported */
|
2013-11-06 12:24:52 +00:00
|
|
|
enum CertStatus {
|
2014-02-27 12:57:44 +00:00
|
|
|
MISSING, ///< certificate is missing, needs initiatlization
|
|
|
|
EXPIRES_SOON, ///< certificate will soon expire, needs renewal
|
|
|
|
EXPIRED, ///< certificate is expired, needs new purchase
|
|
|
|
REVOKED, ///< certificate has been revoked and is invalid
|
|
|
|
VALID ///< certificate is valid
|
2013-10-21 07:10:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2014-02-27 12:57:44 +00:00
|
|
|
|
|
|
|
/// Instanciation is done within suisseid::Scanner
|
|
|
|
/** Instance requires a connenction to the reader an a cryptoky
|
|
|
|
library. This is passes automatically when this class is
|
|
|
|
instanciated through suisseid::Scanner. */
|
2013-10-21 07:10:46 +00:00
|
|
|
Card(mrw::Shared<pcsc::Connection::Reader> reader,
|
2013-11-06 12:24:52 +00:00
|
|
|
const cryptoki::Library& cryptoki):
|
2013-10-21 07:10:46 +00:00
|
|
|
cardos::Commands(reader),
|
2013-11-06 12:24:52 +00:00
|
|
|
_cryptoki(cryptoki) {
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
|
|
|
virtual ~Card() {}
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Find the matching cryptoki::Slot for further access
|
|
|
|
/** @throws slot_not_found if not exactly one matching slot exists */
|
2013-11-06 12:24:52 +00:00
|
|
|
cryptoki::Slot slot() {
|
|
|
|
cryptoki::SlotList slots(_cryptoki.slotList(true, name()));
|
|
|
|
if (slots.size()==1) return slots[0];
|
2014-02-27 12:57:44 +00:00
|
|
|
throw slot_not_found(name());
|
2013-11-06 12:24:52 +00:00
|
|
|
}
|
|
|
|
|
2014-03-05 14:56:19 +00:00
|
|
|
/// Get the reader, needed for example to lock a transaction
|
|
|
|
/** @begincode
|
|
|
|
pcsc::Connection::Reader::Transaction lock(card.reader());
|
|
|
|
[... do some low level stuff ...]
|
|
|
|
@endcode */
|
|
|
|
mrw::Shared<pcsc::Connection::Reader> reader() {
|
|
|
|
return _reader;
|
|
|
|
}
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Minimum allowed PIN length for this card.
|
2013-10-21 07:10:46 +00:00
|
|
|
virtual unsigned int minimalPinLength() = 0;
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Maximum allowed PIN length for this card.
|
2013-10-21 07:10:46 +00:00
|
|
|
virtual unsigned int maximalPinLength() = 0;
|
|
|
|
|
|
|
|
//! Name of the token/slot
|
|
|
|
const std::string& name() {
|
|
|
|
return _reader->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Version of the card
|
|
|
|
virtual std::string version() {
|
|
|
|
return "<unknown>";
|
|
|
|
}
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Status of the certificates on the card
|
2013-11-06 12:24:52 +00:00
|
|
|
virtual CertStatus certStatus() {
|
|
|
|
return MISSING;
|
|
|
|
}
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Starts and returns a cryptoki::Session.
|
2014-01-22 15:14:36 +00:00
|
|
|
cryptoki::Session session() {
|
|
|
|
return cryptoki::Session(slot());
|
|
|
|
}
|
|
|
|
|
2014-02-27 12:57:44 +00:00
|
|
|
/// Starts a cryptoki::Session and returns cryptoki::Session::Info.
|
2014-01-22 15:14:36 +00:00
|
|
|
cryptoki::Session::Info sessionInfo() {
|
|
|
|
return session().getsessioninfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @returns Certificates in DER format.
|
|
|
|
Certificates certificates() {
|
|
|
|
Certificates res;
|
|
|
|
cryptoki::ObjectList certs
|
|
|
|
(session().find(cryptoki::Attribute(CKA_CLASS)
|
|
|
|
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)));
|
|
|
|
for (cryptoki::ObjectList::iterator cert(certs.begin());
|
|
|
|
cert!=certs.end(); ++cert)
|
|
|
|
res.push_back(cert->attribute(CKA_VALUE).value);
|
|
|
|
return res;
|
|
|
|
}
|
2014-01-27 13:48:05 +00:00
|
|
|
|
|
|
|
virtual Certificate certificate(const std::string& keylabel) {
|
|
|
|
cryptoki::ObjectList keys // find keys with digsig-label
|
|
|
|
(session().find(cryptoki::AttributeList()
|
|
|
|
<<cryptoki::Attribute(CKA_CLASS)
|
|
|
|
.from<CK_OBJECT_CLASS>(CKO_PUBLIC_KEY)
|
|
|
|
<<cryptoki::Attribute(CKA_LABEL, keylabel)));
|
|
|
|
for (cryptoki::ObjectList::iterator key(keys.begin());
|
|
|
|
key!=keys.end(); ++key) {
|
|
|
|
cryptoki::Attribute id(key->attribute(CKA_ID));
|
|
|
|
cryptoki::ObjectList certs
|
|
|
|
(session().find(cryptoki::AttributeList()
|
|
|
|
<<cryptoki::Attribute(CKA_CLASS)
|
|
|
|
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)
|
|
|
|
<<id));
|
|
|
|
for (cryptoki::ObjectList::iterator cert(certs.begin());
|
|
|
|
cert!=certs.end(); ++cert) { // return first matching cert
|
|
|
|
return cert->attribute(CKA_VALUE).value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw no_certfound(keylabel);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Certificate authenticationCertificate() = 0;
|
|
|
|
virtual Certificate digitalSignatureCertificate() = 0;
|
2014-01-22 15:14:36 +00:00
|
|
|
|
2013-11-06 12:24:52 +00:00
|
|
|
protected:
|
2013-10-21 07:10:46 +00:00
|
|
|
|
2013-11-06 12:24:52 +00:00
|
|
|
cryptoki::Library _cryptoki;
|
2013-10-21 07:10:46 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
//! Instance of a Post SuisseID smartcard.
|
|
|
|
/*! A SuisseID card issued by Swiss Post.
|
|
|
|
@see http://postsuisseid.ch */
|
2013-11-06 12:24:52 +00:00
|
|
|
class Post: public Card {
|
2013-10-21 07:10:46 +00:00
|
|
|
|
|
|
|
public:
|
2014-02-27 12:57:44 +00:00
|
|
|
|
|
|
|
/// @copydoc Card::Card
|
2013-11-06 12:24:52 +00:00
|
|
|
Post(mrw::Shared<pcsc::Connection::Reader> reader,
|
|
|
|
const cryptoki::Library& cryptoki):
|
|
|
|
Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) {
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned int minimalPinLength() {
|
|
|
|
if (_minPinLen==0) evaluatePinLengths();
|
|
|
|
return _minPinLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned int maximalPinLength() {
|
|
|
|
if (_maxPinLen==-1) evaluatePinLengths();
|
|
|
|
return _maxPinLen;
|
|
|
|
}
|
|
|
|
|
2013-11-06 12:24:52 +00:00
|
|
|
virtual std::string version() {
|
2013-10-21 07:10:46 +00:00
|
|
|
if (_version.size()) return _version; // cache the version
|
2013-11-06 12:24:52 +00:00
|
|
|
return versionFromMFFile("5649");
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
2013-11-06 12:24:52 +00:00
|
|
|
|
|
|
|
virtual CertStatus certStatus() {
|
|
|
|
cryptoki::ObjectList certs
|
2014-01-27 13:48:05 +00:00
|
|
|
(session().find(cryptoki::Attribute(CKA_CLASS)
|
2013-11-06 12:24:52 +00:00
|
|
|
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)));
|
|
|
|
if (certs.size()==0) return MISSING;
|
|
|
|
return VALID;
|
|
|
|
}
|
|
|
|
|
2014-01-27 13:48:05 +00:00
|
|
|
virtual Certificate authenticationCertificate() try {
|
|
|
|
return certificate(DIG_SIG);
|
|
|
|
} catch (const no_certfound&) {
|
|
|
|
throw no_auth();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Certificate digitalSignatureCertificate() try {
|
|
|
|
return certificate(NON_REP);
|
|
|
|
} catch (const no_certfound&) {
|
|
|
|
throw no_digsig();
|
|
|
|
}
|
|
|
|
|
2013-10-21 07:10:46 +00:00
|
|
|
private:
|
|
|
|
|
|
|
|
void evaluatePinLengths() {
|
|
|
|
pcsc::Connection::Reader::Transaction lock(_reader);
|
|
|
|
selectPkcs15File("4408");
|
|
|
|
cardos::BerValues res(readBerFile());
|
|
|
|
for (cardos::BerValues::iterator it(res.begin()); it!=res.end(); ++it)
|
2014-03-07 15:53:22 +00:00
|
|
|
if ((*it)[0][0].string()=="PIN" ||
|
|
|
|
(*it)[0][0].string()=="Digital Signature PIN") {
|
|
|
|
if ((*it)[2][0][2].ulong()>_minPinLen)
|
|
|
|
_minPinLen = (*it)[2][0][2].ulong();
|
|
|
|
if ((*it)[2][0][4].ulong()<_maxPinLen)
|
|
|
|
_maxPinLen = (*it)[2][0][4].ulong();
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-06 12:24:52 +00:00
|
|
|
std::string versionFromMFFile(const std::string& file) {
|
|
|
|
pcsc::Connection::Reader::Transaction lock(_reader);
|
|
|
|
try {
|
|
|
|
selectMfFile(file);
|
2014-03-07 15:53:22 +00:00
|
|
|
return _version = cardos::BerValues(readBinary())[0].string();
|
2013-11-06 12:24:52 +00:00
|
|
|
} catch (...) {
|
|
|
|
return _version = "<unknown>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-21 07:10:46 +00:00
|
|
|
private:
|
|
|
|
|
|
|
|
std::string _version; // version is cached
|
|
|
|
unsigned int _minPinLen; // minimal PIN length is cached
|
|
|
|
unsigned int _maxPinLen; // maximal PIN length is cached
|
|
|
|
};
|
|
|
|
|
|
|
|
//! List of cards, returned by @ref suisseid::Scanner::scan.
|
|
|
|
typedef std::vector<mrw::Shared<Card> > Cards;
|
|
|
|
|
|
|
|
//! Auxiliary SuisseID card manager.
|
|
|
|
/** Use this manager to scan your system for SuisseID cards.
|
|
|
|
|
|
|
|
Usage Example:
|
|
|
|
|
|
|
|
@code
|
|
|
|
#include <suisseid.hxx>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
[...]
|
|
|
|
|
|
|
|
try {
|
|
|
|
suisseid::Cards cards(suisseid::Scanner().scan());
|
|
|
|
for (auto card(cards.begin()); card!=cards.end(); ++card)
|
|
|
|
std::cout<<"Found SuisseID: "<<(*card)->name()<<std::endl;
|
|
|
|
return 0;
|
|
|
|
} catch (std::exception& x) {
|
|
|
|
std::cerr<<"**** ERROR in "<<*argv<<": "<<x.what()<<std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
@endcode */
|
|
|
|
class Scanner {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
Scanner(const std::string& lib="libcvP11.so"):
|
|
|
|
_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() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-10-21 07:10:46 +00:00
|
|
|
Cards res;
|
|
|
|
// By now, scan only for PostSuisseID; in future use factory pattern
|
|
|
|
pcsc::Connection::Strings readers
|
|
|
|
(_pcsc.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*>
|
2013-11-06 12:24:52 +00:00
|
|
|
(new Post(_pcsc.reader(*reader), _cryptoki)));
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
pcsc::Connection _pcsc;
|
|
|
|
cryptoki::Library _cryptoki;
|
|
|
|
|
|
|
|
};
|
2013-11-06 12:24:52 +00:00
|
|
|
|
|
|
|
class StatusCycle {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
StatusCycle(mrw::Shared<Card> card, unsigned int maxRetries = 20):
|
|
|
|
_card(card), _maxRetries(maxRetries), _counter(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
~StatusCycle() {}
|
|
|
|
|
|
|
|
bool run() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
_counter = 0;
|
|
|
|
return start();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
mrw::Shared<Card> card() {
|
|
|
|
return _card;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @name Slots
|
|
|
|
//@{
|
|
|
|
|
|
|
|
struct PinPukChange {
|
|
|
|
std::string oldpin;
|
|
|
|
std::string newpin;
|
|
|
|
bool valid() {
|
|
|
|
return oldpin.size() && newpin.size();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual PinPukChange pinChange() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
return PinPukChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual PinPukChange pinChangeTransportPin() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
return pinChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual PinPukChange pinChangePuk() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
return pinChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void transportPinLocked() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
virtual void pkcs15PinLocked() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
virtual void sigGPinLocked() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
virtual void pukLocked() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void certsExpireSoon() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
virtual void certsExpired() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
virtual void certsRevoked() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// install certificates on the card
|
|
|
|
/** @param bool whether to force reinstallation of existin certificates
|
|
|
|
@return @c true on success */
|
|
|
|
virtual bool installCerts(bool = true) {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//@}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
bool start() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
if (++_counter>_maxRetries) return false;
|
|
|
|
if (_card->transportState())
|
|
|
|
return unlockTransportState();
|
|
|
|
else
|
|
|
|
return checkPkcs15PinStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unlockTransportState() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
if (_card->transportPinRetries()<0)
|
|
|
|
return transportPinLocked(), false;
|
|
|
|
else
|
|
|
|
return changeTransportPin();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool changeTransportPin() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
PinPukChange pins(pinChangeTransportPin());
|
|
|
|
if (!pins.valid()) return false;
|
|
|
|
_card->changePins(pins.newpin, pins.oldpin);
|
|
|
|
_card->unsetTransportState();
|
|
|
|
return start();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkPkcs15PinStatus() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
if (_card->pkcs15PinRetries()<0)
|
|
|
|
return pkcs15PinLocked(), unlockPkcs15();
|
|
|
|
if (_card->pukRetries()<0)
|
|
|
|
return pukLocked(), false;
|
|
|
|
return checkCertificates();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkCertificates() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
switch (_card->certStatus()) {
|
|
|
|
case Card::MISSING: return installCerts() && start();
|
|
|
|
case Card::EXPIRES_SOON: certsExpireSoon(); break;
|
|
|
|
case Card::EXPIRED: return certsExpired(), false;
|
|
|
|
case Card::REVOKED: return certsRevoked(), false;
|
|
|
|
case Card::VALID: break;
|
|
|
|
}
|
|
|
|
return checkSigGPinStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool checkSigGPinStatus() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
if (_card->sigGPinRetries()<0)
|
|
|
|
return sigGPinLocked(), false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool unlockPkcs15() {
|
|
|
|
CRYPTOLOG("log");
|
|
|
|
if (_card->pukRetries()<0)
|
|
|
|
return pukLocked(), false;
|
|
|
|
PinPukChange pins(pinChangePuk());
|
|
|
|
if (!pins.valid()) return false;
|
|
|
|
_card->changePins(pins.newpin, pins.oldpin);
|
|
|
|
return start();
|
|
|
|
}
|
|
|
|
|
|
|
|
mrw::Shared<Card> _card;
|
|
|
|
unsigned int _maxRetries;
|
|
|
|
unsigned int _counter;
|
|
|
|
|
|
|
|
};
|
2014-01-27 13:48:05 +00:00
|
|
|
|
|
|
|
//@}
|
2013-10-21 07:10:46 +00:00
|
|
|
}
|
2014-01-27 13:48:05 +00:00
|
|
|
|
2013-10-21 07:10:46 +00:00
|
|
|
|
|
|
|
#endif
|