/* * COPYRIGHT (c) International Business Machines Corp. 2015-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ #include #include #include #include #include "pkcs11types.h" #include "regress.h" #include "common.c" CK_RV do_GetInfo(void) { CK_FLAGS flags; CK_SESSION_HANDLE session; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_INFO info; // Do some setup and login to the token testcase_begin("C_GetInfo function check"); testcase_rw_session(); testcase_user_login(); testcase_new_assertion(); rc = funcs->C_GetInfo(&info); if (rc != CKR_OK) { testcase_fail("C_GetInfo() rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Library info successfully sourced"); testcase_cleanup: testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSession() failed."); return rc; } CK_RV do_GetSlotList(void) { CK_FLAGS flags; CK_SESSION_HANDLE session; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_BBOOL tokenPresent; CK_SLOT_ID_PTR pSlotList = NULL; CK_ULONG ulCount = 0; tokenPresent = TRUE; testcase_begin("testing C_GetSlotList"); testcase_rw_session(); testcase_user_login(); testcase_new_assertion(); /* pkcs#11v2.20, Section 11.5 * If pSlotList is NULL_PTR, then all that C_GetSlotList does is * return (in *pulCount) the number of slots, without actually * returning a list of slots. */ rc = funcs->C_GetSlotList(tokenPresent, NULL, &ulCount); if (rc != CKR_OK) { testcase_fail("C_GetSlotList rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } if (ulCount) testcase_pass("C_GetSlotList received slot count."); else testcase_fail("C_GetSlotList did not receive slot count."); pSlotList = (CK_SLOT_ID *) malloc(ulCount * sizeof(CK_SLOT_ID)); if (!pSlotList) { testcase_error("malloc failed to allocate memory for list\n"); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } testcase_new_assertion(); /* Get the slots */ rc = funcs->C_GetSlotList(tokenPresent, pSlotList, &ulCount); if (rc != CKR_OK) { testcase_fail("C_GetSlotList rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Slot list returned successfully"); testcase_cleanup: if (pSlotList) free(pSlotList); testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSession failed."); return rc; } CK_RV do_GetSlotInfo(void) { CK_FLAGS flags; CK_SESSION_HANDLE session; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = SLOT_ID; CK_SLOT_INFO info; testcase_begin("testing C_GetSlotInfo"); testcase_rw_session(); testcase_user_login(); /* Test expected values */ testcase_new_assertion(); rc = funcs->C_GetSlotInfo(slot_id, &info); if (rc != CKR_OK) { testcase_fail("C_GetSlotInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Slot info of in-use slot received successfully"); /* Test for invalid slot */ testcase_new_assertion(); rc = funcs->C_GetSlotInfo(9999, &info); if (rc != CKR_SLOT_ID_INVALID) { testcase_fail("C_GetSlotInfo returned %s instead of" " CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); rc = CKR_FUNCTION_FAILED; // dont confuse loop in main goto testcase_cleanup; } testcase_pass("C_GetSlotInfo correctly returned " "CKR_SLOT_ID_INVALID."); rc = 0; // don't confuse loop in main testcase_cleanup: testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSessions failed."); return rc; } CK_RV do_GetTokenInfo(void) { CK_FLAGS flags; CK_SESSION_HANDLE session; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG user_pin_len; CK_SLOT_ID slot_id = SLOT_ID; CK_TOKEN_INFO info; testcase_begin("testing C_GetTokenInfo()"); testcase_rw_session(); testcase_user_login(); testcase_new_assertion(); rc = funcs->C_GetTokenInfo(slot_id, &info); if (rc != CKR_OK) { testcase_fail("C_GetTokenInfo rc=%s", p11_get_ckr(rc)); return rc; } testcase_pass("C_GetTokenInfo returned successfully"); /* Test with an invalid slot id */ testcase_new_assertion(); rc = funcs->C_GetTokenInfo(9999, &info); if (rc != CKR_SLOT_ID_INVALID) { testcase_fail("C_GetTokenInfo() rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_GetTokenInfo returned error when given invalid slot."); testcase_cleanup: testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSessions failed."); return rc; } CK_RV do_GetMechanismList(void) { CK_FLAGS flags = 0; CK_SESSION_HANDLE session = 0; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; CK_ULONG user_pin_len = 0; CK_SLOT_ID slot_id = SLOT_ID; CK_ULONG count = 0; CK_MECHANISM_TYPE *mech_list = NULL; testcase_begin("testing C_GetMechanismList"); testcase_rw_session(); testcase_user_login(); /* pkcs11v2.20, page 111 * If pMechanismList is NULL_PTR, then all that C_GetMechanismList * does is return (in *pulCount) the number of mechanisms, without * actually returning a list of mechanisms. The contents of * *pulCount on entry to C_GetMechanismList has no meaning in this * case, and the call returns the value CKR_OK. */ testcase_new_assertion(); rc = funcs->C_GetMechanismList(slot_id, NULL, &count); if (rc != CKR_OK) { testcase_fail("C_GetMechanismList 1 rc=%s", p11_get_ckr(rc)); return rc; } if (count) testcase_pass("C_GetMechanismList returned mechanism count."); else testcase_fail("C_GetMechanismList did not not return " "mechanism count."); mech_list = (CK_MECHANISM_TYPE *) calloc(1, count * sizeof(CK_MECHANISM_TYPE)); if (!mech_list) { testcase_fail(); rc = CKR_HOST_MEMORY; goto testcase_cleanup; } testcase_new_assertion(); rc = funcs->C_GetMechanismList(slot_id, mech_list, &count); if (rc != CKR_OK) { testcase_fail("C_GetMechanismList 2 rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Mechanism listing from current slot"); /* Test for invalid slot */ testcase_new_assertion(); rc = funcs->C_GetMechanismList(9999, NULL, &count); if (rc != CKR_SLOT_ID_INVALID) { testcase_fail("C_GetMechanismList() returned %s instead of" " CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } testcase_pass("C_GetMechanismList correctly returned " "CKR_SLOT_ID_INVALID."); rc = CKR_OK; testcase_cleanup: if (mech_list) free(mech_list); testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSessions failed."); return rc; } CK_RV do_GetMechanismInfo(void) { CK_FLAGS flags = 0; CK_SESSION_HANDLE session = 0; CK_RV rc = 0; CK_BYTE user_pin[PKCS11_MAX_PIN_LEN] = {0}; CK_ULONG user_pin_len = 0; CK_SLOT_ID slot_id = SLOT_ID; CK_MECHANISM_INFO info; CK_ULONG i = 0, count = 0; CK_MECHANISM_TYPE *mech_list = NULL; memset(&info, 0, sizeof(info)); testcase_begin("testing C_GetMechanismInfo"); testcase_rw_session(); testcase_user_login(); testcase_new_assertion(); rc = funcs->C_GetMechanismList(slot_id, NULL, &count); if (rc != CKR_OK) { testcase_error("C_GetMechanismList #1 rc=%s", p11_get_ckr(rc)); return rc; } mech_list = (CK_MECHANISM_TYPE *) calloc(1, count * sizeof(CK_MECHANISM_TYPE)); if (!mech_list) { rc = CKR_HOST_MEMORY; goto testcase_cleanup; } rc = funcs->C_GetMechanismList(slot_id, mech_list, &count); if (rc != CKR_OK) { testcase_error("C_GetMechanismList #2 rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } for (i = 0; i < count; i++) { rc = funcs->C_GetMechanismInfo(slot_id, mech_list[i], &info); if (rc != CKR_OK) break; } if (rc != CKR_OK) testcase_fail("C_GetMechanismInfo rc=%s", p11_get_ckr(rc)); else testcase_pass("C_GetMechanismInfo was successful."); testcase_new_assertion(); rc = funcs->C_GetMechanismInfo(slot_id, 0x12345678, &info); if (rc != CKR_MECHANISM_INVALID) testcase_fail("C_GetMechanismInfo returned rc=%s instead " "of CKR_MECHANISM_INVALID", p11_get_ckr(rc)); else testcase_pass("C_GetMechanismInfo correctly returned CKR_MECHANISM_INVALID."); testcase_cleanup: if (mech_list) free(mech_list); testcase_user_logout(); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSessions rc=%s", p11_get_ckr(rc)); return rc; } CK_RV do_InitToken(void) { CK_BYTE label[32] = {0}; int len = 0; CK_CHAR so_pin[PKCS11_MAX_PIN_LEN] = {0}; CK_RV rc = 0; testcase_begin("testing C_InitToken"); memcpy(label, "L13 ", 32); for (len = 0; len < 31; len++) { if (label[len] == '\0') { label[len] = ' '; break; } } testcase_new_assertion(); /* test with invalid SO PIN */ rc = funcs->C_InitToken(SLOT_ID, NULL, strlen((char *) so_pin), label); if (rc != CKR_ARGUMENTS_BAD) { testcase_fail("C_InitToken returned %s instead of " "CKR_ARGUMENTS_BAD", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_InitToken correctly return CKR_ARGUMENS_BAD."); /* test with invalid slot id */ testcase_new_assertion(); rc = funcs->C_InitToken(9999, so_pin, strlen((char *) so_pin), label); if (rc != CKR_SLOT_ID_INVALID) { testcase_fail("C_InitToken returned %s instead of " "CKR_SLOT_ID_INVALID.", p11_get_ckr(rc)); rc = CKR_FUNCTION_FAILED; } else { testcase_pass("C_InitToken correctly returned CKR_SLOT_ID_INVALID."); rc = CKR_OK; } testcase_cleanup: return rc; } CK_RV do_InitPIN(void) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_CHAR so_pin[PKCS11_MAX_PIN_LEN]; CK_CHAR user_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG so_pin_len; CK_ULONG user_pin_len; CK_RV rc; testcase_begin("Testing C_InitPIN"); if (get_user_pin(user_pin)) return CKR_FUNCTION_FAILED; user_pin_len = (CK_ULONG) strlen((char *) user_pin); if (get_so_pin(so_pin)) return CKR_FUNCTION_FAILED; so_pin_len = (CK_ULONG) strlen((char *) so_pin); slot_id = SLOT_ID; flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; // try to call C_InitPIN from a public session testcase_new_assertion(); rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); if (rc != CKR_OK) { testcase_error("C_OpenSession rc=%s", p11_get_ckr(rc)); return rc; } rc = funcs->C_InitPIN(session, user_pin, user_pin_len); if (rc != CKR_USER_NOT_LOGGED_IN) { testcase_fail("C_InitPIN returned %s instead of " "CKR_USER_NOT_LOGGED_IN", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_InitPin correctly returned CKR_USER_NOT_LOGGED_IN."); // try to call C_InitPIN from an SO session testcase_new_assertion(); rc = funcs->C_Login(session, CKU_SO, so_pin, so_pin_len); if (rc != CKR_OK) { testcase_error("C_Login #1 failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_InitPIN(session, user_pin, user_pin_len); if (rc != CKR_OK) testcase_fail("C_InitPIN failed: rc=%s", p11_get_ckr(rc)); else testcase_pass("C_InitPIN #1 was successful."); rc = funcs->C_Logout(session); if (rc != CKR_OK) { testcase_error("C_Logout #1 failed."); goto testcase_cleanup; } // try to call C_InitPIN from a normal user session testcase_new_assertion(); rc = funcs->C_Login(session, CKU_USER, user_pin, user_pin_len); if (rc != CKR_OK) { testcase_error("C_Login failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_InitPIN(session, user_pin, user_pin_len); if (rc != CKR_USER_NOT_LOGGED_IN) { testcase_fail("C_InitPIN returned %s instead of " "CKR_USER_NOT_LOGGED_IN.", p11_get_ckr(rc)); rc = CKR_FUNCTION_FAILED; } else { testcase_pass("C_InitPIN #2 was successful."); rc = CKR_OK; } rc = funcs->C_Logout(session); if (rc != CKR_OK) testcase_error("C_Logout #2 rc=%s", p11_get_ckr(rc)); testcase_cleanup: rc = funcs->C_CloseAllSessions(slot_id); if (rc != CKR_OK) testcase_error("C_CloseAllSessions #1 rc=%s", p11_get_ckr(rc)); return rc; } CK_RV do_SetPIN(void) { CK_SLOT_ID slot_id; CK_FLAGS flags; CK_SESSION_HANDLE session; CK_CHAR old_pin[PKCS11_MAX_PIN_LEN]; CK_CHAR new_pin[PKCS11_MAX_PIN_LEN]; CK_ULONG old_len; CK_ULONG new_len; CK_RV rc; testcase_begin("Testing C_SetPIN"); // first, try to get the user PIN if (get_user_pin(old_pin)) return CKR_FUNCTION_FAILED; old_len = (CK_ULONG) strlen((char *) old_pin); memcpy(new_pin, "ABCDEF", 6); new_len = 6; slot_id = SLOT_ID; /* try to call C_SetPIN from a R/O public session, it should fail. */ flags = CKF_SERIAL_SESSION; testcase_new_assertion(); rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); if (rc != CKR_OK) { testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); return rc; } rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); if (rc != CKR_SESSION_READ_ONLY) { testcase_fail("C_SetPIN #1 returned %s instead of " "CKR_SESSION_READ_ONLY.", p11_get_ckr(rc)); rc = CKR_FUNCTION_FAILED; goto testcase_cleanup; } testcase_pass("C_SetPIN successful in pubic session."); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) { testcase_error("C_CloseSession #1 failed."); goto testcase_cleanup; } /* try to call C_SetPIN from a R/W public session, it should work. */ testcase_new_assertion(); flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); if (rc != CKR_OK) { testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); return rc; } rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); if (rc != CKR_OK) { testcase_fail("C_SetPIN failed: rc = %s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_SetPIN successful in r/w pubic session."); rc = funcs->C_CloseSession(session); if (rc != CKR_OK) { testcase_error("C_CloseSession #1 failed."); goto testcase_cleanup; } /* open a new session and try logging in with new pin */ flags = CKF_SERIAL_SESSION | CKF_RW_SESSION; rc = funcs->C_OpenSession(slot_id, flags, NULL, NULL, &session); if (rc != CKR_OK) { testcase_error("C_OpenSession #1 rc=%s", p11_get_ckr(rc)); return rc; } testcase_new_assertion(); rc = funcs->C_Login(session, CKU_USER, new_pin, new_len); if (rc != CKR_OK) { testcase_fail("C_Login #1 failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("Successfully logged in with new pin."); /* try to call C_SetPIN from a normal user session, r/w user. * set back to original user pin. this should work. */ testcase_new_assertion(); rc = funcs->C_SetPIN(session, new_pin, new_len, old_pin, old_len); if (rc != CKR_OK) { testcase_fail("C_SetPIN #2 rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_SetPIN successful."); rc = funcs->C_Logout(session); if (rc != CKR_OK) { testcase_error("C_Logout #1 falied: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } /* * done with user tests...now try with the SO */ if (get_so_pin(old_pin)) return CKR_FUNCTION_FAILED; /* try to call C_SetPIN from a normal user session */ testcase_new_assertion(); rc = funcs->C_Login(session, CKU_SO, old_pin, old_len); if (rc != CKR_OK) { testcase_error("C_Login #3failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } rc = funcs->C_SetPIN(session, old_pin, old_len, new_pin, new_len); if (rc != CKR_OK) { testcase_fail("C_SetPIN #4 failed: rc=%s", p11_get_ckr(rc)); goto testcase_cleanup; } testcase_pass("C_SetPIN successfully set SO PIN."); rc = funcs->C_Logout(session); if (rc != CKR_OK) { testcase_error("C_Logout #3 failed."); goto testcase_cleanup; } /* now login with new pin. should work. */ testcase_new_assertion(); rc = funcs->C_Login(session, CKU_SO, new_pin, new_len); if (rc != CKR_OK) testcase_fail("C_Login #5 failed: rc=%s", p11_get_ckr(rc)); else testcase_pass("C_Login #5 was successful."); /* change the PIN back to the original so the rest of this program * doesn't break */ rc = funcs->C_SetPIN(session, new_pin, new_len, old_pin, old_len); if (rc != CKR_OK) testcase_error("C_SetPIN #5 failed to set back to the original " "SO PIN, rc=%s", p11_get_ckr(rc)); rc = funcs->C_Logout(session); if (rc != CKR_OK) testcase_error("C_Logout #4 failed."); testcase_cleanup: rc = funcs->C_CloseSession(session); if (rc != CKR_OK) testcase_error("C_CloseSession #1 failed."); return rc; } CK_RV api_driver(void) { CK_RV rc; rc = do_GetInfo(); if (rc && !no_stop) return rc; rc = do_GetSlotList(); if (rc && !no_stop) return rc; rc = do_GetSlotInfo(); if (rc && !no_stop) return rc; rc = do_GetTokenInfo(); if (rc && !no_stop) return rc; rc = do_GetMechanismList(); if (rc && !no_stop) return rc; rc = do_GetMechanismInfo(); if (rc && !no_stop) return rc; /* do not run on icsf token */ if (!is_icsf_token(SLOT_ID)) { rc = do_InitToken(); if (rc && !no_stop) return rc; } rc = do_InitPIN(); if (rc && !no_stop) return rc; rc = do_SetPIN(); if (rc && !no_stop) return rc; return rc; } int main(int argc, char **argv) { int rc; CK_C_INITIALIZE_ARGS cinit_args; CK_RV rv = 0; rc = do_ParseArgs(argc, argv); if (rc != 1) return rc; printf("Using slot #%lu...\n\n", SLOT_ID); printf("With option: nostop: %d\n", no_stop); rc = do_GetFunctionList(); if (!rc) { testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); return rc; } memset(&cinit_args, 0x0, sizeof(cinit_args)); cinit_args.flags = CKF_OS_LOCKING_OK; funcs->C_Initialize(&cinit_args); { CK_SESSION_HANDLE hsess = 0; rc = funcs->C_GetFunctionStatus(hsess); if (rc != CKR_FUNCTION_NOT_PARALLEL) return rc; rc = funcs->C_CancelFunction(hsess); if (rc != CKR_FUNCTION_NOT_PARALLEL) return rc; } testcase_setup(0); rv = api_driver(); testcase_print_result(); funcs->C_Finalize(NULL_PTR); /* make sure we return non-zero if rv is non-zero */ return ((rv == 0) || (rv % 256) ? (int)rv : -1); }