From 2c5ef8bfd274d7d6f3cd862a3621d338639593d9 Mon Sep 17 00:00:00 2001 From: Jan Wojtkowski Date: Fri, 7 Feb 2025 09:34:13 +0100 Subject: [PATCH] Add unit-tests to hal-api security-certs Change-Id: Ic1372125de800940d7c1159650683b4380770651 --- CMakeLists.txt | 4 + haltest/CMakeLists.txt | 29 ++++ haltest/main.cpp | 34 ++++ haltest/security-certs.cpp | 288 ++++++++++++++++++++++++++++++++ packaging/hal-api-security.spec | 20 ++- 5 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 haltest/CMakeLists.txt create mode 100644 haltest/main.cpp create mode 100644 haltest/security-certs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a74b70..8cc2497 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,3 +44,7 @@ INSTALL( FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIBDIR}/pkgconfig ) + +IF(HALTEST STREQUAL on) + ADD_SUBDIRECTORY(haltest) +ENDIF() diff --git a/haltest/CMakeLists.txt b/haltest/CMakeLists.txt new file mode 100644 index 0000000..bdf6e68 --- /dev/null +++ b/haltest/CMakeLists.txt @@ -0,0 +1,29 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.0) +PROJECT(security-haltests C CXX) + +SET(HALAPI_LIBRARY "hal-api-security") + +FIND_LIBRARY( + HALAPI_LIBRARY + NAMES libhal-api-security.so + HINTS /usr/lib/hal /usr/lib64/hal + REQUIRED) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(TEST_DEPS REQUIRED capi-system-info gmock) + +INCLUDE_DIRECTORIES(SYSTEM ${TEST_DEPS_INCLUDE_DIRS}) +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}) +LINK_DIRECTORIES(${TEST_DEPS_LIBRARY_DIRS}) + +SET(EXTRA_CFLAGS "-Wall -Wextra -Werror") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +SET(SRCS + ${CMAKE_SOURCE_DIR}/haltest/main.cpp + ${CMAKE_SOURCE_DIR}/haltest/security-certs.cpp) +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${TEST_DEPS_LDFLAGS} ${HALAPI_LIBRARY}) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin/hal) diff --git a/haltest/main.cpp b/haltest/main.cpp new file mode 100644 index 0000000..3915055 --- /dev/null +++ b/haltest/main.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd. + * + * 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 + +int main(int argc, char **argv) +{ + int ret = -1; + + try { + testing::InitGoogleTest(&argc, argv); + ret = RUN_ALL_TESTS(); + } catch (const ::testing::internal::GoogleTestFailureException &e) { + std::cout << "GoogleTestFailureException was thrown:" << e.what() << std::endl; + } catch (...) { + std::cout << "Exception occurred." << std::endl; + } + + return ret; +} diff --git a/haltest/security-certs.cpp b/haltest/security-certs.cpp new file mode 100644 index 0000000..ec95110 --- /dev/null +++ b/haltest/security-certs.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2025 Samsung Electronics Co., Ltd. + * + * 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 + +#include "hal-security-certs.h" + +int check_feature(void) +{ + bool is_supported; + if (SYSTEM_INFO_ERROR_NONE != system_info_get_platform_bool( + "http://tizen.org/feature/security.device_certificate", &is_supported)) + return -1; // error + else if (is_supported) + return 1; // supported + else + return 0; // not supported +} + +class SECURITY_CERTS : public testing::Test +{ +protected: + void SetUp() override { + int ret; + status = check_feature(); + switch (status) { + case 1: + ret = hal_security_certs_get_backend(); + ASSERT_EQ(ret, 0) << "Failed to get security certs backend (" << ret << ")"; + break; + case 0: + GTEST_SKIP() << "Device certificate feature not supported, test skipped."; + break; + case -1: + GTEST_FAIL() << "Checking platform feature failed."; + break; + } + }; + + void TearDown() override { + if (status == 1) { + int ret = hal_security_certs_put_backend(); + EXPECT_EQ(ret, 0) << "Failed to put security certs backend (" << ret << ")"; + } + }; + + int status; +}; + +TEST_F(SECURITY_CERTS, CreateAndFreeKeyContextPositive) +{ + int ret; + + hal_security_certs_context_s context; + std::string correct_key_type = "RSA"; + hal_security_certs_data_s correct_key_type_data_s = + { + const_cast(correct_key_type.c_str()), + correct_key_type.size() + }; + + ret = hal_security_certs_create_key_context(&context, correct_key_type_data_s); + EXPECT_EQ(ret, 0) << "Failed to create key context (" << ret << ")"; + + ret = hal_security_certs_free_key_context(&context); + EXPECT_EQ(ret, 0) << "Failed to free key context (" << ret << ")"; +} + +TEST_F(SECURITY_CERTS, CreateKeyContextNegative) +{ + int ret; + + hal_security_certs_context_s context; + std::string wrong_key_type = "error"; + hal_security_certs_data_s wrong_key_type_data_s = + { + const_cast(wrong_key_type.c_str()), + wrong_key_type.size() + }; + + ret = hal_security_certs_create_key_context(&context, wrong_key_type_data_s); + EXPECT_EQ(ret, -ENODATA) << "Created wrong key context (" << ret << ")"; +} + +TEST_F(SECURITY_CERTS, RequestCertificateChainContextPositive) +{ + int ret; + + hal_security_certs_context_s context; + + for (std::string key_type : {"RSA", "ECDSA"}) + { + hal_security_certs_data_s key_type_data_s = + { + const_cast(key_type.c_str()), + key_type.size() + }; + + ret = hal_security_certs_create_key_context(&context, key_type_data_s); + EXPECT_EQ(ret, 0) << "Failed to create key context (" << ret << ")"; + + hal_security_certs_data_s chain; + ret = hal_security_certs_request_certificate_chain(&context, &chain); + EXPECT_EQ(ret, 0) << "Failed to request certificate chain (" << ret << ")"; + EXPECT_TRUE(chain.length > 0) << "Certificate chain length is zero"; + free(chain.buffer); + + ret = hal_security_certs_free_key_context(&context); + EXPECT_EQ(ret, 0) << "Failed to free key context (" << ret << ")"; + } +} + +TEST_F(SECURITY_CERTS, SignCryptoDataPositive) +{ + int ret; + + hal_security_certs_context_s context; + std::map digest_length_map = + { + {HAL_SECURITY_CERTS_DIGEST_TYPE_MD2, 128/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_MD4, 128/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_MD5, 128/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_SHA1, 160/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_SHA224, 224/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_SHA256, 256/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_SHA384, 384/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_SHA512, 512/8}, + {HAL_SECURITY_CERTS_DIGEST_TYPE_RIPEMD160, 160/8} + }; + + for (std::string key_type : {"RSA", "ECDSA"}) + { + + hal_security_certs_data_s key_type_data_s = + { + const_cast(key_type.c_str()), + key_type.size() + }; + + ret = hal_security_certs_create_key_context(&context, key_type_data_s); + EXPECT_EQ(ret, 0) << "Failed to create key context (" << ret << ")"; + + for (auto digest : digest_length_map) { + char data[digest.second] = {0,}; + hal_security_certs_data_s message_data_s = + { + data, + sizeof(data) + }; + + hal_security_certs_data_s signature; + hal_security_certs_digest_type_e digest_type = static_cast(digest.first); + ret = hal_security_certs_sign_crypto_data(&context, digest_type, message_data_s, &signature); + EXPECT_EQ(ret, 0) << "Failed to sign crypto data (" << ret << ")"; + EXPECT_TRUE(signature.length > 0) << "Signature length is zero"; + free(signature.buffer); + } + + ret = hal_security_certs_free_key_context(&context); + EXPECT_EQ(ret, 0) << "Failed to free key context (" << ret << ")"; + } +} + +TEST_F(SECURITY_CERTS, SignCryptoDataNegative) +{ + int ret; + + hal_security_certs_context_s context; + std::string key_type = "RSA"; + hal_security_certs_data_s key_type_data_s = + { + const_cast(key_type.c_str()), + key_type.size() + }; + + ret = hal_security_certs_create_key_context(&context, key_type_data_s); + EXPECT_EQ(ret, 0) << "Failed to create key context (" << ret << ")"; + + char data[20] = {0,}; + hal_security_certs_data_s message_data_s = + { + data, + sizeof(data) + }; + + hal_security_certs_data_s signature; + ret = hal_security_certs_sign_crypto_data( + &context, HAL_SECURITY_CERTS_DIGEST_TYPE_SHA256, message_data_s, &signature); + EXPECT_EQ(ret, -EINVAL) << "Succeded with wrong size of crypto data to sign (" << ret << ")"; + + hal_security_certs_digest_type_e wrong_digest_type = static_cast(-1); + ret = hal_security_certs_sign_crypto_data(&context, wrong_digest_type, message_data_s, &signature); + EXPECT_EQ(ret, -EINVAL) << "Succeded with wrong digest type to sign crypto data (" << ret << ")"; + + ret = hal_security_certs_free_key_context(&context); + EXPECT_EQ(ret, 0) << "Failed to free key context (" << ret << ")"; +} + +TEST_F(SECURITY_CERTS, GetKeyTypeAndLengthPositive) +{ + int ret; + + std::map> key_map = + { + {"RSA", {HAL_SECURITY_CERTS_KEY_TYPE_RSA, 1024}}, + {"ECDSA", {HAL_SECURITY_CERTS_KEY_TYPE_ECDSA, 521}}, + }; + + for (auto key : key_map) + { + std::string key_type = key.first; + hal_security_certs_crypto_key_type_e ret_key_type_enum; + unsigned int key_bit_length = key.second.second; + hal_security_certs_crypto_key_type_e key_type_enum = key.second.first; + + hal_security_certs_data_s key_type_data_s = + { + const_cast(key_type.c_str()), + key_type.size() + }; + + hal_security_certs_context_s context; + ret = hal_security_certs_create_key_context(&context, key_type_data_s); + EXPECT_EQ(ret, 0) << "Failed to create key context (" << ret << ")"; + + ret = hal_security_certs_get_key_type(&context, &ret_key_type_enum); + EXPECT_EQ(ret, 0) << "Failed to get key type (" << ret << ")"; + EXPECT_EQ(ret_key_type_enum, key_type_enum) << "Incorrect key type (" << ret_key_type_enum << ")"; + + unsigned int key_length = 0; + ret = hal_security_certs_get_key_bit_length(&context, &key_length); + EXPECT_EQ(ret, 0) << "Failed to get key bit length (" << ret << ")"; + EXPECT_EQ(key_length, key_bit_length) << "Incorrect key bit length (" << key_length << ")"; + + ret = hal_security_certs_free_key_context(&context); + EXPECT_EQ(ret, 0) << "Failed to free key context (" << ret << ")"; + } +} + +TEST_F(SECURITY_CERTS, ExtCallApiNegative) +{ + int ret; + + std::string method_name = "test-method-name"; + hal_security_certs_data_s method_name_data_s = + { + const_cast(method_name.c_str()), + method_name.size() + }; + + hal_security_certs_data_s input_data_s; + hal_security_certs_data_s output_data_s; + + ret = hal_security_certs_ext_call_api(method_name_data_s, input_data_s, &output_data_s); + EXPECT_EQ(ret, -EINVAL) << "Executesd not exisitng external call api method (" << ret << ")"; +} + +TEST_F(SECURITY_CERTS, ExtGetApiPrivilegeNegative) +{ + int ret; + + std::string method_name = "test-method-name"; + hal_security_certs_data_s method_name_data_s = + { + const_cast(method_name.c_str()), + method_name.size() + }; + + hal_security_certs_data_s privilege; + + ret = hal_security_certs_ext_get_api_privilege(method_name_data_s, &privilege); + EXPECT_EQ(ret, -EINVAL) << "Executesd not exisitng external call api method (" << ret << ")"; +} diff --git a/packaging/hal-api-security.spec b/packaging/hal-api-security.spec index 92dcb09..38340cf 100644 --- a/packaging/hal-api-security.spec +++ b/packaging/hal-api-security.spec @@ -26,12 +26,24 @@ Requires: %{name} = %{version}-%{release} %description -n %{name}-devel %{name} Interface for product vendor developer +### haltest package ######### +%package -n %{name}-haltests +Summary: %{name} tests +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(gmock) + +%description -n %{name}-haltests +%{name} tests + ### build and install ######### %prep %setup -q cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} \ - -DCMAKE_LIBDIR_PREFIX=%{_libdir}/ + -DCMAKE_LIBDIR_PREFIX=%{_libdir}/ \ + -DHALTEST=on %build cp %{SOURCE1} . @@ -69,3 +81,9 @@ rm -rf %{buildroot} %{_includedir}/hal/hal-security-certs*.h %{_libdir}/pkgconfig/hal-api-security.pc %{_libdir}/hal/lib%{name}.so + +%files -n %{name}-haltests +%defattr(-,root,root,-) +%manifest %{name}.manifest +%license LICENSE.Apache-2.0 +%{_bindir}/hal/security-haltests -- 2.34.1