more documentation; refs #28

master
Marc Wäckerlin 11 years ago
parent 1e45bea4d4
commit 635d466c1c
  1. 8
      doc/doxyfile.in
  2. 27
      doc/examples/cryptoki-demo.cxx
  3. 6
      doc/examples/cryptoki-sign-demo.cxx
  4. 13
      doc/examples/suisse-id-demo.cxx
  5. 13
      src/cryptaux.hxx
  6. 464
      src/cryptoki.hxx
  7. 46
      src/suisseid.hxx

@ -375,7 +375,7 @@ EXTRACT_PACKAGE = NO
# If the EXTRACT_STATIC tag is set to YES all static members of a file
# will be included in the documentation.
EXTRACT_STATIC = NO
EXTRACT_STATIC = YES
# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
# defined locally in source files will be included in the documentation.
@ -1634,7 +1634,7 @@ DOT_FONTPATH =
# indirect inheritance relations. Setting this tag to YES will force the
# CLASS_DIAGRAMS tag to NO.
CLASS_GRAPH = YES
CLASS_GRAPH = NO
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
# will generate a graph for each documented class showing the direct and
@ -1688,7 +1688,7 @@ INCLUDED_BY_GRAPH = YES
# the time of a run. So in most cases it will be better to enable call graphs
# for selected functions only using the \callgraph command.
CALL_GRAPH = YES
CALL_GRAPH = NO
# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
# doxygen will generate a caller dependency graph for every global function
@ -1696,7 +1696,7 @@ CALL_GRAPH = YES
# the time of a run. So in most cases it will be better to enable caller
# graphs for selected functions only using the \callergraph command.
CALLER_GRAPH = YES
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will generate a graphical hierarchy of all classes instead of a textual one.

@ -9,9 +9,11 @@ template <typename Array> void print(const std::vector<Array>& v) {
}
int main(int argc, char const*const*const argv) try {
// //std::vector<int> v(toVector<4>((int[]){1,2,3,4}));
// std::vector<int> v(VECTOR(((int[]){1,2,3,4})));
// print(v);
std::cout<<"Example for buffer to vector conversion:"<<std::endl;
int buff[] = {1, 2, 3, 4};
std::vector<int> vec(cryptoki::toVector(buff));
print(vec);
std::cout<<std::endl;
cryptoki::Library cryptoki(argc==2?argv[1]:"onepin-opensc-pkcs11.so");
cryptoki::Info inf(cryptoki.info());
std::cout<<"Library-Version: "<<pcsc::version()<<std::endl;
@ -61,15 +63,14 @@ int main(int argc, char const*const*const argv) try {
<<"utcTime: \""<<crypto::readable(info.utcTime)
<<'"'<<std::endl;
cryptoki::MechanismList mechs(it->mechanismlist());
for (cryptoki::MechanismList::iterator it2(mechs.begin());
it2!=mechs.end(); ++it2) {
cryptoki::MechanismInfo mechinfo(it->mechanisminfo(*it2));
for (cryptoki::MechanismList::iterator mechinfo(mechs.begin());
mechinfo!=mechs.end(); ++mechinfo) {
std::cout<<"-------------------- Mechanism -----------------"<<std::endl
<<"id: \""<<mechinfo.id<<'"'<<std::endl
<<"name: \""<<mechinfo.name<<'"'<<std::endl
<<"minKeySize: \""<<mechinfo.minKeySize<<'"'<<std::endl
<<"maxKeySize: \""<<mechinfo.maxKeySize<<'"'<<std::endl
<<"flags: \""<<mechinfo.flags<<'"'<<std::endl;
<<"id: \""<<mechinfo->id<<'"'<<std::endl
<<"name: \""<<mechinfo->name<<'"'<<std::endl
<<"minKeySize: \""<<mechinfo->minKeySize<<'"'<<std::endl
<<"maxKeySize: \""<<mechinfo->maxKeySize<<'"'<<std::endl
<<"flags: \""<<mechinfo->flags<<'"'<<std::endl;
}
cryptoki::Session session(*it);
cryptoki::ObjectList objs(session.find());
@ -80,8 +81,8 @@ int main(int argc, char const*const*const argv) try {
cryptoki::AttributeMap attrs(it->attributes());
for (cryptoki::AttributeMap::iterator it(attrs.begin());
it!=attrs.end(); ++it) {
std::cout<<" - attribute: "<<it->second.name()<<"=\""
<<crypto::readable(it->second.value)<<'"'<<std::endl;
std::cout<<" - attribute: "<<it->second.name()<<" = "<<std::endl
<<crypto::readable(it->second.value, 15, 5)<<std::endl;
}
}
std::cout<<"**** Success"<<std::endl;

@ -99,7 +99,11 @@ int main(int argc, char** argv) try {
auto start = std::chrono::system_clock::now();
#endif
for (int i(0); i<r; ++i)
keys[0].sign(txt, CKM_RSA_PKCS);
std::cout<<"Text:"<<std::endl
<<crypto::readable(txt)<<std::endl
<<"Signature:"<<std::endl
<<crypto::readable(keys[0].sign(txt, CKM_RSA_PKCS))
<<std::endl;
#ifndef MRW__OLD_PRE11_COMPILER
auto end = std::chrono::system_clock::now();
auto elapsed(std::chrono::duration_cast<std::chrono::milliseconds>

@ -11,15 +11,18 @@
#include <QtNetwork/QSslCertificate>
#include <QtCore/QDateTime>
void show(const QStringList& sl, const std::string& p="item: ") {
for (QStringList::const_iterator s(sl.begin()); s!=sl.end(); ++s)
std::cout<<p<<QString(s->toUtf8()).toStdString()<<std::endl;
}
// show certificate information
void show(const suisseid::Certificate& cert) {
// makes use of qt library's certificate class
QSslCertificate c(QByteArray(cert.data(), cert.size()), QSsl::Der);
std::cout<<"Certificate info: CN="
<<QString(c.subjectInfo(QSslCertificate::CommonName)
.toUtf8()).toStdString()
<<std::endl
<<" Valid until: "
std::cout<<"Certificate info:";
show(c.subjectInfo(QSslCertificate::CommonName), " CN=");
std::cout<<" Valid until: "
<<QString(c.expiryDate().toString().toUtf8()).toStdString()
<<std::endl;
}

@ -96,10 +96,12 @@ namespace crypto {
}
inline std::string hexTxt(const std::string& data,
std::string::size_type len=20) {
std::string::size_type len=20,
std::string::size_type indent=0) {
std::stringstream res;
std::string::size_type pos(0);
for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it) {
if (pos%len==0) res<<std::string(indent, ' ');
res<<std::hex<<std::setfill('0')<<std::setw(2)
<<(unsigned int)(unsigned char)*it;
++pos;
@ -114,13 +116,14 @@ namespace crypto {
}
inline std::string readable(const std::string& data,
std::string::size_type len=20) {
std::string::size_type len=20,
std::string::size_type indent=0) {
if (!data.size())
return "<empty>";
return std::string(indent, ' ')+"<empty>";
else if (data.find_first_not_of(VALID_CHARS)<data.size())
return hexTxt(data, len);
return hexTxt(data, len, indent);
else
return "\""+data+"\"";
return std::string(indent, ' ')+"\""+data+"\"";
}
//! Convert binary to readable hexadecimal

@ -29,13 +29,26 @@
#include <iomanip>
#include <memory>
/*! @defgroup gcryptoki C++ Wrapper around Cryptoki API */
/*! @defgroup gcryptoki C++ Wrapper around Cryptoki API
Wrapper to abstract the ugly PKCS#11 C-API with nice C++ features,
such as exception handling, memory management, etc.
The cryptoky library loads a dynamic library that is responsible
for translating the card specific commands. The library is passed
in the constructor of cryptoki::Library. Then method
cryptoki::Library::slotList returns all slots found on the
computer. */
//@{
/*! @defgroup cryptokilib Cryptoki C++ Library */
/*! @defgroup globaloperator Global Operator */
/*! @defgroup cryptokitypes Cryptoki C++ Types and Auxiliary */
/*! @defgroup cryptokiexceptions Cryptoki Exceptions */
/** @example cryptoki-demo.cxx */
/** @example cryptoki-sign-demo.cxx */
//@}
/// @addtogroup cryptokitypes
//@{
#ifndef CRYPTOKI_FN_LOG
#include <iostream>
#if __GNUC__ >= 2
@ -58,6 +71,7 @@
" __FILE__ ":" CRYPTOKI_QUOTE(__LINE__)
#endif
#endif
//@}
namespace pcsc {
std::string version();
@ -69,6 +83,11 @@ namespace cryptoki {
//! @addtogroup cryptokitypes
//@{
/// Map cryptoki number to a string, care about unavailable and infinite
/** Cryptoky knows illegal values (unavailable information), which
is mapped to @c - and infinite values which are mapped to @c
when converted to string. All other numbers just show the number
as numeric string. */
inline std::string string(CK_ULONG num) {
switch (num) {
case CK_UNAVAILABLE_INFORMATION: return "-";
@ -81,11 +100,10 @@ namespace cryptoki {
}
}
template <int NUM, typename TYPE> std::vector<TYPE> toVector(TYPE in[NUM]) {
return std::vector<TYPE>(in, in+NUM);
/// Convert any kind of array (buffer) to an std::vector.
template <typename TYPE> std::vector<TYPE> toVector(TYPE in[]) {
return std::vector<TYPE>(in, in+sizeof(in)/sizeof(in[0]));
}
#define CRYPTOKI_TO_VECTOR(ARRAY) \
toVector<sizeof(ARRAY)/sizeof(ARRAY[0])>(ARRAY)
//@}
@ -136,10 +154,9 @@ namespace cryptoki {
class Object;
typedef std::vector<Object> ObjectList;
typedef std::set<CK_MECHANISM_TYPE> MechanismList;
typedef std::vector<CK_ATTRIBUTE_TYPE> AttributeTypeList;
/// Represents a cryproki attribute and maps to C++ types.
class Attribute {
public:
Attribute(CK_ATTRIBUTE_TYPE t = -1): type(t) {}
@ -171,6 +188,7 @@ namespace cryptoki {
a.ulValueLen = value.size();
return a;
}
/// Textual name of the attribute.
std::string name() const {
switch (type) {
case CKA_CLASS: return "CLASS";
@ -234,30 +252,39 @@ namespace cryptoki {
case CKA_HAS_RESET: return "HAS_RESET";
case CKA_VENDOR_DEFINED: return "VENDOR_DEFINED";
//case CKA_IBM_OPAQUE: return "IBM_OPAQUE";
default: return "unknown";
default: return "UNKNOWN";
}
}
std::string readableValue() const {
/// Textual representation of the value.
std::string readableValue(std::string::size_type len=20,
std::string::size_type indent=0) const {
std::string res(indent, ' ');
switch (type) {
case CKA_CLASS:
switch (*((CK_OBJECT_CLASS*)&value[0])) {
case CKO_DATA: return "DATA";
case CKO_CERTIFICATE: return "CERTIFICATE";
case CKO_PUBLIC_KEY: return "PUBLIC_KEY";
case CKO_PRIVATE_KEY: return "PRIVATE_KEY";
case CKO_SECRET_KEY: return "SECRET_KEY";
case CKO_HW_FEATURE: return "HW_FEATURE";
case CKO_DOMAIN_PARAMETERS: return "DOMAIN_PARAMETERS";
case CKO_VENDOR_DEFINED: return "VENDOR_DEFINED";
default: return "unknown";
case CKO_DATA: return res+"DATA";
case CKO_CERTIFICATE: return res+"CERTIFICATE";
case CKO_PUBLIC_KEY: return res+"PUBLIC_KEY";
case CKO_PRIVATE_KEY: return res+"PRIVATE_KEY";
case CKO_SECRET_KEY: return res+"SECRET_KEY";
case CKO_HW_FEATURE: return res+"HW_FEATURE";
case CKO_DOMAIN_PARAMETERS: return res+"DOMAIN_PARAMETERS";
case CKO_VENDOR_DEFINED: return res+"VENDOR_DEFINED";
default: return res+"UNKNOWN";
}
default: return crypto::readable(value);
default: return crypto::readable(value, len, indent);
}
}
/// Initialize from a given type.
/** To use this method, you must know what type the attribute
represents. */
template<typename TYPE> Attribute& from(const TYPE& v) {
value = std::string((char*)&v, sizeof(TYPE));
return *this;
}
/// Convert to a given type.
/** To use this method, you must know what type the attribute
represents. */
template<typename TYPE> TYPE to() const {
assert(sizeof(TYPE)==value.size());
return *reinterpret_cast<const TYPE*>(&value[0]);
@ -268,91 +295,70 @@ namespace cryptoki {
typedef std::map<CK_ATTRIBUTE_TYPE, Attribute> AttributeMap;
typedef std::vector<Attribute> AttributeList;
// class Class {
// public:
// CK_OBJECT_CLASS class;
// };
//class
// //! Map Attribute Class to type
// /*! @todo to be completed ... */
// #define CRYPTOKI_DECLARE_ATTR(ATTR_ID, TYPE) \//
// template<> class AttributeType<ATTR_ID> { \//
// public: typedef TYPE Type; \//
// }
// template<CK_ATTRIBUTE_TYPE Attribute> class AttributeType {};
// CRYPTOKI_DECLARE_ATTR(CKA_CLASS, CK_OBJECT_CLASS);
// CRYPTOKI_DECLARE_ATTR(CKA_HW_FEATURE_TYPE, CK_HW_FEATURE);
// CRYPTOKI_DECLARE_ATTR(CKA_VALUE, FixString<16>);
// CRYPTOKI_DECLARE_ATTR(CKA_RESET_ON_INIT, CK_BBOOL);
// CRYPTOKI_DECLARE_ATTR(CKA_HAS_RESET, CK_BBOOL);
// // CRYPTOKI_DECLARE_ATTR(CKA_VALUE, ); - byte array
// // CRYPTOKI_DECLARE_ATTR(, );
// // CRYPTOKI_DECLARE_ATTR(, );
// // CRYPTOKI_DECLARE_ATTR(, );
// // CRYPTOKI_DECLARE_ATTR(, );
// template<> class AttributeType<CKA_KEY_TYPE> {
// public: typedef CK_KEY_TYPE Type;
// public: typedef Type Param;
// };
// template<> class AttributeType<CKA_APPLICATION> {
// public: typedef CK_CHAR Type;
// public: typedef std::string Param;
// };
// template<> class AttributeType<CKA_VALUE> {
// public: typedef CKA_BYTE Type;
// public: typedef std::string Param;
// };
// #undef CRYPTOKI_DECLARE_ATTR
/// String with fixed length.
/** FixString represents a string with a fix with spaces and can be
converted from and to a std::string by adding and removing the
fill-spaces. */
template<std::string::size_type SIZE>
class FixString: public std::string {
public:
FixString() {}
FixString(const char* const cStr) {
*this = std::string(cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
}
FixString(const unsigned char* const cStr) {
*this = std::string((const char*)cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
}
FixString& operator=(const std::string& other) {
std::string::operator=(other);
return *this;
}
FixString& operator=(const char* const cStr) {
*this = std::string(cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
return *this;
}
FixString& operator=(const unsigned char* const cStr) {
*this = std::string((const char*)cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
return *this;
}
operator unsigned char*() {
return (unsigned char*)begin().operator->();
}
FixString fix() {
FixString cpy(*this);
cpy.resize(SIZE, ' ');
return cpy;
}
};
public:
FixString() {}
FixString(const char* const cStr) {
*this = std::string(cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
}
FixString(const unsigned char* const cStr) {
*this = std::string((const char*)cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
}
FixString& operator=(const std::string& other) {
std::string::operator=(other);
return *this;
}
FixString& operator=(const char* const cStr) {
*this = std::string(cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
return *this;
}
FixString& operator=(const unsigned char* const cStr) {
*this = std::string((const char*)cStr, SIZE);
size_type pos(find_last_not_of(" "));
if (pos!=npos) resize(pos+1); else resize(0);
return *this;
}
operator unsigned char*() {
return (unsigned char*)begin().operator->();
}
FixString fix() {
FixString cpy(*this);
cpy.resize(SIZE, ' ');
return cpy;
}
};
/// C++ representation of mechanism information.
struct MechanismInfo {
CK_MECHANISM_TYPE id;
std::string name;
CK_ULONG minKeySize;
CK_ULONG maxKeySize;
CK_FLAGS flags;
MechanismInfo(CK_MECHANISM_TYPE type): id(type) {
/// Construct from type with undefined infos. Use assigment later.
MechanismInfo(CK_MECHANISM_TYPE type):
minKeySize(0), maxKeySize(0), flags(0) {
*this=type;
}
/// Fully construct from type and infos.
MechanismInfo(CK_MECHANISM_TYPE type, const CK_MECHANISM_INFO& info) {
*this=type;
*this=info;
}
/// Set name and id from CK_MECHANISM_TYPE.
MechanismInfo& operator=(CK_MECHANISM_TYPE type) {
id=type;
switch (id) {
case CKM_RSA_PKCS_KEY_PAIR_GEN: name="RSA_PKCS_KEY_PAIR_GEN"; break;
case CKM_RSA_PKCS: name="RSA_PKCS"; break;
@ -378,7 +384,7 @@ namespace cryptoki {
case CKM_X9_42_DH_DERIVE: name="X9_42_DH_DERIVE"; break;
case CKM_X9_42_DH_HYBRID_DERIVE: name="X9_42_DH_HYBRID_DERIVE"; break;
case CKM_X9_42_MQV_DERIVE: name="X9_42_MQV_DERIVE"; break;
//case CKM_SHA256_RSA_PKCS: name="SHA256_RSA_PKCS"; break;
case CKM_SHA256_RSA_PKCS: name="SHA256_RSA_PKCS"; break;
case CKM_RC2_KEY_GEN: name="RC2_KEY_GEN"; break;
case CKM_RC2_ECB: name="RC2_ECB"; break;
case CKM_RC2_CBC: name="RC2_CBC"; break;
@ -421,15 +427,15 @@ namespace cryptoki {
case CKM_RIPEMD160: name="RIPEMD160"; break;
case CKM_RIPEMD160_HMAC: name="RIPEMD160_HMAC"; break;
case CKM_RIPEMD160_HMAC_GENERAL: name="RIPEMD160_HMAC_GENERAL"; break;
//case CKM_SHA256: name="SHA256"; break;
//case CKM_SHA256_HMAC: name="SHA256_HMAC"; break;
//case CKM_SHA256_HMAC_GENERAL: name="SHA256_HMAC_GENERAL"; break;
//case CKM_SHA384: name="SHA384"; break;
//case CKM_SHA384_HMAC: name="SHA384_HMAC"; break;
//case CKM_SHA384_HMAC_GENERAL: name="SHA384_HMAC_GENERAL"; break;
//case CKM_SHA512: name="SHA512"; break;
//case CKM_SHA512_HMAC: name="SHA512_HMAC"; break;
//case CKM_SHA512_HMAC_GENERAL: name="SHA512_HMAC_GENERAL"; break;
case CKM_SHA256: name="SHA256"; break;
case CKM_SHA256_HMAC: name="SHA256_HMAC"; break;
case CKM_SHA256_HMAC_GENERAL: name="SHA256_HMAC_GENERAL"; break;
case CKM_SHA384: name="SHA384"; break;
case CKM_SHA384_HMAC: name="SHA384_HMAC"; break;
case CKM_SHA384_HMAC_GENERAL: name="SHA384_HMAC_GENERAL"; break;
case CKM_SHA512: name="SHA512"; break;
case CKM_SHA512_HMAC: name="SHA512_HMAC"; break;
case CKM_SHA512_HMAC_GENERAL: name="SHA512_HMAC_GENERAL"; break;
case CKM_CAST_KEY_GEN: name="CAST_KEY_GEN"; break;
case CKM_CAST_ECB: name="CAST_ECB"; break;
case CKM_CAST_CBC: name="CAST_CBC"; break;
@ -442,19 +448,21 @@ namespace cryptoki {
case CKM_CAST3_MAC: name="CAST3_MAC"; break;
case CKM_CAST3_MAC_GENERAL: name="CAST3_MAC_GENERAL"; break;
case CKM_CAST3_CBC_PAD: name="CAST3_CBC_PAD"; break;
//case CKM_CAST5_KEY_GEN: name="CAST5_KEY_GEN"; break;
case CKM_CAST128_KEY_GEN: name="CAST5_KEY_GEN or CAST128_KEY_GEN"; break;
//case CKM_CAST5_ECB: name="CAST5_ECB"; break;
case CKM_CAST128_ECB: name="CAST5_ECB or CAST128_ECB"; break;
//case CKM_CAST5_CBC: name="CAST5_CBC"; break;
case CKM_CAST128_CBC: name="CAST5_CBC or CAST128_CBC"; break;
//case CKM_CAST5_MAC: name="CAST5_MAC"; break;
case CKM_CAST128_MAC: name="CAST5_MAC or CAST128_MAC"; break;
//case CKM_CAST5_MAC_GENERAL: name="CAST5_MAC_GENERAL"; break;
case CKM_CAST128_MAC_GENERAL:
name="CAST5_MAC_GENERAL or CAST128_MAC_GENERAL"; break;
//case CKM_CAST5_CBC_PAD: name="CAST5_CBC_PAD"; break;
case CKM_CAST128_CBC_PAD: name="CAST5_CBC_PAD or CAST128_CBC_PAD"; break;
case CKM_CAST5_KEY_GEN: name="CAST5_KEY_GEN"; break;
//case CKM_CAST128_KEY_GEN: name="CAST5_KEY_GEN or
//CAST128_KEY_GEN"; break;
case CKM_CAST5_ECB: name="CAST5_ECB"; break;
//case CKM_CAST128_ECB: name="CAST5_ECB or CAST128_ECB"; break;
case CKM_CAST5_CBC: name="CAST5_CBC"; break;
//case CKM_CAST128_CBC: name="CAST5_CBC or CAST128_CBC"; break;
case CKM_CAST5_MAC: name="CAST5_MAC"; break;
//case CKM_CAST128_MAC: name="CAST5_MAC or CAST128_MAC"; break;
case CKM_CAST5_MAC_GENERAL: name="CAST5_MAC_GENERAL"; break;
//case CKM_CAST128_MAC_GENERAL: name="CAST5_MAC_GENERAL or
//CAST128_MAC_GENERAL"; break;
case CKM_CAST5_CBC_PAD: name="CAST5_CBC_PAD"; break;
//case CKM_CAST128_CBC_PAD: name="CAST5_CBC_PAD or
//CAST128_CBC_PAD"; break;
case CKM_RC5_KEY_GEN: name="RC5_KEY_GEN"; break;
case CKM_RC5_ECB: name="RC5_ECB"; break;
case CKM_RC5_CBC: name="RC5_CBC"; break;
@ -476,31 +484,34 @@ namespace cryptoki {
name="CONCATENATE_DATA_AND_BASE"; break;
case CKM_XOR_BASE_AND_DATA: name="XOR_BASE_AND_DATA"; break;
case CKM_EXTRACT_KEY_FROM_KEY: name="EXTRACT_KEY_FROM_KEY"; break;
case CKM_SSL3_PRE_MASTER_KEY_GEN: name="SSL3_PRE_MASTER_KEY_GEN"; break;
case CKM_SSL3_PRE_MASTER_KEY_GEN:
name="SSL3_PRE_MASTER_KEY_GEN"; break;
case CKM_SSL3_MASTER_KEY_DERIVE: name="SSL3_MASTER_KEY_DERIVE"; break;
case CKM_SSL3_KEY_AND_MAC_DERIVE: name="SSL3_KEY_AND_MAC_DERIVE"; break;
case CKM_SSL3_KEY_AND_MAC_DERIVE:
name="SSL3_KEY_AND_MAC_DERIVE"; break;
case CKM_SSL3_MASTER_KEY_DERIVE_DH:
name="SSL3_MASTER_KEY_DERIVE_DH"; break;
case CKM_TLS_PRE_MASTER_KEY_GEN: name="TLS_PRE_MASTER_KEY_GEN"; break;
case CKM_TLS_MASTER_KEY_DERIVE: name="TLS_MASTER_KEY_DERIVE"; break;
case CKM_TLS_KEY_AND_MAC_DERIVE: name="TLS_KEY_AND_MAC_DERIVE"; break;
case CKM_TLS_MASTER_KEY_DERIVE_DH: name="TLS_MASTER_KEY_DERIVE_DH"; break;
case CKM_TLS_MASTER_KEY_DERIVE_DH:
name="TLS_MASTER_KEY_DERIVE_DH"; break;
case CKM_SSL3_MD5_MAC: name="SSL3_MD5_MAC"; break;
case CKM_SSL3_SHA1_MAC: name="SSL3_SHA1_MAC"; break;
case CKM_MD5_KEY_DERIVATION: name="MD5_KEY_DERIVATION"; break;
case CKM_MD2_KEY_DERIVATION: name="MD2_KEY_DERIVATION"; break;
case CKM_SHA1_KEY_DERIVATION: name="SHA1_KEY_DERIVATION"; break;
//case CKM_SHA256_KEY_DERIVATION: name="SHA256_KEY_DERIVATION"; break;
case CKM_SHA256_KEY_DERIVATION: name="SHA256_KEY_DERIVATION"; break;
case CKM_PBE_MD2_DES_CBC: name="PBE_MD2_DES_CBC"; break;
case CKM_PBE_MD5_DES_CBC: name="PBE_MD5_DES_CBC"; break;
case CKM_PBE_MD5_CAST_CBC: name="PBE_MD5_CAST_CBC"; break;
case CKM_PBE_MD5_CAST3_CBC: name="PBE_MD5_CAST3_CBC"; break;
//case CKM_PBE_MD5_CAST5_CBC: name="PBE_MD5_CAST5_CBC"; break;
case CKM_PBE_MD5_CAST128_CBC:
name="PBE_MD5_CAST5_CBC or PBE_MD5_CAST128_CBC"; break;
//case CKM_PBE_SHA1_CAST5_CBC: name="PBE_SHA1_CAST5_CBC"; break;
case CKM_PBE_SHA1_CAST128_CBC:
name="PBE_SHA1_CAST5_CBC or PBE_SHA1_CAST128_CBC"; break;
case CKM_PBE_MD5_CAST5_CBC: name="PBE_MD5_CAST5_CBC"; break;
//case CKM_PBE_MD5_CAST128_CBC: name="PBE_MD5_CAST5_CBC or
//PBE_MD5_CAST128_CBC"; break;
case CKM_PBE_SHA1_CAST5_CBC: name="PBE_SHA1_CAST5_CBC"; break;
//case CKM_PBE_SHA1_CAST128_CBC: name="PBE_SHA1_CAST5_CBC or
//PBE_SHA1_CAST128_CBC"; break;
case CKM_PBE_SHA1_RC4_128: name="PBE_SHA1_RC4_128"; break;
case CKM_PBE_SHA1_RC4_40: name="PBE_SHA1_RC4_40"; break;
case CKM_PBE_SHA1_DES3_EDE_CBC: name="PBE_SHA1_DES3_EDE_CBC"; break;
@ -508,7 +519,8 @@ namespace cryptoki {
case CKM_PBE_SHA1_RC2_128_CBC: name="PBE_SHA1_RC2_128_CBC"; break;
case CKM_PBE_SHA1_RC2_40_CBC: name="PBE_SHA1_RC2_40_CBC"; break;
case CKM_PKCS5_PBKD2: name="PKCS5_PBKD2"; break;
case CKM_PBA_SHA1_WITH_SHA1_HMAC: name="PBA_SHA1_WITH_SHA1_HMAC"; break;
case CKM_PBA_SHA1_WITH_SHA1_HMAC:
name="PBA_SHA1_WITH_SHA1_HMAC"; break;
case CKM_KEY_WRAP_LYNKS: name="KEY_WRAP_LYNKS"; break;
case CKM_KEY_WRAP_SET_OAEP: name="KEY_WRAP_SET_OAEP"; break;
case CKM_SKIPJACK_KEY_GEN: name="SKIPJACK_KEY_GEN"; break;
@ -532,9 +544,9 @@ namespace cryptoki {
case CKM_BATON_COUNTER: name="BATON_COUNTER"; break;
case CKM_BATON_SHUFFLE: name="BATON_SHUFFLE"; break;
case CKM_BATON_WRAP: name="BATON_WRAP"; break;
//case CKM_ECDSA_KEY_PAIR_GEN: name="ECDSA_KEY_PAIR_GEN"; break;
case CKM_EC_KEY_PAIR_GEN:
name="ECDSA_KEY_PAIR_GEN or EC_KEY_PAIR_GEN"; break;
case CKM_ECDSA_KEY_PAIR_GEN: name="ECDSA_KEY_PAIR_GEN"; break;
//case CKM_EC_KEY_PAIR_GEN: name="ECDSA_KEY_PAIR_GEN or
//EC_KEY_PAIR_GEN"; break;
case CKM_ECDSA: name="ECDSA"; break;
case CKM_ECDSA_SHA1: name="ECDSA_SHA1"; break;
case CKM_ECDH1_DERIVE: name="ECDH1_DERIVE"; break;
@ -559,13 +571,26 @@ namespace cryptoki {
case CKM_VENDOR_DEFINED: name="VENDOR_DEFINED"; break;
default: {
std::stringstream ss;
ss<<"unknown mechanism: "<<id;
throw exception(ss.str());
ss<<id;
name=ss.str();
}
}
return *this;
}
/// Assign information.
MechanismInfo& operator=(const CK_MECHANISM_INFO& info) {
minKeySize = info.ulMinKeySize;
maxKeySize = info.ulMaxKeySize;
flags = info.flags;
return *this;
}
bool operator<(const MechanismInfo& o) const {
return id<o.id;
}
};
typedef std::set<MechanismInfo> MechanismList;
/// Handle slot information.
struct SlotInfo {
FixString<64> slotDescription;
FixString<32> manufacturerID;
@ -589,6 +614,7 @@ namespace cryptoki {
struct TokenInfo; // forward declaration
inline std::ostream& operator<<(std::ostream& out, const TokenInfo& ti);
/// Handle token information.
struct TokenInfo {
FixString<32> label;
FixString<32> manufacturerID;
@ -638,6 +664,7 @@ namespace cryptoki {
};
/// Textual representation for token information.
inline std::ostream& operator<<(std::ostream& out, const TokenInfo& ti) {
return out
<<"label="<<ti.label<<std::endl
@ -661,7 +688,8 @@ namespace cryptoki {
<<ti.firmwareVersion.minor<<std::endl
<<"utcTime="<<ti.utcTime;
}
/// Handle library information.
struct Info {
CK_VERSION cryptokiVersion;
FixString<32> manufacturerID;
@ -676,20 +704,22 @@ namespace cryptoki {
//@{
/// Load Cryptoki Library for use with Smart Card.
/** This is your starting point when accessing tokens through
PKCS#11. Get an instance using Library::Library. */
class Library {
friend class Slot;
public:
//! Initialize for a given library (default cryptoki)
/*! Please notem, that you must not instanciate more than one
Init per unique function list!
//! Initialize for a given library
/*! @note Do not instanciate more than one Library instance per
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(library, exc) {
_init(new Init(library, exc)) {
CRYPTOLOG("log");
}
@ -699,8 +729,9 @@ namespace cryptoki {
CRYPTOLOG("log");
}
public:
private:
/// Initiatlize the library: load and unload the shared object.
class Init {
private:
@ -725,13 +756,8 @@ namespace cryptoki {
std::string error(CK_RV res);
public:
//! Initialize for a given library (default cryptoki)
/*! Please notem, that you must not instanciate more than one
Init per unique function list!
@param library name of the shared library that supports pkcs#11
@param exc wether exceptions should be thrown */
/// Called from Library::Library
Init(const std::string& library="opensc-pkcs11.so", bool exc=true);
~Init();
@ -767,14 +793,12 @@ namespace cryptoki {
public:
/// Get pointer to cryptoki API functions.
/** Used internally, normally you shouldn't use this directly. */
CK_FUNCTION_LIST* operator->() {
return _init->fn();
}
bool exc() {
return _init->_exc;
}
/*! @name C Like Error Handling
You are strongly recommended not to disable exception
@ -782,6 +806,11 @@ namespace cryptoki {
operation whether it was successful or not. These methods
provide all you need for that. */
//@{
/// @return true if exceptions are thrown in case of error
bool exc() {
return _init->_exc;
}
/*! @return @c true if last cryptoki on this object call was successful */
operator bool() {
@ -792,13 +821,15 @@ namespace cryptoki {
std::string error() {
return _init->error();
}
/// Convert @c CK_RV return code to a human readable text.
std::string error(CK_RV res) {
return _init->error(res);
}
//@}
/// Get cryptoki library informartion.
Info info() {
CRYPTOLOG("log");
Info inf;
@ -825,7 +856,7 @@ namespace cryptoki {
private:
mrw::Shared<Init> _init;
std::shared_ptr<Init> _init;
};
@ -843,16 +874,21 @@ namespace cryptoki {
public:
Slot(const Library& lib, CK_SLOT_ID slot):
_library(lib), _slot(slot), _res(CKR_OK) {
Slot(const Slot& o):
_library(o._library), _slot(o._slot), _res(o._res) {
CRYPTOLOG("ID="<<_slot);
}
Slot(const Slot& o):
_library(o._library), _slot(o._slot), _res(o._res) {
private:
/// Slots are created from Library::slotList.
Slot(const Library& lib, CK_SLOT_ID slot):
_library(lib), _slot(slot), _res(CKR_OK) {
CRYPTOLOG("ID="<<_slot);
}
/// Slots are created from Library::slotList.
/** Empty constructor needs immediate assignment. */
Slot(): _slot(0), _res(-1) {
CRYPTOLOG("ID="<<_slot);
}
@ -877,6 +913,8 @@ namespace cryptoki {
return _res==CKR_OK;
}
public:
/*! @name C Like Error Handling
You are strongly recommended not to disable exception
@ -897,23 +935,23 @@ namespace cryptoki {
//@}
/// Access to the Library.
Library& library() {
return _library;
}
/// Get the Slot's MechanismInfo given a @c CK_MECHANISM_TYPE
/** Used internally by mechanismlist(). */
MechanismInfo mechanisminfo(CK_MECHANISM_TYPE mechanism) {
CRYPTOLOG("log");
MechanismInfo info(mechanism);
CK_MECHANISM_INFO cInfo;
CK_MECHANISM_INFO info;
//! calls @c C_GetMechanismInfo
check(_library->C_GetMechanismInfo(_slot, mechanism, &cInfo),
check(_library->C_GetMechanismInfo(_slot, mechanism, &info),
CRYPTOKI_FN_LOG("C_GetMechanismInfo"));
info.minKeySize = cInfo.ulMinKeySize;
info.maxKeySize = cInfo.ulMaxKeySize;
info.flags = cInfo.flags;
return info;
return MechanismInfo(mechanism, info);
}
/// Get a list of the Slot's mechanisms.
MechanismList mechanismlist() {
CRYPTOLOG("log");
MechanismList res;
@ -930,7 +968,7 @@ namespace cryptoki {
return res;
}
for (CK_ULONG i(0); i<count; ++i)
res.insert(mechanisms[i]);
res.insert(mechanisminfo(mechanisms[i]));
} catch (...) {
delete[] mechanisms;
throw;
@ -961,18 +999,79 @@ namespace cryptoki {
return TokenInfo(cInfo);
}
/*! @bug does not compile:
@code
/// Initialize a token.
/** If the token has not been initialized (i.e. new from the
factory), then the @c pin parameter becomes the initial value
of the SO PIN. If the token is being reinitialized, the @c pin
parameter is checked against the existing SO PIN to
authorize the initialization operation. In both cases, the
SO PIN is the value @c pin after the function completes
successfully. If the SO PIN is lost, then the card must be
reinitialized using a mechanism outside the scope of this
standard. The CKF_TOKEN_INITIALIZED flag in the
CK_TOKEN_INFO structure indicates the action that will
result from calling C_InitToken. If set, the token will be
reinitialized, and the client must supply the existing SO
password in @c pin.
When a token is initialized, all objects that can be
destroyed are destroyed (i.e., all except for
indestructible objects such as keys built into the
token). Also, access by the normal user is disabled until
the SO sets the normal users PIN. Depending on the token,
some default objects may be created, and attributes of
some objects may be set to default values.
If the token has a protected authentication path, as
indicated by the CKF_PROTECTED_AUTHENTICATION_PATH flag in
its CK_TOKEN_INFO being set, then that means that there is
some way for a user to be authenticated to the token without
having the application send a PIN through the Cryptoki
library. One such possibility is that the user enters a PIN
on a PINpad on the token itself, or on the slot device. To
initialize a token with such a protected authentication
path, the @c pin parameter to C_InitToken should be empty.
During the execution of C_InitToken, the SOs PIN will be
entered through the protected authentication path.
If the token has a protected authentication path other than
a PINpad, then it is token- dependent whether or not
C_InitToken can be used to initialize the token.
A token cannot be initialized if Cryptoki detects that any
application has an open session with it; when a call to
C_InitToken is made under such circumstances, the call fails
with error CKR_SESSION_EXISTS. Unfortunately, it may happen
when C_InitToken is called that some other application does
have an open session with the token, but Cryptoki cannot
detect this, because it cannot detect anything about other
applications using the token. If this is the case, then the
consequences of the C_InitToken call are undefined.
The C_InitToken function may not be sufficient to properly
initialize complex tokens. In these situations, an
initialization mechanism outside the scope of Cryptoki must
be employed. The definition of complex token is product
specific.
@param pin SO's initial PIN
@param label label of the token */
bool inittoken(std::string pin, FixString<32> label) {
CRYPTOLOG("log");
CRYPTOLOG("log");
//! calls @c C_InitToken
return check(_library->C_InitToken
(_slot,
(unsigned char*)&pin[0], pin.size(),
(unsigned char*)label.&fix()[0])
CRYPTOKI_FN_LOG("C_InitToken"));
if (pin.size())
return check(_library->C_InitToken
(_slot,
(unsigned char*)&pin[0], pin.size(),
(unsigned char*)&label.fix()[0]),
CRYPTOKI_FN_LOG("C_InitToken"));
else
return check(_library->C_InitToken
(_slot,
0, 0, // pin from external pin pad
(unsigned char*)&label.fix()[0]),
CRYPTOKI_FN_LOG("C_InitToken"));
}
@endcode */
/*! @todo Not implemented:
@code
@ -983,14 +1082,14 @@ namespace cryptoki {
bool registerforslotevent(SlotEventListener&) {
CRYPTOLOG("log");
//! calls @c C_WaitForSlotEvent
return check(_library->C_WaitForSlotEvent(CK_FLAGS, &_slot, CK_VOID_PTR),
return check(_library->C_WaitForSlotEvent(CK_FLAGS, &_slot, 0),
CRYPTOKI_FN_LOG("C_WaitForSlotEvent"));
}
@endcode */
};
//! Session Management
//! Not implemented: CK_RV C_CloseAllSessions(CK_SLOT_ID);
/// Session Management
/** @note Not implemented: CK_RV C_CloseAllSessions(CK_SLOT_ID); */
class Session {
private:
@ -2167,14 +2266,16 @@ namespace cryptoki {
}
//! @groupadd globaloperator
//! @groupadd cryptokitypes
//@{
/// Append a cryptoki::Attribute to a cryptoki::AttributeList.
inline cryptoki::AttributeList& operator<<(cryptoki::AttributeList& list,
const cryptoki::Attribute& attr) {
CRYPTOLOG("log");
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) {
CRYPTOLOG("log");
@ -2184,5 +2285,4 @@ inline cryptoki::AttributeList operator<<(const cryptoki::AttributeList& list,
}
//@}
//@}
#endif

@ -133,6 +133,12 @@ namespace suisseid {
no_digsig() throw():
exception("no digital signature certificate found") {}
};
//----------------------------------------------------------------------------
class slot_not_found: public exception {
public:
slot_not_found(const std::string& name) throw():
exception("matching cryptoki slot for "+name+" not found") {}
};
//@}
/*! @addtogroup suisseidtypes */
@ -145,9 +151,12 @@ namespace suisseid {
/*! @addtogroup suisseidconsts */
//@{
const std::string NON_REP = "SwissSign_nonRep ";
const std::string DIG_SIG = "SwissSign_digSig ";
const std::string DATA_ENC = "SwissSign_dataEnc ";
/// Label of the key for digital signature certificate.
const std::string NON_REP = "SwissSign_nonRep ";
/// Label of the key for authentication certificate
const std::string DIG_SIG = "SwissSign_digSig ";
/// Label of the key required for getting the certificates
const std::string DATA_ENC = "SwissSign_dataEnc ";
//@}
/*! @addtogroup suisseidlib */
@ -160,16 +169,22 @@ namespace suisseid {
public:
/// Status of the card's certificates
/** @note by now, only @c MISSING and @c VALID is supported */
enum CertStatus {
MISSING,
EXPIRES_SOON,
EXPIRED,
REVOKED,
VALID
MISSING, ///< certificate is missing, needs initiatlization
EXPIRES_SOON, ///< certificate will soon expire, needs renewal
EXPIRED, ///< certificate is expired, needs new purchase
REVOKED, ///< certificate has been revoked and is invalid
VALID ///< certificate is valid
};
public:
/// Instanciation is done within suisseid::Scanner
/** Instance requires a connenction to the reader an a cryptoky
library. This is passes automatically when this class is
instanciated through suisseid::Scanner. */
Card(mrw::Shared<pcsc::Connection::Reader> reader,
const cryptoki::Library& cryptoki):
cardos::Commands(reader),
@ -177,13 +192,17 @@ namespace suisseid {
}
virtual ~Card() {}
/// Find the matching cryptoki::Slot for further access
/** @throws slot_not_found if not exactly one matching slot exists */
cryptoki::Slot slot() {
cryptoki::SlotList slots(_cryptoki.slotList(true, name()));
if (slots.size()==1) return slots[0];
throw std::runtime_error("matching cryptoki slot not found");
throw slot_not_found(name());
}
/// Minimum allowed PIN length for this card.
virtual unsigned int minimalPinLength() = 0;
/// Maximum allowed PIN length for this card.
virtual unsigned int maximalPinLength() = 0;
//! Name of the token/slot
@ -196,15 +215,17 @@ namespace suisseid {
return "<unknown>";
}
/// status of the certificates on the card
/// Status of the certificates on the card
virtual CertStatus certStatus() {
return MISSING;
}
/// Starts and returns a cryptoki::Session.
cryptoki::Session session() {
return cryptoki::Session(slot());
}
/// Starts a cryptoki::Session and returns cryptoki::Session::Info.
cryptoki::Session::Info sessionInfo() {
return session().getsessioninfo();
}
@ -258,7 +279,8 @@ namespace suisseid {
class Post: public Card {
public:
/// @copydoc Card::Card
Post(mrw::Shared<pcsc::Connection::Reader> reader,
const cryptoki::Library& cryptoki):
Card(reader, cryptoki), _minPinLen(0), _maxPinLen(-1) {

Loading…
Cancel
Save