Add implemetation of trust-anchor library 04/120004/1
authorsangwan.kwon <sangwan.kwon@samsung.com>
Thu, 16 Mar 2017 13:12:14 +0000 (22:12 +0900)
committersangwan.kwon <sangwan.kwon@samsung.com>
Mon, 20 Mar 2017 02:31:21 +0000 (11:31 +0900)
Change-Id: Id8ea3c9d3c18806daa310b1455064530640fd9b7
Signed-off-by: sangwan.kwon <sangwan.kwon@samsung.com>
15 files changed:
CMakeLists.txt
api/CMakeLists.txt
lib/CMakeLists.txt [new file with mode: 0644]
lib/tanchor.pc.in [new file with mode: 0644]
packaging/trust-anchor.manifest [deleted file]
packaging/trust-anchor.manifest.in [new file with mode: 0644]
packaging/trust-anchor.spec
src/CMakeLists.txt [new file with mode: 0644]
src/api.cpp [new file with mode: 0644]
src/certificate.cpp [new file with mode: 0644]
src/certificate.hxx [new file with mode: 0644]
src/exception.cpp [new file with mode: 0644]
src/exception.hxx [new file with mode: 0644]
src/init-lib.cpp [new file with mode: 0644]
src/trust-anchor.cpp [new file with mode: 0644]

index 3026802..79b4dfe 100644 (file)
@@ -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)
index 92506c9..5619784 100644 (file)
@@ -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 (file)
index 0000000..3182ce6
--- /dev/null
@@ -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 (file)
index 0000000..4a9e58b
--- /dev/null
@@ -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 (file)
index a76fdba..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<manifest>
-       <request>
-               <domain name="_" />
-       </request>
-</manifest>
diff --git a/packaging/trust-anchor.manifest.in b/packaging/trust-anchor.manifest.in
new file mode 100644 (file)
index 0000000..b5de845
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+       <assign>
+               <filesystem path="@TANCHOR_BASE@" label="@SMACK_LABEL@" type="transmutable" />
+       </assign>
+</manifest>
index a3e2110..e21c10f 100644 (file)
@@ -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 (file)
index 0000000..b8a2919
--- /dev/null
@@ -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 (file)
index 0000000..890af6c
--- /dev/null
@@ -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 (file)
index 0000000..0d9bdd5
--- /dev/null
@@ -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 <cstdio>
+#include <vector>
+#include <stdexcept>
+
+#include <openssl/pem.h>
+
+namespace tanchor {
+
+namespace {
+
+using X509Ptr = std::unique_ptr<X509, decltype(&::X509_free)>;
+
+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<char> 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<void*>(&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 (file)
index 0000000..d5f8c8a
--- /dev/null
@@ -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 <string>
+#include <memory>
+#include <cstdio>
+
+namespace tanchor {
+
+using FilePtr = std::unique_ptr<FILE, decltype(&::fclose)>;
+
+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 (file)
index 0000000..be360ca
--- /dev/null
@@ -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 <exception>
+
+#include <klay/exception.h>
+#include <klay/audit/logger.h>
+
+namespace tanchor {
+
+int exceptionGuard(const std::function<int()> &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 (file)
index 0000000..975cb3f
--- /dev/null
@@ -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 <functional>
+
+#define EXCEPTION_GUARD_START return tanchor::exceptionGuard([&]() {
+#define EXCEPTION_GUARD_END   });
+
+namespace tanchor {
+
+int exceptionGuard(const std::function<int()> &);
+
+} // namespace tanchor
diff --git a/src/init-lib.cpp b/src/init-lib.cpp
new file mode 100644 (file)
index 0000000..760c6b1
--- /dev/null
@@ -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 <klay/audit/logger.h>
+#include <klay/audit/dlog-sink.h>
+
+#include <memory>
+
+namespace tanchor {
+namespace {
+
+class InitLib {
+public:
+       InitLib()
+       {
+               audit::Logger::setBackend(new audit::DlogLogSink());
+               audit::Logger::setTag("CERT_SVC");
+       };
+       ~InitLib() = default;
+};
+
+static std::unique_ptr<InitLib> 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 (file)
index 0000000..58aaef5
--- /dev/null
@@ -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 <climits>
+#include <cerrno>
+#include <ctime>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <set>
+#include <vector>
+
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+
+#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<std::string> m_customCertNameSet;
+       std::vector<std::string> 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<int>(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<char> 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