From: Jakub Wlostowski Date: Fri, 7 Feb 2025 12:05:21 +0000 (+0100) Subject: Add Security Keys backend implementation X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3b1e3868f6fc11622ba7c30ca38108886917349f;p=platform%2Fhal%2Fbackend%2Femulator%2Fsecurity-keys.git Add Security Keys backend implementation Change-Id: I689809900c8d83f87a47df0b2a54fdee3b36bc66 --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4c9145f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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. +# + +PROJECT(hal-backend-security-keys LANGUAGES C CXX) +CMAKE_MINIMUM_REQUIRED(VERSION 3.0) + +INCLUDE(GNUInstallDirs) +INCLUDE(CheckLibraryExists) + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "RELEASE") +ENDIF(NOT CMAKE_BUILD_TYPE) + +SET(CMAKE_C_FLAGS_DEBUG "-std=c11 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") +SET(CMAKE_CXX_FLAGS_DEBUG "-std=c++17 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE") +SET(CMAKE_C_FLAGS_RELEASE "-std=c11 -O2 -DNDEBUG") +SET(CMAKE_CXX_FLAGS_RELEASE "-std=c++17 -O2 -DNDEBUG") + +ADD_DEFINITIONS("-Werror -Wall -Wextra") + +SET(CMAKE_POSITION_INDEPENDENT_CODE "True") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") + +ADD_SUBDIRECTORY(src) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9f8d261 --- /dev/null +++ b/LICENSE @@ -0,0 +1,203 @@ +Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/packaging/hal-backend-security-keys.manifest b/packaging/hal-backend-security-keys.manifest new file mode 100644 index 0000000..50eefc9 --- /dev/null +++ b/packaging/hal-backend-security-keys.manifest @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/packaging/hal-backend-security-keys.spec b/packaging/hal-backend-security-keys.spec new file mode 100644 index 0000000..fb0d8b5 --- /dev/null +++ b/packaging/hal-backend-security-keys.spec @@ -0,0 +1,40 @@ +Name: hal-backend-security-keys +Summary: Security Keys (based on key-manager-ta and tef-simulator) backend library +Version: 1.0.0 +Release: 0 +Group: Security/Development +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +Source1001: hal-backend-security-keys.manifest +BuildRequires: cmake +BuildRequires: pkgconfig(hal-rootstrap) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +# FIXME +BuildRequires: key-manager-ta-devel +BuildRequires: key-manager-ta-serialization-devel +BuildRequires: pkgconfig(tef-libteec) +# Disable hal-rootstrap-checker in order to use key-manager-ta +%define disable_hal_rootstrap_checker 1 + +%description +Security Keys (based on key-manager-ta and tef-simulator) backend library + +%prep +%setup -q +cp -a %{SOURCE1001} . + +%build +%cmake . -DHAL_LIB_DIR=%{_hal_libdir} \ + -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:Release} +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%files +%manifest hal-backend-security-keys.manifest +%license LICENSE +%{_hal_libdir}/lib%{name}.so* diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..a0181f5 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved +# +# 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. +# + +PROJECT(hal-backend-security-keys LANGUAGES C CXX) +SET(PROJECT_VERSION "1.0.0") + +SET(_LIB_VERSION_ "${PROJECT_VERSION}") +SET(_LIB_SOVERSION_ "0") + +FIND_PACKAGE(PkgConfig REQUIRED) +PKG_CHECK_MODULES(ROOTSTRAP REQUIRED hal-rootstrap) + +INCLUDE_DIRECTORIES(SYSTEM ${ROOTSTRAP_INCLUDE_DIRS}) +LINK_DIRECTORIES(${ROOTSTRAP_LIBRARY_DIRS}) + +# FIXME +PKG_CHECK_MODULES(SECURITY_KEYS_DEPS REQUIRED tef-libteec) +INCLUDE_DIRECTORIES(SYSTEM ${SECURITY_KEYS_DEPS_INCLUDE_DIRS}) +LINK_DIRECTORIES(${SECURITY_KEYS_DEPS_LIBRARY_DIRS}) +SET(KM_LINK_EXTRA_DEPS km_serialization) + +ADD_LIBRARY(${PROJECT_NAME} SHARED + hal-backend-security-keys-api.cpp + tz-memory.cpp + tz-serializer.cpp + log.cpp) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${ROOTSTRAP_LIBRARIES} -ldlog + ${SECURITY_KEYS_DEPS_LIBRARIES} ${KM_LINK_EXTRA_DEPS}) + +SET_TARGET_PROPERTIES(${PROJECT_NAME} + PROPERTIES + VERSION ${_LIB_VERSION_} + SOVERSION ${_LIB_SOVERSION_} + VISIBILITY_INLINES_HIDDEN TRUE + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${HAL_LIB_DIR} COMPONENT RuntimeLibraries) diff --git a/src/crypto-params.h b/src/crypto-params.h new file mode 100644 index 0000000..4dcee71 --- /dev/null +++ b/src/crypto-params.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma once + +#include +#include + +class Params +{ +public: + static const uint32_t DEFAULT_AES_IV_LEN = 16; // max acceptable size of IV + static const int DEFAULT_AES_GCM_TAG_LEN_BYTES = 16; // length of AES GCM tag + static const int DEFAULT_AES_GCM_TAG_LEN_BITS = DEFAULT_AES_GCM_TAG_LEN_BYTES * 8; + static const int DERIVED_KEY_LENGTH = 16; // length of AES key derived from password in bytes + static const int DERIVED_KEY_LENGTH_BITS = DERIVED_KEY_LENGTH * 8; // as above, in bits + static const int DERIVED_KEY_ITERATIONS = 1024; // iteration count used to derive key + static const uint32_t CIPHER_EXTRA_PADDING_SIZE = 16; //extra memory to add to output buffers for padding purposes +}; \ No newline at end of file diff --git a/src/hal-backend-security-keys-api.cpp b/src/hal-backend-security-keys-api.cpp new file mode 100644 index 0000000..6de8b51 --- /dev/null +++ b/src/hal-backend-security-keys-api.cpp @@ -0,0 +1,1845 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "crypto-params.h" +#include "log.h" +#include "tz-memory.h" +#include "tz-serializer.h" + +#define EXPORT __attribute__ ((visibility("default"))) + +namespace { + +// Identifier of our key-manager TA +const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID; + +tz_algo_type to_tz_algo_type(hal_security_keys_algo_type_e type) +{ + switch (type) { + case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CTR: return ALGO_AES_CTR; + case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CBC: return ALGO_AES_CBC; + case HAL_SECURITY_KEYS_ALGO_TYPE_AES_GCM: return ALGO_AES_GCM; + case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CFB: return ALGO_AES_CFB; + case HAL_SECURITY_KEYS_ALGO_TYPE_RSA_OAEP: return ALGO_RSA; + case HAL_SECURITY_KEYS_ALGO_TYPE_RSA: return ALGO_RSA_SV; + case HAL_SECURITY_KEYS_ALGO_TYPE_DSA: return ALGO_DSA_SV; + case HAL_SECURITY_KEYS_ALGO_TYPE_ECDSA: return ALGO_ECDSA_SV; + default: + throw std::invalid_argument("Requested algorithm is not supported"); + } +} + +tz_ec to_tz_ec_type(hal_security_keys_ec_type_e ec) +{ + switch (ec) { + case HAL_SECURITY_KEYS_EC_TYPE_PRIME192V1: return EC_NIST_P192; + case HAL_SECURITY_KEYS_EC_TYPE_PRIME256V1: return EC_NIST_P256; + case HAL_SECURITY_KEYS_EC_TYPE_SECP384R1: return EC_NIST_P384; + default: + throw std::invalid_argument("EC not supported by tz-backend"); + } +} + +tz_kem to_tz_kem_type(hal_security_keys_kem_type_e kem) +{ + switch (kem) { + case HAL_SECURITY_KEYS_ML_KEM_768: return ML_KEM_768; + case HAL_SECURITY_KEYS_ML_KEM_1024: return ML_KEM_1024; + default: + throw std::invalid_argument("KEM not supported by tz-backend"); + } +} + +tz_data_type to_tz_data_type(hal_security_keys_data_type_e type) +{ + switch (type) { + case HAL_SECURITY_KEYS_DATA_TYPE_BINARY_DATA: return TYPE_GENERIC_SECRET; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_AES: return TYPE_SKEY; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_RSA_PUBLIC: return TYPE_AKEY_PUBLIC_RSA; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_RSA_PRIVATE: return TYPE_AKEY_PRIVATE_RSA; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_DSA_PUBLIC: return TYPE_AKEY_PUBLIC_DSA; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_DSA_PRIVATE: return TYPE_AKEY_PRIVATE_DSA; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_ECDSA_PUBLIC: return TYPE_AKEY_PUBLIC_EC; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_ECDSA_PRIVATE: return TYPE_AKEY_PRIVATE_EC; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_KEM_PUBLIC: return TYPE_AKEY_PUBLIC_KEM; + case HAL_SECURITY_KEYS_DATA_TYPE_KEY_KEM_PRIVATE: return TYPE_AKEY_PRIVATE_KEM; + default: + throw std::invalid_argument("Data type not supported by tz-backend"); + } +} + +tz_hash_type to_tz_hash_type(hal_security_keys_hash_algorithm_e hash) +{ + switch (hash) { + case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA1: return HASH_SHA1; + case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA256: return HASH_SHA256; + case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA384: return HASH_SHA384; + case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA512: return HASH_SHA512; + default: + throw std::invalid_argument("Requested hash algorithm is not supported"); + } +} + +tz_prf to_tz_prf(hal_security_keys_kdf_prf_type_e prf) +{ + switch (prf) { + case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA256: return PRF_HMAC_SHA256; + case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA384: return PRF_HMAC_SHA384; + case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA512: return PRF_HMAC_SHA512; + default: + throw std::invalid_argument("PRF not supported by tz-backend"); + } +} + +tz_kbkdf_mode to_tz_kbkdf_mode(hal_security_keys_kbkdf_mode_e mode) +{ + switch (mode) { + case HAL_SECURITY_KEYS_KBKDF_MODE_COUNTER: return KBKDF_MODE_COUNTER; + default: + throw std::invalid_argument("KBKDF mode not supported by tz-backend"); + } +} + +tz_kbkdf_ctr_loc to_tz_kbkdf_ctr_loc(hal_security_keys_kbkdf_counter_location_e loc) +{ + switch (loc) { + case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_BEFORE_FIXED: return KBKDF_LOC_BEFORE_FIXED; + case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_AFTER_FIXED: return KBKDF_LOC_AFTER_FIXED; + case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_MIDDLE_FIXED: return KBKDF_LOC_MIDDLE_FIXED; + default: + throw std::invalid_argument("KBKDF counter location not supported by tz-backend"); + } +} + +//Maximum size for given key type in bytes according to key-manager-ta implementation. +//Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values. +size_t get_tz_max_key_size(tz_algo_type type) +{ + switch (type) { + case ALGO_RSA: + case ALGO_RSA_SV: + case ALGO_DSA_SV: + return 4096 / 8; + case ALGO_ECDSA_SV: + return 1024 / 8; // 384*2 + additional space for DER encoding + default: + throw std::invalid_argument("Algorithm not supported by tz-backend"); + } +} + +template +T hex_dump(const hal_security_keys_data_s &raw) +{ + T dump; + + if (!raw.buffer) + return dump; + + dump.reserve(2 * raw.length); + constexpr char digit[2][16] = {{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }, { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' + }}; + + for (size_t i = 0; i < raw.length; ++i) { + dump.push_back(digit[uppercase][raw.buffer[i] / 16]); + dump.push_back(digit[uppercase][raw.buffer[i] % 16]); + } + + return dump; +} + +static std::string raw_to_hex_string(const hal_security_keys_data_s &raw) +{ + return hex_dump(raw); +} + +int try_catch(const std::function &func) +{ + try { + return func(); + } catch (const std::invalid_argument &e) { + LOGE("Invalid parameter: " << e.what()); + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + } catch (const std::bad_alloc &e) { + LOGE("Memory allocation exception: " << e.what()); + return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY; + } catch (const std::exception &e) { + LOGE("Exception occurred: " << e.what()); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } catch (...) { + LOGE("Unknown exception occurred."); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } +} + +#define EXCEPTION_GUARD_START return try_catch([&]()->int { +#define EXCEPTION_GUARD_END }); + +#define CHECK_RET(func) do { int ret = (func); if (ret) return ret; } while (0) + +template +void push(TZSerializer& ser, const T& value) +{ + ser.Push(new TZSerializableFlag(static_cast(value))); +} + +template<> +void push(TZSerializer& ser, const hal_security_keys_data_s& value) +{ + ser.Push(new TZSerializableBinary(value)); +} + +template<> +void push(TZSerializer& ser, const hal_security_keys_password_iv_s& value) +{ + int32_t with_pwd = !value.password.buffer ? 0 : 1; + ser.Push(new TZSerializableFlag(with_pwd)); + if (with_pwd) + ser.Push(new TZSerializablePwdData(value.password, value.iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); +} + +template<> +void push(TZSerializer& ser, const hal_security_keys_password_iv_tag_s& value) +{ + int32_t with_pwd = !value.password.buffer ? 0 : 1; + ser.Push(new TZSerializableFlag(with_pwd)); + if (with_pwd) + ser.Push(new TZSerializablePwdData(value.password, + value.iv, + value.tag.length * 8, + value.tag)); +} + +template +void push(TZSerializer& ser, const T& first, const Args&... args) +{ + push(ser, first); + push(ser, args...); +} + +template +TZSerializer makeSerializer(const Args&... args) +{ + TZSerializer ser; + push(ser, args...); + return ser; +} + +TEEC_Operation make_op(uint32_t value, TrustZoneMemory& mem1) +{ + TEEC_Operation op; + + op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_NONE, TEEC_NONE); + + op.params[1].memref.parent = mem1.Get(); + op.params[1].memref.offset = 0; + op.params[1].memref.size = mem1.Get()->size; + return op; +} + +TEEC_Operation make_op(uint32_t value, TrustZoneMemory& mem1, TrustZoneMemory& mem2) +{ + TEEC_Operation op = make_op(value, mem1); + + op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_MEMREF_WHOLE, TEEC_NONE); + + op.params[2].memref.parent = mem2.Get(); + op.params[2].memref.offset = 0; + op.params[2].memref.size = mem2.Get()->size; + + return op; +} + +int execute(tz_command command_id, TEEC_Operation* op, TEEC_Session tz_session) +{ + uint32_t ret = 0; + LOGD("Executing TZ operation " << command_id); + + TEEC_Result result = TEEC_InvokeCommand(&tz_session, static_cast(command_id), op, &ret); + if (result != TEEC_SUCCESS) { + switch (result) { + case TEEC_ERROR_TARGET_DEAD: + LOGE("TA panicked while executing command " << static_cast(command_id)); + return HAL_SECURITY_KEYS_ERROR_TARGET_DEAD; + case TEEC_ERROR_BAD_PARAMETERS: + LOGE("Incorrect parameters provided to TA"); + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + default: + LOGE("TA failed to invoke command " << + static_cast(command_id) << " with error: " << std::hex << + static_cast(result) << " with origin: " << std::hex << ret); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + } + + int ta_ret = op->params[0].value.a; + switch (ta_ret) { + case KM_TA_SUCCESS: + case KM_TA_ERROR_SIGNATURE: + return HAL_SECURITY_KEYS_ERROR_NONE; + case KM_TA_ERROR_AUTH_FAILED: + LOGE("Crypto operation authentication failed"); + return HAL_SECURITY_KEYS_ERROR_AUTHENTICATION_FAILED; + default: + LOGE("Unknown TA error during operation: " << ta_ret); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } +} + +} // anonymous namespace + +int security_keys_context_initialize(hal_security_keys_context_s* context) +{ + EXCEPTION_GUARD_START + LOGD("security_keys_context_initialize"); + + if (!context) + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + + TEEC_Context* tz_context = new TEEC_Context; + TEEC_Session* tz_session = new TEEC_Session; + if (!tz_context || !tz_session) + return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY; + + TEEC_Operation op; + TEEC_Result result; + uint32_t ret; + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); + + result = TEEC_InitializeContext(nullptr, tz_context); + if (result != TEEC_SUCCESS) { + LOGE("Failed to initialize context: " << result); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + context->ctx = (void *)tz_context; + + result = TEEC_OpenSession(tz_context, tz_session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &ret); + if (result != TEEC_SUCCESS) { + LOGE("Failed to open session to Key Manager TA: " << result); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + context->session = (void *)tz_session; + + LOGD("Initialized context"); + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_context_free(hal_security_keys_context_s* context) +{ + EXCEPTION_GUARD_START + LOGD("security_keys_context_free"); + + if (!context) + return 0; + + if (context->session) { + TEEC_Session* tz_session = static_cast(context->session); + TEEC_CloseSession(tz_session); + delete static_cast(context->session); + context->session = nullptr; + } + + if (context->ctx) { + TEEC_Context* tz_context = static_cast(context->ctx); + TEEC_FinalizeContext(tz_context); + delete static_cast(context->ctx); + context->ctx = nullptr; + } + + LOGD("Destroyed context"); + + return 0; + EXCEPTION_GUARD_END +} + +int security_keys_create_iv(const hal_security_keys_context_s context, + hal_security_keys_data_s* iv) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GENERATE_IV + LOGD("security_keys_create_iv"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + TrustZoneMemory iv_memory(*tz_context, Params::DEFAULT_AES_IV_LEN, TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, iv_memory); + + CHECK_RET(execute(CMD_GENERATE_IV, &op, *tz_session)); + + iv->buffer = (unsigned char*)malloc(iv_memory.Get()->size); + if (!(iv->buffer)) { + LOGE("Failed to allocate memory for IV"); + return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY; + } + + memcpy(iv->buffer, iv_memory.Get()->buffer, iv_memory.Get()->size); + iv->length = iv_memory.Get()->size; + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_create_key_aes(const hal_security_keys_context_s context, + const size_t key_size_bits, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_s key_pwd, + hal_security_keys_data_s* key_tag) +{ + EXCEPTION_GUARD_START + LOGD("security_keys_create_key_aes"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + bool with_pwd = !key_pwd.password.buffer ? 0 : 1; + if (with_pwd) { + // command ID = CMD_GENERATE_KEY_PWD + TZSerializer s_in; + s_in.Push(new TZSerializablePwdData(key_pwd.password, key_pwd.iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS)); + s_in.Push(new TZSerializableBinary(key_id)); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_AES_GEN; + op.params[0].value.b = key_size_bits; + + CHECK_RET(execute(CMD_GENERATE_KEY_PWD, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(key_tag); + + if (key_tag->length != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) { + LOGE("Deserialized incorrect key tag"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + return 0; + } else { + // command ID = CMD_GENERATE_KEY + TZSerializer s_in; + s_in.Push(new TZSerializableBinary(key_id)); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + op.params[0].value.a = ALGO_AES_GEN; + op.params[0].value.b = key_size_bits; + + return execute(CMD_GENERATE_KEY, &op, *tz_session); + } + + EXCEPTION_GUARD_END +} + +int create_asym_key_pair(const hal_security_keys_context_s context, + tz_command command_id, + TZSerializer &s_in, + uint32_t gen_param, // key size in bits or type + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_s priv_key_pwd, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_s pub_key_pwd, + hal_security_keys_data_s* priv_key_tag, + hal_security_keys_data_s* pub_key_tag) +{ + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + bool with_pub_pwd = !pub_key_pwd.password.buffer ? 0 : 1; + TZSerializer s_out; + if (with_pub_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + bool with_priv_pwd = !priv_key_pwd.password.buffer ? 0 : 1; + if (with_priv_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + push(s_in, pub_key_pwd, priv_key_pwd, priv_key_id, pub_key_id); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op; + if (s_out.GetSize() == 0) + op = make_op(TEEC_VALUE_INOUT, in_memory); + else + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + op.params[0].value.b = gen_param; + + CHECK_RET(execute(command_id, &op, *tz_session)); + + s_out.Deserialize(out_memory); + if (with_pub_pwd) + s_out.Pull(pub_key_tag); + + if (with_priv_pwd) + s_out.Pull(priv_key_tag); + + return 0; +} + +int security_keys_create_key_pair_rsa(const hal_security_keys_context_s context, + const size_t key_size_bits, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_s priv_key_pwd, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_s pub_key_pwd, + hal_security_keys_data_s* priv_key_tag, + hal_security_keys_data_s* pub_key_tag) + +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GENERATE_RSA_KEYPAIR + LOGD("security_keys_create_key_pair_rsa"); + + TZSerializer s_in; + return create_asym_key_pair(context, CMD_GENERATE_RSA_KEYPAIR, + s_in, key_size_bits, + priv_key_id, priv_key_pwd, + pub_key_id, pub_key_pwd, + priv_key_tag, pub_key_tag); + + EXCEPTION_GUARD_END +} + +int security_keys_create_key_pair_dsa(const hal_security_keys_context_s context, + const size_t key_size_bits, + const hal_security_keys_data_s prime, + const hal_security_keys_data_s subprime, + const hal_security_keys_data_s base, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_s priv_key_pwd, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_s pub_key_pwd, + hal_security_keys_data_s* priv_key_tag, + hal_security_keys_data_s* pub_key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GENERATE_DSA_KEYPAIR + LOGD("security_keys_create_key_pair_dsa"); + + auto s_in = makeSerializer(prime, subprime, base); + return create_asym_key_pair(context, CMD_GENERATE_DSA_KEYPAIR, + s_in, key_size_bits, + priv_key_id, priv_key_pwd, + pub_key_id, pub_key_pwd, + priv_key_tag, pub_key_tag); + + EXCEPTION_GUARD_END +} + +int security_keys_create_key_pair_ecdsa(const hal_security_keys_context_s context, + const hal_security_keys_ec_type_e ec_type, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_s priv_key_pwd, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_s pub_key_pwd, + hal_security_keys_data_s* priv_key_tag, + hal_security_keys_data_s* pub_key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GENERATE_EC_KEYPAIR + LOGD("security_keys_create_key_pair_ecdsa"); + + auto tz_ec_type = to_tz_ec_type(ec_type); + + TZSerializer s_in; + return create_asym_key_pair(context, CMD_GENERATE_EC_KEYPAIR, + s_in, tz_ec_type, + priv_key_id, priv_key_pwd, + pub_key_id, pub_key_pwd, + priv_key_tag, pub_key_tag); + + EXCEPTION_GUARD_END +} + +int security_keys_create_key_pair_kem(const hal_security_keys_context_s context, + const hal_security_keys_kem_type_e kem_type, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_s priv_key_pwd, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_s pub_key_pwd, + hal_security_keys_data_s* priv_key_tag, + hal_security_keys_data_s* pub_key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GENERATE_KEM_KEYPAIR + LOGD("security_keys_create_key_pair_kem"); + + auto tz_kem_type = to_tz_kem_type(kem_type); + + TZSerializer s_in; + return create_asym_key_pair(context, CMD_GENERATE_KEM_KEYPAIR, + s_in, tz_kem_type, + priv_key_id, priv_key_pwd, + pub_key_id, pub_key_pwd, + priv_key_tag, pub_key_tag); + + EXCEPTION_GUARD_END +} + +int security_keys_import_wrapped_key(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s iv, + const hal_security_keys_data_s aad, + const size_t ctr_len_or_tag_size_bits, + const hal_security_keys_data_s wrapping_key_id, + const hal_security_keys_password_iv_tag_s wrapping_key_pwd, + const hal_security_keys_data_s wrapped_key, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_s key_pwd, + const hal_security_keys_data_type_e key_type, + hal_security_keys_data_s* key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_IMPORT_WRAPPED_KEY + LOGD("security_keys_import_wrapped_key wrapped_key size = [" << wrapped_key.length << "]"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + auto tz_key_type = to_tz_data_type(key_type); + + TZSerializer s_in; + if (tz_algo_type == ALGO_RSA) { + s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, tz_hash_type, tz_key_type, + wrapped_key, key_pwd, key_id); + } else { + s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, iv, ctr_len_or_tag_size_bits, + aad, tz_key_type, wrapped_key, key_pwd, key_id); + } + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !key_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + CHECK_RET(execute(CMD_IMPORT_WRAPPED_KEY, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(key_tag); + } + + LOGD("Imported object ID is (hex): " << raw_to_hex_string(key_id)); + + return 0; + + EXCEPTION_GUARD_END +} + +void get_data_size(const hal_security_keys_context_s context, + const hal_security_keys_data_s data_id, + const hal_security_keys_password_iv_tag_s pwd, + const tz_data_type type, + uint32_t &data_size) +{ + // command ID = CMD_GET_DATA_SIZE + LOGD("get_data_size"); + LOGD("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << raw_to_hex_string(data_id)); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data_id, pwd, type); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory); + + execute(CMD_GET_DATA_SIZE, &op, *tz_session); + data_size = op.params[0].value.b; +} + +int security_keys_export_wrapped_key(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s iv, + const hal_security_keys_data_s aad, + const size_t ctr_len_or_tag_size_bits, + const hal_security_keys_data_s wrapping_key_id, + const hal_security_keys_password_iv_tag_s wrapping_key_pwd, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_type_e key_type, + hal_security_keys_data_s* wrapped_key) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_EXPORT_WRAPPED_KEY + LOGD("security_keys_export_wrapped_key"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + auto tz_key_type = to_tz_data_type(key_type); + + TZSerializer s_in; + if (tz_algo_type == ALGO_RSA) { + s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, tz_hash_type, + key_id, key_pwd, tz_key_type); + } else { + s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, iv, ctr_len_or_tag_size_bits, + aad, key_id, key_pwd, tz_key_type); + } + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + uint32_t data_size = 0; + get_data_size(context, key_id, key_pwd, tz_key_type, data_size); + LOGD("get_data_size = [" << data_size << "]"); + + uint32_t enc_overhead = KM_ENCRYPTION_OVERHEAD; + if (tz_algo_type == ALGO_RSA) + enc_overhead = KM_RSA_BLOCK_SIZE; + + // encrypted data may be longer + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(data_size + enc_overhead, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + s_out.Serialize(out_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + CHECK_RET(execute(CMD_EXPORT_WRAPPED_KEY, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(wrapped_key); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_encapsulate_key(const hal_security_keys_context_s context, + const hal_security_keys_kem_type_e kem_type, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_tag_s pub_key_pwd, + const hal_security_keys_data_s shared_secret_id, + const hal_security_keys_password_iv_s shared_secret_pwd, + hal_security_keys_data_s* ciphertext, + hal_security_keys_data_s* shared_secret_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_ENCAPSULATE_KEY + LOGD("security_keys_encapsulate_key"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_kem_type = to_tz_kem_type(kem_type); + + TZSerializer s_in = makeSerializer(pub_key_id, pub_key_pwd, + shared_secret_pwd, shared_secret_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + uint32_t out_memory_size = 0; + switch (tz_kem_type) { + case ML_KEM_768: + out_memory_size = 1088; + break; + case ML_KEM_1024: + out_memory_size = 1568; + break; + default: + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + } + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + + bool with_pwd = !shared_secret_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = tz_kem_type; + + CHECK_RET(execute(CMD_ENCAPSULATE_KEY, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(ciphertext); + if (with_pwd) + s_out.Pull(shared_secret_tag); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_decapsulate_key(const hal_security_keys_context_s context, + const hal_security_keys_kem_type_e kem_type, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_tag_s priv_key_pwd, + const hal_security_keys_data_s shared_secret_id, + const hal_security_keys_password_iv_s shared_secret_pwd, + const hal_security_keys_data_s ciphertext, + hal_security_keys_data_s* shared_secret_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DECAPSULATE_KEY + LOGD("security_keys_decapsulate_key"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_kem_type = to_tz_kem_type(kem_type); + + TZSerializer s_in = makeSerializer(priv_key_id, priv_key_pwd, + shared_secret_pwd, shared_secret_id, ciphertext); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !shared_secret_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + op.params[0].value.a = tz_kem_type; + + CHECK_RET(execute(CMD_DECAPSULATE_KEY, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(shared_secret_tag); + } + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_destroy_key(const hal_security_keys_context_s context, + const hal_security_keys_data_s key_id) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DESTROY_KEY + LOGD("security_keys_destroy_key"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(key_id); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory); + + return execute(CMD_DESTROY_KEY, &op, *tz_session); + + EXCEPTION_GUARD_END +} + +int security_keys_import_data(const hal_security_keys_context_s context, + const hal_security_keys_data_s data_id, + const hal_security_keys_password_iv_s data_pwd, + const hal_security_keys_data_type_e data_type, + const hal_security_keys_data_s data, + const hal_security_keys_data_s data_encryption_iv, + const hal_security_keys_data_s data_encryption_tag, + hal_security_keys_data_s* data_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_IMPORT_DATA + LOGD("security_keys_import_data data size = [" << data.length << "]"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_data_type = to_tz_data_type(data_type); + + uint32_t data_size_bits = data.length * 8; + auto s_in = makeSerializer(tz_data_type, data, data_size_bits, data_encryption_iv, data_encryption_tag, + data_pwd, data_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !data_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + CHECK_RET(execute(CMD_IMPORT_DATA, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(data_tag); + } + + LOGD("Imported object ID is (hex): " << raw_to_hex_string(data_id)); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_export_data(const hal_security_keys_context_s context, + const hal_security_keys_data_s data_id, + const hal_security_keys_password_iv_tag_s data_pwd, + const hal_security_keys_data_type_e data_type, + hal_security_keys_data_s* data) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GET_DATA + LOGD("security_keys_export_data"); + LOGD("Object ID (passed to CMD_GET_DATA) is (hex): " << raw_to_hex_string(data_id)); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_data_type = to_tz_data_type(data_type); + + auto s_in = makeSerializer(data_id, data_pwd, tz_data_type); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + uint32_t data_size = 0; + get_data_size(context, data_id, data_pwd, tz_data_type, data_size); + LOGD("get_data_size = [" << data_size << "]"); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(data_size)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + s_out.Serialize(out_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + + CHECK_RET(execute(CMD_GET_DATA, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(data); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_wrap_concatenated_data(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s wrapping_key_id, + const hal_security_keys_password_iv_tag_s wrapping_key_pwd, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s data, + hal_security_keys_data_s* wrapped_key) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_WRAP_CONCATENATED_DATA + LOGD("security_keys_wrap_concatenated_data"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + + if (tz_algo_type != ALGO_RSA) { + LOGE("Only RSA is supported in security_keys_wrap_concatenated_data"); + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + } + + TZSerializer s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, tz_hash_type, + key_id, key_pwd, data); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + uint32_t out_memory_size = KM_RSA_BLOCK_SIZE; + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + s_out.Serialize(out_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + CHECK_RET(execute(CMD_WRAP_CONCATENATED_DATA, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(wrapped_key); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_unwrap_concatenated_data(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s wrapping_key_id, + const hal_security_keys_password_iv_tag_s wrapping_key_pwd, + const hal_security_keys_data_s wrapped_key, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_s key_pwd, + const hal_security_keys_data_type_e key_type, + const size_t key_size_bits, + hal_security_keys_data_s* data, + hal_security_keys_data_s* key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_UNWRAP_CONCATENATED_DATA + LOGD("security_keys_unwrap_concatenated_data"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + auto tz_key_type = to_tz_data_type(key_type); + + if (tz_algo_type != ALGO_RSA) { + LOGE("Only RSA is supported in security_keys_unwrap_concatenated_data"); + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + } + + TZSerializer s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd, + tz_algo_type, tz_hash_type, tz_key_type, + wrapped_key, key_pwd, key_id, key_size_bits); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + uint32_t out_memory_size = KM_RSA_BLOCK_SIZE; + bool with_pwd = !key_pwd.password.buffer ? 0 : 1; + if (with_pwd) + out_memory_size += Params::DEFAULT_AES_GCM_TAG_LEN_BYTES; + + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + s_out.Serialize(out_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + CHECK_RET(execute(CMD_UNWRAP_CONCATENATED_DATA, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(data); + if (with_pwd) + s_out.Pull(key_tag); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_encrypt_data_auth(const hal_security_keys_context_s context, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s data, + const hal_security_keys_data_s iv, + const hal_security_keys_data_s aad, + const size_t tag_size_bits, + hal_security_keys_data_s* tag, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_ENCRYPT + LOGD("security_keys_encrypt_data_auth"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data, key_pwd, iv, key_id, aad, tag_size_bits); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + uint32_t out_memory_size = static_cast(data.length + Params::CIPHER_EXTRA_PADDING_SIZE); + uint32_t tag_size_bytes = (tag_size_bits + 7) / 8; + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + s_out.Push(new TZSerializableBinary(tag_size_bytes)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_AES_GCM; + + CHECK_RET(execute(CMD_ENCRYPT, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + s_out.Pull(tag); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_decrypt_data_auth(const hal_security_keys_context_s context, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s data, + const hal_security_keys_data_s iv, + const hal_security_keys_data_s aad, + const size_t tag_size_bits, + const hal_security_keys_data_s tag, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DECRYPT + LOGD("security_keys_decrypt_data_auth"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data, key_pwd, iv, key_id, aad, tag_size_bits, tag); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(data.length)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_AES_GCM; + + CHECK_RET(execute(CMD_DECRYPT, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_encrypt_data(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s data, + const hal_security_keys_data_s iv, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_ENCRYPT + LOGD("security_keys_encrypt_data"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer (size = " << + std::to_string(key_id.length) << ")"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + + TZSerializer s_in; + if (tz_algo_type == ALGO_RSA) + s_in = makeSerializer(data, key_pwd, tz_hash_type, key_id); + else + s_in = makeSerializer(data, key_pwd, iv, key_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + uint32_t out_memory_size; + if (tz_algo_type == ALGO_RSA) + out_memory_size = get_tz_max_key_size(ALGO_RSA); + else + out_memory_size = static_cast(data.length + Params::CIPHER_EXTRA_PADDING_SIZE); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = tz_algo_type; + + CHECK_RET(execute(CMD_ENCRYPT, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_decrypt_data(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s data, + const hal_security_keys_data_s iv, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DECRYPT + LOGD("security_keys_decrypt_data"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer (size = " << + std::to_string(key_id.length) << ")"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + + TZSerializer s_in; + if (tz_algo_type == ALGO_RSA) + s_in = makeSerializer(data, key_pwd, tz_hash_type, key_id); + else + s_in = makeSerializer(data, key_pwd, iv, key_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + // decrypt operation does not require padding + uint32_t out_memory_size = data.length; + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(out_memory_size, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = tz_algo_type; + + CHECK_RET(execute(CMD_DECRYPT, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_destroy_data(const hal_security_keys_context_s context, + const hal_security_keys_data_s data_id) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DESTROY_DATA + LOGD("security_keys_destroy_data"); + LOGD("Object ID (passed to CMD_DESTROY_DATA) is (hex): " << raw_to_hex_string(data_id)); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data_id); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory); + + return execute(CMD_DESTROY_DATA, &op, *tz_session); + + EXCEPTION_GUARD_END +} + +int security_keys_cipher_initialize(const hal_security_keys_context_s context, + const bool encrypt, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_tag_s key_pwd, + const hal_security_keys_data_s iv, + const hal_security_keys_data_s aad, + const size_t tag_size_bits, + hal_security_keys_cipher_context_t* cipher_context) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_CIPHER_INIT + LOGD("security_keys_cipher_initialize"); + + if (key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(key_pwd, iv, key_id, aad, tag_size_bits); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + op.params[0].value.a = ALGO_AES_GCM; + op.params[0].value.b = encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT; + + CHECK_RET(execute(CMD_CIPHER_INIT, &op, *tz_session)); + + *cipher_context = op.params[0].value.b; + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_cipher_add_aad(const hal_security_keys_context_s context, + const hal_security_keys_cipher_context_t cipher_context, + const hal_security_keys_data_s aad) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_CIPHER_INIT_AAD + LOGD("security_keys_cipher_add_aad"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(aad); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + op.params[0].value.a = cipher_context; + + return execute(CMD_CIPHER_INIT_AAD, &op, *tz_session); + + EXCEPTION_GUARD_END +} + +int security_keys_cipher_update(const hal_security_keys_context_s context, + const hal_security_keys_cipher_context_t cipher_context, + const hal_security_keys_data_s data, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_CIPHER_UPDATE + LOGD("security_keys_cipher_update"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(data.length)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = cipher_context; + + CHECK_RET(execute(CMD_CIPHER_UPDATE, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_cipher_finalize(const hal_security_keys_context_s context, + const hal_security_keys_cipher_context_t cipher_context, + const hal_security_keys_data_s data, + hal_security_keys_data_s* out) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_CIPHER_FINALIZE + LOGD("security_keys_cipher_finalize"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto s_in = makeSerializer(data); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = cipher_context; + + CHECK_RET(execute(CMD_CIPHER_FINALIZE, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(out); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_cipher_free(const hal_security_keys_context_s context, + const hal_security_keys_cipher_context_t cipher_context) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_CIPHER_CLEANUP + LOGD("security_keys_cipher_free"); + + TEEC_Session* tz_session = static_cast(context.session); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); + op.params[0].value.a = cipher_context; + + return execute(CMD_CIPHER_CLEANUP, &op, *tz_session); + + EXCEPTION_GUARD_END +} + +int security_keys_create_signature(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_tag_s priv_key_pwd, + const hal_security_keys_data_s message, + hal_security_keys_data_s* signature) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_SIGN + LOGD("security_keys_create_signature"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + auto tz_max_key_size = get_tz_max_key_size(tz_algo_type); + + if (priv_key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer (size = " << + std::to_string(priv_key_id.length) << ")"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + auto s_in = makeSerializer(message, priv_key_pwd, priv_key_id); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + s_out.Push(new TZSerializableBinary(tz_max_key_size, false)); + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = tz_algo_type; + op.params[0].value.b = tz_hash_type; + + CHECK_RET(execute(CMD_SIGN, &op, *tz_session)); + + s_out.Deserialize(out_memory); + s_out.Pull(signature); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_verify_signature(const hal_security_keys_context_s context, + const hal_security_keys_algo_type_e algo, + const hal_security_keys_hash_algorithm_e hash, + const hal_security_keys_data_s pub_key_id, + const hal_security_keys_password_iv_tag_s pub_key_pwd, + const hal_security_keys_data_s message, + const hal_security_keys_data_s signature) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_VERIFY + LOGD("security_keys_verify_signature"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_algo_type = to_tz_algo_type(algo); + auto tz_hash_type = to_tz_hash_type(hash); + + if (pub_key_id.length != KM_KEY_ID_SIZE) { + LOGE("TZ Backend received incorrect key buffer (size = " << + std::to_string(pub_key_id.length) << ")"); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + auto s_in = makeSerializer(message, signature, pub_key_pwd, pub_key_id); + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + op.params[0].value.a = tz_algo_type; + op.params[0].value.b = tz_hash_type; + + CHECK_RET(execute(CMD_VERIFY, &op, *tz_session)); + + int ret = op.params[0].value.a; + switch (ret) { + case KM_TA_SUCCESS: + return HAL_SECURITY_KEYS_ERROR_NONE; + case KM_TA_ERROR_SIGNATURE: + LOGW("Signature verification failed"); + return HAL_SECURITY_KEYS_ERROR_VERIFICATION_FAILED; + default: + LOGE("Unknown TA error during operation: " << ret); + return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR; + } + + EXCEPTION_GUARD_END +} + +int security_keys_derive_ecdh(const hal_security_keys_context_s context, + const hal_security_keys_ec_type_e ec_type, + const hal_security_keys_data_s pub_key_x, + const hal_security_keys_data_s pub_key_y, + const hal_security_keys_data_s priv_key_id, + const hal_security_keys_password_iv_tag_s priv_key_pwd, + const hal_security_keys_data_s secret_id, + const hal_security_keys_password_iv_s secret_pwd, + hal_security_keys_data_s* secret_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DERIVE + LOGD("security_keys_derive_ecdh"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_ec_type = to_tz_ec_type(ec_type); + + auto s_in = makeSerializer(priv_key_id, priv_key_pwd, tz_ec_type, + pub_key_x, pub_key_y, secret_pwd, secret_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !secret_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_ECDH_DRV; + + CHECK_RET(execute(CMD_DERIVE, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(secret_tag); + } + + LOGD("Derived object ID is (hex): " << raw_to_hex_string(secret_id)); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_derive_kbkdf(const hal_security_keys_context_s context, + const hal_security_keys_kbkdf_params_s params, + const hal_security_keys_data_s secret_id, + const hal_security_keys_password_iv_tag_s secret_pwd, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_s key_pwd, + hal_security_keys_data_s* key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DERIVE + LOGD("security_keys_derive_kbkdf"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_prf = to_tz_prf(params.prf); + auto tz_mode = to_tz_kbkdf_mode(params.mode); + auto tz_location = to_tz_kbkdf_ctr_loc(params.location); + + auto s_in = makeSerializer(secret_id, secret_pwd, + params.length, params.label, params.context, params.fixed, + tz_prf, tz_mode, tz_location, + params.rlen, params.llen, params.no_separator, + key_pwd, key_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !key_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_KBKDF_DRV; + + CHECK_RET(execute(CMD_DERIVE, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(key_tag); + } + + LOGD("Derived object ID is (hex): " << raw_to_hex_string(key_id)); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_derive_hybrid_kbkdf(const hal_security_keys_context_s context, + const hal_security_keys_kbkdf_params_s params, + const hal_security_keys_data_s first_secret_id, + const hal_security_keys_password_iv_tag_s first_secret_pwd, + const hal_security_keys_data_s second_secret_id, + const hal_security_keys_password_iv_tag_s second_secret_pwd, + const hal_security_keys_data_s key_id, + const hal_security_keys_password_iv_s key_pwd, + hal_security_keys_data_s* key_tag) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_DERIVE_HYBRID + LOGD("security_keys_derive_hybrid_kbkdf"); + + TEEC_Context* tz_context = static_cast(context.ctx); + TEEC_Session* tz_session = static_cast(context.session); + + auto tz_prf = to_tz_prf(params.prf); + auto tz_mode = to_tz_kbkdf_mode(params.mode); + auto tz_location = to_tz_kbkdf_ctr_loc(params.location); + + auto s_in = makeSerializer(first_secret_id, first_secret_pwd, + second_secret_id, second_secret_pwd, + params.length, params.label, params.context, params.fixed, + tz_prf, tz_mode, tz_location, + params.rlen, params.llen, params.no_separator, + key_pwd, key_id); + + TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT); + s_in.Serialize(in_memory); + + TZSerializer s_out; + bool with_pwd = !key_pwd.password.buffer ? 0 : 1; + if (with_pwd) + s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES)); + + TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT); + + TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory); + if (with_pwd) + op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory); + op.params[0].value.a = ALGO_KBKDF_DRV; + + CHECK_RET(execute(CMD_DERIVE_HYBRID, &op, *tz_session)); + + if (with_pwd) { + s_out.Deserialize(out_memory); + s_out.Pull(key_tag); + } + + LOGD("Derived object ID is (hex): " << raw_to_hex_string(key_id)); + + return 0; + + EXCEPTION_GUARD_END +} + +int security_keys_get_max_chunk_size(const hal_security_keys_context_s context, + size_t* chunk_size) +{ + EXCEPTION_GUARD_START + + // command ID = CMD_GET_MAX_CHUNK_SIZE + LOGD("security_keys_get_max_chunk_size"); + + TEEC_Session* tz_session = static_cast(context.session); + + TEEC_Operation op; + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); + + CHECK_RET(execute(CMD_GET_MAX_CHUNK_SIZE, &op, *tz_session)); + + *chunk_size = op.params[0].value.b; + + return 0; + + EXCEPTION_GUARD_END +} + +static int security_keys_backend_init(void **data) +{ + hal_backend_security_keys_funcs *security_keys_funcs; + + if (!data) + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + + security_keys_funcs = *(hal_backend_security_keys_funcs **)data; + if (!security_keys_funcs) + return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER; + + security_keys_funcs->context_initialize = security_keys_context_initialize; + security_keys_funcs->context_free = security_keys_context_free; + security_keys_funcs->create_iv = security_keys_create_iv; + security_keys_funcs->create_key_aes = security_keys_create_key_aes; + security_keys_funcs->create_key_pair_rsa = security_keys_create_key_pair_rsa; + security_keys_funcs->create_key_pair_dsa = security_keys_create_key_pair_dsa; + security_keys_funcs->create_key_pair_ecdsa = security_keys_create_key_pair_ecdsa; + security_keys_funcs->create_key_pair_kem = security_keys_create_key_pair_kem; + security_keys_funcs->import_wrapped_key = security_keys_import_wrapped_key; + security_keys_funcs->export_wrapped_key = security_keys_export_wrapped_key; + security_keys_funcs->encapsulate_key = security_keys_encapsulate_key; + security_keys_funcs->decapsulate_key = security_keys_decapsulate_key; + security_keys_funcs->destroy_key = security_keys_destroy_key; + security_keys_funcs->import_data = security_keys_import_data; + security_keys_funcs->export_data = security_keys_export_data; + security_keys_funcs->wrap_concatenated_data = security_keys_wrap_concatenated_data; + security_keys_funcs->unwrap_concatenated_data = security_keys_unwrap_concatenated_data; + security_keys_funcs->encrypt_data_auth = security_keys_encrypt_data_auth; + security_keys_funcs->decrypt_data_auth = security_keys_decrypt_data_auth; + security_keys_funcs->encrypt_data = security_keys_encrypt_data; + security_keys_funcs->decrypt_data = security_keys_decrypt_data; + security_keys_funcs->destroy_data = security_keys_destroy_data; + security_keys_funcs->cipher_initialize = security_keys_cipher_initialize; + security_keys_funcs->cipher_add_aad = security_keys_cipher_add_aad; + security_keys_funcs->cipher_update = security_keys_cipher_update; + security_keys_funcs->cipher_finalize = security_keys_cipher_finalize; + security_keys_funcs->cipher_free = security_keys_cipher_free; + security_keys_funcs->create_signature = security_keys_create_signature; + security_keys_funcs->verify_signature = security_keys_verify_signature; + security_keys_funcs->derive_ecdh = security_keys_derive_ecdh; + security_keys_funcs->derive_kbkdf = security_keys_derive_kbkdf; + security_keys_funcs->derive_hybrid_kbkdf = security_keys_derive_hybrid_kbkdf; + security_keys_funcs->get_max_chunk_size = security_keys_get_max_chunk_size; + + return 0; +} + +static int security_keys_backend_exit(void *data) +{ + (void) data; + return 0; +} + +EXPORT hal_backend hal_backend_security_keys_data = { + .name = "backend_security_keys", + .vendor = "Samsung", + .init = security_keys_backend_init, + .exit = security_keys_backend_exit, + .major_version = 1, + .minor_version = 0, +}; diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..a57307d --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include +#include + +#ifdef NDEBUG +int __log_level = LOG_ERR; +#else +int __log_level = LOG_DEBUG; +#endif + +#define SECURITY_KEYS_LOG_TAG "SECURITY_KEYS_BACKEND" + +void security_keys_print(int priority, char const *fmt, ...) +{ + log_priority dlog_prio; + + switch (priority) { + case LOG_EMERG: + dlog_prio = DLOG_FATAL; + break; + case LOG_ERR: + dlog_prio = DLOG_ERROR; + break; + case LOG_WARNING: + dlog_prio = DLOG_WARN; + break; + case LOG_INFO: + dlog_prio = DLOG_INFO; + break; + case LOG_DEBUG: + dlog_prio = DLOG_DEBUG; + break; + default: + dlog_prio = DLOG_DEFAULT; + } + + va_list ap; + va_start(ap, fmt); + (void) dlog_vprint(dlog_prio, SECURITY_KEYS_LOG_TAG, fmt, ap); + va_end(ap); +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..a3a35f0 --- /dev/null +++ b/src/log.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma once + +#include +#include +#include + +#define UNUSED __attribute__((unused)) + +extern int __log_level; +extern void security_keys_print(int priority, char const *fmt, ...); + +namespace { + template + void UNUSED __LOG_FUN(int level, const std::stringstream &format, Args&&... args) { + security_keys_print(level, format.str().c_str(), std::forward(args)...); + } + + template <> + void UNUSED __LOG_FUN(int level, const std::stringstream &format) { + security_keys_print(level, "%s", format.str().c_str()); + } + + template + void UNUSED __LOG_FUN(int level, const char *format, Args&&... args) { + security_keys_print(level, format, std::forward(args)...); + } + + template <> + void UNUSED __LOG_FUN(int level, const char *format) { + security_keys_print(level, "%s", format); + } + +} // namespace anonymous + +#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +#define __LOG(LEVEL, FORMAT, ...) \ + do { \ + if (LEVEL <= __log_level) { \ + std::stringstream __LOG_FORMAT; \ + __LOG_FORMAT << __FILENAME__ << ": " << __func__ << "(" << __LINE__ << ") > " << FORMAT; \ + __LOG_FUN(LEVEL, __LOG_FORMAT, ##__VA_ARGS__); \ + } \ + } while (0) + +#define LOGM(...) __LOG(LOG_EMERG, __VA_ARGS__) /* system is unusable */ +#define LOGE(...) __LOG(LOG_ERR, __VA_ARGS__) /* error conditions */ +#define LOGW(...) __LOG(LOG_WARNING, __VA_ARGS__) /* warning conditions */ +#define LOGI(...) __LOG(LOG_INFO, __VA_ARGS__) /* informational */ +#define LOGD(...) __LOG(LOG_DEBUG, __VA_ARGS__) /* debug-level messages */ diff --git a/src/tz-memory.cpp b/src/tz-memory.cpp new file mode 100644 index 0000000..76007cc --- /dev/null +++ b/src/tz-memory.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +#include +#include + +#include "log.h" +#include "tz-memory.h" + +TrustZoneMemory::TrustZoneMemory(TEEC_Context &context, const size_t size, const uint32_t flags) +{ + Allocate(context, size, flags); +} + +TrustZoneMemory::~TrustZoneMemory() +{ + Release(); +} + +void TrustZoneMemory::Allocate(TEEC_Context &context, const size_t size, const uint32_t flags) +{ + LOGD("Allocating " << size << " bytes of shared TZ memory, flags: " << flags); + + m_SharedMemory.size = size; + m_SharedMemory.flags = flags; + + if (size != 0) { + TEEC_Result result = TEEC_AllocateSharedMemory(&context, &m_SharedMemory); + if (result != TEEC_SUCCESS) + throw std::bad_alloc(); + + memset(m_SharedMemory.buffer, 0, m_SharedMemory.size); + } else { + m_SharedMemory.buffer = NULL; + m_SharedMemory.size = 0; + } +} + +TEEC_SharedMemory* TrustZoneMemory::Get() const +{ + return &m_SharedMemory; +} + +void TrustZoneMemory::Release() +{ + if (m_SharedMemory.size != 0) + TEEC_ReleaseSharedMemory(&m_SharedMemory); +} diff --git a/src/tz-memory.h b/src/tz-memory.h new file mode 100644 index 0000000..8771907 --- /dev/null +++ b/src/tz-memory.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma once + +#include + +class TrustZoneMemory final +{ +public: + TrustZoneMemory(TEEC_Context &context, const size_t size, const uint32_t flags); + TrustZoneMemory(const TrustZoneMemory&) = delete; + TrustZoneMemory(TrustZoneMemory &&) = delete; + TrustZoneMemory& operator=(const TrustZoneMemory&) = delete; + TrustZoneMemory& operator=(TrustZoneMemory &&) = delete; + ~TrustZoneMemory(); + + TEEC_SharedMemory* Get() const; + +private: + void Allocate(TEEC_Context &context, const size_t size, const uint32_t flags); + void Release(); + + mutable TEEC_SharedMemory m_SharedMemory; +}; diff --git a/src/tz-serializer.cpp b/src/tz-serializer.cpp new file mode 100644 index 0000000..6193f70 --- /dev/null +++ b/src/tz-serializer.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#include +#include + +#include "crypto-params.h" +#include "tz-serializer.h" + +// TZSerializable +void TZSerializable::Pull(hal_security_keys_data_s*) const +{ + throw std::runtime_error("This serializable does not support conversion to hal_security_keys_data_s"); +} + +void TZSerializable::Pull(uint32_t &) const +{ + throw std::runtime_error("This serializable does not support conversion to uint32_t"); +} + +// TZSerializableBinary +TZSerializableBinary::TZSerializableBinary(uint32_t data_size, bool is_size_fixed) +{ + m_data.data = nullptr; + m_data.data_size = data_size; + m_isSizeFixed = is_size_fixed; + m_expectedSize = data_size; +} + +TZSerializableBinary::TZSerializableBinary(const hal_security_keys_data_s &data) +{ + m_data.data = !data.buffer ? nullptr : data.buffer; + m_data.data_size = data.length; + m_isSizeFixed = true; + m_expectedSize = data.length; +} + +uint32_t TZSerializableBinary::GetSize() const +{ + return KM_SizeOfBinaryData(const_cast(&m_data)); +} + +int TZSerializableBinary::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializeBinaryData(buffer, size_guard, const_cast(&m_data)); +} + +int TZSerializableBinary::Deserialize(void **buffer, uint32_t *size_guard) +{ + int ret = KM_DeserializeBinaryData(buffer, size_guard, &m_data); + if (m_isSizeFixed) { + if (m_data.data_size != m_expectedSize) + throw std::runtime_error("Size of deserialized data differ from size given in constructor."); + } else { + if (m_data.data_size > m_expectedSize) + throw std::runtime_error("Size of deserialized data is bigger than size given in constructor."); + } + return ret; +} + +void TZSerializableBinary::Pull(hal_security_keys_data_s* buf) const +{ + buf->buffer = (unsigned char*)malloc(m_data.data_size); + if (!(buf->buffer)) + throw std::bad_alloc(); + + buf->length = m_data.data_size; + memcpy(buf->buffer, m_data.data, m_data.data_size); +} + +// TZSerializablePwdData +TZSerializablePwdData::TZSerializablePwdData(const hal_security_keys_data_s &pwd, + const hal_security_keys_data_s &iv, + uint32_t tagSizeBits, + const hal_security_keys_data_s &tag) +{ + memset(&m_data, 0, sizeof(KM_PwdData)); + m_data.pwd = !pwd.buffer ? nullptr : pwd.buffer; + m_data.pwd_size = pwd.length; + m_data.iv = !iv.buffer ? nullptr : iv.buffer; + m_data.iv_size = iv.length; + m_data.tag = !tag.buffer ? nullptr : tag.buffer; + m_data.tag_size = tag.length; + m_data.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS; + m_data.it_count = Params::DERIVED_KEY_ITERATIONS; + m_data.tag_len_bits = tagSizeBits; +} + +uint32_t TZSerializablePwdData::GetSize() const +{ + return KM_SizeOfPwdData(const_cast(&m_data)); +} + +int TZSerializablePwdData::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializePwdData(buffer, size_guard, const_cast(&m_data)); +} + +int TZSerializablePwdData::Deserialize(void **, uint32_t *) +{ + throw std::runtime_error("Should not receive any password data from the TA"); +} + +// TZSerializableFlag +uint32_t TZSerializableFlag::GetSize() const +{ + return KM_SizeOfFlag(); +} + +int TZSerializableFlag::Serialize(void **buffer, uint32_t *size_guard) const +{ + return KM_SerializeFlag(buffer, size_guard, m_flag); +} + +int TZSerializableFlag::Deserialize(void **buffer, uint32_t *size_guard) +{ + return KM_DeserializeFlag(buffer, size_guard, &m_flag); +} + +void TZSerializableFlag::Pull(uint32_t &flag) const +{ + flag = m_flag; +} + +// TZSerializer +void TZSerializer::Push(TZSerializable *serializable) +{ + m_serializables.emplace_back(serializable); + m_memorySize += serializable->GetSize(); +} + +void TZSerializer::Serialize(TrustZoneMemory &memory) const +{ + void *inBuffer = memory.Get()->buffer; + uint32_t inBufferGuard = m_memorySize; + + for (const auto& s : m_serializables) { + int ret = s->Serialize(&inBuffer, &inBufferGuard); + if (ret) + throw std::runtime_error("Failed to serialize data, ret: " + ret); + } +} + +void TZSerializer::Deserialize(const TrustZoneMemory &memory) +{ + void *outBuffer = memory.Get()->buffer; + uint32_t outBufferGuard = m_memorySize; + + for (const auto& s : m_serializables) { + int ret = s->Deserialize(&outBuffer, &outBufferGuard); + if (ret) + throw std::runtime_error("Failed to deserialize data, ret: " + ret); + } +} diff --git a/src/tz-serializer.h b/src/tz-serializer.h new file mode 100644 index 0000000..bff9588 --- /dev/null +++ b/src/tz-serializer.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +#include "tz-memory.h" + +class TZSerializable { +public: + TZSerializable() {} + virtual ~TZSerializable() {} + TZSerializable(const TZSerializable&) = delete; + TZSerializable& operator=(const TZSerializable&) = delete; + + virtual uint32_t GetSize() const = 0; + virtual int Serialize(void **buffer, uint32_t *size_guard) const = 0; + virtual int Deserialize(void **buffer, uint32_t *size_guard) = 0; + virtual void Pull(hal_security_keys_data_s* buffer) const; + virtual void Pull(uint32_t &flag) const; +}; + +class TZSerializableBinary : public TZSerializable { +public: + explicit TZSerializableBinary(uint32_t data_size, bool is_size_fixed = true); + explicit TZSerializableBinary(const hal_security_keys_data_s &data); + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; + void Pull(hal_security_keys_data_s* buffer) const override; +private: + KM_BinaryData m_data; + bool m_isSizeFixed; + uint32_t m_expectedSize; +}; + +class TZSerializablePwdData : public TZSerializable { +public: + TZSerializablePwdData(const hal_security_keys_data_s &pwd, + const hal_security_keys_data_s &iv, + uint32_t tagSizeBits, + const hal_security_keys_data_s &tag = {nullptr, 0}); + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; +private: + KM_PwdData m_data; +}; + +class TZSerializableFlag : public TZSerializable { +public: + TZSerializableFlag() : m_flag(0) {} + explicit TZSerializableFlag(uint32_t flag) : m_flag(flag) {} + uint32_t GetSize() const override; + int Serialize(void **buffer, uint32_t *size_guard) const override; + int Deserialize(void **buffer, uint32_t *size_guard) override; + void Pull(uint32_t &flag) const override; +private: + uint32_t m_flag; +}; + +class TZSerializer { +public: + TZSerializer() : m_memorySize(0) {} + ~TZSerializer() {} + TZSerializer(const TZSerializer&) = delete; + TZSerializer(TZSerializer&&) = default; + TZSerializer& operator=(const TZSerializer&) = delete; + TZSerializer& operator=(TZSerializer&&) = default; + + void Push(TZSerializable *serializable); + + template + void Pull(T &buffer); + uint32_t GetSize() const { return m_memorySize; } + void Serialize(TrustZoneMemory &memory) const; + void Deserialize(const TrustZoneMemory &memory); + +private: + std::list> m_serializables; + uint32_t m_memorySize; +}; + +template +void TZSerializer::Pull(T &data) +{ + if (m_serializables.empty()) { + throw std::runtime_error("No more serializables to extract"); + } + + m_serializables.front()->Pull(data); + m_serializables.pop_front(); +}