#ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x400 #include static HMODULE module = NULL; #else /* !_WIN32 */ #include #include static void *module = NULL; #endif /* !_WIN32 */ #include "p11-tests.h" #include #include #include CK_FUNCTION_LIST_PTR p11t_module_funcs = NULL; static const char *init_string = NULL; static CK_C_INITIALIZE_ARGS init_args; static void (*init_func)(void) = NULL; static int is_initialized = 0; void p11t_module_config(const char *name, const char *value) { if(strcmp(name, "init-string") == 0) init_string = value; } static CK_RV create_mutex(void **mutex) { if(!mutex) { p11t_msg_print("CreateMutex: null mutex passed"); return CKR_ARGUMENTS_BAD; } #ifdef _WIN32 *mutex = CreateMutex(NULL, FALSE, NULL); assert(*mutex != NULL); #else /* !_WIN32 */ { pthread_mutex_t *mut; mut = malloc(sizeof(pthread_mutex_t)); assert(mut); if(pthread_mutex_init(mut, NULL) != 0) assert(0); *mutex = mut; } #endif /* !_WIN32 */ return CKR_OK; } static CK_RV destroy_mutex (void *mutex) { if(!mutex) { p11t_msg_print("DestroyMutex: null mutex"); return CKR_MUTEX_BAD; } #ifdef _WIN32 if(!CloseHandle((HANDLE)mutex)) { DWORD error = GetLastError(); if(error == ERROR_INVALID_HANDLE) { p11t_msg_print("DestroyMutex: mutex is invalid"); return CKR_MUTEX_BAD; } else { p11t_msg_print("DestroyMutex: failed: %d", GetLastError()); return CKR_GENERAL_ERROR; } } #else /* !_WIN32 */ { int res = pthread_mutex_destroy(mutex); if(res != 0) { if(res == EBUSY) { p11t_msg_print("DestroyMutex: mutex is locked"); return CKR_GENERAL_ERROR; } else if(res == EINVAL) { p11t_msg_print("DestroyMutex: mutex is invalid"); return CKR_MUTEX_BAD; } else { p11t_msg_print("DestroyMutex: failed: %d", res); return CKR_GENERAL_ERROR; } } } #endif /* !_WIN32 */ return CKR_OK; } static CK_RV lock_mutex (void *mutex) { if(!mutex) { p11t_msg_print("LockMutex: null mutex"); return CKR_MUTEX_BAD; } #ifdef _WIN32 { DWORD result = WaitForSingleObject((HANDLE)mutex, INFINITE); if(result == WAIT_ABANDONED) { p11t_msg_print("LockMutex: thread exited without releasing mutex"); return CKR_CANT_LOCK; } else if(result == WAIT_FAILED) { DWORD error = GetLastError(); if(error == ERROR_INVALID_HANDLE) { p11t_msg_print("LockMutex: invalid handle"); return CKR_MUTEX_BAD; } else { p11t_msg_print("LockMutex: failed: %d", error); return CKR_GENERAL_ERROR; } } else if(result != WAIT_OBJECT_0) { p11t_msg_print("LockMutex: couldn't lock"); return CKR_CANT_LOCK; } } #else /* !_WIN32 */ { int res = pthread_mutex_lock(mutex); if(res != 0) { if(res == EDEADLK) { p11t_msg_print("LockMutex: would deadlock"); return CKR_CANT_LOCK; } else if(res == EINVAL) { p11t_msg_print("LockMutex: invalid mutex used"); return CKR_MUTEX_BAD; } else { p11t_msg_print("LockMutex: failed: %d", res); return CKR_GENERAL_ERROR; } } } #endif /* !_WIN32 */ return CKR_OK; } static CK_RV unlock_mutex (void *mutex) { if(!mutex) { p11t_msg_print("UnlockMutex: null mutex"); return CKR_MUTEX_BAD; } #ifdef _WIN32 if(!ReleaseMutex((HANDLE)mutex)) { DWORD error = GetLastError(); if(error == ERROR_NOT_OWNER) { p11t_msg_print("UnlockMutex: mutex not locked"); return CKR_MUTEX_NOT_LOCKED; } else if(error == ERROR_INVALID_HANDLE) { p11t_msg_print("UnlockMutex: invalid mutex used"); return CKR_MUTEX_BAD; } else { p11t_msg_print("UnlockMutex: failed: %d", error); return CKR_GENERAL_ERROR; } } #else /* !_WIN32 */ { int res = pthread_mutex_lock(mutex); if(res != 0) { if(res == EPERM) { p11t_msg_print("UnlockMutex: mutex not locked"); return CKR_MUTEX_NOT_LOCKED; } else if(res == EINVAL) { p11t_msg_print("UnlockMutex: invalid mutex used"); return CKR_MUTEX_BAD; } else { p11t_msg_print("UnlockMutex: failed: %d", res); return CKR_GENERAL_ERROR; } } else { free(mutex); } } #endif /* !_WIN32 */ return CKR_OK; } void p11t_module_load(const char *filename) { CK_FUNCTION_LIST_PTR list; CK_C_GetFunctionList get_function_list; CK_RV rv; #ifdef _WIN32 module = LoadLibrary(filename); if(!module) p11t_msg_fatal("couldn't load library: %s: %s", filename, p11t_msg_lasterr()); /* Lookup the appropriate function in the library */ get_function_list = (CK_C_GetFunctionList)GetProcAddress(module, "C_GetFunctionList"); if(!get_function_list) p11t_msg_fatal("C_GetFunctionList: couldn't find function in library: %s: %s", filename, p11t_msg_lasterr()); #else /* !_WIN32 */ module = dlopen(filename, RTLD_NOW); if(!module) p11t_msg_fatal("couldn't open library: %s: %s", filename, dlerror()); /* Lookup the appropriate function in library */ get_function_list = (CK_C_GetFunctionList)dlsym (module, "C_GetFunctionList"); if(!get_function_list) p11t_msg_fatal("C_GetFunctionList: couldn't find function in library: %s: %s", filename, dlerror()); #endif /* !_WIN32 */ /* Get the function list */ rv = (get_function_list)(&p11t_module_funcs); if(rv != CKR_OK) p11t_msg_fatal("C_GetFunctiontList: couldn't get function list: %s", p11t_msg_rv(rv)); if(p11t_test_unexpected) { /** C_GetFunctionList */ rv = (p11t_module_funcs->C_GetFunctionList)(&list); if(rv != CKR_OK) p11t_msg_print("C_GetFunctionList: call through function list failed: %s", p11t_msg_rv(rv)); /** - See if returns same data as library entry point */ if(!memcmp(list, p11t_module_funcs, sizeof(*list)) != 0) p11t_msg_print("C_GetFunctionList: function lists returned directly and recursively differ"); } } static int initialize_common(const char *mode) { CK_RV rv; /** C_Initialize **/ assert(p11t_module_funcs); /** - Normal call */ rv = (p11t_module_funcs->C_Initialize) (&init_args); if (rv != CKR_OK) { if(rv != CKR_CANT_LOCK) p11t_msg_print("C_Initialize: failed (%s): %s", mode, p11t_msg_rv(rv)); return 0; } else { is_initialized = 1; return 1; } } static void initialize_locking_1(void) { /** - Locking: no threads */ memset(&init_args, 0, sizeof (init_args)); init_args.pReserved = (void*)init_string; if(initialize_common("locking mode 1: no threads")) init_func = initialize_locking_1; } static void initialize_locking_2(void) { /** - Locking: os locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = CKF_OS_LOCKING_OK; init_args.pReserved = (void*)init_string; if(initialize_common("locking mode 2: os locking")) init_func = initialize_locking_2; } static void initialize_locking_3(void) { /** - Locking: app locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = 0; init_args.CreateMutex = create_mutex; init_args.DestroyMutex = destroy_mutex; init_args.LockMutex = lock_mutex; init_args.UnlockMutex = unlock_mutex; init_args.pReserved = (void*)init_string; if(initialize_common("locking mode 3: app locking")) init_func = initialize_locking_3; } static void initialize_locking_4(void) { /** - Locking: either locking */ memset(&init_args, 0, sizeof (init_args)); init_args.flags = CKF_OS_LOCKING_OK; init_args.CreateMutex = create_mutex; init_args.DestroyMutex = destroy_mutex; init_args.LockMutex = lock_mutex; init_args.UnlockMutex = unlock_mutex; init_args.pReserved = (void*)init_string; if(initialize_common("locking mode 4: either locking")) init_func = initialize_locking_4; } void p11t_module_initialize(void) { CK_INFO info; CK_RV rv; assert(p11t_module_funcs); if(p11t_test_unexpected) { /** - Calls without initializing */ rv = (p11t_module_funcs->C_GetInfo)(&info); p11t_check_returns("C_GetInfo: shouldn't run without initialize", rv, CKR_CRYPTOKI_NOT_INITIALIZED); /** - NULL argument */ rv = (p11t_module_funcs->C_Initialize) (NULL); p11t_check_returns("C_Initialize: should succeed with null argument", rv, CKR_OK); is_initialized = 1; p11t_module_finalize(); } /** - Multiple initialize with C_Finalize between */ initialize_locking_1(); p11t_module_finalize(); initialize_locking_2(); p11t_module_finalize(); initialize_locking_3(); p11t_module_finalize(); initialize_locking_4(); p11t_module_finalize(); /* Actually initialize with whatever succeeded last */ if(!init_func) p11t_msg_fatal("C_Initialize: no initialize succeded cannot continue"); (init_func)(); if(!is_initialized) p11t_msg_fatal("C_Initialize: couldn't initialize pkcs11 module"); if(p11t_test_unexpected) { /** - Double initialize in a row */ rv = (p11t_module_funcs->C_Initialize) (&init_args); if(rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { p11t_msg_print("C_Initialize: double initialize should return CKR_CRYPTOKI_ALREADY_INITIALIZED: %s", p11t_msg_rv(rv)); } } is_initialized = 1; } void p11t_module_finalize(void) { CK_RV rv; /** C_Finalize */ if(is_initialized) { if(p11t_test_unexpected) { /** - With invalid argument */ rv = p11t_module_funcs->C_Finalize(&rv); p11t_check_returns("C_Finalize: bad argument", rv, CKR_ARGUMENTS_BAD); } /** - Normal call */ assert(p11t_module_funcs); rv = p11t_module_funcs->C_Finalize(NULL); p11t_check_returns("C_Finalize", rv, CKR_OK); is_initialized = 0; } if(p11t_test_unexpected) { /** - Double finalize in a row */ rv = p11t_module_funcs->C_Finalize(NULL); p11t_check_returns("C_Finalize: double finalize", rv, CKR_CRYPTOKI_NOT_INITIALIZED); } } void p11t_module_unload(void) { if(module) { #ifdef _WIN32 FreeLibrary(module); #else dlclose(module); #endif } module = NULL; }