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}\"'"
# Get rid of that stupid -O2 -g opions!
# Get rid of that stupid -O2 -g options!
CXXFLAGS="${CXXFLAGS:-}"
# languages
@@ -93,6 +93,9 @@ AC_CHECK_PROG(have_doxygen, doxygen, yes, no)
AC_CHECK_PROG(have_dot, dot, yes, no)
PKG_PROG_PKG_CONFIG
# libraries
#PKG_CHECK_MODULES([QT], [QtNetwork])
AC_ARG_ENABLE(pedantic,
[AS_HELP_STRING([--enable-pedantic],
[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
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
Package: libpcscxx

4
debian/rules vendored
View File

@@ -40,7 +40,7 @@ endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
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"
@@ -89,7 +89,7 @@ binary-arch: install
# dh_installinfo
# dh_installman
dh_link
dh_strip
dh_strip --dbg-package=libpcscxx-dbg
dh_compress
dh_fixperms
# dh_perl

View File

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

View File

@@ -3,6 +3,7 @@
## 1 2 3 4 5 6 7 8
## 45678901234567890123456789012345678901234567890123456789012345678901234567890
noinst_HEADERS = suisse-id-demo.hxx
noinst_PROGRAMS = pcsc-demo cryptoki-sign-demo cryptoki-demo \
openssl-tcp-demo openssl-ssl-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_ssl_demo_SOURCES = openssl-ssl-demo.cxx
openssl_engine_demo_SOURCES = openssl-engine-demo.cxx
suisse_id_demo_SOURCES = suisse-id-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

View File

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

View File

@@ -5,14 +5,10 @@
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <suisseid.hxx>
#include <suisse-id-demo.hxx>
#include <mrw/args.hxx>
#include <stdexcept>
#include <iostream>
int main(int argc, char** argv) try {
std::string lib("libcvP11.so");
mrw::args::parse(argc, argv,
"Sign a text (optionally several times for performance"
@@ -23,13 +19,77 @@ int main(int argc, char** argv) try {
<<mrw::args::param(lib, "lib")));
suisseid::Cards cards(suisseid::Scanner(lib).scan());
for (suisseid::Cards::iterator card(cards.begin()); card!=cards.end(); ++card)
std::cout<<"Found SuisseID:"<<std::endl
for (suisseid::Cards::iterator card(cards.begin());
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
<<" Version: "<<(*card)->version()<<std::endl
<<" 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;
} 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
#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
namespace cardos {
/// @defgroup gcardos C++ Access to Siemens CardOS V4.4
@@ -42,38 +41,40 @@ namespace cardos {
//----------------------------------------------------------------------------
class wrong_pin: public exception {
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 {
public:
user_pin_locked(const std::string& s) throw():
exception("user pin locked\n"+s) {}
exception("user pin locked "+s) {}
};
//----------------------------------------------------------------------------
class wrong_puk: public exception {
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 {
public:
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():
exception("wrong result,\n"+reason) {}
exception("wrong result, "+reason) {}
};
//----------------------------------------------------------------------------
class runtime_error: public exception {
public:
runtime_error(const std::string& reason) throw():
exception("runtime error, "+reason) {}
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 {
public:
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)) {}
};
//----------------------------------------------------------------------------
@@ -81,8 +82,8 @@ namespace cardos {
public:
card_transmission_failed(const std::string& position,
const std::string& reason) throw():
exception("transmission to card failed:\n"+position
+"\nreason:\n"+reason) {
exception("transmission to card failed: "+position
+" reason: "+reason) {
}
};
//----------------------------------------------------------------------------
@@ -90,8 +91,8 @@ namespace cardos {
public:
wrong_dataformat(const std::string& data,
const std::string& reason) throw():
exception("wrong dataformat:\n"+crypto::hex(data)
+"\nreason:\n"+reason) {
exception("wrong dataformat: "+crypto::hex(data)
+" 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 {
public:
enum Class {
@@ -361,41 +302,6 @@ namespace cardos {
std::string _value;
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
@@ -439,11 +345,7 @@ namespace cardos {
//@{
/// Implements CardOS V4.4 commands.
/** 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. */
/** Directly sends CardOS V4.4 commands to a smart card using APDUs. */
class Commands {
public:
@@ -452,9 +354,9 @@ namespace cardos {
/// @name Setup Smart Card Reader
//@{
/// Uninitialized class, use @ref reader to setup assign smart card reader.
Commands() {
}
/// Uninitialized class
/** Use @ref reader to setup assign smart card reader. */
Commands() {}
/// Initialize with given smart card reader.
Commands(mrw::Shared<pcsc::Connection::Reader> reader):
@@ -484,6 +386,7 @@ namespace cardos {
the security status of the current DF. The command
cannot be applied to CODE files. */
void activateFile() {
CRYPTOLOG("log");
check(send(0x00, 0x44, 0x00, 0x00));
}
@@ -532,13 +435,15 @@ namespace cardos {
@see freeTransactionBuffer */
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));
}
//! Free transaction buffer
/*! @see allocateTransactionBuffer */
void freeTransactionBuffer(unsigned char id) {
CRYPTOLOG("log");
check(send(0x80, 0x12, 0x00, id));
}
@@ -587,6 +492,7 @@ namespace cardos {
referenced by the files AC APPEND is granted in the
security status of the current DF. */
void appendRecord(unsigned char efId, std::string data) {
CRYPTOLOG("log");
check(send(0x00, 0xE2, 0x00, efId, data));
}
@@ -654,12 +560,14 @@ namespace cardos {
@return Digital Signature */
std::string cardAuthenticate(bool hashInclIdentNum,
std::string systemChallange) {
CRYPTOLOG("log");
return check(send(0x80, 0x88, hashInclIdentNum?0x01:0x02, 0x00,
systemChallange));
}
//! Changes the object data of any BS object except for PIN TEST objects
void changeKeyData() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -667,17 +575,21 @@ namespace cardos {
/** Changes a PIN. */
void changeReferenceData(unsigned char id, std::string newData,
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
//! provided with the command.
void changeSystemKey() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Creates a file (only EF or DF)
void createFile(BerValue) {
CRYPTOLOG("log");
// check(send(0x00, 0xE0, 0x00, 0x00, BerValue(0x62h,
// data).raw()));
assert(!"not implemented");
@@ -685,16 +597,19 @@ namespace cardos {
//! Deactivates a file or a file tree
void deactivateFile() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Decreases a record value
void decrease() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Deletes a file (DF or EF)
void deleteFile() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -702,21 +617,25 @@ namespace cardos {
//! Reads file information of EFs and/or DFs in the current DF
BerValue directory(FileTypes types, unsigned char offset=0) {
CRYPTOLOG("log");
return BerValue(check(send(0x80, 0x16, types, offset)));
}
//! Enables an already loaded and activated but disabled license package.
void enablePackage() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Erases the file system in the EEPROM.
void eraseFiles() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Performs a challenge/response test
void externalAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -724,26 +643,31 @@ namespace cardos {
//! ADMINISTRATION after creation of the MF or changes only from
//! MANUFACTURING to INITIALIZATION.
void format() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Generates a key pair for the RSA/RSA2 algorithms within the card
void generateKeyPair() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Generates an internal random number (i.e. SC_Challenge)
void getChallange() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Reads system information
std::string getData(unsigned char mode) {
CRYPTOLOG("log");
return check(send(0x00, 0xCA, 0x01, mode));
}
//! Product name, version, release date, copyright string
std::string getDataProductName() {
CRYPTOLOG("log");
return getData(0x80);
}
@@ -755,6 +679,7 @@ namespace cardos {
//! Chip production data as supplied by Infineon, PROM area
ChipProductionData getDataChipProduction() {
CRYPTOLOG("log");
std::string code(getData(0x81));
ChipProductionData res = {
code.substr(8, 8),
@@ -781,6 +706,7 @@ namespace cardos {
The external random number is stored in the XRAM of the
smart card. */
void giveRandom(std::string random) {
CRYPTOLOG("log");
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)
- other value → rfu */
std::string increase(unsigned char efId=0, unsigned short size=1) {
CRYPTOLOG("log");
std::string data;
data.resize(2);
data[0] = size>>8;
@@ -803,32 +730,38 @@ namespace cardos {
//! Manufacturer use only
void initializeEeprom() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Manufacturer use only
void initializeEnd() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Performs cryptographic algorithms for authentication
void internalAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Activates a package
void loadExecutable() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Opens or closes a logical channel
std::string manageChannel(unsigned char mode, unsigned char channelId) {
CRYPTOLOG("log");
return check(send(0x00, 0x70, mode, channelId));
}
//! Loads a CSE (RESTORE) or sets a component of the CSE (SET)
//! and/or sets an extended headerlist
void manageSecureEnvironment() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -836,21 +769,25 @@ namespace cardos {
//! MAC/Signature calculation and, depending on the input, a
//! session key derivation.
void mutualAuthenticate() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Performs a cryptographic operation
void performSecurityOperation() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Controls the command sequence transactions
void performTransactonOperation() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Personalizer use only
void personalize() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -882,16 +819,19 @@ namespace cardos {
@prereq The command can be executed in the life cycle phases
ADMINISTRATION and OPERATIONAL. */
void phaseControl() {
CRYPTOLOG("log");
check(send(0x80, 0x10, 0x00, 0x00));
}
//! Installs / administrates / overwrites different objects
void putData() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Read a BINARY file
std::string readBinary(unsigned short offset = 0) {
CRYPTOLOG("log");
return check(send(0x00, 0xB0, offset>>8, offset&0xFF));
}
@@ -908,12 +848,15 @@ namespace cardos {
std::string readRecord(unsigned char record = 0,
unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log");
return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode));
}
/// Read all records from a record oriented file
BerValues readBerFile() {
CRYPTOLOG("log");
BerValues content;
pcsc::Connection::Reader::Transaction lock(_reader);
while (true) {
std::string res(send(0x00, 0xB2, 0, NEXT_RECORD));
if (cardos::Commands::retCode(res)!=0x9000) break;
@@ -924,11 +867,13 @@ namespace cardos {
//! Resets the error counter of a BS object to its maximum
void resetRetryCounter() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Resets the security status of the current DF
void resetSecurityCounter() {
CRYPTOLOG("log");
assert(!"not implemented");
}
@@ -954,6 +899,7 @@ namespace cardos {
= DF_OR_EF_USING_PATH_FROM_MF,
FileSelectionReturn ret
= RETURN_NOTHING) {
CRYPTOLOG("log");
return BerValue(check(send(0x00, 0xA4, mode, ret, file)));
}
@@ -961,32 +907,38 @@ namespace cardos {
//! the effective Command Data Field Length / Response Data
//! Field Length.
void setDataFieldLength() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Enables or disables the usage of an existing transaction buffer
void setTransactionState() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Signs a hashed input using a decryption key with the RSA_SIG
//! algorithm.
void signByDecryptionKey() {
CRYPTOLOG("log");
assert(!"not implemented");
}
//! Uninstalls a package of the smart card
void uninstallPackage() {
CRYPTOLOG("log");
assert(!"not implemented");
}
/// Read the previously file from smart card
std::string readBinFile() {
CRYPTOLOG("log");
return check(send(0x00, 0xB0, 0x00, 0x00));
}
//! Updates a BINARY file
void updateBinary(std::string data, unsigned short offset=0) {
CRYPTOLOG("log");
check(send(0x00, 0xD6, offset>>8, offset&0xFF, data));
}
@@ -995,6 +947,7 @@ namespace cardos {
unsigned char record = 0,
unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log");
return check(send(0x00, 0xDC, record, (sfi&0xF8)|mode, data));
}
@@ -1006,12 +959,14 @@ namespace cardos {
//! Performs a PIN test (CHV test)
void verify(std::string pin, unsigned char id,
VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log");
check(send(0x00, 0x20, 0x00, id|mode, pin));
}
//! Performs a PIN test (CHV test)
/*! @return number of remaining PIN retries or -1 if PIN is locked */
int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log");
std::string res(send(0x00, 0x20, 0x00, id|mode));
unsigned int value((((unsigned int)(unsigned char)res[0])*256)
+((unsigned int)(unsigned char)res[1]));
@@ -1036,7 +991,7 @@ namespace cardos {
}
/// Path to SigG (Signaturgesetz)
std::string sigg() {
std::string sigG() {
return crypto::hexToBin("1fff");
}
@@ -1068,24 +1023,32 @@ namespace cardos {
/// Logon with transport PIN
void logonTransport(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG();
logon(transportPin(), pin);
}
/// Logon with SigG (Signaturgesetz) secure PIN
void logonSigG(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG();
logon(sigGPin(), pin);
}
/// Logon with PKCS#15 user PUK to unlock user PIN
void logonPuk(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF();
logon(puk(), pin);
}
/// Logon with PKCS#15 user PIN
void logonPkcs15(std::string pin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF();
logon(pkcs15Pin(), pin);
}
@@ -1095,18 +1058,24 @@ namespace cardos {
transport PIN and then the card is unlocked and the
transport state is unset. */
void changeSigGPin(std::string newPin, std::string oldPin) {
selectSigG();
CRYPTOLOG("log");
if (transportState()) { // first time use, reset transport state
pcsc::Connection::Reader::Transaction lock(_reader);
logonTransport(oldPin);
changeReferenceData(sigGPin(), newPin);
unsetTransportState();
} else { // ordinary PIN change
pcsc::Connection::Reader::Transaction lock(_reader);
logonSigG(oldPin);
selectSigG();
changeReferenceData(sigGPin(), newPin, oldPin);
}
}
/// Change PKCS#15 user PIN
void changePkcs15Pin(std::string newPin, std::string oldPin) {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF();
changeReferenceData(pkcs15Pin(), newPin, oldPin);
}
@@ -1116,87 +1085,110 @@ namespace cardos {
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
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 {
changePkcs15Pin(newPin, oldPin);
try {
changeSigGPin(newPin, oldPin);
if (sigGPinRetries()!=-1) changeSigGPin(newPin, oldPin);
} catch (...) {
changePkcs15Pin(oldPin, newPin); // undo PKCS#15 PIN change
throw; // change SigG PIN failed
// undo PKCS#15 PIN change
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
void selectPkcs15File(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015"+file)));
}
/// Select a file in the SigG (Signaturgesetz) part on the smart card
void selectSigGFile(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff"+file)));
}
/// Select a file in the MF part on the smart card
void selectMfFile(std::string file) {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f00"+file)));
}
/// Select the PKCS#15 part on the smart card
void selectPkcs15() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f005015")));
}
/// Select the SigG (Signaturgesetz) part on the smart card
void selectSigG() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x08, 0x0C, crypto::hexToBin("3f001fff")));
}
/// Select the MFpart on the smart card
void selectMF() {
CRYPTOLOG("log");
check(send(0x00, 0xA4, 0x00, 0x0C));
}
/// @return binary serial number
std::string serial() {
CRYPTOLOG("log");
return getDataChipProduction().serial;
}
/// @return @c true if card is still in transport state
bool transportState() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigGFile("fe15");
return std::string(4, '\0')==readBinary();
return std::string(4, '\0')==readRecord();
}
/// Mark card as initiakized and no more in transport state
void unsetTransportState() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigGFile("fe15");
increase();
}
/*! @return number of remaining transport PIN retries or -1 if locked */
int transportPinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG();
return verify(transportPin());
}
/*! @return number of remaining PKCS#15 PIN retries or -1 if locked */
int pkcs15PinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF();
return verify(pkcs15Pin());
}
/*! @return number of remaining SigG PIN retries or -1 if locked */
int sigGPinRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectSigG();
return verify(sigGPin());
}
/*! @return number of remaining PUK retries or -1 if locked */
int pukRetries() {
CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader);
selectMF();
return verify(puk());
}
@@ -1240,7 +1232,7 @@ namespace cardos {
else if (data.size()>4)
return send(data[0], data[1], data[2], data[3], data.substr(4));
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
@@ -1316,10 +1308,10 @@ namespace cardos {
return "CLA invalid (Hi nibble)";
case 0x6f00:
return
"Technical Error:\n"
" 1 Attempt to create more than 254 records in a file.\n"
"Technical Error: "
" 1 Attempt to create more than 254 records in a file. "
" 2 Package uses SDK version which is not compatible to"
" API version\n"
" API version "
" 3 Package contains invalid statements (LOAD EXECUTABLE)";
case 0x6f81:
return "File is invalidated because of checksum error (prop.)";
@@ -1342,7 +1334,7 @@ namespace cardos {
return "Transaction buffer too small";
case 0x6fff:
return
"Internal assertion (invalid internal error)\n"
"Internal assertion (invalid internal error) "
"This error is no runtime error but an internal error which can"
" occur because of a programming error only.";
case 0x9000:
@@ -1384,7 +1376,8 @@ namespace cardos {
std::string check(std::string 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);
}
@@ -1410,7 +1403,7 @@ namespace cardos {
}
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)
<<" ins="<<crypto::binToHex(ins)
<<" p1="<<crypto::binToHex(p1)
@@ -1420,7 +1413,7 @@ namespace cardos {
}
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)
<<" ins="<<crypto::binToHex(ins)
<<" 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 */
//@{
#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
namespace crypto {

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,9 @@
#ifndef __OPENSSL_ENGINE_HXX__
#define __OPENSSL_ENGINE_HXX__
#include <cryptaux.hxx>
#include <openssl/opensslv.h>
#ifndef OPENSSL_VERSION_NUMBER
# 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());}
#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
//@{
@@ -75,56 +60,56 @@ namespace openssl {
public:
Engine(): _e(ENGINE_new()) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
}
virtual ~Engine() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
OPENSSL_CHECK(ENGINE_free(_e));
}
virtual const char* id() = 0;
virtual const char* name() = 0;
virtual int init() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual int finish() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual int ctrl(int, long, void*, void(*)()) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual int cmd() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual EVP_PKEY* pubkey(const char*, UI_METHOD*, void*) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 0;
}
virtual EVP_PKEY* privkey(const char*, UI_METHOD*, void*) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 0;
}
virtual int rsaEncrypt() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual int rsaDecrypt() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual std::string rsaSign(const std::string&, unsigned int) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
throw std::runtime_error("rsaSign not implemented");
}
virtual int rsaVerify() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
virtual int rsaFinish() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
@@ -140,7 +125,7 @@ namespace openssl {
public:
static void add(Engine *e) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
_prototypes[e->id()] = e;
_map[e->_e] = e;
OPENSSL_CHECK(ENGINE_set_id(e->_e, e->id()));
@@ -176,43 +161,43 @@ namespace openssl {
private:
static int destroy(ENGINE* e) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
return 1;
}
static int init(ENGINE* e) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->init():0;
}
static int finish(ENGINE* e) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->finish():0;
}
static int ctrl(ENGINE* e, int cmd, long i, void* p, void(*f)()) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(e));
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) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(e));
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) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->privkey(c, u, d):0;
}
static int rsaEncrypt(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));
return it!=_map.end()?it->second->rsaEncrypt():0;
}
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));
return it!=_map.end()?it->second->rsaDecrypt():0;
}
@@ -221,32 +206,32 @@ namespace openssl {
unsigned char *to,
unsigned int*tlen,
const RSA *rsa) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine));
if (it==_map.end()) return 0;
try {
std::string res(it->second->rsaSign
(std::string((const char*)from, flen),
type));
OPENSSL_LOG("to="<<(void*)to<<"; len="<<*tlen);
OPENSSL_LOG("siglen="<<res.size());
CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen);
CRYPTOLOG("siglen="<<res.size());
*tlen = res.size();
std::copy(res.begin(), res.end(), to);
return 1;
} catch (const std::exception& e) {
OPENSSL_LOG("ERROR: "<<e.what());
CRYPTOLOG("ERROR: "<<e.what());
return 0;
}
}
static int rsaVerify(int, const unsigned char*,
unsigned int, OPENSSL_V0_CONST unsigned char*,
unsigned int, const RSA* rsa) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaVerify():0;
}
static int rsaFinish(RSA *rsa) {
OPENSSL_LOG("log");
CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaFinish():0;
}
@@ -254,7 +239,7 @@ namespace openssl {
protected:
static RSA_METHOD* rsa() {
OPENSSL_LOG("log");
CRYPTOLOG("log");
static RSA_METHOD ops;
if (!ops.rsa_priv_enc) {
ops = *RSA_get_default_method();

View File

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

View File

@@ -10,25 +10,6 @@
#ifndef 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 <mrw/shared.hxx>
@@ -132,7 +113,9 @@ namespace pcsc {
//----------------------------------------------------------------------------
class exception: public std::exception {
public:
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {}
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {
CRYPTOLOG("ERROR: "<<what());
}
~exception() throw() {}
const char* what() const throw() {
return _what.c_str();
@@ -144,21 +127,28 @@ namespace pcsc {
class not_implemented: public exception {
public:
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 {
public:
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 {
public:
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 {
@@ -216,10 +206,12 @@ namespace pcsc {
destructor und must therefore live longer than the
Transaction instance. */
Transaction(mrw::Shared<Reader> r): _reader(r), _running(true) {
CRYPTOLOG("log");
_reader->beginTransaction();
}
//! Cancels the transaction if not yet finished.
~Transaction() try {
CRYPTOLOG("log");
end();
} catch (...) {
if (!std::uncaught_exception()) throw;
@@ -247,6 +239,7 @@ namespace pcsc {
//! Disconnects connection.
~Reader() {
CRYPTOLOG("Disconnect Reader");
_state = SCardDisconnect(_id, SCARD_RESET_CARD);
if (!std::uncaught_exception())
_connection->check("disconnect smartcard");
@@ -328,13 +321,13 @@ namespace pcsc {
SCARD_IO_REQUEST rPci;
rPci.dwProtocol = pci()->dwProtocol;
rPci.cbPciLength = sizeof(rPci);
// don't log; could log pins
//PCSC_LOG("SCardTransmit: "<<crypto::hex(in));
// log only in verbose debuggung; could log pins
CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in));
check(SCardTransmit(_id, &rPci,
(unsigned char*)in.c_str(), in.size(),
0, buff, &len),
"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);
}
@@ -346,13 +339,13 @@ namespace pcsc {
std::string in) {
DWORD len(256); // arbitrary
UCHAR dataBuffer[256];
PCSC_LOG("SCardControl: "<<"Command: "<<controlCode);
PCSC_LOG(" -> "<<crypto::hex(in));
CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode);
CRYPTOLOG(" -> "<<crypto::hex(in));
check(SCardControl(_id, controlCode,
(unsigned char*)in.c_str(), in.size(),
dataBuffer, sizeof(dataBuffer), &len),
"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);
}
@@ -387,9 +380,11 @@ namespace pcsc {
/*! Calls @c SCardBeginTransaction unless it's already inside
a transaction. */
void beginTransaction() {
if (++_neesting==1)
if (++_neesting==1) {
CRYPTOLOG("open transaction");
check(SCardBeginTransaction(_id), "smartcard begin transaction");
}
}
//! Use scoped transactions with @ref 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
endTransaction than to @c beginTransaction. */
void endTransaction() {
if (--_neesting==0)
if (--_neesting==0) {
CRYPTOLOG("close transaction");
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD),
"smartcard end transaction");
else if (_neesting<0) {
} else if (_neesting<0) {
_neesting = 0;
throw neesting_error();
}
@@ -432,6 +428,7 @@ namespace pcsc {
DWORD mode=SCARD_SHARE_SHARED,
DWORD protocol=SCARD_PROTOCOL_T1):
name(nm), _connection(c) {
CRYPTOLOG("Connect Reader");
check(SCardConnect(_connection->id(), strconv(name).c_str(),
mode, protocol,
&_id, &_protocol),
@@ -513,7 +510,7 @@ namespace pcsc {
&num),
"smartcard get size of readers of groups "+grp))
return res;
PCSC_LOG("size of readers: "<<num);
CRYPTOLOG("size of readers: "<<num);
if (!num) return res;
std::auto_ptr<char_t> nm(new char_t[num]);
if (!check(SCardListReaders(_connectionlifetime->id(),
@@ -521,9 +518,9 @@ namespace pcsc {
nm.get(), &num),
"smartcard list reader names of groups "+grp))
return res;
PCSC_LOG("got all readers, size is "<<num);
CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res;
PCSC_LOG("list of readers: "
CRYPTOLOG("list of readers: "
<<crypto::readable(std::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):
_exc(exc), _id(0),
_state(SCardEstablishContext(s, 0, 0, &_id)) {
CRYPTOLOG("Open Connection");
check("establish smartcard context");
}
//! Closes the connection (releases the smartcard context)
~ConnectionLifetime() {
CRYPTOLOG("Close Connection");
_state = SCardReleaseContext(_id);
if (!std::uncaught_exception()) check("smartcard release context");
}
@@ -641,7 +640,13 @@ namespace pcsc {
bool check(const std::string& context="") {
if (_exc&&!*this)
if (context.size())
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(context+": "+error());
else
throw access_error(context+": "+error());
else
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(error());
else
throw access_error(error());
return *this;
@@ -721,8 +726,8 @@ namespace pcsc {
ss<<"The smart card resource manager has shut down.";
break;
case SCARD_E_SHARING_VIOLATION:
ss<<"The smart card cannot be accessed because of other outstanding"
<<" connections.";
ss<<"The smart card cannot be accessed because of other"
<<" outstanding connections.";
break;
case SCARD_E_SYSTEM_CANCELLED:
ss<<"The action was cancelled by the system, presumably to log"
@@ -757,8 +762,8 @@ namespace pcsc {
ss<<"No error was encountered.";
break;
case SCARD_W_REMOVED_CARD:
ss<<"The smart card has been removed, so that further communication"
<<" is not possible.";
ss<<"The smart card has been removed, so that further"
<<" communication is not possible.";
break;
case SCARD_W_RESET_CARD:
ss<<"The smart card was reset.";

View File

@@ -82,19 +82,29 @@ namespace suisseid {
public:
enum Status {
TRANSPORT
enum CertStatus {
MISSING,
EXPIRES_SOON,
EXPIRED,
REVOKED,
VALID
};
public:
Card(mrw::Shared<pcsc::Connection::Reader> reader,
mrw::Shared<cryptoki::Slot> slot):
const cryptoki::Library& cryptoki):
cardos::Commands(reader),
_slot(slot) {
_cryptoki(cryptoki) {
}
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 maximalPinLength() = 0;
@@ -108,22 +118,27 @@ namespace suisseid {
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.
/*! A SuisseID card issued by Swiss Post.
@see http://postsuisseid.ch */
class PostSuisseID: public Card {
class Post: public Card {
public:
PostSuisseID(mrw::Shared<pcsc::Connection::Reader> reader,
mrw::Shared<cryptoki::Slot> slot):
Card(reader, slot), _minPinLen(0), _maxPinLen(-1) {
Post(mrw::Shared<pcsc::Connection::Reader> reader,
const cryptoki::Library& cryptoki):
Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) {
}
virtual unsigned int minimalPinLength() {
@@ -136,15 +151,18 @@ namespace suisseid {
return _maxPinLen;
}
std::string version() {
virtual std::string version() {
if (_version.size()) return _version; // cache the version
pcsc::Connection::Reader::Transaction lock(_reader);
try {
selectMfFile("5649");
return _version = cardos::BerValue(readBinary())[0].value();
} catch (...) {
return _version = "<unknown>";
return versionFromMFFile("5649");
}
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:
@@ -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:
std::string _version; // version is cached
@@ -221,6 +249,7 @@ namespace suisseid {
/// Scan for available known SuisseID cards on the system.
/** @return List of detected SuisseID smart cards. */
Cards scan() {
CRYPTOLOG("log");
Cards res;
// By now, scan only for PostSuisseID; in future use factory pattern
pcsc::Connection::Strings readers
@@ -230,7 +259,7 @@ namespace suisseid {
cryptoki::SlotList slots(_cryptoki.slotList(true, *reader));
if (slots.size()==1)
res.push_back(dynamic_cast<Card*>
(new PostSuisseID(_pcsc.reader(*reader), slots[0])));
(new Post(_pcsc.reader(*reader), _cryptoki)));
}
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;
};
}
//@}