/*! @file @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #include #include #include #include #ifndef WIN32 #include #define CK_PTR * typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; typedef CK_RV (*CK_C_GetFunctionList) (CK_FUNCTION_LIST_PTR_PTR ppFunctionList); #else #include #undef ERROR #endif namespace cryptoki { bool Library::Init::functionList(const std::string& library) { CRYPTOLOG("try to load: "< (reinterpret_cast (dlsym(_lib, "C_GetFunctionList")))); #else CK_C_GetFunctionList fnl ((CK_C_GetFunctionList)GetProcAddress(_lib, "C_GetFunctionList")); #endif if (!fnl) throw exception("required library symbol C_GetFunctionList not found in " +library); CRYPTOLOG("Got C_GetFunctionList, now call it"); //! calls @c C_GetFunctionList return check(fnl(&_fn), CRYPTOKI_FN_LOG("C_GetFunctionList")); } bool Library::Init::check(CK_RV result, const std::string& context) { _res = result; if (_exc && !*this) { if (context.size()) { if (_res==CKR_PIN_INCORRECT) throw wrong_pin(context+": "+error()); else throw access_error(context+": "+error()); } else { if (_res==CKR_PIN_INCORRECT) throw wrong_pin(error()); else throw access_error(error()); } } return _res==CKR_OK; } std::string Library::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 ("<C_Initialize(0), //! @todo add optional argument CRYPTOKI_FN_LOG("C_Initialize")); } catch (...) { throw access_error(CRYPTOKI_FN_LOG("C_Initialize") +": Error in initialization of library "+library); } Library::Init::~Init() { CRYPTOLOG("log"); /// ignore failure in disconnect, possibly smartcard has /// been removed try { //! calls @c C_Finalize check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); #ifndef WIN32 if (_lib) dlclose(_lib); _lib = 0; #else FreeLibrary(_lib); _lib = 0; #endif _fn = 0; } catch (std::exception& e) { CRYPTOLOG("unloading cryptoki library failed, reason: "<C_GetInfo(CK_INFO_PTR), CRYPTOKI_FN_LOG("C_GetInfo")); } @endcode */ SlotList Library::slotList(bool tokenPresent, std::string name) { CRYPTOLOG("log"); CRYPTOLOG("looking for card name: \"" <check(_init->_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, 0, &count), CRYPTOKI_FN_LOG("C_GetSlotList")); CRYPTOLOG("found "<_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, slots, &count); } while (r==CKR_BUFFER_TOO_SMALL); _init->check(r, CRYPTOKI_FN_LOG("C_GetSlotList")); if (!*this) return res; for (CK_ULONG i(0); i slot matches"); res.push_back(s); } } } catch (...) { delete[] slots; throw; } delete[] slots; return res; } //============================================================================ ObjectList Session::find(const AttributeList& attrs) { CRYPTOLOG("log"); ObjectList res; CK_ATTRIBUTE* a(0); try { if (attrs.size()) { a = new CK_ATTRIBUTE[attrs.size()]; for (AttributeList::size_type i(0); iC_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._library->C_FindObjects (_session, &obj, 1, &objs), CRYPTOKI_FN_LOG("C_FindObjects")) && objs; res.push_back(Object(*this, obj))); } //! calls @c C_FindObjectsFinal check(_slot._library->C_FindObjectsFinal(_session), CRYPTOKI_FN_LOG("C_FindObjectsFinal")); delete[] a; return res; } catch (...) { delete[] a; throw; } } //---------------------------------------------------------------------------- ObjectList Session::find(const Attribute& a) { CRYPTOLOG("log"); AttributeList al; al.push_back(a); return find(al); } //---------------------------------------------------------------------------- ObjectList Session::find(const Attribute& a1, const Attribute& a2) { CRYPTOLOG("log"); AttributeList al; al.push_back(a1); al.push_back(a2); return find(al); } //---------------------------------------------------------------------------- Object Session::create(const std::string& label, const openssl::X509& cert) { CRYPTOLOG("log"); AttributeList attrs; attrs.push_back(Attribute(CKA_CLASS) .from(CKO_CERTIFICATE)); attrs.push_back(Attribute(CKA_TOKEN).from(TRUE)); attrs.push_back(Attribute(CKA_PRIVATE).from(FALSE)); attrs.push_back(Attribute(CKA_MODIFIABLE).from(TRUE)); attrs.push_back(Attribute(CKA_LABEL, label)); attrs.push_back(Attribute(CKA_CERTIFICATE_TYPE) .from(CKC_X_509)); attrs.push_back(Attribute(CKA_SUBJECT, cert.subjectDER())); attrs.push_back(Attribute(CKA_ID, cert.id())); //attrs.push_back(Attribute(CKA_ISSUER, cert.issuerDER())); // attrs.push_back(Attribute(CKA_SERIAL_NUMBER, cert.serialDER())); attrs.push_back(Attribute(CKA_VALUE, cert.valueDER())); CRYPTOLOG("create: serial = "<(CKO_PRIVATE_KEY)); attrs.push_back(Attribute(CKA_TOKEN).from(TRUE)); attrs.push_back(Attribute(CKA_PRIVATE).from(TRUE)); attrs.push_back(Attribute(CKA_MODIFIABLE).from(TRUE)); attrs.push_back(Attribute(CKA_LABEL, label)); attrs.push_back(Attribute(CKA_KEY_TYPE).from(CKK_RSA)); attrs.push_back(Attribute(CKA_ID, cert.id())); attrs.push_back(Attribute(CKA_DERIVE).from(FALSE)); attrs.push_back(Attribute(CKA_SUBJECT, cert.subjectDER())); attrs.push_back(Attribute(CKA_SENSITIVE).from(TRUE)); attrs.push_back(Attribute(CKA_SECONDARY_AUTH).from(FALSE)); attrs.push_back(Attribute(CKA_DECRYPT) // Required by Doujak/Inverardi .from(usage&(X509v3_KU_DATA_ENCIPHERMENT |(usage&X509v3_KU_KEY_ENCIPHERMENT)) ?TRUE:FALSE)); // instead of CKA_UNWRAP attrs.push_back(Attribute(CKA_SIGN) .from(usage&(X509v3_KU_DIGITAL_SIGNATURE |X509v3_KU_NON_REPUDIATION) ?TRUE:FALSE)); attrs.push_back(Attribute(CKA_SIGN_RECOVER) // same as CKA_SIGN .from(usage&(X509v3_KU_DIGITAL_SIGNATURE |X509v3_KU_NON_REPUDIATION) ?TRUE:FALSE)); attrs.push_back(Attribute(CKA_EXTRACTABLE).from(FALSE)); attrs.push_back(Attribute(CKA_MODULUS, key.modulus())); attrs.push_back(Attribute(CKA_PUBLIC_EXPONENT, key.publicExponent())); attrs.push_back(Attribute(CKA_PRIVATE_EXPONENT, key.privateExponent())); attrs.push_back(Attribute(CKA_PRIME_1, key.prime1())); attrs.push_back(Attribute(CKA_PRIME_2, key.prime2())); attrs.push_back(Attribute(CKA_EXPONENT_1, key.exponent1())); attrs.push_back(Attribute(CKA_EXPONENT_2, key.exponent2())); attrs.push_back(Attribute(CKA_COEFFICIENT, key.coefficient())); return create(attrs); } //---------------------------------------------------------------------------- Object Session::create(const AttributeList& attrs) { CRYPTOLOG("log"); CK_ATTRIBUTE* a(0); try { if (attrs.size()) { a = new CK_ATTRIBUTE[attrs.size()]; for (AttributeList::size_type i(0); i