From 3012a6c5ede90b3274fdb9ee019ffc38c3d0ea33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20W=C3=A4ckerlin?= Date: Tue, 1 Apr 2014 13:10:51 +0000 Subject: [PATCH] fixed tons of warnings; refs #28 --- doc/examples/cardos-demo.cxx | 5 +- doc/examples/create-files-demo.cxx | 6 +- doc/examples/cryptoki-demo.cxx | 14 +- doc/examples/cryptoki-sign-demo.cxx | 11 +- src/cardos.hxx | 175 ++++----- src/cryptaux.hxx | 11 +- src/cryptoki.cxx | 23 +- src/cryptoki.hxx | 536 ++++++++++++++-------------- src/openssl-engine.hxx | 62 +++- src/openssl.hxx | 74 ++-- src/overview.doc | 2 +- src/pcsc.hxx | 24 +- src/suisseid.hxx | 36 +- 13 files changed, 543 insertions(+), 436 deletions(-) diff --git a/doc/examples/cardos-demo.cxx b/doc/examples/cardos-demo.cxx index 77864ca..47401c8 100644 --- a/doc/examples/cardos-demo.cxx +++ b/doc/examples/cardos-demo.cxx @@ -104,9 +104,8 @@ class Commands: public cardos::Commands { void selectReader() { listReader(); - if (_readers.size()<0) return; - int num(-1); - if (std::cin>>num && num>=0 && num<_readers.size()) { + pcsc::Connection::Strings::size_type num(0); + if (std::cin>>num && num<_readers.size()) { _reader = pcsc::Connection::reader(_readers[num]); std::cout<<"Active Reader: "<<_readers[num]< #include -pcsc::Connection::Strings readers; - void list() { pcsc::Connection::Strings readers(pcsc::Connection::scan()); std::cout<<"Found "<attributes()); - for (cryptoki::AttributeMap::iterator it(attrs.begin()); - it!=attrs.end(); ++it) { - std::cout<<" - attribute: "<second.name()<<" = "<second.value, 15, 5)<attributes()); + for (cryptoki::AttributeMap::iterator it3(attrs.begin()); + it3!=attrs.end(); ++it3) { + std::cout<<" - attribute: "<second.name()<<" = "<second.value, 15, 5)<(CKO_CERTIFICATE))); - for (cryptoki::ObjectList::iterator c(certs.begin()); c!=certs.end(); ++c) { - std::string label(c->attribute(CKA_LABEL).value); + for (cryptoki::ObjectList::iterator it(certs.begin()); + it!=certs.end(); ++it) { + std::string label(it->attribute(CKA_LABEL).value); if (cert.size()&&cert!=label) continue; - cryptoki::Attribute id(c->attribute(CKA_ID)); + cryptoki::Attribute id(it->attribute(CKA_ID)); cryptoki::ObjectList keys (session.find(cryptoki::Attribute(CKA_CLASS) .from(CKO_PUBLIC_KEY), id)); if (!keys.size()) continue; std::cout<<"Found Certificate: " - <attribute(CKA_LABEL).value<attribute(CKA_LABEL).value<& values): - _tag(tag), _sequence(values) { + BerValue(unsigned char t, const std::vector& vs): + _tag(t), _sequence(vs) { if (!isContainer()) - throw runtime_error("BER tag 0x"+crypto::binToHex(tag) + throw runtime_error("BER tag 0x"+crypto::binToHex(_tag) +" is not a container"); } @@ -227,7 +227,7 @@ namespace cardos { return tagPC()==CONSTRUCTED; } - unsigned int size() { + std::vector::size_type size() { return _sequence.size(); } @@ -235,7 +235,7 @@ namespace cardos { return _tag; } - BerValue operator[](unsigned int i) { + BerValue operator[](std::vector::size_type i) { if (i>=_sequence.size()) throw array_range(i, _sequence.size()); return _sequence[i]; } @@ -424,13 +424,13 @@ namespace cardos { Commands() {} /// Initialize with given smart card reader. - Commands(pcsc::shared_ptr::t reader): - _reader(reader) { + Commands(pcsc::shared_ptr::t r): + _reader(r) { } /// Set smart card reader. - void reader(pcsc::shared_ptr::t reader) { - _reader = reader; + void reader(pcsc::shared_ptr::t r) { + _reader = r; } //@} @@ -446,10 +446,10 @@ namespace cardos { will not return an error, if the current file is already active. - @prereq The command can only be executed, if the right - referenced by the file’s AC ACTIVATE is granted in - the security status of the current DF. The command - cannot be applied to CODE files. */ + @pre The command can only be executed, if the right + referenced by the file’s AC ACTIVATE is granted in 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)); @@ -480,10 +480,8 @@ namespace cardos { - - - + @@ -493,8 +491,8 @@ namespace cardos {
Bytes P1-P2
P1 (MODE)P2Meaning
Bit 7Bits 6 – 0
Bit 7Bits 6 – 0
1HI valueLO value Allocate buffer with size HI-LO
- @prereq The command can only be executed, if the right - referenced by the MF’s AC ALLOCATE is granted. + @pre The command can only be executed, if the right + referenced by the MF’s AC ALLOCATE is granted. @returns 1 byte: ID of allocated buffer @@ -502,7 +500,8 @@ namespace cardos { std::string allocateTransactionBuffer(unsigned short size) { CRYPTOLOG("log"); if (size>0x7FFF) throw runtime_error("requested buffer too large"); - return check(send(0x80, 0x12, 8|size>>8, size&0xFF)); + return check(send(0x80, 0x12, (unsigned char)(8|size>>8), + (unsigned char)(size&0xFF))); } //! Free transaction buffer @@ -553,9 +552,9 @@ namespace cardos { the record consists of one byte. The tag byte is not interpreted by APPEND RECORD. - @prereq The command can only be executed, if the right - referenced by the file’s AC APPEND is granted in the - security status of the current DF. */ + @pre The command can only be executed, if the right + 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)); @@ -577,7 +576,7 @@ namespace cardos { - the number of loaded Packages (s. GET DATA command, mode 88h) - the system internal parameters (9 bytes consisting 22h) and - optionally, the Chip Unique Identification Number - (as indicated in mode byte P1, @refs getData, mode 81h, + (as indicated in mode byte P1, @ref getData, mode 81h, Bytes 11-16). The commands supports 2 modes indicated by the parameter P1: @@ -594,28 +593,37 @@ namespace cardos { chapter 2.4.2.4 - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +
Format of the input for hash value calculation
System_ChallengeCommand Header
CLA INS P1 P2
Global Life Cycle PhaseInternal ParametersNumber of loaded PackagesChip Unique Identification Number (opt.)
xxh…xxh80h 88h Mode 00hxxh22h…22hxxhxxh…xxh
n bytes4 bytes1 byte9 bytes1 byte6 bytes/empty
Format of the input for hash value calculation
System_ChallengeCommand Header
CLA INS P1 P2
Global Life Cycle PhaseInternal ParametersNumber of loaded PackagesChip Unique Identification Number (opt.)
xxh…xxh80h 88h Mode 00hxxh22h…22hxxhxxh…xxh
n bytes4 bytes1 byte9 bytes1 byte6 bytes/empty
- @prereq The System_Challenge provided by the application - must be greater or equal to 16 bytes. Since the - command does not support chaining, the length of the - System_Challenge is limited by the IO buffer size. + @pre The System_Challenge provided by the application must + be greater or equal to 16 bytes. Since the command + does not support chaining, the length of the + System_Challenge is limited by the IO buffer size. @note The application must use the corresponding RSA2 public key to verify the Digital Signature received from the @@ -653,7 +661,7 @@ namespace cardos { } //! Creates a file (only EF or DF) - void createFile(std::string path="", const std::string data="") { + void createFile(std::string /*path*/="", const std::string& /*data*/="") { CRYPTOLOG("log"); // pcsc::Connection::Reader::Transaction lock(_reader); // if (path.size()) select(path); @@ -818,8 +826,8 @@ namespace cardos { CRYPTOLOG("log"); std::string data; data.resize(2); - data[0] = size>>8; - data[1] = size&0xff; + data[0] = char((unsigned char)(size>>8)); + data[1] = char((unsigned char)(size&0xff)); return check(send(0x80, 0x32, 0x00, efId, data)); // 0x08 or 0x80? // old code was 0x80, manual says 0x08 (manual exactly says: "8xh") } @@ -907,13 +915,13 @@ namespace cardos { can also be undone (without reset) with another PHASE CONTROL command. - @prereq Changing from ADMINISTRATION to OPERATIONAL is not - protected. Changing from OPERATIONAL to - ADMINISTRATION is controlled by the right referenced - by the current DF’s AC LCYCLE. + @pre Changing from ADMINISTRATION to OPERATIONAL is not + protected. Changing from OPERATIONAL to ADMINISTRATION + is controlled by the right referenced by the current + DF’s AC LCYCLE. - @prereq The command can be executed in the life cycle phases - ADMINISTRATION and OPERATIONAL. */ + @pre The command can be executed in the life cycle phases + ADMINISTRATION and OPERATIONAL. */ void phaseControl() { CRYPTOLOG("log"); check(send(0x80, 0x10, 0x00, 0x00)); @@ -930,7 +938,8 @@ namespace cardos { CRYPTOLOG("log"); pcsc::Connection::Reader::Transaction lock(_reader); if (path.size()) select(path); - return check(send(0x00, 0xB0, offset>>8, offset&0xFF)); + return check(send(0x00, 0xB0, (unsigned char)(offset>>8), + (unsigned char)(offset&0xFF))); } enum ReadRecordMode { @@ -950,7 +959,8 @@ namespace cardos { CRYPTOLOG("log"); pcsc::Connection::Reader::Transaction lock(_reader); if (path.size()) select(path); - return check(send(0x00, 0xB2, record, (sfi&0xF8)|mode)); + return check(send(0x00, 0xB2, record, + (unsigned char)((sfi&0xF8)|mode))); } /// Read all records from a record oriented file @@ -1042,7 +1052,8 @@ namespace cardos { //! Updates a BINARY file void updateBinary(std::string data, unsigned short offset=0) { CRYPTOLOG("log"); - check(send(0x00, 0xD6, offset>>8, offset&0xFF, data)); + check(send(0x00, 0xD6, (unsigned char)(offset>>8), + (unsigned char)(offset&0xFF), data)); } //! Overwrites an existing record. @@ -1051,7 +1062,8 @@ namespace cardos { unsigned char sfi = 0, ReadRecordMode mode = ABSOLUTE_RECORD) { CRYPTOLOG("log"); - return check(send(0x00, 0xDC, record, (sfi&0xF8)|mode, data)); + return check(send(0x00, 0xDC, record, + (unsigned char)((sfi&0xF8)|mode), data)); } enum VerifyMode { @@ -1063,14 +1075,14 @@ namespace cardos { void verify(std::string pin, unsigned char id, VerifyMode mode = SEARCH_FROM_DF) { CRYPTOLOG("log"); - check(send(0x00, 0x20, 0x00, id|mode, pin)); + check(send(0x00, 0x20, 0x00, (unsigned char)(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)); + std::string res(send(0x00, 0x20, 0x00, (unsigned char)(id|mode))); unsigned int value((((unsigned int)(unsigned char)res[0])*256) +((unsigned int)(unsigned char)res[1])); if ((value&0x63C0)==0x63C0) return value&0x0F; @@ -1511,7 +1523,9 @@ namespace cardos { return result; } - std::string send(char cla, char ins, char p1, char p2, std::string lc) { + std::string send(unsigned char cla, unsigned char ins, + unsigned char p1, unsigned char p2, + std::string lc) { if (!_reader) throw runtime_error("no reader selected"); CARDOS_LOG("APDU: cla="< + (reinterpret_cast + (dlsym(_lib, "C_GetFunctionList")))); #else - CK_C_GetFunctionList fn + CK_C_GetFunctionList fnl ((CK_C_GetFunctionList)GetProcAddress(_lib, "C_GetFunctionList")); #endif - if (!fn) + if (!fnl) throw exception("required library symbol C_GetFunctionList not found in " +library); CRYPTOLOG("Got C_GetFunctionList, now call it"); //! calls @c C_GetFunctionList - return check(fn(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList")); + return check(fnl(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList")); } bool Library::Init::check(CK_RV result, const std::string& context) { _res = result; - if (_exc && !*this) - if (context.size()) + if (_exc && !*this) { + if (context.size()) { if (_res==CKR_PIN_INCORRECT) throw wrong_pin(context+": "+error()); else throw access_error(context+": "+error()); - else + } else { if (_res==CKR_PIN_INCORRECT) throw wrong_pin(error()); else throw access_error(error()); + } + } return _res==CKR_OK; } @@ -344,7 +349,7 @@ namespace cryptoki { attrs.push_back(Attribute(CKA_SECONDARY_AUTH).from(FALSE)); attrs.push_back(Attribute(CKA_DECRYPT) // Required by Doujak/Inverardi .from(usage&(X509v3_KU_DATA_ENCIPHERMENT - |usage&X509v3_KU_KEY_ENCIPHERMENT) + |(usage&X509v3_KU_KEY_ENCIPHERMENT)) ?TRUE:FALSE)); // instead of CKA_UNWRAP attrs.push_back(Attribute(CKA_SIGN) .from(usage&(X509v3_KU_DIGITAL_SIGNATURE diff --git a/src/cryptoki.hxx b/src/cryptoki.hxx index e74973a..f471a38 100644 --- a/src/cryptoki.hxx +++ b/src/cryptoki.hxx @@ -54,7 +54,7 @@ #if __GNUC__ >= 2 //! Cryptoki Error Message Formatting /*! If you want to change cryptoki error formatting, just - redefine your own CRYPTOKY_FN_LOG macro before #include + redefine your own CRYPTOKY_FN_LOG macro before \#include <cryptoki.hxx>. #return std::String */ #define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \ @@ -64,19 +64,15 @@ #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 + redefine your own CRYPTOKY_FN_LOG macro before \#include <cryptoki.hxx>. - #return std::String */ + @return string */ #define CRYPTOKI_FN_LOG(X) X " failed in \ " __FILE__ ":" CRYPTOKI_QUOTE(__LINE__) #endif #endif //@} -namespace pcsc { - std::string version(); -} - //! @ref gcryptoki @copydoc gcryptoki namespace cryptoki { @@ -261,7 +257,7 @@ namespace cryptoki { std::string res(indent, ' '); switch (type) { case CKA_CLASS: - switch (*((CK_OBJECT_CLASS*)&value[0])) { + switch (*((const CK_OBJECT_CLASS*)&value[0])) { case CKO_DATA: return res+"DATA"; case CKO_CERTIFICATE: return res+"CERTIFICATE"; case CKO_PUBLIC_KEY: return res+"PUBLIC_KEY"; @@ -279,7 +275,7 @@ namespace cryptoki { /** To use this method, you must know what type the attribute represents. */ template Attribute& from(const TYPE& v) { - value = std::string((char*)&v, sizeof(TYPE)); + value = std::string((const char*)&v, sizeof(TYPE)); return *this; } /// Convert to a given type. @@ -1107,9 +1103,9 @@ namespace cryptoki { shared library. Normally you need only one instance. @param library name of the shared library that supports pkcs#11 - @param exc wether exceptions should be thrown */ - Library(const std::string& library, bool exc=true): - _init(new Init(library, exc)) { + @param exceptions whether exceptions should be thrown */ + Library(const std::string& library, bool exceptions=true): + _init(new Init(library, exceptions)) { CRYPTOLOG("log"); } @@ -1545,7 +1541,8 @@ namespace cryptoki { public: //! Opens a new session. - /*! @param slot slot to open a session on */ + /*! @param slot slot to open a session on + @param rw whether session is read/write or read only*/ Session(const Slot& slot, bool rw=false): _slot(slot), _session(0), _res(CKR_OK) { CRYPTOLOG("log"); @@ -1553,8 +1550,7 @@ namespace cryptoki { //! @todo pass parameter } - //! Opens a new session. - /*! @param slot slot to open a session on */ + //! Copy session. Session(const Session& o): _slot(o._slot), _session(o._session), _res(CKR_OK) { CRYPTOLOG("log"); @@ -1822,6 +1818,26 @@ namespace cryptoki { CRYPTOKI_FN_LOG("C_GetSessionInfo")); return info; } + + /*! @todo Not implemented: + @code + bool seedrandom() { + CRYPTOLOG("log"); + //! calls @c C_SeedRandom + return check(_slot.library()->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG), + CRYPTOKI_FN_LOG("C_SeedRandom")); + } + @endcode */ + + /*! @todo Not implemented: + @code + bool setpin() { + CRYPTOLOG("log"); + //! calls @c C_SetPIN + return check(_slot.library()->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG), + CRYPTOKI_FN_LOG("C_SetPIN")); + } + @endcode */ /*! @todo Not implemented: @code @@ -1833,6 +1849,13 @@ namespace cryptoki { } @endcode */ + //@} + + /** @name login with pin + + Unlock access with pin (login) and unlock after use (logout). */ + //@{ + private: class Login { @@ -1846,8 +1869,8 @@ namespace cryptoki { //! calls @c C_Login _session.check(_session._slot.library()->C_Login (_session._session, userType, - (CK_CHAR*)pin.c_str(), - pin.size()), + const_cast((const CK_CHAR*)pin.c_str()), + (int)pin.size()), CRYPTOKI_FN_LOG("C_Login")); } @@ -1874,37 +1897,26 @@ namespace cryptoki { public: - void login(const std::string& pin, CK_USER_TYPE userType=CKU_USER) { + /// Login to card + /** @param pin to unlock card + @param userType user type */ + void login(const std::string& pin, + CK_USER_TYPE userType=CKU_USER) { CRYPTOLOG("log"); _login = new Login(*this, pin, userType); } - + + /// Logout from card + /** Undo the last login. */ void logout() { CRYPTOLOG("log"); _login.reset(); } mrw::Shared _login; - - /*! @todo Not implemented: - @code - bool seedrandom() { - CRYPTOLOG("log"); - //! calls @c C_SeedRandom - return check(_slot.library()->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG), - CRYPTOKI_FN_LOG("C_SeedRandom")); - } - @endcode */ - /*! @todo Not implemented: - @code - bool setpin() { - CRYPTOLOG("log"); - //! calls @c C_SetPIN - return check(_slot.library()->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG), - CRYPTOKI_FN_LOG("C_SetPIN")); - } - @endcode */ + //@} + }; class Object { @@ -1985,6 +1997,218 @@ namespace cryptoki { //! @todo don't call verifyfinal()? } + bool destroy() { + CRYPTOLOG("log"); + //! calls @c C_DestroyObject + return check(_session._slot.library()->C_DestroyObject + (_session._session, _object), + CRYPTOKI_FN_LOG("C_DestroyObject")); + } + + //! Get a Single Attribute + Attribute operator[](CK_ATTRIBUTE_TYPE a) { + CRYPTOLOG("log"); + return attribute(a); + } + + //! Get a Single Attribute + Attribute attribute(CK_ATTRIBUTE_TYPE a) { + 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), + CRYPTOKI_FN_LOG("C_GetAttributeValue")) + || !(long)attr.ulValueLen>0l) + //! Without exception handling, size and type must be checked too. + return res; + 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), + CRYPTOKI_FN_LOG("C_GetAttributeValue"))) + /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open + Cryptoki. From the Specs: «In the special case + of an attribute whose value is an array of + attributes, for example CKA_WRAP_TEMPLATE, where + it is passed in with pValue not NULL, then if + the pValue of elements within the array is + NULL_PTR then the ulValueLen of elements within + the array will be set to the required length. If + the pValue of elements within the array is not + NULL_PTR, then the ulValueLen element of + attributes within the array must reflect the + space that the corresponding pValue points to, + and pValue is filled in if there is sufficient + room. Therefore it is important to initialize + the contents of a buffer before calling + C_GetAttributeValue to get such an array + value. If any ulValueLen within the array isn't + large enough, it will be set to -1 and the + function will return CKR_BUFFER_TOO_SMALL, as it + does if an attribute in the pTemplate argument + has ulValueLen too small. Note that any + attribute whose value is an array of attributes + is identifiable by virtue of the attribute type + having the CKF_ARRAY_ATTRIBUTE bit set.» */ + res = Attribute(attr); + else + free(attr.pValue); + } catch (...) { + free(attr.pValue); + throw; + } + return res; + } + + //! Get a List of Attributes. + /*! If @c attrs is empty, all available attributes are + returned. Attributes that cannot be accessed or that are not + available in this Object won't be in the result map. There + is no exception in this case. */ + AttributeMap attributes(AttributeTypeList attrs + = AttributeTypeList()) { + CRYPTOLOG("log"); + AttributeMap res; + //! Gets all attributes, if @c attrs is empty + if (attrs.empty()) { + attrs.push_back(CKA_CLASS); + attrs.push_back(CKA_TOKEN); + attrs.push_back(CKA_PRIVATE); + attrs.push_back(CKA_LABEL); + attrs.push_back(CKA_APPLICATION); + attrs.push_back(CKA_VALUE); + attrs.push_back(CKA_OBJECT_ID); + attrs.push_back(CKA_CERTIFICATE_TYPE); + attrs.push_back(CKA_ISSUER); + attrs.push_back(CKA_SERIAL_NUMBER); + attrs.push_back(CKA_AC_ISSUER); + attrs.push_back(CKA_OWNER); + attrs.push_back(CKA_ATTR_TYPES); + attrs.push_back(CKA_TRUSTED); + attrs.push_back(CKA_KEY_TYPE); + attrs.push_back(CKA_SUBJECT); + attrs.push_back(CKA_ID); + attrs.push_back(CKA_SENSITIVE); + attrs.push_back(CKA_ENCRYPT); + attrs.push_back(CKA_DECRYPT); + attrs.push_back(CKA_WRAP); + attrs.push_back(CKA_UNWRAP); + attrs.push_back(CKA_SIGN); + attrs.push_back(CKA_SIGN_RECOVER); + attrs.push_back(CKA_VERIFY); + attrs.push_back(CKA_VERIFY_RECOVER); + attrs.push_back(CKA_DERIVE); + attrs.push_back(CKA_START_DATE); + attrs.push_back(CKA_END_DATE); + attrs.push_back(CKA_MODULUS); + attrs.push_back(CKA_MODULUS_BITS); + attrs.push_back(CKA_PUBLIC_EXPONENT); + attrs.push_back(CKA_PRIVATE_EXPONENT); + attrs.push_back(CKA_PRIME_1); + attrs.push_back(CKA_PRIME_2); + attrs.push_back(CKA_EXPONENT_1); + attrs.push_back(CKA_EXPONENT_2); + attrs.push_back(CKA_COEFFICIENT); + attrs.push_back(CKA_PRIME); + attrs.push_back(CKA_SUBPRIME); + attrs.push_back(CKA_BASE); + attrs.push_back(CKA_PRIME_BITS); + //attrs.push_back(CKA_SUBPRIME_BITS); + attrs.push_back(CKA_VALUE_BITS); + attrs.push_back(CKA_VALUE_LEN); + attrs.push_back(CKA_EXTRACTABLE); + attrs.push_back(CKA_LOCAL); + attrs.push_back(CKA_NEVER_EXTRACTABLE); + attrs.push_back(CKA_ALWAYS_SENSITIVE); + attrs.push_back(CKA_KEY_GEN_MECHANISM); + attrs.push_back(CKA_MODIFIABLE); + attrs.push_back(CKA_ECDSA_PARAMS); + attrs.push_back(CKA_EC_PARAMS); + attrs.push_back(CKA_EC_POINT); + attrs.push_back(CKA_SECONDARY_AUTH); + attrs.push_back(CKA_AUTH_PIN_FLAGS); + attrs.push_back(CKA_HW_FEATURE_TYPE); + attrs.push_back(CKA_RESET_ON_INIT); + attrs.push_back(CKA_HAS_RESET); + attrs.push_back(CKA_VENDOR_DEFINED); + //attrs.push_back(CKA_IBM_OPAQUE); + } + CK_ATTRIBUTE attr; + for (AttributeTypeList::const_iterator it(attrs.begin()); + it!=attrs.end(); ++it) { + attr = CK_ATTRIBUTE{*it, 0, 0}; + try { + //! calls @c C_GetAttributeValue + if (_session._slot.library()->C_GetAttributeValue + (_session._session, _object, &attr, 1) + == CKR_ATTRIBUTE_TYPE_INVALID + || _res == CKR_ATTRIBUTE_SENSITIVE) { + continue; //! Ignores unsupported Attributes. + } else { + check(_res, CRYPTOKI_FN_LOG("C_GetAttributeValue")); + 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), + CRYPTOKI_FN_LOG("C_GetAttributeValue"))) + /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open + Cryptoki. From the Specs: «In the special + case of an attribute whose value is an + array of attributes, for example + CKA_WRAP_TEMPLATE, where it is passed in + with pValue not NULL, then if the pValue + of elements within the array is NULL_PTR + then the ulValueLen of elements within the + array will be set to the required + length. If the pValue of elements within + the array is not NULL_PTR, then the + ulValueLen element of attributes within + the array must reflect the space that the + corresponding pValue points to, and pValue + is filled in if there is sufficient + room. Therefore it is important to + initialize the contents of a buffer before + calling C_GetAttributeValue to get such an + array value. If any ulValueLen within the + array isn't large enough, it will be set + to -1 and the function will return + CKR_BUFFER_TOO_SMALL, as it does if an + attribute in the pTemplate argument has + ulValueLen too small. Note that any + attribute whose value is an array of + attributes is identifiable by virtue of + the attribute type having the + CKF_ARRAY_ATTRIBUTE bit set.» */ + res.insert(std::make_pair(attr.type, Attribute(attr))); + else + free(attr.pValue); + } else if (*it==CKA_MODULUS && attr.ulValueLen==0) { + /*! @bug This is a bug in opensc-pkcs11.so: If + @c CKA_MODULUS has a size of 0 bytes, the + following query to @c CKA_MODULUS_BITS ends + in a segmentation fault. + + @note @c CKA_MODULUS @b must immediately be + followed by @c CKA_MODULUS_BITS in the + attribute list, because if the size of @c + CKA_MODULUS is 0 Bytes, the following + attribute query is skipped as a work around + to this bug. */ + if (++it==attrs.end()) break; + } + } + } catch (...) { + free(attr.pValue); + throw; + } + } + return res; + } + //@} /*! @name C Like Error Handling @@ -2046,13 +2270,15 @@ namespace cryptoki { //! calls @c C_Decrypt check(_session._slot.library()->C_Decrypt (_session._session, - (unsigned char*)&in[0], in.size(), 0, &size), + const_cast((const unsigned char*)&in[0]), + in.size(), 0, &size), CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOLOG("maximum size is "<C_Decrypt (_session._session, - (unsigned char*)&in[0], in.size(), + const_cast((const unsigned char*)&in[0]), + in.size(), (unsigned char*)&res[0], &size), CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOLOG("exact size is "<C_DecryptDigestUpdate (_session._session, - (unsigned char*)&in[0], in.size(), + const_cast((const unsigned char*)&in[0]), in.size(), (unsigned char*)&res[0], &size), CRYPTOKI_FN_LOG("C_DecryptDigestUpdate")); res.resize(size); @@ -2230,7 +2456,6 @@ namespace cryptoki { CRYPTOKI_FN_LOG("C_VerifyUpdate")); } @endcode */ - //@} /*! @todo Not implemented: @code @@ -2243,15 +2468,6 @@ namespace cryptoki { } @endcode */ - bool destroy() { - CRYPTOLOG("log"); - //! calls @c C_DestroyObject - return check(_session._slot.library()->C_DestroyObject - (_session._session, _object), - CRYPTOKI_FN_LOG("C_DestroyObject")); - } - - /*! @todo Not implemented: @code bool digestkey() { @@ -2265,7 +2481,8 @@ namespace cryptoki { bool encryptinit(CK_MECHANISM_TYPE type, const std::string& param) { CRYPTOLOG("log"); CK_MECHANISM mech = { - type, param.size()?(void*)¶m[0]:0, param.size() + type, param.size()?const_cast((const void*)¶m[0]):0, + param.size() }; CRYPTOLOG("encryptinit: type="<C_Encrypt (_session._session, - (unsigned char*)&in[0], in.size(), 0, &size), + const_cast((const unsigned char*)&in[0]), + in.size(), 0, &size), CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOLOG("maximum size is "<C_Encrypt (_session._session, - (unsigned char*)&in[0], in.size(), + const_cast((const unsigned char*)&in[0]), in.size(), (unsigned char*)&res[0], &size), CRYPTOKI_FN_LOG("C_Encrypt")); res.resize(size); @@ -2345,211 +2563,6 @@ namespace cryptoki { } @endcode */ - - //! Get a Single Attribute - Attribute operator[](CK_ATTRIBUTE_TYPE a) { - CRYPTOLOG("log"); - return attribute(a); - } - - //! Get a Single Attribute - Attribute attribute(CK_ATTRIBUTE_TYPE a) { - 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), - CRYPTOKI_FN_LOG("C_GetAttributeValue")) - || !(long)attr.ulValueLen>0l) - //! Without exception handling, size and type must be checked too. - return res; - 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), - CRYPTOKI_FN_LOG("C_GetAttributeValue"))) - /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open - Cryptoki. From the Specs: «In the special case - of an attribute whose value is an array of - attributes, for example CKA_WRAP_TEMPLATE, where - it is passed in with pValue not NULL, then if - the pValue of elements within the array is - NULL_PTR then the ulValueLen of elements within - the array will be set to the required length. If - the pValue of elements within the array is not - NULL_PTR, then the ulValueLen element of - attributes within the array must reflect the - space that the corresponding pValue points to, - and pValue is filled in if there is sufficient - room. Therefore it is important to initialize - the contents of a buffer before calling - C_GetAttributeValue to get such an array - value. If any ulValueLen within the array isn't - large enough, it will be set to -1 and the - function will return CKR_BUFFER_TOO_SMALL, as it - does if an attribute in the pTemplate argument - has ulValueLen too small. Note that any - attribute whose value is an array of attributes - is identifiable by virtue of the attribute type - having the CKF_ARRAY_ATTRIBUTE bit set.» */ - res = Attribute(attr); - else - free(attr.pValue); - } catch (...) { - free(attr.pValue); - throw; - } - return res; - } - - //! Get a List of Attributes. - /*! If @c attrs is empty, all available attributes are - returned. Attributes that cannot be accessed or that are not - available in this Object won't be in the result map. There - is no exception in this case. */ - AttributeMap attributes(AttributeTypeList attrs - = AttributeTypeList()) { - CRYPTOLOG("log"); - AttributeMap res; - //! Gets all attributes, if @c attrs is empty - if (attrs.empty()) { - attrs.push_back(CKA_CLASS); - attrs.push_back(CKA_TOKEN); - attrs.push_back(CKA_PRIVATE); - attrs.push_back(CKA_LABEL); - attrs.push_back(CKA_APPLICATION); - attrs.push_back(CKA_VALUE); - attrs.push_back(CKA_OBJECT_ID); - attrs.push_back(CKA_CERTIFICATE_TYPE); - attrs.push_back(CKA_ISSUER); - attrs.push_back(CKA_SERIAL_NUMBER); - attrs.push_back(CKA_AC_ISSUER); - attrs.push_back(CKA_OWNER); - attrs.push_back(CKA_ATTR_TYPES); - attrs.push_back(CKA_TRUSTED); - attrs.push_back(CKA_KEY_TYPE); - attrs.push_back(CKA_SUBJECT); - attrs.push_back(CKA_ID); - attrs.push_back(CKA_SENSITIVE); - attrs.push_back(CKA_ENCRYPT); - attrs.push_back(CKA_DECRYPT); - attrs.push_back(CKA_WRAP); - attrs.push_back(CKA_UNWRAP); - attrs.push_back(CKA_SIGN); - attrs.push_back(CKA_SIGN_RECOVER); - attrs.push_back(CKA_VERIFY); - attrs.push_back(CKA_VERIFY_RECOVER); - attrs.push_back(CKA_DERIVE); - attrs.push_back(CKA_START_DATE); - attrs.push_back(CKA_END_DATE); - attrs.push_back(CKA_MODULUS); - attrs.push_back(CKA_MODULUS_BITS); - attrs.push_back(CKA_PUBLIC_EXPONENT); - attrs.push_back(CKA_PRIVATE_EXPONENT); - attrs.push_back(CKA_PRIME_1); - attrs.push_back(CKA_PRIME_2); - attrs.push_back(CKA_EXPONENT_1); - attrs.push_back(CKA_EXPONENT_2); - attrs.push_back(CKA_COEFFICIENT); - attrs.push_back(CKA_PRIME); - attrs.push_back(CKA_SUBPRIME); - attrs.push_back(CKA_BASE); - attrs.push_back(CKA_PRIME_BITS); - //attrs.push_back(CKA_SUBPRIME_BITS); - attrs.push_back(CKA_VALUE_BITS); - attrs.push_back(CKA_VALUE_LEN); - attrs.push_back(CKA_EXTRACTABLE); - attrs.push_back(CKA_LOCAL); - attrs.push_back(CKA_NEVER_EXTRACTABLE); - attrs.push_back(CKA_ALWAYS_SENSITIVE); - attrs.push_back(CKA_KEY_GEN_MECHANISM); - attrs.push_back(CKA_MODIFIABLE); - attrs.push_back(CKA_ECDSA_PARAMS); - attrs.push_back(CKA_EC_PARAMS); - attrs.push_back(CKA_EC_POINT); - attrs.push_back(CKA_SECONDARY_AUTH); - attrs.push_back(CKA_AUTH_PIN_FLAGS); - attrs.push_back(CKA_HW_FEATURE_TYPE); - attrs.push_back(CKA_RESET_ON_INIT); - attrs.push_back(CKA_HAS_RESET); - attrs.push_back(CKA_VENDOR_DEFINED); - //attrs.push_back(CKA_IBM_OPAQUE); - } - CK_ATTRIBUTE attr; - for (AttributeTypeList::const_iterator it(attrs.begin()); - it!=attrs.end(); ++it) { - attr = (CK_ATTRIBUTE){*it, 0, 0}; - try { - //! calls @c C_GetAttributeValue - if (_session._slot.library()->C_GetAttributeValue - (_session._session, _object, &attr, 1) - == CKR_ATTRIBUTE_TYPE_INVALID - || _res == CKR_ATTRIBUTE_SENSITIVE) { - continue; //! Ignores unsupported Attributes. - } else { - check(_res, CRYPTOKI_FN_LOG("C_GetAttributeValue")); - 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), - CRYPTOKI_FN_LOG("C_GetAttributeValue"))) - /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open - Cryptoki. From the Specs: «In the special - case of an attribute whose value is an - array of attributes, for example - CKA_WRAP_TEMPLATE, where it is passed in - with pValue not NULL, then if the pValue - of elements within the array is NULL_PTR - then the ulValueLen of elements within the - array will be set to the required - length. If the pValue of elements within - the array is not NULL_PTR, then the - ulValueLen element of attributes within - the array must reflect the space that the - corresponding pValue points to, and pValue - is filled in if there is sufficient - room. Therefore it is important to - initialize the contents of a buffer before - calling C_GetAttributeValue to get such an - array value. If any ulValueLen within the - array isn't large enough, it will be set - to -1 and the function will return - CKR_BUFFER_TOO_SMALL, as it does if an - attribute in the pTemplate argument has - ulValueLen too small. Note that any - attribute whose value is an array of - attributes is identifiable by virtue of - the attribute type having the - CKF_ARRAY_ATTRIBUTE bit set.» */ - res.insert(std::make_pair(attr.type, Attribute(attr))); - else - free(attr.pValue); - } else if (*it==CKA_MODULUS && attr.ulValueLen==0) { - /*! @bug This is a bug in opensc-pkcs11.so: If - @c CKA_MODULUS has a size of 0 bytes, the - following query to @c CKA_MODULUS_BITS ends - in a segmentation fault. - - @note @c CKA_MODULUS @b must immediately be - followed by @c CKA_MODULUS_BITS in the - attribute list, because if the size of @c - CKA_MODULUS is 0 Bytes, the following - attribute query is skipped as a work around - to this bug. */ - if (++it==attrs.end()) break; - } - } - } catch (...) { - free(attr.pValue); - throw; - } - } - return res; - } - /*! @todo Not implemented: @code bool getobjectsize() { @@ -2660,8 +2673,9 @@ namespace cryptoki { } -//! @groupadd cryptokitypes +//! @addtogroup cryptokitypes //@{ + /// Append a cryptoki::Attribute to a cryptoki::AttributeList. inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list, const cryptoki::Attribute& attr) { @@ -2669,6 +2683,7 @@ inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list, list.push_back(attr); return list; } + /// Append a cryptoki::Attribute to a new copy of a cryptoki::AttributeList. inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list, const cryptoki::Attribute& attr) { @@ -2677,6 +2692,7 @@ inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list, res.push_back(attr); return res; } + //@} #endif diff --git a/src/openssl-engine.hxx b/src/openssl-engine.hxx index 8919829..75f3b0a 100644 --- a/src/openssl-engine.hxx +++ b/src/openssl-engine.hxx @@ -38,9 +38,26 @@ #if __GNUC__ >= 2 //! Macro for internal OpenSSL checks. /*! You can define a different implementation in your compile call */ -#define OPENSSL_CHECK(X) if (!(X)) {ERR_load_ENGINE_strings(); std::stringstream ss; for (unsigned int err(0); err=ERR_get_error();) ss<<"Error: "<second->privkey(c, u, d):0; } - static int rsaEncrypt(int flen,const unsigned char *from, + static int rsaEncrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { CRYPTOLOG("log"); Map::iterator it(_map.find(rsa->engine)); - return it!=_map.end()?it->second->rsaEncrypt():0; + if (it==_map.end()) return 0; + try { + std::string res(it->second->rsaEncrypt + (std::string((const char*)from, flen), + padding)); + std::copy(res.begin(), res.end(), to); + return 1; + } catch (const std::exception& e) { + CRYPTOLOG("ERROR: "<engine)); - return it!=_map.end()?it->second->rsaDecrypt():0; + if (it==_map.end()) return 0; + try { + std::string res(it->second->rsaDecrypt + (std::string((const char*)from, flen), + padding)); + std::copy(res.begin(), res.end(), to); + return 1; + } catch (const std::exception& e) { + CRYPTOLOG("ERROR: "<()); + V0_CONST unsigned char* c + ((V0_CONST 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); @@ -1121,13 +1130,13 @@ namespace openssl { try { EVP_PKEY *pkey(0); ::X509 *cert(0); - STACK_OF(X509) *ca(0); - if (!PKCS12_parse(p12, password.c_str(), &pkey, &cert, &ca)) + STACK_OF(X509) *cal(0); + if (!PKCS12_parse(p12, password.c_str(), &pkey, &cert, &cal)) throw pkcs12_parsing_failed(filename); if (pkey) _key = new PrivateKey(pkey); if (cert) _cert = new X509(cert); - for (int i(sk_num(CV_STACK ca)); i>0; --i) - _ca.push_back(new X509((::X509*)sk_pop(CV_STACK ca))); + for (int i(sk_num(CV_STACK cal)); i>0; --i) + _ca.push_back(new X509((::X509*)sk_pop(CV_STACK cal))); PKCS12_free(p12); } catch (...) { PKCS12_free(p12); @@ -1210,7 +1219,8 @@ namespace openssl { //! Read PKCS#7 from memory. PKCS7(const std::string& memory) { CRYPTOLOG("log"); - BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size())); + BIO* mem(BIO_new_mem_buf(const_cast((const void*)memory.data()), + (int)memory.size())); ::PKCS7 *p7(d2i_PKCS7_bio(mem, 0)); BIO_free(mem); if (!p7) throw pkcs7_parsing_failed(); @@ -1327,7 +1337,7 @@ namespace openssl { TCP& write(const std::string& s) { CRYPTOLOG("log"); if (!_bio) throw tcp_closed_connection(); - unsigned int x(BIO_write(_bio, s.begin().operator->(), s.size())); + unsigned int x(BIO_write(_bio, s.begin().operator->(), (int)s.size())); if (x<=0) if (BIO_should_retry(_bio)) return write(s); else { @@ -1432,7 +1442,7 @@ namespace openssl { void verify() { CRYPTOLOG("log"); if (!_ssl) throw ssl_no_connection(); - int res(SSL_get_verify_result(_ssl)); + long res(SSL_get_verify_result(_ssl)); if (res!=X509_V_OK) throw ssl_verification_failed(res); } private: diff --git a/src/overview.doc b/src/overview.doc index ec1b9db..205fc17 100644 --- a/src/overview.doc +++ b/src/overview.doc @@ -21,7 +21,7 @@ For special documentations, such as global overviews and tutorials, please refere to [Pages](pages.html). - @chapter mainoverview Overview of the Components + @section mainoverview Overview of the Components @dot digraph g { diff --git a/src/pcsc.hxx b/src/pcsc.hxx index 5a75d12..1eb17a3 100644 --- a/src/pcsc.hxx +++ b/src/pcsc.hxx @@ -77,10 +77,6 @@ } #endif -namespace pcsc { - std::string version(); -} - /*! @defgroup gpcsc C++ Wrapper around pcsc-lite API This library is a C++ wrapper to the awful pcsc-lite interface. @@ -250,7 +246,7 @@ namespace pcsc { DWORD dummy(0); DWORD s; DWORD len(MAX_ATR_SIZE); - unsigned char a[len]; + unsigned char a[MAX_ATR_SIZE]; check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len), "query smartcard status"); return Status(s, std::string((char*)a, len)); @@ -316,15 +312,17 @@ namespace pcsc { @note Prefer the transmit methods that passes @c cla, @c ins, @c p1 and @c p2 separate.*/ std::string transmit(std::string in) { - DWORD len(1024); // arbitrary - unsigned char buff[len]; + const DWORD bufflen(1024); + DWORD len(bufflen); // arbitrary + unsigned char buff[bufflen]; SCARD_IO_REQUEST rPci; rPci.dwProtocol = pci()->dwProtocol; rPci.cbPciLength = sizeof(rPci); // log only in verbose debuggung; could log pins CRYPTOLOG_VERBOSE("SCardTransmit: "< "< "< "< transportState; @@ -201,7 +201,7 @@ namespace suisseid { } /// Get the reader, needed for example to lock a transaction - /** @begincode + /** @code pcsc::Connection::Reader::Transaction lock(card.reader()); [... do some low level stuff ...] @endcode */ @@ -292,7 +292,7 @@ namespace suisseid { /// @copydoc Card::Card Post(mrw::Shared reader, const cryptoki::Library& cryptoki): - Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) { + Card(reader, cryptoki), _minPinLen(0), _maxPinLen(0) { } virtual unsigned int minimalPinLength() { @@ -301,7 +301,7 @@ namespace suisseid { } virtual unsigned int maximalPinLength() { - if (_maxPinLen==-1) evaluatePinLengths(); + if (_maxPinLen==0) evaluatePinLengths(); return _maxPinLen; } @@ -411,9 +411,12 @@ namespace suisseid { // By now, scan only for PostSuisseID; in future use factory pattern pcsc::Connection::Strings readers (pcsc::Connection::getReadersWithAtr("4b53776973735369676e")); + CRYPTOLOG("number of pcsc-readers: "< (new Post(pcsc::Connection::reader(*reader), @@ -452,7 +455,8 @@ namespace suisseid { /// @name Slots //@{ - + + /// Structure to provide old and new pin struct PinPukChange { std::string oldpin; std::string newpin; @@ -460,49 +464,65 @@ namespace suisseid { return oldpin.size() && newpin.size(); } }; - + + /// Pin change required - get pins from user virtual PinPukChange pinChange() { CRYPTOLOG("log"); return PinPukChange(); } + /// Transport pin change required - get pins from user virtual PinPukChange pinChangeTransportPin() { CRYPTOLOG("log"); return pinChange(); } + /// Puk change required - get pins from user virtual PinPukChange pinChangePuk() { CRYPTOLOG("log"); return pinChange(); } + /// Transport pin locked - you may show an error message virtual void transportPinLocked() { CRYPTOLOG("log"); } + + /// PKCS#15 pin locked - you may show an error message virtual void pkcs15PinLocked() { CRYPTOLOG("log"); } + + /// SigG pin locked - you may show an error message virtual void sigGPinLocked() { CRYPTOLOG("log"); } + + /// Puk locked - you may show an error message virtual void pukLocked() { CRYPTOLOG("log"); } + /// Certificates will expire soon - you may show an error message virtual void certsExpireSoon() { CRYPTOLOG("log"); } + + /// Certificates are expired soon - you may show an error message virtual void certsExpired() { CRYPTOLOG("log"); } + + /// Certificates have been revoked - you may show an error message virtual void certsRevoked() { CRYPTOLOG("log"); } /// install certificates on the card - /** @param bool whether to force reinstallation of existin certificates + /** @param reinstall whether to force reinstallation of existing + certificates @return @c true on success */ - virtual bool installCerts(bool = true) { + virtual bool installCerts(bool reinstall = true) { CRYPTOLOG("log"); return false; }