|
|
@ -17,6 +17,8 @@ |
|
|
|
// for inline implementations only
|
|
|
|
// for inline implementations only
|
|
|
|
#include <sstream> |
|
|
|
#include <sstream> |
|
|
|
#include <cstdlib> // malloc/free |
|
|
|
#include <cstdlib> // malloc/free |
|
|
|
|
|
|
|
#include <cstring> // memset |
|
|
|
|
|
|
|
#include <iomanip> |
|
|
|
|
|
|
|
|
|
|
|
#include <iostream> // debug |
|
|
|
#include <iostream> // debug |
|
|
|
|
|
|
|
|
|
|
@ -34,6 +36,31 @@ namespace cryptoki { |
|
|
|
#define UNDEF_CRYPTOKI_FN_LOG |
|
|
|
#define UNDEF_CRYPTOKI_FN_LOG |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string hex(const std::string& data) { |
|
|
|
|
|
|
|
std::stringstream res; |
|
|
|
|
|
|
|
for (std::string::const_iterator it(data.begin()); it!=data.end(); ++it) |
|
|
|
|
|
|
|
res<<std::hex<<std::setfill('0')<<std::setw(2) |
|
|
|
|
|
|
|
<<(unsigned int)(unsigned char)*it; |
|
|
|
|
|
|
|
return res.str(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const std::string LETTER_CHARS |
|
|
|
|
|
|
|
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); |
|
|
|
|
|
|
|
static const std::string NUMBER_CHARS |
|
|
|
|
|
|
|
("0123456789"); |
|
|
|
|
|
|
|
static const std::string GRAFIC_CHARS |
|
|
|
|
|
|
|
("!\"#%&'()*+,-./:;<=>?[\\]^_{|}~"); |
|
|
|
|
|
|
|
static const std::string BLANK_CHARS |
|
|
|
|
|
|
|
(" "); |
|
|
|
|
|
|
|
static const std::string VALID_CHARS |
|
|
|
|
|
|
|
(LETTER_CHARS+NUMBER_CHARS+GRAFIC_CHARS+BLANK_CHARS); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string readable(const std::string& data) { |
|
|
|
|
|
|
|
if (data.find_first_not_of(VALID_CHARS)<data.size()) |
|
|
|
|
|
|
|
return hex(data); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return data; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <int NUM, typename TYPE> std::vector<TYPE> toVector(TYPE in[NUM]) { |
|
|
|
template <int NUM, typename TYPE> std::vector<TYPE> toVector(TYPE in[NUM]) { |
|
|
|
return std::vector<TYPE>(in, in+NUM); |
|
|
|
return std::vector<TYPE>(in, in+NUM); |
|
|
@ -515,10 +542,29 @@ namespace cryptoki { |
|
|
|
/*! Please notem, that you must not instanciate more than one
|
|
|
|
/*! Please notem, that you must not instanciate more than one
|
|
|
|
Init per unique function list! |
|
|
|
Init per unique function list! |
|
|
|
|
|
|
|
|
|
|
|
@param fn function list to be used within this instance |
|
|
|
@param library name of the shared library that supports pkcs#11 |
|
|
|
@param exc wether exceptions should be thrown */ |
|
|
|
@param exc wether exceptions should be thrown */ |
|
|
|
Init(const std::string& library="onepin-opensc-pkcs11.so", bool exc=true); |
|
|
|
Init(const std::string& library="onepin-opensc-pkcs11.so", bool exc=true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~Init() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
//! calls @c C_Finalize
|
|
|
|
|
|
|
|
return check(_slot._init->_fn->C_Finalize(0), |
|
|
|
|
|
|
|
CRYPTOKI_FN_LOG("C_Finalize")); |
|
|
|
|
|
|
|
} catch (...) { |
|
|
|
|
|
|
|
if (!std::uncaught_exception()) throw; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! @todo Not implemented:
|
|
|
|
|
|
|
|
@code |
|
|
|
|
|
|
|
bool finalize() { |
|
|
|
|
|
|
|
//! calls @c C_Finalize
|
|
|
|
|
|
|
|
return check(_slot._init->_fn->C_Finalize(CK_VOID_PTR), |
|
|
|
|
|
|
|
CRYPTOKI_FN_LOG("C_Finalize")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! @name C Like Error Handling
|
|
|
|
/*! @name C Like Error Handling
|
|
|
|
|
|
|
|
|
|
|
|
You are strongly recommended not to disable exception |
|
|
|
You are strongly recommended not to disable exception |
|
|
@ -575,7 +621,7 @@ namespace cryptoki { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
_res = result; |
|
|
|
_res = result; |
|
|
|
if (_init->_exc && !*this) |
|
|
|
if (_init->_exc && !*this) |
|
|
|
if (context.size()) |
|
|
|
if (!context.empty()) |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
else |
|
|
|
else |
|
|
|
throw access_error(error()); |
|
|
|
throw access_error(error()); |
|
|
@ -725,7 +771,7 @@ namespace cryptoki { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
_res = result; |
|
|
|
_res = result; |
|
|
|
if (_slot._init->_exc && !*this) |
|
|
|
if (_slot._init->_exc && !*this) |
|
|
|
if (context.size()) |
|
|
|
if (!context.empty()) |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
else |
|
|
|
else |
|
|
|
throw access_error(error()); |
|
|
|
throw access_error(error()); |
|
|
@ -951,14 +997,6 @@ namespace cryptoki { |
|
|
|
res.resize(size); |
|
|
|
res.resize(size); |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*! @todo Not implemented:
|
|
|
|
|
|
|
|
@code |
|
|
|
|
|
|
|
bool finalize() { |
|
|
|
|
|
|
|
//! calls @c C_Finalize
|
|
|
|
|
|
|
|
return check(_slot._init->_fn->C_Finalize(CK_VOID_PTR), |
|
|
|
|
|
|
|
CRYPTOKI_FN_LOG("C_Finalize")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
@endcode */ |
|
|
|
@endcode */ |
|
|
|
|
|
|
|
|
|
|
|
/*! @todo Not implemented:
|
|
|
|
/*! @todo Not implemented:
|
|
|
@ -1188,7 +1226,7 @@ namespace cryptoki { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
bool check(CK_RV result, const std::string& context="") { |
|
|
|
_res = result; |
|
|
|
_res = result; |
|
|
|
if (_session->_slot._init->_exc && !*this) |
|
|
|
if (_session->_slot._init->_exc && !*this) |
|
|
|
if (context.size()) |
|
|
|
if (!context.empty()) |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
throw access_error(context+": "+error()); |
|
|
|
else |
|
|
|
else |
|
|
|
throw access_error(error()); |
|
|
|
throw access_error(error()); |
|
|
@ -1331,11 +1369,11 @@ namespace cryptoki { |
|
|
|
} |
|
|
|
} |
|
|
|
@endcode */ |
|
|
|
@endcode */ |
|
|
|
|
|
|
|
|
|
|
|
AttributeMap getattributevalue(AttributeTypeList attributes |
|
|
|
AttributeMap attributes(AttributeTypeList attributes |
|
|
|
=AttributeTypeList()) { |
|
|
|
= AttributeTypeList()) { |
|
|
|
AttributeMap res; |
|
|
|
AttributeMap res; |
|
|
|
//! Gets all attributes, if @c attributes is empty
|
|
|
|
//! Gets all attributes, if @c attributes is empty
|
|
|
|
if (!attributes.size()) { |
|
|
|
if (attributes.empty()) { |
|
|
|
attributes.push_back(CKA_CLASS); |
|
|
|
attributes.push_back(CKA_CLASS); |
|
|
|
attributes.push_back(CKA_TOKEN); |
|
|
|
attributes.push_back(CKA_TOKEN); |
|
|
|
attributes.push_back(CKA_PRIVATE); |
|
|
|
attributes.push_back(CKA_PRIVATE); |
|
|
@ -1404,28 +1442,71 @@ namespace cryptoki { |
|
|
|
attrs = (CK_ATTRIBUTE){*it, 0, 0}; |
|
|
|
attrs = (CK_ATTRIBUTE){*it, 0, 0}; |
|
|
|
try { |
|
|
|
try { |
|
|
|
//! calls @c C_GetAttributeValue
|
|
|
|
//! calls @c C_GetAttributeValue
|
|
|
|
if (check(_session->_slot._init->_fn->C_GetAttributeValue |
|
|
|
if (_session->_slot._init->_fn->C_GetAttributeValue |
|
|
|
(_session->_session, _object, &attrs, 1), |
|
|
|
(_session->_session, _object, &attrs, 1) |
|
|
|
CRYPTOKI_FN_LOG("C_GetAttributeValue"))) { |
|
|
|
== CKR_ATTRIBUTE_TYPE_INVALID |
|
|
|
if (attrs.ulValueLen>0) { |
|
|
|
|| _res == CKR_ATTRIBUTE_SENSITIVE) { |
|
|
|
|
|
|
|
continue; //! Ignores unsupported Attributes.
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
check(_res, CRYPTOKI_FN_LOG("C_GetAttributeValue")); |
|
|
|
|
|
|
|
if ((long)attrs.ulValueLen>0l) { |
|
|
|
attrs.pValue = malloc(attrs.ulValueLen); |
|
|
|
attrs.pValue = malloc(attrs.ulValueLen); |
|
|
|
if (_session->_slot._init->_fn->C_GetAttributeValue |
|
|
|
attrs.pValue = memset(attrs.pValue, 0, attrs.ulValueLen); |
|
|
|
(_session->_session, _object, &attrs, 1) |
|
|
|
if (check(_session->_slot._init->_fn->C_GetAttributeValue |
|
|
|
== CKR_ATTRIBUTE_TYPE_INVALID) |
|
|
|
(_session->_session, _object, &attrs, 1), |
|
|
|
std::cerr<<"*** Inv. Attr:"<<Attribute(*it).name()<<std::endl; |
|
|
|
CRYPTOKI_FN_LOG("C_GetAttributeValue"))) |
|
|
|
else { |
|
|
|
/*! @todo There's no @c CKA_WRAP_TEMPLATE in Open
|
|
|
|
check(_res, CRYPTOKI_FN_LOG("C_GetAttributeValue")); |
|
|
|
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 â<EFBFBD><EFBFBD>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(attrs.type, Attribute(attrs))); |
|
|
|
res.insert(std::make_pair(attrs.type, Attribute(attrs))); |
|
|
|
} |
|
|
|
else |
|
|
|
} else |
|
|
|
free(attrs.pValue); |
|
|
|
std::cerr<<"*** Wrong Attr: "<<Attribute(*it).name()<<std::endl; |
|
|
|
} else if (*it==CKA_MODULUS && attrs.ulValueLen==0) { |
|
|
|
|
|
|
|
/*! @bug This is a bug in onepin-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==attributes.end()) break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return res; |
|
|
|
|
|
|
|
} catch (...) { |
|
|
|
} catch (...) { |
|
|
|
free(attrs.pValue); |
|
|
|
free(attrs.pValue); |
|
|
|
throw; |
|
|
|
throw; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return res; |
|
|
|
// CK_ATTRIBUTE* attrs(new CK_ATTRIBUTE[attributes.size()]);
|
|
|
|
// CK_ATTRIBUTE* attrs(new CK_ATTRIBUTE[attributes.size()]);
|
|
|
|
// AttributeTypeList::const_iterator it(attributes.begin());
|
|
|
|
// AttributeTypeList::const_iterator it(attributes.begin());
|
|
|
|
// for (AttributeTypeList::size_type i(0); it!=attributes.end(); ++it, ++i)
|
|
|
|
// for (AttributeTypeList::size_type i(0); it!=attributes.end(); ++it, ++i)
|
|
|
|