xtest: pkcs11: add symmetric cipher tests

Adds 1005, 1006 and 1007 testing symmetric ciphers via
- C_EncryptInit()
- C_Encrypt()
- C_EncryptUpdate()
- C_EncryptFinal()
- C_DecryptInit()
- C_Decrypt()
- C_DecryptUpdate()
- C_DecryptFinal()

Reviewed-by: Vesa Jääskeläinen <vesa.jaaskelainen@vaisala.com>
Co-developed-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/host/xtest/pkcs11_1000.c b/host/xtest/pkcs11_1000.c
index ad300e6..c29f2fc 100644
--- a/host/xtest/pkcs11_1000.c
+++ b/host/xtest/pkcs11_1000.c
@@ -19,6 +19,29 @@
  */
 static const CK_BYTE cktest_aes128_key[16];
 
+static const CK_BYTE cktest_aes128_iv[16];
+
+static const CK_AES_CTR_PARAMS cktest_aes_ctr_params = {
+	.ulCounterBits = 1,
+};
+
+static CK_MECHANISM cktest_aes_ecb_mechanism = {
+	CKM_AES_ECB,
+	NULL, 0,
+};
+static CK_MECHANISM cktest_aes_cbc_mechanism = {
+	CKM_AES_CBC,
+	(CK_BYTE_PTR)cktest_aes128_iv, sizeof(cktest_aes128_iv),
+};
+static CK_MECHANISM cktest_aes_ctr_mechanism = {
+	CKM_AES_CTR,
+	(CK_BYTE_PTR)&cktest_aes_ctr_params, sizeof(cktest_aes_ctr_params),
+};
+static CK_MECHANISM cktest_aes_cts_mechanism = {
+	CKM_AES_CTS,
+	(CK_BYTE_PTR)cktest_aes128_iv, sizeof(cktest_aes128_iv),
+};
+
 /*
  * Util to find a slot on which to open a session
  */
@@ -1027,3 +1050,416 @@
 
 ADBG_CASE_DEFINE(pkcs11, 1004, xtest_pkcs11_test_1004,
 		 "PKCS11: create/destroy PKCS#11 simple objects");
+
+
+static const CK_MECHANISM_TYPE allowed_only_aes_ecb[] = {
+	CKM_AES_ECB,
+};
+static const CK_MECHANISM_TYPE allowed_not_aes_ecb[] = {
+	CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_AES_CTR, CKM_AES_CTS,
+	CKM_AES_GCM, CKM_AES_CCM,
+};
+static const CK_MECHANISM_TYPE allowed_only_aes_cbcnopad[] = {
+	CKM_AES_CBC,
+};
+static const CK_MECHANISM_TYPE allowed_not_aes_cbcnopad[] = {
+	CKM_AES_ECB, CKM_AES_CBC_PAD, CKM_AES_CTR, CKM_AES_CTS,
+	CKM_AES_GCM, CKM_AES_CCM,
+};
+static const CK_MECHANISM_TYPE allowed_only_aes_ctr[] = {
+	CKM_AES_CTR,
+};
+static const CK_MECHANISM_TYPE allowed_not_aes_ctr[] = {
+	CKM_AES_ECB, CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_AES_CTS,
+	CKM_AES_GCM, CKM_AES_CCM,
+};
+static const CK_MECHANISM_TYPE allowed_only_aes_cts[] = {
+	CKM_AES_CTS,
+};
+static const CK_MECHANISM_TYPE allowed_not_aes_cts[] = {
+	CKM_AES_ECB, CKM_AES_CBC, CKM_AES_CBC_PAD, CKM_AES_CTR,
+	CKM_AES_GCM, CKM_AES_CCM,
+};
+
+#define CKTEST_AES_KEY \
+	{ CKA_CLASS,	&(CK_OBJECT_CLASS){CKO_SECRET_KEY},	\
+			sizeof(CK_OBJECT_CLASS) },		\
+	{ CKA_KEY_TYPE,	&(CK_KEY_TYPE){CKK_AES},		\
+			sizeof(CK_KEY_TYPE) },			\
+	{ CKA_VALUE,	(void *)cktest_aes128_key,		\
+			sizeof(cktest_aes128_key) }
+
+#define CKTEST_AES_ALLOWED_KEY(_allowed) \
+	{ CKA_ALLOWED_MECHANISMS, (void *)_allowed, sizeof(_allowed), }
+
+#define CK_KEY_ALLOWED_AES_TEST(_label, _allowed) \
+	static CK_ATTRIBUTE _label[] = {				\
+		CKTEST_AES_KEY,						\
+		{ CKA_ENCRYPT,	&(CK_BBOOL){CK_TRUE}, sizeof(CK_BBOOL) }, \
+		{ CKA_DECRYPT,	&(CK_BBOOL){CK_TRUE}, sizeof(CK_BBOOL) }, \
+		CKTEST_AES_ALLOWED_KEY(_allowed),			\
+	}
+
+#define CK_KEY_ALLOWED_AES_ENC_TEST(_label, _allowed) \
+	static CK_ATTRIBUTE _label[] = {				\
+		CKTEST_AES_KEY,						\
+		{ CKA_ENCRYPT,	&(CK_BBOOL){CK_TRUE}, sizeof(CK_BBOOL) }, \
+		CKTEST_AES_ALLOWED_KEY(_allowed),			\
+	}
+#define CK_KEY_ALLOWED_AES_DEC_TEST(_label, _allowed) \
+	static CK_ATTRIBUTE _label[] = {				\
+		CKTEST_AES_KEY,						\
+		{ CKA_DECRYPT,	&(CK_BBOOL){CK_TRUE}, sizeof(CK_BBOOL) }, \
+		CKTEST_AES_ALLOWED_KEY(_allowed),			\
+	}
+
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_only_ecb, allowed_only_aes_ecb);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_not_ecb, allowed_not_aes_ecb);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_only_cbcnopad, allowed_only_aes_cbcnopad);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_not_cbcnopad, allowed_not_aes_cbcnopad);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_only_cts, allowed_only_aes_cts);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_not_cts, allowed_not_aes_cts);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_only_ctr, allowed_only_aes_ctr);
+CK_KEY_ALLOWED_AES_TEST(cktest_aes_not_ctr, allowed_not_aes_ctr);
+
+struct cktest_allowed_test {
+	CK_ATTRIBUTE_PTR attr_key;
+	CK_ULONG attr_count;
+	CK_MECHANISM_PTR mechanism;
+};
+
+#define CKTEST_KEY_MECHA(key, mecha) {	\
+		.attr_key = key,		\
+		.attr_count = ARRAY_SIZE(key),	\
+		.mechanism = mecha,		\
+	}
+
+static const struct cktest_allowed_test cktest_allowed_valid[] = {
+	CKTEST_KEY_MECHA(cktest_aes_only_ecb, &cktest_aes_ecb_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_only_cbcnopad, &cktest_aes_cbc_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_only_cts, &cktest_aes_cts_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_only_ctr, &cktest_aes_ctr_mechanism),
+};
+
+static const struct cktest_allowed_test cktest_allowed_invalid[] = {
+	CKTEST_KEY_MECHA(cktest_aes_not_ecb, &cktest_aes_ecb_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_not_cbcnopad, &cktest_aes_cbc_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_not_cts, &cktest_aes_cts_mechanism),
+	CKTEST_KEY_MECHA(cktest_aes_not_ctr, &cktest_aes_ctr_mechanism),
+};
+
+/* Create session object and token object from a session */
+static CK_RV cipher_init_final(ADBG_Case_t *c, CK_SESSION_HANDLE session,
+				CK_ATTRIBUTE_PTR attr_key, CK_ULONG attr_count,
+				CK_MECHANISM_PTR mechanism, uint32_t mode,
+				CK_RV expected_rc)
+{
+	CK_RV rv2 = CKR_GENERAL_ERROR;
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_OBJECT_HANDLE object = CK_INVALID_HANDLE;
+
+	switch (mode) {
+	case TEE_MODE_ENCRYPT:
+	case TEE_MODE_DECRYPT:
+		break;
+	default:
+		ADBG_EXPECT_TRUE(c, false);
+	}
+
+	rv = C_CreateObject(session, attr_key, attr_count, &object);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return rv;
+
+	if (mode == TEE_MODE_ENCRYPT)
+		rv = C_EncryptInit(session, mechanism, object);
+	if (mode == TEE_MODE_DECRYPT)
+		rv = C_DecryptInit(session, mechanism, object);
+
+	if (!ADBG_EXPECT_CK_RESULT(c, expected_rc, rv)) {
+		rv = CKR_GENERAL_ERROR;
+		goto out;
+	}
+
+	if (rv) {
+		/*
+		 * If we're here it was the expected error code above and
+		 * we're supposed to return OK below.
+		 */
+		rv = CKR_OK;
+	} else {
+		if (mode == TEE_MODE_ENCRYPT)
+			rv = C_EncryptFinal(session, NULL, NULL);
+		if (mode == TEE_MODE_DECRYPT)
+			rv = C_DecryptFinal(session, NULL, NULL);
+
+		/* Only check that the operation is no more active */
+		if (!ADBG_EXPECT_TRUE(c, rv != CKR_BUFFER_TOO_SMALL))
+			rv = CKR_GENERAL_ERROR;
+	}
+
+out:
+	rv2 = C_DestroyObject(session, object);
+	ADBG_EXPECT_CK_OK(c, rv2);
+
+	if (rv)
+		return rv;
+	else
+		return rv2;
+}
+
+CK_KEY_ALLOWED_AES_ENC_TEST(cktest_aes_enc_only_cts, allowed_only_aes_cts);
+
+CK_KEY_ALLOWED_AES_DEC_TEST(cktest_aes_dec_only_ctr, allowed_only_aes_ctr);
+
+static void xtest_pkcs11_test_1005(ADBG_Case_t *c)
+{
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_SLOT_ID slot = 0;
+	CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
+	CK_FLAGS session_flags = CKF_SERIAL_SESSION;
+	size_t n = 0;
+
+	rv = init_lib_and_find_token_slot(&slot);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return;
+
+	rv = C_OpenSession(slot, session_flags, NULL, 0, &session);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	for (n = 0; n < ARRAY_SIZE(cktest_allowed_valid); n++) {
+
+		Do_ADBG_BeginSubCase(c, "valid usage #%zu", n);
+
+		rv = cipher_init_final(c, session,
+					cktest_allowed_valid[n].attr_key,
+					cktest_allowed_valid[n].attr_count,
+					cktest_allowed_valid[n].mechanism,
+					TEE_MODE_ENCRYPT,
+					CKR_OK);
+
+		ADBG_EXPECT_CK_OK(c, rv);
+
+		Do_ADBG_EndSubCase(c, NULL);
+		if (rv)
+			goto out;
+
+	}
+
+	for (n = 0; n < ARRAY_SIZE(cktest_allowed_invalid); n++) {
+		Do_ADBG_BeginSubCase(c, "invalid usage #%zu", n);
+
+		rv = cipher_init_final(c, session,
+					cktest_allowed_invalid[n].attr_key,
+					cktest_allowed_invalid[n].attr_count,
+					cktest_allowed_invalid[n].mechanism,
+					TEE_MODE_ENCRYPT,
+					CKR_KEY_FUNCTION_NOT_PERMITTED);
+
+		ADBG_EXPECT_CK_OK(c, rv);
+
+		Do_ADBG_EndSubCase(c, NULL);
+		if (rv)
+			goto out;
+
+	}
+
+out:
+	rv = C_CloseSession(session);
+	ADBG_EXPECT_CK_OK(c, rv);
+
+	rv = close_lib();
+	ADBG_EXPECT_CK_OK(c, rv);
+}
+
+
+ADBG_CASE_DEFINE(pkcs11, 1005, xtest_pkcs11_test_1005,
+		"PKCS11: Check ciphering with valid and invalid keys #1");
+
+static void xtest_pkcs11_test_1006(ADBG_Case_t *c)
+{
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_SLOT_ID slot = 0;
+	CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
+	CK_FLAGS session_flags = CKF_SERIAL_SESSION;
+
+	rv = init_lib_and_find_token_slot(&slot);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return;
+
+	rv = C_OpenSession(slot, session_flags, NULL, 0, &session);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	/* Encrypt only AES CTS key */
+	rv = cipher_init_final(c, session,
+				cktest_aes_enc_only_cts,
+				ARRAY_SIZE(cktest_aes_enc_only_cts),
+				&cktest_aes_cts_mechanism,
+				TEE_MODE_ENCRYPT,
+				CKR_OK);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	rv = cipher_init_final(c, session,
+				cktest_aes_enc_only_cts,
+				ARRAY_SIZE(cktest_aes_enc_only_cts),
+				&cktest_aes_cts_mechanism,
+				TEE_MODE_DECRYPT,
+				CKR_KEY_FUNCTION_NOT_PERMITTED);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	/* Decrypt only AES CTR key */
+	rv = cipher_init_final(c, session,
+				cktest_aes_dec_only_ctr,
+				ARRAY_SIZE(cktest_aes_dec_only_ctr),
+				&cktest_aes_ctr_mechanism,
+				TEE_MODE_ENCRYPT,
+				CKR_KEY_FUNCTION_NOT_PERMITTED);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	rv = cipher_init_final(c, session,
+				cktest_aes_dec_only_ctr,
+				ARRAY_SIZE(cktest_aes_dec_only_ctr),
+				&cktest_aes_ctr_mechanism,
+				TEE_MODE_ENCRYPT,
+				CKR_KEY_FUNCTION_NOT_PERMITTED);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+out:
+	rv = C_CloseSession(session);
+	ADBG_EXPECT_CK_OK(c, rv);
+
+	rv = close_lib();
+	ADBG_EXPECT_CK_OK(c, rv);
+}
+ADBG_CASE_DEFINE(pkcs11, 1006, xtest_pkcs11_test_1006,
+		"PKCS11: Check ciphering with valid and invalid keys #2");
+
+static CK_RV open_cipher_session(ADBG_Case_t *c,
+				 CK_SLOT_ID slot, CK_SESSION_HANDLE_PTR session,
+				 CK_ATTRIBUTE_PTR attr_key, CK_ULONG attr_count,
+				 CK_MECHANISM_PTR mechanism, uint32_t mode)
+{
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_OBJECT_HANDLE object = CK_INVALID_HANDLE;
+	CK_FLAGS session_flags = CKF_SERIAL_SESSION;
+
+	switch (mode) {
+	case TEE_MODE_ENCRYPT:
+	case TEE_MODE_DECRYPT:
+		break;
+	default:
+		ADBG_EXPECT_TRUE(c, false);
+		return CKR_GENERAL_ERROR;
+	}
+
+	rv = C_OpenSession(slot, session_flags, NULL, 0, session);
+	if (rv == CKR_DEVICE_MEMORY)
+		return rv;
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return rv;
+
+	rv = C_CreateObject(*session, attr_key, attr_count, &object);
+	if (rv == CKR_DEVICE_MEMORY)
+		return rv;
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return rv;
+
+	if (mode == TEE_MODE_ENCRYPT)
+		rv = C_EncryptInit(*session, mechanism, object);
+	if (mode == TEE_MODE_DECRYPT)
+		rv = C_DecryptInit(*session, mechanism, object);
+
+	if (rv == CKR_DEVICE_MEMORY)
+		return rv;
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return CKR_GENERAL_ERROR;
+
+	return rv;
+}
+
+static void xtest_pkcs11_test_1007(ADBG_Case_t *c)
+{
+	CK_RV rv = CKR_GENERAL_ERROR;
+	CK_SLOT_ID slot = 0;
+	CK_SESSION_HANDLE sessions[128];
+	size_t n = 0;
+
+	for (n = 0; n < ARRAY_SIZE(sessions); n++)
+		sessions[n] = CK_INVALID_HANDLE;
+
+	rv = init_lib_and_find_token_slot(&slot);
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		return;
+
+	for (n = 0; n < ARRAY_SIZE(sessions); n++) {
+
+		rv = open_cipher_session(c, slot, &sessions[n],
+					 cktest_allowed_valid[0].attr_key,
+					 cktest_allowed_valid[0].attr_count,
+					 cktest_allowed_valid[0].mechanism,
+					 TEE_MODE_ENCRYPT);
+
+		/* Failure due to memory allocation is not a error case */
+		if (rv == CKR_DEVICE_MEMORY)
+			break;
+
+		if (!ADBG_EXPECT_CK_OK(c, rv))
+			goto out;
+	}
+
+	if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, n, >, 0))
+		goto out;
+
+	Do_ADBG_Log("    created sessions count: %zu", n);
+
+	/* Closing session with out bound and invalid IDs (or negative ID) */
+	rv = C_CloseSession(sessions[n - 1] + 1024);
+	ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv);
+	rv = C_CloseSession(CK_INVALID_HANDLE);
+	ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv);
+	rv = C_CloseSession(~0);
+	ADBG_EXPECT_CK_RESULT(c, CKR_SESSION_HANDLE_INVALID, rv);
+
+	/* Closing each session: all related resources shall be free */
+	for (n = 0; n < ARRAY_SIZE(sessions); n++) {
+		if (sessions[n] == CK_INVALID_HANDLE)
+			continue;
+
+		rv = C_CloseSession(sessions[n]);
+		ADBG_EXPECT_CK_OK(c, rv);
+		sessions[n] = CK_INVALID_HANDLE;
+	}
+
+	/* Open and close another session */
+	rv = open_cipher_session(c, slot, &sessions[0],
+				 cktest_allowed_valid[0].attr_key,
+				 cktest_allowed_valid[0].attr_count,
+				 cktest_allowed_valid[0].mechanism,
+				 TEE_MODE_ENCRYPT);
+
+	if (!ADBG_EXPECT_CK_OK(c, rv))
+		goto out;
+
+	rv = C_CloseSession(sessions[0]);
+	ADBG_EXPECT_CK_OK(c, rv);
+	sessions[0] = CK_INVALID_HANDLE;
+
+out:
+	for (n = 0; n < ARRAY_SIZE(sessions); n++) {
+		if (sessions[n] == CK_INVALID_HANDLE)
+			continue;
+
+		rv = C_CloseSession(sessions[n]);
+		ADBG_EXPECT_CK_OK(c, rv);
+	}
+
+	rv = close_lib();
+	ADBG_EXPECT_CK_OK(c, rv);
+}
+ADBG_CASE_DEFINE(pkcs11, 1007, xtest_pkcs11_test_1007,
+		"PKCS11: Check operations release at session closure");