This library provides a simple and nice C++ wrapper around these libraries, so that programmers can concentrate on functionality. It offers general support for PCSC-lite, OpenSSL, PKCS#11, plus specific functionality for the SuisseID.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

285 lines
11 KiB

/*! @file
@id $Id$
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
#include <cryptoki.hxx>
#include <sstream>
#include <memory>
#include <dlfcn.h>
#include <iostream>
#define CRYPTOKI_LOG(X) std::clog<<"... "<<X<<" in "<<__PRETTY_FUNCTION__<<std::endl;
namespace cryptoki {
#ifndef CRYPTOKI_FN_LOG
#if __GNUC__ >= 2
#define CRYPTOKI_FN_LOG(X) (std::string(X " failed in ") \
+std::string(__PRETTY_FUNCTION__))
#else
#define CRYPTOKI_FN_LOG(X) X " failed"
#endif
#endif
bool Init::functionList(const std::string& library) {
void* lib(dlopen(library.c_str(), RTLD_NOW));
if (!lib) throw exception("open of library failed: "+library);
CK_RV(*fn)(CK_FUNCTION_LIST**)
((CK_RV(*)(CK_FUNCTION_LIST**))dlsym(lib, "C_GetFunctionList"));
if (!fn)
throw exception("required library symbol C_GetFunctionList not found in "
+library);
//! calls @c C_GetFunctionList
return check(fn(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList"));
}
bool Init::check(CK_RV result, const std::string& context) {
_res = result;
if (_exc && !*this)
if (context.size())
throw access_error(context+": "+error());
else
throw access_error(error());
return _res==CKR_OK;
}
std::string Init::error(CK_RV res) {
switch (res) {
case CKR_OK: return "CKR_OK";
case CKR_CANCEL: return "CKR_CANCEL";
case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY";
case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID";
case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR";
case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED";
case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD";
case CKR_NO_EVENT: return "CKR_NO_EVENT";
case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS";
case CKR_CANT_LOCK: return "CKR_CANT_LOCK";
case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY";
case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE";
case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID";
case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID";
case CKR_DATA_INVALID: return "CKR_DATA_INVALID";
case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE";
case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR";
case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY";
case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED";
case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID";
case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE";
case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED";
case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL";
case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED";
case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID";
case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE";
case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT";
case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED";
case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED";
case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED";
case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE";
case CKR_KEY_FUNCTION_NOT_PERMITTED:
return "CKR_KEY_FUNCTION_NOT_PERMITTED";
case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE";
case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE";
case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID";
case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID";
case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID";
case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE";
case CKR_OPERATION_NOT_INITIALIZED:
return "CKR_OPERATION_NOT_INITIALIZED";
case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT";
case CKR_PIN_INVALID: return "CKR_PIN_INVALID";
case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE";
case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED";
case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED";
case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED";
case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT";
case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID";
case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY";
case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS";
case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS";
case CKR_SESSION_READ_WRITE_SO_EXISTS:
return "CKR_SESSION_READ_WRITE_SO_EXISTS";
case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID";
case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE";
case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE";
case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT";
case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT";
case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED";
case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED";
case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
case CKR_UNWRAPPING_KEY_SIZE_RANGE:
return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN";
case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN";
case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED";
case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID";
case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES";
case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID";
case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE";
case CKR_WRAPPING_KEY_HANDLE_INVALID:
return "CKR_WRAPPING_KEY_HANDLE_INVALID";
case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE";
case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
case CKR_RANDOM_SEED_NOT_SUPPORTED:
return "CKR_RANDOM_SEED_NOT_SUPPORTED";
case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG";
case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID";
case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL";
case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID";
case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE";
case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE";
case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED";
case CKR_CRYPTOKI_ALREADY_INITIALIZED:
return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD";
case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED";
case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED";
default: {
std::stringstream ss;
ss<<"unknown error code ("<<res<<')';
return ss.str();
}
}
}
Init::Init(const std::string& library, bool exc):
_exc(exc), _res(CKR_OK), _fn(0) {
//! calls @c functionList
if (!functionList(library)) return;
//! calls @c C_Initialize
check(_fn->C_Initialize(0), //! @todo add optional argument
CRYPTOKI_FN_LOG("C_Initialize"));
}
Init::operator bool() {
return _res==CKR_OK;
}
std::string Init::error() {
return error(_res);
}
/*! @todo Not implemented:
@code
bool Init::getinfo() {
//! calls @c C_GetInfo
return check(_init._fn->C_GetInfo(CK_INFO_PTR),
CRYPTOKI_FN_LOG("C_GetInfo"));
}
@endcode */
SlotList Init::slotList(bool tokenPresent) {
SlotList res;
CK_ULONG count(0);
//! calls @c C_GetSlotList
check(_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, 0, &count),
CRYPTOKI_FN_LOG("C_GetSlotList"));
if (!count || !*this) return res;
CK_SLOT_ID* slots = 0;
try {
do {
delete[] slots;
slots = new CK_SLOT_ID[count];
_res = _fn->C_GetSlotList(tokenPresent?TRUE:FALSE, slots, &count);
} while (_res==CKR_BUFFER_TOO_SMALL);
check(_res, CRYPTOKI_FN_LOG("C_GetSlotList"));
if (!*this) return res;
for (CK_ULONG i(0); i<count; ++i) res.push_back(Slot(*this, slots[i]));
} catch (...) {
delete[] slots;
throw;
}
delete[] slots;
return res;
}
15 years ago
//============================================================================
ObjectList Session::find(const AttributeList& attrs) {
ObjectList res;
CK_ATTRIBUTE* a(0);
try {
if (attrs.size()) {
a = new CK_ATTRIBUTE[attrs.size()];
for (AttributeList::size_type i(0); i<attrs.size(); ++i)
a[i] = attrs[i];
15 years ago
}
//! calls @c C_FindObjectsInit
if (check(_slot._init->_fn->C_FindObjectsInit
(_session, a, attrs.size()),
CRYPTOKI_FN_LOG("C_FindObjectsInit"))) {
CK_OBJECT_HANDLE obj;
//! calls @c C_FindObjects
for (CK_ULONG objs(0);
check(_slot._init->_fn->C_FindObjects
(_session, &obj, 1, &objs),
CRYPTOKI_FN_LOG("C_FindObjects")) && objs;
res.push_back(Object(*this, obj)));
}
//! calls @c C_FindObjectsFinal
check(_slot._init->_fn->C_FindObjectsFinal(_session),
CRYPTOKI_FN_LOG("C_FindObjectsFinal"));
delete[] a;
return res;
} catch (...) {
delete[] a;
throw;
}
}
//----------------------------------------------------------------------------
Object Session::create(const openssl::X509& cert) {
AttributeList attrs;
attrs.push_back(Attribute(CKA_CLASS)
.from<CK_OBJECT_CLASS>(CKO_CERTIFICATE));
attrs.push_back(Attribute(CKA_CERTIFICATE_TYPE)
.from<CK_CERTIFICATE_TYPE>(CKC_X_509));
attrs.push_back(Attribute(CKA_SUBJECT, cert.subjectDER()));
attrs.push_back(Attribute(CKA_VALUE, cert.valueDER()));
return create(attrs);
}
Object Session::create(const openssl::PrivateKey& key) {
AttributeList attrs;
return create(attrs);
}
Object Session::create(const openssl::PKCS12& p12) {
AttributeList attrs;
return create(attrs);
}
//----------------------------------------------------------------------------
Object Session::create(const AttributeList& attrs) {
CK_ATTRIBUTE* a(0);
try {
if (attrs.size()) {
a = new CK_ATTRIBUTE[attrs.size()];
for (AttributeList::size_type i(0); i<attrs.size(); ++i)
a[i] = attrs[i];
}
CK_OBJECT_HANDLE object;
//! calls @c C_CreateObject
check(_slot._init->_fn->C_CreateObject
(_session, a, attrs.size(), &object),
CRYPTOKI_FN_LOG("C_CreateObject"));
delete[] a;
return Object(*this, object);
} catch (...) {
delete[] a;
throw;
}
}
}