aboutsummaryrefslogtreecommitdiff
path: root/core/arch/arm32
diff options
context:
space:
mode:
authorSY Chiu <sy.chiu@linaro.org>2014-11-25 15:42:38 +0800
committerSY Chiu <sy.chiu@linaro.org>2015-01-23 18:11:33 +0800
commite022f121a55b503b4cd5cfb3b55f1e60c06a8d46 (patch)
tree16fd8e9578bb246be68a9382e88f8df3df46faa3 /core/arch/arm32
parentf362e777b904f28d3a8309f5304c812ef17f821f (diff)
SE API: Session, Protocol and Channel implementation
- Implement Session which maintains the connection between TA and a specific SE Reader - Implement ISO7816 transport layer protocol, and Channel management - Implement Utilities to handle AID(ISO7816-3) and APDU(ISO7816-4) - Brunch of self tests to velidate functionality of each module Signed-off-by: SY Chiu <sy.chiu@linaro.org> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> Reviewed-by: Joakim Bech <joakim.bech@linaro.org> Tested-by: SY Chiu <sy.chiu@linaro.org> (Modified QEMU + jcardsim)
Diffstat (limited to 'core/arch/arm32')
-rw-r--r--core/arch/arm32/kernel/tee_ta_manager.c1
-rw-r--r--core/arch/arm32/sta/se_api_self_tests.c360
2 files changed, 358 insertions, 3 deletions
diff --git a/core/arch/arm32/kernel/tee_ta_manager.c b/core/arch/arm32/kernel/tee_ta_manager.c
index 57d7663..1963bbc 100644
--- a/core/arch/arm32/kernel/tee_ta_manager.c
+++ b/core/arch/arm32/kernel/tee_ta_manager.c
@@ -620,6 +620,7 @@ static TEE_Result tee_ta_load(const kta_signed_header_t *signed_ta,
TAILQ_INIT(&ctx->open_sessions);
TAILQ_INIT(&ctx->cryp_states);
TAILQ_INIT(&ctx->objects);
+ TAILQ_INIT(&ctx->se_sessions);
TAILQ_INIT(&ctx->storage_enums);
ctx->head = sec_head;
diff --git a/core/arch/arm32/sta/se_api_self_tests.c b/core/arch/arm32/sta/se_api_self_tests.c
index e1d45fa..adb4d5e 100644
--- a/core/arch/arm32/sta/se_api_self_tests.c
+++ b/core/arch/arm32/sta/se_api_self_tests.c
@@ -33,6 +33,12 @@
#include <kernel/tee_common_unpg.h>
#include <tee/se/manager.h>
#include <tee/se/reader.h>
+#include <tee/se/session.h>
+#include <tee/se/protocol.h>
+#include <tee/se/aid.h>
+#include <tee/se/apdu.h>
+#include <tee/se/channel.h>
+#include <tee/se/util.h>
#include <stdlib.h>
#include <string.h>
@@ -93,11 +99,14 @@ static void close_session(void *pSessionContext __unused)
static TEE_Result test_reader(struct tee_se_reader_handle **handle)
{
TEE_Result ret;
- uint8_t cmd[] = { 0x0, 0x70 , 0x00, 0x00 };
+ uint8_t cmd[] = { ISO7816_CLA, MANAGE_CHANNEL_CMD,
+ OPEN_CHANNEL, OPEN_NEXT_AVAILABLE };
uint8_t resp[3];
size_t resp_size = sizeof(resp);
+ const int expected_channel_id = 1;
- /* transmit should failed since no one attached to the reader */
+ DMSG("entry");
+ /* transmit should fail since no one attached to the reader */
ret = tee_se_reader_transmit(handle[0], cmd, sizeof(cmd),
resp, &resp_size);
ASSERT(ret == TEE_ERROR_BAD_STATE);
@@ -114,13 +123,343 @@ static TEE_Result test_reader(struct tee_se_reader_handle **handle)
ret = tee_se_reader_transmit(handle[0], cmd, sizeof(cmd),
resp, &resp_size);
ASSERT(ret == TEE_SUCCESS);
- ASSERT(resp[0] == 0x1 && resp[1] == 0x90 && resp[2] == 0x0);
+ ASSERT(resp[0] == expected_channel_id &&
+ resp[1] == CMD_OK_SW1 && resp[2] == CMD_OK_SW2);
tee_se_reader_detach(handle[0]);
ASSERT(1 == tee_se_reader_get_refcnt(handle[0]));
tee_se_reader_detach(handle[0]);
+ DMSG("exit");
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result test_aid(struct tee_se_reader_handle **handles)
+{
+ struct tee_se_session *s = NULL;
+ struct tee_se_channel *b = NULL, *l = NULL;
+ struct tee_se_aid *aid = NULL;
+ TEE_Result ret;
+
+ DMSG("entry");
+ ret = aid_create("D0000CAFE00001", &aid);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_reader_open_session(NULL, handles[0], &s);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_session_open_basic_channel(s, aid, &b);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_session_open_logical_channel(s, aid, &l);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ASSERT(aid_get_refcnt(aid) == 3);
+
+ tee_se_session_close_channel(s, b);
+ tee_se_session_close_channel(s, l);
+
+ ASSERT(aid_get_refcnt(aid) == 1);
+
+ tee_se_reader_close_session(NULL, s);
+ aid_release(aid);
+ DMSG("exit");
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result test_session(struct tee_se_reader_handle **handles)
+{
+ struct tee_se_channel *c1 = NULL, *c2 = NULL;
+ struct tee_se_session *s1 = NULL, *s2 = NULL;
+ TEE_Result ret;
+
+ DMSG("entry");
+ ret = tee_se_reader_open_session(NULL, handles[0], &s1);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* should success, multiple sessions open by different user */
+ ret = tee_se_reader_open_session(NULL, handles[0], &s2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* open basic channel on s1 (should success) */
+ ret = tee_se_session_open_basic_channel(s1, NULL, &c1);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* open basic channel on s2
+ * (should fail, basic channel is locked by s1)
+ */
+ ret = tee_se_session_open_basic_channel(s2, NULL, &c2);
+ ASSERT(ret == TEE_ERROR_NOT_SUPPORTED);
+ ASSERT(c2 == NULL);
+
+ /* close basic channel on s1 */
+ tee_se_session_close_channel(s1, c1);
+ c1 = NULL;
+
+ /* open basic channel on s2 (this time should success) */
+ ret = tee_se_session_open_basic_channel(s1, NULL, &c2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* close basic channel on s2 */
+ tee_se_session_close_channel(s2, c2);
+ c2 = NULL;
+
+ /* open logical channel on s1 and s2 (both should success) */
+ ret = tee_se_session_open_logical_channel(s1, NULL, &c1);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = tee_se_session_open_logical_channel(s2, NULL, &c2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* clean up */
+ tee_se_session_close_channel(s1, c1);
+ tee_se_session_close_channel(s2, c2);
+
+ tee_se_reader_close_session(NULL, s1);
+ tee_se_reader_close_session(NULL, s2);
+ DMSG("exit");
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result test_select_resp(struct tee_se_reader_handle **handles)
+{
+ struct tee_se_aid *aid = NULL;
+ struct tee_se_session *s = NULL;
+ struct tee_se_channel *c = NULL;
+ struct resp_apdu *resp;
+ TEE_Result ret;
+
+ DMSG("entry");
+ ret = aid_create("D0000CAFE00001", &aid);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_reader_open_session(NULL, handles[0], &s);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_session_open_logical_channel(s, aid, &c);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_channel_get_select_response(c, &resp);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ASSERT((resp_apdu_get_sw1(resp) == CMD_OK_SW1) &&
+ (resp_apdu_get_sw2(resp) == CMD_OK_SW2));
+
+ /*
+ * the ownership of resp apdu should be the channel
+ * and it should be the only owner
+ */
+ ASSERT(apdu_get_refcnt(to_apdu_base(resp)) == 1);
+
+ /* increase the reference counter of resp apdu */
+ apdu_acquire(to_apdu_base(resp));
+
+ /* clean up */
+ tee_se_session_close_channel(s, c);
+
+ /* channel should release resp apdu when closed */
+ ASSERT(apdu_get_refcnt(to_apdu_base(resp)) == 1);
+ apdu_release(to_apdu_base(resp));
+
+ tee_se_reader_close_session(NULL, s);
+ aid_release(aid);
+ DMSG("exit");
+
+ return TEE_SUCCESS;
+}
+
+/*
+ * The JAVA Card Simulator (jcardsim.jar) built-in applet(s):
+ *
+ * AID |Type
+ * -------------------------------------+----------------------
+ * D0000CAFE00001 | MultiSelectable
+ * (default selected on basic channel) |
+ * -------------------------------------+----------------------
+ * D0000CAFE00002 | Non-MultiSelectable
+ * -------------------------------------+----------------------
+ *
+ */
+static TEE_Result test_logical_channel(struct tee_se_reader_handle **handles)
+{
+ struct tee_se_channel *channel[MAX_LOGICAL_CHANNEL] = { NULL };
+ struct tee_se_aid *aid = NULL;
+ struct tee_se_session *s = NULL;
+ TEE_Result ret;
+ int i;
+
+ DMSG("entry");
+ ret = tee_se_reader_open_session(NULL, handles[0], &s);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /*
+ * test open logical channels based on AID selected on basic channel
+ * (D0000CAFE00001 is default selected on basic channel,
+ * this call should success since D0000CAFE00001 is MultiSelectable,
+ * upon open, each logical channel should select D0000CAFE00001)
+ */
+ for (i = 1; i < MAX_LOGICAL_CHANNEL; i ++) {
+ ret = tee_se_session_open_logical_channel(s, NULL, &channel[i]);
+ ASSERT(ret == TEE_SUCCESS);
+ }
+
+ /*
+ * should fail on next open
+ * (exceeds maximum logical channel number)
+ */
+ ret = tee_se_session_open_logical_channel(s, NULL, &channel[0]);
+ ASSERT(ret == TEE_ERROR_NOT_SUPPORTED);
+
+ /* close 3 channels */
+ for (i = 1; i < 4; i++) {
+ tee_se_session_close_channel(s, channel[i]);
+ channel[i] = NULL;
+ }
+
+ /* re-open 3 channels (should success) */
+ for (i = 1; i < 4; i++) {
+ ret = tee_se_session_open_logical_channel(s, NULL, &channel[i]);
+ ASSERT(ret == TEE_SUCCESS);
+ }
+
+ /* logical channel 1 select D0000CAFE00002 (should success) */
+ aid_create("D0000CAFE00002", &aid);
+ ret = tee_se_channel_select(channel[1], aid);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* logical channel 2 select D0000CAFE00002
+ * (should fail since D0000CAFE00002 is not MultiSelectable)
+ */
+ ret = tee_se_channel_select(channel[2], aid);
+ ASSERT(ret == TEE_ERROR_NOT_SUPPORTED);
+
+ /* clean up */
+ for (i = 1; i < MAX_LOGICAL_CHANNEL; i++)
+ tee_se_session_close_channel(s, channel[i]);
+ tee_se_reader_close_session(NULL, s);
+ aid_release(aid);
+ DMSG("exit");
+
+ return TEE_SUCCESS;
+}
+
+static TEE_Result verify_result(struct resp_apdu *apdu, const char *data)
+{
+ size_t str_length = strlen(data);
+ size_t byte_length = strlen(data) / 2;
+ uint8_t *resp_data = resp_apdu_get_resp_data(apdu);
+ size_t resp_len = resp_apdu_get_resp_data_len(apdu);
+ uint8_t bytes[byte_length];
+ size_t i = 0;
+
+ ASSERT(resp_len == byte_length);
+
+ hex_decode(data, str_length, bytes);
+ while (i < resp_len) {
+ ASSERT(bytes[i] == resp_data[i]);
+ i++;
+ }
+ return TEE_SUCCESS;
+}
+
+static TEE_Result test_transmit(struct tee_se_reader_handle **handles)
+{
+ struct tee_se_channel *c1 = NULL, *c2 = NULL;
+ struct tee_se_session *s1 = NULL, *s2 = NULL;
+ struct tee_se_aid *full_aid = NULL, *partial_aid = NULL;
+ struct cmd_apdu *cmd;
+ struct resp_apdu *resp;
+ size_t tx_buf_len = 0, rx_buf_len = 7;
+ TEE_Result ret;
+
+ DMSG("entry");
+ ret = aid_create("D0000CAFE00001", &full_aid);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = aid_create("D0000CAFE0000", &partial_aid);
+ ASSERT(ret == TEE_SUCCESS);
+
+ cmd = alloc_cmd_apdu(ISO7816_CLA, 0xFF, 0x0, 0x0,
+ tx_buf_len, rx_buf_len, NULL);
+ ASSERT(cmd);
+ resp = alloc_resp_apdu(rx_buf_len);
+ ASSERT(resp);
+
+ ret = tee_se_reader_open_session(NULL, handles[0], &s1);
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_reader_open_session(NULL, handles[0], &s2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* open logical channel on s1 (given full aid) */
+ ret = tee_se_session_open_logical_channel(s1, full_aid, &c1);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* should route to D0000CAFE00001 */
+ ret = tee_se_channel_transmit(c1, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* select next should fail (full aid given) */
+ ret = tee_se_channel_select_next(c1);
+ ASSERT(ret == TEE_ERROR_ITEM_NOT_FOUND);
+
+ /* open logical channel on s2 (given partial aid) */
+ ret = tee_se_session_open_logical_channel(s2, partial_aid, &c2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* should route to D0000CAFE00001 */
+ ret = tee_se_channel_transmit(c2, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = verify_result(resp, "D0000CAFE00001");
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* select next should success (select D0000CAFE00002) */
+ ret = tee_se_channel_select_next(c2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* should route to D0000CAFE00002 */
+ ret = tee_se_channel_transmit(c2, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = verify_result(resp, "D0000CAFE00002");
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* select next should success (select D0000CAFE00001) */
+ ret = tee_se_channel_select_next(c2);
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* should route to D0000CAFE00001 */
+ ret = tee_se_channel_transmit(c2, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = verify_result(resp, "D0000CAFE00001");
+ ASSERT(ret == TEE_SUCCESS);
+
+ /*
+ * test route to the same applet in a row from different channel
+ * (both should success)
+ */
+ ret = tee_se_channel_transmit(c1, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = verify_result(resp, "D0000CAFE00001");
+ ASSERT(ret == TEE_SUCCESS);
+
+ ret = tee_se_channel_transmit(c2, cmd, resp);
+ ASSERT(ret == TEE_SUCCESS);
+ ret = verify_result(resp, "D0000CAFE00001");
+ ASSERT(ret == TEE_SUCCESS);
+
+ /* clean up */
+ tee_se_session_close_channel(s1, c1);
+ tee_se_session_close_channel(s2, c2);
+
+ tee_se_reader_close_session(NULL, s1);
+ tee_se_reader_close_session(NULL, s2);
+
+ aid_release(full_aid);
+ aid_release(partial_aid);
+ DMSG("exit");
return TEE_SUCCESS;
}
@@ -135,6 +474,21 @@ static TEE_Result se_api_self_tests(uint32_t nParamTypes __attribute__((__unused
tee_se_manager_get_readers(handles, &size);
+ ret = test_aid(handles);
+ CHECK(ret);
+
+ ret = test_select_resp(handles);
+ CHECK(ret);
+
+ ret = test_session(handles);
+ CHECK(ret);
+
+ ret = test_logical_channel(handles);
+ CHECK(ret);
+
+ ret = test_transmit(handles);
+ CHECK(ret);
+
ret = test_reader(handles);
CHECK(ret);