diff options
author | SY Chiu <sy.chiu@linaro.org> | 2014-11-25 15:42:38 +0800 |
---|---|---|
committer | SY Chiu <sy.chiu@linaro.org> | 2015-01-23 18:11:33 +0800 |
commit | e022f121a55b503b4cd5cfb3b55f1e60c06a8d46 (patch) | |
tree | 16fd8e9578bb246be68a9382e88f8df3df46faa3 /core/arch/arm32 | |
parent | f362e777b904f28d3a8309f5304c812ef17f821f (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.c | 1 | ||||
-rw-r--r-- | core/arch/arm32/sta/se_api_self_tests.c | 360 |
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); |