/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define TLOG_TAG "hwaes_unittest" #include #include #include #include #include #include #include #include #include #define AUX_PAGE_SIZE() getauxval(AT_PAGESZ) #if SIMULATION #define MAX_TRY_TIMES 3 #else #define MAX_TRY_TIMES 1000 #endif #define UNUSED_HWAES_ERROR_CODE HWAES_NO_ERROR #define HWAES_GCM_IV_SIZE 12 #if WITH_HWCRYPTO_UNITTEST #define DISABLED_WITHOUT_HWCRYPTO_UNITTEST(name) name #else #define DISABLED_WITHOUT_HWCRYPTO_UNITTEST(name) DISABLED_##name #endif /** * struct hwaes_iov - an wrapper of an array of iovec. * @iovs: array of iovec. * @num_iov: number of iovec. * @total_len: total length of the tipc message. */ struct hwaes_iov { struct iovec iov[TIPC_MAX_MSG_PARTS]; size_t num_iov; size_t total_len; }; /** * struct hwaes_shm - an wrapper of an array of shared memory handles. * @handles: array of shared memory handles. * @num_handles: number of shared memory handles. */ struct hwaes_shm { handle_t handles[HWAES_MAX_NUM_HANDLES]; size_t num_handles; }; struct test_vector { uint32_t mode; struct hwcrypt_arg_in key; struct hwcrypt_arg_in iv; struct hwcrypt_arg_in aad; struct hwcrypt_arg_in tag; struct hwcrypt_arg_in plaintext; struct hwcrypt_arg_in ciphertext; }; /* * Test vectors are from boringssl cipher_tests.txt which are in turn taken from * the GCM spec at * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf * * We are intentionally not testing non-standard IV lengths because we don't * support this (yet). */ /* AES 128 GCM */ static const uint8_t gcm_test1_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test1_iv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test1_plaintext[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test1_ciphertext[] = { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78}; static const uint8_t gcm_test1_aad[] = {}; static const uint8_t gcm_test1_tag[] = {0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf}; static const uint8_t gcm_test2_key[] = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08}; static const uint8_t gcm_test2_iv[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88}; static const uint8_t gcm_test2_plaintext[] = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55}; static const uint8_t gcm_test2_ciphertext[] = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85}; static const uint8_t gcm_test2_aad[] = {}; static const uint8_t gcm_test2_tag[] = {0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4}; static const uint8_t gcm_test3_key[] = {0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08}; static const uint8_t gcm_test3_iv[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88}; static const uint8_t gcm_test3_plaintext[] = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39}; static const uint8_t gcm_test3_ciphertext[] = { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91}; static const uint8_t gcm_test3_aad[] = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2}; static const uint8_t gcm_test3_tag[] = {0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47}; /* AES 256 GCM */ static const uint8_t gcm_test4_key[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test4_iv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test4_plaintext[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t gcm_test4_ciphertext[] = { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18}; static const uint8_t gcm_test4_aad[] = {}; static const uint8_t gcm_test4_tag[] = {0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19}; static const uint8_t gcm_test5_key[] = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08}; static const uint8_t gcm_test5_iv[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88}; static const uint8_t gcm_test5_plaintext[] = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55}; static const uint8_t gcm_test5_ciphertext[] = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad}; static const uint8_t gcm_test5_aad[] = {}; static const uint8_t gcm_test5_tag[] = {0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c}; static const uint8_t gcm_test6_key[] = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08}; static const uint8_t gcm_test6_iv[] = {0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88}; static const uint8_t gcm_test6_plaintext[] = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39}; static const uint8_t gcm_test6_ciphertext[] = { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62}; static const uint8_t gcm_test6_aad[] = { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2}; static const uint8_t gcm_test6_tag[] = {0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b}; /* clang-format off */ #define TV_DATA(name_, field_) \ .field_ = {.data_ptr = &name_##_##field_, .len = sizeof(name_##_##field_)} #define TV(mode_, name_) \ { \ .mode = mode_, \ TV_DATA(name_, key), \ TV_DATA(name_, iv), \ TV_DATA(name_, aad), \ TV_DATA(name_, tag), \ TV_DATA(name_, ciphertext), \ TV_DATA(name_, plaintext) \ } /* clang-format on */ static const struct test_vector vectors[] = { TV(HWAES_GCM_MODE, gcm_test1), TV(HWAES_GCM_MODE, gcm_test2), TV(HWAES_GCM_MODE, gcm_test3), TV(HWAES_GCM_MODE, gcm_test4), TV(HWAES_GCM_MODE, gcm_test5), TV(HWAES_GCM_MODE, gcm_test6), }; static void parse_vector(const struct test_vector* vector, struct hwcrypt_shm_hd* shm_handle, struct hwcrypt_args* args, int encrypt) { args->key_type = HWAES_PLAINTEXT_KEY; args->padding = HWAES_NO_PADDING; args->mode = vector->mode; args->key = vector->key; args->iv = vector->iv; args->aad = vector->aad; if (encrypt) { args->text_in = vector->plaintext; } else { args->text_in = vector->ciphertext; args->tag_in = vector->tag; } uint8_t* base = (uint8_t*)shm_handle->base; args->text_out.data_ptr = base; args->text_out.len = args->text_in.len; args->text_out.shm_hd_ptr = shm_handle; if (encrypt && vector->tag.len > 0) { args->tag_out.data_ptr = base + args->text_out.len; args->tag_out.len = vector->tag.len; args->tag_out.shm_hd_ptr = shm_handle; } } static const uint8_t hwaes_key[32]; static const uint8_t hwaes_iv[16]; static const uint8_t hwaes_cbc_plaintext[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t hwaes_cbc_ciphertext[] = { 0xdc, 0x95, 0xc0, 0x78, 0xa2, 0x40, 0x89, 0x89, 0xad, 0x48, 0xa2, 0x14, 0x92, 0x84, 0x20, 0x87, 0x08, 0xc3, 0x74, 0x84, 0x8c, 0x22, 0x82, 0x33, 0xc2, 0xb3, 0x4f, 0x33, 0x2b, 0xd2, 0xe9, 0xd3}; typedef struct hwaes { hwaes_session_t hwaes_session; handle_t memref; void* shm_base; size_t shm_len; struct hwcrypt_shm_hd shm_hd; struct hwcrypt_args args_encrypt; struct hwcrypt_args args_decrypt; struct hwaes_req req_hdr; struct hwaes_aes_req cmd_hdr; struct hwaes_shm_desc shm_descs[HWAES_MAX_NUM_HANDLES]; struct hwaes_iov req_iov; struct hwaes_shm req_shm; } hwaes_t; static void make_bad_request(handle_t channel, struct hwaes_iov* req_iov, struct hwaes_shm* req_shm, bool expect_reply, uint32_t expect_error) { struct uevent event; ipc_msg_info_t msg_inf; bool got_msg = false; ipc_msg_t req_msg = { .iov = req_iov->iov, .num_iov = req_iov->num_iov, .handles = req_shm->handles, .num_handles = req_shm->num_handles, }; int rc; rc = send_msg(channel, &req_msg); ASSERT_EQ((size_t)rc, req_iov->total_len); rc = wait(channel, &event, INFINITE_TIME); ASSERT_EQ(rc, NO_ERROR); if (expect_reply) { ASSERT_NE(event.event & IPC_HANDLE_POLL_MSG, 0); } else { ASSERT_EQ(event.event, IPC_HANDLE_POLL_HUP); return; } rc = get_msg(channel, &msg_inf); ASSERT_EQ(rc, NO_ERROR); got_msg = true; ASSERT_EQ(msg_inf.len, sizeof(struct hwaes_resp)); struct hwaes_resp resp_hdr = {0}; struct iovec resp_iov = { .iov_base = (void*)&resp_hdr, .iov_len = sizeof(resp_hdr), }; ipc_msg_t resp_msg = { .iov = &resp_iov, .num_iov = 1, .handles = NULL, .num_handles = 0, }; rc = read_msg(channel, msg_inf.id, 0, &resp_msg); ASSERT_EQ((size_t)rc, msg_inf.len); struct hwaes_req* req_hdr = (struct hwaes_req*)req_iov->iov[0].iov_base; ASSERT_EQ(resp_hdr.cmd, req_hdr->cmd | HWAES_RESP_BIT); put_msg(channel, msg_inf.id); EXPECT_EQ(expect_error, resp_hdr.result); return; test_abort: if (got_msg) { put_msg(channel, msg_inf.id); } return; } TEST_F_SETUP(hwaes) { int rc; void* shm_base; size_t shm_len = AUX_PAGE_SIZE(); _state->hwaes_session = INVALID_IPC_HANDLE; _state->memref = INVALID_IPC_HANDLE; _state->shm_base = NULL; rc = hwaes_open(&_state->hwaes_session); ASSERT_EQ(rc, 0); shm_base = memalign(AUX_PAGE_SIZE(), shm_len); ASSERT_NE(NULL, shm_base, "fail to allocate shared memory"); rc = memref_create(shm_base, shm_len, PROT_READ | PROT_WRITE); ASSERT_GE(rc, 0); _state->memref = (handle_t)rc; _state->shm_base = shm_base; _state->shm_len = shm_len; memset(_state->shm_base, 0, _state->shm_len); memcpy(_state->shm_base, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); _state->shm_hd = (struct hwcrypt_shm_hd){ .handle = _state->memref, .base = _state->shm_base, .size = _state->shm_len, }; _state->args_encrypt = (struct hwcrypt_args){ .key = { .data_ptr = hwaes_key, .len = sizeof(hwaes_key), }, .iv = { .data_ptr = hwaes_iv, .len = sizeof(hwaes_iv), }, .text_in = { .data_ptr = _state->shm_base, .len = sizeof(hwaes_cbc_plaintext), .shm_hd_ptr = &_state->shm_hd, }, .text_out = { .data_ptr = _state->shm_base, .len = sizeof(hwaes_cbc_ciphertext), .shm_hd_ptr = &_state->shm_hd, }, .key_type = HWAES_PLAINTEXT_KEY, .padding = HWAES_NO_PADDING, .mode = HWAES_CBC_MODE, }; _state->args_decrypt = (struct hwcrypt_args){ .key = { .data_ptr = hwaes_key, .len = sizeof(hwaes_key), }, .iv = { .data_ptr = hwaes_iv, .len = sizeof(hwaes_iv), }, .text_in = { .data_ptr = _state->shm_base, .len = sizeof(hwaes_cbc_ciphertext), .shm_hd_ptr = &_state->shm_hd, }, .text_out = { .data_ptr = _state->shm_base, .len = sizeof(hwaes_cbc_plaintext), .shm_hd_ptr = &_state->shm_hd, }, .key_type = HWAES_PLAINTEXT_KEY, .padding = HWAES_NO_PADDING, .mode = HWAES_CBC_MODE, }; _state->req_hdr = (struct hwaes_req){ .cmd = HWAES_AES, }; _state->cmd_hdr = (struct hwaes_aes_req){ .key = (struct hwaes_data_desc){ .len = sizeof(hwaes_key), .shm_idx = 0, }, .num_handles = 1, }; _state->shm_descs[0] = (struct hwaes_shm_desc){.size = _state->shm_len}; _state->req_iov = (struct hwaes_iov){ .iov = { {&_state->req_hdr, sizeof(_state->req_hdr)}, {&_state->cmd_hdr, sizeof(_state->cmd_hdr)}, {&_state->shm_descs, sizeof(struct hwaes_shm_desc)}, }, .num_iov = 3, .total_len = sizeof(_state->req_hdr) + sizeof(_state->cmd_hdr) + sizeof(struct hwaes_shm_desc), }; _state->req_shm = (struct hwaes_shm){ .handles = {_state->memref}, .num_handles = 1, }; test_abort:; } TEST_F_TEARDOWN(hwaes) { close(_state->hwaes_session); close(_state->memref); free(_state->shm_base); } TEST_F(hwaes, GenericInvalidSession) { hwaes_session_t invalid = INVALID_IPC_HANDLE; struct hwcrypt_args args = {}; // should fail immediately int rc = hwaes_encrypt(invalid, &args); EXPECT_EQ(ERR_BAD_HANDLE, rc, "generic - bad handle"); } TEST_F(hwaes, RequestHeaderReservedNotZero) { _state->req_hdr.reserved = 1U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, false, UNUSED_HWAES_ERROR_CODE); } TEST_F(hwaes, CommandUnsupported) { _state->req_hdr.cmd = 0U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_NOT_IMPLEMENTED); } TEST_F(hwaes, CommandHeaderReservedNotZero) { _state->cmd_hdr.reserved = 1U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, false, UNUSED_HWAES_ERROR_CODE); } TEST_F(hwaes, SharedMemoryHandlesNumberConflict) { _state->cmd_hdr.num_handles += 1; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, false, UNUSED_HWAES_ERROR_CODE); } TEST_F(hwaes, SharedMemoryDescriptorReservedNotZero) { _state->shm_descs[0].reserved = 1U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_IO); } TEST_F(hwaes, SharedMemoryDescriptorWrongWriteFlag) { _state->shm_descs[0].write = 2U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_IO); } TEST_F(hwaes, SharedMemoryDescriptorBadSize) { /* size is not page aligned */ _state->shm_descs[0].size = 4; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_INVALID_ARGS); } TEST_F(hwaes, DataDescriptorReservedNotZero) { _state->cmd_hdr.key.reserved = 1U; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_IO); } TEST_F(hwaes, DataDescriptorBadLength) { _state->cmd_hdr.key.len = _state->shm_len + 1ULL; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_INVALID_ARGS); } TEST_F(hwaes, DataDescriptorBadSharedMemoryHandleIndex) { _state->cmd_hdr.key.shm_idx = 4; make_bad_request(_state->hwaes_session, &_state->req_iov, &_state->req_shm, true, HWAES_ERR_IO); } TEST_F(hwaes, InvalidSharedMemoryHandle) { struct hwcrypt_shm_hd bad_shm_hd = { .handle = INVALID_IPC_HANDLE, .base = _state->shm_base, .size = _state->shm_len, }; _state->args_encrypt.text_in.shm_hd_ptr = &bad_shm_hd; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_BAD_HANDLE, rc, "expect bad handle error"); } TEST_F(hwaes, BadSharedMemorySize) { struct hwcrypt_shm_hd bad_shm_hd = { .handle = _state->memref, .base = _state->shm_base, .size = 0, }; _state->args_encrypt.text_in.shm_hd_ptr = &bad_shm_hd; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect bad length error"); } TEST_F(hwaes, KeyArgumentNotSetEncrypt) { _state->args_encrypt.key.len = 0; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, IVArgumentNotSetEncrypt) { _state->args_encrypt.iv.len = 0; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, TextInArgumentNotSetEncrypt) { _state->args_encrypt.text_in.len = 0; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, TextOutArgumentNotSetEncrypt) { _state->args_encrypt.text_out.len = 0; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, KeyArgumentNotSetDecrypt) { _state->args_decrypt.key.len = 0; int rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, IVArgumentNotSetDecrypt) { _state->args_decrypt.iv.len = 0; int rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, TextInArgumentNotSetDecrypt) { _state->args_decrypt.text_in.len = 0; int rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, TextOutArgumentNotSetDecrypt) { _state->args_decrypt.text_out.len = 0; int rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "expect invalid_args error"); } TEST_F(hwaes, EncryptionDecryptionCBC) { int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(NO_ERROR, rc, "encryption - cbc mode"); rc = memcmp(_state->shm_base, hwaes_cbc_ciphertext, sizeof(hwaes_cbc_ciphertext)); EXPECT_EQ(0, rc, "wrong encryption result"); rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(NO_ERROR, rc, "decryption - cbc mode"); rc = memcmp(_state->shm_base, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); EXPECT_EQ(0, rc, "wrong decryption result"); } TEST_F(hwaes, EncryptionDecryptionCBCNoSHM) { uint8_t buf[sizeof(hwaes_cbc_plaintext)] = {0}; memcpy(buf, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); _state->args_encrypt.text_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; _state->args_encrypt.text_out = (struct hwcrypt_arg_out){ .data_ptr = buf, .len = sizeof(buf), }; _state->args_decrypt.text_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; _state->args_decrypt.text_out = (struct hwcrypt_arg_out){ .data_ptr = buf, .len = sizeof(buf), }; int rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(NO_ERROR, rc, "encryption - cbc mode"); rc = memcmp(buf, hwaes_cbc_ciphertext, sizeof(hwaes_cbc_ciphertext)); EXPECT_EQ(0, rc, "wrong encryption result"); rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(NO_ERROR, rc, "decryption - cbc mode"); rc = memcmp(buf, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); EXPECT_EQ(0, rc, "wrong decryption result"); } TEST_F(hwaes, RunEncryptMany) { int rc; for (size_t i = 0; i < MAX_TRY_TIMES; i++) { rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); ASSERT_EQ(NO_ERROR, rc, "encryption - in loop"); } memcpy(_state->shm_base, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(NO_ERROR, rc, "encryption - final round"); rc = memcmp(_state->shm_base, hwaes_cbc_ciphertext, sizeof(hwaes_cbc_ciphertext)); EXPECT_EQ(0, rc, "wrong encryption result"); test_abort:; } TEST_F(hwaes, EncryptVectors) { const struct test_vector* vector = vectors; for (unsigned long i = 0; i < countof(vectors); ++i, ++vector) { memset(_state->shm_base, 0, _state->shm_len); struct hwcrypt_args args = {}; struct hwcrypt_shm_hd shm_hd = { .handle = _state->memref, .base = _state->shm_base, .size = _state->shm_len, }; parse_vector(vector, &shm_hd, &args, 1 /* encrypt */); int rc = hwaes_encrypt(_state->hwaes_session, &args); EXPECT_EQ(NO_ERROR, rc, "Encryption failed for test vector %lu\n", i); rc = memcmp(_state->shm_base, vector->ciphertext.data_ptr, vector->ciphertext.len); EXPECT_EQ(0, rc, "wrong ciphertext result"); if (vector->tag.len > 0) { rc = memcmp((uint8_t*)_state->shm_base + vector->ciphertext.len, vector->tag.data_ptr, vector->tag.len); EXPECT_EQ(0, rc, "wrong encryption tag result"); } } test_abort:; } TEST_F(hwaes, DecryptVectors) { const struct test_vector* vector = vectors; for (unsigned long i = 0; i < countof(vectors); ++i, ++vector) { memset(_state->shm_base, 0, _state->shm_len); struct hwcrypt_args args = {}; struct hwcrypt_shm_hd shm_hd = { .handle = _state->memref, .base = _state->shm_base, .size = _state->shm_len, }; parse_vector(vector, &shm_hd, &args, 0 /* decrypt */); int rc = hwaes_decrypt(_state->hwaes_session, &args); EXPECT_EQ(NO_ERROR, rc, "Decryption failed for test vector %lu\n", i); rc = memcmp(_state->shm_base, vector->plaintext.data_ptr, vector->plaintext.len); EXPECT_EQ(0, rc, "wrong decryption result"); } test_abort:; } TEST_F(hwaes, InvalidAEADArgsForCBC) { int rc; uint8_t buf[sizeof(hwaes_cbc_plaintext)] = {0}; _state->args_encrypt.aad = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported AAD"); _state->args_encrypt.aad = (struct hwcrypt_arg_in){}; _state->args_encrypt.tag_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported tag"); _state->args_encrypt.tag_in = (struct hwcrypt_arg_in){}; _state->args_encrypt.tag_out = (struct hwcrypt_arg_out){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported tag"); _state->args_decrypt.aad = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported AAD"); _state->args_decrypt.aad = (struct hwcrypt_arg_in){}; _state->args_decrypt.tag_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported tag"); _state->args_decrypt.tag_in = (struct hwcrypt_arg_in){}; _state->args_decrypt.tag_out = (struct hwcrypt_arg_out){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "unsupported tag"); } TEST_F(hwaes, InvalidGCMTagArgs) { int rc; uint8_t buf[16] = {0}; _state->args_encrypt.mode = HWAES_GCM_MODE; ASSERT_LE(HWAES_GCM_IV_SIZE, _state->args_encrypt.iv.len, "IV length too short"); _state->args_encrypt.iv.len = HWAES_GCM_IV_SIZE; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "missing tag output for GCM"); _state->args_encrypt.tag_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "wrong tag direction for encryption"); _state->args_decrypt.mode = HWAES_GCM_MODE; ASSERT_LE(HWAES_GCM_IV_SIZE, _state->args_decrypt.iv.len, "IV length too short"); _state->args_decrypt.iv.len = HWAES_GCM_IV_SIZE; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "missing tag input for GCM"); _state->args_decrypt.tag_in = (struct hwcrypt_arg_in){ .data_ptr = buf, .len = sizeof(buf), }; _state->args_decrypt.tag_out = (struct hwcrypt_arg_out){ .data_ptr = buf, .len = sizeof(buf), }; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "wrong tag direction for decryption"); test_abort:; } static const uint8_t opaque_key_ciphertext[] = { 0x8c, 0xc8, 0xc0, 0xc7, 0x76, 0x57, 0xb4, 0x4f, 0x22, 0xd3, 0x33, 0x2e, 0x6f, 0x23, 0x92, 0x51, 0x21, 0x69, 0x30, 0xff, 0x84, 0x88, 0x4c, 0x38, 0x04, 0xe5, 0x17, 0xad, 0x5c, 0x08, 0x87, 0xfc, }; #define HWKEY_OPAQUE_KEY_ID "com.android.trusty.hwaes.unittest.opaque_handle" TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(EncryptWithOpaqueKey)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE] = {0}; uint32_t key_handle_size = HWKEY_OPAQUE_HANDLE_MAX_SIZE; rc = hwkey_get_keyslot_data(hwkey_session, HWKEY_OPAQUE_KEY_ID, key_handle, &key_handle_size); EXPECT_EQ(NO_ERROR, rc, "Could not get opaque key handle"); EXPECT_LE(key_handle_size, HWKEY_OPAQUE_HANDLE_MAX_SIZE, "Wrong handle size"); _state->args_encrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_encrypt.key.data_ptr = key_handle; _state->args_encrypt.key.len = key_handle_size; _state->args_encrypt.key.shm_hd_ptr = NULL; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(NO_ERROR, rc, "opaque encryption - cbc mode"); rc = memcmp(_state->shm_base, opaque_key_ciphertext, sizeof(opaque_key_ciphertext)); EXPECT_EQ(0, rc, "wrong encryption result"); hwkey_close(hwkey_session); test_abort:; } TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(DecryptWithOpaqueKey)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE] = {0}; uint32_t key_handle_size = HWKEY_OPAQUE_HANDLE_MAX_SIZE; rc = hwkey_get_keyslot_data(hwkey_session, HWKEY_OPAQUE_KEY_ID, key_handle, &key_handle_size); EXPECT_EQ(NO_ERROR, rc, "Could not get opaque key handle"); EXPECT_LE(key_handle_size, HWKEY_OPAQUE_HANDLE_MAX_SIZE, "Wrong handle size"); _state->args_decrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_decrypt.key.data_ptr = key_handle; _state->args_decrypt.key.len = key_handle_size; _state->args_decrypt.key.shm_hd_ptr = NULL; memcpy(_state->shm_base, opaque_key_ciphertext, sizeof(opaque_key_ciphertext)); _state->args_decrypt.text_in.data_ptr = _state->shm_base; _state->args_decrypt.text_in.len = sizeof(opaque_key_ciphertext); _state->args_decrypt.text_in.shm_hd_ptr = &_state->shm_hd; rc = hwaes_decrypt(_state->hwaes_session, &_state->args_decrypt); EXPECT_EQ(NO_ERROR, rc, "opaque decryption - cbc mode"); rc = memcmp(_state->shm_base, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); EXPECT_EQ(0, rc, "wrong decryption result"); hwkey_close(hwkey_session); test_abort:; } TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(RunOpaqueEncryptMany)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE] = {0}; uint32_t key_handle_size = HWKEY_OPAQUE_HANDLE_MAX_SIZE; rc = hwkey_get_keyslot_data(hwkey_session, HWKEY_OPAQUE_KEY_ID, key_handle, &key_handle_size); EXPECT_EQ(NO_ERROR, rc, "Could not get opaque key handle"); EXPECT_LE(key_handle_size, HWKEY_OPAQUE_HANDLE_MAX_SIZE, "Wrong handle size"); _state->args_encrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_encrypt.key.data_ptr = key_handle; _state->args_encrypt.key.len = key_handle_size; _state->args_encrypt.key.shm_hd_ptr = NULL; for (size_t i = 0; i < MAX_TRY_TIMES; i++) { rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); ASSERT_EQ(NO_ERROR, rc, "encryption - in loop"); } memcpy(_state->shm_base, hwaes_cbc_plaintext, sizeof(hwaes_cbc_plaintext)); rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(NO_ERROR, rc, "encryption - final round"); rc = memcmp(_state->shm_base, opaque_key_ciphertext, sizeof(opaque_key_ciphertext)); EXPECT_EQ(0, rc, "wrong encryption result"); hwkey_close(hwkey_session); test_abort:; } TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(InvalidOpaqueKeySize)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE + 1] = {0}; _state->args_encrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_encrypt.key.data_ptr = key_handle; _state->args_encrypt.key.len = sizeof(key_handle); _state->args_encrypt.key.shm_hd_ptr = NULL; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "Did not error on invalid opaque key size"); hwkey_close(hwkey_session); test_abort:; } TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(InvalidOpaqueKeyTerminator)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE]; /* Non-null terminated handle */ memset(key_handle, 0xa, HWKEY_OPAQUE_HANDLE_MAX_SIZE); _state->args_encrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_encrypt.key.data_ptr = key_handle; _state->args_encrypt.key.len = sizeof(key_handle); _state->args_encrypt.key.shm_hd_ptr = NULL; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_INVALID_ARGS, rc, "Did not error on invalid opaque key"); hwkey_close(hwkey_session); test_abort:; } TEST_F(hwaes, DISABLED_WITHOUT_HWCRYPTO_UNITTEST(OutdatedOpaqueHandle)) { long rc = hwkey_open(); ASSERT_GE(rc, 0, "Could not connect to hwkey"); hwkey_session_t hwkey_session = (hwkey_session_t)rc; uint8_t key_handle[HWKEY_OPAQUE_HANDLE_MAX_SIZE] = {0}; uint32_t key_handle_size = HWKEY_OPAQUE_HANDLE_MAX_SIZE; rc = hwkey_get_keyslot_data(hwkey_session, HWKEY_OPAQUE_KEY_ID, key_handle, &key_handle_size); EXPECT_EQ(NO_ERROR, rc, "Could not get opaque key handle"); EXPECT_LE(key_handle_size, HWKEY_OPAQUE_HANDLE_MAX_SIZE, "Wrong handle size"); /* Close the session and invalidate the handle */ hwkey_close(hwkey_session); _state->args_encrypt.key_type = HWAES_OPAQUE_HANDLE; _state->args_encrypt.key.data_ptr = key_handle; _state->args_encrypt.key.len = key_handle_size; _state->args_encrypt.key.shm_hd_ptr = NULL; rc = hwaes_encrypt(_state->hwaes_session, &_state->args_encrypt); EXPECT_EQ(ERR_IO, rc, "Should not be able to fetch key for opaque handle"); test_abort:; } PORT_TEST(hwaes, "com.android.trusty.hwaes.test")