#include "p11-tests.h" #include static const char *login_user_pin = NULL; static const char *login_so_pin = NULL; void p11t_session_config(const char *name, const char *value) { if(strcmp(name, "login-user-pin") == 0) login_user_pin = value; if(strcmp(name, "login-so-pin") == 0) login_so_pin = value; } /* ---------------------------------------------------------------------------------- * TESTS */ void session_info(CK_SESSION_HANDLE session, CK_SLOT_ID slot, CK_FLAGS flags, CK_STATE state) { CK_SESSION_INFO info; CK_RV rv; if(session == CK_INVALID) return; /** C_GetSessionInfo */ if(p11t_test_unexpected) { /** - Invalid session */ rv = (p11t_module_funcs->C_GetSessionInfo)((CK_SESSION_HANDLE)-33, &info); p11t_check_returns("C_GetSessionInfo: with invalid session", rv, CKR_SESSION_HANDLE_INVALID); /** - NULL arguments */ rv = (p11t_module_funcs->C_GetSessionInfo)(session, NULL); p11t_check_returns("C_GetSessionInfo: with null", rv, CKR_ARGUMENTS_BAD); } /** - Valid call */ rv = (p11t_module_funcs->C_GetSessionInfo)(session, &info); if(!p11t_check_returns("C_GetSessionInfo", rv, CKR_OK)) return; /** - Valid slot id */ p11t_check_ulong("CK_SESSION_INFO.slotID", info.slotID, slot); /** - Valid state for session */ p11t_check_ulong("CK_SESSION_INFO.state", info.state, state); /** - Valid flags for session */ p11t_check_flag("CK_SESSION_INFO.flags", info.flags, flags); } static CK_UTF8CHAR_PTR calculate_pin(CK_SLOT_ID slot, CK_USER_TYPE user, CK_ULONG_PTR n_pin) { CK_TOKEN_INFO_PTR info; const char *pin; *n_pin = 0; info = p11t_slot_get_token_info(slot); if(info && info->flags & CKF_PROTECTED_AUTHENTICATION_PATH) return NULL; if(user == CKU_USER) pin = login_user_pin; else if(user == CKU_SO) pin = login_so_pin; else pin = NULL; if(pin) *n_pin = (CK_ULONG)strlen(pin); return (CK_UTF8CHAR_PTR)pin; } void session_user_login(CK_SLOT_ID slot) { CK_SESSION_HANDLE session_ro = CK_INVALID; CK_SESSION_HANDLE session_rw = CK_INVALID; CK_UTF8CHAR_PTR pin; CK_ULONG n_pin; CK_RV rv; pin = calculate_pin(slot, CKU_USER, &n_pin); rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_Login: open RO session", rv, CKR_OK); rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session_rw); p11t_check_returns("C_Login: open RW session", rv, CKR_OK); /* Check the session state before login */ session_info(session_ro, slot, CKF_SERIAL_SESSION, CKS_RO_PUBLIC_SESSION); session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_PUBLIC_SESSION); /** C_Login */ if(p11t_test_unexpected) { /** - Invalid session */ rv = (p11t_module_funcs->C_Login)((CK_ULONG)-55, CKU_USER, pin, n_pin); p11t_check_returns("C_Login: invalid session", rv, CKR_SESSION_HANDLE_INVALID); /** - Invalid user type */ rv = (p11t_module_funcs->C_Login)(session_ro, CK_INVALID, pin, n_pin); p11t_check_returns("C_Login: invalid user type", rv, CKR_USER_TYPE_INVALID); } /** - Normal login */ rv = (p11t_module_funcs->C_Login)(session_ro, CKU_USER, pin, n_pin); if(rv == CKR_USER_TYPE_INVALID) return; if(!p11t_check_returns("C_Login", rv, CKR_OK)) return; /** - Login changes all session state */ session_info(session_ro, slot, CKF_SERIAL_SESSION, CKS_RO_USER_FUNCTIONS); session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_USER_FUNCTIONS); /** C_Logout */ if(p11t_test_unexpected) { /** - Invalid session */ rv = (p11t_module_funcs->C_Logout)((CK_ULONG)-55); p11t_check_returns("C_Logout: invalid session", rv, CKR_SESSION_HANDLE_INVALID); } /** - Normal logout */ rv = (p11t_module_funcs->C_Logout)(session_rw); p11t_check_returns("C_Logout", rv, CKR_OK); /** - Logout changes all session state */ session_info(session_ro, slot, CKF_SERIAL_SESSION, CKS_RO_PUBLIC_SESSION); session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_PUBLIC_SESSION); } void session_so_login(CK_SLOT_ID slot) { CK_SESSION_HANDLE session_ro = CK_INVALID; CK_SESSION_HANDLE session_rw = CK_INVALID; CK_UTF8CHAR_PTR pin; CK_ULONG n_pin; CK_RV rv; pin = calculate_pin(slot, CKU_SO, &n_pin); rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session_rw); p11t_check_returns("C_OpenSession: open RW session", rv, CKR_OK); /* Check the session state before login */ session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_PUBLIC_SESSION); /** C_Login */ if(p11t_test_unexpected) { rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: open RO session because SO", rv, CKR_OK); /** - Login as SO not allowed with RO session */ rv = (p11t_module_funcs->C_Login)(session_ro, CKU_SO, pin, n_pin); p11t_check_returns("C_Login: with RO as SO", rv, CKR_SESSION_READ_ONLY_EXISTS); rv = (p11t_module_funcs->C_CloseSession)(session_ro); p11t_check_returns("C_CloseSession: close RO session because SO", rv, CKR_OK); } /** - Login as SO */ rv = (p11t_module_funcs->C_Login)(session_rw, CKU_SO, pin, n_pin); if(rv == CKR_USER_TYPE_INVALID) return; if(!p11t_check_returns("C_Login: as SO", rv, CKR_OK)) return; /** - Login changes all session state */ session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_SO_FUNCTIONS); if(p11t_test_unexpected) { /** - Can't open RO session when logged in as SO */ rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: open RO when SO logged in", rv, CKR_SESSION_READ_WRITE_SO_EXISTS); } /** - Logout from SO */ rv = (p11t_module_funcs->C_Logout)(session_rw); p11t_check_returns("C_Logout", rv, CKR_OK); /** - Logout SO changes goes back to public */ session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_PUBLIC_SESSION); } void session_main(CK_SLOT_ID slot) { CK_SESSION_HANDLE session_ro = CK_INVALID; CK_SESSION_HANDLE session_rw = CK_INVALID; CK_SESSION_HANDLE session_ro2 = CK_INVALID; CK_SESSION_INFO info; CK_RV rv; assert(p11t_module_funcs); /** C_OpenSession */ if(p11t_test_unexpected) { /** - Invalid slot */ rv = (p11t_module_funcs->C_OpenSession)((CK_SLOT_ID)-5, CKF_SERIAL_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: with invalid slot", rv, CKR_SLOT_ID_INVALID); /** - Null arguments */ rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, NULL); p11t_check_returns("C_OpenSession: with invalid slot", rv, CKR_ARGUMENTS_BAD); /** - No flags */ rv = (p11t_module_funcs->C_OpenSession)(slot, 0, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: with 0 flags", rv, CKR_SESSION_PARALLEL_NOT_SUPPORTED); /** - Without serial flag */ rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_RW_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: with RW flags", rv, CKR_SESSION_PARALLEL_NOT_SUPPORTED); } /** - Valid flags */ rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, &session_ro); p11t_check_returns("C_OpenSession: with serial flags", rv, CKR_OK); rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION, NULL, NULL, &session_ro2); p11t_check_returns("C_OpenSession: with serial flags", rv, CKR_OK); /** - Read write session */ rv = (p11t_module_funcs->C_OpenSession)(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session_rw); if(rv == CKR_TOKEN_WRITE_PROTECTED) session_rw = CK_INVALID; else p11t_check_returns("C_OpenSession: with read write flags", rv, CKR_OK); /* Test all the sessions and validate their state */ session_info(session_ro, slot, CKF_SERIAL_SESSION, CKS_RO_PUBLIC_SESSION); session_info(session_ro2, slot, CKF_SERIAL_SESSION, CKS_RO_PUBLIC_SESSION); session_info(session_rw, slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, CKS_RW_PUBLIC_SESSION); /** C_CloseSession */ if(p11t_test_unexpected) { /** - Invalid session */ rv = (p11t_module_funcs->C_CloseSession)((CK_SESSION_HANDLE)-10); p11t_check_returns("C_CloseSession: invalid handle", rv, CKR_SESSION_HANDLE_INVALID); } if(session_ro != CK_INVALID) { /** - Normal call */ rv = (p11t_module_funcs->C_CloseSession)(session_ro); p11t_check_returns("C_CloseSession: valid", rv, CKR_OK); if(p11t_test_unexpected) { /** - Check open session was closed */ rv = (p11t_module_funcs->C_GetSessionInfo)(session_ro, &info); p11t_check_returns("C_GetSessionInfo: after close", rv, CKR_SESSION_HANDLE_INVALID); /** - Close twice */ /* * Note that CKR_SESSION_CLOSED is a valid return in this case. * That should only be returned in the rare case when a session * was closed during the execution of a function. A corner case. */ rv = (p11t_module_funcs->C_CloseSession)(session_ro); p11t_check_returns("C_CloseSession: valid", rv, CKR_SESSION_HANDLE_INVALID); } } if(session_rw != CK_INVALID) { rv = (p11t_module_funcs->C_CloseSession)(session_rw); p11t_check_returns("C_CloseSession: read write", rv, CKR_OK); } /** C_CloseAllSessions */ if(p11t_test_unexpected) { /** - Invalid slot id */ rv = (p11t_module_funcs->C_CloseAllSessions)((CK_SLOT_ID)-34); p11t_check_returns("C_CloseAllSessions: invalid slot", rv, CKR_SLOT_ID_INVALID); } /** - Normal call */ rv = (p11t_module_funcs->C_CloseAllSessions)(slot); p11t_check_returns("C_CloseAllSessions", rv, CKR_OK); if(p11t_test_unexpected) { /** - Check open session was closed */ rv = (p11t_module_funcs->C_GetSessionInfo)(session_ro2, &info); p11t_check_returns("C_GetSessionInfo: after close all", rv, CKR_SESSION_HANDLE_INVALID); /** - Call when no sessions open */ rv = (p11t_module_funcs->C_CloseAllSessions)(slot); p11t_check_returns("C_CloseAllSessions", rv, CKR_OK); } } void session_pin(CK_SLOT_ID slot) { /** C_InitPIN */ /** - Not Implemented */ /** C_SetPIN */ /** - Not Implemented */ } void session_operation_state(CK_SLOT_ID slot) { /** C_GetOperationState */ /** - Not Implemented */ /** C_SetOperationState */ /** - Not Implemented */ } void p11t_session_tests() { CK_ULONG i; for(i = 0; i < p11t_slot_count; ++i) { CK_SLOT_ID slot = p11t_slot_get_id(i); session_pin(slot); session_main(slot); session_user_login(slot); session_so_login(slot); } } /* ---------------------------------------------------------------------------------- * METHODS */ CK_SESSION_HANDLE p11t_session_open(CK_SLOT_ID slot, int readwrite) { CK_SESSION_HANDLE session; CK_FLAGS flags; assert(p11t_module_funcs); flags = CKF_SERIAL_SESSION; if(readwrite) flags |= CKF_RW_SESSION; if((p11t_module_funcs->C_OpenSession)(slot, flags, NULL, NULL, &session) != CKR_OK) return CK_INVALID; return session; } int p11t_session_login(CK_SESSION_HANDLE session) { CK_SESSION_INFO info; CK_UTF8CHAR_PTR pin; CK_ULONG n_pin; assert(session != CK_INVALID); assert(p11t_module_funcs); if((p11t_module_funcs->C_GetSessionInfo)(session, &info) != CKR_OK) return 0; switch(info.state) { case CKS_RO_USER_FUNCTIONS: case CKS_RW_USER_FUNCTIONS: case CKS_RW_SO_FUNCTIONS: return 1; } pin = calculate_pin(info.slotID, CKU_USER, &n_pin); if((p11t_module_funcs->C_Login)(session, CKU_USER, pin, n_pin) != CKR_OK) return 0; return 1; } int p11t_session_logout(CK_SESSION_HANDLE session) { CK_SESSION_INFO info; assert(session != CK_INVALID); assert(p11t_module_funcs); if((p11t_module_funcs->C_GetSessionInfo)(session, &info) != CKR_OK) return 0; switch(info.state) { case CKS_RO_PUBLIC_SESSION: case CKS_RW_PUBLIC_SESSION: return 1; } if((p11t_module_funcs->C_Logout)(session) != CKR_OK) return 0; return 1; } int p11t_session_close(CK_SESSION_HANDLE session) { CK_RV rv; assert(session != CK_INVALID); assert(p11t_module_funcs); rv = (p11t_module_funcs->C_CloseSession)(session); switch(rv) { case CKR_SESSION_HANDLE_INVALID: case CKR_SESSION_CLOSED: case CKR_OK: return 1; default: return 0; } } int p11t_session_close_all(CK_SLOT_ID slot) { assert(p11t_module_funcs); if((p11t_module_funcs->C_CloseAllSessions)(slot) == CKR_OK) return 1; return 0; }