| /* |
| * Copyright (c) 2018, Linaro Limited |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License Version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program 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 General Public License for more details. |
| */ |
| |
| #include <ck_debug.h> |
| #include <inttypes.h> |
| #include <pkcs11.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "xtest_test.h" |
| #include "xtest_helpers.h" |
| |
| /* |
| * Util to find a slot on which to open a session |
| */ |
| static CK_RV close_lib(void) |
| { |
| return C_Finalize(0); |
| } |
| |
| static CK_RV init_lib_and_find_token_slot(CK_SLOT_ID *slot) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_SLOT_ID_PTR slots = NULL; |
| CK_ULONG count = 0; |
| |
| rv = C_Initialize(0); |
| if (rv) |
| return rv; |
| |
| rv = C_GetSlotList(CK_TRUE, NULL, &count); |
| if (rv != CKR_OK) |
| goto bail; |
| |
| if (count < 1) { |
| rv = CKR_GENERAL_ERROR; |
| goto bail; |
| } |
| |
| slots = malloc(count * sizeof(CK_SLOT_ID)); |
| if (!slots) { |
| rv = CKR_HOST_MEMORY; |
| goto bail; |
| } |
| |
| rv = C_GetSlotList(CK_TRUE, slots, &count); |
| if (rv) |
| goto bail; |
| |
| /* Use the last slot */ |
| *slot = slots[count - 1]; |
| |
| bail: |
| free(slots); |
| if (rv) |
| close_lib(); |
| |
| return rv; |
| } |
| |
| static void xtest_pkcs11_test_1000(ADBG_Case_t *c) |
| { |
| CK_RV rv; |
| |
| rv = C_Initialize(NULL); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| rv = C_Finalize(NULL); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| rv = C_Initialize(NULL); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| rv = C_Initialize(NULL); |
| ADBG_EXPECT_CK_RESULT(c, CKR_CRYPTOKI_ALREADY_INITIALIZED, rv); |
| |
| rv = C_Finalize(NULL); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| rv = C_Finalize(NULL); |
| ADBG_EXPECT_CK_RESULT(c, CKR_CRYPTOKI_NOT_INITIALIZED, rv); |
| } |
| |
| ADBG_CASE_DEFINE(pkcs11, 1000, xtest_pkcs11_test_1000, |
| "Initialize and close Cryptoki library"); |
| |
| static void xtest_pkcs11_test_1001(ADBG_Case_t *c) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_SLOT_ID_PTR slot_ids = NULL; |
| CK_ULONG slot_count = 0; |
| CK_ULONG present_slot_count = 0; |
| CK_INFO lib_info = { }; |
| CK_SLOT_INFO slot_info = { }; |
| CK_TOKEN_INFO token_info = { }; |
| CK_FUNCTION_LIST_PTR ckfunc_list = NULL; |
| size_t i = 0; |
| CK_SLOT_ID max_slot_id = 0; |
| CK_MECHANISM_TYPE_PTR mecha_types = NULL; |
| CK_ULONG mecha_count = 0; |
| CK_MECHANISM_INFO mecha_info = { }; |
| |
| rv = C_Initialize(NULL); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| Do_ADBG_BeginSubCase(c, "Test C_GetFunctionList()"); |
| |
| rv = C_GetFunctionList(&ckfunc_list); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (!ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetInfo) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetSlotList) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetSlotInfo) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetTokenInfo) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetMechanismList) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetMechanismInfo)) |
| goto out; |
| |
| Do_ADBG_EndSubCase(c, "Test C_GetFunctionList()"); |
| Do_ADBG_BeginSubCase(c, "Test C_GetInfo()"); |
| |
| rv = C_GetInfo(&lib_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| Do_ADBG_EndSubCase(c, "Test C_GetInfo()"); |
| Do_ADBG_BeginSubCase(c, "Test C_GetSlotList()"); |
| |
| rv = C_GetSlotList(0, NULL, &slot_count); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, slot_count, !=, 0)) |
| goto out; |
| |
| if (slot_count > 1) { |
| /* Ensure case non-NULL-buffer and zero-count is tested */ |
| CK_SLOT_ID id = 0; |
| |
| slot_count = 0; |
| rv = C_GetSlotList(0, &id, &slot_count); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_BUFFER_TOO_SMALL, rv)) |
| goto out; |
| } |
| |
| rv = C_GetSlotList(1, NULL, &present_slot_count); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, slot_count, ==, |
| present_slot_count)) |
| goto out; |
| |
| slot_ids = calloc(slot_count, sizeof(CK_SLOT_ID)); |
| if (!ADBG_EXPECT_NOT_NULL(c, slot_ids)) |
| goto out; |
| |
| slot_count--; |
| rv = C_GetSlotList(1, slot_ids, &slot_count); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_BUFFER_TOO_SMALL, rv)) |
| goto out; |
| |
| rv = C_GetSlotList(1, slot_ids, &slot_count); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| Do_ADBG_EndSubCase(c, "Test C_GetSlotList()"); |
| Do_ADBG_BeginSubCase(c, "Test C_Get{Slot|Token}Info()"); |
| |
| for (i = 0; i < slot_count; i++) { |
| CK_SLOT_ID slot = slot_ids[i]; |
| |
| rv = C_GetSlotInfo(slot, &slot_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (max_slot_id < slot) |
| max_slot_id = slot; |
| } |
| |
| Do_ADBG_EndSubCase(c, "Test C_Get{Slot|Token}Info()"); |
| Do_ADBG_BeginSubCase(c, "Test C_GetMechanism{List|Info}()"); |
| |
| for (i = 0; i < slot_count; i++) { |
| CK_SLOT_ID slot = slot_ids[i]; |
| size_t j = 0; |
| |
| mecha_count = 0; |
| rv = C_GetMechanismList(slot, NULL, &mecha_count); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (mecha_count == 0) |
| continue; |
| |
| free(mecha_types); |
| mecha_types = calloc(mecha_count, sizeof(*mecha_types)); |
| if (!ADBG_EXPECT_NOT_NULL(c, mecha_types)) |
| goto out; |
| |
| /* Test specific case: valid buffer reference with 0 count */ |
| mecha_count = 0; |
| rv = C_GetMechanismList(slot, mecha_types, &mecha_count); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_BUFFER_TOO_SMALL, rv)) |
| goto out; |
| |
| rv = C_GetMechanismList(slot, mecha_types, &mecha_count); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| for (j = 0; j < mecha_count; j++) { |
| rv = C_GetMechanismInfo(slot, mecha_types[j], |
| &mecha_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| } |
| } |
| |
| Do_ADBG_EndSubCase(c, "Test C_GetMechanism{List|Info}()"); |
| Do_ADBG_BeginSubCase(c, "Test C_Get*Info() with invalid reference"); |
| |
| rv = C_GetSlotInfo(max_slot_id + 1, &slot_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(max_slot_id + 1, &token_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| mecha_count = 1; |
| if (!mecha_types) |
| mecha_types = malloc(sizeof(*mecha_types)); |
| if (!ADBG_EXPECT_NOT_NULL(c, mecha_types)) |
| goto out; |
| |
| rv = C_GetMechanismList(max_slot_id + 1, mecha_types, &mecha_count); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| rv = C_GetMechanismInfo(max_slot_id + 1, CKM_AES_KEY_GEN, &mecha_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| rv = C_GetSlotInfo(ULONG_MAX, &slot_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(ULONG_MAX, &token_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| mecha_count = 1; |
| rv = C_GetMechanismList(ULONG_MAX, mecha_types, &mecha_count); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| rv = C_GetMechanismInfo(ULONG_MAX, CKM_AES_KEY_GEN, &mecha_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SLOT_ID_INVALID, rv)) |
| goto out; |
| |
| out: |
| Do_ADBG_EndSubCase(c, NULL); |
| free(slot_ids); |
| free(mecha_types); |
| |
| rv = C_Finalize(NULL); |
| ADBG_EXPECT_CK_OK(c, rv); |
| } |
| |
| ADBG_CASE_DEFINE(pkcs11, 1001, xtest_pkcs11_test_1001, |
| "PKCS11: List PKCS#11 slots and get information from"); |
| |
| static void xtest_pkcs11_test_1002(ADBG_Case_t *c) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_SLOT_ID slot = 0; |
| CK_SESSION_HANDLE session[3] = { 0 }; |
| CK_FLAGS session_flags = 0; |
| CK_SESSION_INFO session_info = { }; |
| CK_FUNCTION_LIST_PTR ckfunc_list = NULL; |
| |
| rv = init_lib_and_find_token_slot(&slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| rv = C_GetFunctionList(&ckfunc_list); |
| if (!ADBG_EXPECT_CK_OK(c, rv) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_OpenSession) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_CloseSession) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_CloseAllSessions) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_GetSessionInfo)) |
| goto bail; |
| |
| Do_ADBG_BeginSubCase(c, "Test C_OpenSession()/C_GetSessionInfo()"); |
| |
| session_flags = CKF_RW_SESSION; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session[0]); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_ARGUMENTS_BAD, rv)) |
| goto bail; |
| |
| session_flags = CKF_SERIAL_SESSION; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session[0]); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[0], &session_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.slotID, ==, slot) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.flags, ==, |
| session_flags) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.state, ==, |
| CKS_RO_PUBLIC_SESSION) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.ulDeviceError, ==, 0)) |
| goto bail; |
| |
| session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session[1]); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[1], &session_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.slotID, ==, slot) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.flags, ==, |
| session_flags) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.state, ==, |
| CKS_RW_PUBLIC_SESSION) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.ulDeviceError, ==, 0)) |
| goto bail; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session[2]); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[2], &session_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.slotID, ==, slot) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.flags, ==, |
| session_flags) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.state, ==, |
| CKS_RW_PUBLIC_SESSION) || |
| !ADBG_EXPECT_COMPARE_UNSIGNED(c, session_info.ulDeviceError, ==, 0)) |
| goto bail; |
| |
| Do_ADBG_EndSubCase(c, "Test C_OpenSession()/C_GetSessionInfo()"); |
| Do_ADBG_BeginSubCase(c, "Test C_CloseSession()"); |
| |
| /* Close 2 of them */ |
| rv = C_CloseSession(session[0]); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[0], &session_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[1], &session_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[2], &session_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| /* Close all remaining sessions, later calls should failed on session */ |
| rv = C_CloseAllSessions(slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| rv = C_CloseSession(session[1]); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv)) |
| goto bail; |
| |
| rv = C_CloseSession(session[2]); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[1], &session_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv)) |
| goto bail; |
| |
| rv = C_GetSessionInfo(session[2], &session_info); |
| if (!ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv)) |
| goto bail; |
| |
| /* Open a session, should be closed from library closure */ |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session[0]); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto bail; |
| |
| bail: |
| Do_ADBG_EndSubCase(c, NULL); |
| rv = close_lib(); |
| ADBG_EXPECT_CK_OK(c, rv); |
| } |
| |
| ADBG_CASE_DEFINE(pkcs11, 1002, xtest_pkcs11_test_1002, |
| "PKCS11: Open and close PKCS#11 sessions"); |
| |
| /* |
| * Helpers for tests where we must log into the token. |
| * These define the genuine PINs and label to be used with the test token. |
| */ |
| static CK_UTF8CHAR test_token_so_pin[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, }; |
| static CK_UTF8CHAR test_token_user_pin[] = { |
| 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, |
| }; |
| static CK_UTF8CHAR test_token_label[] = "PKCS11 TA test token"; |
| |
| static CK_RV init_test_token(CK_SLOT_ID slot) |
| { |
| return C_InitToken(slot, test_token_so_pin, sizeof(test_token_so_pin), |
| test_token_label); |
| } |
| |
| /* Login as user, eventually reset user PIN if needed */ |
| static CK_RV init_user_test_token(CK_SLOT_ID slot) |
| { |
| CK_FLAGS session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; |
| CK_SESSION_HANDLE session = CK_INVALID_HANDLE; |
| CK_RV rv = CKR_GENERAL_ERROR; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session); |
| if (rv) |
| return rv; |
| |
| rv = C_Login(session, CKU_USER, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| if (rv == CKR_OK) { |
| C_Logout(session); |
| C_CloseSession(session); |
| return rv; |
| } |
| |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| if (rv) { |
| C_CloseSession(session); |
| |
| rv = init_test_token(slot); |
| if (rv) |
| return rv; |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session); |
| if (rv) |
| return rv; |
| |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| if (rv) { |
| C_CloseSession(session); |
| return rv; |
| } |
| } |
| |
| rv = C_InitPIN(session, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| |
| C_Logout(session); |
| C_CloseSession(session); |
| |
| return rv; |
| } |
| |
| static CK_RV test_already_initialized_token(ADBG_Case_t *c, CK_SLOT_ID slot) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_TOKEN_INFO token_info = { }; |
| /* Same content as test_token_so_pin[] but 1 more byte */ |
| CK_UTF8CHAR pin1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }; |
| /* Same content as test_token_so_pin[] but 1 different byte */ |
| CK_UTF8CHAR pin2[] = { 0, 1, 2, 3, 4, 5, 6, 6, 8, 9, 10, }; |
| CK_FLAGS flags = 0; |
| |
| Do_ADBG_BeginSubCase(c, "C_InitToken() on initialized token"); |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_InitToken(slot, test_token_so_pin, |
| sizeof(test_token_so_pin) - 1, test_token_label); |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, rv, !=, CKR_OK)) |
| goto out; |
| |
| rv = C_InitToken(slot, pin1, sizeof(pin1), test_token_label); |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, rv, !=, CKR_OK)) |
| goto out; |
| |
| rv = C_InitToken(slot, pin2, sizeof(pin2), test_token_label); |
| if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, rv, !=, CKR_OK)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| flags = token_info.flags; |
| |
| /* Token should have set CKF_SO_PIN_COUNT_LOW to 1 */ |
| if (!ADBG_EXPECT_TRUE(c, !!(flags & CKF_SO_PIN_COUNT_LOW))) { |
| rv = CKR_GENERAL_ERROR; |
| goto out; |
| } |
| |
| rv = init_test_token(slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| flags = token_info.flags; |
| |
| /* |
| * Token should have reset CKF_SO_PIN_COUNT_LOW to 0. |
| * Other flags should show a sane initialized state. |
| */ |
| if (!ADBG_EXPECT_TRUE(c, !(flags & CKF_SO_PIN_COUNT_LOW)) || |
| !ADBG_EXPECT_TRUE(c, !!(flags & CKF_TOKEN_INITIALIZED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_ERROR_STATE)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_INITIALIZED))) { |
| rv = CKR_GENERAL_ERROR; |
| goto out; |
| } |
| |
| rv = init_user_test_token(slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| flags = token_info.flags; |
| |
| if (!ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_COUNT_LOW)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_FINAL_TRY)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_LOCKED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_TO_BE_CHANGED)) || |
| !ADBG_EXPECT_TRUE(c, !!(flags & CKF_USER_PIN_INITIALIZED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_ERROR_STATE))) { |
| rv = CKR_GENERAL_ERROR; |
| goto out; |
| } |
| |
| out: |
| Do_ADBG_EndSubCase(c, "C_InitToken() on initialized token"); |
| |
| return rv; |
| } |
| |
| static CK_RV test_uninitialized_token(ADBG_Case_t *c, CK_SLOT_ID slot) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_TOKEN_INFO token_info = { }; |
| CK_FLAGS flags = 0; |
| |
| Do_ADBG_BeginSubCase(c, "C_InitToken() on uninitialized token"); |
| |
| rv = init_test_token(slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| flags = token_info.flags; |
| |
| if (!ADBG_EXPECT_TRUE(c, !!(flags & CKF_TOKEN_INITIALIZED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_ERROR_STATE)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_INITIALIZED))) { |
| rv = CKR_GENERAL_ERROR; |
| goto out; |
| } |
| |
| rv = init_user_test_token(slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| flags = token_info.flags; |
| |
| if (!ADBG_EXPECT_TRUE(c, !!(flags & CKF_TOKEN_INITIALIZED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_COUNT_LOW)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_FINAL_TRY)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_LOCKED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_USER_PIN_TO_BE_CHANGED)) || |
| !ADBG_EXPECT_TRUE(c, !!(flags & CKF_USER_PIN_INITIALIZED)) || |
| !ADBG_EXPECT_TRUE(c, !(flags & CKF_ERROR_STATE))) |
| rv = CKR_GENERAL_ERROR; |
| |
| out: |
| Do_ADBG_EndSubCase(c, "C_InitToken() on uninitialized token"); |
| |
| return rv; |
| } |
| |
| static CK_RV test_login_logout(ADBG_Case_t *c, CK_SLOT_ID slot) |
| { |
| CK_FLAGS session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; |
| CK_SESSION_HANDLE session = CK_INVALID_HANDLE; |
| CK_RV rv = CKR_GENERAL_ERROR; |
| |
| Do_ADBG_BeginSubCase(c, "Test C_Login()/C_Logout()"); |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| /* Logout: should fail as we did not log in yet */ |
| rv = C_Logout(session); |
| ADBG_EXPECT_CK_RESULT(c, CKR_USER_NOT_LOGGED_IN, rv); |
| |
| /* Login/re-log/logout user */ |
| rv = C_Login(session, CKU_USER, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_Login(session, CKU_USER, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| ADBG_EXPECT_CK_RESULT(c, CKR_USER_ALREADY_LOGGED_IN, rv); |
| |
| rv = C_Logout(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| /* Login/re-log/logout security officer */ |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| ADBG_EXPECT_CK_RESULT(c, CKR_USER_ALREADY_LOGGED_IN, rv); |
| |
| rv = C_Logout(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| /* Login user then SO and reverse */ |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| rv = C_Login(session, CKU_USER, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| ADBG_EXPECT_CK_RESULT(c, CKR_USER_ANOTHER_ALREADY_LOGGED_IN, rv); |
| |
| rv = C_Logout(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| rv = C_Login(session, CKU_USER, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| rv = C_Login(session, CKU_SO, test_token_so_pin, |
| sizeof(test_token_so_pin)); |
| ADBG_EXPECT_CK_RESULT(c, CKR_USER_ANOTHER_ALREADY_LOGGED_IN, rv); |
| |
| rv = C_Logout(session); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| /* Login context specifc, in an invalid case (need an operation) */ |
| rv = C_Login(session, CKU_CONTEXT_SPECIFIC, test_token_user_pin, |
| sizeof(test_token_user_pin)); |
| ADBG_EXPECT_CK_RESULT(c, CKR_OPERATION_NOT_INITIALIZED, rv); |
| |
| rv = C_CloseSession(session); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| out: |
| Do_ADBG_EndSubCase(c, "Test C_Login()/C_Logout()"); |
| return rv; |
| } |
| |
| static CK_RV test_set_pin(ADBG_Case_t *c, CK_SLOT_ID slot, |
| CK_USER_TYPE user_type) |
| { |
| CK_FLAGS session_flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; |
| CK_SESSION_HANDLE session = CK_INVALID_HANDLE; |
| CK_UTF8CHAR some_pin[] = { 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7 }; |
| CK_UTF8CHAR_PTR old_pin = NULL; |
| CK_USER_TYPE ut = user_type; |
| size_t old_pin_sz = 0; |
| CK_RV rv2 = CKR_OK; |
| CK_RV rv = CKR_OK; |
| |
| Do_ADBG_BeginSubCase(c, "Test C_SetPIN() user_type %lu", user_type); |
| |
| rv = C_OpenSession(slot, session_flags, NULL, 0, &session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| if (user_type == CKU_SO) { |
| old_pin = (CK_UTF8CHAR_PTR)test_token_so_pin; |
| old_pin_sz = sizeof(test_token_so_pin); |
| } else { |
| old_pin = (CK_UTF8CHAR_PTR)test_token_user_pin; |
| old_pin_sz = sizeof(test_token_user_pin); |
| ut = CKU_USER; |
| } |
| |
| if (ut == user_type) { |
| rv = C_Login(session, ut, old_pin, old_pin_sz); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out_session; |
| } |
| |
| rv = C_SetPIN(session, old_pin, old_pin_sz, some_pin, sizeof(some_pin)); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) { |
| if (ut == user_type) |
| goto out_logout; |
| else |
| goto out_session; |
| } |
| |
| if (ut == user_type) { |
| rv = C_Logout(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out_session; |
| } |
| |
| rv = C_Login(session, ut, some_pin, sizeof(some_pin)); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out_session; |
| |
| rv = C_SetPIN(session, some_pin, sizeof(some_pin), old_pin, old_pin_sz); |
| ADBG_EXPECT_CK_OK(c, rv); |
| |
| out_logout: |
| rv2 = C_Logout(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv2) && !rv) |
| rv = rv2; |
| out_session: |
| rv2 = C_CloseSession(session); |
| if (!ADBG_EXPECT_CK_OK(c, rv2) && !rv) |
| rv = rv2; |
| out: |
| Do_ADBG_EndSubCase(c, "Test C_SetPIN() user_type %lu", user_type); |
| |
| return rv; |
| } |
| |
| static void xtest_pkcs11_test_1003(ADBG_Case_t *c) |
| { |
| CK_RV rv = CKR_GENERAL_ERROR; |
| CK_FUNCTION_LIST_PTR ckfunc_list = NULL; |
| CK_SLOT_ID slot = 0; |
| CK_TOKEN_INFO token_info = { }; |
| |
| rv = C_GetFunctionList(&ckfunc_list); |
| if (!ADBG_EXPECT_CK_OK(c, rv) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_InitToken) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_InitPIN) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_SetPIN) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_Login) || |
| !ADBG_EXPECT_NOT_NULL(c, ckfunc_list->C_Logout)) |
| goto out; |
| |
| rv = init_lib_and_find_token_slot(&slot); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| return; |
| |
| rv = C_GetTokenInfo(slot, &token_info); |
| if (!ADBG_EXPECT_CK_OK(c, rv)) |
| goto out; |
| |
| /* Abort test if token is about to lock */ |
| if (!ADBG_EXPECT_TRUE(c, !(token_info.flags & CKF_SO_PIN_FINAL_TRY))) |
| goto out; |
| |
| if (!(token_info.flags & CKF_TOKEN_INITIALIZED)) { |
| rv = test_uninitialized_token(c, slot); |
| if (rv != CKR_OK) |
| goto out; |
| } |
| |
| rv = test_already_initialized_token(c, slot); |
| if (rv != CKR_OK) |
| goto out; |
| |
| rv = test_login_logout(c, slot); |
| if (rv != CKR_OK) |
| goto out; |
| |
| rv = test_set_pin(c, slot, CKU_USER); |
| if (rv != CKR_OK) |
| goto out; |
| |
| rv = test_set_pin(c, slot, CKU_SO); |
| if (rv != CKR_OK) |
| goto out; |
| |
| /* |
| * CKU_CONTEXT_SPECIFIC is anything not CKU_USER or CKU_SO in order |
| * to skip the initial login. |
| */ |
| test_set_pin(c, slot, CKU_CONTEXT_SPECIFIC); |
| out: |
| rv = close_lib(); |
| ADBG_EXPECT_CK_OK(c, rv); |
| } |
| |
| ADBG_CASE_DEFINE(pkcs11, 1003, xtest_pkcs11_test_1003, |
| "PKCS11: Login to PKCS#11 token"); |