From 885cb0f0fe4c83fa2dbb8b371f5093343679eda6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Wed, 6 Nov 2013 12:24:52 +0000 Subject: [PATCH] Added all SuisseID Functionality except certificate import from server, which shall remain closed; refs #28 --- configure.in | 5 +- debian/control | 14 + debian/rules | 4 +- doc/examples/cryptoki-sign-demo.cxx | 2 +- doc/examples/makefile.am | 10 +- doc/examples/openssl-engine-demo.cxx | 4 +- doc/examples/suisse-id-demo.cxx | 84 +++- doc/examples/suisse-id-demo.hxx | 100 +++++ src/cardos.hxx | 477 ++++++--------------- src/cryptaux.hxx | 51 +++ src/cryptoki.cxx | 52 +-- src/cryptoki.hxx | 602 +++++++++++++++------------ src/makefile.am | 14 +- src/openssl-engine.hxx | 79 ++-- src/openssl.hxx | 276 ++++++------ src/pcsc.hxx | 87 ++-- src/suisseid.hxx | 222 +++++++++- 17 files changed, 1157 insertions(+), 926 deletions(-) create mode 100644 doc/examples/suisse-id-demo.hxx diff --git a/configure.in b/configure.in index 8509aa7..5f65f8a 100644 --- a/configure.in +++ b/configure.in @@ -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])], diff --git a/debian/control b/debian/control index 33f9021..fbecfe9 100644 --- a/debian/control +++ b/debian/control @@ -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 diff --git a/debian/rules b/debian/rules index a295da3..8ed8c7e 100755 --- a/debian/rules +++ b/debian/rules @@ -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 diff --git a/doc/examples/cryptoki-sign-demo.cxx b/doc/examples/cryptoki-sign-demo.cxx index 6af72d8..35749fe 100644 --- a/doc/examples/cryptoki-sign-demo.cxx +++ b/doc/examples/cryptoki-sign-demo.cxx @@ -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(CKO_PRIVATE_KEY), id); diff --git a/doc/examples/makefile.am b/doc/examples/makefile.am index e2b75bc..524effd 100644 --- a/doc/examples/makefile.am +++ b/doc/examples/makefile.am @@ -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 diff --git a/doc/examples/openssl-engine-demo.cxx b/doc/examples/openssl-engine-demo.cxx index 0cd52ec..cb267c3 100644 --- a/doc/examples/openssl-engine-demo.cxx +++ b/doc/examples/openssl-engine-demo.cxx @@ -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"; } }; diff --git a/doc/examples/suisse-id-demo.cxx b/doc/examples/suisse-id-demo.cxx index 014b51e..01c9ead 100644 --- a/doc/examples/suisse-id-demo.cxx +++ b/doc/examples/suisse-id-demo.cxx @@ -5,14 +5,10 @@ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 -#include - +#include #include -#include -#include 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 { <name()<version()<minimalPinLength() - <<" - "<<(*card)->maximalPinLength()<name()<version()<minimalPinLength() + <<" - "<<(*card)->maximalPinLength()<pkcs15PinRetries()<sigGPinRetries()<transportPinRetries()<pukRetries()<slot()); + cryptoki::Session::Info info(session.getsessioninfo()); + std::cout<<" Session:"<(CKO_CERTIFICATE))); + std::cout<<" Certificates: "<>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"< SuisseID is bad"<>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?"< +#include +#include + +class TextualCycle: public suisseid::StatusCycle { + + public: + + TextualCycle(mrw::Shared 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!"<>pin; + if (pin=="x") { + std::cout<slot()); + try { + session.login(pin); + } catch (const cryptoki::wrong_pin& x) { + std::cout<<"**** Wrong PIN!"<_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 { @@ -360,41 +301,6 @@ namespace cardos { unsigned char _length; std::string _value; std::vector _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); - // } - // } - // } }; @@ -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 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 file’s 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) { - try { - changePkcs15Pin(newPin, 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 { - 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="<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 "" 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 _reader; - - }; - + } //@} diff --git a/src/cryptaux.hxx b/src/cryptaux.hxx index f113c36..318184c 100644 --- a/src/cryptaux.hxx +++ b/src/cryptaux.hxx @@ -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__< +# 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: "< +# 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: "<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(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 = "< #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 #include @@ -61,24 +58,6 @@ " __FILE__ ":" CRYPTOKI_QUOTE(__LINE__) #endif #endif -#ifndef CRYPTOKI_LOG - #include - #if __GNUC__ >= 2 - //! Cryptoki Logging - /*! If you want to change cryptoki logging mechanism, just - redefine your own CRYPTOKI_LOG macro before #include - <cryptoki.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define CRYPTOKI_LOG(X) std::clog<#include - <cryptoki.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define CRYPTOKI_LOG(X) std::clog< 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; + typedef std::multimap 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: "<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), - CRYPTOKI_FN_LOG("C_CloseSession")); + slots().insert(std::make_pair(_slot._slot, _session)); + } + + //! calls @c C_CloseSession if it's the last session + void close() { + CRYPTOLOG("references: "<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, 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: "<_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,89 +1189,133 @@ 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), - CRYPTOKI_FN_LOG("C_GetSessionInfo")); + 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 ""; + } } - @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, + 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, - (CK_CHAR*)pin.c_str(), - pin.size()), - CRYPTOKI_FN_LOG("C_Login")); + _session.check(_session._slot._library->C_Login + (_session._session, userType, + (CK_CHAR*)pin.c_str(), + pin.size()), + CRYPTOKI_FN_LOG("C_Login")); } ~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: "< _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 { - _login.reset(); - } catch (...) { - _login.reset(); - throw; - } - } + CRYPTOLOG("log"); + _login.reset(); + } - mrw::Shared _login; + mrw::Shared _login; /*! @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; 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, 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()?¶m[0]:0, param.size() }; - CRYPTOKI_LOG("decryptinit: type="<_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 "<_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 "<_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 "<_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 "<_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*)¶m[0]:0, param.size() }; - CRYPTOKI_LOG("encryptinit: type="<_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 "<_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()?¶m[0]:0, param.size() }; - CRYPTOKI_LOG("signinit: type="<_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()?¶m[0]:0, param.size() }; - CRYPTOKI_LOG("verifyinit: type="<_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; diff --git a/src/makefile.am b/src/makefile.am index fb4d7ec..37a05f4 100644 --- a/src/makefile.am +++ b/src/makefile.am @@ -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 diff --git a/src/openssl-engine.hxx b/src/openssl-engine.hxx index adff922..2eafa7e 100644 --- a/src/openssl-engine.hxx +++ b/src/openssl-engine.hxx @@ -7,6 +7,9 @@ #ifndef __OPENSSL_ENGINE_HXX__ #define __OPENSSL_ENGINE_HXX__ + +#include + #include #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: "< - #if __GNUC__ >= 2 - //! Openssl Logging - /*! If you want to change openssl logging mechanism, just - redefine your own OPENSSL_LOG macro before #include - <openssl.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define OPENSSL_LOG(X) std::clog<#include - <openssl.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define OPENSSL_LOG(X) std::clog<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="<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(); diff --git a/src/openssl.hxx b/src/openssl.hxx index 26ccc67..a026363 100644 --- a/src/openssl.hxx +++ b/src/openssl.hxx @@ -60,26 +60,6 @@ namespace pcsc { std::string version(); } -#ifndef OPENSSL_LOG - #include - #if __GNUC__ >= 2 - //! Openssl Logging - /*! If you want to change openssl logging mechanism, just - redefine your own OPENSSL_LOG macro before #include - <openssl.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define OPENSSL_LOG(X) std::clog<#include - <openssl.hxx>. Define it empty for no logging at - all. By default logs to std::clog. */ - #define OPENSSL_LOG(X) std::clog<()); 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(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); diff --git a/src/pcsc.hxx b/src/pcsc.hxx index 9d94962..58eec68 100644 --- a/src/pcsc.hxx +++ b/src/pcsc.hxx @@ -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< - @endcode - - Example, use qDebug(): - @code - #define PCSC_LOG(x) qDebug()< - @endcode */ -#define PCSC_LOG(x) // if unset, do nothing -#endif - #include #include @@ -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: "< 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: "< "< "< "< "< "< "<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: "< 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 "< reader, - mrw::Shared 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 ""; } - private: + /// status of the certificates on the card + virtual CertStatus certStatus() { + return MISSING; + } + + protected: - mrw::Shared _slot; + 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 reader, - mrw::Shared slot): - Card(reader, slot), _minPinLen(0), _maxPinLen(-1) { + Post(mrw::Shared reader, + const cryptoki::Library& cryptoki): + Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) { } virtual unsigned int minimalPinLength() { @@ -136,17 +151,20 @@ 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 = ""; - } + return versionFromMFFile("5649"); } - + + virtual CertStatus certStatus() { + cryptoki::Session session(slot()); + cryptoki::ObjectList certs + (session.find(cryptoki::Attribute(CKA_CLASS) + .from(CKO_CERTIFICATE))); + if (certs.size()==0) return MISSING; + return VALID; + } + private: void evaluatePinLengths() { @@ -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 = ""; + } + } + 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 - (new PostSuisseID(_pcsc.reader(*reader), slots[0]))); + (new Post(_pcsc.reader(*reader), _cryptoki))); } return res; } @@ -241,6 +270,159 @@ namespace suisseid { cryptoki::Library _cryptoki; }; + + class StatusCycle { + + public: + + StatusCycle(mrw::Shared card, unsigned int maxRetries = 20): + _card(card), _maxRetries(maxRetries), _counter(0) { + } + + ~StatusCycle() {} + + bool run() { + CRYPTOLOG("log"); + _counter = 0; + return start(); + } + + protected: + + mrw::Shared 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; + unsigned int _maxRetries; + unsigned int _counter; + + }; } //@}