diff --git a/src/pkcs11/libpkcs11.c b/src/pkcs11/libpkcs11.c new file mode 100644 index 00000000..dfafaa3a --- /dev/null +++ b/src/pkcs11/libpkcs11.c @@ -0,0 +1,135 @@ +/* + * Convenience pkcs11 library that can be linked into an application, + * and will bind to a specific pkcs11 module. + * + * Copyright (C) 2002 Olaf Kirch + */ + +#include "pkcs11.h" +#include +#include +#include + +#define MAGIC 0xd00bed00 + +struct sc_pkcs11_module { + unsigned int _magic; +#if defined(linux) + void * _dl_handle; +#endif +}; + +static int sys_dlopen(sc_pkcs11_module_t *, const char *); +static int sys_dlclose(sc_pkcs11_module_t *); +static void * sys_dlsym(sc_pkcs11_module_t *, const char *); + +/* + * Load a module - this will load the shared object, call + * C_Initialize, and get the list of function pointers + */ +sc_pkcs11_module_t * +C_LoadModule(const char *mspec, CK_FUNCTION_LIST_PTR_PTR funcs) +{ + sc_pkcs11_module_t *mod; + CK_RV (*c_get_function_list)(CK_FUNCTION_LIST_PTR_PTR); + int rv; + + mod = (sc_pkcs11_module_t *) calloc(1, sizeof(*mod)); + mod->_magic = MAGIC; + if (sys_dlopen(mod, mspec) < 0) + goto failed; + + /* Get the list of function pointers */ + c_get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) + sys_dlsym(mod, "C_GetFunctionList"); + if (!c_get_function_list) + goto failed; + rv = c_get_function_list(funcs); + if (rv == CKR_OK) + return mod; + +failed: C_UnloadModule(mod); + return NULL; +} + +/* + * Unload a pkcs11 module. + * The calling application is responsible for cleaning up + * and calling C_Finalize + */ +CK_RV +C_UnloadModule(sc_pkcs11_module_t *mod) +{ + if (!mod || mod->_magic != MAGIC) + return CKR_ARGUMENTS_BAD; + + if (sys_dlclose(mod) < 0) + return CKR_FUNCTION_FAILED; + + memset(mod, 0, sizeof(*mod)); + free(mod); + return CKR_OK; +} + +#ifdef linux +#include + +/* + * Module loader for platforms that have dlopen + * + * This is intentionally primitive; we may want a more + * elaborate loader in libopensc one day + */ +int +sys_dlopen(struct sc_pkcs11_module *mod, const char *name) +{ + const char **dir, *ldlist[64]; + char pathbuf[4096], *ldenv; + unsigned int n = 0; + + if ((ldenv = getenv("LD_LIBRARY_PATH")) + && (ldenv = strdup(ldenv))) { + ldlist[n] = strtok(ldenv, ":"); + while (ldlist[n] != NULL && ++n < 63) + ldlist[n] = strtok(NULL, ":"); + } + ldlist[n] = NULL; + + if (name == NULL) + name = "opensc-pkcs11.so"; + + for (dir = ldlist; *dir; dir++) { + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", *dir, name); + mod->_dl_handle = dlopen(pathbuf, RTLD_NOW); + if (mod->_dl_handle != NULL) + break; + } + + if (mod->_dl_handle == NULL) + mod->_dl_handle = dlopen(name, RTLD_NOW); + + if (ldenv) + free(ldenv); + + return (mod->_dl_handle? 0 : -1); +} + +int +sys_dlclose(struct sc_pkcs11_module *mod) +{ + if (mod->_dl_handle) + dlclose(mod->_dl_handle); + mod->_dl_handle = NULL; + return 0; +} + + +void * +sys_dlsym(sc_pkcs11_module_t *mod, const char *name) +{ + if (!mod->_dl_handle) + return NULL; + return dlsym(mod->_dl_handle, name); +} + +#endif diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h new file mode 100644 index 00000000..58cfa5ab --- /dev/null +++ b/src/pkcs11/pkcs11.h @@ -0,0 +1,48 @@ +/* + * pkcs11.h: OpenSC project's PKCS#11 library header + * + * Copyright (C) 2002 Timo Teräs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OPENSC_PKCS11_H +#define OPENSC_PKCS11_H + +#ifndef _WIN32 +#include +#include +#else +#include +#pragma pack(push, cryptoki, 1) +#include +#pragma pack(pop, cryptoki) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sc_pkcs11_module sc_pkcs11_module_t; + +extern sc_pkcs11_module_t *C_LoadModule(const char *name, + CK_FUNCTION_LIST_PTR_PTR); +extern CK_RV C_UnloadModule(sc_pkcs11_module_t *); + +#ifdef __cplusplus +} +#endif + +#endif