From: sangwan.kwon Date: Thu, 16 Mar 2017 13:12:14 +0000 (+0900) Subject: Add implemetation of trust-anchor library X-Git-Tag: submit/tizen/20170623.014003~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3d5c521ad80d6c3b28d6c9b1f0e8c686c7d2ec43;p=platform%2Fcore%2Fsecurity%2Ftrust-anchor.git Add implemetation of trust-anchor library Change-Id: Id8ea3c9d3c18806daa310b1455064530640fd9b7 Signed-off-by: sangwan.kwon --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3026802..79b4dfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,12 +20,59 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.8) PROJECT(trust-anchor) +INCLUDE(FindPkgConfig) +INCLUDE(GNUInstallDirs) + +IF(NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "DEBUG") +ENDIF(NOT CMAKE_BUILD_TYPE) + +STRING(REGEX MATCH "([^.]*)" API_VERSION "${LIB_VERSION}") +SET(TANCHOR_INCLUDE ${PROJECT_SOURCE_DIR}/api) +SET(TANCHOR_SRC ${PROJECT_SOURCE_DIR}/src) +SET(TARGET_TANCHOR_LIB ${LIB_NAME}) + +ADD_DEFINITIONS("-DTANCHOR_USR_DIR=\"${TANCHOR_USR}\"") +ADD_DEFINITIONS("-DTANCHOR_GLOBAL_DIR=\"${TANCHOR_GLOBAL}\"") +ADD_DEFINITIONS("-DTANCHOR_BUNDLE=\"${TANCHOR_BUNDLE}\"") +ADD_DEFINITIONS("-DTZ_SYS_CA_CERTS=\"${TZ_SYS_CA_CERTS}\"") +ADD_DEFINITIONS("-DTZ_SYS_CA_BUNDLE=\"${TZ_SYS_CA_BUNDLE}\"") + +IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) + SET(CXX_STD "c++0x") +else() + SET(CXX_STD "c++11") +endif() + +ADD_DEFINITIONS("-fPIC") +ADD_DEFINITIONS("-Werror") +ADD_DEFINITIONS("-Wall") +ADD_DEFINITIONS("-Wextra") +ADD_DEFINITIONS("-pedantic") +ADD_DEFINITIONS("-pedantic-errors") + +SET(CMAKE_C_FLAGS_PROFILING "-g -O0 -pg") +SET(CMAKE_CXX_FLAGS_PROFILING "-g -O0 -pg -std=${CXX_STD} -fno-rtti") +SET(CMAKE_C_FLAGS_DEBUG "-g -O0 -ggdb") +SET(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -ggdb -std=${CXX_STD} -fno-rtti") +SET(CMAKE_C_FLAGS_RELEASE "-g -O2 -DNDEBUG") +SET(CMAKE_CXX_FLAGS_RELEASE "-g -O2 -DNDEBUG -std=${CXX_STD} -fno-rtti") +SET(CMAKE_C_FLAGS_CCOV "-g -O0 --coverage") +SET(CMAKE_CXX_FLAGS_CCOV "-g -O0 --coverage -std=${CXX_STD} -fno-rtti") + +SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed") + +IF(NOT DEFINED LIB_INSTALL_DIR) + SET(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") +ENDIF(NOT DEFINED LIB_INSTALL_DIR) + IF(NOT DEFINED INCLUDE_INSTALL_DIR) SET(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}") ENDIF(NOT DEFINED INCLUDE_INSTALL_DIR) -SET(TANCHOR_INCLUDE ${PROJECT_SOURCE_DIR}/api/tanchor) - -CONFIGURE_FILE(packaging/trust-anchor.manifest trust-anchor.manifest) +CONFIGURE_FILE(packaging/trust-anchor.manifest.in trust-anchor.manifest @ONLY) ADD_SUBDIRECTORY(api) +ADD_SUBDIRECTORY(lib) +ADD_SUBDIRECTORY(src) diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 92506c9..5619784 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -16,5 +16,5 @@ # @author Sangwan kwon (sangwan.kwon@samsung.com) # -INSTALL(DIRECTORY ${TANCHOR_INCLUDE} +INSTALL(DIRECTORY ${TANCHOR_INCLUDE}/tanchor DESTINATION ${INCLUDE_INSTALL_DIR}) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..3182ce6 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2017 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 +# +# @file CMakeLists.txt +# @author Sangwan kwon (sangwan.kwon@samsung.com) +# @brief Configure pkgconfig files +# + +CONFIGURE_FILE(${LIB_NAME}.pc.in ${LIB_NAME}.pc @ONLY) + +INSTALL(FILES ${LIB_NAME}.pc + DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) diff --git a/lib/tanchor.pc.in b/lib/tanchor.pc.in new file mode 100644 index 0000000..4a9e58b --- /dev/null +++ b/lib/tanchor.pc.in @@ -0,0 +1,12 @@ +# Package Information for pkg-config + +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=%{prefix} +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@ + +Name: @LIB_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @LIB_VERSION@ +Libs: -L${libdir} -l@LIB_NAME@ +Cflags: -I${includedir}/@LIB_NAME@ diff --git a/packaging/trust-anchor.manifest b/packaging/trust-anchor.manifest deleted file mode 100644 index a76fdba..0000000 --- a/packaging/trust-anchor.manifest +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/packaging/trust-anchor.manifest.in b/packaging/trust-anchor.manifest.in new file mode 100644 index 0000000..b5de845 --- /dev/null +++ b/packaging/trust-anchor.manifest.in @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packaging/trust-anchor.spec b/packaging/trust-anchor.spec index a3e2110..e21c10f 100644 --- a/packaging/trust-anchor.spec +++ b/packaging/trust-anchor.spec @@ -7,6 +7,25 @@ Summary: Trust Anchor API Group: Security/Certificate Management BuildRequires: gcc BuildRequires: cmake +BuildRequires: coreutils +BuildRequires: pkgconfig(klay) +BuildRequires: pkgconfig(openssl) +BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: ca-certificates +BuildRequires: ca-certificates-devel +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%global lib_name tanchor +%global user_name security_fw +%global group_name security_fw +%global smack_label System + +%global tanchor_base %{TZ_SYS_DATA} +%global tanchor_res %{tanchor_base}/res +%global tanchor_usr %{tanchor_base}/usr +%global tanchor_global %{tanchor_base}/global +%global tanchor_bundle %{tanchor_base}/ca-bundle.pem %description The package provides trust-anchor which the application can assign @@ -15,6 +34,11 @@ SSL root certificates for its HTTPS communication. %files %manifest %{name}.manifest %license LICENSE +%{_libdir}/lib%{lib_name}.so.0 +%{_libdir}/lib%{lib_name}.so.%{version} +%dir %attr(-, %{user_name}, %{group_name}) %{tanchor_usr} +%dir %attr(-, %{user_name}, %{group_name}) %{tanchor_global} +%attr(-, %{user_name}, %{group_name}) %{tanchor_bundle} %prep %setup -q @@ -22,13 +46,35 @@ SSL root certificates for its HTTPS communication. %build %{!?build_type:%define build_type "RELEASE"} -%cmake . -DCMAKE_BUILD_TYPE=%{build_type} +%cmake . -DCMAKE_BUILD_TYPE=%{build_type} \ + -DLIB_NAME=%{lib_name} \ + -DLIB_VERSION=%{version} \ + -DUSER_NAME=%{user_name} \ + -DGROUP_NAME=%{group_name} \ + -DSMACK_LABEL=%{smack_label} \ + -DTANCHOR_BASE=%{tanchor_base} \ + -DTANCHOR_RES=%{tanchor_res} \ + -DTANCHOR_USR=%{tanchor_usr} \ + -DTANCHOR_GLOBAL=%{tanchor_global} \ + -DTANCHOR_BUNDLE=%{tanchor_bundle} \ + -DTZ_SYS_CA_CERTS=%{TZ_SYS_CA_CERTS} \ + -DTZ_SYS_CA_BUNDLE=%{TZ_SYS_CA_BUNDLE} make %{?_smp_mflags} %install %make_install +mkdir -p %{buildroot}%{tanchor_res} +mkdir -p %{buildroot}%{tanchor_usr} +mkdir -p %{buildroot}%{tanchor_global} + +touch %{buildroot}%{tanchor_bundle} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + ## Devel Package ############################################################### %package devel Summary: Trust Anchor API (development files) @@ -39,6 +85,8 @@ Requires: %{name} = %{version}-%{release} The package provides Trust Anchor API development files. %files devel -%{_includedir}/tanchor/error.h -%{_includedir}/tanchor/trust-anchor.h -%{_includedir}/tanchor/trust-anchor.hxx +%{_includedir}/%{lib_name}/error.h +%{_includedir}/%{lib_name}/trust-anchor.h +%{_includedir}/%{lib_name}/trust-anchor.hxx +%{_libdir}/lib%{lib_name}.so +%{_libdir}/pkgconfig/%{lib_name}.pc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..b8a2919 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (c) 2017 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 +# +# @file CMakeLists.txt +# @author Sangwan Kwon (sangwan.kwon@samsung.com) +# @breif Make trust anchor library +# +PKG_CHECK_MODULES(${TARGET_TANCHOR_LIB}_DEP REQUIRED klay + openssl) + +SET(${TARGET_TANCHOR_LIB}_SRCS ${TANCHOR_SRC}/init-lib.cpp + ${TANCHOR_SRC}/exception.cpp + ${TANCHOR_SRC}/api.cpp + ${TANCHOR_SRC}/certificate.cpp + ${TANCHOR_SRC}/trust-anchor.cpp) + +INCLUDE_DIRECTORIES(SYSTEM ${TANCHOR_INCLUDE} + ${TANCHOR_SRC} + ${${TARGET_TANCHOR_LIB}_DEP_INCLUDE_DIRS}) + +ADD_LIBRARY(${TARGET_TANCHOR_LIB} SHARED ${${TARGET_TANCHOR_LIB}_SRCS}) + +# TODO(sangwan.kwon) visibility needed to be hidden +SET_TARGET_PROPERTIES(${TARGET_TANCHOR_LIB} + PROPERTIES COMPILE_FLAGS "-D_GNU_SOURCE -fPIC -fvisibility=default" + SOVERSION ${API_VERSION} + VERSION ${LIB_VERSION} +) + +TARGET_LINK_LIBRARIES(${TARGET_TANCHOR_LIB} + ${${TARGET_TANCHOR_LIB}_DEP_LIBRARIES} +) + +INSTALL(TARGETS ${TARGET_TANCHOR_LIB} + DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/api.cpp b/src/api.cpp new file mode 100644 index 0000000..890af6c --- /dev/null +++ b/src/api.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file api.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief Implementation of trust anchor CAPI + */ +#include "tanchor/trust-anchor.h" +#include "tanchor/trust-anchor.hxx" + +using namespace tanchor; + +int trust_anchor_global_install(const char *package_id, + const char *app_certificates_path, + bool with_system_certificates) +{ + TrustAnchor ta(package_id, app_certificates_path); + return ta.install(with_system_certificates); +} + +int trust_anchor_usr_install(const char *package_id, + const char *app_certificates_path, + uid_t uid, + bool with_system_certificates) +{ + TrustAnchor ta(package_id, app_certificates_path, uid); + return ta.install(with_system_certificates); +} + +int trust_anchor_global_launch(const char *package_id, + const char *app_certificates_path, + bool with_system_certificates) +{ + TrustAnchor ta(package_id, app_certificates_path); + return ta.launch(with_system_certificates); +} + +int trust_anchor_usr_launch(const char *package_id, + const char *app_certificates_path, + uid_t uid, + bool with_system_certificates) +{ + TrustAnchor ta(package_id, app_certificates_path, uid); + return ta.launch(with_system_certificates); +} + +int trust_anchor_global_uninstall(const char *package_id, + const char *app_certificates_path) +{ + TrustAnchor ta(package_id, app_certificates_path); + return ta.uninstall(); +} + +int trust_anchor_usr_uninstall(const char *package_id, + const char *app_certificates_path, + uid_t uid) +{ + TrustAnchor ta(package_id, app_certificates_path, uid); + return ta.uninstall(); +} diff --git a/src/certificate.cpp b/src/certificate.cpp new file mode 100644 index 0000000..0d9bdd5 --- /dev/null +++ b/src/certificate.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file certificate.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief + */ +#include "certificate.hxx" + +#include +#include +#include + +#include + +namespace tanchor { + +namespace { + +using X509Ptr = std::unique_ptr; + +const std::string START_CERT = "-----BEGIN CERTIFICATE-----"; +const std::string END_CERT = "-----END CERTIFICATE-----"; +const std::string START_TRUSTED = "-----BEGIN TRUSTED CERTIFICATE-----"; +const std::string END_TRUSTED = "-----END TRUSTED CERTIFICATE-----"; + +const int HASH_LENGTH = 8; + +} // namespace anonymous + +Certificate::Certificate(const std::string &path) : + m_fp(FilePtr(fopen(path.c_str(), "rb"), ::fclose)) +{ + if (this->m_fp == nullptr) + throw std::invalid_argument("Faild to open certificate."); +} + +std::string Certificate::getSubjectNameHash() const +{ + X509Ptr x509(::PEM_read_X509(this->m_fp.get(), NULL, NULL, NULL), + ::X509_free); + if (x509 == nullptr) { + ::rewind(this->m_fp.get()); + x509 = X509Ptr(::PEM_read_X509_AUX(this->m_fp.get(), NULL, NULL, NULL), + ::X509_free); + } + + if (x509 == nullptr) + throw std::logic_error("Failed to read certificate."); + + std::vector buf(HASH_LENGTH + 1); + snprintf(buf.data(), buf.size(), + "%08lx", ::X509_subject_name_hash(x509.get())); + + return std::string(buf.data(), HASH_LENGTH); +} + +std::string Certificate::getCertificateData() const +{ + std::fseek(this->m_fp.get(), 0L, SEEK_END); + unsigned int fsize = std::ftell(this->m_fp.get()); + std::rewind(this->m_fp.get()); + + std::string content(fsize, 0); + if (fsize != std::fread(static_cast(&content[0]), 1, fsize, + this->m_fp.get())) + throw std::logic_error("Failed to read certificate from fp."); + + return this->parseData(content); +} + +std::string Certificate::parseData(const std::string &data) const +{ + if (data.empty()) + throw std::logic_error("There is no data to parse."); + + size_t from = data.find(START_CERT); + size_t to = data.find(END_CERT); + size_t tailLen = END_CERT.length(); + + if (from == std::string::npos || to == std::string::npos || from > to) { + from = data.find(START_TRUSTED); + to = data.find(END_TRUSTED); + tailLen = END_TRUSTED.length(); + } + + if (from == std::string::npos || to == std::string::npos || from > to) + throw std::logic_error("Failed to parse certificate."); + + return std::string(data, from, to - from + tailLen); +} + +} // namespace tanchor diff --git a/src/certificate.hxx b/src/certificate.hxx new file mode 100644 index 0000000..d5f8c8a --- /dev/null +++ b/src/certificate.hxx @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file certificate.hxx + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief + */ +#pragma once + +#include +#include +#include + +namespace tanchor { + +using FilePtr = std::unique_ptr; + +class Certificate { +public: + explicit Certificate(const std::string &path); + virtual ~Certificate(void) = default; + + Certificate(const Certificate &) = delete; + Certificate(Certificate &&) = delete; + Certificate &operator=(const Certificate &) = delete; + Certificate &operator=(Certificate &&) = delete; + + std::string getSubjectNameHash() const; + std::string getCertificateData() const; + +private: + std::string parseData(const std::string &data) const; + + FilePtr m_fp; +}; + +} // namespace tanchor diff --git a/src/exception.cpp b/src/exception.cpp new file mode 100644 index 0000000..be360ca --- /dev/null +++ b/src/exception.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file exception.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief Exception guard and custom exceptions + */ +#include "exception.hxx" + +#include + +#include +#include + +namespace tanchor { + +int exceptionGuard(const std::function &func) +{ + // TODO add custom error code + try { + return func(); + } catch (runtime::Exception &e) { + ERROR(e.what()); + return -1; + } catch (const std::invalid_argument &e) { + ERROR("Invalid argument: " << e.what()); + return -1; + } catch (const std::exception &e) { + ERROR(e.what()); + return -1; + } catch (...) { + ERROR("Unknown exception occurred."); + return -1; + } +} + +} // namespace tanchor diff --git a/src/exception.hxx b/src/exception.hxx new file mode 100644 index 0000000..975cb3f --- /dev/null +++ b/src/exception.hxx @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017 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. + */ +/* + * @file exception.h + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief Exception guard and custom exceptions + */ +#pragma once + +#include + +#define EXCEPTION_GUARD_START return tanchor::exceptionGuard([&]() { +#define EXCEPTION_GUARD_END }); + +namespace tanchor { + +int exceptionGuard(const std::function &); + +} // namespace tanchor diff --git a/src/init-lib.cpp b/src/init-lib.cpp new file mode 100644 index 0000000..760c6b1 --- /dev/null +++ b/src/init-lib.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file init-lib.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief Init global configuration for library + */ + +#include +#include + +#include + +namespace tanchor { +namespace { + +class InitLib { +public: + InitLib() + { + audit::Logger::setBackend(new audit::DlogLogSink()); + audit::Logger::setTag("CERT_SVC"); + }; + ~InitLib() = default; +}; + +static std::unique_ptr init(new(std::nothrow)(InitLib)); + +} // namespace anonymous +} // namespace tanchor diff --git a/src/trust-anchor.cpp b/src/trust-anchor.cpp new file mode 100644 index 0000000..58aaef5 --- /dev/null +++ b/src/trust-anchor.cpp @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2017 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 + */ +/* + * @file trust-anchor.cpp + * @author Sangwan Kwon (sangwan.kwon@samsung.com) + * @version 0.1 + * @brief Implementation of trust anchor + */ +#include "tanchor/trust-anchor.hxx" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "certificate.hxx" +#include "exception.hxx" + +namespace tanchor { + +namespace { + +const std::string BASE_USR_PATH(TANCHOR_USR_DIR); +const std::string BASE_GLOBAL_PATH(TANCHOR_GLOBAL_DIR); +const std::string TANCHOR_BUNDLE_PATH(TANCHOR_BUNDLE); +const std::string SYS_CERTS_PATH(TZ_SYS_CA_CERTS); +const std::string SYS_BUNDLE_PATH(TZ_SYS_CA_BUNDLE); +const std::string MOUNT_POINT_CERTS(TZ_SYS_CA_CERTS); +const std::string MOUNT_POINT_BUNDLE(TZ_SYS_CA_BUNDLE); +const std::string BUNDLE_NAME("ca-bundle.pem"); +const std::string NEW_LINE("\n"); + +} // namespace anonymous + +class TrustAnchor::Impl { +public: + explicit Impl(const std::string &packageId, + const std::string &certsDir, + uid_t uid) noexcept; + explicit Impl(const std::string &packageId, + const std::string &certsDir) noexcept; + virtual ~Impl(void) = default; + + int install(bool withSystemCerts) noexcept; + int uninstall(bool isRollback = false) noexcept; + int launch(bool withSystemCerts); + +private: + void preInstall(void) const; + void linkTo(const std::string &src, const std::string &dst) const; + void makeCustomBundle(bool withSystemCerts); + std::string readLink(const std::string &path) const; + std::string getUniqueHashName(const std::string &hashName) const; + bool isSystemCertsModified(void) const; + + std::string m_packageId; + std::string m_appCertsPath; + uid_t m_uid; + + std::string m_customBasePath; + std::string m_customCertsPath; + std::string m_customBundlePath; + + std::set m_customCertNameSet; + std::vector m_customCertsData; +}; + +TrustAnchor::Impl::Impl(const std::string &packageId, + const std::string &certsDir, + uid_t uid) noexcept : + m_packageId(packageId), + m_appCertsPath(certsDir), + m_uid(uid), + m_customBasePath(BASE_USR_PATH + "/" + + std::to_string(static_cast(uid)) + "/" + + packageId), + m_customCertsPath(m_customBasePath + "/certs"), + m_customBundlePath(m_customBasePath + "/bundle"), + m_customCertNameSet(), + m_customCertsData() {} + +TrustAnchor::Impl::Impl(const std::string &packageId, + const std::string &certsDir) noexcept : + m_packageId(packageId), + m_appCertsPath(certsDir), + m_uid(-1), + m_customBasePath(BASE_GLOBAL_PATH + "/" + packageId), + m_customCertsPath(m_customBasePath + "/certs"), + m_customBundlePath(m_customBasePath + "/bundle"), + m_customCertNameSet(), + m_customCertsData() {} + +std::string TrustAnchor::Impl::readLink(const std::string &path) const +{ + std::vector buf(PATH_MAX); + ssize_t count = readlink(path.c_str(), buf.data(), buf.size()); + return std::string(buf.data(), (count > 0) ? count : 0); +} + +void TrustAnchor::Impl::linkTo(const std::string &src, + const std::string &dst) const +{ + errno = 0; + int ret = ::symlink(src.c_str(), dst.c_str()); + if (ret != 0) + throw std::logic_error("Fail to link " + src + " -> " + dst + + "[" + std::to_string(errno) + "]"); +} + +void TrustAnchor::Impl::preInstall(void) const +{ + runtime::File customBaseDir(this->m_customBasePath); + if (customBaseDir.exists()) { + WARN("App custom directory is already exist. remove it!"); + customBaseDir.remove(true); + } + customBaseDir.makeDirectory(true); + + runtime::File customCertsDir(this->m_customCertsPath); + customCertsDir.makeDirectory(); + + runtime::File customBundleDir(this->m_customBundlePath); + customBundleDir.makeDirectory(); + + runtime::File appCertsDir(this->m_appCertsPath); + if (!appCertsDir.exists() || !appCertsDir.isDirectory()) + throw std::invalid_argument("App custom certs path is wrong. : " + + m_appCertsPath); + + DEBUG("Success to pre-install stage."); +} + +int TrustAnchor::Impl::install(bool withSystemCerts) noexcept +{ + EXCEPTION_GUARD_START + + this->preInstall(); + + if (withSystemCerts) { + // link system certificates to the custom directory + runtime::DirectoryIterator iter(SYS_CERTS_PATH), end; + while (iter != end) { + linkTo(readLink(iter->getPath()), + this->m_customCertsPath + "/" + iter->getName()); + this->m_customCertNameSet.emplace(iter->getName()); + ++iter; + } + DEBUG("Success to migrate system certificates."); + } + + // link app certificates to the custom directory as subjectNameHash + runtime::DirectoryIterator iter(this->m_appCertsPath), end; + while (iter != end) { + Certificate cert(iter->getPath()); + std::string hashName = this->getUniqueHashName(cert.getSubjectNameHash()); + linkTo(iter->getPath(), + this->m_customCertsPath + "/" + hashName); + this->m_customCertNameSet.emplace(std::move(hashName)); + + this->m_customCertsData.emplace_back(cert.getCertificateData()); + ++iter; + } + + this->makeCustomBundle(withSystemCerts); + + INFO("Success to install[" << this->m_packageId << + "] to " << this->m_customBasePath); + return 0; + + EXCEPTION_GUARD_END +} + +int TrustAnchor::Impl::uninstall(bool isRollback) noexcept +{ + EXCEPTION_GUARD_START + + runtime::File customBaseDir(this->m_customBasePath); + if (!customBaseDir.exists() && !isRollback) + throw std::invalid_argument("There is no installed anchor previous."); + + if (customBaseDir.exists()) + customBaseDir.remove(true); + + INFO("Success to uninstall. : " << this->m_packageId); + return 0; + + EXCEPTION_GUARD_END +} + +bool TrustAnchor::Impl::isSystemCertsModified(void) const +{ + struct stat systemAttr, customAttr; + + stat(SYS_BUNDLE_PATH.c_str(), &systemAttr); + DEBUG("System bundle mtime : " << ::ctime(&systemAttr.st_mtime)); + + auto customBundle = this->m_customBundlePath + "/" + BUNDLE_NAME; + stat(customBundle.c_str(), &customAttr); + DEBUG("Custom bundle mtime : " << ::ctime(&customAttr.st_mtime)); + + return systemAttr.st_mtime > customAttr.st_mtime; +} + +int TrustAnchor::Impl::launch(bool withSystemCerts) +{ + EXCEPTION_GUARD_START + + if (withSystemCerts && this->isSystemCertsModified()) + this->makeCustomBundle(true); + + errno = 0; + // disassociate from the parent namespace + if (::unshare(CLONE_NEWNS)) + throw std::logic_error("Failed to unshare namespace > " + + std::to_string(errno)); + + // convert it to a slave for preventing propagation + if (::mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) + throw std::logic_error("Failed to disconnect root fs."); + + if (::mount(this->m_customCertsPath.c_str(), + MOUNT_POINT_CERTS.c_str(), + NULL, + MS_BIND, + NULL)) + throw std::logic_error("Failed to mount certs."); + + auto bundle = this->m_customBundlePath + "/" + BUNDLE_NAME; + if (::mount(bundle.c_str(), + MOUNT_POINT_BUNDLE.c_str(), + NULL, + MS_BIND, + NULL)) + throw std::logic_error("Failed to mount bundle."); + + INFO("Success to launch. : " << this->m_packageId); + return 0; + + EXCEPTION_GUARD_END +} + +std::string TrustAnchor::Impl::getUniqueHashName( + const std::string &hashName) const +{ + int sameFileNameCnt = 0; + std::string uniqueName; + do { + uniqueName = hashName + "." + std::to_string(sameFileNameCnt++); + } while (this->m_customCertNameSet.find(uniqueName) != + this->m_customCertNameSet.end()); + + return uniqueName; +} + +void TrustAnchor::Impl::makeCustomBundle(bool withSystemCerts) +{ + runtime::File customBundle(this->m_customBundlePath + "/" + + BUNDLE_NAME); + if (customBundle.exists()) { + WARN("App custom bundle is already exist. remove it!"); + customBundle.remove(); + } + + DEBUG("Start to migrate previous bundle."); + if (withSystemCerts) { + runtime::File sysBundle(SYS_BUNDLE_PATH); + if (!sysBundle.exists()) + throw std::logic_error("There is no system bundle file."); + sysBundle.copyTo(this->m_customBundlePath); + } else { + runtime::File tanchorBundle(TANCHOR_BUNDLE_PATH); + if (!tanchorBundle.exists()) + throw std::logic_error("There is no tanchor bundle file."); + tanchorBundle.copyTo(this->m_customBundlePath); + } + DEBUG("Finish migrating previous bundle."); + + if (this->m_customCertsData.empty()) { + DEBUG("System certificates is changed after TrustAnchor installation."); + runtime::DirectoryIterator iter(this->m_appCertsPath), end; + while (iter != end) { + Certificate cert(iter->getPath()); + this->m_customCertsData.emplace_back(cert.getCertificateData()); + ++iter; + } + } + + DEBUG("Start to add app's certificate to bundle."); + customBundle.open(O_RDWR | O_APPEND); + for (const auto &cert : this->m_customCertsData) { + customBundle.write(cert.c_str(), cert.length()); + customBundle.write(NEW_LINE.c_str(), NEW_LINE.length()); + } + + INFO("Success to make app custom bundle."); +} + +TrustAnchor::TrustAnchor(const std::string &packageId, + const std::string &certsDir, + uid_t uid) noexcept : + m_pImpl(new Impl(packageId, certsDir, uid)) {} + +TrustAnchor::TrustAnchor(const std::string &packageId, + const std::string &certsDir) noexcept : + m_pImpl(new Impl(packageId, certsDir)) {} + +TrustAnchor::~TrustAnchor(void) = default; + +int TrustAnchor::install(bool withSystemCerts) noexcept +{ + if (this->m_pImpl == nullptr) + return -1; + + int ret = this->m_pImpl->install(withSystemCerts); + + if (ret != 0) { + ERROR("Failed to intall ACTA. Remove custom directory for rollback."); + this->m_pImpl->uninstall(true); + } + + return ret; +} + +int TrustAnchor::uninstall(void) noexcept +{ + if (this->m_pImpl == nullptr) + return -1; + + return this->m_pImpl->uninstall(); +} + +int TrustAnchor::launch(bool withSystemCerts) noexcept +{ + if (this->m_pImpl == nullptr) + return -1; + + return this->m_pImpl->launch(withSystemCerts); +} + +} // namespace tanchor