fixed tons of warnings; refs #28

master
Marc Wäckerlin 11 years ago
parent 9596d5d760
commit 3012a6c5ed
  1. 5
      doc/examples/cardos-demo.cxx
  2. 6
      doc/examples/create-files-demo.cxx
  3. 14
      doc/examples/cryptoki-demo.cxx
  4. 11
      doc/examples/cryptoki-sign-demo.cxx
  5. 175
      src/cardos.hxx
  6. 11
      src/cryptaux.hxx
  7. 23
      src/cryptoki.cxx
  8. 536
      src/cryptoki.hxx
  9. 62
      src/openssl-engine.hxx
  10. 74
      src/openssl.hxx
  11. 2
      src/overview.doc
  12. 24
      src/pcsc.hxx
  13. 36
      src/suisseid.hxx

@ -104,9 +104,8 @@ class Commands: public cardos::Commands {
void selectReader() { void selectReader() {
listReader(); listReader();
if (_readers.size()<0) return; pcsc::Connection::Strings::size_type num(0);
int num(-1); if (std::cin>>num && num<_readers.size()) {
if (std::cin>>num && num>=0 && num<_readers.size()) {
_reader = pcsc::Connection::reader(_readers[num]); _reader = pcsc::Connection::reader(_readers[num]);
std::cout<<"Active Reader: "<<_readers[num]<<std::endl; std::cout<<"Active Reader: "<<_readers[num]<<std::endl;
} else throw std::runtime_error("no valid reader selected"); } else throw std::runtime_error("no valid reader selected");

@ -21,8 +21,6 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
pcsc::Connection::Strings readers;
void list() { void list() {
pcsc::Connection::Strings readers(pcsc::Connection::scan()); pcsc::Connection::Strings readers(pcsc::Connection::scan());
std::cout<<"Found "<<readers.size()<<" readers" std::cout<<"Found "<<readers.size()<<" readers"
@ -34,7 +32,7 @@ void list() {
} }
int main(int argc, char** argv) try { int main(int argc, char** argv) try {
int reader(0); unsigned int reader(0);
std::string pin; std::string pin;
std::string path("3f00"); std::string path("3f00");
std::string id("8888"); std::string id("8888");
@ -62,7 +60,7 @@ int main(int argc, char** argv) try {
<<mrw::args::param(data, "text")) <<mrw::args::param(data, "text"))
); );
pcsc::Connection::Strings readers(pcsc::Connection::scan()); pcsc::Connection::Strings readers(pcsc::Connection::scan());
if (reader<0 || readers.size()<reader) { if (readers.size()<reader) {
std::cerr<<"reader not found: "<<reader<<std::endl; std::cerr<<"reader not found: "<<reader<<std::endl;
return 1; return 1;
} }

@ -75,14 +75,14 @@ int main(int argc, char const*const*const argv) try {
cryptoki::Session session(*it); cryptoki::Session session(*it);
cryptoki::ObjectList objs(session.find()); cryptoki::ObjectList objs(session.find());
std::cout<<"Objects Found: "<<objs.size()<<std::endl; std::cout<<"Objects Found: "<<objs.size()<<std::endl;
for (cryptoki::ObjectList::iterator it(objs.begin()); for (cryptoki::ObjectList::iterator it2(objs.begin());
it!=objs.end(); ++it) { it2!=objs.end(); ++it2) {
std::cout<<"-------------------- Object -----------------"<<std::endl; std::cout<<"-------------------- Object -----------------"<<std::endl;
cryptoki::AttributeMap attrs(it->attributes()); cryptoki::AttributeMap attrs(it2->attributes());
for (cryptoki::AttributeMap::iterator it(attrs.begin()); for (cryptoki::AttributeMap::iterator it3(attrs.begin());
it!=attrs.end(); ++it) { it3!=attrs.end(); ++it3) {
std::cout<<" - attribute: "<<it->second.name()<<" = "<<std::endl std::cout<<" - attribute: "<<it3->second.name()<<" = "<<std::endl
<<crypto::readable(it->second.value, 15, 5)<<std::endl; <<crypto::readable(it3->second.value, 15, 5)<<std::endl;
} }
} }
std::cout<<"**** Success"<<std::endl; std::cout<<"**** Success"<<std::endl;

@ -71,17 +71,18 @@ int main(int argc, char** argv) try {
cryptoki::ObjectList certs cryptoki::ObjectList certs
(session.find(cryptoki::Attribute(CKA_CLASS) (session.find(cryptoki::Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE))); .from<CK_OBJECT_CLASS>(CKO_CERTIFICATE)));
for (cryptoki::ObjectList::iterator c(certs.begin()); c!=certs.end(); ++c) { for (cryptoki::ObjectList::iterator it(certs.begin());
std::string label(c->attribute(CKA_LABEL).value); it!=certs.end(); ++it) {
std::string label(it->attribute(CKA_LABEL).value);
if (cert.size()&&cert!=label) continue; if (cert.size()&&cert!=label) continue;
cryptoki::Attribute id(c->attribute(CKA_ID)); cryptoki::Attribute id(it->attribute(CKA_ID));
cryptoki::ObjectList keys cryptoki::ObjectList keys
(session.find(cryptoki::Attribute(CKA_CLASS) (session.find(cryptoki::Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_PUBLIC_KEY), .from<CK_OBJECT_CLASS>(CKO_PUBLIC_KEY),
id)); id));
if (!keys.size()) continue; if (!keys.size()) continue;
std::cout<<"Found Certificate: " std::cout<<"Found Certificate: "
<<c->attribute(CKA_LABEL).value<<std::endl; <<it->attribute(CKA_LABEL).value<<std::endl;
if (!cert.size()) continue; if (!cert.size()) continue;
std::cout<<"Pin: "; std::cout<<"Pin: ";
std::string pin; std::string pin;
@ -98,7 +99,7 @@ int main(int argc, char** argv) try {
#ifndef MRW__OLD_PRE11_COMPILER #ifndef MRW__OLD_PRE11_COMPILER
auto start = std::chrono::system_clock::now(); auto start = std::chrono::system_clock::now();
#endif #endif
for (int i(0); i<r; ++i) for (unsigned int i(0); i<r; ++i)
std::cout<<"Text:"<<std::endl std::cout<<"Text:"<<std::endl
<<crypto::readable(txt)<<std::endl <<crypto::readable(txt)<<std::endl
<<"Signature:"<<std::endl <<"Signature:"<<std::endl

@ -111,7 +111,7 @@ namespace cardos {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class array_range: public exception { class array_range: public exception {
public: public:
array_range(unsigned int i, unsigned int j) throw(): array_range(unsigned long i, unsigned long j) throw():
exception("array index out of range: "+mrw::string(i) exception("array index out of range: "+mrw::string(i)
+"; length: "+mrw::string(j)) { +"; length: "+mrw::string(j)) {
} }
@ -198,16 +198,16 @@ namespace cardos {
public: public:
BerValue(unsigned char tag, const std::string& value): BerValue(unsigned char t, const std::string& v):
_tag(tag), _value(value) { _tag(t), _value(v) {
if (isContainer()) if (isContainer())
while (_value.size()) _sequence.push_back(BerValue(_value)); while (_value.size()) _sequence.push_back(BerValue(_value));
} }
BerValue(unsigned char tag, const std::vector<BerValue>& values): BerValue(unsigned char t, const std::vector<BerValue>& vs):
_tag(tag), _sequence(values) { _tag(t), _sequence(vs) {
if (!isContainer()) if (!isContainer())
throw runtime_error("BER tag 0x"+crypto::binToHex(tag) throw runtime_error("BER tag 0x"+crypto::binToHex(_tag)
+" is not a container"); +" is not a container");
} }
@ -227,7 +227,7 @@ namespace cardos {
return tagPC()==CONSTRUCTED; return tagPC()==CONSTRUCTED;
} }
unsigned int size() { std::vector<BerValue>::size_type size() {
return _sequence.size(); return _sequence.size();
} }
@ -235,7 +235,7 @@ namespace cardos {
return _tag; return _tag;
} }
BerValue operator[](unsigned int i) { BerValue operator[](std::vector<BerValue>::size_type i) {
if (i>=_sequence.size()) throw array_range(i, _sequence.size()); if (i>=_sequence.size()) throw array_range(i, _sequence.size());
return _sequence[i]; return _sequence[i];
} }
@ -424,13 +424,13 @@ namespace cardos {
Commands() {} Commands() {}
/// Initialize with given smart card reader. /// Initialize with given smart card reader.
Commands(pcsc::shared_ptr<pcsc::Connection::Reader>::t reader): Commands(pcsc::shared_ptr<pcsc::Connection::Reader>::t r):
_reader(reader) { _reader(r) {
} }
/// Set smart card reader. /// Set smart card reader.
void reader(pcsc::shared_ptr<pcsc::Connection::Reader>::t reader) { void reader(pcsc::shared_ptr<pcsc::Connection::Reader>::t r) {
_reader = reader; _reader = r;
} }
//@} //@}
@ -446,10 +446,10 @@ namespace cardos {
will not return an error, if the current file is already will not return an error, if the current file is already
active. active.
@prereq The command can only be executed, if the right @pre The command can only be executed, if the right
referenced by the files AC ACTIVATE is granted in referenced by the files AC ACTIVATE is granted in the
the security status of the current DF. The command security status of the current DF. The command cannot
cannot be applied to CODE files. */ be applied to CODE files. */
void activateFile() { void activateFile() {
CRYPTOLOG("log"); CRYPTOLOG("log");
check(send(0x00, 0x44, 0x00, 0x00)); check(send(0x00, 0x44, 0x00, 0x00));
@ -480,10 +480,8 @@ namespace cardos {
<table> <table>
<caption>Bytes P1-P2</caption> <caption>Bytes P1-P2</caption>
<thead>
<tr><td colspan="2">P1 (MODE)</td><td>P2</td><td>Meaning</td></tr> <tr><td colspan="2">P1 (MODE)</td><td>P2</td><td>Meaning</td></tr>
<tr><td>Bit 7</td><td>Bits 6 0</td><td/><td/></tr> <tr><td>Bit 7</td><td>Bits 6 0</td><td></td><td></td></tr>
</thead>
<tr> <tr>
<td>1</td><td>HI value</td><td>LO value</td> <td>1</td><td>HI value</td><td>LO value</td>
<td>Allocate buffer with size HI-LO</td> <td>Allocate buffer with size HI-LO</td>
@ -493,8 +491,8 @@ namespace cardos {
</tr> </tr>
</table> </table>
@prereq The command can only be executed, if the right @pre The command can only be executed, if the right
referenced by the MFs AC ALLOCATE is granted. referenced by the MFs AC ALLOCATE is granted.
@returns 1 byte: ID of allocated buffer @returns 1 byte: ID of allocated buffer
@ -502,7 +500,8 @@ namespace cardos {
std::string allocateTransactionBuffer(unsigned short size) { std::string allocateTransactionBuffer(unsigned short size) {
CRYPTOLOG("log"); CRYPTOLOG("log");
if (size>0x7FFF) throw runtime_error("requested buffer too large"); 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 //! Free transaction buffer
@ -553,9 +552,9 @@ namespace cardos {
the record consists of one byte. The tag byte is not the record consists of one byte. The tag byte is not
interpreted by APPEND RECORD. interpreted by APPEND RECORD.
@prereq The command can only be executed, if the right @pre The command can only be executed, if the right
referenced by the files AC APPEND is granted in the referenced by the files AC APPEND is granted in the
security status of the current DF. */ security status of the current DF. */
void appendRecord(unsigned char efId, std::string data) { void appendRecord(unsigned char efId, std::string data) {
CRYPTOLOG("log"); CRYPTOLOG("log");
check(send(0x00, 0xE2, 0x00, efId, data)); 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 number of loaded Packages (s. GET DATA command, mode 88h)
- the system internal parameters (9 bytes consisting 22h) and - the system internal parameters (9 bytes consisting 22h) and
- optionally, the Chip Unique Identification Number - 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). Bytes 11-16).
The commands supports 2 modes indicated by the parameter P1: The commands supports 2 modes indicated by the parameter P1:
@ -594,28 +593,37 @@ namespace cardos {
chapter 2.4.2.4 chapter 2.4.2.4
<table> <table>
<caption>Format of the input for hash value calculation</caption> <caption>Format of the input for hash value calculation</caption>
<thead><tr> <tr>
<th>System_Challenge</th> <th>System_Challenge</th>
<th>Command Header<br/>CLA INS P1 P2</th> <th>Command Header<br/>CLA INS P1 P2</th>
<th>Global Life Cycle Phase</th> <th>Global Life Cycle Phase</th>
<th>Internal Parameters</th> <th>Internal Parameters</th>
<th>Number of loaded Packages</th> <th>Number of loaded Packages</th>
<th>Chip Unique Identification Number (opt.)</th> <th>Chip Unique Identification Number (opt.)</th>
</tr></thead> </tr>
<tr> <tr>
<td>xxhxxh</td><td>80h 88h Mode 00h</td><td>xxh</td> <td>xxhxxh</td>
<td>22h22h</td><td>xxh</td><td>xxhxxh</td> <td>80h 88h Mode 00h</td>
</tr><tr> <td>xxh</td>
<td>n bytes</td><td>4 bytes</td><td>1 byte</td><td>9 bytes</td> <td>22h22h</td>
<td>1 byte</td><td>6 bytes/empty</td> <td>xxh</td>
</tr> <td>xxhxxh</td>
</tr>
<tr>
<td>n bytes</td>
<td>4 bytes</td>
<td>1 byte</td>
<td>9 bytes</td>
<td>1 byte</td>
<td>6 bytes/empty</td>
</tr>
</table> </table>
@prereq The System_Challenge provided by the application @pre The System_Challenge provided by the application must
must be greater or equal to 16 bytes. Since the be greater or equal to 16 bytes. Since the command
command does not support chaining, the length of the does not support chaining, the length of the
System_Challenge is limited by the IO buffer size. System_Challenge is limited by the IO buffer size.
@note The application must use the corresponding RSA2 public @note The application must use the corresponding RSA2 public
key to verify the Digital Signature received from the key to verify the Digital Signature received from the
@ -653,7 +661,7 @@ namespace cardos {
} }
//! Creates a file (only EF or DF) //! 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"); CRYPTOLOG("log");
// pcsc::Connection::Reader::Transaction lock(_reader); // pcsc::Connection::Reader::Transaction lock(_reader);
// if (path.size()) select(path); // if (path.size()) select(path);
@ -818,8 +826,8 @@ namespace cardos {
CRYPTOLOG("log"); CRYPTOLOG("log");
std::string data; std::string data;
data.resize(2); data.resize(2);
data[0] = size>>8; data[0] = char((unsigned char)(size>>8));
data[1] = size&0xff; data[1] = char((unsigned char)(size&0xff));
return check(send(0x80, 0x32, 0x00, efId, data)); // 0x08 or 0x80? return check(send(0x80, 0x32, 0x00, efId, data)); // 0x08 or 0x80?
// old code was 0x80, manual says 0x08 (manual exactly says: "8xh") // 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 can also be undone (without reset) with another PHASE
CONTROL command. CONTROL command.
@prereq Changing from ADMINISTRATION to OPERATIONAL is not @pre Changing from ADMINISTRATION to OPERATIONAL is not
protected. Changing from OPERATIONAL to protected. Changing from OPERATIONAL to ADMINISTRATION
ADMINISTRATION is controlled by the right referenced is controlled by the right referenced by the current
by the current DFs AC LCYCLE. DFs AC LCYCLE.
@prereq The command can be executed in the life cycle phases @pre The command can be executed in the life cycle phases
ADMINISTRATION and OPERATIONAL. */ ADMINISTRATION and OPERATIONAL. */
void phaseControl() { void phaseControl() {
CRYPTOLOG("log"); CRYPTOLOG("log");
check(send(0x80, 0x10, 0x00, 0x00)); check(send(0x80, 0x10, 0x00, 0x00));
@ -930,7 +938,8 @@ namespace cardos {
CRYPTOLOG("log"); CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader); pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path); 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 { enum ReadRecordMode {
@ -950,7 +959,8 @@ namespace cardos {
CRYPTOLOG("log"); CRYPTOLOG("log");
pcsc::Connection::Reader::Transaction lock(_reader); pcsc::Connection::Reader::Transaction lock(_reader);
if (path.size()) select(path); 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 /// Read all records from a record oriented file
@ -1042,7 +1052,8 @@ namespace cardos {
//! Updates a BINARY file //! Updates a BINARY file
void updateBinary(std::string data, unsigned short offset=0) { void updateBinary(std::string data, unsigned short offset=0) {
CRYPTOLOG("log"); 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. //! Overwrites an existing record.
@ -1051,7 +1062,8 @@ namespace cardos {
unsigned char sfi = 0, unsigned char sfi = 0,
ReadRecordMode mode = ABSOLUTE_RECORD) { ReadRecordMode mode = ABSOLUTE_RECORD) {
CRYPTOLOG("log"); 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 { enum VerifyMode {
@ -1063,14 +1075,14 @@ namespace cardos {
void verify(std::string pin, unsigned char id, void verify(std::string pin, unsigned char id,
VerifyMode mode = SEARCH_FROM_DF) { VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log"); 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) //! Performs a PIN test (CHV test)
/*! @return number of remaining PIN retries or -1 if PIN is locked */ /*! @return number of remaining PIN retries or -1 if PIN is locked */
int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) { int verify(unsigned char id, VerifyMode mode = SEARCH_FROM_DF) {
CRYPTOLOG("log"); 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 value((((unsigned int)(unsigned char)res[0])*256)
+((unsigned int)(unsigned char)res[1])); +((unsigned int)(unsigned char)res[1]));
if ((value&0x63C0)==0x63C0) return value&0x0F; if ((value&0x63C0)==0x63C0) return value&0x0F;
@ -1511,7 +1523,9 @@ namespace cardos {
return result; 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"); if (!_reader) throw runtime_error("no reader selected");
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla) CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
<<" ins="<<crypto::binToHex(ins) <<" ins="<<crypto::binToHex(ins)
@ -1521,7 +1535,8 @@ namespace cardos {
return logResult(_reader->transmit(cla, ins, p1, p2, lc)); return logResult(_reader->transmit(cla, ins, p1, p2, lc));
} }
std::string send(char cla, char ins, char p1, char p2) { std::string send(unsigned char cla, unsigned char ins,
unsigned char p1, unsigned char p2) {
if (!_reader) throw runtime_error("no reader selected"); if (!_reader) throw runtime_error("no reader selected");
CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla) CARDOS_LOG("APDU: cla="<<crypto::binToHex(cla)
<<" ins="<<crypto::binToHex(ins) <<" ins="<<crypto::binToHex(ins)
@ -1545,7 +1560,7 @@ namespace cardos {
typedef pcsc::shared_ptr<Object>::t Child; typedef pcsc::shared_ptr<Object>::t Child;
typedef std::vector<Child> Children; typedef std::vector<Child> Children;
public: public:
Object(const std::string& path): _path(path) {} Object(const std::string& p): _path(p) {}
virtual ~Object() {} virtual ~Object() {}
virtual const std::string& path() const { virtual const std::string& path() const {
return _path; return _path;
@ -1618,11 +1633,11 @@ namespace cardos {
/// Represents a File on a Smart Card /// Represents a File on a Smart Card
class File: public Object { class File: public Object {
public: public:
File(Commands& cmd, const std::string& path, const std::string& file): File(Commands& cmd, const std::string& p, const std::string& file):
Object(path), _file(file) { Object(p), _file(file) {
CRYPTOLOG("new file "<<file<<" at "<<path); CRYPTOLOG("new file "<<file<<" at "<<p);
try { try {
_content = cmd.readBinary(path+file); _content = cmd.readBinary(p+file);
try { try {
_contentInfo = cardos::BerValues(_content).print(); _contentInfo = cardos::BerValues(_content).print();
} catch (...) { } catch (...) {
@ -1631,9 +1646,9 @@ namespace cardos {
_contentInfo = x.what(); _contentInfo = x.what();
} }
} }
File(const std::string& path, const std::string& file): File(const std::string& p, const std::string& file):
Object(path), _file(file) { Object(p), _file(file) {
CRYPTOLOG("new file "<<file<<" at "<<path); CRYPTOLOG("new file "<<file<<" at "<<p);
} }
std::string name() const { std::string name() const {
return _file; return _file;
@ -1660,9 +1675,9 @@ namespace cardos {
/// Represents a Link on a Smart Card /// Represents a Link on a Smart Card
class Link: public File { class Link: public File {
public: public:
Link(Commands& cmd, const std::string& path, const std::string& file): Link(Commands& cmd, const std::string& p, const std::string& file):
File(cmd, path, file) { File(cmd, p, file) {
CRYPTOLOG("new link "<<file<<" at "<<path); CRYPTOLOG("new link "<<file<<" at "<<p);
} }
std::string type() const { std::string type() const {
return "Link"; return "Link";
@ -1673,11 +1688,11 @@ namespace cardos {
/// Represents a Counter on a Smart Card /// Represents a Counter on a Smart Card
class Counter: public File { class Counter: public File {
public: public:
Counter(Commands& cmd, const std::string& path, const std::string& file): Counter(Commands& cmd, const std::string& p, const std::string& file):
File(path, file) { File(p, file) {
CRYPTOLOG("new counter "<<file<<" at "<<path); CRYPTOLOG("new counter "<<file<<" at "<<p);
try { try {
_content = cmd.readRecord(path+file); _content = cmd.readRecord(p+file);
std::stringstream s; std::stringstream s;
s<<crypto::ulongFromBinary(_content); s<<crypto::ulongFromBinary(_content);
_contentInfo = s.str(); _contentInfo = s.str();
@ -1694,8 +1709,8 @@ namespace cardos {
/// Represents a Directory on a Smart Card /// Represents a Directory on a Smart Card
class Dir: public Object { class Dir: public Object {
public: public:
Dir(Commands& cmd, const std::string& path): Object(path) { Dir(Commands& cmd, const std::string& p): Object(p) {
CRYPTOLOG("new directory path="<<path); CRYPTOLOG("new directory path="<<p);
setup(cmd); setup(cmd);
} }
std::string name() const { std::string name() const {

@ -80,6 +80,11 @@
# endif # endif
#endif #endif
namespace pcsc {
/// Get library version identification
std::string version();
}
//! @ref gcrypto @copydoc gcrypto //! @ref gcrypto @copydoc gcrypto
namespace crypto { namespace crypto {
@ -165,9 +170,9 @@ namespace crypto {
<<s.find_first_not_of(HEX))).str()); <<s.find_first_not_of(HEX))).str());
std::string res; std::string res;
for (std::string::const_iterator it(s.begin()); it!=s.end(); ++it) { for (std::string::const_iterator it(s.begin()); it!=s.end(); ++it) {
unsigned char c(HEX.find(*it)); std::string::size_type c(HEX.find(*it));
if (++it!=s.end()) (c <<= 4) += HEX.find(*it); if (++it!=s.end()) (c <<= 4) += HEX.find(*it);
res += std::string(1, (char)c); res += std::string(1, (std::string::value_type)c);
} }
return res; return res;
} }
@ -176,7 +181,7 @@ namespace crypto {
inline std::string toBinary(unsigned long data, int bytes=2) { inline std::string toBinary(unsigned long data, int bytes=2) {
std::string res(0, bytes); std::string res(0, bytes);
for (int i(0); i<bytes; ++i) { for (int i(0); i<bytes; ++i) {
res[i] = data&0xff; res[i] = std::string::value_type(data&0xff);
data>>=8; data>>=8;
} }
return res; return res;

@ -33,33 +33,38 @@ namespace cryptoki {
if (!_lib) throw exception("open of library failed: "+library); if (!_lib) throw exception("open of library failed: "+library);
CRYPTOLOG("loaded: "<<library); CRYPTOLOG("loaded: "<<library);
#ifndef WIN32 #ifndef WIN32
CK_C_GetFunctionList fn /// @bug in dlsym: returns void* but should return void(*)()
((CK_C_GetFunctionList)dlsym(_lib, "C_GetFunctionList")); CK_C_GetFunctionList fnl
(reinterpret_cast<CK_C_GetFunctionList>
(reinterpret_cast<long long>
(dlsym(_lib, "C_GetFunctionList"))));
#else #else
CK_C_GetFunctionList fn CK_C_GetFunctionList fnl
((CK_C_GetFunctionList)GetProcAddress(_lib, "C_GetFunctionList")); ((CK_C_GetFunctionList)GetProcAddress(_lib, "C_GetFunctionList"));
#endif #endif
if (!fn) if (!fnl)
throw exception("required library symbol C_GetFunctionList not found in " throw exception("required library symbol C_GetFunctionList not found in "
+library); +library);
CRYPTOLOG("Got C_GetFunctionList, now call it"); CRYPTOLOG("Got C_GetFunctionList, now call it");
//! calls @c C_GetFunctionList //! calls @c C_GetFunctionList
return check(fn(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList")); return check(fnl(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList"));
} }
bool Library::Init::check(CK_RV result, const std::string& context) { bool Library::Init::check(CK_RV result, const std::string& context) {
_res = result; _res = result;
if (_exc && !*this) if (_exc && !*this) {
if (context.size()) if (context.size()) {
if (_res==CKR_PIN_INCORRECT) if (_res==CKR_PIN_INCORRECT)
throw wrong_pin(context+": "+error()); throw wrong_pin(context+": "+error());
else else
throw access_error(context+": "+error()); throw access_error(context+": "+error());
else } else {
if (_res==CKR_PIN_INCORRECT) if (_res==CKR_PIN_INCORRECT)
throw wrong_pin(error()); throw wrong_pin(error());
else else
throw access_error(error()); throw access_error(error());
}
}
return _res==CKR_OK; return _res==CKR_OK;
} }
@ -344,7 +349,7 @@ namespace cryptoki {
attrs.push_back(Attribute(CKA_SECONDARY_AUTH).from<CK_BBOOL>(FALSE)); attrs.push_back(Attribute(CKA_SECONDARY_AUTH).from<CK_BBOOL>(FALSE));
attrs.push_back(Attribute(CKA_DECRYPT) // Required by Doujak/Inverardi attrs.push_back(Attribute(CKA_DECRYPT) // Required by Doujak/Inverardi
.from<CK_BBOOL>(usage&(X509v3_KU_DATA_ENCIPHERMENT .from<CK_BBOOL>(usage&(X509v3_KU_DATA_ENCIPHERMENT
|usage&X509v3_KU_KEY_ENCIPHERMENT) |(usage&X509v3_KU_KEY_ENCIPHERMENT))
?TRUE:FALSE)); // instead of CKA_UNWRAP ?TRUE:FALSE)); // instead of CKA_UNWRAP
attrs.push_back(Attribute(CKA_SIGN) attrs.push_back(Attribute(CKA_SIGN)
.from<CK_BBOOL>(usage&(X509v3_KU_DIGITAL_SIGNATURE .from<CK_BBOOL>(usage&(X509v3_KU_DIGITAL_SIGNATURE

@ -54,7 +54,7 @@
#if __GNUC__ >= 2 #if __GNUC__ >= 2
//! Cryptoki Error Message Formatting //! Cryptoki Error Message Formatting
/*! If you want to change cryptoki error formatting, just /*! If you want to change cryptoki error formatting, just
redefine your own CRYPTOKY_FN_LOG macro before <code>#include redefine your own CRYPTOKY_FN_LOG macro before <code>\#include
&lt;cryptoki.hxx&gt;</code>. &lt;cryptoki.hxx&gt;</code>.
#return std::String */ #return std::String */
#define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \ #define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \
@ -64,19 +64,15 @@
#define CRYPTOKI_QUOTE2(X) #X #define CRYPTOKI_QUOTE2(X) #X
//! Cryptoki Error Message Formatting //! Cryptoki Error Message Formatting
/*! If you want to change cryptoki error formatting, just /*! If you want to change cryptoki error formatting, just
redefine your own CRYPTOKY_FN_LOG macro before <code>#include redefine your own CRYPTOKY_FN_LOG macro before <code>\#include
&lt;cryptoki.hxx&gt;</code>. &lt;cryptoki.hxx&gt;</code>.
#return std::String */ @return string */
#define CRYPTOKI_FN_LOG(X) X " failed in \ #define CRYPTOKI_FN_LOG(X) X " failed in \
" __FILE__ ":" CRYPTOKI_QUOTE(__LINE__) " __FILE__ ":" CRYPTOKI_QUOTE(__LINE__)
#endif #endif
#endif #endif
//@} //@}
namespace pcsc {
std::string version();
}
//! @ref gcryptoki @copydoc gcryptoki //! @ref gcryptoki @copydoc gcryptoki
namespace cryptoki { namespace cryptoki {
@ -261,7 +257,7 @@ namespace cryptoki {
std::string res(indent, ' '); std::string res(indent, ' ');
switch (type) { switch (type) {
case CKA_CLASS: case CKA_CLASS:
switch (*((CK_OBJECT_CLASS*)&value[0])) { switch (*((const CK_OBJECT_CLASS*)&value[0])) {
case CKO_DATA: return res+"DATA"; case CKO_DATA: return res+"DATA";
case CKO_CERTIFICATE: return res+"CERTIFICATE"; case CKO_CERTIFICATE: return res+"CERTIFICATE";
case CKO_PUBLIC_KEY: return res+"PUBLIC_KEY"; 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 /** To use this method, you must know what type the attribute
represents. */ represents. */
template<typename TYPE> Attribute& from(const TYPE& v) { template<typename TYPE> Attribute& from(const TYPE& v) {
value = std::string((char*)&v, sizeof(TYPE)); value = std::string((const char*)&v, sizeof(TYPE));
return *this; return *this;
} }
/// Convert to a given type. /// Convert to a given type.
@ -1107,9 +1103,9 @@ namespace cryptoki {
shared library. Normally you need only one instance. shared library. Normally you need only one instance.
@param library name of the shared library that supports pkcs#11 @param library name of the shared library that supports pkcs#11
@param exc wether exceptions should be thrown */ @param exceptions whether exceptions should be thrown */
Library(const std::string& library, bool exc=true): Library(const std::string& library, bool exceptions=true):
_init(new Init(library, exc)) { _init(new Init(library, exceptions)) {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
@ -1545,7 +1541,8 @@ namespace cryptoki {
public: public:
//! Opens a new session. //! Opens a new session.
/*! @param slot slot to open a session on */ /*! @param slot slot to open a session on
@param rw whether session is read/write or read only*/
Session(const Slot& slot, bool rw=false): Session(const Slot& slot, bool rw=false):
_slot(slot), _session(0), _res(CKR_OK) { _slot(slot), _session(0), _res(CKR_OK) {
CRYPTOLOG("log"); CRYPTOLOG("log");
@ -1553,8 +1550,7 @@ namespace cryptoki {
//! @todo pass parameter //! @todo pass parameter
} }
//! Opens a new session. //! Copy session.
/*! @param slot slot to open a session on */
Session(const Session& o): Session(const Session& o):
_slot(o._slot), _session(o._session), _res(CKR_OK) { _slot(o._slot), _session(o._session), _res(CKR_OK) {
CRYPTOLOG("log"); CRYPTOLOG("log");
@ -1822,6 +1818,26 @@ namespace cryptoki {
CRYPTOKI_FN_LOG("C_GetSessionInfo")); CRYPTOKI_FN_LOG("C_GetSessionInfo"));
return info; 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: /*! @todo Not implemented:
@code @code
@ -1833,6 +1849,13 @@ namespace cryptoki {
} }
@endcode */ @endcode */
//@}
/** @name login with pin
Unlock access with pin (login) and unlock after use (logout). */
//@{
private: private:
class Login { class Login {
@ -1846,8 +1869,8 @@ namespace cryptoki {
//! calls @c C_Login //! calls @c C_Login
_session.check(_session._slot.library()->C_Login _session.check(_session._slot.library()->C_Login
(_session._session, userType, (_session._session, userType,
(CK_CHAR*)pin.c_str(), const_cast<CK_CHAR*>((const CK_CHAR*)pin.c_str()),
pin.size()), (int)pin.size()),
CRYPTOKI_FN_LOG("C_Login")); CRYPTOKI_FN_LOG("C_Login"));
} }
@ -1874,37 +1897,26 @@ namespace cryptoki {
public: 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"); CRYPTOLOG("log");
_login = new Login(*this, pin, userType); _login = new Login(*this, pin, userType);
} }
/// Logout from card
/** Undo the last login. */
void logout() { void logout() {
CRYPTOLOG("log"); CRYPTOLOG("log");
_login.reset(); _login.reset();
} }
mrw::Shared<Login> _login; mrw::Shared<Login> _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 { class Object {
@ -1985,6 +1997,218 @@ namespace cryptoki {
//! @todo don't call verifyfinal()? //! @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 /*! @name C Like Error Handling
@ -2046,13 +2270,15 @@ namespace cryptoki {
//! calls @c C_Decrypt //! calls @c C_Decrypt
check(_session._slot.library()->C_Decrypt check(_session._slot.library()->C_Decrypt
(_session._session, (_session._session,
(unsigned char*)&in[0], in.size(), 0, &size), const_cast<CK_BYTE_PTR>((const unsigned char*)&in[0]),
in.size(), 0, &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOLOG("maximum size is "<<size<<"Bytes"); CRYPTOLOG("maximum size is "<<size<<"Bytes");
res.resize(size, 0); res.resize(size, 0);
check(_session._slot.library()->C_Decrypt check(_session._slot.library()->C_Decrypt
(_session._session, (_session._session,
(unsigned char*)&in[0], in.size(), const_cast<CK_BYTE_PTR>((const unsigned char*)&in[0]),
in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOLOG("exact size is "<<size<<"Bytes"); CRYPTOLOG("exact size is "<<size<<"Bytes");
@ -2068,7 +2294,7 @@ namespace cryptoki {
//! calls @c C_DecryptDigestUpdate //! calls @c C_DecryptDigestUpdate
check(_session._slot.library()->C_DecryptDigestUpdate check(_session._slot.library()->C_DecryptDigestUpdate
(_session._session, (_session._session,
(unsigned char*)&in[0], in.size(), const_cast<CK_BYTE_PTR>((const unsigned char*)&in[0]), in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_DecryptDigestUpdate")); CRYPTOKI_FN_LOG("C_DecryptDigestUpdate"));
res.resize(size); res.resize(size);
@ -2230,7 +2456,6 @@ namespace cryptoki {
CRYPTOKI_FN_LOG("C_VerifyUpdate")); CRYPTOKI_FN_LOG("C_VerifyUpdate"));
} }
@endcode */ @endcode */
//@}
/*! @todo Not implemented: /*! @todo Not implemented:
@code @code
@ -2243,15 +2468,6 @@ namespace cryptoki {
} }
@endcode */ @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: /*! @todo Not implemented:
@code @code
bool digestkey() { bool digestkey() {
@ -2265,7 +2481,8 @@ namespace cryptoki {
bool encryptinit(CK_MECHANISM_TYPE type, const std::string& param) { bool encryptinit(CK_MECHANISM_TYPE type, const std::string& param) {
CRYPTOLOG("log"); CRYPTOLOG("log");
CK_MECHANISM mech = { CK_MECHANISM mech = {
type, param.size()?(void*)&param[0]:0, param.size() type, param.size()?const_cast<CK_VOID_PTR>((const void*)&param[0]):0,
param.size()
}; };
CRYPTOLOG("encryptinit: type="<<type<<"; mech=("<<mech.mechanism CRYPTOLOG("encryptinit: type="<<type<<"; mech=("<<mech.mechanism
<<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')'); <<", "<<mech.pParameter<<", "<<mech.ulParameterLen<<')');
@ -2283,13 +2500,14 @@ namespace cryptoki {
//! calls @c C_Encrypt //! calls @c C_Encrypt
check(_session._slot.library()->C_Encrypt check(_session._slot.library()->C_Encrypt
(_session._session, (_session._session,
(unsigned char*)&in[0], in.size(), 0, &size), const_cast<CK_BYTE_PTR>((const unsigned char*)&in[0]),
in.size(), 0, &size),
CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_FN_LOG("C_Decrypt"));
CRYPTOLOG("maximum size is "<<size<<"Bytes"); CRYPTOLOG("maximum size is "<<size<<"Bytes");
res.resize(size, 0); res.resize(size, 0);
check(_session._slot.library()->C_Encrypt check(_session._slot.library()->C_Encrypt
(_session._session, (_session._session,
(unsigned char*)&in[0], in.size(), const_cast<CK_BYTE_PTR>((const unsigned char*)&in[0]), in.size(),
(unsigned char*)&res[0], &size), (unsigned char*)&res[0], &size),
CRYPTOKI_FN_LOG("C_Encrypt")); CRYPTOKI_FN_LOG("C_Encrypt"));
res.resize(size); res.resize(size);
@ -2345,211 +2563,6 @@ namespace cryptoki {
} }
@endcode */ @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: /*! @todo Not implemented:
@code @code
bool getobjectsize() { bool getobjectsize() {
@ -2660,8 +2673,9 @@ namespace cryptoki {
} }
//! @groupadd cryptokitypes //! @addtogroup cryptokitypes
//@{ //@{
/// Append a cryptoki::Attribute to a cryptoki::AttributeList. /// Append a cryptoki::Attribute to a cryptoki::AttributeList.
inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list, inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list,
const cryptoki::Attribute& attr) { const cryptoki::Attribute& attr) {
@ -2669,6 +2683,7 @@ inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list,
list.push_back(attr); list.push_back(attr);
return list; return list;
} }
/// Append a cryptoki::Attribute to a new copy of a cryptoki::AttributeList. /// Append a cryptoki::Attribute to a new copy of a cryptoki::AttributeList.
inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list, inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list,
const cryptoki::Attribute& attr) { const cryptoki::Attribute& attr) {
@ -2677,6 +2692,7 @@ inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list,
res.push_back(attr); res.push_back(attr);
return res; return res;
} }
//@} //@}
#endif #endif

@ -38,9 +38,26 @@
#if __GNUC__ >= 2 #if __GNUC__ >= 2
//! Macro for internal OpenSSL checks. //! Macro for internal OpenSSL checks.
/*! You can define a different implementation in your compile call */ /*! 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: "<<ERR_error_string(err, 0)<<"; "; ss<<"Command "<<#X<<" failed in function "<<__PRETTY_FUNCTION__<<" in file "<<__FILE__<<":"<<__LINE__; throw std::runtime_error(ss.str());} #define OPENSSL_CHECK(X) \
if (!(X)) { \
ERR_load_ENGINE_strings(); \
std::stringstream ss; \
for (unsigned long err(0); (err=ERR_get_error());) \
ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; \
ss<<"Command "<<#X<<" failed in function "<<__PRETTY_FUNCTION__ \
<<" in file "<<__FILE__<<":"<<__LINE__; \
throw std::runtime_error(ss.str()); \
}
#else #else
#define OPENSSL_CHECK(X) if (!(X)) {ERR_load_ENGINE_strings(); std::stringstream ss; for (unsigned int err(0); err=ERR_get_error();) ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; ss<<"Command "<<#X<<" failed in file "<<__FILE__<<":"<<__LINE__; throw std::runtime_error(ss.str());} #define OPENSSL_CHECK(X) \
if (!(X)) { \
ERR_load_ENGINE_strings(); \
std::stringstream ss; \
for (unsigned long err(0); (err=ERR_get_error());) \
ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; \
ss<<"Command "<<#X<<" failed in file "<<__FILE__<<":"<<__LINE__; \
throw std::runtime_error(ss.str()); \
}
#endif #endif
#endif #endif
@ -98,13 +115,13 @@ namespace openssl {
CRYPTOLOG("log"); CRYPTOLOG("log");
return 0; return 0;
} }
virtual int rsaEncrypt() { virtual std::string rsaEncrypt(const std::string&, int) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return 1; throw std::runtime_error("rsaEncrypt not implemented");
} }
virtual int rsaDecrypt() { virtual std::string rsaDecrypt(const std::string&, int) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return 1; throw std::runtime_error("rsaDecrypt not implemented");
} }
virtual std::string rsaSign(const std::string&, unsigned int) { virtual std::string rsaSign(const std::string&, unsigned int) {
CRYPTOLOG("log"); CRYPTOLOG("log");
@ -166,7 +183,7 @@ namespace openssl {
private: private:
static int destroy(ENGINE* e) { static int destroy(ENGINE*) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return 1; return 1;
} }
@ -195,17 +212,38 @@ namespace openssl {
Map::iterator it(_map.find(e)); Map::iterator it(_map.find(e));
return it!=_map.end()?it->second->privkey(c, u, d):0; return it!=_map.end()?it->second->privkey(c, u, d):0;
} }
static int rsaEncrypt(int flen,const unsigned char *from, static int rsaEncrypt(int flen, const unsigned char *from,
unsigned char *to, unsigned char *to,
RSA *rsa, int padding) { RSA *rsa, int padding) {
CRYPTOLOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaEncrypt():0; 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: "<<e.what());
return 0;
}
} }
static int rsaDecrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { static int rsaDecrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding) {
CRYPTOLOG("log"); CRYPTOLOG("log");
Map::iterator it(_map.find(rsa->engine)); Map::iterator it(_map.find(rsa->engine));
return it!=_map.end()?it->second->rsaDecrypt():0; 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: "<<e.what());
return 0;
}
} }
static int rsaSign(int type, const unsigned char *from, static int rsaSign(int type, const unsigned char *from,
unsigned int flen, unsigned int flen,
@ -221,7 +259,7 @@ namespace openssl {
type)); type));
CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen); CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen);
CRYPTOLOG("siglen="<<res.size()); CRYPTOLOG("siglen="<<res.size());
*tlen = res.size(); *tlen = (unsigned int)res.size();
std::copy(res.begin(), res.end(), to); std::copy(res.begin(), res.end(), to);
return 1; return 1;
} catch (const std::exception& e) { } catch (const std::exception& e) {

@ -62,10 +62,6 @@
#include <cstdio> #include <cstdio>
#include <cassert> #include <cassert>
namespace pcsc {
std::string version();
}
/*! @defgroup gopenssl C++ Wrapper around OpenSSL API /*! @defgroup gopenssl C++ Wrapper around OpenSSL API
Support for SSL-connections, engines, keys and certificates. */ Support for SSL-connections, engines, keys and certificates. */
//@{ //@{
@ -371,11 +367,11 @@ namespace openssl {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
class ssl_verification_failed: public ssl_error { class ssl_verification_failed: public ssl_error {
public: public:
ssl_verification_failed(int num) throw(): ssl_verification_failed(long num) throw():
ssl_error("certificate verification failed: "+reason(num)) { ssl_error("certificate verification failed: "+reason(num)) {
CRYPTOLOG("**** exception ****"); CRYPTOLOG("**** exception ****");
} }
static std::string reason(int num) { static std::string reason(long num) {
switch (num) { switch (num) {
case X509_V_OK: case X509_V_OK:
return "X509_V_OK: Ok the operation was successful."; return "X509_V_OK: Ok the operation was successful.";
@ -534,7 +530,7 @@ namespace openssl {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
BigNum(const std::string& num): BigNum(const std::string& num):
_bn(BN_bin2bn((const unsigned char*)num.data(), num.size(), 0)) { _bn(BN_bin2bn((const unsigned char*)num.data(), (int)num.size(), 0)) {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
~BigNum() { ~BigNum() {
@ -603,7 +599,7 @@ namespace openssl {
return &_cb; return &_cb;
} }
operator std::string() const { operator std::string() const {
return std::string((char*)_cb, 8); return std::string((const std::string::value_type*)_cb, 8);
} }
private: private:
DES_cblock _cb; DES_cblock _cb;
@ -654,9 +650,11 @@ namespace openssl {
} }
//! DES CBC Encryption //! DES CBC Encryption
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key block key
@param ivec vector */
inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcEnc(std::string txt, CBlock8 key, CBlock8& ivec) {
CRYPTOLOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
@ -669,9 +667,10 @@ namespace openssl {
} }
//! DES CBC Encryption with empty vector //! DES CBC Encryption with empty vector
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key block key */
inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) { inline std::string desCbcEnc(const std::string& txt, const CBlock8& key) {
CRYPTOLOG("log"); CRYPTOLOG("log");
CBlock8 ivec; CBlock8 ivec;
@ -679,9 +678,11 @@ namespace openssl {
} }
//! DES CBC Decryption //! DES CBC Decryption
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key block key
@param ivec vector */
inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) { inline std::string desCbcDec(std::string txt, CBlock8 key, CBlock8& ivec) {
CRYPTOLOG("log"); CRYPTOLOG("log");
if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0); if (txt.size()%8!=0) txt.resize((txt.size()/8+1)*8, 0);
@ -696,16 +697,20 @@ namespace openssl {
//! DES CBC Decryption with empty vector //! DES CBC Decryption with empty vector
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key block key */
inline std::string desCbcDec(const std::string& txt, const CBlock8& key) { inline std::string desCbcDec(const std::string& txt, const CBlock8& key) {
CRYPTOLOG("log"); CRYPTOLOG("log");
CBlock8 ivec; CBlock8 ivec;
return desCbcDec(txt, key, ivec); return desCbcDec(txt, key, ivec);
} }
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key1 block key 1
@param key2 block key 2
@param ivec vector */
inline std::string des2edeCbcEnc(std::string txt, inline std::string des2edeCbcEnc(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
@ -720,9 +725,12 @@ namespace openssl {
return res; return res;
} }
/*! @param txt If the length is not an integral multiple of eight /*! @param txt If the length is not an integral multiple of eight
bytes, it is zero filled. The output is always an bytes, it is zero filled. The output is always an
integral multiple of eight bytes. */ integral multiple of eight bytes.
@param key1 block key 1
@param key2 block key 2
@param ivec vector */
inline std::string des2edeCbcDec(std::string txt, inline std::string des2edeCbcDec(std::string txt,
CBlock8 key1, CBlock8 key2, CBlock8 key1, CBlock8 key2,
CBlock8 ivec = CBlock8()) { CBlock8 ivec = CBlock8()) {
@ -785,7 +793,8 @@ namespace openssl {
//! Initialize from DER encoded cerificate. //! Initialize from DER encoded cerificate.
X509(const std::string& der): _x509(0) { X509(const std::string& der): _x509(0) {
CRYPTOLOG("log"); CRYPTOLOG("log");
V0_CONST unsigned char* c((unsigned char*)der.begin().operator->()); V0_CONST unsigned char* c
((V0_CONST unsigned char*)der.begin().operator->());
if (!(_x509=d2i_X509(0, &c, der.size())) || if (!(_x509=d2i_X509(0, &c, der.size())) ||
(const char*)c!=der.begin().operator->()+der.size()) (const char*)c!=der.begin().operator->()+der.size())
throw x509_decoding_failed(der); throw x509_decoding_failed(der);
@ -1121,13 +1130,13 @@ namespace openssl {
try { try {
EVP_PKEY *pkey(0); EVP_PKEY *pkey(0);
::X509 *cert(0); ::X509 *cert(0);
STACK_OF(X509) *ca(0); STACK_OF(X509) *cal(0);
if (!PKCS12_parse(p12, password.c_str(), &pkey, &cert, &ca)) if (!PKCS12_parse(p12, password.c_str(), &pkey, &cert, &cal))
throw pkcs12_parsing_failed(filename); throw pkcs12_parsing_failed(filename);
if (pkey) _key = new PrivateKey(pkey); if (pkey) _key = new PrivateKey(pkey);
if (cert) _cert = new X509(cert); if (cert) _cert = new X509(cert);
for (int i(sk_num(CV_STACK ca)); i>0; --i) for (int i(sk_num(CV_STACK cal)); i>0; --i)
_ca.push_back(new X509((::X509*)sk_pop(CV_STACK ca))); _ca.push_back(new X509((::X509*)sk_pop(CV_STACK cal)));
PKCS12_free(p12); PKCS12_free(p12);
} catch (...) { } catch (...) {
PKCS12_free(p12); PKCS12_free(p12);
@ -1210,7 +1219,8 @@ namespace openssl {
//! Read PKCS#7 from memory. //! Read PKCS#7 from memory.
PKCS7(const std::string& memory) { PKCS7(const std::string& memory) {
CRYPTOLOG("log"); CRYPTOLOG("log");
BIO* mem(BIO_new_mem_buf((void*)memory.data(), memory.size())); BIO* mem(BIO_new_mem_buf(const_cast<void*>((const void*)memory.data()),
(int)memory.size()));
::PKCS7 *p7(d2i_PKCS7_bio(mem, 0)); ::PKCS7 *p7(d2i_PKCS7_bio(mem, 0));
BIO_free(mem); BIO_free(mem);
if (!p7) throw pkcs7_parsing_failed(); if (!p7) throw pkcs7_parsing_failed();
@ -1327,7 +1337,7 @@ namespace openssl {
TCP& write(const std::string& s) { TCP& write(const std::string& s) {
CRYPTOLOG("log"); CRYPTOLOG("log");
if (!_bio) throw tcp_closed_connection(); 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 (x<=0)
if (BIO_should_retry(_bio)) return write(s); if (BIO_should_retry(_bio)) return write(s);
else { else {
@ -1432,7 +1442,7 @@ namespace openssl {
void verify() { void verify() {
CRYPTOLOG("log"); CRYPTOLOG("log");
if (!_ssl) throw ssl_no_connection(); 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); if (res!=X509_V_OK) throw ssl_verification_failed(res);
} }
private: private:

@ -21,7 +21,7 @@
For special documentations, such as global overviews and For special documentations, such as global overviews and
tutorials, please refere to [Pages](pages.html). tutorials, please refere to [Pages](pages.html).
@chapter mainoverview Overview of the Components @section mainoverview Overview of the Components
@dot @dot
digraph g { digraph g {

@ -77,10 +77,6 @@
} }
#endif #endif
namespace pcsc {
std::string version();
}
/*! @defgroup gpcsc C++ Wrapper around pcsc-lite API /*! @defgroup gpcsc C++ Wrapper around pcsc-lite API
This library is a C++ wrapper to the awful pcsc-lite interface. This library is a C++ wrapper to the awful pcsc-lite interface.
@ -250,7 +246,7 @@ namespace pcsc {
DWORD dummy(0); DWORD dummy(0);
DWORD s; DWORD s;
DWORD len(MAX_ATR_SIZE); DWORD len(MAX_ATR_SIZE);
unsigned char a[len]; unsigned char a[MAX_ATR_SIZE];
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len), check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len),
"query smartcard status"); "query smartcard status");
return Status(s, std::string((char*)a, len)); return Status(s, std::string((char*)a, len));
@ -316,15 +312,17 @@ namespace pcsc {
@note Prefer the transmit methods that passes @c cla, @c @note Prefer the transmit methods that passes @c cla, @c
ins, @c p1 and @c p2 separate.*/ ins, @c p1 and @c p2 separate.*/
std::string transmit(std::string in) { std::string transmit(std::string in) {
DWORD len(1024); // arbitrary const DWORD bufflen(1024);
unsigned char buff[len]; DWORD len(bufflen); // arbitrary
unsigned char buff[bufflen];
SCARD_IO_REQUEST rPci; SCARD_IO_REQUEST rPci;
rPci.dwProtocol = pci()->dwProtocol; rPci.dwProtocol = pci()->dwProtocol;
rPci.cbPciLength = sizeof(rPci); rPci.cbPciLength = sizeof(rPci);
// log only in verbose debuggung; could log pins // log only in verbose debuggung; could log pins
CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in)); CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in));
check(SCardTransmit(_id, &rPci, check(SCardTransmit(_id, &rPci,
(unsigned char*)in.c_str(), in.size(), (LPCBYTE)in.c_str(),
in.size(),
0, buff, &len), 0, buff, &len),
"smartcard transmit message "+crypto::hex(in)); "smartcard transmit message "+crypto::hex(in));
//CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len))); //CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
@ -342,7 +340,7 @@ namespace pcsc {
CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode); CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode);
CRYPTOLOG(" -> "<<crypto::hex(in)); CRYPTOLOG(" -> "<<crypto::hex(in));
check(SCardControl(_id, controlCode, check(SCardControl(_id, controlCode,
(unsigned char*)in.c_str(), in.size(), (LPCBYTE)in.c_str(), in.size(),
dataBuffer, sizeof(dataBuffer), &len), dataBuffer, sizeof(dataBuffer), &len),
"smartcard control message sent"); "smartcard control message sent");
CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len))); CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
@ -498,6 +496,8 @@ namespace pcsc {
//! Find all readers with a given ATR. //! Find all readers with a given ATR.
/*! @param atr full or partial ATR to match to the reader's ATR /*! @param atr full or partial ATR to match to the reader's ATR
@param s scope of scanning
@param exceptions whether exeptions should be thrown on error
@returns list of readers that contain @c atr in their ATR */ @returns list of readers that contain @c atr in their ATR */
static Strings getReadersWithAtr(const std::string& atr, static Strings getReadersWithAtr(const std::string& atr,
Scope s=USER, bool exceptions=true) { Scope s=USER, bool exceptions=true) {
@ -593,9 +593,9 @@ namespace pcsc {
//! Throws an exception if neccessary. //! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and /*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command. */ an error occured in the last command. */
bool check(long state, const std::string& context="") { bool check(long s, const std::string& context="") {
_state = state; _state = s;
check(context); return check(context);
} }
//! Throws an exception if neccessary. //! Throws an exception if neccessary.

@ -67,7 +67,7 @@ namespace suisseid {
pukRetries pukRetries
[URL="\ref cardos::Commands::pukRetries"]; [URL="\ref cardos::Commands::pukRetries"];
changePin changePin
[URL="\ref cardos::Commands::changePin"]; [URL="\ref cardos::Commands::changePins"];
broken [label="replace card"]; broken [label="replace card"];
start -> transportState; start -> transportState;
@ -201,7 +201,7 @@ namespace suisseid {
} }
/// Get the reader, needed for example to lock a transaction /// Get the reader, needed for example to lock a transaction
/** @begincode /** @code
pcsc::Connection::Reader::Transaction lock(card.reader()); pcsc::Connection::Reader::Transaction lock(card.reader());
[... do some low level stuff ...] [... do some low level stuff ...]
@endcode */ @endcode */
@ -292,7 +292,7 @@ namespace suisseid {
/// @copydoc Card::Card /// @copydoc Card::Card
Post(mrw::Shared<pcsc::Connection::Reader> reader, Post(mrw::Shared<pcsc::Connection::Reader> reader,
const cryptoki::Library& cryptoki): const cryptoki::Library& cryptoki):
Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) { Card(reader, cryptoki), _minPinLen(0), _maxPinLen(0) {
} }
virtual unsigned int minimalPinLength() { virtual unsigned int minimalPinLength() {
@ -301,7 +301,7 @@ namespace suisseid {
} }
virtual unsigned int maximalPinLength() { virtual unsigned int maximalPinLength() {
if (_maxPinLen==-1) evaluatePinLengths(); if (_maxPinLen==0) evaluatePinLengths();
return _maxPinLen; return _maxPinLen;
} }
@ -411,9 +411,12 @@ namespace suisseid {
// By now, scan only for PostSuisseID; in future use factory pattern // By now, scan only for PostSuisseID; in future use factory pattern
pcsc::Connection::Strings readers pcsc::Connection::Strings readers
(pcsc::Connection::getReadersWithAtr("4b53776973735369676e")); (pcsc::Connection::getReadersWithAtr("4b53776973735369676e"));
CRYPTOLOG("number of pcsc-readers: "<<readers.size());
for (pcsc::Connection::Strings::iterator reader(readers.begin()); for (pcsc::Connection::Strings::iterator reader(readers.begin());
reader!=readers.end(); ++reader) { reader!=readers.end(); ++reader) {
cryptoki::SlotList slots(_cryptoki.slotList(true, *reader)); cryptoki::SlotList slots(_cryptoki.slotList(true, *reader));
CRYPTOLOG("number of cryptoki-readers for "<<*reader
<<": "<<slots.size());
if (slots.size()==1) if (slots.size()==1)
res.push_back(dynamic_cast<Card*> res.push_back(dynamic_cast<Card*>
(new Post(pcsc::Connection::reader(*reader), (new Post(pcsc::Connection::reader(*reader),
@ -452,7 +455,8 @@ namespace suisseid {
/// @name Slots /// @name Slots
//@{ //@{
/// Structure to provide old and new pin
struct PinPukChange { struct PinPukChange {
std::string oldpin; std::string oldpin;
std::string newpin; std::string newpin;
@ -460,49 +464,65 @@ namespace suisseid {
return oldpin.size() && newpin.size(); return oldpin.size() && newpin.size();
} }
}; };
/// Pin change required - get pins from user
virtual PinPukChange pinChange() { virtual PinPukChange pinChange() {
CRYPTOLOG("log"); CRYPTOLOG("log");
return PinPukChange(); return PinPukChange();
} }
/// Transport pin change required - get pins from user
virtual PinPukChange pinChangeTransportPin() { virtual PinPukChange pinChangeTransportPin() {
CRYPTOLOG("log"); CRYPTOLOG("log");
return pinChange(); return pinChange();
} }
/// Puk change required - get pins from user
virtual PinPukChange pinChangePuk() { virtual PinPukChange pinChangePuk() {
CRYPTOLOG("log"); CRYPTOLOG("log");
return pinChange(); return pinChange();
} }
/// Transport pin locked - you may show an error message
virtual void transportPinLocked() { virtual void transportPinLocked() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// PKCS#15 pin locked - you may show an error message
virtual void pkcs15PinLocked() { virtual void pkcs15PinLocked() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// SigG pin locked - you may show an error message
virtual void sigGPinLocked() { virtual void sigGPinLocked() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// Puk locked - you may show an error message
virtual void pukLocked() { virtual void pukLocked() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// Certificates will expire soon - you may show an error message
virtual void certsExpireSoon() { virtual void certsExpireSoon() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// Certificates are expired soon - you may show an error message
virtual void certsExpired() { virtual void certsExpired() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// Certificates have been revoked - you may show an error message
virtual void certsRevoked() { virtual void certsRevoked() {
CRYPTOLOG("log"); CRYPTOLOG("log");
} }
/// install certificates on the card /// 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 */ @return @c true on success */
virtual bool installCerts(bool = true) { virtual bool installCerts(bool reinstall = true) {
CRYPTOLOG("log"); CRYPTOLOG("log");
return false; return false;
} }

Loading…
Cancel
Save