Added all SuisseID Functionality except certificate import from server, which shall remain closed; refs #28

This commit is contained in:
Marc Wäckerlin
2013-11-06 12:24:52 +00:00
parent 3b702012c1
commit 885cb0f0fe
17 changed files with 1157 additions and 926 deletions

View File

@@ -75,7 +75,7 @@ AC_SUBST_FILE(CHANGE_LOG)
AM_CPPFLAGS="-DPACKAGEVERSION='\"${VERSION}\"' -DPACKAGENAME='\"${PACKAGENAME}\"'" AM_CPPFLAGS="-DPACKAGEVERSION='\"${VERSION}\"' -DPACKAGENAME='\"${PACKAGENAME}\"'"
# Get rid of that stupid -O2 -g opions! # Get rid of that stupid -O2 -g options!
CXXFLAGS="${CXXFLAGS:-}" CXXFLAGS="${CXXFLAGS:-}"
# languages # languages
@@ -93,6 +93,9 @@ AC_CHECK_PROG(have_doxygen, doxygen, yes, no)
AC_CHECK_PROG(have_dot, dot, yes, no) AC_CHECK_PROG(have_dot, dot, yes, no)
PKG_PROG_PKG_CONFIG PKG_PROG_PKG_CONFIG
# libraries
#PKG_CHECK_MODULES([QT], [QtNetwork])
AC_ARG_ENABLE(pedantic, AC_ARG_ENABLE(pedantic,
[AS_HELP_STRING([--enable-pedantic], [AS_HELP_STRING([--enable-pedantic],
[enable all warnings and checks, abort on warnings])], [enable all warnings and checks, abort on warnings])],

14
debian/control vendored
View File

@@ -14,6 +14,20 @@ Description: C++ Wrapper around PCSClite, Cryptoki, OpenSSL
C++ wrappers around the ugly C-Interfaces of pcsc-lite, cryptoki and C++ wrappers around the ugly C-Interfaces of pcsc-lite, cryptoki and
open-ssl. open-ssl.
. .
Development Package
.
For more details, see: https://dev.marc.waeckerlin.org/projects/libpcscxx
Package: libpcscxx-dbg
Section: debug
Architecture: any
Depends: libpcscxx (= ${binary:Version})
Description: C++ Wrapper around PCSClite, Cryptoki, OpenSSL
C++ wrappers around the ugly C-Interfaces of pcsc-lite, cryptoki and
open-ssl.
.
Debugging Symbols
.
For more details, see: https://dev.marc.waeckerlin.org/projects/libpcscxx For more details, see: https://dev.marc.waeckerlin.org/projects/libpcscxx
Package: libpcscxx Package: libpcscxx

4
debian/rules vendored
View File

@@ -40,7 +40,7 @@ endif
ifneq "$(wildcard /usr/share/misc/config.guess)" "" ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess cp -f /usr/share/misc/config.guess config.guess
endif endif
CPPFLAGS="-DALLOW_SSL_0_8 -std=c++0x" ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" CPPFLAGS="-DALLOW_SSL_0_8 -std=c++0x" CXXFLAGS="-ggdb" LDFLAG="-ggdb" ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)"
# does not work: LDFLAGS="-Wl,-z,defs" # does not work: LDFLAGS="-Wl,-z,defs"
@@ -89,7 +89,7 @@ binary-arch: install
# dh_installinfo # dh_installinfo
# dh_installman # dh_installman
dh_link dh_link
dh_strip dh_strip --dbg-package=libpcscxx-dbg
dh_compress dh_compress
dh_fixperms dh_fixperms
# dh_perl # dh_perl

View File

@@ -86,7 +86,7 @@ int main(int argc, char** argv) try {
std::cout<<"Pin: "; std::cout<<"Pin: ";
std::string pin; std::string pin;
std::cin>>pin; std::cin>>pin;
cryptoki::Session::Login l(session, pin); session.login(pin);
keys = session.find(cryptoki::Attribute(CKA_CLASS) keys = session.find(cryptoki::Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_PRIVATE_KEY), .from<CK_OBJECT_CLASS>(CKO_PRIVATE_KEY),
id); id);

View File

@@ -3,6 +3,7 @@
## 1 2 3 4 5 6 7 8 ## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890
noinst_HEADERS = suisse-id-demo.hxx
noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \ noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \
openssl-tcp-demo openssl-ssl-demo \ openssl-tcp-demo openssl-ssl-demo \
openssl-engine-demo suisse-id-demo cardos-demo openssl-engine-demo suisse-id-demo cardos-demo
@@ -32,7 +33,14 @@ cryptoki_sign_demo_SOURCES = cryptoki-sign-demo.cxx
openssl_tcp_demo_SOURCES = openssl-tcp-demo.cxx openssl_tcp_demo_SOURCES = openssl-tcp-demo.cxx
openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx openssl_ssl_demo_SOURCES = openssl-ssl-demo.cxx
openssl_engine_demo_SOURCES = openssl-engine-demo.cxx openssl_engine_demo_SOURCES = openssl-engine-demo.cxx
suisse_id_demo_SOURCES = suisse-id-demo.cxx
cardos_demo_SOURCES = cardos-demo.cxx cardos_demo_SOURCES = cardos-demo.cxx
suisse_id_demo_SOURCES = suisse-id-demo.cxx
# moc_suisse-id-demo.cxx
#suisse_id_demo_CXXFLAGS = ${QT_CFLAGS}
#suisse_id_demo_LDADD = ${QT_LIBS}
moc_%.cxx: %.hxx
moc -o $@ $<
CLEANFILES = moc_suisse-id-demo.cxx
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

View File

@@ -14,11 +14,11 @@ class TestEngine: virtual public openssl::Engine {
public: public:
virtual const char* id() { virtual const char* id() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return "TestEngine_ID"; return "TestEngine_ID";
} }
virtual const char* name() { virtual const char* name() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return "TestEngine_NAME"; return "TestEngine_NAME";
} }
}; };

View File

@@ -5,14 +5,10 @@
// 1 2 3 4 5 6 7 8 // 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 // 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <suisseid.hxx> #include <suisse-id-demo.hxx>
#include <mrw/args.hxx> #include <mrw/args.hxx>
#include <stdexcept>
#include <iostream>
int main(int argc, char** argv) try { int main(int argc, char** argv) try {
std::string lib("libcvP11.so"); std::string lib("libcvP11.so");
mrw::args::parse(argc, argv, mrw::args::parse(argc, argv,
"Sign a text (optionally several times for performance" "Sign a text (optionally several times for performance"
@@ -23,13 +19,77 @@ int main(int argc, char** argv) try {
<<mrw::args::param(lib, "lib"))); <<mrw::args::param(lib, "lib")));
suisseid::Cards cards(suisseid::Scanner(lib).scan()); suisseid::Cards cards(suisseid::Scanner(lib).scan());
for (suisseid::Cards::iterator card(cards.begin()); card!=cards.end(); ++card) for (suisseid::Cards::iterator card(cards.begin());
std::cout<<"Found SuisseID:"<<std::endl card!=cards.end(); ++card) {
std::string choice;
while (choice!="n") try {
std::cout<<"=================================================="<<std::endl
<<"Found SuisseID:"<<std::endl
<<" Reader Name: "<<(*card)->name()<<std::endl <<" Reader Name: "<<(*card)->name()<<std::endl
<<" Version: "<<(*card)->version()<<std::endl <<" Version: "<<(*card)->version()<<std::endl
<<" PIN-Length: "<<(*card)->minimalPinLength() <<" PIN-Length: "<<(*card)->minimalPinLength()
<<" - "<<(*card)->maximalPinLength()<<std::endl; <<" - "<<(*card)->maximalPinLength()<<std::endl
<<" PIN retries:"<<std::endl
<<" PKCS#15: "<<(*card)->pkcs15PinRetries()<<std::endl
<<" SigG: "<<(*card)->sigGPinRetries()<<std::endl
<<" Transport: "<<(*card)->transportPinRetries()<<std::endl
<<" PUK: "<<(*card)->pukRetries()<<std::endl;
cryptoki::Session session((*card)->slot());
cryptoki::Session::Info info(session.getsessioninfo());
std::cout<<" Session:"<<std::endl
<<" Slot: "<<info.slotID<<std::endl
<<" State: "<<session.state(info)<<std::endl
<<" Flags: "<<((info.flags|CKF_RW_SESSION)
?"read/write":"read only")<<std::endl
<<" Device Error: "<<info.ulDeviceError<<std::endl;
cryptoki::ObjectList certs
(session.find(cryptoki::Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)));
std::cout<<" Certificates: "<<certs.size()<<std::endl;
std::cout<<"--------------------------------------------------"<<std::endl
<<"Your Order Sir:"<<std::endl
<<" n: proceed to next card"<<std::endl
<<" c: check this card"<<std::endl
<<" r: remove all certificates"<<std::endl
<<" p: PIN change"<<std::endl
<<" i: (re-) import certificates"<<std::endl
<<" q: quit"<<std::endl;
std::cin>>choice;
try {
if (choice=="n") { // handled above in the while-loop
} else if (choice=="c") {
TextualCycle check(*card);
if (check.run())
std::cout<<"----> SuisseID is fine"<<std::endl;
else
std::cout<<"****> SuisseID is bad"<<std::endl;
} else if (choice=="r") {
std::cout<<"Not yet implemented."<<std::endl;
} else if (choice=="p") {
std::string oldpin, newpin;
std::cout<<"Enter Old PIN: ";
std::cin>>oldpin;
std::cout<<"Enter New PIN: ";
std::cin>>newpin;
if (oldpin.size() && newpin.size())
(*card)->changePins(newpin, oldpin);
} else if (choice=="i") {
TextualCycle check(*card);
check.installCerts(true);
} else if (choice=="q") {
return 0;
} else {
std::cout<<"I beg your pardon, Sir?"<<std::endl;
}
} catch (const std::exception& x) {
std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
}
} catch (std::exception& x) {
std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
choice="n"; // proceed
}
}
return 0; return 0;
} catch (std::exception& x) { } catch (std::exception& x) {
std::cerr<<"**** ERROR in "<<*argv<<": "<<x.what()<<std::endl; std::cerr<<"**** ERROR: "<<x.what()<<std::endl;
} }

View File

@@ -0,0 +1,100 @@
/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#ifndef SUISSE_ID_DEMO_HXX
#define SUISSE_ID_DEMO_HXX
#include <suisseid.hxx>
#include <iostream>
#include <cassert>
class TextualCycle: public suisseid::StatusCycle {
public:
TextualCycle(mrw::Shared<suisseid::Card> card):
StatusCycle(card) {
}
protected:
/// @name slots
//@{
virtual PinPukChange pinChangeTransportPin() {
PinPukChange pinpuk;
std::cout<<"Enter Transport PIN: ";
std::cin>>pinpuk.oldpin;
std::cout<<"Enter New PIN: ";
std::cin>>pinpuk.newpin;
return pinpuk;
}
virtual PinPukChange pinChangePuk() {
PinPukChange pinpuk;
std::cout<<"Enter PUK to unlock PKCS#15 PIN: ";
std::cin>>pinpuk.oldpin;
std::cout<<"Enter New PKCS#15 PIN: ";
std::cin>>pinpuk.newpin;
return pinpuk;
}
virtual void transportPinLocked() {
std::cout<<"Transport PIN is Locked!"<<std::endl;
}
virtual void pkcs15PinLocked() {
std::cout<<"PKCS#15 PIN is Locked!"<<std::endl;
}
virtual void sigGPinLocked() {
std::cout<<"SigG PIN is Locked!"<<std::endl;
}
virtual void pukLocked() {
std::cout<<"PUK is Locked!"<<std::endl;
}
virtual void certsExpireSoon() {
std::cout<<"Certificates Expire Soon!"<<std::endl;
}
virtual void certsExpired() {
std::cout<<"Certificates Expired!"<<std::endl;
}
virtual void certsRevoked() {
std::cout<<"Certificates Revoked!"<<std::endl;
}
public:
/// install certificates on the card
virtual bool installCerts(bool force = true) {
std::cout<<"Installing Certificates ..."<<std::endl;
std::string pin;
std::cout<<"Enter PIN (x to abort): ";
std::cin>>pin;
if (pin=="x") {
std::cout<<std::endl<<"User aborted"<<std::endl;
return false; // user aborts
}
cryptoki::Session session(card()->slot());
try {
session.login(pin);
} catch (const cryptoki::wrong_pin& x) {
std::cout<<"**** Wrong PIN!"<<std::endl;
std::cout<<x.what()<<std::endl;
return false;
}
std::cout<<"**** Not implemented"<<std::endl;
return true;
}
};
#endif

View File

@@ -16,10 +16,9 @@
#ifndef CARDOS_LOG #ifndef CARDOS_LOG
#define CARDOS_LOG(X) // no logging by default #define CARDOS_LOG(X) // no logging by default
// use e.g. #define CARDOS_LOG(X) std::cout<<X<<std::endl // use e.g. #define CARDOS_LOG(X) std::clog<<X<<std::endl
#endif #endif
namespace cardos { namespace cardos {
/// @defgroup gcardos C++ Access to Siemens CardOS V4.4 /// @defgroup gcardos C++ Access to Siemens CardOS V4.4
@@ -42,38 +41,40 @@ namespace cardos {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class wrong_pin: public exception { class wrong_pin: public exception {
public: public:
wrong_pin(const std::string& s) throw(): exception("wrong pin\n"+s) {} wrong_pin(const std::string& s) throw(): exception("wrong pin "+s) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class user_pin_locked: public exception { class user_pin_locked: public exception {
public: public:
user_pin_locked(const std::string& s) throw(): user_pin_locked(const std::string& s) throw():
exception("user pin locked\n"+s) {} exception("user pin locked "+s) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class wrong_puk: public exception { class wrong_puk: public exception {
public: public:
wrong_puk(const std::string& s) throw(): exception("wrong puk\n"+s) {} wrong_puk(const std::string& s) throw(): exception("wrong puk "+s) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class wrong_result: public exception { class wrong_result: public exception {
public: public:
wrong_result(const std::string& reason, const std::string& data) throw(): wrong_result(const std::string& reason, const std::string& data) throw():
exception("wrong result,\n"+reason+":\n"+crypto::hex(data)) {} exception("wrong result, "+reason+": "+crypto::hex(data)) {}
wrong_result(const std::string& reason) throw(): wrong_result(const std::string& reason) throw():
exception("wrong result,\n"+reason) {} exception("wrong result, "+reason) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class runtime_error: public exception { class runtime_error: public exception {
public: public:
runtime_error(const std::string& reason) throw():
exception("runtime error, "+reason) {}
runtime_error(const std::string& reason, const std::string& data) throw(): runtime_error(const std::string& reason, const std::string& data) throw():
exception("runtime error,\n"+reason+":\n"+crypto::hex(data)) {} exception("runtime error, "+reason+": "+crypto::hex(data)) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class unexpected_challenge_length: public exception { class unexpected_challenge_length: public exception {
public: public:
unexpected_challenge_length(const std::string& data) throw(): unexpected_challenge_length(const std::string& data) throw():
exception("challenge should be 8 bytes, challenge is:\n" exception("challenge should be 8 bytes, challenge is: "
+crypto::hex(data)) {} +crypto::hex(data)) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -81,8 +82,8 @@ namespace cardos {
public: public:
card_transmission_failed(const std::string& position, card_transmission_failed(const std::string& position,
const std::string& reason) throw(): const std::string& reason) throw():
exception("transmission to card failed:\n"+position exception("transmission to card failed: "+position
+"\nreason:\n"+reason) { +" reason: "+reason) {
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -90,8 +91,8 @@ namespace cardos {
public: public:
wrong_dataformat(const std::string& data, wrong_dataformat(const std::string& data,
const std::string& reason) throw(): const std::string& reason) throw():
exception("wrong dataformat:\n"+crypto::hex(data) exception("wrong dataformat: "+crypto::hex(data)
+"\nreason:\n"+reason) { +" reason: "+reason) {
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -111,66 +112,6 @@ namespace cardos {
//============================================================================ //============================================================================
/// @addtogroup cardostypes
//@{
/// Represents the Smart Card's Tag Length Value Encoded File Format.
class TagLengthValue {
public:
enum Tag {
DIRECTORY_ENTRY = 0x6F,
FILE_TYPE = 0x82,
FILE_IDENTIFIER = 0x86,
NEXT_OFFSET = 0x8A,
VERSION_INFO_CONTAINER = 0xff,
VERSION_INFO_STRING = 0x01
};
public:
/// Initialize from a File's Content
TagLengthValue(const std::string& content):
_size(0), _content(content) {
if (_content.size()<2)
throw wrong_dataformat(_content, "not a TLV, too small");
for (std::string::size_type pos(0); pos!=_content.size();
pos+=_content[pos+1]+2) {
++_size;
if (pos+2>_content.size())
throw wrong_dataformat(_content, "not a TLV, wrong size");
}
}
/// Return RAW File Content
std::string raw() {
return _content;
}
TagLengthValue at(unsigned int i) {
if (i>=_size) throw array_range(i, _size);
std::string::size_type pos(0);
for (unsigned int j(0); j!=i; ++j) {
pos+=_content[pos+1]+2;
}
return TagLengthValue(_content.substr(pos, _content[pos+1]+2));
}
std::string str() {
switch ((int)_content[0]) {
case VERSION_INFO_STRING:
return _content.substr(2, (int)_content[1]);
default:
throw wrong_dataformat(_content, "not a string");
}
}
TagLengthValue tlv() {
switch ((int)_content[0]) {
case VERSION_INFO_CONTAINER:
return TagLengthValue(_content.substr(2, (int)_content[1]));
default:
throw wrong_dataformat(_content, "not a container");
}
}
private:
unsigned int _size;
std::string _content;
};
class BerValue { class BerValue {
public: public:
enum Class { enum Class {
@@ -361,41 +302,6 @@ namespace cardos {
std::string _value; std::string _value;
std::vector<BerValue> _sequence; std::vector<BerValue> _sequence;
// BerValue(const std::string& content) {
// if (content.size()<2 ||
// content.size()<2+(std::string::size_type)content[1])
// throw wrong_dataformat(content, "not a BER, value too small");
// if (content.size()>2+(std::string::size_type)content[1]) {
// _tag = UNIVERSAL|CONSTRUCTED|SEQUENCE;
// _length = content.size()-2;
// _value = content.substr(2, _length);
// for (std::string::size_type pos(0); pos!=content.size();
// pos+=content[pos+1]+2) {
// if (pos+2>content.size() ||
// (std::string::size_type)content[pos+1]+2>content.size())
// throw wrong_dataformat(content, "not a BER, wrong size");
// _sequence.push_back
// (BerValue(content.substr(pos, content[pos+1]+2)));
// }
// } else {
// _tag = content[0];
// _length = content[1];
// _value = content.substr(2, _length);
// if (isContainer()) {
// for (std::string::size_type pos(2); pos!=content.size();
// pos+=content[pos+1]+2) {
// if (pos+2>content.size() ||
// (std::string::size_type)content[pos+1]+2>content.size())
// throw wrong_dataformat(content, "not a BER, wrong size");
// _sequence.push_back
// (BerValue(content.substr(pos, content[pos+1]+2)));
// }
// } else {
// _value = content.substr(2, _length);
// }
// }
// }
}; };
/// Store a sequence of BerValue /// Store a sequence of BerValue
@@ -439,11 +345,7 @@ namespace cardos {
//@{ //@{
/// 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. */
This class does not do any transaction handling. Please handle
transactions on a higher level, when you access these
methods. */
class Commands { class Commands {
public: public:
@@ -452,9 +354,9 @@ namespace cardos {
/// @name Setup Smart Card Reader /// @name Setup Smart Card Reader
//@{ //@{
/// Uninitialized class, use @ref reader to setup assign smart card reader. /// Uninitialized class
Commands() { /** Use @ref reader to setup assign smart card reader. */
} Commands() {}
/// Initialize with given smart card reader. /// Initialize with given smart card reader.
Commands(mrw::Shared<pcsc::Connection::Reader> reader): Commands(mrw::Shared<pcsc::Connection::Reader> reader):
@@ -484,6 +386,7 @@ namespace cardos {
the security status of the current DF. The command the security status of the current DF. The command
cannot be applied to CODE files. */ cannot be applied to CODE files. */
void activateFile() { void activateFile() {
CRYPTOLOG("log");
check(send(0x00, 0x44, 0x00, 0x00)); check(send(0x00, 0x44, 0x00, 0x00));
} }
@@ -532,13 +435,15 @@ namespace cardos {
@see freeTransactionBuffer */ @see freeTransactionBuffer */
std::string allocateTransactionBuffer(unsigned short size) { std::string allocateTransactionBuffer(unsigned short size) {
if (size>0x7FFF) throw std::runtime_error("requested buffer too large"); CRYPTOLOG("log");
if (size>0x7FFF) throw runtime_error("requested buffer too large");
return check(send(0x80, 0x12, 8|size>>8, size&0xFF)); return check(send(0x80, 0x12, 8|size>>8, size&0xFF));
} }
//! Free transaction buffer //! Free transaction buffer
/*! @see allocateTransactionBuffer */ /*! @see allocateTransactionBuffer */
void freeTransactionBuffer(unsigned char id) { void freeTransactionBuffer(unsigned char id) {
CRYPTOLOG("log");
check(send(0x80, 0x12, 0x00, id)); check(send(0x80, 0x12, 0x00, id));
} }
@@ -587,6 +492,7 @@ namespace cardos {
referenced by the files AC APPEND is granted in the referenced by the files AC APPEND is granted in the
security status of the current DF. */ security status of the current DF. */
void appendRecord(unsigned char efId, std::string data) { void appendRecord(unsigned char efId, std::string data) {
CRYPTOLOG("log");
check(send(0x00, 0xE2, 0x00, efId, data)); check(send(0x00, 0xE2, 0x00, efId, data));
} }
@@ -654,12 +560,14 @@ namespace cardos {
@return Digital Signature */ @return Digital Signature */
std::string cardAuthenticate(bool hashInclIdentNum, std::string cardAuthenticate(bool hashInclIdentNum,
std::string systemChallange) { std::string systemChallange) {
CRYPTOLOG("log");
return check(send(0x80, 0x88, hashInclIdentNum?0x01:0x02, 0x00, return check(send(0x80, 0x88, hashInclIdentNum?0x01:0x02, 0x00,
systemChallange)); systemChallange));
} }
//! Changes the object data of any BS object except for PIN TEST objects //! Changes the object data of any BS object except for PIN TEST objects
void changeKeyData() { void changeKeyData() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -667,17 +575,21 @@ namespace cardos {
/** Changes a PIN. */ /** Changes a PIN. */
void changeReferenceData(unsigned char id, std::string newData, void changeReferenceData(unsigned char id, std::string newData,
std::string oldData=std::string()) { std::string oldData=std::string()) {
check(send(0x00, 0x24, oldData.size()?0x00:0x01, id, oldData+newData)); CRYPTOLOG("log");
check(send(0x00, 0x24, oldData.size()?0x00:0x01, 0x80|id,
oldData+newData));
} }
//! Changes the data of a system key to the new key data //! Changes the data of a system key to the new key data
//! provided with the command. //! provided with the command.
void changeSystemKey() { void changeSystemKey() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Creates a file (only EF or DF) //! Creates a file (only EF or DF)
void createFile(BerValue) { void createFile(BerValue) {
CRYPTOLOG("log");
// check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h, // check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h,
// data).raw())); // data).raw()));
assert(!"not implemented"); assert(!"not implemented");
@@ -685,16 +597,19 @@ namespace cardos {
//! Deactivates a file or a file tree //! Deactivates a file or a file tree
void deactivateFile() { void deactivateFile() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Decreases a record value //! Decreases a record value
void decrease() { void decrease() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Deletes a file (DF or EF) //! Deletes a file (DF or EF)
void deleteFile() { void deleteFile() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -702,21 +617,25 @@ namespace cardos {
//! Reads file information of EFs and/or DFs in the current DF //! Reads file information of EFs and/or DFs in the current DF
BerValue directory(FileTypes types, unsigned char offset=0) { BerValue directory(FileTypes types, unsigned char offset=0) {
CRYPTOLOG("log");
return BerValue(check(send(0x80, 0x16, types, offset))); return BerValue(check(send(0x80, 0x16, types, offset)));
} }
//! Enables an already loaded and activated but disabled license package. //! Enables an already loaded and activated but disabled license package.
void enablePackage() { void enablePackage() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Erases the file system in the EEPROM. //! Erases the file system in the EEPROM.
void eraseFiles() { void eraseFiles() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Performs a challenge/response test //! Performs a challenge/response test
void externalAuthenticate() { void externalAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -724,26 +643,31 @@ namespace cardos {
//! ADMINISTRATION after creation of the MF or changes only from //! ADMINISTRATION after creation of the MF or changes only from
//! MANUFACTURING to INITIALIZATION. //! MANUFACTURING to INITIALIZATION.
void format() { void format() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Generates a key pair for the RSA/RSA2 algorithms within the card //! Generates a key pair for the RSA/RSA2 algorithms within the card
void generateKeyPair() { void generateKeyPair() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Generates an internal random number (i.e. SC_Challenge) //! Generates an internal random number (i.e. SC_Challenge)
void getChallange() { void getChallange() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Reads system information //! Reads system information
std::string getData(unsigned char mode) { std::string getData(unsigned char mode) {
CRYPTOLOG("log");
return check(send(0x00, 0xCA, 0x01, mode)); return check(send(0x00, 0xCA, 0x01, mode));
} }
//! Product name, version, release date, copyright string //! Product name, version, release date, copyright string
std::string getDataProductName() { std::string getDataProductName() {
CRYPTOLOG("log");
return getData(0x80); return getData(0x80);
} }
@@ -755,6 +679,7 @@ namespace cardos {
//! Chip production data as supplied by Infineon, PROM area //! Chip production data as supplied by Infineon, PROM area
ChipProductionData getDataChipProduction() { ChipProductionData getDataChipProduction() {
CRYPTOLOG("log");
std::string code(getData(0x81)); std::string code(getData(0x81));
ChipProductionData res = { ChipProductionData res = {
code.substr(8, 8), code.substr(8, 8),
@@ -781,6 +706,7 @@ namespace cardos {
The external random number is stored in the XRAM of the The external random number is stored in the XRAM of the
smart card. */ smart card. */
void giveRandom(std::string random) { void giveRandom(std::string random) {
CRYPTOLOG("log");
check(send(0x80, 0x86, 0x00, 0x00, random)); check(send(0x80, 0x86, 0x00, 0x00, random));
} }
@@ -793,6 +719,7 @@ namespace cardos {
- bits 7-3 = ppppp, bits 2-0=0 → use SFI ppppp (11111 not allowed) - bits 7-3 = ppppp, bits 2-0=0 → use SFI ppppp (11111 not allowed)
- other value → rfu */ - other value → rfu */
std::string increase(unsigned char efId=0, unsigned short size=1) { std::string increase(unsigned char efId=0, unsigned short size=1) {
CRYPTOLOG("log");
std::string data; std::string data;
data.resize(2); data.resize(2);
data[0] = size>>8; data[0] = size>>8;
@@ -803,32 +730,38 @@ namespace cardos {
//! Manufacturer use only //! Manufacturer use only
void initializeEeprom() { void initializeEeprom() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Manufacturer use only //! Manufacturer use only
void initializeEnd() { void initializeEnd() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Performs cryptographic algorithms for authentication //! Performs cryptographic algorithms for authentication
void internalAuthenticate() { void internalAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Activates a package //! Activates a package
void loadExecutable() { void loadExecutable() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Opens or closes a logical channel //! Opens or closes a logical channel
std::string manageChannel(unsigned char mode, unsigned char channelId) { std::string manageChannel(unsigned char mode, unsigned char channelId) {
CRYPTOLOG("log");
return check(send(0x00, 0x70, mode, channelId)); return check(send(0x00, 0x70, mode, channelId));
} }
//! Loads a CSE (RESTORE) or sets a component of the CSE (SET) //! Loads a CSE (RESTORE) or sets a component of the CSE (SET)
//! and/or sets an extended headerlist //! and/or sets an extended headerlist
void manageSecureEnvironment() { void manageSecureEnvironment() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -836,21 +769,25 @@ namespace cardos {
//! MAC/Signature calculation and, depending on the input, a //! MAC/Signature calculation and, depending on the input, a
//! session key derivation. //! session key derivation.
void mutualAuthenticate() { void mutualAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Performs a cryptographic operation //! Performs a cryptographic operation
void performSecurityOperation() { void performSecurityOperation() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Controls the command sequence transactions //! Controls the command sequence transactions
void performTransactonOperation() { void performTransactonOperation() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Personalizer use only //! Personalizer use only
void personalize() { void personalize() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -882,16 +819,19 @@ namespace cardos {
@prereq The command can be executed in the life cycle phases @prereq The command can be executed in the life cycle phases
ADMINISTRATION and OPERATIONAL. */ ADMINISTRATION and OPERATIONAL. */
void phaseControl() { void phaseControl() {
CRYPTOLOG("log");
check(send(0x80, 0x10, 0x00, 0x00)); check(send(0x80, 0x10, 0x00, 0x00));
} }
//! Installs / administrates / overwrites different objects //! Installs / administrates / overwrites different objects
void putData() { void putData() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Read a BINARY file //! Read a BINARY file
std::string readBinary(unsigned short offset = 0) { std::string readBinary(unsigned short offset = 0) {
CRYPTOLOG("log");
return check(send(0x00, 0xB0, offset>>8, offset&0xFF)); return check(send(0x00, 0xB0, offset>>8, offset&0xFF));
} }
@@ -908,12 +848,15 @@ namespace cardos {
std::string readRecord(unsigned char record = 0, std::string readRecord(unsigned char record = 0,
unsigned char sfi = 0, unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) { ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log");
return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode)); return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode));
} }
/// Read all records from a record oriented file /// Read all records from a record oriented file
BerValues readBerFile() { BerValues readBerFile() {
CRYPTOLOG("log");
BerValues content; BerValues content;
pcsc::Connection::Reader::Transaction lock(_reader);
while (true) { while (true) {
std::string res(send(0x00, 0xB2, 0, NEXT_RECORD)); std::string res(send(0x00, 0xB2, 0, NEXT_RECORD));
if (cardos::Commands::retCode(res)!=0x9000) break; if (cardos::Commands::retCode(res)!=0x9000) break;
@@ -924,11 +867,13 @@ namespace cardos {
//! Resets the error counter of a BS object to its maximum //! Resets the error counter of a BS object to its maximum
void resetRetryCounter() { void resetRetryCounter() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Resets the security status of the current DF //! Resets the security status of the current DF
void resetSecurityCounter() { void resetSecurityCounter() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
@@ -954,6 +899,7 @@ namespace cardos {
= DF_OR_EF_USING_PATH_FROM_MF, = DF_OR_EF_USING_PATH_FROM_MF,
FileSelectionReturn ret FileSelectionReturn ret
= RETURN_NOTHING) { = RETURN_NOTHING) {
CRYPTOLOG("log");
return BerValue(check(send(0x00, 0xA4, mode, ret, file))); return BerValue(check(send(0x00, 0xA4, mode, ret, file)));
} }
@@ -961,32 +907,38 @@ namespace cardos {
//! the effective Command Data Field Length / Response Data //! the effective Command Data Field Length / Response Data
//! Field Length. //! Field Length.
void setDataFieldLength() { void setDataFieldLength() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Enables or disables the usage of an existing transaction buffer //! Enables or disables the usage of an existing transaction buffer
void setTransactionState() { void setTransactionState() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Signs a hashed input using a decryption key with the RSA_SIG //! Signs a hashed input using a decryption key with the RSA_SIG
//! algorithm. //! algorithm.
void signByDecryptionKey() { void signByDecryptionKey() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
//! Uninstalls a package of the smart card //! Uninstalls a package of the smart card
void uninstallPackage() { void uninstallPackage() {
CRYPTOLOG("log");
assert(!"not implemented"); assert(!"not implemented");
} }
/// Read the previously file from smart card /// Read the previously file from smart card
std::string readBinFile() { std::string readBinFile() {
CRYPTOLOG("log");
return check(send(0x00, 0xB0, 0x00, 0x00)); return check(send(0x00, 0xB0, 0x00, 0x00));
} }
//! Updates a BINARY file //! Updates a BINARY file
void updateBinary(std::string data, unsigned short offset=0) { void updateBinary(std::string data, unsigned short offset=0) {
CRYPTOLOG("log");
check(send(0x00, 0xD6, offset>>8, offset&0xFF, data)); check(send(0x00, 0xD6, offset>>8, offset&0xFF, data));
} }
@@ -995,6 +947,7 @@ namespace cardos {
unsigned char record = 0, unsigned char record = 0,
unsigned char sfi = 0, unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) { ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log");
return check(send(0x00, 0xDC, record, (sfi&0xF8)|mode, data)); return check(send(0x00, 0xDC, record, (sfi&0xF8)|mode, data));
} }
@@ -1006,12 +959,14 @@ namespace cardos {
//! Performs a PIN test (CHV test) //! Performs a PIN test (CHV test)
void verify(std::string pin, unsigned char id, void verify(std::string pin, unsigned char id,
VerifyMode mode = SEARCH_FROM_DF) { VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log");
check(send(0x00, 0x20, 0x00, id|mode, pin)); check(send(0x00, 0x20, 0x00, id|mode, pin));
} }
//! Performs a PIN test (CHV test) //! Performs a PIN test (CHV test)
/*! @return number of remaining PIN retries or -1 if PIN is locked */ /*! @return number of remaining PIN retries or -1 if PIN is locked */
int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) { int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log");
std::string res(send(0x00, 0x20, 0x00, id|mode)); std::string res(send(0x00, 0x20, 0x00, id|mode));
unsigned int value((((unsigned int)(unsigned char)res[0])*256) unsigned int value((((unsigned int)(unsigned char)res[0])*256)
+((unsigned int)(unsigned char)res[1])); +((unsigned int)(unsigned char)res[1]));
@@ -1036,7 +991,7 @@ namespace cardos {
} }
/// Path to SigG (Signaturgesetz) /// Path to SigG (Signaturgesetz)
std::string sigg() { std::string sigG() {
return crypto::hexToBin("1fff"); return crypto::hexToBin("1fff");
} }
@@ -1068,24 +1023,32 @@ namespace cardos {
/// Logon with transport PIN /// Logon with transport PIN
void logonTransport(std::string pin) { void logonTransport(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG(); selectSigG();
logon(transportPin(), pin); logon(transportPin(), pin);
} }
/// Logon with SigG (Signaturgesetz) secure PIN /// Logon with SigG (Signaturgesetz) secure PIN
void logonSigG(std::string pin) { void logonSigG(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG(); selectSigG();
logon(sigGPin(), pin); logon(sigGPin(), pin);
} }
/// Logon with PKCS#15 user PUK to unlock user PIN /// Logon with PKCS#15 user PUK to unlock user PIN
void logonPuk(std::string pin) { void logonPuk(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF(); selectMF();
logon(puk(), pin); logon(puk(), pin);
} }
/// Logon with PKCS#15 user PIN /// Logon with PKCS#15 user PIN
void logonPkcs15(std::string pin) { void logonPkcs15(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF(); selectMF();
logon(pkcs15Pin(), pin); logon(pkcs15Pin(), pin);
} }
@@ -1095,18 +1058,24 @@ namespace cardos {
transport PIN and then the card is unlocked and the transport PIN and then the card is unlocked and the
transport state is unset. */ transport state is unset. */
void changeSigGPin(std::string newPin, std::string oldPin) { void changeSigGPin(std::string newPin, std::string oldPin) {
selectSigG(); CRYPTOLOG("log");
if (transportState()) { // first time use, reset transport state if (transportState()) { // first time use, reset transport state
pcsc::Connection::Reader::Transaction lock(_reader);
logonTransport(oldPin); logonTransport(oldPin);
changeReferenceData(sigGPin(), newPin); changeReferenceData(sigGPin(), newPin);
unsetTransportState(); unsetTransportState();
} else { // ordinary PIN change } else { // ordinary PIN change
pcsc::Connection::Reader::Transaction lock(_reader);
logonSigG(oldPin);
selectSigG();
changeReferenceData(sigGPin(), newPin, oldPin); changeReferenceData(sigGPin(), newPin, oldPin);
} }
} }
/// Change PKCS#15 user PIN /// Change PKCS#15 user PIN
void changePkcs15Pin(std::string newPin, std::string oldPin) { void changePkcs15Pin(std::string newPin, std::string oldPin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF(); selectMF();
changeReferenceData(pkcs15Pin(), newPin, oldPin); changeReferenceData(pkcs15Pin(), newPin, oldPin);
} }
@@ -1116,87 +1085,110 @@ namespace cardos {
state, if so, old PIN must be transport PIN. in any case, state, if so, old PIN must be transport PIN. in any case,
change PIN on PKCS#15 and SigG from the same old PIN to the change PIN on PKCS#15 and SigG from the same old PIN to the
same new PIN. */ same new PIN. */
void changePin(std::string newPin, std::string oldPin) { void changePins(std::string newPin, std::string oldPin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
if (transportState()) {
if (sigGPinRetries()!=-1) changeSigGPin(newPin, oldPin);
if (pkcs15PinRetries()!=-1) changePkcs15Pin(newPin, oldPin);
} else {
if (pkcs15PinRetries()!=-1) changePkcs15Pin(newPin, oldPin);
try { try {
changePkcs15Pin(newPin, oldPin); if (sigGPinRetries()!=-1) changeSigGPin(newPin, oldPin);
try {
changeSigGPin(newPin, oldPin);
} catch (...) { } catch (...) {
changePkcs15Pin(oldPin, newPin); // undo PKCS#15 PIN change // undo PKCS#15 PIN change
throw; // change SigG PIN failed if (pkcs15PinRetries()!=-1) changePkcs15Pin(oldPin, newPin);
throw;
} }
} catch (...) {
throw; // change PKCS#15 PIN failed
} }
} }
/// Select a file in the PKCS#15 part on the smart card /// Select a file in the PKCS#15 part on the smart card
void selectPkcs15File(std::string file) { void selectPkcs15File(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"+file))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"+file)));
} }
/// Select a file in the SigG (Signaturgesetz) part on the smart card /// Select a file in the SigG (Signaturgesetz) part on the smart card
void selectSigGFile(std::string file) { void selectSigGFile(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"+file))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"+file)));
} }
/// Select a file in the MF part on the smart card /// Select a file in the MF part on the smart card
void selectMfFile(std::string file) { void selectMfFile(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file)));
} }
/// Select the PKCS#15 part on the smart card /// Select the PKCS#15 part on the smart card
void selectPkcs15() { void selectPkcs15() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015")));
} }
/// Select the SigG (Signaturgesetz) part on the smart card /// Select the SigG (Signaturgesetz) part on the smart card
void selectSigG() { void selectSigG() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"))); check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff")));
} }
/// Select the MFpart on the smart card /// Select the MFpart on the smart card
void selectMF() { void selectMF() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x00, 0x0C)); check(send(0x00, 0xA4, 0x00, 0x0C));
} }
/// @return binary serial number /// @return binary serial number
std::string serial() { std::string serial() {
CRYPTOLOG("log");
return getDataChipProduction().serial; return getDataChipProduction().serial;
} }
/// @return @c true if card is still in transport state /// @return @c true if card is still in transport state
bool transportState() { bool transportState() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigGFile("fe15"); selectSigGFile("fe15");
return std::string(4, '\0')==readBinary(); return std::string(4, '\0')==readRecord();
} }
/// Mark card as initiakized and no more in transport state /// Mark card as initiakized and no more in transport state
void unsetTransportState() { void unsetTransportState() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigGFile("fe15"); selectSigGFile("fe15");
increase(); increase();
} }
/*! @return number of remaining transport PIN retries or -1 if locked */ /*! @return number of remaining transport PIN retries or -1 if locked */
int transportPinRetries() { int transportPinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG(); selectSigG();
return verify(transportPin()); return verify(transportPin());
} }
/*! @return number of remaining PKCS#15 PIN retries or -1 if locked */ /*! @return number of remaining PKCS#15 PIN retries or -1 if locked */
int pkcs15PinRetries() { int pkcs15PinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF(); selectMF();
return verify(pkcs15Pin()); return verify(pkcs15Pin());
} }
/*! @return number of remaining SigG PIN retries or -1 if locked */ /*! @return number of remaining SigG PIN retries or -1 if locked */
int sigGPinRetries() { int sigGPinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG(); selectSigG();
return verify(sigGPin()); return verify(sigGPin());
} }
/*! @return number of remaining PUK retries or -1 if locked */ /*! @return number of remaining PUK retries or -1 if locked */
int pukRetries() { int pukRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF(); selectMF();
return verify(puk()); return verify(puk());
} }
@@ -1240,7 +1232,7 @@ namespace cardos {
else if (data.size()>4) else if (data.size()>4)
return send(data[0], data[1], data[2], data[3], data.substr(4)); return send(data[0], data[1], data[2], data[3], data.substr(4));
else else
throw std::runtime_error("wrong APDU pass at least 4 bytes in hex"); throw runtime_error("wrong APDU pass at least 4 bytes in hex");
} }
//! @return error text of APDU result string //! @return error text of APDU result string
@@ -1316,10 +1308,10 @@ namespace cardos {
return "CLA invalid (Hi nibble)"; return "CLA invalid (Hi nibble)";
case 0x6f00: case 0x6f00:
return return
"Technical Error:\n" "Technical Error: "
" 1 Attempt to create more than 254 records in a file.\n" " 1 Attempt to create more than 254 records in a file. "
" 2 Package uses SDK version which is not compatible to" " 2 Package uses SDK version which is not compatible to"
" API version\n" " API version "
" 3 Package contains invalid statements (LOAD EXECUTABLE)"; " 3 Package contains invalid statements (LOAD EXECUTABLE)";
case 0x6f81: case 0x6f81:
return "File is invalidated because of checksum error (prop.)"; return "File is invalidated because of checksum error (prop.)";
@@ -1342,7 +1334,7 @@ namespace cardos {
return "Transaction buffer too small"; return "Transaction buffer too small";
case 0x6fff: case 0x6fff:
return return
"Internal assertion (invalid internal error)\n" "Internal assertion (invalid internal error) "
"This error is no runtime error but an internal error which can" "This error is no runtime error but an internal error which can"
" occur because of a programming error only."; " occur because of a programming error only.";
case 0x9000: case 0x9000:
@@ -1384,7 +1376,8 @@ namespace cardos {
std::string check(std::string res) { std::string check(std::string res) {
unsigned int value(retCode(res)); unsigned int value(retCode(res));
if (value!=0x9000) throw std::runtime_error(error(value)); if (value==0x6300) throw wrong_pin(error(value));
if (value!=0x9000) throw runtime_error(error(value));
return retData(res); return retData(res);
} }
@@ -1410,7 +1403,7 @@ namespace cardos {
} }
std::string send(char cla, char ins, char p1, char p2, std::string lc) { std::string send(char cla, char ins, char p1, char p2, std::string lc) {
if (!_reader) throw std::runtime_error("no reader selected"); if (!_reader) throw runtime_error("no reader selected");
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla) CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
<<" ins="<<crypto::binToHex(ins) <<" ins="<<crypto::binToHex(ins)
<<" p1="<<crypto::binToHex(p1) <<" p1="<<crypto::binToHex(p1)
@@ -1420,7 +1413,7 @@ namespace cardos {
} }
std::string send(char cla, char ins, char p1, char p2) { std::string send(char cla, char ins, char p1, char p2) {
if (!_reader) throw std::runtime_error("no reader selected"); if (!_reader) throw runtime_error("no reader selected");
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla) CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
<<" ins="<<crypto::binToHex(ins) <<" ins="<<crypto::binToHex(ins)
<<" p1="<<crypto::binToHex(p1) <<" p1="<<crypto::binToHex(p1)
@@ -1437,212 +1430,6 @@ namespace cardos {
}; };
//@} //@}
//============================================================================
class Access {
public:
enum TokenVersion {PZ2007, PZ2009, PZ2010};
private:
Access(); // not available, reader is required
public:
std::string serialNumber() {
return check(_reader->transmit(0x00, 0xCA, 0x01, 0x81),
"read serial number").substr(8, 8);
}
bool firstUse() {
#ifndef Q_OS_MAC
pcsc::Connection::Reader::Transaction lock(_reader);
#endif
// SigG Part:
// 1. select file "transport protection state" /1/ #236
check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x1F\xFF\xFE\x15", 4),
"select file \"transport protection state\"");
// 2. read PIN_T's current use counter value
std::string res(check(_reader->transmit(0x00, 0xB2, 0x00, 0x04),
"read PIN_T counter"));
if (res.size()!=6) throw wrong_result("cannot check for first use");
return res.substr(0, 4)==std::string("\0\0\0\0", 4); // uninitialized: 0
}
//! get file version info
/*! @return Content of file "Version Info" or "<unknown>" if
there's no such file */
void unlock(const std::string puk, const std::string pin,
bool force=false) {
// #ifndef Q_OS_MAC
// pcsc::Connection::Reader::Transaction lock(_reader);
// #endif
// check(_reader->transmit(0x00, 0xA4, 0x00, 0x0C), "select MF");
// try {
// check(_reader->transmit(0x00, 0x20, 0x00, 0x02, puk), "verify PUK");
// } catch (std::exception& e) {
// throw wrong_puk(std::string("verify user PUK failed: ")+e.what());
// }
// if (force) { // kill old dig sig
// while (checkDigSigPin().valid())
// try {
// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C,
// "\x1F\xFF\xFE\x15", 4),
// "select SigG");
// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, pin),
// "verify for correct old PIN in SigG");
// break; // ok, pin still vaild, user is a winner
// } catch (...) {} // normally ends up here, retry until broken
// } else {
// if (checkDigSigPin().valid()) try {
// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C,
// "\x1F\xFF\xFE\x15", 4),
// "select SigG");
// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, pin),
// "verify for correct old PIN in SigG");
// } catch (std::exception& e) {
// throw wrong_pin(std::string("verify SigG PIN failed: ")+e.what());
// }
// }
// check(_reader->transmit(0x00, 0xA4, 0x00, 0x0C), "select MF");
// check(_reader->transmit(0x00, 0x24, 0x01, 0x81, pin), "reset user PIN");
}
void changePin(const std::string oldPin, const std::string newPin) {
// #ifndef Q_OS_MAC
// pcsc::Connection::Reader::Transaction lock(_reader);
// #endif
// if (version()==PZ2007||firstUse()) {
// changePinSigG(oldPin, newPin);
// changePinPkcs15(oldPin, newPin);
// } else {
// if (checkUserPin().locked())
// throw user_pin_locked("pin change is not possible");
// changePinPkcs15(oldPin, newPin);
// if (!checkDigSigPin().locked())
// changePinSigG(oldPin, newPin);
// }
}
void changePinSigG(const std::string oldPin, const std::string newPin) {
// #ifndef Q_OS_MAC
// pcsc::Connection::Reader::Transaction lock(_reader);
// #endif
// bool first(firstUse());
// // select DF SigG /1/ #236
// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x1F\xFF\xFE\x15", 4),
// "select DF SigG");
// try {
// if (first) // verify PIN_T /1/ #248 (optional!)
// check(_reader->transmit(0x00, 0x20, 0x00, 0xF1, oldPin),
// "verify PIN_T");
// else // verify PIN (not in transport state)
// check(_reader->transmit(0x00, 0x20, 0x00, 0x81, oldPin),
// "verify PIN");
// } catch (const std::exception& e) {
// throw wrong_pin(std::string("verify SigG-PIN failed: ")+e.what());
// }
// // change reference data SigG-PIN /1/ #125,81
// if (first)
// check(_reader->transmit(0x00, 0x24, 0x01, 0x81, newPin),
// "change reference data SigG-PIN first time");
// else
// check(_reader->transmit(0x00, 0x24, 0x00, 0x81, oldPin+newPin),
// "change reference data SigG-PIN");
// // mark pin as changed, no more transport state
// for (int i(0); true; ++i) try { // «bugfix» for freddy: multiple tries
// if (first)
// check(_reader->transmit(0x80, 0x32, 0x00, 0x00, "\x01", 1),
// "mark pin as changed");
// break; // jump out of the loop, all everything is ok
// } catch (...) { // retry up to 10 times
// if (i>=10) throw;
// }
}
void changePinPkcs15(const std::string oldPin, const std::string newPin) {
// #ifndef Q_OS_MAC
// pcsc::Connection::Reader::Transaction lock(_reader);
// #endif
// // select MF
// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x3F\x00", 2),
// "select MF");
// try {
// // change reference data | Use PIN ID
// check(_reader->transmit(0x00, 0x24, 0x00, 0x01, oldPin+newPin),
// "set new PIN");
// } catch (const std::exception& e) {
// throw wrong_pin(std::string("verify PKCS#15-PIN failed: ")
// +e.what());
// }
// // select DF PKCS#15
// check(_reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x50\x15", 2),
// "select DF PKCS#15");
}
static unsigned int retCode(const std::string& res) {
if (res.size()>=2)
return ((((unsigned int)(unsigned char)res[res.size()-2])*256)
+((unsigned int)(unsigned char)res[res.size()-1]));
else
return -1;
}
private:
friend class CardOsTest;
//! ANSI Padding: Fill to 8 byte blocks with @c 0x00
static std::string ansiPadding(std::string data) {
while (data.size()%8!=0) data += (char)0x00;
return data;
}
//! ISO Padding: mark end with @c 0x80, then do @ref ansiPadding
static std::string isoPadding(std::string data) {
data += (char)0x80; // command+ISO_Padding_Byte(0x80)
return ansiPadding(data);
}
static std::string des3enc(const std::string& data,
const openssl::CBlock8& key1,
const openssl::CBlock8& key2) {
// initial vector is always 0
return openssl::des2edeCbcEnc(isoPadding(data), key1, key2);
}
// retail mac signature
static std::string sign(const std::string& data,
const openssl::CBlock8& key1,
const openssl::CBlock8& key2) {
// initial vector is 0 anyway...
openssl::CBlock8 ivec;
openssl::desCbcEnc(isoPadding(data), key1, ivec);
return openssl::desCbcEnc(openssl::desCbcDec(ivec, key2), key1);
}
const std::string& check(const std::string& res,
const std::string& position) const {
// static unsigned long SUCCESS(0x9000);
// unsigned long c(retCode(res));
// if (c!=SUCCESS) throw card_transmission_failed(position,
// Commands::error(c));
return res;
}
//========================================================================
private:
mrw::Shared<pcsc::Connection::Reader> _reader;
};
} }
//@} //@}

View File

@@ -17,6 +17,57 @@
/*! @defgroup gcrypto Auxiliary Crypto-Functions */ /*! @defgroup gcrypto Auxiliary Crypto-Functions */
//@{ //@{
#define CRYPTOLOG_QUOTE(X) CRYPTOLOG_QUOTE2(X)
#define CRYPTOLOG_QUOTE2(X) #X
#if __GNUC__ >= 2
# define CRYPTOLOG_END " -- "<<__PRETTY_FUNCTION__<<std::endl
#else
# define CRYPTOLOG_END std::endl
#endif
// Logging, enable with -DDEBUG
#ifndef CRYPTOLOG
# ifndef DEBUG
# define CRYPTOLOG(X)
# 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 \
<<CRYPTOLOG_END; \
}
# endif
#endif
// Verbose logging, use with care, will also log PINs.
// Enable with -DDEBUG -DVERBOSE
#ifndef CRYPTOLOG_VERBOSE
# if !(defined(DEBUG)&&defined(VERBOSE))
# define CRYPTOLOG_VERBOSE(X)
# 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 \
<<CRYPTOLOG_END; \
}
# endif
#endif
//! @see gcrypto //! @see gcrypto
namespace crypto { namespace crypto {

View File

@@ -24,14 +24,14 @@ typedef CK_RV (*CK_C_GetFunctionList)
namespace cryptoki { namespace cryptoki {
bool Library::Init::functionList(const std::string& library) { bool Library::Init::functionList(const std::string& library) {
CRYPTOKI_LOG("try to load: "<<library); CRYPTOLOG("try to load: "<<library);
#ifndef WIN32 #ifndef WIN32
_lib = dlopen(library.c_str(), RTLD_NOW); _lib = dlopen(library.c_str(), RTLD_NOW);
#else #else
_lib = LoadLibrary(library.c_str()); _lib = LoadLibrary(library.c_str());
#endif #endif
if (!_lib) throw exception("open of library failed: "+library); if (!_lib) throw exception("open of library failed: "+library);
CRYPTOKI_LOG("loaded: "<<library); CRYPTOLOG("loaded: "<<library);
#ifndef WIN32 #ifndef WIN32
CK_C_GetFunctionList fn CK_C_GetFunctionList fn
((CK_C_GetFunctionList)dlsym(_lib, "C_GetFunctionList")); ((CK_C_GetFunctionList)dlsym(_lib, "C_GetFunctionList"));
@@ -42,24 +42,28 @@ namespace cryptoki {
if (!fn) if (!fn)
throw exception("required library symbol C_GetFunctionList not found in " throw exception("required library symbol C_GetFunctionList not found in "
+library); +library);
CRYPTOKI_LOG("Got C_GetFunctionList, now call it"); CRYPTOLOG("Got C_GetFunctionList, now call it");
//! calls @c C_GetFunctionList //! calls @c C_GetFunctionList
return check(fn(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList")); return check(fn(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList"));
} }
bool Library::Init::check(CK_RV result, const std::string& context) { bool Library::Init::check(CK_RV result, const std::string& context) {
CRYPTOKI_LOG("log");
_res = result; _res = result;
if (_exc && !*this) if (_exc && !*this)
if (context.size()) if (context.size())
if (_res==CKR_PIN_INCORRECT)
throw wrong_pin(context+": "+error());
else
throw access_error(context+": "+error()); throw access_error(context+": "+error());
else
if (_res==CKR_PIN_INCORRECT)
throw wrong_pin(error());
else else
throw access_error(error()); throw access_error(error());
return _res==CKR_OK; return _res==CKR_OK;
} }
std::string Library::Init::error(CK_RV res) { std::string Library::Init::error(CK_RV res) {
CRYPTOKI_LOG("log");
switch (res) { switch (res) {
case CKR_OK: return "CKR_OK"; case CKR_OK: return "CKR_OK";
case CKR_CANCEL: return "CKR_CANCEL"; case CKR_CANCEL: return "CKR_CANCEL";
@@ -168,10 +172,10 @@ namespace cryptoki {
Library::Init::Init(const std::string& library, bool exc) try: Library::Init::Init(const std::string& library, bool exc) try:
_exc(exc), _res(CKR_OK), _fn(0) { _exc(exc), _res(CKR_OK), _fn(0) {
CRYPTOKI_LOG("library: "<<library); CRYPTOLOG("library: "<<library);
//! calls @c functionList //! calls @c functionList
if (!functionList(library)) return; if (!functionList(library)) return;
CRYPTOKI_LOG("now initialize "<<library); CRYPTOLOG("now initialize "<<library);
assert(_fn); assert(_fn);
//! calls @c C_Initialize //! calls @c C_Initialize
check(_fn->C_Initialize(0), //! @todo add optional argument check(_fn->C_Initialize(0), //! @todo add optional argument
@@ -182,7 +186,7 @@ namespace cryptoki {
} }
Library::Init::~Init() { Library::Init::~Init() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
try { try {
//! calls @c C_Finalize //! calls @c C_Finalize
check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize"));
@@ -200,12 +204,10 @@ namespace cryptoki {
} }
Library::Init::operator bool() { Library::Init::operator bool() {
CRYPTOKI_LOG("log "<<(_res==CKR_OK?"success":"failed"));
return _res==CKR_OK; return _res==CKR_OK;
} }
std::string Library::Init::error() { std::string Library::Init::error() {
CRYPTOKI_LOG("log");
return error(_res); return error(_res);
} }
@@ -219,7 +221,7 @@ namespace cryptoki {
@endcode */ @endcode */
SlotList Library::slotList(bool tokenPresent, std::string name) { SlotList Library::slotList(bool tokenPresent, std::string name) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
SlotList res; SlotList res;
CK_ULONG count(0); CK_ULONG count(0);
//! calls @c C_GetSlotList //! calls @c C_GetSlotList
@@ -252,7 +254,7 @@ namespace cryptoki {
//============================================================================ //============================================================================
ObjectList Session::find(const AttributeList& attrs) { ObjectList Session::find(const AttributeList& attrs) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
ObjectList res; ObjectList res;
CK_ATTRIBUTE* a(0); CK_ATTRIBUTE* a(0);
try { try {
@@ -262,19 +264,19 @@ namespace cryptoki {
a[i] = attrs[i]; a[i] = attrs[i];
} }
//! calls @c C_FindObjectsInit //! calls @c C_FindObjectsInit
if (check(_slot->_library->C_FindObjectsInit if (check(_slot._library->C_FindObjectsInit
(_session, a, attrs.size()), (_session, a, attrs.size()),
CRYPTOKI_FN_LOG("C_FindObjectsInit"))) { CRYPTOKI_FN_LOG("C_FindObjectsInit"))) {
CK_OBJECT_HANDLE obj; CK_OBJECT_HANDLE obj;
//! calls @c C_FindObjects //! calls @c C_FindObjects
for (CK_ULONG objs(0); for (CK_ULONG objs(0);
check(_slot->_library->C_FindObjects check(_slot._library->C_FindObjects
(_session, &obj, 1, &objs), (_session, &obj, 1, &objs),
CRYPTOKI_FN_LOG("C_FindObjects")) && objs; CRYPTOKI_FN_LOG("C_FindObjects")) && objs;
res.push_back(Object(*this, obj))); res.push_back(Object(*this, obj)));
} }
//! calls @c C_FindObjectsFinal //! calls @c C_FindObjectsFinal
check(_slot->_library->C_FindObjectsFinal(_session), check(_slot._library->C_FindObjectsFinal(_session),
CRYPTOKI_FN_LOG("C_FindObjectsFinal")); CRYPTOKI_FN_LOG("C_FindObjectsFinal"));
delete[] a; delete[] a;
return res; return res;
@@ -286,7 +288,7 @@ namespace cryptoki {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
ObjectList Session::find(const Attribute& a) { ObjectList Session::find(const Attribute& a) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
AttributeList al; AttributeList al;
al.push_back(a); al.push_back(a);
return find(al); return find(al);
@@ -294,7 +296,7 @@ namespace cryptoki {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
ObjectList Session::find(const Attribute& a1, const Attribute& a2) { ObjectList Session::find(const Attribute& a1, const Attribute& a2) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
AttributeList al; AttributeList al;
al.push_back(a1); al.push_back(a1);
al.push_back(a2); al.push_back(a2);
@@ -303,7 +305,7 @@ namespace cryptoki {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Object Session::create(const std::string& label, const openssl::X509& cert) { Object Session::create(const std::string& label, const openssl::X509& cert) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
AttributeList attrs; AttributeList attrs;
attrs.push_back(Attribute(CKA_CLASS) attrs.push_back(Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)); .from<CK_OBJECT_CLASS>(CKO_CERTIFICATE));
@@ -318,14 +320,14 @@ namespace cryptoki {
attrs.push_back(Attribute(CKA_ISSUER, cert.issuerDER())); attrs.push_back(Attribute(CKA_ISSUER, cert.issuerDER()));
attrs.push_back(Attribute(CKA_SERIAL_NUMBER, cert.serial())); attrs.push_back(Attribute(CKA_SERIAL_NUMBER, cert.serial()));
attrs.push_back(Attribute(CKA_VALUE, cert.valueDER())); attrs.push_back(Attribute(CKA_VALUE, cert.valueDER()));
CRYPTOKI_LOG("create: serial = "<<crypto::hex(cert.serial())); CRYPTOLOG("create: serial = "<<crypto::hex(cert.serial()));
return create(attrs); return create(attrs);
} }
Object Session::create(const std::string& label, Object Session::create(const std::string& label,
const openssl::PrivateKey& key, const openssl::PrivateKey& key,
const openssl::X509& cert) { const openssl::X509& cert) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
int usage(cert.keyUsageFlags()); int usage(cert.keyUsageFlags());
AttributeList attrs; AttributeList attrs;
attrs.push_back(Attribute(CKA_CLASS) attrs.push_back(Attribute(CKA_CLASS)
@@ -366,7 +368,7 @@ namespace cryptoki {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
Object Session::create(const AttributeList& attrs) { Object Session::create(const AttributeList& attrs) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CK_ATTRIBUTE* a(0); CK_ATTRIBUTE* a(0);
try { try {
if (attrs.size()) { if (attrs.size()) {
@@ -377,11 +379,11 @@ namespace cryptoki {
for (AttributeList::size_type i(0); i<attrs.size(); ++i) { for (AttributeList::size_type i(0); i<attrs.size(); ++i) {
std::string value((char*)a[i].pValue, a[i].ulValueLen); std::string value((char*)a[i].pValue, a[i].ulValueLen);
Attribute xxx(a[i].type, value); Attribute xxx(a[i].type, value);
CRYPTOKI_LOG("Attribute: "<<xxx.name()<<" = "<<xxx.readableValue()); CRYPTOLOG("Attribute: "<<xxx.name()<<" = "<<xxx.readableValue());
}; };
CK_OBJECT_HANDLE object; CK_OBJECT_HANDLE object;
//! calls @c C_CreateObject //! calls @c C_CreateObject
check(_slot->_library->C_CreateObject check(_slot._library->C_CreateObject
(_session, a, attrs.size(), &object), (_session, a, attrs.size(), &object),
CRYPTOKI_FN_LOG("C_CreateObject")); CRYPTOKI_FN_LOG("C_CreateObject"));
delete[] a; delete[] a;

View File

@@ -36,10 +36,6 @@
/*! @defgroup cryptokitypes Cryptoki C++ Types and Auxiliary */ /*! @defgroup cryptokitypes Cryptoki C++ Types and Auxiliary */
/*! @defgroup cryptokiexceptions Cryptoki Exceptions */ /*! @defgroup cryptokiexceptions Cryptoki Exceptions */
#ifndef CRYPTOKI_LOG
#define CRYPTOKI_LOG(X)
#endif
#ifndef CRYPTOKI_FN_LOG #ifndef CRYPTOKI_FN_LOG
#include <iostream> #include <iostream>
#if __GNUC__ >= 2 #if __GNUC__ >= 2
@@ -51,7 +47,8 @@
#define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \ #define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \
+std::string(__PRETTY_FUNCTION__)) +std::string(__PRETTY_FUNCTION__))
#else #else
#define CRYPTOKI_QUOTE(X) #X #define CRYPTOKI_QUOTE(X) CRYPTOKI_QUOTE2(X)
#define CRYPTOKI_QUOTE2(X) #X
//! Cryptoki Error Message Formatting //! Cryptoki Error Message Formatting
/*! If you want to change cryptoki error formatting, just /*! If you want to change cryptoki error formatting, just
redefine your own CRYPTOKY_FN_LOG macro before <code>#include redefine your own CRYPTOKY_FN_LOG macro before <code>#include
@@ -61,24 +58,6 @@
" __FILE__ ":" CRYPTOKI_QUOTE(__LINE__) " __FILE__ ":" CRYPTOKI_QUOTE(__LINE__)
#endif #endif
#endif #endif
#ifndef CRYPTOKI_LOG
#include <iostream>
#if __GNUC__ >= 2
//! Cryptoki Logging
/*! If you want to change cryptoki logging mechanism, just
redefine your own CRYPTOKI_LOG macro before <code>#include
&lt;cryptoki.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define CRYPTOKI_LOG(X) std::clog<<X<<" @ "<<__PRETTY_FUNCTION__<<std::endl
#else
//! Cryptoki Logging
/*! If you want to change cryptoki logging mechanism, just
redefine your own CRYPTOKI_LOG macro before <code>#include
&lt;cryptoki.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define CRYPTOKI_LOG(X) std::clog<<X<<" @ "<<__FILE__<<__LINE__<<std::endl
#endif
#endif
namespace pcsc { namespace pcsc {
std::string version(); std::string version();
@@ -119,6 +98,7 @@ namespace cryptoki {
public: public:
exception(const std::string& reason) throw(): exception(const std::string& reason) throw():
_what("cryptoki: "+reason) { _what("cryptoki: "+reason) {
CRYPTOLOG("ERROR: "<<what());
} }
~exception() throw() {} ~exception() throw() {}
const char* what() const throw() { const char* what() const throw() {
@@ -131,15 +111,19 @@ namespace cryptoki {
class not_implemented: public exception { class not_implemented: public exception {
public: public:
not_implemented(const std::string& reason) throw(): not_implemented(const std::string& reason) throw():
exception("feature is not implemented:\n"+reason) { exception("feature is not implemented: "+reason) {}
}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class access_error: public exception { class access_error: public exception {
public: public:
access_error(const std::string& reason) throw(): access_error(const std::string& reason) throw():
exception("smardcard access error:\n"+reason) { exception("smardcard access error: "+reason) {}
} };
//----------------------------------------------------------------------------
class wrong_pin: public access_error {
public:
wrong_pin(const std::string& reason) throw():
access_error("wrong pin: "+reason) {}
}; };
//@} //@}
@@ -635,8 +619,9 @@ namespace cryptoki {
@param library name of the shared library that supports pkcs#11 @param library name of the shared library that supports pkcs#11
@param exc wether exceptions should be thrown */ @param exc wether exceptions should be thrown */
Library(const std::string& library="opensc-pkcs11.so", bool exc=true): Library(const std::string& library, bool exc=true):
_init(library, exc) { _init(library, exc) {
CRYPTOLOG("log");
} }
public: public:
@@ -740,7 +725,7 @@ namespace cryptoki {
//@} //@}
Info info() { Info info() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
Info inf; Info inf;
CK_INFO cInf; CK_INFO cInf;
//! calls @c C_GetInfo //! calls @c C_GetInfo
@@ -781,13 +766,19 @@ namespace cryptoki {
CK_SLOT_ID _slot; CK_SLOT_ID _slot;
CK_RV _res; CK_RV _res;
public:
Slot(const Library& lib, CK_SLOT_ID slot): Slot(const Library& lib, CK_SLOT_ID slot):
_library(lib), _slot(slot), _res(CKR_OK) { _library(lib), _slot(slot), _res(CKR_OK) {
CRYPTOKI_LOG("log"); CRYPTOLOG("ID="<<_slot);
}
Slot(const Slot& o):
_library(o._library), _slot(o._slot), _res(o._res) {
CRYPTOLOG("ID="<<_slot);
} }
bool check(CK_RV result, const std::string& context="") { bool check(CK_RV result, const std::string& context="") {
CRYPTOKI_LOG("log");
_res = result; _res = result;
if (_library.exc() && !*this) if (_library.exc() && !*this)
if (!context.empty()) if (!context.empty())
@@ -797,21 +788,6 @@ namespace cryptoki {
return _res==CKR_OK; return _res==CKR_OK;
} }
public:
//! Don't use without assignment! For standard containers only!
Slot() {
CRYPTOKI_LOG("log");
}
Slot& operator=(const Slot& o) {
CRYPTOKI_LOG("log");
_library = o._library;
_slot = o._slot;
_res = o._res;
return *this;
}
/*! @name C Like Error Handling /*! @name C Like Error Handling
You are strongly recommended not to disable exception You are strongly recommended not to disable exception
@@ -822,20 +798,18 @@ namespace cryptoki {
/*! @return @c true if last cryptoki on this object call was successful */ /*! @return @c true if last cryptoki on this object call was successful */
operator bool() { operator bool() {
CRYPTOKI_LOG("log");
return _res==CKR_OK; return _res==CKR_OK;
} }
/*! @return error text of last cryptoki call */ /*! @return error text of last cryptoki call */
std::string error() { std::string error() {
CRYPTOKI_LOG("log");
return _library.error(_res); return _library.error(_res);
} }
//@} //@}
MechanismInfo mechanisminfo(CK_MECHANISM_TYPE mechanism) { MechanismInfo mechanisminfo(CK_MECHANISM_TYPE mechanism) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
MechanismInfo info(mechanism); MechanismInfo info(mechanism);
CK_MECHANISM_INFO cInfo; CK_MECHANISM_INFO cInfo;
//! calls @c C_GetMechanismInfo //! calls @c C_GetMechanismInfo
@@ -848,7 +822,7 @@ namespace cryptoki {
} }
MechanismList mechanismlist() { MechanismList mechanismlist() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
MechanismList res; MechanismList res;
CK_ULONG count(0); CK_ULONG count(0);
//! calls @c C_GetMechanismList //! calls @c C_GetMechanismList
@@ -873,7 +847,7 @@ namespace cryptoki {
} }
SlotInfo slotinfo() { SlotInfo slotinfo() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
SlotInfo info; SlotInfo info;
CK_SLOT_INFO cInfo; CK_SLOT_INFO cInfo;
//! calls @c C_GetSlotInfo //! calls @c C_GetSlotInfo
@@ -888,7 +862,7 @@ namespace cryptoki {
} }
TokenInfo tokeninfo() { TokenInfo tokeninfo() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
TokenInfo info; TokenInfo info;
//! calls @c C_GetTokenInfo //! calls @c C_GetTokenInfo
CK_TOKEN_INFO cInfo; CK_TOKEN_INFO cInfo;
@@ -918,7 +892,7 @@ namespace cryptoki {
/*! @bug does not compile: /*! @bug does not compile:
@code @code
bool inittoken(std::string pin, FixString<32> label) { bool inittoken(std::string pin, FixString<32> label) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_InitToken //! calls @c C_InitToken
return check(_library->C_InitToken return check(_library->C_InitToken
(_slot, (_slot,
@@ -935,7 +909,7 @@ namespace cryptoki {
} }
bool registerforslotevent(SlotEventListener&) { bool registerforslotevent(SlotEventListener&) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_WaitForSlotEvent //! calls @c C_WaitForSlotEvent
return check(_library->C_WaitForSlotEvent(CK_FLAGS, &_slot, CK_VOID_PTR), return check(_library->C_WaitForSlotEvent(CK_FLAGS, &_slot, CK_VOID_PTR),
CRYPTOKI_FN_LOG("C_WaitForSlotEvent")); CRYPTOKI_FN_LOG("C_WaitForSlotEvent"));
@@ -951,16 +925,22 @@ namespace cryptoki {
friend class Login; friend class Login;
friend class Object; friend class Object;
mrw::Shared<Slot> _slot; typedef std::multimap<CK_SLOT_ID, CK_SESSION_HANDLE> Slots;
Slot _slot;
CK_SESSION_HANDLE _session; CK_SESSION_HANDLE _session;
CK_RV _res; CK_RV _res;
static Slots& slots() {
static Slots _slots;
return _slots;
}
Session(); // forbidden Session(); // forbidden
bool check(CK_RV result, const std::string& context="") { bool check(CK_RV result, const std::string& context="") {
CRYPTOKI_LOG("log");
_res = result; _res = result;
if (_slot->_library.exc() && !*this) if (_slot._library.exc() && !*this)
if (!context.empty()) if (!context.empty())
throw access_error(context+": "+error()); throw access_error(context+": "+error());
else else
@@ -968,43 +948,72 @@ namespace cryptoki {
return _res==CKR_OK; return _res==CKR_OK;
} }
void free() { //! calls @c C_OpenSession if it's the first session
CRYPTOKI_LOG("log"); void open(bool rw=false) {
try { CRYPTOLOG("references: "<<slots().count(_slot._slot));
//! closes login. if (slots().count(_slot._slot)==0) {
logout(); check(_slot._library->C_OpenSession
} catch (...) { // still try to close session (_slot._slot, CKF_SERIAL_SESSION|(rw?CKF_RW_SESSION:0),
//! calls @c C_CloseSession 0, 0, &_session),
try { CRYPTOKI_FN_LOG("C_OpenSession"));
check(_slot->_library->C_CloseSession(_session), } else {
CRYPTOKI_FN_LOG("C_CloseSession")); _session = slots().find(_slot._slot)->second;
} catch (...) {} // only report first problem
throw;
} }
//! calls @c C_CloseSession slots().insert(std::make_pair(_slot._slot, _session));
check(_slot->_library->C_CloseSession(_session), }
//! calls @c C_CloseSession if it's the last session
void close() {
CRYPTOLOG("references: "<<slots().count(_slot._slot));
if (slots().count(_slot._slot)==1) {
slots().erase(slots().find(_slot._slot));
check(_slot._library->C_CloseSession(_session),
CRYPTOKI_FN_LOG("C_CloseSession")); CRYPTOKI_FN_LOG("C_CloseSession"));
} else {
slots().erase(slots().find(_slot._slot));
}
_session=0;
} }
public: public:
//! Opens a new session. //! Opens a new session.
/*! @param slot slot to open a session on */ /*! @param slot slot to open a session on */
Session(mrw::Shared<Slot> slot, bool rw=false): Session(const Slot& slot, bool rw=false):
_slot(slot), _session(0), _res(CKR_OK) { _slot(slot), _session(0), _res(CKR_OK) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_OpenSession open(rw);
check(_slot->_library->C_OpenSession //! @todo pass parameter
(_slot->_slot, CKF_SERIAL_SESSION|(rw?CKF_RW_SESSION:0), }
0, 0, &_session),
CRYPTOKI_FN_LOG("C_OpenSession")); //! Opens a new session.
/*! @param slot slot to open a session on */
Session(const Session& o):
_slot(o._slot), _session(o._session), _res(CKR_OK) {
CRYPTOLOG("log");
slots().insert(std::make_pair(_slot._slot, _session));
//! @todo pass parameter //! @todo pass parameter
} }
~Session() try { ~Session() try {
CRYPTOKI_LOG("log"); CRYPTOLOG("log "<<(std::uncaught_exception()?"IN EXCEPTION":""));
free(); try {
logout();
} catch (const std::exception& x) {
CRYPTOLOG("caught: "<<x.what());
close();
if (!std::uncaught_exception()) throw;
} catch (...) { } catch (...) {
CRYPTOLOG("caught");
close();
if (!std::uncaught_exception()) throw;
}
close();
} catch (const std::exception& x) {
CRYPTOLOG("caught: "<<x.what());
if (!std::uncaught_exception()) throw;
} catch (...) {
CRYPTOLOG("caught");
if (!std::uncaught_exception()) throw; if (!std::uncaught_exception()) throw;
} }
@@ -1040,14 +1049,12 @@ namespace cryptoki {
/*! @return @c true if last cryptoki on this object call was successful */ /*! @return @c true if last cryptoki on this object call was successful */
operator bool() { operator bool() {
CRYPTOKI_LOG("log");
return _res==CKR_OK; return _res==CKR_OK;
} }
/*! @return error text of last cryptoki call */ /*! @return error text of last cryptoki call */
std::string error() { std::string error() {
CRYPTOKI_LOG("log"); return _slot._library.error(_res);
return _slot->_library.error(_res);
} }
//@} //@}
@@ -1059,9 +1066,9 @@ namespace cryptoki {
//@{ //@{
bool cancel() { bool cancel() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_CancelFunction //! calls @c C_CancelFunction
return check(_slot->_library->C_CancelFunction(_session), return check(_slot._library->C_CancelFunction(_session),
CRYPTOKI_FN_LOG("C_CancelFunction")); CRYPTOKI_FN_LOG("C_CancelFunction"));
} }
@@ -1069,12 +1076,12 @@ namespace cryptoki {
Object create(const AttributeList& attrs); Object create(const AttributeList& attrs);
std::string digest(std::string in) { std::string digest(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_Digest //! calls @c C_Digest
check(_slot->_library->C_Digest check(_slot._library->C_Digest
(_session, (_session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
@@ -1084,12 +1091,12 @@ namespace cryptoki {
} }
std::string digestencryptupdate(std::string in) { std::string digestencryptupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_DigestEncryptUpdate //! calls @c C_DigestEncryptUpdate
check(_slot->_library->C_DigestEncryptUpdate check(_slot._library->C_DigestEncryptUpdate
(_session, (_session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
@@ -1101,9 +1108,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool digestfinal() { bool digestfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DigestFinal //! calls @c C_DigestFinal
return check(_slot->_library->C_DigestFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), return check(_slot._library->C_DigestFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_DigestFinal")); CRYPTOKI_FN_LOG("C_DigestFinal"));
} }
@endcode */ @endcode */
@@ -1111,9 +1118,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool digestinit() { bool digestinit() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DigestInit //! calls @c C_DigestInit
return check(_slot->_library->C_DigestInit(_session, CK_MECHANISM_PTR), return check(_slot._library->C_DigestInit(_session, CK_MECHANISM_PTR),
CRYPTOKI_FN_LOG("C_DigestInit")); CRYPTOKI_FN_LOG("C_DigestInit"));
} }
@endcode */ @endcode */
@@ -1121,9 +1128,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool digestupdate() { bool digestupdate() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DigestUpdate //! calls @c C_DigestUpdate
return check(_slot->_library->C_DigestUpdate(_session, CK_BYTE_PTR, CK_ULONG), return check(_slot._library->C_DigestUpdate(_session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_DigestUpdate")); CRYPTOKI_FN_LOG("C_DigestUpdate"));
} }
@endcode */ @endcode */
@@ -1131,9 +1138,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool findobjectsfinal() { bool findobjectsfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_FindObjectsFinal //! calls @c C_FindObjectsFinal
return check(_slot->_library->C_FindObjectsFinal(_session), return check(_slot._library->C_FindObjectsFinal(_session),
CRYPTOKI_FN_LOG("C_FindObjectsFinal")); CRYPTOKI_FN_LOG("C_FindObjectsFinal"));
} }
@endcode */ @endcode */
@@ -1141,9 +1148,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool findobjectsinit() { bool findobjectsinit() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_FindObjectsInit //! calls @c C_FindObjectsInit
return check(_slot->_library->C_FindObjectsInit(_session, CK_ATTRIBUTE_PTR, CK_ULONG), return check(_slot._library->C_FindObjectsInit(_session, CK_ATTRIBUTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_FindObjectsInit")); CRYPTOKI_FN_LOG("C_FindObjectsInit"));
} }
@endcode */ @endcode */
@@ -1151,9 +1158,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool findobjects() { bool findobjects() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_FindObjects //! calls @c C_FindObjects
return check(_session->_slot->_library->C_FindObjects(_session, CK_OBJECT_HANDLE_PTR, CK_ULONG, return check(_session->_slot._library->C_FindObjects(_session, CK_OBJECT_HANDLE_PTR, CK_ULONG,
CK_ULONG_PTR), CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_FindObjects")); CRYPTOKI_FN_LOG("C_FindObjects"));
} }
@@ -1162,9 +1169,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool generaterandom() { bool generaterandom() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GenerateRandom //! calls @c C_GenerateRandom
return check(_slot->_library->C_GenerateRandom(_session, CK_BYTE_PTR, CK_ULONG), return check(_slot._library->C_GenerateRandom(_session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_GenerateRandom")); CRYPTOKI_FN_LOG("C_GenerateRandom"));
} }
@endcode */ @endcode */
@@ -1172,9 +1179,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool getfunctionstatus() { bool getfunctionstatus() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GetFunctionStatus //! calls @c C_GetFunctionStatus
return check(_slot->_library->C_GetFunctionStatus(_session), return check(_slot._library->C_GetFunctionStatus(_session),
CRYPTOKI_FN_LOG("C_GetFunctionStatus")); CRYPTOKI_FN_LOG("C_GetFunctionStatus"));
} }
@endcode */ @endcode */
@@ -1182,44 +1189,87 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool getoperationstate() { bool getoperationstate() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GetOperationState //! calls @c C_GetOperationState
return check(_slot->_library->C_GetOperationState(_session, CK_BYTE_PTR, CK_ULONG_PTR), return check(_slot._library->C_GetOperationState(_session, CK_BYTE_PTR, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_GetOperationState")); CRYPTOKI_FN_LOG("C_GetOperationState"));
} }
@endcode */ @endcode */
/*! @todo Not implemented: /** definition of session info:
@code @code
bool getsessioninfo() { struct CK_SESSION_INFO {
CRYPTOKI_LOG("log"); CK_SLOT_ID slotID;
CK_STATE state;
CK_FLAGS flags;
CK_ULONG ulDeviceError;
};
@endcode
where:
- @c slotID ID of the slot that interfaces with the token
- @c state The state of the session
- @c 0 @c CKS_RO_PUBLIC_SESSION
- @c 1 @c CKS_RO_USER_FUNCTIONS
- @c 2 @c CKS_RW_PUBLIC_SESSION
- @c 3 @c CKS_RW_USER_FUNCTIONS
- @c 4 @c CKS_RW_SO_FUNCTIONS
- @c flags Bit flags that define the type of session; the
flags are defined as:
- @c CKF_RW_SESSION
- True if the session is read/write.
- False if the session is read only.
- @c CKF_SERIAL_SESSION Deprecated, always true.
- @c ulDeviceError An error code defined by the
cryptographic device. Used for errors not covered by
Cryptoki. */
typedef CK_SESSION_INFO Info;
/** @return session information */
Info getsessioninfo() {
CRYPTOLOG("log");
CK_SESSION_INFO info;
//! calls @c C_GetSessionInfo //! calls @c C_GetSessionInfo
return check(_slot->_library->C_GetSessionInfo(_session, CK_SESSION_INFO_PTR), check(_slot._library->C_GetSessionInfo(_session, &info),
CRYPTOKI_FN_LOG("C_GetSessionInfo")); CRYPTOKI_FN_LOG("C_GetSessionInfo"));
return info;
}
std::string state(const Info& info) {
switch (info.state) {
case 0: return "CKS_RO_PUBLIC_SESSION";
case 1: return "CKS_RO_USER_FUNCTIONS";
case 2: return "CKS_RW_PUBLIC_SESSION ";
case 3: return "CKS_RW_USER_FUNCTIONS";
case 4: return "CKS_RW_SO_FUNCTIONS";
default: return "<UNKNOWN>";
}
} }
@endcode */
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool initpin() { bool initpin() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_InitPIN //! calls @c C_InitPIN
return check(_slot->_library->C_InitPIN(_session, CK_CHAR_PTR, CK_ULONG), return check(_slot._library->C_InitPIN(_session, CK_CHAR_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_InitPIN")); CRYPTOKI_FN_LOG("C_InitPIN"));
} }
@endcode */ @endcode */
private:
class Login { class Login {
public: public:
Login(mrw::Shared<Session> session, Login(Session& session,
const std::string& pin, const std::string& pin,
CK_USER_TYPE userType=CKU_USER): _session(session) { CK_USER_TYPE userType=CKU_USER): _session(session) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_Login //! calls @c C_Login
_session->check(_session->_slot->_library->C_Login _session.check(_session._slot._library->C_Login
(_session->_session, userType, (_session._session, userType,
(CK_CHAR*)pin.c_str(), (CK_CHAR*)pin.c_str(),
pin.size()), pin.size()),
CRYPTOKI_FN_LOG("C_Login")); CRYPTOKI_FN_LOG("C_Login"));
@@ -1228,33 +1278,34 @@ namespace cryptoki {
~Login() { ~Login() {
try { try {
//! calls @c C_Logout //! calls @c C_Logout
_session->check(_session->_slot->_library->C_Logout _session.check(_session._slot._library->C_Logout
(_session->_session), (_session._session),
CRYPTOKI_FN_LOG("C_Logout")); CRYPTOKI_FN_LOG("C_Logout"));
} catch (const std::exception& x) {
if (!std::uncaught_exception()) throw;
CRYPTOLOG("ERROR during error cleanup: "<<x.what());
} catch (...) { } catch (...) {
if (!std::uncaught_exception()) throw; if (!std::uncaught_exception()) throw;
CRYPTOLOG("ERROR during error cleanup.");
} }
} }
private: private:
mrw::Shared<Session> _session; Session& _session;
}; };
public:
void login(const std::string& pin, CK_USER_TYPE userType=CKU_USER) { void login(const std::string& pin, CK_USER_TYPE userType=CKU_USER) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
_login = new Login(*this, pin, userType); _login = new Login(*this, pin, userType);
} }
void logout() { void logout() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
try {
_login.reset(); _login.reset();
} catch (...) {
_login.reset();
throw;
}
} }
mrw::Shared<Login> _login; mrw::Shared<Login> _login;
@@ -1262,9 +1313,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool seedrandom() { bool seedrandom() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SeedRandom //! calls @c C_SeedRandom
return check(_slot->_library->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG), return check(_slot._library->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_SeedRandom")); CRYPTOKI_FN_LOG("C_SeedRandom"));
} }
@endcode */ @endcode */
@@ -1272,9 +1323,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool setpin() { bool setpin() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SetPIN //! calls @c C_SetPIN
return check(_slot->_library->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG), return check(_slot._library->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_SetPIN")); CRYPTOKI_FN_LOG("C_SetPIN"));
} }
@endcode */ @endcode */
@@ -1287,13 +1338,12 @@ namespace cryptoki {
friend class Session; friend class Session;
CK_OBJECT_HANDLE _object; CK_OBJECT_HANDLE _object;
mrw::Shared<Session> _session; Session _session;
CK_RV _res; CK_RV _res;
bool check(CK_RV result, const std::string& context="") { bool check(CK_RV result, const std::string& context="") {
CRYPTOKI_LOG("log");
_res = result; _res = result;
if (_session->_slot->_library.exc() && !*this) if (_session._slot._library.exc() && !*this)
if (!context.empty()) if (!context.empty())
throw access_error(context+": "+error()); throw access_error(context+": "+error());
else else
@@ -1303,9 +1353,9 @@ namespace cryptoki {
Object(); // forbidden Object(); // forbidden
Object(mrw::Shared<Session> session, CK_OBJECT_HANDLE obj): Object(const Session& session, CK_OBJECT_HANDLE obj):
_object(obj), _session(session), _res(CKR_OK) { _object(obj), _session(session), _res(CKR_OK) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
} }
public: public:
@@ -1318,30 +1368,30 @@ namespace cryptoki {
std::string encrypt(const std::string& data, CK_MECHANISM_TYPE type, std::string encrypt(const std::string& data, CK_MECHANISM_TYPE type,
const std::string& param=std::string()) { const std::string& param=std::string()) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CRYPTOKI_LOG("encryptinit"); CRYPTOLOG("encryptinit");
encryptinit(type, param); encryptinit(type, param);
CRYPTOKI_LOG("encrypt"); CRYPTOLOG("encrypt");
return encrypt(data); return encrypt(data);
//! @todo don't call encryptfinal()? //! @todo don't call encryptfinal()?
} }
std::string decrypt(const std::string& data, CK_MECHANISM_TYPE type, std::string decrypt(const std::string& data, CK_MECHANISM_TYPE type,
const std::string& param=std::string()) { const std::string& param=std::string()) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CRYPTOKI_LOG("decryptinit"); CRYPTOLOG("decryptinit");
decryptinit(type, param); decryptinit(type, param);
CRYPTOKI_LOG("decrypt"); CRYPTOLOG("decrypt");
return decrypt(data); return decrypt(data);
//! @todo don't call decryptfinal()? //! @todo don't call decryptfinal()?
} }
std::string sign(const std::string& data, CK_MECHANISM_TYPE type, std::string sign(const std::string& data, CK_MECHANISM_TYPE type,
const std::string& param=std::string()) { const std::string& param=std::string()) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CRYPTOKI_LOG("signinit"); CRYPTOLOG("signinit");
signinit(type, param); signinit(type, param);
CRYPTOKI_LOG("sign"); CRYPTOLOG("sign");
return sign(data); return sign(data);
//! @todo don't call signfinal()? //! @todo don't call signfinal()?
} }
@@ -1349,10 +1399,10 @@ namespace cryptoki {
bool verify(const std::string& data, const std::string& signature, bool verify(const std::string& data, const std::string& signature,
CK_MECHANISM_TYPE type, CK_MECHANISM_TYPE type,
const std::string& param=std::string()) { const std::string& param=std::string()) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CRYPTOKI_LOG("verifyinit"); CRYPTOLOG("verifyinit");
verifyinit(type, param); verifyinit(type, param);
CRYPTOKI_LOG("verify"); CRYPTOLOG("verify");
return verify(data, signature); return verify(data, signature);
//! @todo don't call verifyfinal()? //! @todo don't call verifyfinal()?
} }
@@ -1369,14 +1419,12 @@ namespace cryptoki {
/*! @return @c true if last cryptoki on this object call was successful */ /*! @return @c true if last cryptoki on this object call was successful */
operator bool() { operator bool() {
CRYPTOKI_LOG("log");
return _res==CKR_OK; return _res==CKR_OK;
} }
/*! @return error text of last cryptoki call */ /*! @return error text of last cryptoki call */
std::string error() { std::string error() {
CRYPTOKI_LOG("log"); return _session._slot._library.error(_res);
return _session->_slot->_library.error(_res);
} }
//@} //@}
@@ -1390,58 +1438,58 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool copyobject() { bool copyobject() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_CopyObject //! calls @c C_CopyObject
return check(_session->_slot->_library->C_CopyObject(_session->_session, CK_OBJECT_HANDLE, return check(_session._slot._library->C_CopyObject(_session._session, CK_OBJECT_HANDLE,
CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR),
CRYPTOKI_FN_LOG("C_CopyObject")); CRYPTOKI_FN_LOG("C_CopyObject"));
} }
@endcode */ @endcode */
bool decryptinit(CK_MECHANISM_TYPE type, std::string param) { bool decryptinit(CK_MECHANISM_TYPE type, std::string param) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CK_MECHANISM mech = { CK_MECHANISM mech = {
type, param.size()?&param[0]:0, param.size() type, param.size()?&param[0]:0, param.size()
}; };
CRYPTOKI_LOG("decryptinit: type="<<type<<"; mech=("<<mech.mechanism CRYPTOLOG("decryptinit: type="<<type<<"; mech=("<<mech.mechanism
<<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')'); <<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')');
//! calls @c C_DecryptInit //! calls @c C_DecryptInit
return check(_session->_slot->_library->C_DecryptInit return check(_session._slot._library->C_DecryptInit
(_session->_session, &mech, _object), (_session._session, &mech, _object),
CRYPTOKI_FN_LOG("C_DecryptInit")); CRYPTOKI_FN_LOG("C_DecryptInit"));
} }
//! requires decryptinit to be called before //! requires decryptinit to be called before
std::string decrypt(const std::string& in) { std::string decrypt(const std::string& in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
CK_ULONG size(0); // two calls, first to get minimum buffer length CK_ULONG size(0); // two calls, first to get minimum buffer length
CRYPTOKI_LOG("get size"); CRYPTOLOG("get size");
//! calls @c C_Decrypt //! calls @c C_Decrypt
check(_session->_slot->_library->C_Decrypt check(_session._slot._library->C_Decrypt
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), 0, &size), (unsigned char*)&in[0], in.size(), 0, &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOKI_LOG("maximum size is "<<size<<"Bytes"); CRYPTOLOG("maximum size is "<<size<<"Bytes");
res.resize(size, 0); res.resize(size, 0);
check(_session->_slot->_library->C_Decrypt check(_session._slot._library->C_Decrypt
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOKI_LOG("exact size is "<<size<<"Bytes"); CRYPTOLOG("exact size is "<<size<<"Bytes");
res.resize(size); res.resize(size);
return res; return res;
} }
std::string decryptdigestupdate(std::string in) { std::string decryptdigestupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_DecryptDigestUpdate //! calls @c C_DecryptDigestUpdate
check(_session->_slot->_library->C_DecryptDigestUpdate check(_session._slot._library->C_DecryptDigestUpdate
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_DecryptDigestUpdate")); CRYPTOKI_FN_LOG("C_DecryptDigestUpdate"));
@@ -1450,22 +1498,22 @@ namespace cryptoki {
} }
bool decryptfinal() { bool decryptfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DecryptFinal //! calls @c C_DecryptFinal
return check(_session->_slot->_library->C_DecryptFinal return check(_session._slot._library->C_DecryptFinal
(_session->_session, 0, 0), (_session._session, 0, 0),
CRYPTOKI_FN_LOG("C_DecryptFinal")); CRYPTOKI_FN_LOG("C_DecryptFinal"));
//! @todo does this work? //! @todo does this work?
} }
std::string decryptupdate(std::string in) { std::string decryptupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_DecryptUpdate //! calls @c C_DecryptUpdate
check(_session->_slot->_library->C_DecryptUpdate check(_session._slot._library->C_DecryptUpdate
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_DecryptUpdate")); CRYPTOKI_FN_LOG("C_DecryptUpdate"));
@@ -1474,13 +1522,13 @@ namespace cryptoki {
} }
std::string decryptverifyupdate(std::string in) { std::string decryptverifyupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_DecryptVerifyUpdate //! calls @c C_DecryptVerifyUpdate
check(_session->_slot->_library->C_DecryptVerifyUpdate check(_session._slot._library->C_DecryptVerifyUpdate
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_DecryptVerifyUpdate")); CRYPTOKI_FN_LOG("C_DecryptVerifyUpdate"));
@@ -1490,34 +1538,34 @@ namespace cryptoki {
std::string sign(std::string in) { std::string sign(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
CK_ULONG size(0); CK_ULONG size(0);
check(_session->_slot->_library->C_Sign check(_session._slot._library->C_Sign
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(),0, &size), (unsigned char*)&in[0], in.size(),0, &size),
CRYPTOKI_FN_LOG("C_Sign")); CRYPTOKI_FN_LOG("C_Sign"));
CRYPTOKI_LOG("maximum size is "<<size<<"Bytes"); CRYPTOLOG("maximum size is "<<size<<"Bytes");
res.resize(size, 0); res.resize(size, 0);
//! calls @c C_Sign //! calls @c C_Sign
check(_session->_slot->_library->C_Sign check(_session._slot._library->C_Sign
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_Sign")); CRYPTOKI_FN_LOG("C_Sign"));
CRYPTOKI_LOG("exact size is "<<size<<"Bytes"); CRYPTOLOG("exact size is "<<size<<"Bytes");
res.resize(size); res.resize(size);
return res; return res;
} }
std::string signencryptupdate(std::string in) { std::string signencryptupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_SignEncryptUpdate //! calls @c C_SignEncryptUpdate
check(_session->_slot->_library->C_SignEncryptUpdate check(_session._slot._library->C_SignEncryptUpdate
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_SignEncryptUpdate")); CRYPTOKI_FN_LOG("C_SignEncryptUpdate"));
@@ -1528,21 +1576,21 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool signfinal() { bool signfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SignFinal //! calls @c C_SignFinal
return check(_slot->_library->C_SignFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), return check(_slot._library->C_SignFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_SignFinal")); CRYPTOKI_FN_LOG("C_SignFinal"));
} }
@endcode */ @endcode */
std::string signrecover(std::string in) { std::string signrecover(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_SignRecover //! calls @c C_SignRecover
check(_session->_slot->_library->C_SignRecover check(_session._slot._library->C_SignRecover
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_SignRecover")); CRYPTOKI_FN_LOG("C_SignRecover"));
@@ -1553,18 +1601,18 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool signupdate() { bool signupdate() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SignUpdate //! calls @c C_SignUpdate
return check(_session->_slot->_library->C_SignUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), return check(_session._slot._library->C_SignUpdate(_session._session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_SignUpdate")); CRYPTOKI_FN_LOG("C_SignUpdate"));
} }
@endcode */ @endcode */
bool verify(std::string data, std::string signature) { bool verify(std::string data, std::string signature) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_Verify //! calls @c C_Verify
return check(_session->_slot->_library->C_Verify return check(_session._slot._library->C_Verify
(_session->_session, (_session._session,
(unsigned char*)&data[0], data.size(), (unsigned char*)&data[0], data.size(),
(unsigned char*)&signature[0], signature.size()), (unsigned char*)&signature[0], signature.size()),
CRYPTOKI_FN_LOG("C_Verify")); CRYPTOKI_FN_LOG("C_Verify"));
@@ -1573,21 +1621,21 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool verifyfinal() { bool verifyfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_VerifyFinal //! calls @c C_VerifyFinal
return check(_session->_slot->_library->C_VerifyFinal(_session->_session, CK_BYTE_PTR, CK_ULONG), return check(_session._slot._library->C_VerifyFinal(_session._session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_VerifyFinal")); CRYPTOKI_FN_LOG("C_VerifyFinal"));
} }
@endcode */ @endcode */
std::string verifyrecover(std::string in) { std::string verifyrecover(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_VerifyRecover //! calls @c C_VerifyRecover
check(_session->_slot->_library->C_VerifyRecover check(_session._slot._library->C_VerifyRecover
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_VerifyRecover")); CRYPTOKI_FN_LOG("C_VerifyRecover"));
@@ -1598,9 +1646,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool verifyupdate() { bool verifyupdate() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_VerifyUpdate //! calls @c C_VerifyUpdate
return check(_session->_slot->_library->C_VerifyUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), return check(_session._slot._library->C_VerifyUpdate(_session._session, CK_BYTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_VerifyUpdate")); CRYPTOKI_FN_LOG("C_VerifyUpdate"));
} }
@endcode */ @endcode */
@@ -1609,19 +1657,19 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool derivekey() { bool derivekey() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DeriveKey //! calls @c C_DeriveKey
return check(_session->_slot->_library->C_DeriveKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, return check(_session._slot._library->C_DeriveKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR),
CRYPTOKI_FN_LOG("C_DeriveKey")); CRYPTOKI_FN_LOG("C_DeriveKey"));
} }
@endcode */ @endcode */
bool destroy() { bool destroy() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DestroyObject //! calls @c C_DestroyObject
return check(_session->_slot->_library->C_DestroyObject return check(_session._slot._library->C_DestroyObject
(_session->_session, _object), (_session._session, _object),
CRYPTOKI_FN_LOG("C_DestroyObject")); CRYPTOKI_FN_LOG("C_DestroyObject"));
} }
@@ -1629,40 +1677,40 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool digestkey() { bool digestkey() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_DigestKey //! calls @c C_DigestKey
return check(_session->_slot->_library->C_DigestKey(_session->_session, CK_OBJECT_HANDLE), return check(_session._slot._library->C_DigestKey(_session._session, CK_OBJECT_HANDLE),
CRYPTOKI_FN_LOG("C_DigestKey")); CRYPTOKI_FN_LOG("C_DigestKey"));
} }
@endcode */ @endcode */
bool encryptinit(CK_MECHANISM_TYPE type, const std::string& param) { bool encryptinit(CK_MECHANISM_TYPE type, const std::string& param) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CK_MECHANISM mech = { CK_MECHANISM mech = {
type, param.size()?(void*)&param[0]:0, param.size() type, param.size()?(void*)&param[0]:0, param.size()
}; };
CRYPTOKI_LOG("encryptinit: type="<<type<<"; mech=("<<mech.mechanism CRYPTOLOG("encryptinit: type="<<type<<"; mech=("<<mech.mechanism
<<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')'); <<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')');
//! calls @c C_EncryptInit //! calls @c C_EncryptInit
return check(_session->_slot->_library->C_EncryptInit return check(_session._slot._library->C_EncryptInit
(_session->_session, &mech, _object), (_session._session, &mech, _object),
CRYPTOKI_FN_LOG("C_EncryptInit")); CRYPTOKI_FN_LOG("C_EncryptInit"));
} }
std::string encrypt(const std::string& in) { std::string encrypt(const std::string& in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
CK_ULONG size(0); // two calls, first to get minimum buffer length CK_ULONG size(0); // two calls, first to get minimum buffer length
CRYPTOKI_LOG("get size"); CRYPTOLOG("get size");
//! calls @c C_Encrypt //! calls @c C_Encrypt
check(_session->_slot->_library->C_Encrypt check(_session._slot._library->C_Encrypt
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), 0, &size), (unsigned char*)&in[0], in.size(), 0, &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOKI_LOG("maximum size is "<<size<<"Bytes"); CRYPTOLOG("maximum size is "<<size<<"Bytes");
res.resize(size, 0); res.resize(size, 0);
check(_session->_slot->_library->C_Encrypt check(_session._slot._library->C_Encrypt
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_Encrypt")); CRYPTOKI_FN_LOG("C_Encrypt"));
@@ -1673,21 +1721,21 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool encryptfinal() { bool encryptfinal() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_EncryptFinal //! calls @c C_EncryptFinal
return check(_session->_slot->_library->C_EncryptFinal(_session->_session, CK_BYTE_PTR, CK_ULONG_PTR), return check(_session._slot._library->C_EncryptFinal(_session._session, CK_BYTE_PTR, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_EncryptFinal")); CRYPTOKI_FN_LOG("C_EncryptFinal"));
} }
@endcode */ @endcode */
std::string encryptupdate(std::string in) { std::string encryptupdate(std::string in) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
res.resize(in.size()); res.resize(in.size());
CK_ULONG size(res.size()); //! @todo check if size is ok CK_ULONG size(res.size()); //! @todo check if size is ok
//! calls @c C_EncryptUpdate //! calls @c C_EncryptUpdate
check(_session->_slot->_library->C_EncryptUpdate check(_session._slot._library->C_EncryptUpdate
(_session->_session, (_session._session,
(unsigned char*)&in[0], in.size(), (unsigned char*)&in[0], in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_EncryptUpdate")); CRYPTOKI_FN_LOG("C_EncryptUpdate"));
@@ -1698,9 +1746,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool generatekey() { bool generatekey() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GenerateKey //! calls @c C_GenerateKey
return check(_session->_slot->_library->C_GenerateKey(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, return check(_session._slot._library->C_GenerateKey(_session._session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR,
CK_ULONG, CK_OBJECT_HANDLE_PTR), CK_ULONG, CK_OBJECT_HANDLE_PTR),
CRYPTOKI_FN_LOG("C_GenerateKey")); CRYPTOKI_FN_LOG("C_GenerateKey"));
} }
@@ -1710,9 +1758,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool generatekeypair() { bool generatekeypair() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GenerateKeyPair //! calls @c C_GenerateKeyPair
return check(_session->_slot->_library->C_GenerateKeyPair(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, return check(_session._slot._library->C_GenerateKeyPair(_session._session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR,
CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG,
CK_OBJECT_HANDLE_PTR, CK_OBJECT_HANDLE_PTR), CK_OBJECT_HANDLE_PTR, CK_OBJECT_HANDLE_PTR),
CRYPTOKI_FN_LOG("C_GenerateKeyPair")); CRYPTOKI_FN_LOG("C_GenerateKeyPair"));
@@ -1722,18 +1770,18 @@ namespace cryptoki {
//! Get a Single Attribute //! Get a Single Attribute
Attribute operator[](CK_ATTRIBUTE_TYPE a) { Attribute operator[](CK_ATTRIBUTE_TYPE a) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
return attribute(a); return attribute(a);
} }
//! Get a Single Attribute //! Get a Single Attribute
Attribute attribute(CK_ATTRIBUTE_TYPE a) { Attribute attribute(CK_ATTRIBUTE_TYPE a) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
Attribute res; Attribute res;
CK_ATTRIBUTE attr((CK_ATTRIBUTE){a, 0, 0}); CK_ATTRIBUTE attr((CK_ATTRIBUTE){a, 0, 0});
//! calls @c C_GetAttributeValue //! calls @c C_GetAttributeValue
if (!check(_session->_slot->_library->C_GetAttributeValue if (!check(_session._slot._library->C_GetAttributeValue
(_session->_session, _object, &attr, 1), (_session._session, _object, &attr, 1),
CRYPTOKI_FN_LOG("C_GetAttributeValue")) CRYPTOKI_FN_LOG("C_GetAttributeValue"))
|| !(long)attr.ulValueLen>0l) || !(long)attr.ulValueLen>0l)
//! Without exception handling, size and type must be checked too. //! Without exception handling, size and type must be checked too.
@@ -1741,8 +1789,8 @@ namespace cryptoki {
try { try {
attr.pValue = malloc(attr.ulValueLen); attr.pValue = malloc(attr.ulValueLen);
attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen);
if (check(_session->_slot->_library->C_GetAttributeValue if (check(_session._slot._library->C_GetAttributeValue
(_session->_session, _object, &attr, 1), (_session._session, _object, &attr, 1),
CRYPTOKI_FN_LOG("C_GetAttributeValue"))) CRYPTOKI_FN_LOG("C_GetAttributeValue")))
/*! @todo There's no @c CKA_WRAP_TEMPLATE in Open /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open
Cryptoki. From the Specs: «In the special case Cryptoki. From the Specs: «In the special case
@@ -1785,7 +1833,7 @@ namespace cryptoki {
is no exception in this case. */ is no exception in this case. */
AttributeMap attributes(AttributeTypeList attrs AttributeMap attributes(AttributeTypeList attrs
= AttributeTypeList()) { = AttributeTypeList()) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
AttributeMap res; AttributeMap res;
//! Gets all attributes, if @c attrs is empty //! Gets all attributes, if @c attrs is empty
if (attrs.empty()) { if (attrs.empty()) {
@@ -1857,8 +1905,8 @@ namespace cryptoki {
attr = (CK_ATTRIBUTE){*it, 0, 0}; attr = (CK_ATTRIBUTE){*it, 0, 0};
try { try {
//! calls @c C_GetAttributeValue //! calls @c C_GetAttributeValue
if (_session->_slot->_library->C_GetAttributeValue if (_session._slot._library->C_GetAttributeValue
(_session->_session, _object, &attr, 1) (_session._session, _object, &attr, 1)
== CKR_ATTRIBUTE_TYPE_INVALID == CKR_ATTRIBUTE_TYPE_INVALID
|| _res == CKR_ATTRIBUTE_SENSITIVE) { || _res == CKR_ATTRIBUTE_SENSITIVE) {
continue; //! Ignores unsupported Attributes. continue; //! Ignores unsupported Attributes.
@@ -1867,8 +1915,8 @@ namespace cryptoki {
if ((long)attr.ulValueLen>0l) { if ((long)attr.ulValueLen>0l) {
attr.pValue = malloc(attr.ulValueLen); attr.pValue = malloc(attr.ulValueLen);
attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen);
if (check(_session->_slot->_library->C_GetAttributeValue if (check(_session._slot._library->C_GetAttributeValue
(_session->_session, _object, &attr, 1), (_session._session, _object, &attr, 1),
CRYPTOKI_FN_LOG("C_GetAttributeValue"))) CRYPTOKI_FN_LOG("C_GetAttributeValue")))
/*! @todo There's no @c CKA_WRAP_TEMPLATE in Open /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open
Cryptoki. From the Specs: «In the special Cryptoki. From the Specs: «In the special
@@ -1927,9 +1975,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool getobjectsize() { bool getobjectsize() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_GetObjectSize //! calls @c C_GetObjectSize
return check(_session->_slot->_library->C_GetObjectSize(_session->_session, CK_OBJECT_HANDLE, CK_ULONG_PTR), return check(_session._slot._library->C_GetObjectSize(_session._session, CK_OBJECT_HANDLE, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_GetObjectSize")); CRYPTOKI_FN_LOG("C_GetObjectSize"));
} }
@endcode */ @endcode */
@@ -1938,9 +1986,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool setattributevalue() { bool setattributevalue() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SetAttributeValue //! calls @c C_SetAttributeValue
return check(_session->_slot->_library->C_SetAttributeValue(_session->_session, CK_OBJECT_HANDLE, return check(_session._slot._library->C_SetAttributeValue(_session._session, CK_OBJECT_HANDLE,
CK_ATTRIBUTE_PTR, CK_ULONG), CK_ATTRIBUTE_PTR, CK_ULONG),
CRYPTOKI_FN_LOG("C_SetAttributeValue")); CRYPTOKI_FN_LOG("C_SetAttributeValue"));
} }
@@ -1949,33 +1997,33 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool setoperationstate() { bool setoperationstate() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SetOperationState //! calls @c C_SetOperationState
return check(_session->_slot->_library->C_SetOperationState(_session->_session, CK_BYTE_PTR, CK_ULONG, return check(_session._slot._library->C_SetOperationState(_session._session, CK_BYTE_PTR, CK_ULONG,
CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), CK_OBJECT_HANDLE, CK_OBJECT_HANDLE),
CRYPTOKI_FN_LOG("C_SetOperationState")); CRYPTOKI_FN_LOG("C_SetOperationState"));
} }
@endcode */ @endcode */
bool signinit(CK_MECHANISM_TYPE type, std::string param) { bool signinit(CK_MECHANISM_TYPE type, std::string param) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CK_MECHANISM mech = { CK_MECHANISM mech = {
type, param.size()?&param[0]:0, param.size() type, param.size()?&param[0]:0, param.size()
}; };
CRYPTOKI_LOG("signinit: type="<<type<<"; mech=("<<mech.mechanism CRYPTOLOG("signinit: type="<<type<<"; mech=("<<mech.mechanism
<<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')'); <<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')');
//! calls @c C_SignInit //! calls @c C_SignInit
return check(_session->_slot->_library->C_SignInit return check(_session._slot._library->C_SignInit
(_session->_session, &mech, _object), (_session._session, &mech, _object),
CRYPTOKI_FN_LOG("C_SignInit")); CRYPTOKI_FN_LOG("C_SignInit"));
} }
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool signrecoverinit() { bool signrecoverinit() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_SignRecoverInit //! calls @c C_SignRecoverInit
return check(_session->_slot->_library->C_SignRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), return check(_session._slot._library->C_SignRecoverInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE),
CRYPTOKI_FN_LOG("C_SignRecoverInit")); CRYPTOKI_FN_LOG("C_SignRecoverInit"));
} }
@endcode */ @endcode */
@@ -1983,9 +2031,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool unwrapkey() { bool unwrapkey() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_UnwrapKey //! calls @c C_UnwrapKey
return check(_session->_slot->_library->C_UnwrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, return check(_session._slot._library->C_UnwrapKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG,
CK_OBJECT_HANDLE_PTR), CK_OBJECT_HANDLE_PTR),
CRYPTOKI_FN_LOG("C_UnwrapKey")); CRYPTOKI_FN_LOG("C_UnwrapKey"));
@@ -1993,24 +2041,24 @@ namespace cryptoki {
@endcode */ @endcode */
bool verifyinit(CK_MECHANISM_TYPE type, std::string param) { bool verifyinit(CK_MECHANISM_TYPE type, std::string param) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
CK_MECHANISM mech = { CK_MECHANISM mech = {
type, param.size()?&param[0]:0, param.size() type, param.size()?&param[0]:0, param.size()
}; };
CRYPTOKI_LOG("verifyinit: type="<<type<<"; mech=("<<mech.mechanism CRYPTOLOG("verifyinit: type="<<type<<"; mech=("<<mech.mechanism
<<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')'); <<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')');
//! calls @c C_VerifyInit //! calls @c C_VerifyInit
return check(_session->_slot->_library->C_VerifyInit return check(_session._slot._library->C_VerifyInit
(_session->_session, &mech, _object), (_session._session, &mech, _object),
CRYPTOKI_FN_LOG("C_VerifyInit")); CRYPTOKI_FN_LOG("C_VerifyInit"));
} }
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool verifyrecoverinit() { bool verifyrecoverinit() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_VerifyRecoverInit //! calls @c C_VerifyRecoverInit
return check(_session->_slot->_library->C_VerifyRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), return check(_session._slot._library->C_VerifyRecoverInit(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE),
CRYPTOKI_FN_LOG("C_VerifyRecoverInit")); CRYPTOKI_FN_LOG("C_VerifyRecoverInit"));
} }
@endcode */ @endcode */
@@ -2019,9 +2067,9 @@ namespace cryptoki {
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
bool wrapkey() { bool wrapkey() {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
//! calls @c C_WrapKey //! calls @c C_WrapKey
return check(_session->_slot->_library->C_WrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, return check(_session._slot._library->C_WrapKey(_session._session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR), CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR),
CRYPTOKI_FN_LOG("C_WrapKey")); CRYPTOKI_FN_LOG("C_WrapKey"));
} }
@@ -2038,13 +2086,13 @@ namespace cryptoki {
//@{ //@{
inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list, inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list,
const cryptoki::Attribute& attr) { const cryptoki::Attribute& attr) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
list.push_back(attr); list.push_back(attr);
return list; return list;
} }
inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list, inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list,
const cryptoki::Attribute& attr) { const cryptoki::Attribute& attr) {
CRYPTOKI_LOG("log"); CRYPTOLOG("log");
cryptoki::AttributeList res(list); cryptoki::AttributeList res(list);
res.push_back(attr); res.push_back(attr);
return res; return res;

View File

@@ -5,8 +5,9 @@
## 1 2 3 4 5 6 7 8 ## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890 ## 45678901234567890123456789012345678901234567890123456789012345678901234567890
#MOC_FILES=moc_certimport.cxx
include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx \ 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
if !MINGW32 if !MINGW32
if MAC if MAC
@@ -29,10 +30,13 @@ EXTRA_DIST = $(pkgconfig_DATA).in ${top_srcdir}/src/*.doc
lib_LTLIBRARIES = libpcscxx.la lib_LTLIBRARIES = libpcscxx.la
libpcscxx_la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx \ libpcscxx_la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx version.cxx \
version.cxx openssl-engine.cxx openssl-engine.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
@@ -45,10 +49,12 @@ endif
noinst_PROGRAMS = versiontest noinst_PROGRAMS = versiontest
versiontest_SOURCES = versiontest.cxx versiontest_SOURCES = versiontest.cxx
moc_%.cxx: %.hxx
moc -o $@ $<
clean-local: clean-local:
-rm -r ${QMAKE_TARGET}.app -rm -r ${QMAKE_TARGET}.app
CLEANFILES = CLEANFILES = ${MOC_FILES}
DISTCLEANFILES = $(pkgconfig_DATA) DISTCLEANFILES = $(pkgconfig_DATA)
MAINTAINERCLEANFILES = makefile.in MAINTAINERCLEANFILES = makefile.in

View File

@@ -7,6 +7,9 @@
#ifndef __OPENSSL_ENGINE_HXX__ #ifndef __OPENSSL_ENGINE_HXX__
#define __OPENSSL_ENGINE_HXX__ #define __OPENSSL_ENGINE_HXX__
#include <cryptaux.hxx>
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#ifndef OPENSSL_VERSION_NUMBER #ifndef OPENSSL_VERSION_NUMBER
# error OpenSSL Version Number not Found # error OpenSSL Version Number not Found
@@ -34,24 +37,6 @@
#define OPENSSL_CHECK(X) if (!X) {ERR_load_ENGINE_strings(); std::stringstream ss; for (unsigned int err(0); err=ERR_get_error();) ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; ss<<"Command "<<#X<<" failed in file "<<__FILE__<<":"<<__LINE__; throw std::runtime_error(ss.str());} #define OPENSSL_CHECK(X) if (!X) {ERR_load_ENGINE_strings(); std::stringstream ss; for (unsigned int err(0); err=ERR_get_error();) ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; ss<<"Command "<<#X<<" failed in file "<<__FILE__<<":"<<__LINE__; throw std::runtime_error(ss.str());}
#endif #endif
#endif #endif
#ifndef OPENSSL_LOG
#include <iostream>
#if __GNUC__ >= 2
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__PRETTY_FUNCTION__<<std::endl
#else
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__FILE__<<__LINE__<<std::endl
#endif
#endif
//! @addtogroup gopenssl //! @addtogroup gopenssl
//@{ //@{
@@ -75,56 +60,56 @@ namespace openssl {
public: public:
Engine(): _e(ENGINE_new()) { Engine(): _e(ENGINE_new()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
virtual ~Engine() { virtual ~Engine() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
OPENSSL_CHECK(ENGINE_free(_e)); OPENSSL_CHECK(ENGINE_free(_e));
} }
virtual const char* id() = 0; virtual const char* id() = 0;
virtual const char* name() = 0; virtual const char* name() = 0;
virtual int init() { virtual int init() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual int finish() { virtual int finish() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual int ctrl(int, long, void*, void(*)()) { virtual int ctrl(int, long, void*, void(*)()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual int cmd() { virtual int cmd() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual EVP_PKEY* pubkey(const char*, UI_METHOD*, void*) { virtual EVP_PKEY* pubkey(const char*, UI_METHOD*, void*) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 0; return 0;
} }
virtual EVP_PKEY* privkey(const char*, UI_METHOD*, void*) { virtual EVP_PKEY* privkey(const char*, UI_METHOD*, void*) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 0; return 0;
} }
virtual int rsaEncrypt() { virtual int rsaEncrypt() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual int rsaDecrypt() { virtual int rsaDecrypt() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual std::string rsaSign(const std::string&, unsigned int) { virtual std::string rsaSign(const std::string&, unsigned int) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
throw std::runtime_error("rsaSign not implemented"); throw std::runtime_error("rsaSign not implemented");
} }
virtual int rsaVerify() { virtual int rsaVerify() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
virtual int rsaFinish() { virtual int rsaFinish() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
@@ -140,7 +125,7 @@ namespace openssl {
public: public:
static void add(Engine *e) { static void add(Engine *e) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
_prototypes[e->id()] = e; _prototypes[e->id()] = e;
_map[e->_e] = e; _map[e->_e] = e;
OPENSSL_CHECK(ENGINE_set_id(e->_e, e->id())); OPENSSL_CHECK(ENGINE_set_id(e->_e, e->id()));
@@ -176,43 +161,43 @@ namespace openssl {
private: private:
static int destroy(ENGINE* e) { static int destroy(ENGINE* e) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
static int init(ENGINE* e) { static int init(ENGINE* e) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->init():0; return it!=_map.end()?it->second->init():0;
} }
static int finish(ENGINE* e) { static int finish(ENGINE* e) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->finish():0; return it!=_map.end()?it->second->finish():0;
} }
static int ctrl(ENGINE* e, int cmd, long i, void* p, void(*f)()) { static int ctrl(ENGINE* e, int cmd, long i, void* p, void(*f)()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->ctrl(cmd, i, p, f):0; return it!=_map.end()?it->second->ctrl(cmd, i, p, f):0;
} }
static EVP_PKEY* pubkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) { static EVP_PKEY* pubkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->pubkey(c, u, d):0; return it!=_map.end()?it->second->pubkey(c, u, d):0;
} }
static EVP_PKEY* privkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) { static EVP_PKEY* privkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->privkey(c, u, d):0; return it!=_map.end()?it->second->privkey(c, u, d):0;
} }
static int rsaEncrypt(int flen,const unsigned char *from, static int rsaEncrypt(int flen,const unsigned char *from,
unsigned char *to, unsigned char *to,
RSA *rsa, int padding) { RSA *rsa, int padding) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaEncrypt():0; return it!=_map.end()?it->second->rsaEncrypt():0;
} }
static int rsaDecrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { static int rsaDecrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaDecrypt():0; return it!=_map.end()?it->second->rsaDecrypt():0;
} }
@@ -221,32 +206,32 @@ namespace openssl {
unsigned char *to, unsigned char *to,
unsigned int*tlen, unsigned int*tlen,
const RSA *rsa) { const RSA *rsa) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
if (it==_map.end()) return 0; if (it==_map.end()) return 0;
try { try {
std::string res(it->second->rsaSign std::string res(it->second->rsaSign
(std::string((const char*)from, flen), (std::string((const char*)from, flen),
type)); type));
OPENSSL_LOG("to="<<(void*)to<<"; len="<<*tlen); CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen);
OPENSSL_LOG("siglen="<<res.size()); CRYPTOLOG("siglen="<<res.size());
*tlen = res.size(); *tlen = res.size();
std::copy(res.begin(), res.end(), to); std::copy(res.begin(), res.end(), to);
return 1; return 1;
} catch (const std::exception& e) { } catch (const std::exception& e) {
OPENSSL_LOG("ERROR: "<<e.what()); CRYPTOLOG("ERROR: "<<e.what());
return 0; return 0;
} }
} }
static int rsaVerify(int, const unsigned char*, static int rsaVerify(int, const unsigned char*,
unsigned int, OPENSSL_V0_CONST unsigned char*, unsigned int, OPENSSL_V0_CONST unsigned char*,
unsigned int, const RSA* rsa) { unsigned int, const RSA* rsa) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaVerify():0; return it!=_map.end()?it->second->rsaVerify():0;
} }
static int rsaFinish(RSA *rsa) { static int rsaFinish(RSA *rsa) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaFinish():0; return it!=_map.end()?it->second->rsaFinish():0;
} }
@@ -254,7 +239,7 @@ namespace openssl {
protected: protected:
static RSA_METHOD* rsa() { static RSA_METHOD* rsa() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
static RSA_METHOD ops; static RSA_METHOD ops;
if (!ops.rsa_priv_enc) { if (!ops.rsa_priv_enc) {
ops = *RSA_get_default_method(); ops = *RSA_get_default_method();

View File

@@ -60,26 +60,6 @@ namespace pcsc {
std::string version(); std::string version();
} }
#ifndef OPENSSL_LOG
#include <iostream>
#if __GNUC__ >= 2
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__PRETTY_FUNCTION__<<std::endl
#else
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before <code>#include
&lt;openssl.hxx&gt;</code>. Define it empty for no logging at
all. By default logs to <code>std::clog</code>. */
#define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__FILE__<<__LINE__<<std::endl
#endif
#endif
/*! @defgroup gopenssl C++ Wrapper around OpenSSL API */ /*! @defgroup gopenssl C++ Wrapper around OpenSSL API */
//@{ //@{
//! @defgroup openssllib OpenSSL C++ Library //! @defgroup openssllib OpenSSL C++ Library
@@ -97,7 +77,7 @@ namespace openssl {
public: public:
exception(const std::string& reason) throw(): exception(const std::string& reason) throw():
_what("openssl: "+reason) { _what("openssl: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
~exception() throw() {} ~exception() throw() {}
const char* what() const throw() { const char* what() const throw() {
@@ -110,8 +90,8 @@ namespace openssl {
class openssl_error: public exception { class openssl_error: public exception {
public: public:
openssl_error(const std::string& reason) throw(): openssl_error(const std::string& reason) throw():
exception(reason+'\n'+ERR_error_string(ERR_get_error(), 0)) { exception(reason+' '+ERR_error_string(ERR_get_error(), 0)) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -119,7 +99,7 @@ namespace openssl {
public: public:
cannot_init(const std::string& reason) throw(): cannot_init(const std::string& reason) throw():
openssl_error("openssl initialization: "+reason) { openssl_error("openssl initialization: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -127,7 +107,7 @@ namespace openssl {
public: public:
encryption_error(const std::string& reason) throw(): encryption_error(const std::string& reason) throw():
openssl_error("encryption: "+reason) { openssl_error("encryption: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -135,7 +115,7 @@ namespace openssl {
public: public:
pkcs12_error(const std::string& reason) throw(): pkcs12_error(const std::string& reason) throw():
openssl_error("pkcs12: "+reason) { openssl_error("pkcs12: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -143,7 +123,7 @@ namespace openssl {
public: public:
pkcs7_error(const std::string& reason) throw(): pkcs7_error(const std::string& reason) throw():
openssl_error("pkcs7: "+reason) { openssl_error("pkcs7: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -151,7 +131,7 @@ namespace openssl {
public: public:
x509_error(const std::string& reason) throw(): x509_error(const std::string& reason) throw():
openssl_error("x509: "+reason) { openssl_error("x509: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -159,7 +139,7 @@ namespace openssl {
public: public:
key_error(const std::string& reason) throw(): key_error(const std::string& reason) throw():
openssl_error("private key: "+reason) { openssl_error("private key: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -167,7 +147,7 @@ namespace openssl {
public: public:
tcp_error(const std::string& reason) throw(): tcp_error(const std::string& reason) throw():
openssl_error("tcp "+reason) { openssl_error("tcp "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -175,7 +155,7 @@ namespace openssl {
public: public:
ssl_error(const std::string& reason) throw(): ssl_error(const std::string& reason) throw():
openssl_error("ssl: "+reason) { openssl_error("ssl: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -183,7 +163,7 @@ namespace openssl {
public: public:
cannot_encrypt(std::string reason) throw(): cannot_encrypt(std::string reason) throw():
encryption_error("cannot encrypt text: "+reason) { encryption_error("cannot encrypt text: "+reason) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -191,15 +171,15 @@ namespace openssl {
public: public:
allocation_failed() throw(): allocation_failed() throw():
x509_error("memory allocation failed") { x509_error("memory allocation failed") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class x509_decoding_failed: public x509_error { class x509_decoding_failed: public x509_error {
public: public:
x509_decoding_failed(const std::string& der) throw(): x509_decoding_failed(const std::string& der) throw():
x509_error("certificate decoding failed:\n"+crypto::readable(der)) { x509_error("certificate decoding failed: "+crypto::readable(der)) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -207,7 +187,7 @@ namespace openssl {
public: public:
undefined_certificate() throw(): undefined_certificate() throw():
x509_error("certificate must not be 0") { x509_error("certificate must not be 0") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -215,7 +195,7 @@ namespace openssl {
public: public:
x509_parsing_failed() throw(): x509_parsing_failed() throw():
x509_error("parsing DER encoded certificate failed") { x509_error("parsing DER encoded certificate failed") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -223,7 +203,7 @@ namespace openssl {
public: public:
x509_copy_failed() throw(): x509_copy_failed() throw():
x509_error("certificate object copy failed") { x509_error("certificate object copy failed") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -231,7 +211,7 @@ namespace openssl {
public: public:
key_copy_failed() throw(): key_copy_failed() throw():
key_error("key object copy failed") { key_error("key object copy failed") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -239,7 +219,7 @@ namespace openssl {
public: public:
undefined_key() throw(): undefined_key() throw():
key_error("private key must not be 0") { key_error("private key must not be 0") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -247,7 +227,7 @@ namespace openssl {
public: public:
pkcs12_reading_failed(const std::string& file) throw(): pkcs12_reading_failed(const std::string& file) throw():
pkcs12_error("reading DER encoded p12 file failed: "+file) { pkcs12_error("reading DER encoded p12 file failed: "+file) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -255,21 +235,21 @@ namespace openssl {
public: public:
pkcs12_parsing_failed(const std::string& file) throw(): pkcs12_parsing_failed(const std::string& file) throw():
pkcs12_error("parsing DER encoded p12 file failed: "+file) { pkcs12_error("parsing DER encoded p12 file failed: "+file) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs12_no_private_key: public pkcs12_error { class pkcs12_no_private_key: public pkcs12_error {
public: public:
pkcs12_no_private_key() throw(): pkcs12_error("no private key") { pkcs12_no_private_key() throw(): pkcs12_error("no private key") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs12_no_x509: public pkcs12_error { class pkcs12_no_x509: public pkcs12_error {
public: public:
pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") { pkcs12_no_x509() throw(): pkcs12_error("no x509 certificate") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -277,7 +257,7 @@ namespace openssl {
public: public:
pkcs7_reading_failed(const std::string& file) throw(): pkcs7_reading_failed(const std::string& file) throw():
pkcs7_error("reading DER encoded p7 file failed: "+file) { pkcs7_error("reading DER encoded p7 file failed: "+file) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -285,7 +265,7 @@ namespace openssl {
public: public:
pkcs7_parsing_failed() throw(): pkcs7_parsing_failed() throw():
pkcs7_error("parsing DER encoded p7 failed") { pkcs7_error("parsing DER encoded p7 failed") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
pkcs7_parsing_failed(const std::string& file) throw(): pkcs7_parsing_failed(const std::string& file) throw():
pkcs7_error("parsing DER encoded p7 file failed: "+file) { pkcs7_error("parsing DER encoded p7 file failed: "+file) {
@@ -295,14 +275,14 @@ namespace openssl {
class pkcs7_unsupported_format: public pkcs7_error { class pkcs7_unsupported_format: public pkcs7_error {
public: public:
pkcs7_unsupported_format() throw(): pkcs7_error("format not supported") { pkcs7_unsupported_format() throw(): pkcs7_error("format not supported") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class pkcs7_no_x509: public pkcs7_error { class pkcs7_no_x509: public pkcs7_error {
public: public:
pkcs7_no_x509() throw(): pkcs7_error("no x509 certificate") { pkcs7_no_x509() throw(): pkcs7_error("no x509 certificate") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -310,7 +290,7 @@ namespace openssl {
public: public:
cannot_open_file(const std::string& file) throw(): cannot_open_file(const std::string& file) throw():
exception("cannot open file: "+file) { exception("cannot open file: "+file) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -318,7 +298,7 @@ namespace openssl {
public: public:
tcp_connection_failed(const std::string& hostPort) throw(): tcp_connection_failed(const std::string& hostPort) throw():
tcp_error("connection failed to: "+hostPort) { tcp_error("connection failed to: "+hostPort) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -326,35 +306,35 @@ namespace openssl {
public: public:
tcp_server_not_specified() throw(): tcp_server_not_specified() throw():
tcp_error("reconnect without prior connect") { tcp_error("reconnect without prior connect") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class tcp_closed_connection: public tcp_error { class tcp_closed_connection: public tcp_error {
public: public:
tcp_closed_connection() throw(): tcp_error("closed connection") { tcp_closed_connection() throw(): tcp_error("closed connection") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class tcp_read_error: public tcp_error { class tcp_read_error: public tcp_error {
public: public:
tcp_read_error() throw(): tcp_error("read error") { tcp_read_error() throw(): tcp_error("read error") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class tcp_write_error: public tcp_error { class tcp_write_error: public tcp_error {
public: public:
tcp_write_error() throw(): tcp_error("write error") { tcp_write_error() throw(): tcp_error("write error") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class ssl_cannot_create_context: public ssl_error { class ssl_cannot_create_context: public ssl_error {
public: public:
ssl_cannot_create_context() throw(): ssl_error("cannot create context") { ssl_cannot_create_context() throw(): ssl_error("cannot create context") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -362,7 +342,7 @@ namespace openssl {
public: public:
ssl_certificate_file_not_loaded(const std::string& file) throw(): ssl_certificate_file_not_loaded(const std::string& file) throw():
ssl_error("certificate file not loaded: "+file) { ssl_error("certificate file not loaded: "+file) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -370,7 +350,7 @@ namespace openssl {
public: public:
ssl_certificate_folder_not_loaded(const std::string& path) throw(): ssl_certificate_folder_not_loaded(const std::string& path) throw():
ssl_error("certificate folder not loaded: "+path) { ssl_error("certificate folder not loaded: "+path) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -378,7 +358,7 @@ namespace openssl {
public: public:
ssl_no_connection() throw(): ssl_no_connection() throw():
ssl_error("no ssl connection") { ssl_error("no ssl connection") {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@@ -386,7 +366,7 @@ namespace openssl {
public: public:
ssl_verification_failed(int num) throw(): ssl_verification_failed(int num) throw():
ssl_error("certificate verification failed: "+reason(num)) { ssl_error("certificate verification failed: "+reason(num)) {
OPENSSL_LOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
static std::string reason(int num) { static std::string reason(int num) {
switch (num) { switch (num) {
@@ -531,7 +511,7 @@ namespace openssl {
class Init { class Init {
public: public:
Init() { Init() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
SSL_load_error_strings(); SSL_load_error_strings();
ERR_load_BIO_strings(); ERR_load_BIO_strings();
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
@@ -544,30 +524,30 @@ namespace openssl {
public: public:
BigNum(): BigNum():
_bn(BN_new()) { _bn(BN_new()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
BigNum(const std::string& num): BigNum(const std::string& num):
_bn(BN_bin2bn((const unsigned char*)num.data(), num.size(), 0)) { _bn(BN_bin2bn((const unsigned char*)num.data(), num.size(), 0)) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
~BigNum() { ~BigNum() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
BN_free(_bn); BN_free(_bn);
} }
int size() const { int size() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return size(_bn); return size(_bn);
} }
static int size(BIGNUM* n) { static int size(BIGNUM* n) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BN_num_bytes(n); return BN_num_bytes(n);
} }
std::string string() const { std::string string() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return string(_bn); return string(_bn);
} }
static std::string string(BIGNUM* a) { static std::string string(BIGNUM* a) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
std::string res(BN_num_bytes(a), '0'); std::string res(BN_num_bytes(a), '0');
BN_bn2bin(a, (unsigned char*)res.begin().operator->()); BN_bn2bin(a, (unsigned char*)res.begin().operator->());
return res; return res;
@@ -626,7 +606,7 @@ namespace openssl {
/*! @param txt text to encrypt - size must be a multiple of 8 /*! @param txt text to encrypt - size must be a multiple of 8
@param key1 DES key for encryption */ @param key1 DES key for encryption */
inline std::string desEnc(const std::string& txt, CBlock8 key1) { inline std::string desEnc(const std::string& txt, CBlock8 key1) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
std::string res(txt); std::string res(txt);
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@@ -648,7 +628,7 @@ namespace openssl {
/*! @param txt text to decrypt - size must be a multiple of 8 /*! @param txt text to decrypt - size must be a multiple of 8
@param key1 DES key for decryption */ @param key1 DES key for decryption */
inline std::string desDec(const std::string& txt, CBlock8 key1) { inline std::string desDec(const std::string& txt, CBlock8 key1) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
std::string res(txt); std::string res(txt);
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@@ -671,7 +651,7 @@ namespace openssl {
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks; DES_key_schedule ks;
@@ -686,7 +666,7 @@ namespace openssl {
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) { inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
CBlock8 ivec; CBlock8 ivec;
return desCbcEnc(txt, key, ivec); return desCbcEnc(txt, key, ivec);
} }
@@ -696,7 +676,7 @@ namespace openssl {
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks; DES_key_schedule ks;
@@ -711,7 +691,7 @@ namespace openssl {
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes. */
inline std::string desCbcDec(const std::string& txt, const CBlock8& key) { inline std::string desCbcDec(const std::string& txt, const CBlock8& key) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
CBlock8 ivec; CBlock8 ivec;
return desCbcDec(txt, key, ivec); return desCbcDec(txt, key, ivec);
} }
@@ -722,7 +702,7 @@ namespace openssl {
inline std::string des2edeCbcEnc(std::string txt, inline std::string des2edeCbcEnc(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks1, ks2; DES_key_schedule ks1, ks2;
@@ -739,7 +719,7 @@ namespace openssl {
inline std::string des2edeCbcDec(std::string txt, inline std::string des2edeCbcDec(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
std::string res(txt.size(), 0); std::string res(txt.size(), 0);
DES_key_schedule ks1, ks2; DES_key_schedule ks1, ks2;
@@ -753,7 +733,7 @@ namespace openssl {
//! @todo untested //! @todo untested
inline std::string des2ecbEnc(std::string txt, inline std::string des2ecbEnc(std::string txt,
CBlock8 key1, CBlock8 key2) { CBlock8 key1, CBlock8 key2) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@@ -771,7 +751,7 @@ namespace openssl {
//! @todo untested //! @todo untested
inline std::string des2ecbDec(std::string txt, inline std::string des2ecbDec(std::string txt,
CBlock8 key1, CBlock8 key2) { CBlock8 key1, CBlock8 key2) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
std::string res; std::string res;
if (txt.size()%8!=0) if (txt.size()%8!=0)
throw cannot_encrypt("text size must be a multiple of eight"); throw cannot_encrypt("text size must be a multiple of eight");
@@ -792,19 +772,19 @@ namespace openssl {
public: public:
//! Construct empty certificate. //! Construct empty certificate.
X509(): _x509(X509_new()) { X509(): _x509(X509_new()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_x509) throw allocation_failed(); if (!_x509) throw allocation_failed();
} }
//! Initialize from DER encoded cerificate. //! Initialize from DER encoded cerificate.
X509(const std::string& der): _x509(0) { X509(const std::string& der): _x509(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
V0_CONST unsigned char* c((unsigned char*)der.begin().operator->()); V0_CONST unsigned char* c((unsigned char*)der.begin().operator->());
if (!(_x509=d2i_X509(0, &c, der.size())) || if (!(_x509=d2i_X509(0, &c, der.size())) ||
(const char*)c!=der.begin().operator->()+der.size()) (const char*)c!=der.begin().operator->()+der.size())
throw x509_decoding_failed(der); throw x509_decoding_failed(der);
} }
X509(const X509& o): _x509(0) { X509(const X509& o): _x509(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
_x509 = X509_dup(o._x509); _x509 = X509_dup(o._x509);
// unsigned char* d(0); // unsigned char* d(0);
// int len(i2d_X509(o._x509, &d)); // int len(i2d_X509(o._x509, &d));
@@ -816,15 +796,15 @@ namespace openssl {
} }
//! Take over OpenSSL allocated certificate. //! Take over OpenSSL allocated certificate.
X509(::X509 *x509): _x509(x509) { X509(::X509 *x509): _x509(x509) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_x509) throw undefined_certificate(); if (!_x509) throw undefined_certificate();
} }
~X509() { ~X509() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_free(_x509); X509_free(_x509);
} }
X509& operator=(const X509& o) { X509& operator=(const X509& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_free(_x509); X509_free(_x509);
_x509 = 0; _x509 = 0;
_x509 = X509_dup(o._x509); _x509 = X509_dup(o._x509);
@@ -843,7 +823,7 @@ namespace openssl {
} }
//! Get DER encoded subject. //! Get DER encoded subject.
std::string subjectDER() const { std::string subjectDER() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509_NAME(X509_get_subject_name(_x509), &c)); int len(i2d_X509_NAME(X509_get_subject_name(_x509), &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@@ -852,7 +832,7 @@ namespace openssl {
} }
//! Get DER encoded issuer. //! Get DER encoded issuer.
std::string issuerDER() const { std::string issuerDER() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509_NAME(X509_get_issuer_name(_x509), &c)); int len(i2d_X509_NAME(X509_get_issuer_name(_x509), &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@@ -861,7 +841,7 @@ namespace openssl {
} }
//! Get DER encoded value. //! Get DER encoded value.
std::string valueDER() const { std::string valueDER() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
unsigned char* c(0); unsigned char* c(0);
int len(i2d_X509(_x509, &c)); int len(i2d_X509(_x509, &c));
std::string res((char*)c, len); std::string res((char*)c, len);
@@ -870,7 +850,7 @@ namespace openssl {
} }
//! Get serial number. //! Get serial number.
std::string serial() const { std::string serial() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
/* @bug tcp://albistechnologies.com reports: «could be a /* @bug tcp://albistechnologies.com reports: «could be a
failure in openSSL: len too short by 1 if serial number failure in openSSL: len too short by 1 if serial number
starts with 00 ASN1_INTEGER* ser = starts with 00 ASN1_INTEGER* ser =
@@ -894,7 +874,7 @@ namespace openssl {
} }
//! Get id. //! Get id.
std::string id() const { std::string id() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
unsigned char c[SHA_DIGEST_LENGTH]; unsigned char c[SHA_DIGEST_LENGTH];
SHA1(_x509->cert_info->key->public_key->data, SHA1(_x509->cert_info->key->public_key->data,
_x509->cert_info->key->public_key->length, _x509->cert_info->key->public_key->length,
@@ -903,7 +883,7 @@ namespace openssl {
} }
//! Get common name. //! Get common name.
std::string commonName() const { std::string commonName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -914,7 +894,7 @@ namespace openssl {
} }
//! Get country name. //! Get country name.
std::string countryName() const { std::string countryName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -925,7 +905,7 @@ namespace openssl {
} }
//! Get locality name. //! Get locality name.
std::string localityName() const { std::string localityName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -936,7 +916,7 @@ namespace openssl {
} }
//! Get state or province name. //! Get state or province name.
std::string stateOrProvinceName() const { std::string stateOrProvinceName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -948,7 +928,7 @@ namespace openssl {
} }
//! Get organization name. //! Get organization name.
std::string organizationName() const { std::string organizationName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -960,7 +940,7 @@ namespace openssl {
} }
//! Check whether it's a CA certificate. //! Check whether it's a CA certificate.
bool isCa() { bool isCa() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
BASIC_CONSTRAINTS* bc(0); BASIC_CONSTRAINTS* bc(0);
int pos(X509_get_ext_by_NID(_x509, NID_basic_constraints, -1)); int pos(X509_get_ext_by_NID(_x509, NID_basic_constraints, -1));
if (pos>=0) if (pos>=0)
@@ -969,7 +949,7 @@ namespace openssl {
} }
//! Get organizational unit name. //! Get organizational unit name.
std::string organizationalUnitName() const { std::string organizationalUnitName() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
X509_NAME *name(X509_get_subject_name(_x509)); X509_NAME *name(X509_get_subject_name(_x509));
ASN1_STRING* cn ASN1_STRING* cn
(X509_NAME_ENTRY_get_data (X509_NAME_ENTRY_get_data
@@ -981,7 +961,7 @@ namespace openssl {
} }
//! Get key usage flags. //! Get key usage flags.
int keyUsageFlags() const { int keyUsageFlags() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
int res(X509v3_KU_UNDEF); int res(X509v3_KU_UNDEF);
int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1)); int pos(X509_get_ext_by_NID(_x509, NID_key_usage, -1));
if (pos>=0) { if (pos>=0) {
@@ -1005,61 +985,61 @@ namespace openssl {
class PrivateKey { class PrivateKey {
public: public:
PrivateKey(): _key(EVP_PKEY_new()) { PrivateKey(): _key(EVP_PKEY_new()) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_key) throw allocation_failed(); if (!_key) throw allocation_failed();
} }
PrivateKey(const PrivateKey& o): _key(0) { PrivateKey(const PrivateKey& o): _key(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
copy(o); copy(o);
} }
PrivateKey(EVP_PKEY* k): _key(k) { PrivateKey(EVP_PKEY* k): _key(k) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_key) throw undefined_key(); if (!_key) throw undefined_key();
} }
~PrivateKey() { ~PrivateKey() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
EVP_PKEY_free(_key); EVP_PKEY_free(_key);
} }
PrivateKey& operator=(const PrivateKey& o) { PrivateKey& operator=(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
copy(o); copy(o);
return *this; return *this;
} }
std::string modulus() const { std::string modulus() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->n); return BigNum::string(rsa()->n);
} }
std::string publicExponent() const { std::string publicExponent() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->e); return BigNum::string(rsa()->e);
} }
std::string privateExponent() const { std::string privateExponent() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->d); return BigNum::string(rsa()->d);
} }
std::string prime1() const { std::string prime1() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->p); return BigNum::string(rsa()->p);
} }
std::string prime2() const { std::string prime2() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->q); return BigNum::string(rsa()->q);
} }
std::string exponent1() const { std::string exponent1() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->dmp1); return BigNum::string(rsa()->dmp1);
} }
std::string exponent2() const { std::string exponent2() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->dmq1); return BigNum::string(rsa()->dmq1);
} }
std::string coefficient() const { std::string coefficient() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return BigNum::string(rsa()->iqmp); return BigNum::string(rsa()->iqmp);
} }
private: private:
void copy(const PrivateKey& o) { void copy(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
EVP_PKEY_free(_key); EVP_PKEY_free(_key);
if (!(_key=EVP_PKEY_new())) throw allocation_failed(); if (!(_key=EVP_PKEY_new())) throw allocation_failed();
rsa(o); rsa(o);
@@ -1068,44 +1048,44 @@ namespace openssl {
/*ec(o);*/ /*ec(o);*/
} }
void rsa(const PrivateKey& o) { void rsa(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
//! @todo throw exception if 0? //! @todo throw exception if 0?
RSA* tmp(o.rsa()); RSA* tmp(o.rsa());
if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_RSA(_key, tmp)) throw key_copy_failed();
} }
void dsa(const PrivateKey& o) { void dsa(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
DSA* tmp(o.dsa()); DSA* tmp(o.dsa());
if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_DSA(_key, tmp)) throw key_copy_failed();
} }
void dh(const PrivateKey& o) { void dh(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
DH* tmp(o.dh()); DH* tmp(o.dh());
if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_DH(_key, tmp)) throw key_copy_failed();
} }
/* Not available on mac osx /* Not available on mac osx
void ec(const PrivateKey& o) { void ec(const PrivateKey& o) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
EC_KEY* tmp(o.ec()); EC_KEY* tmp(o.ec());
if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed(); if (tmp&&!EVP_PKEY_set1_EC_KEY(_key, tmp)) throw key_copy_failed();
} }
*/ */
RSA* rsa() const { RSA* rsa() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
//! @todo throw exception if 0? //! @todo throw exception if 0?
return EVP_PKEY_get1_RSA(_key); return EVP_PKEY_get1_RSA(_key);
} }
DSA* dsa() const { DSA* dsa() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return EVP_PKEY_get1_DSA(_key); return EVP_PKEY_get1_DSA(_key);
} }
DH* dh() const { DH* dh() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return EVP_PKEY_get1_DH(_key); return EVP_PKEY_get1_DH(_key);
} }
/* Not available on mac osx /* Not available on mac osx
EC_KEY* ec() const { EC_KEY* ec() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return EVP_PKEY_get1_EC_KEY(_key); return EVP_PKEY_get1_EC_KEY(_key);
}*/ }*/
EVP_PKEY* _key; EVP_PKEY* _key;
@@ -1125,7 +1105,7 @@ namespace openssl {
//! Read from a PKCS#12 (.p12) file. //! Read from a PKCS#12 (.p12) file.
PKCS12(std::string filename, std::string password): PKCS12(std::string filename, std::string password):
_key(0), _cert(0) { _key(0), _cert(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
FILE* file(fopen(filename.c_str(), "rb")); FILE* file(fopen(filename.c_str(), "rb"));
if (!file) throw cannot_open_file(filename); if (!file) throw cannot_open_file(filename);
::PKCS12 *p12(d2i_PKCS12_fp(file, 0)); ::PKCS12 *p12(d2i_PKCS12_fp(file, 0));
@@ -1149,7 +1129,7 @@ namespace openssl {
} }
~PKCS12() { ~PKCS12() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
delete _key; delete _key;
delete _cert; delete _cert;
for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it) for (X509List::iterator it(_ca.begin()); it!=_ca.end(); ++it)
@@ -1157,29 +1137,29 @@ namespace openssl {
} }
bool hasPrivateKey() const { bool hasPrivateKey() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _key; return _key;
} }
bool hasCert() const { bool hasCert() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _cert; return _cert;
} }
const PrivateKey& privateKey() const { const PrivateKey& privateKey() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_key) throw pkcs12_no_private_key(); if (!_key) throw pkcs12_no_private_key();
return *_key; return *_key;
}; };
const X509& x509() const { const X509& x509() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_cert) throw pkcs12_no_x509(); if (!_cert) throw pkcs12_no_x509();
return *_cert; return *_cert;
}; };
const X509List& ca() const { const X509List& ca() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _ca; return _ca;
} }
@@ -1222,7 +1202,7 @@ namespace openssl {
//! Read PKCS#7 from memory. //! Read PKCS#7 from memory.
PKCS7(const std::string& memory) { PKCS7(const std::string& memory) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size())); BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size()));
::PKCS7 *p7(d2i_PKCS7_bio(mem, 0)); ::PKCS7 *p7(d2i_PKCS7_bio(mem, 0));
BIO_free(mem); BIO_free(mem);
@@ -1240,13 +1220,13 @@ namespace openssl {
} }
~PKCS7() { ~PKCS7() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
for (X509List::iterator it(_certs.begin()); it!=_certs.end(); ++it) for (X509List::iterator it(_certs.begin()); it!=_certs.end(); ++it)
delete *it; delete *it;
} }
const X509List& certs() const { const X509List& certs() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _certs; return _certs;
} }
@@ -1266,16 +1246,16 @@ namespace openssl {
public: public:
TCP(): _bio(0) { TCP(): _bio(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
TCP(const std::string& hostPort): _bio(0) { TCP(const std::string& hostPort): _bio(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
connect(hostPort); connect(hostPort);
} }
virtual ~TCP() { virtual ~TCP() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
try { try {
close(); close();
} catch (...) { } catch (...) {
@@ -1284,7 +1264,7 @@ namespace openssl {
} }
virtual TCP& connect(const std::string& hostPort) { virtual TCP& connect(const std::string& hostPort) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
close(); close();
if (!(_bio=BIO_new_connect(const_cast<char*>(hostPort.c_str()))) || if (!(_bio=BIO_new_connect(const_cast<char*>(hostPort.c_str()))) ||
BIO_do_connect(_bio)<=0) BIO_do_connect(_bio)<=0)
@@ -1301,18 +1281,18 @@ namespace openssl {
} }
operator bool() const { operator bool() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _bio>0; return _bio>0;
} }
TCP& operator>>(std::string& s) { TCP& operator>>(std::string& s) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
s += read(); s += read();
return *this; return *this;
} }
TCP& operator<<(const std::string& s) { TCP& operator<<(const std::string& s) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return write(s); return write(s);
} }
@@ -1321,7 +1301,7 @@ namespace openssl {
server is waiting for next request, but connection is still server is waiting for next request, but connection is still
open? */ open? */
std::string read() { std::string read() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (_bio<=0) throw tcp_closed_connection(); if (_bio<=0) throw tcp_closed_connection();
const int BUFF_SZ(1024); const int BUFF_SZ(1024);
char buff[BUFF_SZ]; char buff[BUFF_SZ];
@@ -1338,7 +1318,7 @@ namespace openssl {
} }
TCP& write(const std::string& s) { TCP& write(const std::string& s) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (_bio<=0) throw tcp_closed_connection(); if (_bio<=0) throw tcp_closed_connection();
unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size())); unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size()));
if (x<=0) if (x<=0)
@@ -1352,7 +1332,7 @@ namespace openssl {
} }
virtual TCP& close() { virtual TCP& close() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (_bio>0) BIO_free_all(_bio); if (_bio>0) BIO_free_all(_bio);
_bio = 0; _bio = 0;
return *this; return *this;
@@ -1370,10 +1350,10 @@ namespace openssl {
public: public:
TrustStore(const std::string& pathToPemFile): TrustStore(const std::string& pathToPemFile):
_file(pathToPemFile) { _file(pathToPemFile) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
const std::string& file() const { const std::string& file() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _file; return _file;
} }
private: private:
@@ -1384,10 +1364,10 @@ namespace openssl {
public: public:
CertificateFolder(const std::string& certificateFolder): CertificateFolder(const std::string& certificateFolder):
_path(certificateFolder) { _path(certificateFolder) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
} }
const std::string& path() const { const std::string& path() const {
OPENSSL_LOG("log"); CRYPTOLOG("log");
return _path; return _path;
} }
private: private:
@@ -1403,7 +1383,7 @@ namespace openssl {
SSL(const TrustStore& file): SSL(const TrustStore& file):
_ctx(SSL_CTX_new(SSLv23_client_method())), _ctx(SSL_CTX_new(SSLv23_client_method())),
_ssl(0) { _ssl(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_ctx) throw ssl_cannot_create_context(); if (!_ctx) throw ssl_cannot_create_context();
if (!SSL_CTX_load_verify_locations(_ctx, file.file().c_str(), 0)) if (!SSL_CTX_load_verify_locations(_ctx, file.file().c_str(), 0))
throw ssl_certificate_file_not_loaded(file.file()); throw ssl_certificate_file_not_loaded(file.file());
@@ -1411,18 +1391,18 @@ namespace openssl {
SSL(const CertificateFolder& folder): SSL(const CertificateFolder& folder):
_ctx(SSL_CTX_new(SSLv23_client_method())), _ctx(SSL_CTX_new(SSLv23_client_method())),
_ssl(0) { _ssl(0) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_ctx) throw ssl_cannot_create_context(); if (!_ctx) throw ssl_cannot_create_context();
if (!SSL_CTX_load_verify_locations(_ctx, 0, folder.path().c_str())) if (!SSL_CTX_load_verify_locations(_ctx, 0, folder.path().c_str()))
throw ssl_certificate_folder_not_loaded(folder.path()); throw ssl_certificate_folder_not_loaded(folder.path());
} }
~SSL() { ~SSL() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
close(); close();
SSL_CTX_free(_ctx); SSL_CTX_free(_ctx);
} }
virtual SSL& connect(const std::string& hostPort) { virtual SSL& connect(const std::string& hostPort) {
OPENSSL_LOG("log"); CRYPTOLOG("log");
close(); close();
if (!(_bio=BIO_new_ssl_connect(_ctx))) if (!(_bio=BIO_new_ssl_connect(_ctx)))
throw tcp_connection_failed(hostPort); throw tcp_connection_failed(hostPort);
@@ -1436,14 +1416,14 @@ namespace openssl {
return *this; return *this;
} }
virtual SSL& close() { virtual SSL& close() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
TCP::close(); TCP::close();
_ssl = 0; //! @todo is this correct? <-- _ssl = 0; //! @todo is this correct? <--
return *this; return *this;
} }
protected: protected:
void verify() { void verify() {
OPENSSL_LOG("log"); CRYPTOLOG("log");
if (!_ssl) throw ssl_no_connection(); if (!_ssl) throw ssl_no_connection();
int res(SSL_get_verify_result(_ssl)); int res(SSL_get_verify_result(_ssl));
if (res!=X509_V_OK) throw ssl_verification_failed(res); if (res!=X509_V_OK) throw ssl_verification_failed(res);

View File

@@ -10,25 +10,6 @@
#ifndef PCSC_HXX #ifndef PCSC_HXX
#define PCSC_HXX #define PCSC_HXX
#ifndef PCSC_LOG
//! Declare PCSC_LOG before #include in your de, if you want logging.
/*! PCSC_LOG passes its argument to a stream, so your definition must
behave so that the argument can be streamed.
Example, use std::log:
@code
#define PCSC_LOG(x) std::clog<<x<<" ("<<__PRETTY_FUNCTION__<<')'<<std::endl
#include <pcsc.hxx>
@endcode
Example, use qDebug():
@code
#define PCSC_LOG(x) qDebug()<<x
#include <pcsc.hxx>
@endcode */
#define PCSC_LOG(x) // if unset, do nothing
#endif
#include <cryptaux.hxx> #include <cryptaux.hxx>
#include <mrw/shared.hxx> #include <mrw/shared.hxx>
@@ -132,7 +113,9 @@ namespace pcsc {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class exception: public std::exception { class exception: public std::exception {
public: public:
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {} exception(const std::string& reason) throw(): _what("pcsc: "+reason) {
CRYPTOLOG("ERROR: "<<what());
}
~exception() throw() {} ~exception() throw() {}
const char* what() const throw() { const char* what() const throw() {
return _what.c_str(); return _what.c_str();
@@ -144,21 +127,28 @@ namespace pcsc {
class not_implemented: public exception { class not_implemented: public exception {
public: public:
not_implemented(const std::string& reason) throw(): not_implemented(const std::string& reason) throw():
exception("feature is not implemented:\n"+reason) { exception("feature is not implemented: "+reason) {
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class access_error: public exception { class access_error: public exception {
public: public:
access_error(const std::string& reason) throw(): access_error(const std::string& reason) throw():
exception("smardcard access error:\n"+reason) { exception("smardcard access error: "+reason) {
}
};
//----------------------------------------------------------------------------
class wrong_pin: public access_error {
public:
wrong_pin(const std::string& reason) throw():
access_error("wrong pin: "+reason) {
} }
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class runtime_error: public exception { class runtime_error: public exception {
public: public:
runtime_error(const std::string& reason, const std::string& data) throw(): runtime_error(const std::string& reason, const std::string& data) throw():
exception("runtime error,\n"+reason+":\n"+crypto::hex(data)) {} exception("runtime error, "+reason+": "+crypto::hex(data)) {}
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class neesting_error: public exception { class neesting_error: public exception {
@@ -216,10 +206,12 @@ namespace pcsc {
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(mrw::Shared<Reader> r): _reader(r), _running(true) {
CRYPTOLOG("log");
_reader->beginTransaction(); _reader->beginTransaction();
} }
//! Cancels the transaction if not yet finished. //! Cancels the transaction if not yet finished.
~Transaction() try { ~Transaction() try {
CRYPTOLOG("log");
end(); end();
} catch (...) { } catch (...) {
if (!std::uncaught_exception()) throw; if (!std::uncaught_exception()) throw;
@@ -247,6 +239,7 @@ namespace pcsc {
//! Disconnects connection. //! Disconnects connection.
~Reader() { ~Reader() {
CRYPTOLOG("Disconnect Reader");
_state = SCardDisconnect(_id, SCARD_RESET_CARD); _state = SCardDisconnect(_id, SCARD_RESET_CARD);
if (!std::uncaught_exception()) if (!std::uncaught_exception())
_connection->check("disconnect smartcard"); _connection->check("disconnect smartcard");
@@ -328,13 +321,13 @@ namespace pcsc {
SCARD_IO_REQUEST rPci; SCARD_IO_REQUEST rPci;
rPci.dwProtocol = pci()->dwProtocol; rPci.dwProtocol = pci()->dwProtocol;
rPci.cbPciLength = sizeof(rPci); rPci.cbPciLength = sizeof(rPci);
// don't log; could log pins // log only in verbose debuggung; could log pins
//PCSC_LOG("SCardTransmit: "<<crypto::hex(in)); CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in));
check(SCardTransmit(_id, &rPci, check(SCardTransmit(_id, &rPci,
(unsigned char*)in.c_str(), in.size(), (unsigned char*)in.c_str(), in.size(),
0, buff, &len), 0, buff, &len),
"smartcard transmit message "+crypto::hex(in)); "smartcard transmit message "+crypto::hex(in));
//PCSC_LOG(" -> "<<crypto::hex(std::string((char*)buff, len))); //CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
return std::string((char*)buff, len); return std::string((char*)buff, len);
} }
@@ -346,13 +339,13 @@ namespace pcsc {
std::string in) { std::string in) {
DWORD len(256); // arbitrary DWORD len(256); // arbitrary
UCHAR dataBuffer[256]; UCHAR dataBuffer[256];
PCSC_LOG("SCardControl: "<<"Command: "<<controlCode); CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode);
PCSC_LOG(" -> "<<crypto::hex(in)); CRYPTOLOG(" -> "<<crypto::hex(in));
check(SCardControl(_id, controlCode, check(SCardControl(_id, controlCode,
(unsigned char*)in.c_str(), in.size(), (unsigned char*)in.c_str(), in.size(),
dataBuffer, sizeof(dataBuffer), &len), dataBuffer, sizeof(dataBuffer), &len),
"smartcard control message sent"); "smartcard control message sent");
PCSC_LOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len))); CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
return std::string((char*)dataBuffer, len); return std::string((char*)dataBuffer, len);
} }
@@ -387,9 +380,11 @@ namespace pcsc {
/*! Calls @c SCardBeginTransaction unless it's already inside /*! Calls @c SCardBeginTransaction unless it's already inside
a transaction. */ a transaction. */
void beginTransaction() { void beginTransaction() {
if (++_neesting==1) if (++_neesting==1) {
CRYPTOLOG("open transaction");
check(SCardBeginTransaction(_id), "smartcard begin transaction"); check(SCardBeginTransaction(_id), "smartcard begin transaction");
} }
}
//! Use scoped transactions with @ref Transaction //! Use scoped transactions with @ref Transaction
/*! Calls @c SCardEndTransaction if it's inside a transaction. /*! Calls @c SCardEndTransaction if it's inside a transaction.
@@ -397,10 +392,11 @@ namespace pcsc {
@throws neesting_error if there are more calls to @c @throws neesting_error if there are more calls to @c
endTransaction than to @c beginTransaction. */ endTransaction than to @c beginTransaction. */
void endTransaction() { void endTransaction() {
if (--_neesting==0) if (--_neesting==0) {
CRYPTOLOG("close transaction");
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), check(SCardEndTransaction(_id, SCARD_LEAVE_CARD),
"smartcard end transaction"); "smartcard end transaction");
else if (_neesting<0) { } else if (_neesting<0) {
_neesting = 0; _neesting = 0;
throw neesting_error(); throw neesting_error();
} }
@@ -432,6 +428,7 @@ namespace pcsc {
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) {
CRYPTOLOG("Connect Reader");
check(SCardConnect(_connection->id(), strconv(name).c_str(), check(SCardConnect(_connection->id(), strconv(name).c_str(),
mode, protocol, mode, protocol,
&_id, &_protocol), &_id, &_protocol),
@@ -513,7 +510,7 @@ namespace pcsc {
&num), &num),
"smartcard get size of readers of groups "+grp)) "smartcard get size of readers of groups "+grp))
return res; return res;
PCSC_LOG("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 (!check(SCardListReaders(_connectionlifetime->id(),
@@ -521,9 +518,9 @@ namespace pcsc {
nm.get(), &num), nm.get(), &num),
"smartcard list reader names of groups "+grp)) "smartcard list reader names of groups "+grp))
return res; return res;
PCSC_LOG("got all readers, size is "<<num); CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res; if (!num) return res;
PCSC_LOG("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 = split(strconv(string(nm.get(), num-1)));
} }
@@ -620,10 +617,12 @@ namespace pcsc {
ConnectionLifetime(Scope s, bool exc): ConnectionLifetime(Scope s, bool exc):
_exc(exc), _id(0), _exc(exc), _id(0),
_state(SCardEstablishContext(s, 0, 0, &_id)) { _state(SCardEstablishContext(s, 0, 0, &_id)) {
CRYPTOLOG("Open Connection");
check("establish smartcard context"); check("establish smartcard context");
} }
//! Closes the connection (releases the smartcard context) //! Closes the connection (releases the smartcard context)
~ConnectionLifetime() { ~ConnectionLifetime() {
CRYPTOLOG("Close Connection");
_state = SCardReleaseContext(_id); _state = SCardReleaseContext(_id);
if (!std::uncaught_exception()) check("smartcard release context"); if (!std::uncaught_exception()) check("smartcard release context");
} }
@@ -641,7 +640,13 @@ namespace pcsc {
bool check(const std::string& context="") { bool check(const std::string& context="") {
if (_exc&&!*this) if (_exc&&!*this)
if (context.size()) if (context.size())
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(context+": "+error());
else
throw access_error(context+": "+error()); throw access_error(context+": "+error());
else
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(error());
else else
throw access_error(error()); throw access_error(error());
return *this; return *this;
@@ -721,8 +726,8 @@ namespace pcsc {
ss<<"The smart card resource manager has shut down."; ss<<"The smart card resource manager has shut down.";
break; break;
case SCARD_E_SHARING_VIOLATION: case SCARD_E_SHARING_VIOLATION:
ss<<"The smart card cannot be accessed because of other outstanding" ss<<"The smart card cannot be accessed because of other"
<<" connections."; <<" outstanding connections.";
break; break;
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"
@@ -757,8 +762,8 @@ namespace pcsc {
ss<<"No error was encountered."; ss<<"No error was encountered.";
break; break;
case SCARD_W_REMOVED_CARD: case SCARD_W_REMOVED_CARD:
ss<<"The smart card has been removed, so that further communication" ss<<"The smart card has been removed, so that further"
<<" is not possible."; <<" communication is not possible.";
break; break;
case SCARD_W_RESET_CARD: case SCARD_W_RESET_CARD:
ss<<"The smart card was reset."; ss<<"The smart card was reset.";

View File

@@ -82,19 +82,29 @@ namespace suisseid {
public: public:
enum Status { enum CertStatus {
TRANSPORT MISSING,
EXPIRES_SOON,
EXPIRED,
REVOKED,
VALID
}; };
public: public:
Card(mrw::Shared<pcsc::Connection::Reader> reader, Card(mrw::Shared<pcsc::Connection::Reader> reader,
mrw::Shared<cryptoki::Slot> slot): const cryptoki::Library& cryptoki):
cardos::Commands(reader), cardos::Commands(reader),
_slot(slot) { _cryptoki(cryptoki) {
} }
virtual ~Card() {} virtual ~Card() {}
cryptoki::Slot slot() {
cryptoki::SlotList slots(_cryptoki.slotList(true, name()));
if (slots.size()==1) return slots[0];
throw std::runtime_error("matching cryptoki slot not found");
}
virtual unsigned int minimalPinLength() = 0; virtual unsigned int minimalPinLength() = 0;
virtual unsigned int maximalPinLength() = 0; virtual unsigned int maximalPinLength() = 0;
@@ -108,22 +118,27 @@ namespace suisseid {
return "<unknown>"; return "<unknown>";
} }
private: /// status of the certificates on the card
virtual CertStatus certStatus() {
return MISSING;
}
mrw::Shared<cryptoki::Slot> _slot; protected:
cryptoki::Library _cryptoki;
}; };
//! Instance of a Post SuisseID smartcard. //! Instance of a Post SuisseID smartcard.
/*! A SuisseID card issued by Swiss Post. /*! A SuisseID card issued by Swiss Post.
@see http://postsuisseid.ch */ @see http://postsuisseid.ch */
class PostSuisseID: public Card { class Post: public Card {
public: public:
PostSuisseID(mrw::Shared<pcsc::Connection::Reader> reader, Post(mrw::Shared<pcsc::Connection::Reader> reader,
mrw::Shared<cryptoki::Slot> slot): const cryptoki::Library& cryptoki):
Card(reader, slot), _minPinLen(0), _maxPinLen(-1) { Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) {
} }
virtual unsigned int minimalPinLength() { virtual unsigned int minimalPinLength() {
@@ -136,15 +151,18 @@ namespace suisseid {
return _maxPinLen; return _maxPinLen;
} }
std::string version() { virtual std::string version() {
if (_version.size()) return _version; // cache the version if (_version.size()) return _version; // cache the version
pcsc::Connection::Reader::Transaction lock(_reader); return versionFromMFFile("5649");
try {
selectMfFile("5649");
return _version = cardos::BerValue(readBinary())[0].value();
} catch (...) {
return _version = "<unknown>";
} }
virtual CertStatus certStatus() {
cryptoki::Session session(slot());
cryptoki::ObjectList certs
(session.find(cryptoki::Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)));
if (certs.size()==0) return MISSING;
return VALID;
} }
private: private:
@@ -163,6 +181,16 @@ namespace suisseid {
} }
} }
std::string versionFromMFFile(const std::string& file) {
pcsc::Connection::Reader::Transaction lock(_reader);
try {
selectMfFile(file);
return _version = cardos::BerValue(readBinary())[0].value();
} catch (...) {
return _version = "<unknown>";
}
}
private: private:
std::string _version; // version is cached std::string _version; // version is cached
@@ -221,6 +249,7 @@ namespace suisseid {
/// 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() {
CRYPTOLOG("log");
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
@@ -230,7 +259,7 @@ namespace suisseid {
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 PostSuisseID(_pcsc.reader(*reader), slots[0]))); (new Post(_pcsc.reader(*reader), _cryptoki)));
} }
return res; return res;
} }
@@ -242,6 +271,159 @@ namespace suisseid {
}; };
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;
};
} }
//@} //@}