pkcs11 1002: test session API functions

Add test of C_OpenSession(), C_GetSessionInfo(), C_CloseSession() and
C_CloseAllSessions() from PKCS11 TA test token in pkcs11 regression
test 1002.

Test token over which test is made is the last slot found if the slot
list reported by the Cryptoki library. Helper function
init_lib_and_find_token_slot() takes care of Cryptoki pre-session setup.

Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/host/xtest/pkcs11_1000.c b/host/xtest/pkcs11_1000.c
index eed7225..c7c7a08 100644
--- a/host/xtest/pkcs11_1000.c
+++ b/host/xtest/pkcs11_1000.c
@@ -21,6 +21,54 @@
 #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_tee_test_1000(ADBG_Case_t *c)
 {
 	CK_RV rv;
@@ -241,3 +289,133 @@
 
 ADBG_CASE_DEFINE(pkcs11, 1001, xtest_tee_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");