#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 int (*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) { const char *old = P11T_SECTION("CreateMutex"); CK_RV ret = CKR_OK; if(!mutex) { P11T_CHECK_FAIL("Arguments should not be null"); ret = CKR_ARGUMENTS_BAD; } else { #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 */ } p11t_msg_prefix(old); return ret; } static CK_RV destroy_mutex (void *mutex) { const char *old = P11T_SECTION("DestroyMutex"); CK_RV ret = CKR_OK; if(!mutex) { P11T_CHECK_FAIL("Mutex should not be null"); ret = CKR_MUTEX_BAD; } else { #ifdef _WIN32 if(!CloseHandle((HANDLE)mutex)) { DWORD error = GetLastError(); if(error == ERROR_INVALID_HANDLE) { P11T_CHECK_FAIL("Mutex should not be invalid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", GetLastError()); ret = CKR_GENERAL_ERROR; } } #else /* !_WIN32 */ int res = pthread_mutex_destroy(mutex); if(res != 0) { if(res == EBUSY) { P11T_CHECK_FAIL("Mutex should not be locked"); ret = CKR_GENERAL_ERROR; } else if(res == EINVAL) { P11T_CHECK_FAIL("Mutex should not be invalid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", res); ret = CKR_GENERAL_ERROR; } } #endif /* !_WIN32 */ } p11t_msg_prefix(old); return ret; } static CK_RV lock_mutex (void *mutex) { const char *old = P11T_SECTION("LockMutex"); CK_RV ret = CKR_OK; if(!mutex) { P11T_CHECK_FAIL("null mutex"); ret = CKR_MUTEX_BAD; } else { #ifdef _WIN32 DWORD result = WaitForSingleObject((HANDLE)mutex, INFINITE); if(result == WAIT_ABANDONED) { P11T_CHECK_FAIL("Thread should not exit without releasing mutex"); ret = CKR_CANT_LOCK; } else if(result == WAIT_FAILED) { DWORD error = GetLastError(); if(error == ERROR_INVALID_HANDLE) { P11T_CHECK_FAIL("Mutex should not be invalid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", error); ret = CKR_GENERAL_ERROR; } } else if(result != WAIT_OBJECT_0) { p11t_check_warn("couldn't lock"); ret = CKR_CANT_LOCK; } #else /* !_WIN32 */ int res = pthread_mutex_lock(mutex); if(res != 0) { if(res == EDEADLK) { P11T_CHECK_FAIL("Mutex should not deadlock"); ret = CKR_CANT_LOCK; } else if(res == EINVAL) { P11T_CHECK_FAIL("Mutex should not be invalid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", res); ret = CKR_GENERAL_ERROR; } } #endif /* !_WIN32 */ } p11t_msg_prefix(old); return ret; } static CK_RV unlock_mutex (void *mutex) { const char *old = P11T_SECTION("UnlockMutex"); CK_RV ret = CKR_OK; if(!mutex) { P11T_CHECK_FAIL("Mutex should not be null"); ret = CKR_MUTEX_BAD; } else { #ifdef _WIN32 if(!ReleaseMutex((HANDLE)mutex)) { DWORD error = GetLastError(); if(error == ERROR_NOT_OWNER) { P11T_CHECK_FAIL("Mutex should be locked"); ret = CKR_MUTEX_NOT_LOCKED; } else if(error == ERROR_INVALID_HANDLE) { P11T_CHECK_FAIL("Mutex should not be invalid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", error); ret = CKR_GENERAL_ERROR; } } #else /* !_WIN32 */ int res = pthread_mutex_lock(mutex); if(res != 0) { if(res == EPERM) { P11T_CHECK_FAIL("Mutex should not be locked"); ret = CKR_MUTEX_NOT_LOCKED; } else if(res == EINVAL) { P11T_CHECK_FAIL("Mutex should be valid"); ret = CKR_MUTEX_BAD; } else { p11t_check_warn("failed: %d", res); ret = CKR_GENERAL_ERROR; } } else { free(mutex); } #endif /* !_WIN32 */ } p11t_msg_prefix(old); return ret; } int 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_os()); /* 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_os()); #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) { P11T_SECTION("C_GetFunctionList"); rv = (p11t_module_funcs->C_GetFunctionList)(&list); P11T_CHECK_RV("Call through function list", rv, CKR_OK); if(memcmp(list, p11t_module_funcs, sizeof(*list)) != 0) p11t_check_info("Call doesn't return same data as library C_GetFunctionList entry point"); } return CONTINUE; } static int initialize_common(const char *mode) { CK_RV rv; P11T_SECTION("C_Initialize"); assert(p11t_module_funcs); rv = (p11t_module_funcs->C_Initialize) (&init_args); if(rv == CKR_CANT_LOCK) { p11t_check_info("Module didn't accept %s", mode); return 0; } if(rv != CKR_OK) { p11t_check_fail("Couldn't initialize with %s: %s", mode, p11t_msg_rv(rv)); return 0; } is_initialized = 1; return 1; } static int initialize_locking_1(void) { P11T_CHECK_NOTE("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; return CONTINUE; } static int initialize_locking_2(void) { P11T_CHECK_NOTE("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; return CONTINUE; } static int initialize_locking_3(void) { P11T_CHECK_NOTE("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; return CONTINUE; } static int initialize_locking_4(void) { P11T_CHECK_NOTE("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; return CONTINUE; } int p11t_module_initialize(void) { CK_INFO info; CK_RV rv; assert(p11t_module_funcs); P11T_SECTION("C_Initialize"); if(p11t_test_unexpected) { rv = (p11t_module_funcs->C_GetInfo)(&info); P11T_CHECK_RV("Calls without initializing", rv, CKR_CRYPTOKI_NOT_INITIALIZED); rv = (p11t_module_funcs->C_Initialize) (NULL); P11T_CHECK_RV("Null argument", rv, CKR_OK); is_initialized = 1; p11t_module_finalize(); } P11T_CHECK_NOTE("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("Couldn't initialize module via any method"); (init_func)(); if(!is_initialized) p11t_msg_fatal("Failed to initialize module"); if(p11t_test_unexpected) { rv = (p11t_module_funcs->C_Initialize) (&init_args); P11T_CHECK_RV("Double initialize in a row", rv, CKR_CRYPTOKI_ALREADY_INITIALIZED); } is_initialized = 1; return CONTINUE; } int p11t_module_finalize(void) { CK_RV rv; P11T_SECTION("C_Finalize"); if(is_initialized) { if(p11t_test_unexpected) { rv = p11t_module_funcs->C_Finalize(&rv); P11T_CHECK_RV("With invalid argument", rv, CKR_ARGUMENTS_BAD); } assert(p11t_module_funcs); rv = p11t_module_funcs->C_Finalize(NULL); P11T_CHECK_RV("Normal call", rv, CKR_OK); is_initialized = 0; } if(p11t_test_unexpected) { rv = p11t_module_funcs->C_Finalize(NULL); P11T_CHECK_RV("Double finalize in a row", rv, CKR_CRYPTOKI_NOT_INITIALIZED); } return CONTINUE; } int p11t_module_unload(void) { if(module) { #ifdef _WIN32 FreeLibrary(module); #else dlclose(module); #endif } module = NULL; return CONTINUE; }