--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+##### Configure project version, especially when using
+##### outdated tools like CMake v2
+
+IF(POLICY CMP0048)
+ CMAKE_POLICY(SET CMP0048 NEW)
+ENDIF()
+
+IF(POLICY CMP0069)
+ CMAKE_POLICY(SET CMP0069 NEW)
+ENDIF()
+
+IF(CMAKE_VERSION VERSION_LESS 3.0)
+ PROJECT(device-certificate-manager CXX C)
+ SET(PROJECT_VERSION "1.0")
+ELSE()
+ PROJECT(device-certificate-manager VERSION 1.0 LANGUAGES C CXX)
+ENDIF()
+
+INCLUDE(GNUInstallDirs)
+
+IF(NOT (CMAKE_VERSION VERSION_LESS 3.9))
+ INCLUDE(CheckIPOSupported)
+ check_ipo_supported(RESULT IPO_ALLOWED)
+ELSE()
+ SET(IPO_ALLOWED YES)
+ENDIF()
+
+find_package(Threads REQUIRED)
+
+INCLUDE(cmake/CheckFrameworks.cmake)
+INCLUDE(cmake/CStandard.cmake)
+
+SET(ENABLE_DUMMY_BACKEND OFF)
+
+IF(NOT ARTIK_SECURITY_FOUND)
+ SET(ENABLE_DUMMY_BACKEND ON)
+ message(WARNING "Dummy backend enabled as no usable frameworks found")
+ENDIF()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dcm_build_config.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/dcm_build_config.h)
+
+configure_file(packaging/device-certificate-manager-tests.manifest.in
+ ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager-tests.manifest)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(shared)
+
+SET(DCM_UNIX_SOCKET_PATH "/run/device-certificate-manager.socket")
+add_definitions(-DDCM_UNIX_SOCKET_PATH="${DCM_UNIX_SOCKET_PATH}")
+
+add_subdirectory(dcm-daemon)
+add_subdirectory(dcm-client)
+add_subdirectory(tests)
+add_subdirectory(tools)
+
+add_subdirectory(systemd)
--- /dev/null
+Copyright (c) 2000 - 2015 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.
--- /dev/null
+IF(CMAKE_VERSION VERSION_LESS 3.1)
+ include(CheckCXXCompilerFlag)
+ include(CheckCCompilerFlag)
+
+ message(STATUS "Using old cmake, will detect C++11 and C11 manually")
+
+ CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+ CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
+ CHECK_CXX_COMPILER_FLAG("-std=gnu++11" COMPILER_SUPPORTS_GNUXX11)
+ CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" COMPILER_SUPPORTS_GNUXX0X)
+ CHECK_CXX_COMPILER_FLAG("/std:c++14" COMPILER_SUPPORTS_STDCXX14)
+ CHECK_CXX_COMPILER_FLAG("/std:c++latest" COMPILER_SUPPORTS_STDCXXLATEST)
+
+ IF(COMPILER_SUPPORTS_CXX11)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "-std=c++11")
+ ELSEIF(COMPILER_SUPPORTS_CXX0X)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "-std=c++0x")
+ ELSEIF(COMPILER_SUPPORTS_GNUXX11)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "-std=gnu++11")
+ ELSEIF(COMPILER_SUPPORTS_GNUXX0X)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "-std=gnu++0x")
+ ELSEIF(COMPILER_SUPPORTS_STDCXXLATEST)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "/std:c++latest")
+ ELSEIF(COMPILER_SUPPORTS_STDCXX14)
+ SET(OLD_CMAKE_CXXFLAGS_CXX11 "/std:c++14")
+ ELSE()
+ MESSAGE(FATAL_ERROR "No known way to enable C++11. Please upgrade cmake or compiler")
+ ENDIF()
+
+ CHECK_C_COMPILER_FLAG("-std=c11" COMPILER_SUPPORTS_C11)
+ CHECK_C_COMPILER_FLAG("-std=gnu11" COMPILER_SUPPORTS_GNU11)
+
+ IF(COMPILER_SUPPORTS_C11)
+ SET(OLD_CMAKE_CLAGS_C11 "-std=c11")
+ ELSEIF(COMPILER_SUPPORTS_GNU11)
+ SET(OLD_CMAKE_CLAGS_C11 "-std=gnu11")
+ ELSE()
+ IF((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_C_COMPILER_ID MATCHES "GNU"))
+ MESSAGE(FATAL_ERROR "Can't find way to enable C11")
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+MACRO(ApplyCxx11Standard TargetName)
+ IF(CMAKE_VERSION VERSION_LESS 3.1)
+ IF(NOT __OLD_CMAKE_CXX11_ALREADY_APPLIED)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OLD_CMAKE_CXXFLAGS_CXX11}")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OLD_CMAKE_CLAGS_C11}")
+ SET(__OLD_CMAKE_CXX11_ALREADY_APPLIED TRUE)
+ ENDIF()
+ ELSE()
+ set_property(TARGET ${TargetName}
+ PROPERTY
+ CXX_STANDARD 11)
+ set_property(TARGET ${TargetName}
+ PROPERTY
+ CXX_STANDARD_REQUIRED TRUE)
+ set_property(TARGET ${TargetName}
+ PROPERTY
+ C_STANDARD 11)
+ set_property(TARGET ${TargetName}
+ PROPERTY
+ C_STANDARD_REQUIRED TRUE)
+ ENDIF()
+ENDMACRO(ApplyCxx11Standard)
--- /dev/null
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckIncludeFileCXX)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckIncludeFiles)
+
+CHECK_INCLUDE_FILE("pkix_interface.h" HAVE_PKIX_INTERFACE)
+
+FIND_PACKAGE(Boost 1.54
+ REQUIRED
+ COMPONENTS
+ serialization
+ filesystem
+ program_options
+ log
+ thread
+ system
+ )
+
+FIND_PACKAGE(PkgConfig REQUIRED)
+
+PKG_CHECK_MODULES(ARTIK_SECURITY artik-security)
+
+IF(ARTIK_SECURITY_FOUND)
+ SET(HAVE_ARTIK_SECURITY_LIBRARY TRUE)
+ENDIF()
+
+PKG_CHECK_MODULES(DLOG dlog)
+
+PKG_CHECK_MODULES(SECURITY_MANAGER security-manager)
+
+CHECK_FUNCTION_EXISTS(fork HAVE_FORK)
+
+find_package(Protobuf REQUIRED)
+
+#### Find mbedtls ####
+
+find_library(MBEDTLS_LIB
+ mbedtls)
+
+find_library(MBEDCRYPTO_LIB
+ mbedcrypto)
+
+IF(MBEDTLS_LIB-NOTFOUND)
+ message(FATAL_ERROR "mbedtls not found ...")
+ENDIF()
+
+IF(MBEDCRYPTO_LIB-NOTFOUND)
+ message(FATAL_ERROR "mbedcrypto not found ...")
+ENDIF()
+
+CHECK_INCLUDE_FILES("mbedtls/rsa.h;mbedtls/ecdsa.h" MBEDTLS_HEADERS_OK)
+
+IF(NOT MBEDTLS_HEADERS_OK)
+ message(FATAL_ERROR "No mbedtls headers")
+ENDIF()
+
+PKG_CHECK_MODULES(SYSTEMD libsystemd)
+
+PKG_CHECK_MODULES(SMACK libsmack)
--- /dev/null
+#cmakedefine HAVE_PKIX_INTERFACE
+#cmakedefine HAVE_ARTIK_SECURITY_LIBRARY
+#cmakedefine HAVE_FORK
+
+#define PROJECT_VERSION "@PROJECT_VERSION@"
--- /dev/null
+#
+# DCM client library build script
+# Jaroslaw Pelczar <j.pelczar@samsung.com>
+#
+
+include(GenerateExportHeader)
+
+configure_file(device-certificate-manager.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager.pc
+ @ONLY)
+
+###### Include and library directories ######
+
+IF(DLOG_FOUND)
+ include_directories(${DLOG_INCLUDE_DIRS})
+ link_directories(${DLOG_LIBRARY_DIRS})
+ add_definitions(-DUSE_DLOG_LOGGING=1)
+ENDIF()
+
+include_directories(${PROTOBUF_INCLUDE_DIRS})
+link_directories(${PROTOBUF_LIBRARY_DIRS})
+
+include_directories(${Boost_INCLUDE_DIRS})
+link_directories(${Boost_LIBRARY_DIRS})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+###### Protobuf generator #######
+
+PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS dcm_support.proto)
+
+###### Library sources ######
+
+add_library(device-certificate-manager
+ SHARED
+ dcmclient.cpp
+ dcm_hw_interface.cpp
+ ../shared/protobuf_asio.cpp
+ ${PROTO_SRCS}
+ ${PROTO_HDRS})
+
+###### Export header generation ######
+
+GENERATE_EXPORT_HEADER(device-certificate-manager
+ BASE_NAME DEVICE_CERTIFICATE_MANAGER
+ PREFIX_NAME API_
+ )
+
+###### Linking ######
+
+ApplyCxx11Standard(device-certificate-manager)
+
+target_link_libraries(device-certificate-manager
+ ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${PROTOBUF_LIBRARIES}
+ ${MBEDTLS_LIB}
+ ${MBEDCRYPTO_LIB})
+
+IF(DLOG_FOUND)
+ target_link_libraries(device-certificate-manager ${DLOG_LIBRARIES})
+ENDIF()
+
+###### Properties of library ######
+
+set_property(TARGET device-certificate-manager PROPERTY DEFINE_SYMBOL DEVICE_CERTIFICATE_MANAGER_EXPORT)
+set_property(TARGET device-certificate-manager PROPERTY VISIBILITY_INLINES_HIDDEN TRUE)
+set_property(TARGET device-certificate-manager PROPERTY VERSION 1.0)
+set_property(TARGET device-certificate-manager PROPERTY C_VISIBILITY_PRESET hidden)
+set_property(TARGET device-certificate-manager PROPERTY CXX_VISIBILITY_PRESET hidden)
+
+###### Installation ######
+
+install(TARGETS device-certificate-manager
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/device_certificate_manager_export.h
+ dcm_client.h
+ dcm_hw_interface.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_CLIENT_DCM_CLIENT_H_
+#define DCM_CLIENT_DCM_CLIENT_H_
+
+#include "device_certificate_manager_export.h"
+#include <memory>
+#include <vector>
+#include <mbedtls/md.h>
+
+class API_DEVICE_CERTIFICATE_MANAGER_EXPORT dcm_client_connection :
+ public std::enable_shared_from_this<dcm_client_connection>
+{
+private:
+ dcm_client_connection(const dcm_client_connection&) = delete;
+ dcm_client_connection& operator = (const dcm_client_connection&) = delete;
+
+protected:
+ dcm_client_connection() API_DEVICE_CERTIFICATE_MANAGER_NO_EXPORT;
+ virtual ~dcm_client_connection() API_DEVICE_CERTIFICATE_MANAGER_NO_EXPORT;
+
+public:
+ /*!
+ * Initialize default instance of the client connection.
+ *
+ * Standard C++ exceptions may be thrown in case of error
+ */
+ static std::shared_ptr<dcm_client_connection> create();
+
+ /*!
+ * Associate key context with this object. This function can be called
+ * only once. This function doesn't throw any exceptions.
+ */
+ virtual bool create_context(const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) noexcept = 0;
+
+
+ /*!
+ * Request certificate chain associated with this context
+ */
+ virtual int get_certificate_chain(std::vector<uint8_t>& chain) noexcept = 0;
+
+ /*!
+ * Return name of key type (UNKNOWN, RSA or ECDSA for now)
+ */
+ virtual const std::string& key_type() const noexcept = 0;
+
+ /*!
+ * Return length of the crypto key in bits
+ */
+ virtual unsigned int key_length() const noexcept = 0;
+
+ /*!
+ * Sign data with context certificate
+ *
+ * This function returns error codes from the mbedtls error value space
+ */
+ virtual int sign_data(mbedtls_md_type_t digestType,
+ const void * hash_data, size_t hash_size,
+ std::vector<uint8_t>& digest) noexcept = 0;
+};
+
+#endif /* DCM_CLIENT_DCM_CLIENT_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_CLIENT_DCM_CLIENT_P_H_
+#define DCM_CLIENT_DCM_CLIENT_P_H_
+
+#include "dcm_client.h"
+#include "dcm_support.pb.h"
+#include <memory>
+#include <mutex>
+#include <array>
+#include <boost/asio.hpp>
+
+class API_DEVICE_CERTIFICATE_MANAGER_NO_EXPORT dcm_client_connection_impl final : public dcm_client_connection
+{
+public:
+ dcm_client_connection_impl();
+ dcm_client_connection_impl(boost::asio::io_service& ioService);
+ virtual ~dcm_client_connection_impl();
+
+ bool create_context(const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) noexcept override;
+
+ int get_certificate_chain(std::vector<uint8_t>& chain) noexcept override;
+
+ const std::string& key_type() const noexcept override;
+
+ unsigned int key_length() const noexcept override;
+
+ int sign_data(mbedtls_md_type_t digestType,
+ const void * hash_data, size_t hash_size,
+ std::vector<uint8_t>& digest) noexcept override;
+
+ void sendReceive(RequestMessage& request, ResponseMessage& response);
+
+private:
+ void ensureSocketConnected();
+
+
+private:
+ boost::asio::io_service fIOService;
+ std::mutex fLock;
+ uint64_t fCookie = 0;
+ std::unique_ptr<boost::asio::local::stream_protocol::socket> fSocket;
+ CryptoKeyType fKeyType = CRYPTO_KEY_TYPE_INVALID;
+ unsigned int fKeyLength = 0;
+};
+
+#endif /* DCM_CLIENT_DCM_CLIENT_P_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dcm_hw_interface.h"
+#include "dcm_client.h"
+#include <mbedtls/pk_internal.h>
+#include <mbedtls/rsa.h>
+#include <mbedtls/pk.h>
+#include <vector>
+#include <cstring>
+#include <map>
+#include <mutex>
+
+#ifdef USE_DLOG_LOGGING
+#define LOG_TAG "dcm-client"
+#include <dlog.h>
+#endif
+
+struct dcm_key_context_internal {
+ std::shared_ptr<dcm_client_connection> connection;
+ std::vector<uint8_t> cached_cert_chain;
+ mbedtls_pk_info_t ec_info;
+};
+
+static std::map<const void *, std::weak_ptr<dcm_client_connection>> sEDCSAContexts;
+static std::mutex sEDCSAContextsMutex;
+
+void* DCM_HWGetKeyContext(const char* service, const char* usage, const char* keytype) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("Create new context for");
+#endif
+
+ try {
+ std::unique_ptr<dcm_key_context_internal> context(new dcm_key_context_internal());
+
+ std::string service_string(service ? service : "");
+ std::string usage_string(usage ? usage : "");
+ std::string keytype_string(keytype ? keytype : "");
+
+ context->connection = dcm_client_connection::create();
+
+ if(!context->connection->create_context(service_string,
+ usage_string,
+ keytype_string))
+ {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Can't create connection context");
+#endif
+ return nullptr;
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("Created context %p", context.get());
+#endif
+
+ return context.release();
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Context creation failure");
+#endif
+ return nullptr;
+ }
+}
+
+int DCM_HWFreeKeyContext(void* keyContext)
+{
+ if(!keyContext) {
+ return HWIF_ERR_INVALID_PARAM;
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("Delete context %p", keyContext);
+#endif
+
+ delete reinterpret_cast<dcm_key_context_internal *>(keyContext);
+
+ return HWIF_SUCCESS;
+}
+
+int DCM_HWGetOwnCertificateChain(const void* keyContext,
+ unsigned char** cert_chain, size_t* cert_chain_len)
+{
+ dcm_key_context_internal * context = reinterpret_cast<dcm_key_context_internal *>(
+ const_cast<void *>(keyContext));
+
+ if(!keyContext || !cert_chain || !cert_chain_len) {
+ return HWIF_ERR_INVALID_PARAM;
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("Request certificate chain for session %p", keyContext);
+#endif
+
+ if(!context->cached_cert_chain.empty()) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("Use cached certificate chain");
+#endif
+
+ *cert_chain = &context->cached_cert_chain[0];
+ *cert_chain_len = context->cached_cert_chain.size();
+ return HWIF_SUCCESS;
+ }
+
+ int result;
+
+ if((result = context->connection->get_certificate_chain(context->cached_cert_chain)) == 0) {
+ *cert_chain = &context->cached_cert_chain[0];
+ *cert_chain_len = context->cached_cert_chain.size();
+ }
+
+ return result;
+}
+
+static int pk_rsa_alt_decrypt_func( void *ctx, int mode, size_t *olen,
+ const unsigned char *input, unsigned char *output,
+ size_t output_max_len )
+{
+#ifdef USE_DLOG_LOGGING
+ LOGE("Can't use this API to decrypt RSA data");
+#endif
+
+ return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+}
+
+static int pk_rsa_alt_sign_func( void *ctx,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+ int mode, mbedtls_md_type_t md_alg, unsigned int hashlen,
+ const unsigned char *hash, unsigned char *sig )
+{
+ if(!ctx) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ if(mode != MBEDTLS_RSA_PRIVATE) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ dcm_key_context_internal * context = reinterpret_cast<dcm_key_context_internal *>(ctx);
+
+ try {
+ std::vector<uint8_t> digest;
+
+ int error = context->connection->sign_data(md_alg,
+ hash,
+ hashlen,
+ digest);
+
+ if(error == 0) {
+ if(digest.size() > MBEDTLS_MPI_MAX_SIZE) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ memcpy(sig, &digest[0], digest.size());
+ }
+
+ return error;
+ } catch(...) {
+ return MBEDTLS_ERR_PK_ALLOC_FAILED;
+ }
+}
+
+
+static size_t pk_rsa_alt_key_len_func( void *ctx )
+{
+ if(!ctx) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ dcm_key_context_internal * context = reinterpret_cast<dcm_key_context_internal *>(ctx);
+
+ return (context->connection->key_length() + 7) / 8;
+}
+
+static int SetupRSAContext(mbedtls_pk_context* ctx, void* key_context) {
+ return mbedtls_pk_setup_rsa_alt(ctx,
+ key_context,
+ pk_rsa_alt_decrypt_func,
+ pk_rsa_alt_sign_func,
+ pk_rsa_alt_key_len_func) ? HWIF_ERROR : HWIF_SUCCESS;
+}
+
+static int ecdsa_sign_alt( void *ctx, mbedtls_md_type_t md_alg,
+ const unsigned char *hash, size_t hash_len,
+ unsigned char *sig, size_t *sig_len,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
+{
+ if(!ctx) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ std::unique_lock<std::mutex> locker(sEDCSAContextsMutex);
+ auto context = sEDCSAContexts[ctx].lock();
+
+ if(!context) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Trying to sign ECDSA data on deleted context");
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ locker.unlock();
+
+ try {
+ std::vector<uint8_t> digest;
+
+ int error = context->sign_data(md_alg,
+ hash,
+ hash_len,
+ digest);
+
+ if(error == 0) {
+ if(digest.size() > MBEDTLS_MPI_MAX_SIZE) {
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ memcpy(sig, &digest[0], digest.size());
+ *sig_len = digest.size();
+ }
+
+ return error;
+ } catch(...) {
+ return MBEDTLS_ERR_PK_ALLOC_FAILED;
+ }
+}
+
+static void eckey_free_wrap_alt( void *ctx )
+{
+ const mbedtls_pk_info_t *mbedtls_ec_info;
+ mbedtls_ec_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
+ mbedtls_ec_info->ctx_free_func(ctx);
+ std::unique_lock<std::mutex> locker(sEDCSAContextsMutex);
+ sEDCSAContexts.erase(ctx);
+}
+
+static size_t eckey_get_bitlen_alt( const void *ctx )
+{
+ std::unique_lock<std::mutex> locker(sEDCSAContextsMutex);
+ auto context = sEDCSAContexts[ctx].lock();
+
+ if(!context) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Trying to sign ECDSA data on deleted context");
+#endif
+ return 0;
+ }
+
+ return context->key_length();
+}
+
+static int SetupECDSAContext(mbedtls_pk_context* ctx, void* key_context) {
+ const mbedtls_pk_info_t *mbedtls_ec_info;
+ dcm_key_context_internal * context = reinterpret_cast<dcm_key_context_internal *>(key_context);
+
+ mbedtls_ec_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
+
+ if(!mbedtls_ec_info) {
+ return HWIF_ERROR;
+ }
+
+ context->ec_info = *mbedtls_ec_info;
+ context->ec_info.sign_func = ecdsa_sign_alt;
+ context->ec_info.ctx_free_func = eckey_free_wrap_alt;
+ context->ec_info.get_bitlen = eckey_get_bitlen_alt;
+
+ if(mbedtls_pk_setup(ctx, &context->ec_info)) {
+ return HWIF_ERROR;
+ }
+
+ try {
+ std::unique_lock<std::mutex> locker(sEDCSAContextsMutex);
+ sEDCSAContexts.emplace(ctx->pk_ctx, context->connection);
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Got exception when inserting to map");
+#endif
+ mbedtls_pk_free(ctx);
+ return HWIF_ERR_OUT_OF_MEMORY;
+ }
+
+ return HWIF_SUCCESS;
+}
+
+int DCM_HWSetupPkContext(mbedtls_pk_context* ctx, void* key_context)
+{
+ dcm_key_context_internal * context = reinterpret_cast<dcm_key_context_internal *>(key_context);
+
+ if(!context || !ctx) {
+ return HWIF_ERR_INVALID_PARAM;
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("Setup PK context %p with key context %p", ctx, key_context);
+#endif
+
+ const auto& key_type(context->connection->key_type());
+
+ if(key_type == "RSA") {
+ return SetupRSAContext(ctx, key_context);
+ } else if(key_type == "ECDSA") {
+ return SetupECDSAContext(ctx, key_context);
+ } else {
+#ifdef USE_DLOG_LOGGING
+ LOGE("Unsupported key type received from server");
+#endif
+ }
+
+ return HWIF_ERR_INVALID_PARAM;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_CLIENT_DCM_HW_INTERFACE_H_
+#define DCM_CLIENT_DCM_HW_INTERFACE_H_
+
+#include "device_certificate_manager_export.h"
+#include <mbedtls/ssl.h>
+#include <errno.h>
+
+/**
+ * Error-definition for hw interface
+ */
+
+typedef enum HwifResult {
+ HWIF_ERR_INVALID_PARAM = -EINVAL, /**< Invalid Paramter */
+ HWIF_ERR_OUT_OF_MEMORY = -ENOMEM, /**< Out of memory */
+ HWIF_ERR_NO_DATA = -ENODATA, /**< No data found */
+ HWIF_ERROR = -EFAULT, /**< Internal Error */
+ HWIF_SUCCESS = 0, /**< No Error */
+} HwifResult_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This callback will be invoked to get a key context based on specific name indication
+ * (service name, key usage, key type). The key context may be same with the alias name.
+ *
+ * @param[in] service service name indicates first category name
+ * @param[in] usage usage name indicates sub-category name
+ * @param[in] keytype (optional) key type name indication if any, otherwise it usually will be NULL
+ * @return void type pointer value on success, otherwise NULL
+ */
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT void* DCM_HWGetKeyContext(const char* service, const char* usage, const char* keytype);
+
+/**
+ * This callback will deallocate the key context that was retrieved from TZ
+ * by calling GetHwKeyContext callback.
+ *
+ * @param[in] keyContext key context object to be deallocated,
+ * which was obtained from GetHwKeyContext callback function
+ * @return 0 on success, otherwise a negative value
+ */
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT int DCM_HWFreeKeyContext(void* keyContext);
+
+/**
+ * This callback will be invoked to load own(i.e., pre-injected) certificate from HW(e.g., TZ, eSE)
+ *
+ * @param[in] keyContext key context object that identifies proper certificate chain
+ * @param[out] cert_chain certificate chain in binary
+ * @param[out] cert_chain_len total length of certificate chain
+ * @return 0 on success, otherwise a negative value
+ */
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT int DCM_HWGetOwnCertificateChain(const void* keyContext,
+ unsigned char** cert_chain, size_t* cert_chain_len);
+
+/**
+ * This callback should provide setting up alternative functions (e.g., rsa_sign, key_len, etc)
+ * of which HW(e.g., TZ, eSE) management library to the specified mbedtls context
+ * that will be used during handshake.
+ *
+ * @param[in] ctx pointer of pk context of mbedtls
+ * @param[in] keyContext key context object that identifies proper public/private key
+ * @return 0 on success, otherwise a negative value
+ */
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT int DCM_HWSetupPkContext(mbedtls_pk_context* ctx, void* key_context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DCM_CLIENT_DCM_HW_INTERFACE_H_ */
--- /dev/null
+syntax = "proto2";
+
+/*
+ * Type of the crypto key
+ */
+enum CryptoKeyType {
+ CRYPTO_KEY_TYPE_INVALID = 0;
+ CRYPTO_KEY_TYPE_ECDSA = 1;
+ CRYPTO_KEY_TYPE_RSA = 2;
+}
+
+/*
+ * These values match the mbedtls ones
+ */
+enum MessageDigestType {
+ MD_NONE = 0;
+ MD_MD2 = 1;
+ MD_MD4 = 2;
+ MD_MD5 = 3;
+ MD_SHA1 = 4;
+ MD_SHA224 = 5;
+ MD_SHA256 = 6;
+ MD_SHA384 = 7;
+ MD_SHA512 = 8;
+ MD_RIPEMD160 = 9;
+}
+
+message AssociateKeyContext
+{
+ required string service = 1;
+ required string usage = 2;
+ required string key_type = 3;
+}
+
+message AssociateKeyContextResponse
+{
+ required int32 result = 1;
+ optional uint64 context_cookie = 2;
+ optional CryptoKeyType key_type = 3;
+ optional uint32 key_length = 4;
+}
+
+message RequestCertificateChain
+{
+ required uint64 context_cookie = 1;
+}
+
+message RequestCertificateChainResponse
+{
+ required int32 result = 1;
+ optional bytes cert_chain = 2;
+}
+
+message SignRequest
+{
+ required uint64 context_cookie = 1;
+ required bytes data_to_sign = 2;
+ required MessageDigestType digest_type = 3;
+}
+
+message SignResponse
+{
+ required int32 result = 1;
+ optional bytes signature = 2;
+}
+
+message RequestMessage {
+ oneof request_oneof {
+ AssociateKeyContext associate_context = 1;
+ RequestCertificateChain request_chain = 2;
+ SignRequest sign_data = 3;
+ }
+}
+
+message ResponseMessage {
+ oneof reply_oneof {
+ AssociateKeyContextResponse associate_context = 1;
+ RequestCertificateChainResponse request_chain = 2;
+ SignResponse sign_data = 3;
+ }
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dcm_client_p.h"
+#include "dcm_support.pb.h"
+#include "dcm_hw_interface.h"
+#include <cassert>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <protobuf_asio.h>
+#include <inttypes.h>
+#ifdef USE_DLOG_LOGGING
+#define LOG_TAG "dcm-client"
+#include <dlog.h>
+#endif
+
+static_assert(MD_NONE == (unsigned int)MBEDTLS_MD_NONE, "MBEDTLS_MD_NONE mismatch");
+static_assert(MD_MD2 == (unsigned int)MBEDTLS_MD_MD2, "MBEDTLS_MD_MD2 mismatch");
+static_assert(MD_MD4 == (unsigned int)MBEDTLS_MD_MD4, "MBEDTLS_MD_MD4 mismatch");
+static_assert(MD_MD5 == (unsigned int)MBEDTLS_MD_MD5, "MBEDTLS_MD_MD5 mismatch");
+static_assert(MD_SHA1 == (unsigned int)MBEDTLS_MD_SHA1, "MBEDTLS_MD_SHA1 mismatch");
+static_assert(MD_SHA224 == (unsigned int)MBEDTLS_MD_SHA224, "MBEDTLS_MD_SHA224 mismatch");
+static_assert(MD_SHA256 == (unsigned int)MBEDTLS_MD_SHA256, "MBEDTLS_MD_SHA256 mismatch");
+static_assert(MD_SHA384 == (unsigned int)MBEDTLS_MD_SHA384, "MBEDTLS_MD_SHA384 mismatch");
+static_assert(MD_SHA512 == (unsigned int)MBEDTLS_MD_SHA512, "MBEDTLS_MD_SHA512 mismatch");
+static_assert(MD_RIPEMD160 == (unsigned int)MBEDTLS_MD_RIPEMD160, "MBEDTLS_MD_RIPEMD160 mismatch");
+
+static std::string sKeyTypeUnknown("UNKNOWN");
+static std::string sKeyTypeRSA("RSA");
+static std::string sKeyTypeECDSA("ECDSA");
+
+dcm_client_connection_impl::dcm_client_connection_impl()
+{
+}
+
+dcm_client_connection_impl::~dcm_client_connection_impl()
+{
+}
+
+dcm_client_connection::dcm_client_connection()
+{
+#ifdef USE_DLOG_LOGGING
+ LOGD("dcm_client_connection: Allocated new client connection at %p", this);
+#endif
+}
+
+dcm_client_connection::~dcm_client_connection()
+{
+#ifdef USE_DLOG_LOGGING
+ LOGD("dcm_client_connection: Deallocated client connection at %p", this);
+#endif
+}
+
+std::shared_ptr<dcm_client_connection> dcm_client_connection::create()
+{
+ return std::make_shared<dcm_client_connection_impl>();
+}
+
+void dcm_client_connection_impl::sendReceive(RequestMessage& request, ResponseMessage& response)
+{
+#ifdef USE_DLOG_LOGGING
+ LOGD("Send request to server in connection %p of type %d", this, request.request_oneof_case());
+#endif
+
+ protobuf_sync_message_serialization(*fSocket).encodeMessage(request);
+
+ protobuf_sync_message_deserialization(*fSocket).decodeMessage(response);
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("Received response from server in connection %p of type %d", this, response.reply_oneof_case());
+#endif
+}
+
+bool dcm_client_connection_impl::create_context(const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) noexcept
+{
+ std::lock_guard<std::mutex> locker(fLock);
+
+ if(fCookie) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Cookie has already been requested for session %p", __FUNCTION__, this);
+#endif
+ // Already created
+ return false;
+ }
+
+ if(!fSocket) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Ensure that socket is connected for session %p", __FUNCTION__, this);
+#endif
+ try {
+ ensureSocketConnected();
+ } catch(std::exception& ex) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Caught exception \"%s\" when connecting socket for session %p", __FUNCTION__, ex.what(), this);
+#endif
+ return false;
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Caught unknown exception when connecting socket for session %p", __FUNCTION__, this);
+#endif
+ return false;
+ }
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Connection established. Requesting cookie", __FUNCTION__);
+#endif
+
+ try {
+ RequestMessage request;
+ ResponseMessage response;
+
+ auto * assoc_req = request.mutable_associate_context();
+
+ assoc_req->set_service(serviceName);
+ assoc_req->set_usage(usage);
+ assoc_req->set_key_type(key_type);
+
+ sendReceive(request, response);
+
+ if(!response.has_associate_context()) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: received response is not context association message in context %p", __FUNCTION__, this);
+#endif
+ return false;
+ }
+
+ auto& assoc_message(response.associate_context());
+
+ if(assoc_message.result() != 0) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Received context association message with error %d in %p", __FUNCTION__, assoc_message.result(), this);
+#endif
+ return false;
+ }
+
+ fCookie = assoc_message.context_cookie();
+ fKeyType = assoc_message.key_type();
+ fKeyLength = assoc_message.key_length();
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Received cookie %" PRIx64 " with key type %s and length %zd for session %p",
+ __FUNCTION__,
+ fCookie,
+ this->key_type().c_str(),
+ fKeyLength,
+ this);
+#endif
+ } catch(std::exception& ex) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Caught exception \"%s\" when establishing cookie for session %p", __FUNCTION__, ex.what(), this);
+#endif
+ fSocket.reset();
+ return false;
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Caught unknown exception when establishing cookie for session %p", __FUNCTION__, this);
+#endif
+ fSocket.reset();
+ return false;
+ }
+
+ return true;
+}
+
+void dcm_client_connection_impl::ensureSocketConnected()
+{
+ fSocket.reset(new boost::asio::local::stream_protocol::socket(fIOService));
+ boost::asio::local::stream_protocol::endpoint endpoint(DCM_UNIX_SOCKET_PATH);
+ fSocket->connect(endpoint);
+}
+
+int dcm_client_connection_impl::get_certificate_chain(std::vector<uint8_t>& chain) noexcept
+{
+ std::lock_guard<std::mutex> locker(fLock);
+
+ if(!fCookie) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Trying to request certificate in session %p without connection", __FUNCTION__, this);
+#endif
+ return HWIF_ERR_INVALID_PARAM;
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Requesting certificate chain for session %p", __FUNCTION__, this);
+#endif
+
+ try {
+ RequestMessage request;
+ ResponseMessage response;
+
+ auto * cert_req = request.mutable_request_chain();
+
+ cert_req->set_context_cookie(fCookie);
+
+ sendReceive(request, response);
+
+ if(!response.has_request_chain()) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Response from server is not certificate chain response on session %p", __FUNCTION__, this);
+#endif
+ return HWIF_ERR_NO_DATA;
+ }
+
+ auto& cert_resp(response.request_chain());
+
+ if(cert_resp.result() != 0) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Server can't respond with certificate chain: error %d in session %p", __FUNCTION__,
+ cert_resp.result(), this);
+#endif
+ return HWIF_ERR_NO_DATA;
+ }
+
+ if(cert_resp.cert_chain().size() == 0) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Server can't respond with certificate chain: certificate empty", __FUNCTION__);
+#endif
+ return HWIF_ERR_NO_DATA;
+ }
+
+ // Add space for last zero byte if needed
+ chain.reserve(cert_resp.cert_chain().size() + 1);
+ chain.resize(cert_resp.cert_chain().size());
+
+ memcpy(&chain[0], cert_resp.cert_chain().c_str(), cert_resp.cert_chain().size());
+
+ if(chain[chain.size() - 1] != 0) {
+ // Pad with zero
+ chain.push_back(0);
+ }
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Received %zd bytes of certificate for session %p", __FUNCTION__, cert_resp.cert_chain().size(), this);
+#endif
+ } catch(std::bad_alloc&) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Out of memory when requesting certificate for session %p", __FUNCTION__, this);
+#endif
+ return HWIF_ERR_OUT_OF_MEMORY;
+ } catch(std::invalid_argument&) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Invalid argument passed for certificate request for session %p", __FUNCTION__, this);
+#endif
+ return HWIF_ERR_INVALID_PARAM;
+ } catch(std::exception& ex) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, ex.what());
+#endif
+ return HWIF_ERROR;
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, "Unknown error");
+#endif
+ return HWIF_ERROR;
+ }
+
+ return HWIF_SUCCESS;
+}
+
+const std::string& dcm_client_connection_impl::key_type() const noexcept {
+ switch(fKeyType) {
+ case CRYPTO_KEY_TYPE_RSA: return sKeyTypeRSA;
+ case CRYPTO_KEY_TYPE_ECDSA: return sKeyTypeECDSA;
+ default: return sKeyTypeUnknown;
+ }
+}
+
+int dcm_client_connection_impl::sign_data(mbedtls_md_type_t digestType, const void * hash_data,
+ size_t hash_size, std::vector<uint8_t>& digest) noexcept
+{
+ std::lock_guard<std::mutex> locker(fLock);
+
+ if(!fCookie) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Trying to request data signing in object %p but there is no connection", __FUNCTION__);
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(digestType);
+
+ if(!md_info) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Can't find hash data for digest type %d", __FUNCTION__, digestType);
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ if(hash_size == 0) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Overriding hash size to %zd bytes", __FUNCTION__, hash_size);
+#endif
+ hash_size = mbedtls_md_get_size(md_info);
+ } else if(hash_size != mbedtls_md_get_size(md_info)) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Hash size mismatch. Expected %zd but got %zd", __FUNCTION__, hash_size, (size_t)mbedtls_md_get_size(md_info));
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ try {
+ RequestMessage request;
+ ResponseMessage response;
+
+ auto * sign_req = request.mutable_sign_data();
+
+ sign_req->set_context_cookie(fCookie);
+ sign_req->set_data_to_sign(hash_data, hash_size);
+ sign_req->set_digest_type(static_cast<MessageDigestType>(digestType));
+
+ sendReceive(request, response);
+
+ if(!response.has_sign_data()) {
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Response for hash signature has no signature data", __FUNCTION__);
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ auto& sign_resp(response.sign_data());
+
+ if(sign_resp.result() != 0) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Signature request for session %p received error %d", __FUNCTION__, this, sign_resp.result());
+#endif
+ return sign_resp.result();
+ }
+
+ const auto& signature = sign_resp.signature();
+
+ if(signature.empty()) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Received signature object is empty for session %p", __FUNCTION__, this);
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ digest.resize(signature.size());
+ memcpy(&digest[0], signature.c_str(), signature.size());
+
+#ifdef USE_DLOG_LOGGING
+ LOGD("%s: Received %zd bytes of signed object for session %p", __FUNCTION__, signature.size(), this);
+#endif
+ } catch(std::bad_alloc&) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: Out of memory when processing sign request for session %p", __FUNCTION__, this);
+#endif
+ return MBEDTLS_ERR_PK_ALLOC_FAILED;
+ } catch(std::exception& ex) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: When processing signature for session %p got exception : %s", __FUNCTION__, this, ex.what());
+#endif
+ } catch(...) {
+#ifdef USE_DLOG_LOGGING
+ LOGE("%s: When processing signature for session %p got exception : %s", __FUNCTION__, this, "Unknown error");
+#endif
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ return 0;
+}
+
+unsigned int dcm_client_connection_impl::key_length() const noexcept {
+ return fKeyLength;
+}
--- /dev/null
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=${prefix}/include
+
+Name: device-certificate-manager
+Description: Device Certificate Manager Package
+Version: @VERSION@
+Requires: iotivity
+Libs: -L${libdir} -ldevice-certificate-manager
+Cflags: -I${includedir}/device-certificate-manager
--- /dev/null
+#
+# DCM daemon build script
+# Jaroslaw Pelczar <j.pelczar@samsung.com>
+#
+
+###### Protobuf generator #######
+
+PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ../dcm-client/dcm_support.proto)
+
+add_custom_target(protobuf_generated
+ DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
+
+###### Setup include paths and library directories #######
+
+ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
+
+IF(DLOG_FOUND)
+ include_directories(${DLOG_INCLUDE_DIRS})
+ link_directories(${DLOG_LIBRARY_DIRS})
+ add_definitions(${DLOG_CFLAGS_OTHER})
+ add_definitions(-DUSE_DLOG_LOGGING=1)
+ENDIF(DLOG_FOUND)
+
+IF(SECURITY_MANAGER_FOUND)
+ include_directories(${SECURITY_MANAGER_INCLUDE_DIRS})
+ link_directories(${SECURITY_MANAGER_LIBRARY_DIRS})
+ add_definitions(${SECURITY_MANAGER_CFLAGS_OTHER})
+ add_definitions(-DUSE_SECURITY_MANAGER=1)
+ENDIF(SECURITY_MANAGER_FOUND)
+
+IF(SYSTEMD_FOUND)
+ include_directories(${SYSTEMD_INCLUDE_DIRS})
+ link_directories(${SYSTEMD_LIBRARY_DIRS})
+ add_definitions(${SYSTEMD_CFLAGS_OTHER})
+ add_definitions(-DUSE_SYSTEMD_API=1)
+ENDIF(SYSTEMD_FOUND)
+
+IF(ARTIK_SECURITY_FOUND)
+ include_directories(${ARTIK_SECURITY_INCLUDE_DIRS})
+ add_definitions(${ARTIK_SECURITY_CFLAGS_OTHER})
+ENDIF(ARTIK_SECURITY_FOUND)
+
+IF(SMACK_FOUND)
+ include_directories(${SMACK_INCLUDE_DIRS})
+ link_directories(${SMACK_LIBRARY_DIRS})
+ add_definitions(${SMACK_CFLAGS_OTHER})
+ add_definitions(-DUSE_SMACK=1)
+ENDIF(SMACK_FOUND)
+
+include_directories(${Boost_INCLUDE_DIRS})
+link_directories(${Boost_LIBRARY_DIRS})
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+
+###### Crypto Backends #######
+
+add_subdirectory(dummy-backend)
+add_subdirectory(see-backend)
+
+IF(ENABLE_DUMMY_BACKEND)
+ SET(DUMMY_BACKEND_OBJECTS $<TARGET_OBJECTS:dummy_backend_objects>)
+ENDIF(ENABLE_DUMMY_BACKEND)
+
+IF(ARTIK_SECURITY_FOUND)
+ SET(SEE_BACKEND_OBJECTS $<TARGET_OBJECTS:see-backend>)
+ENDIF(ARTIK_SECURITY_FOUND)
+
+###### Main executable #######
+
+add_executable(device-certificate-managerd
+ main.cpp
+ dcmserver.cpp
+ dcmsession.cpp
+ serviceadapter.cpp
+ ../shared/protobuf_asio.cpp
+ abstractcryptobackend.cpp
+ abstractcryptobackendcontext.cpp
+ cryptobackendroster.cpp
+ dllresolver.cpp
+ ${PROTO_SRCS}
+ ${PROTO_HDRS}
+ ${DUMMY_BACKEND_OBJECTS}
+ ${SEE_BACKEND_OBJECTS}
+ )
+
+add_dependencies(device-certificate-managerd protobuf_generated)
+
+ApplyCxx11Standard(device-certificate-managerd)
+
+###### Framework linking #######
+
+target_link_libraries(device-certificate-managerd ${Boost_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ device-certificate-manager
+ dl)
+
+IF(DLOG_FOUND)
+ target_link_libraries(device-certificate-managerd ${DLOG_LIBRARIES})
+ENDIF(DLOG_FOUND)
+
+IF(SECURITY_MANAGER_FOUND)
+ target_link_libraries(device-certificate-managerd ${SECURITY_MANAGER_LIBRARIES})
+ENDIF(SECURITY_MANAGER_FOUND)
+
+IF(SYSTEMD_FOUND)
+ target_link_libraries(device-certificate-managerd ${SYSTEMD_LIBRARIES})
+ENDIF(SYSTEMD_FOUND)
+
+IF(SMACK_FOUND)
+ target_link_libraries(device-certificate-managerd ${SMACK_LIBRARIES})
+ENDIF(SMACK_FOUND)
+
+###### Installation #######
+
+install(TARGETS device-certificate-managerd
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "abstractcryptobackend.h"
+
+asbtract_crypto_backend::asbtract_crypto_backend() {
+}
+
+asbtract_crypto_backend::~asbtract_crypto_backend() {
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_ABSTRACTCRYPTOBACKEND_H_
+#define DCM_DAEMON_ABSTRACTCRYPTOBACKEND_H_
+
+#include <memory>
+#include <boost/noncopyable.hpp>
+#include "dcm_support.pb.h"
+
+class abstract_crypto_backend_context;
+
+class asbtract_crypto_backend : public std::enable_shared_from_this<asbtract_crypto_backend>,
+ public boost::noncopyable
+{
+protected:
+ asbtract_crypto_backend();
+
+public:
+ virtual ~asbtract_crypto_backend();
+
+ virtual float will_handle_service(const std::string& serviceName,
+ const std::string& usage) = 0;
+
+ virtual std::shared_ptr<abstract_crypto_backend_context> create_client_context(
+ const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) = 0;
+};
+
+#endif /* DCM_DAEMON_ABSTRACTCRYPTOBACKEND_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "abstractcryptobackendcontext.h"
+
+abstract_crypto_backend_context::abstract_crypto_backend_context() {
+}
+
+abstract_crypto_backend_context::~abstract_crypto_backend_context() {
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_ABSTRACTCRYPTOBACKENDCONTEXT_H_
+#define DCM_DAEMON_ABSTRACTCRYPTOBACKENDCONTEXT_H_
+
+#include "abstractcryptobackend.h"
+
+class abstract_crypto_backend_context : public std::enable_shared_from_this<abstract_crypto_backend_context> {
+protected:
+ abstract_crypto_backend_context();
+
+public:
+ virtual ~abstract_crypto_backend_context();
+
+ virtual int request_certificate_chain(std::string& mutable_chain) = 0;
+
+ virtual int sign_crypto_data(MessageDigestType digestType, const std::string& dataToSign,
+ std::string& digestResult) = 0;
+
+ virtual CryptoKeyType key_type() = 0;
+
+ virtual unsigned int key_length() = 0;
+};
+
+#endif /* DCM_DAEMON_ABSTRACTCRYPTOBACKENDCONTEXT_H_ */
--- /dev/null
+#include "cryptobackendroster.h"
+
+crypto_backend_roster& crypto_backend_roster::instance() {
+ static crypto_backend_roster sInstance;
+ return sInstance;
+}
+
+void crypto_backend_roster::register_backend(std::shared_ptr<asbtract_crypto_backend> context)
+{
+ std::unique_lock<std::mutex> locker(fLock);
+ fBackends.push_back(context);
+}
+
+std::shared_ptr<asbtract_crypto_backend> crypto_backend_roster::choose_backend(const std::string& serviceName,
+ const std::string& usage)
+{
+ std::shared_ptr<asbtract_crypto_backend> best;
+ float best_score = -1.0f;
+
+ std::unique_lock<std::mutex> locker(fLock);
+
+ for(const auto& backend : fBackends) {
+ float score = backend->will_handle_service(serviceName, usage);
+ if(score > best_score) {
+ best_score = score;
+ best = backend;
+ }
+ }
+
+ return best;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_CRYPTOBACKENDROSTER_H_
+#define DCM_DAEMON_CRYPTOBACKENDROSTER_H_
+
+#include <list>
+#include <mutex>
+#include "abstractcryptobackend.h"
+
+class crypto_backend_roster {
+public:
+ static crypto_backend_roster& instance();
+
+ void register_backend(std::shared_ptr<asbtract_crypto_backend> context);
+
+ std::shared_ptr<asbtract_crypto_backend> choose_backend(const std::string& serviceName,
+ const std::string& usage);
+
+private:
+ std::mutex fLock;
+ std::list<std::shared_ptr<asbtract_crypto_backend>> fBackends;
+};
+
+template<typename Klass> struct crypto_backend_registration {
+ crypto_backend_registration() {
+ crypto_backend_roster::instance().register_backend(std::make_shared<Klass>());
+ }
+};
+
+#endif /* DCM_DAEMON_CRYPTOBACKENDROSTER_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dcmserver.h"
+#include "dcmsession.h"
+#include "logging.h"
+
+dcm_server::dcm_server(boost::asio::io_service& io_service, boost::asio::local::stream_protocol::acceptor&& acceptor) :
+ fService(io_service),
+ fAcceptor(std::move(acceptor))
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Construct server object";
+}
+
+dcm_server::~dcm_server()
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Destroy server object";
+}
+
+void dcm_server::start()
+{
+ do_accept();
+}
+
+void dcm_server::do_accept()
+{
+ BOOST_LOG_FUNCTION();
+
+ auto self(this->shared_from_this());
+ std::shared_ptr<dcm_session> session;
+
+ try {
+ session = std::make_shared<dcm_session>(fService, shared_from_this());
+ } catch(std::bad_alloc& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Out of memory when trying to allocate new session";
+ return;
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Can't create new session object: " << ex.what();
+ return;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Start accepting connections";
+
+ fAcceptor.async_accept(session->socket(),
+ [session, self](boost::system::error_code error_code)
+ {
+ BOOST_LOG_FUNCTION();
+ if(!error_code) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Accepted session";
+ session->start();
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't accept new session " << error_code;
+ }
+ self->do_accept();
+ });
+}
+
+std::shared_ptr<asbtract_crypto_backend> dcm_server::crypto_backend() {
+ std::unique_lock<std::mutex> locker(this->fLock);
+ return fCryptoBackend;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_DCMSERVER_H_
+#define DCM_DAEMON_DCMSERVER_H_
+
+#include <boost/asio.hpp>
+#include <boost/noncopyable.hpp>
+#include <mutex>
+#include <memory>
+
+class asbtract_crypto_backend;
+
+class dcm_server final : public boost::noncopyable, public std::enable_shared_from_this<dcm_server> {
+public:
+ dcm_server(boost::asio::io_service& io_service, boost::asio::local::stream_protocol::acceptor&& acceptor);
+ ~dcm_server();
+
+ void start();
+
+ std::shared_ptr<asbtract_crypto_backend> crypto_backend();
+
+private:
+ void do_accept();
+
+private:
+ boost::asio::io_service& fService;
+ boost::asio::local::stream_protocol::acceptor fAcceptor;
+ std::mutex fLock;
+ std::shared_ptr<asbtract_crypto_backend> fCryptoBackend;
+};
+
+#endif /* DCM_DAEMON_DCMSERVER_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dcmsession.h"
+#include "logging.h"
+#include "exception_translator.h"
+#include "dcmserver.h"
+#include "cryptobackendroster.h"
+
+#include <mbedtls/md.h>
+#include <mbedtls/pk.h>
+#include <iostream>
+#include <cassert>
+#include <map>
+#include <mutex>
+
+#ifdef USE_SMACK
+#include <sys/smack.h>
+#endif
+
+#ifdef USE_SECURITY_MANAGER
+#include <security-manager.h>
+#endif
+
+#ifdef USE_SMACK
+static char const *const OWNER_ID_SYSTEM = "/System";
+#endif
+
+#if defined(USE_SECURITY_MANAGER) && defined(USE_SMACK)
+static std::map<std::string, std::string> sPackageIdMapping;
+static std::mutex sPackageIdMappingMutex;
+#endif
+
+dcm_session::dcm_session(boost::asio::io_service& io_service, const std::shared_ptr<dcm_server>& server) :
+ fService(io_service),
+ fSocket(io_service),
+ fServer(server)
+{
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create new session object " << this;
+}
+
+dcm_session::~dcm_session()
+{
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Destroy session object " << this;
+}
+
+#if defined(USE_SMACK) && defined(USE_SECURITY_MANAGER)
+static int assignToString(std::vector<char> &vec, socklen_t len, std::string &res)
+{
+ if (vec.size() <= len)
+ return -1;
+ vec[len] = 0; // old implementation getsockopt returns cstring without 0
+ if (vec[len - 1] == 0) --len;// new implementation of getsockopt returns cstring size+1
+ res.assign(vec.data(), len);
+ return 0;
+}
+
+static int getCredentialsFromSocket(int sock, std::string &res)
+{
+ std::vector<char> result(SMACK_LABEL_LEN + 1);
+ socklen_t length = SMACK_LABEL_LEN;
+
+ if (0 == getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length)) {
+ return assignToString(result, length, res);
+ }
+
+ if (errno != ERANGE) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "getsockopt failed";
+ return -1;
+ }
+
+ result.resize(length + 1);
+
+ if (0 > getsockopt(sock, SOL_SOCKET, SO_PEERSEC, result.data(), &length)) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "getsockopt failed with errno: " << errno;
+ return -1;
+ }
+
+ return assignToString(result, length, res);
+}
+
+static int getPkgIdFromSocket(int sock, std::string &pkgId)
+{
+ char *pkg = nullptr;
+
+ int ret = security_manager_identify_app_from_socket(sock, &pkg, nullptr);
+
+ if (ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Owner of socket is not connected with pkgid. "
+ "This case must be special-labled client. e.g. User, System";
+ return 1;
+ }
+
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "security_manager_identify_app_from_socket failed with error: "
+ << ret;
+ return -1;
+ }
+
+ try {
+ pkgId = pkg;
+ } catch(...) {
+ free(pkg);
+ throw;
+ }
+
+ free(pkg);
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Socket: " << sock << " Was translated to owner id: " << pkgId;
+ return 0;
+}
+
+static void mapToDomainLabel(std::string &label)
+{
+ static const std::string subdomainSep = "::";
+ static const auto systemLabelLen = strlen(OWNER_ID_SYSTEM);
+
+ if (label.length() > systemLabelLen + subdomainSep.length() &&
+ label.compare(0, systemLabelLen, OWNER_ID_SYSTEM) == 0 &&
+ label.compare(systemLabelLen, subdomainSep.length(), subdomainSep) == 0) {
+ label = OWNER_ID_SYSTEM;
+ }
+}
+#endif
+
+bool dcm_session::get_client_id(int handle, std::string& result)
+{
+ BOOST_LOG_FUNCTION();
+
+#if defined(USE_SMACK) && defined(USE_SECURITY_MANAGER)
+ try {
+ std::string smackLabel;
+ int error = getCredentialsFromSocket(handle, smackLabel);
+
+ if(error < 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Socket access failure. Disconnecting";
+ return false;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Client credential is " << smackLabel;
+
+ std::unique_lock<std::mutex> locker(sPackageIdMappingMutex);
+
+ auto it = sPackageIdMapping.find(smackLabel);
+
+ if(it != sPackageIdMapping.end()) {
+ result = it->second;
+ return true;
+ }
+
+ std::string pkgId;
+ int retCode = getPkgIdFromSocket(handle, pkgId);
+
+ if (retCode < 0) {
+ return false;
+ }
+
+ if (retCode == 1) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Special smack label case. label: " << smackLabel;
+ pkgId = "/" + smackLabel;
+ }
+
+ mapToDomainLabel(pkgId);
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << smackLabel << " mapped to " << pkgId;
+
+ result = pkgId;
+ sPackageIdMapping.emplace(std::move(smackLabel), std::move(pkgId));
+
+ return true;
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception when translating socket: " << ex.what();
+ return false;
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught unknown exception when translating socket";
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+void dcm_session::start()
+{
+ BOOST_LOG_FUNCTION();
+
+ int handle = fSocket.native_handle();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Accepted connection with socket " << fSocket.native_handle();
+
+ std::string label;
+ if(get_client_id(handle, label)) {
+ do_receive();
+ }
+}
+
+void dcm_session::do_receive() noexcept
+{
+ BOOST_LOG_FUNCTION();
+
+ try {
+ auto self(shared_from_this());
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Read new message";
+
+ fDeserializer.read_message(fSocket,
+ [self, this](const boost::system::error_code& error, std::size_t bytes_read) {
+ BOOST_LOG_FUNCTION();
+ if(!error) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Received " << bytes_read << " bytes from client";
+ decode_message();
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Client disconnected: " << error;
+ // Connection object will be released by shared ptr
+ }
+ });
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while trying to read message : " << ex.what();
+ // Connection object will be released by shared ptr
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while trying to read message : " << "unknown";
+ // Connection object will be released by shared ptr
+ }
+}
+
+void dcm_session::decode_message() noexcept
+{
+ BOOST_LOG_FUNCTION();
+ try {
+ // Try to decode whole message
+ RequestMessage requestMessage;
+
+ if(!fDeserializer.decode_received_message(requestMessage)) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't parse message from stream";
+ // This will terminate connection
+ return;
+ }
+
+ switch(requestMessage.request_oneof_case())
+ {
+ case RequestMessage::kAssociateContext:
+ handle_context_association(requestMessage.associate_context());
+ break;
+ case RequestMessage::kRequestChain:
+ handle_cert_chain(requestMessage.request_chain());
+ break;
+ case RequestMessage::kSignData:
+ handle_sign_request(requestMessage.sign_data());
+ break;
+ default:
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Incorrect request message type";
+ // This will terminate connection
+ return;
+ }
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while parsing message : " << ex.what();
+ // Connection object will be released by shared ptr
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while parsing message : " << "unknown";
+ // Connection object will be released by shared ptr
+ }
+}
+
+void dcm_session::reply(const ResponseMessage& resp) noexcept
+{
+ BOOST_LOG_FUNCTION();
+ try {
+ auto self(shared_from_this());
+
+ fSerializer.encodeMessage(resp);
+
+ fSerializer.async_write(fSocket,
+ [self, this](const boost::system::error_code& error, std::size_t bytes_written)
+ {
+ BOOST_LOG_FUNCTION();
+ if(!error) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Written " << bytes_written << " to socket";
+ do_receive();
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Server disconnected: " << error;
+ // Connection object will be released by shared ptr
+ }
+ });
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while sending message : " << ex.what();
+ // Connection object will be released by shared ptr
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception while sending message : " << "unknown";
+ // Connection object will be released by shared ptr
+ }
+}
+
+void dcm_session::handle_context_association(const AssociateKeyContext& message)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Associate context";
+
+ ResponseMessage msg;
+ auto * contextResponse = msg.mutable_associate_context();
+
+ if(fCryptoContext) {
+ contextResponse->set_result(EEXIST);
+ reply(msg);
+ return;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Associate context from service " <<
+ message.service() << " with usage " << message.usage() << " and key type " << message.key_type();
+
+ auto server = fServer.lock();
+
+ if(!server) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Server object gone while handling message";
+ return;
+ }
+
+ int error = run_with_exception_handler([&]() {
+ auto backend = crypto_backend_roster::instance().choose_backend(message.service(), message.usage());
+
+ if(!backend) {
+ throw std::invalid_argument("Unable to find crypto backend");
+ }
+
+ fCryptoContext = backend->create_client_context(message.service(), message.usage(), message.key_type());
+ fCookie = (uintptr_t)fCryptoContext.get();
+
+ contextResponse->set_key_type(fCryptoContext->key_type());
+ contextResponse->set_key_length(fCryptoContext->key_length());
+ contextResponse->set_context_cookie(fCookie);
+ });
+
+ contextResponse->set_result(error);
+
+ reply(msg);
+}
+
+void dcm_session::handle_cert_chain(const RequestCertificateChain& message)
+{
+ BOOST_LOG_FUNCTION();
+
+ ResponseMessage msg;
+ auto * certificateResponse = msg.mutable_request_chain();
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Request certificate chain";
+
+ if(message.context_cookie() != fCookie) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Received unknown context cookie";
+ certificateResponse->set_result(-EINVAL);
+ reply(msg);
+ return;
+ }
+
+ if(!fCryptoContext) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
+ certificateResponse->set_result(-EINVAL);
+ reply(msg);
+ return;
+ }
+
+ certificateResponse->set_result(
+ fCryptoContext->request_certificate_chain(
+ *certificateResponse->mutable_cert_chain()));
+
+ reply(msg);
+}
+
+void dcm_session::handle_sign_request(const SignRequest& message)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Request data signing";
+
+ ResponseMessage msg;
+ auto * signingResponse = msg.mutable_sign_data();
+
+ if(message.context_cookie() != fCookie) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Received unknown context cookie";
+ signingResponse->set_result(MBEDTLS_ERR_PK_BAD_INPUT_DATA);
+ reply(msg);
+ return;
+ }
+
+ if(!fCryptoContext) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
+ signingResponse->set_result(MBEDTLS_ERR_PK_BAD_INPUT_DATA);
+ reply(msg);
+ return;
+ }
+
+ const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(
+ static_cast<mbedtls_md_type_t>(
+ message.digest_type()));
+
+ if(!md_info) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't find crypto algorithm specified by caller";
+ signingResponse->set_result(MBEDTLS_ERR_PK_BAD_INPUT_DATA);
+ reply(msg);
+ return;
+ }
+
+ if(message.data_to_sign().size() != mbedtls_md_get_size(md_info)) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) <<
+ "Input hash length mismatch. It is " <<
+ message.data_to_sign().size() << " but should be " <<
+ mbedtls_md_get_size(md_info);
+ signingResponse->set_result(MBEDTLS_ERR_PK_BAD_INPUT_DATA);
+ reply(msg);
+ return;
+ }
+
+ signingResponse->set_result(
+ fCryptoContext->sign_crypto_data(message.digest_type(),
+ message.data_to_sign(),
+ *signingResponse->mutable_signature()));
+
+ reply(msg);
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_DCMSESSION_H_
+#define DCM_DAEMON_DCMSESSION_H_
+
+#include <memory>
+#include <boost/asio.hpp>
+#include <boost/noncopyable.hpp>
+#include "dcm_support.pb.h"
+#include "abstractcryptobackendcontext.h"
+#include <protobuf_asio.h>
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+class dcm_server;
+
+class dcm_session final : public std::enable_shared_from_this<dcm_session>,
+ public boost::noncopyable
+{
+public:
+ dcm_session(boost::asio::io_service& io_service, const std::shared_ptr<dcm_server>& server);
+ ~dcm_session();
+
+ void start();
+
+ inline boost::asio::local::stream_protocol::socket& socket() {
+ return fSocket;
+ }
+
+private:
+ void do_receive() noexcept;
+ void decode_message() noexcept;
+ void reply(const ResponseMessage& resp) noexcept;
+
+ bool get_client_id(int handle, std::string& result);
+
+ void handle_context_association(const AssociateKeyContext& message);
+ void handle_cert_chain(const RequestCertificateChain& message);
+ void handle_sign_request(const SignRequest& message);
+
+private:
+ boost::asio::io_service& fService;
+ boost::asio::local::stream_protocol::socket fSocket;
+ protobuf_async_message_serialization fSerializer;
+ protobuf_async_message_deserialization fDeserializer;
+ std::weak_ptr<dcm_server> fServer;
+ std::shared_ptr<abstract_crypto_backend_context> fCryptoContext;
+ uint64_t fCookie = 0;
+};
+
+#endif /* DCM_DAEMON_DCMSESSION_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dllresolver.h"
+#include "logging.h"
+#include <dlfcn.h>
+
+dll_resolver::dll_resolver(const std::string& libraryName) :
+ fLibraryName(libraryName),
+ fLibraryHandle(nullptr)
+{
+}
+
+dll_resolver::~dll_resolver()
+{
+ if(fLibraryHandle.load(std::memory_order_relaxed)) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Unloading library " << fLibraryName;
+ dlclose(fLibraryHandle.exchange(nullptr, std::memory_order_relaxed));
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Unloaded library " << fLibraryName;
+ }
+}
+
+void * dll_resolver::resolve_function(const int * key_ptr, const char * name) noexcept
+{
+ BOOST_LOG_FUNCTION();
+
+ std::unique_lock<std::mutex> locker(fCacheLock);
+
+ if(key_ptr) {
+ auto it = fCache.find(key_ptr);
+
+ if(it != fCache.end())
+ return it->second;
+ }
+
+ void * handle = fLibraryHandle.load(std::memory_order_relaxed);
+
+ if(handle) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Resolving symbol " << name << " from " << fLibraryName;
+ void * sym = dlsym(handle, name);
+ if(!sym) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to resolve symbol " << name << " from " <<
+ fLibraryName << ": Error is " << dlerror();
+ } else {
+ try {
+ if(key_ptr) {
+ fCache.emplace(key_ptr, sym);
+ }
+ } catch(...) {
+ }
+ }
+ return sym;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Trying to resolve symbol " << name << " from not loaded library " << fLibraryName;
+
+ return nullptr;
+}
+
+bool dll_resolver::ensure_loaded() noexcept
+{
+ BOOST_LOG_FUNCTION();
+
+ std::unique_lock<std::mutex> locker(fCacheLock);
+
+ void * handle = fLibraryHandle.load(std::memory_order_acquire);
+
+ if(handle)
+ return true;
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Loading library " << fLibraryName;
+
+ handle = dlopen(fLibraryName.c_str(), RTLD_LAZY | RTLD_LOCAL);
+
+ if(!handle) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to load library " << fLibraryName << ": " << dlerror();
+ return false;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Library loaded " << fLibraryName;
+
+ void * expectedValue = nullptr;
+
+ if(!fLibraryHandle.compare_exchange_strong(expectedValue, handle, std::memory_order_release)) {
+ // Someone else have opened the library
+ dlclose(handle);
+ }
+
+ return true;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_DLLRESOLVER_H_
+#define DCM_DAEMON_DLLRESOLVER_H_
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <atomic>
+#include <stdexcept>
+#include <map>
+#include <mutex>
+
+class dll_resolver : public boost::noncopyable {
+public:
+ dll_resolver(const std::string& libraryName);
+ ~dll_resolver();
+
+ bool ensure_loaded() noexcept;
+ void * resolve_function(const int * key_ptr, const char * name) noexcept;
+
+ template<typename ReturnValue, typename... Args> ReturnValue invoke(const int * __key_ptr, const char * name, Args... args) {
+ typedef ReturnValue (* function_t)(Args...);
+ function_t func = (function_t)resolve_function(__key_ptr, name);
+ if(!func) {
+ throw std::runtime_error("Trying to call unresolved function");
+ }
+ return func(args...);
+ }
+
+private:
+ std::string fLibraryName;
+ std::atomic<void *> fLibraryHandle;
+ std::mutex fCacheLock;
+ std::map<const int *, void *> fCache;
+};
+
+#endif /* DCM_DAEMON_DLLRESOLVER_H_ */
--- /dev/null
+IF(ENABLE_DUMMY_BACKEND)
+
+find_program(OPENSSL_TOOL openssl)
+
+IF(NOT OPENSSL_TOOL)
+ MESSAGE(FATAL_ERROR "openssl required to build dummy CA")
+ENDIF()
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key
+ COMMAND ${OPENSSL_TOOL} genrsa -out ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key 1024)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA.pem
+ COMMAND ${OPENSSL_TOOL} req -x509 -new -nodes -key ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key
+ -sha256 -days 1024 -out ${CMAKE_CURRENT_BINARY_DIR}/rootCA.pem
+ -subj "/C=PL/ST=Test1/L=Test2/O=Dis/CN=www.example.com"
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key
+ COMMAND ${OPENSSL_TOOL} ecparam -name secp521r1 -genkey -noout -out ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.pem
+ COMMAND ${OPENSSL_TOOL} req -x509 -new -nodes -key ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key
+ -sha256 -days 1024 -out ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.pem
+ -subj "/C=PL/ST=Test1/L=Test2/O=Dis/CN=www.example.com"
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_key.c
+ COMMAND $<TARGET_FILE:helper_bin2c> ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_key.c dummy_rootca_rsa_key
+ DEPENDS helper_bin2c ${CMAKE_CURRENT_BINARY_DIR}/rootCA.key)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_cert.c
+ COMMAND $<TARGET_FILE:helper_bin2c> ${CMAKE_CURRENT_BINARY_DIR}/rootCA.pem ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_cert.c dummy_rootca_rsa_cert
+ DEPENDS helper_bin2c ${CMAKE_CURRENT_BINARY_DIR}/rootCA.pem)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_key.c
+ COMMAND $<TARGET_FILE:helper_bin2c> ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_key.c dummy_rootca_ecdsa_key
+ DEPENDS helper_bin2c ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.key)
+
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_cert.c
+ COMMAND $<TARGET_FILE:helper_bin2c> ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.pem ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_cert.c dummy_rootca_ecdsa_cert
+ DEPENDS helper_bin2c ${CMAKE_CURRENT_BINARY_DIR}/rootECDSA.pem)
+
+add_library(dummy_backend_objects
+ OBJECT
+ dummycryptobackend.cpp
+ dummycryptobackendcontext.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_key.c
+ ${CMAKE_CURRENT_BINARY_DIR}/rootCA_ecdsa_cert.c
+ ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_key.c
+ ${CMAKE_CURRENT_BINARY_DIR}/rootCA_rsa_cert.c)
+
+add_dependencies(dummy_backend_objects protobuf_generated)
+
+ENDIF()
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dummycryptobackend.h"
+#include "dummycryptobackendcontext.h"
+#include <cryptobackendroster.h>
+#include "logging.h"
+
+crypto_backend_registration<dummy_crypto_backend> dummy_crypto_backend::dummy_crypto_backend_registration;
+
+dummy_crypto_backend::dummy_crypto_backend() {
+
+}
+
+dummy_crypto_backend::~dummy_crypto_backend() {
+}
+
+std::shared_ptr<abstract_crypto_backend_context> dummy_crypto_backend::create_client_context(
+ const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) <<
+ "Create new client context for service" << serviceName <<
+ " and usage " << usage <<
+ " with key type " << key_type;
+
+
+ return std::make_shared<dummy_crypto_backend_context>(key_type);
+}
+
+float dummy_crypto_backend::will_handle_service(const std::string&,
+ const std::string&)
+{
+ return 0.01f;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKEND_H_
+#define DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKEND_H_
+
+#include "abstractcryptobackend.h"
+#include "cryptobackendroster.h"
+
+class dummy_crypto_backend final : public asbtract_crypto_backend {
+public:
+ dummy_crypto_backend();
+ virtual ~dummy_crypto_backend();
+
+ virtual std::shared_ptr<abstract_crypto_backend_context> create_client_context(
+ const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) override;
+
+ virtual float will_handle_service(const std::string& serviceName,
+ const std::string& usage);
+
+ static crypto_backend_registration<dummy_crypto_backend> dummy_crypto_backend_registration;
+};
+
+#endif /* DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKEND_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "dummycryptobackendcontext.h"
+#include <mbedtls/pk.h>
+#include <mbedtls/ctr_drbg.h>
+#include <iostream>
+#include "logging.h"
+
+extern "C" {
+ extern size_t dummy_rootca_rsa_key_size;
+ extern char dummy_rootca_rsa_key[];
+ extern size_t dummy_rootca_rsa_cert_size;
+ extern char dummy_rootca_rsa_cert[];
+ extern size_t dummy_rootca_ecdsa_key_size;
+ extern char dummy_rootca_ecdsa_key[];
+ extern size_t dummy_rootca_ecdsa_cert_size;
+ extern char dummy_rootca_ecdsa_cert[];
+}
+
+dummy_crypto_backend_context::dummy_crypto_backend_context(const std::string& keyType) {
+ BOOST_LOG_FUNCTION();
+ if(keyType.empty() || keyType == "RSA") {
+ fKey = CRYPTO_KEY_TYPE_RSA;
+ } else if(keyType == "ECDSA") {
+ fKey = CRYPTO_KEY_TYPE_ECDSA;
+ } else {
+ throw std::invalid_argument("Unsupported key type");
+ }
+
+ mbedtls_entropy_init( &fEntropy );
+ mbedtls_ctr_drbg_init( &fCtrDrbg );
+
+ int ret = mbedtls_ctr_drbg_seed( &fCtrDrbg,
+ mbedtls_entropy_func,
+ &fEntropy,
+ (const unsigned char *)this,
+ sizeof(dummy_crypto_backend_context) );
+
+ if(!ret) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't seed entropy source";
+ mbedtls_ctr_drbg_free( &fCtrDrbg );
+ mbedtls_entropy_free( &fEntropy );
+ throw std::runtime_error("seed failure");
+ }
+}
+
+dummy_crypto_backend_context::~dummy_crypto_backend_context() {
+ BOOST_LOG_FUNCTION();
+ mbedtls_ctr_drbg_free( &fCtrDrbg );
+ mbedtls_entropy_free( &fEntropy );
+}
+
+int dummy_crypto_backend_context::request_certificate_chain(std::string& mutable_chain)
+{
+ BOOST_LOG_FUNCTION();
+ if(fKey == CRYPTO_KEY_TYPE_RSA) {
+ mutable_chain.assign(dummy_rootca_rsa_cert, dummy_rootca_rsa_cert_size);
+ } else {
+ mutable_chain.assign(dummy_rootca_ecdsa_cert, dummy_rootca_ecdsa_cert_size);
+ }
+
+ return 0;
+}
+
+int dummy_crypto_backend_context::sign_crypto_data(MessageDigestType digestType,
+ const std::string& dataToSign,
+ std::string& digestResult)
+{
+ BOOST_LOG_FUNCTION();
+ int error;
+
+ mbedtls_pk_context pk;
+ mbedtls_pk_init(&pk);
+
+ if(fKey == CRYPTO_KEY_TYPE_RSA) {
+ error = mbedtls_pk_parse_key(&pk,
+ (const unsigned char *)dummy_rootca_rsa_key,
+ dummy_rootca_rsa_key_size + 1, // Include 0 byte for PEM
+ nullptr, 0);
+
+ } else {
+ error = mbedtls_pk_parse_key(&pk,
+ (const unsigned char *)dummy_rootca_ecdsa_key,
+ dummy_rootca_ecdsa_key_size + 1, // Include 0 byte for PEM
+ nullptr, 0);
+ }
+
+ if(error != 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't parse private key";
+ mbedtls_pk_free(&pk);
+ return error;
+ }
+
+ size_t sig_len = 0;
+ digestResult.resize(MBEDTLS_MPI_MAX_SIZE);
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Maximum digest size is " << digestResult.size();
+
+ error = mbedtls_pk_sign(&pk,
+ static_cast<mbedtls_md_type_t>(digestType),
+ (const unsigned char *)dataToSign.c_str(),
+ dataToSign.size(),
+ (unsigned char *)digestResult.c_str(),
+ &sig_len,
+ &mbedtls_ctr_drbg_random,
+ &fCtrDrbg);
+
+ if(error != 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Signature generation failed";
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Signature size is " << sig_len;
+ digestResult.resize(sig_len);
+ }
+
+ mbedtls_pk_free(&pk);
+
+ return error;
+}
+
+CryptoKeyType dummy_crypto_backend_context::dummy_crypto_backend_context::key_type()
+{
+ return fKey;
+}
+
+unsigned int dummy_crypto_backend_context::key_length()
+{
+ BOOST_LOG_FUNCTION();
+ unsigned int keyLength = 0;
+
+ mbedtls_pk_context pk;
+ mbedtls_pk_init(&pk);
+
+ if(fKey == CRYPTO_KEY_TYPE_RSA) {
+ int error = mbedtls_pk_parse_key(&pk,
+ (const unsigned char *)dummy_rootca_rsa_key,
+ dummy_rootca_rsa_key_size + 1, // Include 0 byte for PEM
+ nullptr, 0);
+
+ assert(error == 0);
+ assert(mbedtls_pk_get_type(&pk) == MBEDTLS_PK_RSA);
+ (void)error;
+ } else {
+ int error = mbedtls_pk_parse_key(&pk,
+ (const unsigned char *)dummy_rootca_ecdsa_key,
+ dummy_rootca_ecdsa_key_size + 1, // Include 0 byte for PEM
+ nullptr, 0);
+
+ assert(error == 0);
+ assert(mbedtls_pk_get_type(&pk) == MBEDTLS_PK_ECKEY);
+ (void)error;
+ }
+
+ keyLength = mbedtls_pk_get_bitlen(&pk);
+ mbedtls_pk_free(&pk);
+
+ return keyLength;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKENDCONTEXT_H_
+#define DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKENDCONTEXT_H_
+
+#include "abstractcryptobackendcontext.h"
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+
+class dummy_crypto_backend_context final : public abstract_crypto_backend_context {
+public:
+ dummy_crypto_backend_context(const std::string& keyType);
+ virtual ~dummy_crypto_backend_context();
+
+ virtual int request_certificate_chain(std::string& mutable_chain) override;
+
+ virtual int sign_crypto_data(MessageDigestType digestType, const std::string& dataToSign,
+ std::string& digestResult) override;
+
+ virtual CryptoKeyType key_type() override;
+
+ virtual unsigned int key_length() override;
+
+private:
+ CryptoKeyType fKey;
+ mbedtls_entropy_context fEntropy;
+ mbedtls_ctr_drbg_context fCtrDrbg;
+};
+
+#endif /* DCM_DAEMON_DUMMY_BACKEND_DUMMYCRYPTOBACKENDCONTEXT_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
+#define DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
+
+#include <memory>
+#include <stdexcept>
+#include <cerrno>
+#include <boost/system/system_error.hpp>
+
+template<typename T> inline int run_with_exception_handler(T t) {
+ try {
+ t();
+ } catch(boost::system::system_error& ex) {
+ return -ex.code().value();
+ } catch(std::bad_alloc&) {
+ return -ENOMEM;
+ } catch(std::domain_error&) {
+ return -EDOM;
+ } catch(std::invalid_argument&) {
+ return -EINVAL;
+ } catch(std::length_error&) {
+ return -EINVAL;
+ } catch(std::out_of_range&) {
+ return -EINVAL;
+ } catch(std::range_error&) {
+ return -ERANGE;
+ } catch(std::overflow_error&) {
+ return -EOVERFLOW;
+ } catch(std::underflow_error&) {
+ return -EOVERFLOW;
+ } catch(std::exception&) {
+ return -EINVAL;
+ } catch(...) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#endif /* DCM_DAEMON_EXCEPTION_TRANSLATOR_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_LOGGING_H_
+#define DCM_DAEMON_LOGGING_H_
+
+#include <boost/log/common.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/attributes.hpp>
+#include <boost/log/sinks/sync_frontend.hpp>
+#include <boost/log/sinks/syslog_backend.hpp>
+#include <boost/log/sources/logger.hpp>
+#include <boost/log/utility/setup/console.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+#include <boost/log/attributes/timer.hpp>
+#include <boost/log/attributes/named_scope.hpp>
+
+#ifdef USE_DLOG_LOGGING
+#define LOG_TAG "dcm-server"
+#include <dlog.h>
+#endif
+
+enum class log_severity {
+ debug,
+ normal,
+ warning,
+ error
+};
+
+// Global logger declaration
+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(dcm_logger, boost::log::sources::severity_logger_mt<log_severity>)
+
+#endif /* DCM_DAEMON_LOGGING_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 <boost/program_options.hpp>
+#include <boost/asio.hpp>
+
+#include <iostream>
+#include <unistd.h>
+#include <cstdlib>
+#include <sys/stat.h>
+#include <sys/signal.h>
+
+#include "dcm_build_config.h"
+#include "dcmserver.h"
+#include "logging.h"
+#include "serviceadapter.h"
+
+#include <boost/log/sinks.hpp>
+#include <boost/log/support/date_time.hpp>
+
+#include <boost_log_dlog_sink.h>
+
+namespace po = boost::program_options;
+
+struct OptionContext {
+ bool fShowHelp = false;
+ bool fShowVersion = false;
+ std::string fSocketName = DCM_UNIX_SOCKET_PATH;
+
+ void parse_options(int argc, char ** argv)
+ {
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "Print this help")
+ ("version", "Print version")
+ ;
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ if(vm.count("help")) {
+ std::cout << desc << std::endl;
+ fShowHelp = true;
+ return;
+ }
+
+ if(vm.count("version")) {
+ fShowVersion = true;
+ return;
+ }
+ }
+};
+
+BOOST_LOG_ATTRIBUTE_KEYWORD(_scope, "Scope", boost::log::attributes::named_scope::value_type)
+BOOST_LOG_ATTRIBUTE_KEYWORD(_timestamp, "TimeStamp", boost::posix_time::ptime)
+BOOST_LOG_ATTRIBUTE_KEYWORD(_severity, "Severity", log_severity)
+
+void init_logging()
+{
+ auto sink = boost::make_shared<boost::log::sinks::synchronous_sink<dlog_output_backend>>();
+
+ dlog_custom_severity_mapping<log_severity> mapping("Severity");
+
+ mapping[log_severity::debug] = DLOG_DEBUG;
+ mapping[log_severity::error] = DLOG_ERROR;
+ mapping[log_severity::normal] = DLOG_INFO;
+ mapping[log_severity::warning] = DLOG_WARN;
+
+ sink->locked_backend()->set_severity_mapper(mapping);
+ sink->locked_backend()->set_log_domain("dcm-server");
+
+#if !defined(NDEBUG)
+ sink->set_filter(_severity >= log_severity::normal);
+#endif
+
+ sink->set_formatter(boost::log::expressions::stream
+ << boost::log::expressions::attr< unsigned int >("RecordID") // First an attribute "RecordID" is written to the log
+ << " [" // then this delimiter separates it from the rest of the line
+ << boost::log::expressions::if_(boost::log::expressions::has_attr("Tag"))
+ [
+ boost::log::expressions::stream << boost::log::expressions::attr< std::string >("Tag") // then goes another attribute named "Tag"
+ // Note here we explicitly stated that its type
+ // should be std::string. We could omit it just
+ // like we did it with the "RecordID", but in this case
+ // library would have to detect the actual attribute value
+ // type in run time which has the following consequences:
+ // - On the one hand, the attribute would have been output
+ // even if it has another type (not std::string).
+ // - On the other, this detection does not come for free
+ // and will result in performance decrease.
+ //
+ // In general it's better you to specify explicitly which
+ // type should an attribute have wherever it is possible.
+ // You may specify an MPL sequence of types if the attribute
+ // may have more than one type. And you will have to specify
+ // it anyway if the library is not familiar with it (see
+ // boost/log/utility/type_dispatch/standard_types.hpp for the list
+ // of the supported out-of-the-box types).
+ << "] [" // yet another delimiter
+ ]
+ << boost::log::expressions::format_named_scope("Scope", boost::log::keywords::format = "%n", boost::log::keywords::iteration = boost::log::expressions::reverse) << "] "
+ << boost::log::expressions::smessage); // here goes the log record text
+ boost::log::core::get()->add_sink(sink);
+
+ boost::log::add_common_attributes();
+ boost::log::core::get()->add_thread_attribute("Scope", boost::log::attributes::named_scope());
+}
+
+int main(int argc, char ** argv)
+{
+ init_logging();
+
+ BOOST_LOG_FUNCTION();
+
+ OptionContext options;
+
+ try {
+ options.parse_options(argc, argv);
+ } catch(std::exception& ex) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Failed to parse options: " << ex.what();
+ return EXIT_FAILURE;
+ }
+
+ if(options.fShowHelp) {
+ return EXIT_SUCCESS;
+ }
+
+ if(options.fShowVersion) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Device Certificate Manager version " PROJECT_VERSION;
+ return EXIT_SUCCESS;
+ }
+
+ service_adapter serviceAdapter(options.fSocketName);
+
+ try {
+ boost::asio::io_service io_service;
+
+ /* Catch signals */
+ boost::asio::signal_set stop_signals(io_service, SIGINT, SIGTERM);
+
+ stop_signals.async_wait([&io_service](const boost::system::error_code&, int sig) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Stopped by signal " << sig;
+ io_service.stop();
+ });
+
+ /* Change the file mode mask */
+ (void)umask(0);
+
+ /* Use root directory as working directory */
+ int error = chdir("/");
+ (void)error; // Don't care
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create platform socket";
+
+ auto server(std::make_shared<dcm_server>(io_service, serviceAdapter.create_platform_socket_acceptor(io_service)));
+
+ boost::asio::signal_set hup_signals(io_service, SIGHUP);
+
+ hup_signals.async_wait([](const boost::system::error_code&, int) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Received HUP signal";
+ });
+
+ serviceAdapter.notify_start_complete();
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Start server";
+
+ server->start();
+ io_service.run();
+ } catch(std::bad_alloc& e) {
+ serviceAdapter.notify_start_failure(ENOMEM);
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Server failed with OOM exception: " << e.what();
+ return EXIT_FAILURE;
+ } catch(std::exception& e) {
+ serviceAdapter.notify_start_failure(EFAULT);
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Server failed with exception: " << e.what();
+ return EXIT_FAILURE;
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Server failed with unknown exception";
+ serviceAdapter.notify_start_failure(EFAULT);
+ return EXIT_FAILURE;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Server terminated";
+
+ return 0;
+}
--- /dev/null
+IF(ARTIK_SECURITY_FOUND)
+ add_library(see-backend
+ OBJECT
+ seebackend.cpp
+ seebackendcontext.cpp)
+
+ add_dependencies(see-backend protobuf_generated)
+ENDIF()
--- /dev/null
+/*
+ * Workaround for broken header definitions
+ */
+#undef public
+#define public
+#include <artik/security.h>
+#undef public
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "seebackend.h"
+#include "seebackendcontext.h"
+#include "logging.h"
+#include <mutex>
+
+#include "artik_security.h"
+
+crypto_backend_registration<see_backend> see_backend::see_crypto_backend_registration;
+
+see_backend::see_backend() :
+ fSeeInitOK(false),
+ fDllResolver(std::string("libartik-security.so.0"))
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Constructed SEE backend";
+}
+
+see_backend::~see_backend() {
+ BOOST_LOG_FUNCTION();
+ if(fSeeInitOK) {
+ try {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Deinitializing SEE backend";
+ fDllResolver.invoke<void>(nullptr, "see_deinit");
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Deinitialized SEE backend";
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Exception caught when deinitializing SEE backend";
+ }
+ }
+}
+
+void see_backend::initialize_see() {
+ if(fSeeInitOK)
+ return;
+
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Initializing SEE backend";
+
+ std::unique_lock<std::mutex> locker(fSEEMutex);
+
+ try {
+ int error = fDllResolver.invoke<int>(nullptr, "see_init", "TEST_ID", "TEST_PASSWORD");
+
+ if(error != 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "SEE framework init failure: " << error;
+ fSeeInitOK = false;
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "SEE framework initialized";
+ fSeeInitOK = true;
+ }
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Caught exception when initializing SEE backend";
+ fSeeInitOK = false;
+ }
+}
+
+std::shared_ptr<abstract_crypto_backend_context> see_backend::create_client_context(
+ const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type)
+{
+ BOOST_LOG_FUNCTION();
+ initialize_see();
+
+ if(!fSeeInitOK)
+ throw std::runtime_error("SEE not initialized");
+
+ return std::make_shared<see_backend_context>(std::static_pointer_cast<see_backend>(shared_from_this()), key_type);
+}
+
+float see_backend::will_handle_service(const std::string&,
+ const std::string&)
+{
+ BOOST_LOG_FUNCTION();
+ if(!fDllResolver.ensure_loaded())
+ return -1.0f;
+
+ initialize_see();
+
+ if(!fSeeInitOK)
+ return -1.0f;
+
+ return 1.0f;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+
+#ifndef DCM_DAEMON_SEE_BACKEND_SEEBACKEND_H_
+#define DCM_DAEMON_SEE_BACKEND_SEEBACKEND_H_
+
+#include "abstractcryptobackend.h"
+#include "cryptobackendroster.h"
+#include <dllresolver.h>
+#include <mutex>
+
+class see_backend: public asbtract_crypto_backend
+{
+public:
+ see_backend();
+ virtual ~see_backend();
+
+ virtual std::shared_ptr<abstract_crypto_backend_context> create_client_context(
+ const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) override;
+
+ virtual float will_handle_service(const std::string& serviceName,
+ const std::string& usage);
+
+ inline dll_resolver& get_dll_resolver() {
+ return fDllResolver;
+ }
+
+ static crypto_backend_registration<see_backend> see_crypto_backend_registration;
+
+private:
+ void initialize_see();
+
+private:
+ bool fSeeInitOK = false;
+ std::mutex fSEEMutex;
+ dll_resolver fDllResolver;
+};
+
+#endif /* DCM_DAEMON_SEE_BACKEND_SEEBACKEND_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "seebackendcontext.h"
+#include "logging.h"
+#include "artik_security.h"
+
+#include <mbedtls/pk.h>
+
+static int see_get_certificate_key = 0;
+static int see_get_ecdsa_signature_key;
+
+see_backend_context::see_backend_context(std::shared_ptr<see_backend> backend, const std::string& keyType) :
+ fBackendPtr(backend)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Created new SEE with key " << keyType;
+
+ if(keyType.empty() || keyType == "ECDSA") {
+ fKeyType = CRYPTO_KEY_TYPE_ECDSA;
+ } else {
+ throw std::invalid_argument("Unsupported key type");
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Created new SEE context at " << this;
+}
+
+see_backend_context::~see_backend_context()
+{
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Deleting SEE context " << this;
+}
+
+int see_backend_context::request_certificate_chain(std::string& mutable_chain)
+{
+ BOOST_LOG_FUNCTION();
+ see_data cert;
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "SEE : Request certificate chain";
+
+ auto backend = fBackendPtr.lock();
+
+ if(!backend) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to acquire backend pointer";
+ return -EINVAL;
+ }
+
+ auto& resolver(backend->get_dll_resolver());
+
+ int error = resolver.invoke<int, const char *, see_data *>(&see_get_certificate_key, "see_get_certificate", "ARTIK/0", &cert);
+
+ if(error != 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Can't invoke get certificate function";
+ return -EINVAL;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "SEE: Got certificate with " << cert.length << " bytes";
+
+ try {
+ mutable_chain.assign((const char *)cert.data, cert.length);
+ } catch(...) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "SEE: Got exception when assigning data";
+ free(cert.data);
+ throw;
+ }
+
+ free(cert.data);
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Requested certificate in " << this;
+
+ return 0;
+}
+
+int see_backend_context::sign_crypto_data(MessageDigestType digestType, const std::string& dataToSign,
+ std::string& digestResult)
+{
+ BOOST_LOG_FUNCTION();
+ see_data hashed_data;
+ see_data signed_data;
+
+ hashed_data.data = (void *)dataToSign.c_str();
+ hashed_data.length = dataToSign.size();
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "SEE: Sign " << hashed_data.length << " bytes";
+
+ auto backend = fBackendPtr.lock();
+
+ if(!backend) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to acquire backend pointer";
+ return -EINVAL;
+ }
+
+ auto& resolver(backend->get_dll_resolver());
+
+ int error = resolver.invoke<int, see_ecdsa_curve, const char *, see_data, see_data *>(
+ &see_get_ecdsa_signature_key,
+ "see_get_ecdsa_signature",
+ ECDSA_SEC_P256R1,
+ "ARTIK/0",
+ hashed_data,
+ &signed_data);
+
+ if(error != 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to generate ECDSA signature in " << this << " :" << error;
+ return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "SEE: Generated ECDSA signature";
+
+ try {
+ digestResult.assign((const char *)signed_data.data, signed_data.length);
+ } catch(...) {
+ free(signed_data.data);
+ throw;
+ }
+
+ free(signed_data.data);
+
+ return 0;
+}
+
+CryptoKeyType see_backend_context::key_type()
+{
+ return fKeyType;
+}
+
+unsigned int see_backend_context::key_length()
+{
+ return 256;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_SEE_BACKEND_SEEBACKENDCONTEXT_H_
+#define DCM_DAEMON_SEE_BACKEND_SEEBACKENDCONTEXT_H_
+
+#include "abstractcryptobackendcontext.h"
+#include "seebackend.h"
+
+class see_backend_context final : public abstract_crypto_backend_context {
+public:
+ see_backend_context(std::shared_ptr<see_backend> backend, const std::string& keyType);
+ virtual ~see_backend_context();
+
+ virtual int request_certificate_chain(std::string& mutable_chain) override;
+
+ virtual int sign_crypto_data(MessageDigestType digestType, const std::string& dataToSign,
+ std::string& digestResult) override;
+
+ virtual CryptoKeyType key_type() override;
+
+ virtual unsigned int key_length() override;
+
+private:
+ CryptoKeyType fKeyType;
+ std::weak_ptr<see_backend> fBackendPtr;
+};
+
+#endif /* DCM_DAEMON_SEE_BACKEND_SEEBACKENDCONTEXT_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "serviceadapter.h"
+#include "logging.h"
+
+#include <boost/filesystem.hpp>
+#include <cstring>
+
+#ifdef USE_SYSTEMD_API
+#include <systemd/sd-daemon.h>
+#endif
+
+service_adapter::service_adapter(const std::string& default_socket_path) :
+ fDefaultSocketPath(default_socket_path)
+{
+}
+
+service_adapter::~service_adapter()
+{
+ if(fDefaultSocketPathUsed) {
+ boost::filesystem::remove(fDefaultSocketPath);
+ }
+}
+
+boost::asio::local::stream_protocol::acceptor service_adapter::create_platform_socket_acceptor(boost::asio::io_service& io_service)
+{
+ BOOST_LOG_FUNCTION();
+
+#ifdef USE_SYSTEMD_API
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Try to get socket from systemd";
+
+ int n = sd_listen_fds(0);
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << n << " sockets provided by systemd";
+
+ if( n > 0 ) {
+ for(int fd = SD_LISTEN_FDS_START ; fd < SD_LISTEN_FDS_START + n ; ++fd) {
+ if(sd_is_socket_unix(fd, SOCK_STREAM, 1, fDefaultSocketPath.c_str(), 0)) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Got UNIX domain socket with fd " << fd;
+
+ return boost::asio::local::stream_protocol::acceptor(
+ io_service,
+ boost::asio::local::stream_protocol(),
+ fd);
+ }
+ }
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "No systemd sockets found";
+
+ throw std::runtime_error("No socket created by systemd");
+#else
+ fDefaultSocketPathUsed = true;
+ boost::filesystem::remove(fDefaultSocketPath);
+
+ return boost::asio::local::stream_protocol::acceptor(
+ io_service,
+ boost::asio::local::stream_protocol::endpoint(fDefaultSocketPath));
+#endif
+}
+
+void service_adapter::notify_start_complete()
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Notify start completed to systemd";
+
+#ifdef USE_SYSTEMD_API
+ sd_listen_fds(1);
+ sd_notify(0, "READY=1");
+ fStartCompleteNotified = true;
+#endif
+}
+
+void service_adapter::notify_start_failure(int error)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Notify start failure";
+
+#ifdef USE_SYSTEMD_API
+ if(!fStartCompleteNotified) {
+ sd_notifyf(0, "STATUS=Failed to start up: %s\nERRNO=%d", strerror(error), error);
+ }
+#endif
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_SERVICEADAPTER_H_
+#define DCM_DAEMON_SERVICEADAPTER_H_
+
+#include <boost/noncopyable.hpp>
+#include <boost/asio.hpp>
+
+class service_adapter final : public boost::noncopyable {
+public:
+ service_adapter(const std::string& default_socket_path);
+ ~service_adapter();
+
+ boost::asio::local::stream_protocol::acceptor create_platform_socket_acceptor(boost::asio::io_service& io_service);
+
+ void notify_start_complete();
+ void notify_start_failure(int error);
+
+private:
+ std::string fDefaultSocketPath;
+ bool fDefaultSocketPathUsed = false;
+ bool fStartCompleteNotified = false;
+};
+
+#endif /* DCM_DAEMON_SERVICEADAPTER_H_ */
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
+
+
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="@CMAKE_INSTALL_FULL_BINDIR@/dcm_example_client" exec_label="@SMACK_DOMAIN_NAME@" />
+ <filesystem path="@CMAKE_INSTALL_FULL_BINDIR@/dcm_hw_api_test" exec_label="@SMACK_DOMAIN_NAME@" />
+ </assign>
+</manifest>
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
--- /dev/null
+Name: device-certificate-manager
+Summary: Device Certificate Manager daemon and libraries
+Version: 0.1
+Release: 1
+Group: Security/Secure Storage
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1001: device-certificate-manager.manifest
+Source1002: device-certificate-manager-devel.manifest
+BuildRequires: cmake
+BuildRequires: pkgconfig(dlog)
+# BuildRequires: pkgconfig(artik-security)
+BuildRequires: pkgconfig(libsystemd-daemon)
+BuildRequires: pkgconfig(security-manager)
+BuildRequires: pkgconfig(libsmack)
+BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires: pkgconfig(iotivity)
+BuildRequires: pkgconfig(protobuf)
+BuildRequires: boost-devel
+BuildRequires: openssl
+Summary: Device Certificate Manager
+Group: Security/Libraries
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+%{?systemd_requires}
+
+%global user_name key-manager
+%global group_name key-manager
+%global service_name device-certificate-manager
+%global smack_domain_name System
+
+%description
+Device Certificate Manager provides cryptography services
+for the Iotivity framework.
+
+%package -n device-certificate-manager-devel
+Summary: Device Certificate Manager (development)
+Group: Security/Development
+Requires: pkgconfig(iotivity)
+Requires: device-certificate-manager = %{version}-%{release}
+
+%description -n device-certificate-manager-devel
+Device Certificate Manager development headers and libraries
+
+%package -n device-certificate-manager-tests
+Summary: Internal tests for Device Certificate Manager
+Group: Security/Testing
+Requires: device-certificate-manager = %{version}-%{release}
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description -n device-certificate-manager-tests
+Internal tests for Device Certificate Manager
+
+%prep
+%setup -q
+cp -a %{SOURCE1001} .
+cp -a %{SOURCE1002} .
+
+%build
+
+%cmake . -DVERSION=%{version} \
+ -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:Release} \
+ -DSYSTEMD_UNIT_DIR=%{_unitdir} \
+ -DSERVICE_NAME=%{service_name} \
+ -DUSER_NAME=%{user_name} \
+ -DGROUP_NAME=%{group_name} \
+ -DSMACK_DOMAIN_NAME=%{smack_domain_name}
+
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+%install_service multi-user.target.wants device-certificate-manager.service
+%install_service sockets.target.wants device-certificate-manager-control.socket
+
+%post
+
+systemctl daemon-reload
+if [ $1 = 1 ]; then
+ # installation
+ systemctl start device-certificate-manager.service
+fi
+
+%preun
+if [ $1 = 0 ]; then
+ # unistall
+ systemctl stop device-certificate-manager.service
+fi
+
+%postun
+if [ $1 = 0 ]; then
+ # unistall
+ systemctl daemon-reload
+fi
+
+%files
+%manifest device-certificate-manager.manifest
+%license LICENSE
+%{_bindir}/device-certificate-managerd
+%{_libdir}/libdevice-certificate-manager.so.1.0
+%{_unitdir}/multi-user.target.wants/device-certificate-manager.service
+%{_unitdir}/device-certificate-manager.service
+%{_unitdir}/device-certificate-manager.target
+%{_unitdir}/sockets.target.wants/device-certificate-manager-control.socket
+%{_unitdir}/device-certificate-manager-control.socket
+
+%files -n device-certificate-manager-devel
+%manifest device-certificate-manager-devel.manifest
+%license LICENSE
+%{_libdir}/libdevice-certificate-manager.so
+%{_includedir}/device-certificate-manager/*.h
+%{_libdir}/pkgconfig/*.pc
+
+%files -n device-certificate-manager-tests
+%manifest device-certificate-manager-tests.manifest
+%license LICENSE
+%{_bindir}/dcm_example_client
+%{_bindir}/dcm_hw_api_test
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef SHARED_BOOST_LOG_DLOG_SINK_H_
+#define SHARED_BOOST_LOG_DLOG_SINK_H_
+
+#include <boost/log/sinks.hpp>
+#include <functional>
+
+#ifdef USE_DLOG_LOGGING
+#include <dlog.h>
+#else
+typedef enum {
+ DLOG_UNKNOWN = 0, /**< Keep this always at the start */
+ DLOG_DEFAULT, /**< Default */
+ DLOG_VERBOSE, /**< Verbose */
+ DLOG_DEBUG, /**< Debug */
+ DLOG_INFO, /**< Info */
+ DLOG_WARN, /**< Warning */
+ DLOG_ERROR, /**< Error */
+ DLOG_FATAL, /**< Fatal */
+ DLOG_SILENT, /**< Silent */
+ DLOG_PRIO_MAX /**< Keep this always at the end. */
+} log_priority;
+#endif
+
+template<typename AttributeValueT = int> class dlog_direct_severity_mapping :
+ public boost::log::sinks::basic_direct_mapping<log_priority, AttributeValueT>
+{
+ typedef boost::log::sinks::basic_direct_mapping<log_priority, AttributeValueT> base_type;
+public:
+ explicit dlog_direct_severity_mapping(boost::log::attribute_name const& name) :
+ base_type(name)
+ {
+ }
+};
+
+template<typename AttributeValueT = int> class dlog_custom_severity_mapping :
+ public boost::log::sinks::basic_custom_mapping<log_priority, AttributeValueT>
+{
+ typedef boost::log::sinks::basic_custom_mapping<log_priority, AttributeValueT> base_type;
+public:
+ explicit dlog_custom_severity_mapping(boost::log::attribute_name const& name) :
+ base_type(name, DLOG_DEBUG)
+ {
+ }
+};
+
+class dlog_output_backend :
+ public boost::log::sinks::basic_formatted_sink_backend<char>
+{
+ typedef boost::log::sinks::basic_formatted_sink_backend<char> base_type;
+ typedef std::function< log_priority (boost::log::record_view const&) > severity_mapper_type;
+
+private:
+ std::string log_domain_;
+ severity_mapper_type level_mapper_;
+
+ inline void send(log_priority level, string_type const& formatted_message) {
+#ifdef USE_DLOG_LOGGING
+ dlog_print(level, log_domain_.c_str(), formatted_message.c_str());
+#else
+ fprintf(stderr, "%d/(%s): %s\n", level, log_domain_.c_str(), formatted_message.c_str());
+#endif
+ }
+
+public:
+ dlog_output_backend()
+ {
+ }
+
+ void consume(boost::log::record_view const& rec, string_type const& formatted_message) {
+ if(!level_mapper_) {
+ send(DLOG_DEBUG, formatted_message);
+ } else {
+ send(level_mapper_(rec), formatted_message);
+ }
+ }
+
+ void set_log_domain(const std::string& name)
+ {
+ log_domain_ = name;
+ }
+
+ void set_severity_mapper(severity_mapper_type const& mapper)
+ {
+ level_mapper_ = mapper;
+ }
+};
+
+#endif /* SHARED_BOOST_LOG_DLOG_SINK_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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 "protobuf_asio.h"
+#include <google/protobuf/io/coded_stream.h>
+#include <stdexcept>
+
+protobuf_sync_message_serialization::protobuf_sync_message_serialization(
+ boost::asio::local::stream_protocol::socket& socket) :
+ fSocket(socket)
+{
+}
+
+void protobuf_sync_message_serialization::encodeMessage(const google::protobuf::MessageLite& message)
+{
+ google::protobuf::io::CopyingOutputStreamAdaptor os(this);
+ google::protobuf::io::CodedOutputStream coded_os(&os);
+
+ coded_os.WriteLittleEndian32(message.ByteSize());
+ if(!message.SerializeToCodedStream(&coded_os)) {
+ throw std::invalid_argument("Message serialization error");
+ }
+}
+
+bool protobuf_sync_message_serialization::Write(const void* buffer, int size)
+{
+ try {
+ boost::asio::write(fSocket, boost::asio::buffer(buffer, size));
+ } catch(...) {
+ return false;
+ }
+ return true;
+}
+
+protobuf_sync_message_deserialization::protobuf_sync_message_deserialization(
+ boost::asio::local::stream_protocol::socket& socket) :
+ fSocket(socket)
+{
+}
+
+void protobuf_sync_message_deserialization::decodeMessage(google::protobuf::MessageLite& message)
+{
+ google::protobuf::uint8 header[4];
+ google::protobuf::uint32 length;
+ boost::asio::read(fSocket, boost::asio::buffer(header));
+ google::protobuf::io::CodedInputStream::ReadLittleEndian32FromArray(header, &length);
+
+ if(length < 1 || length > kDCMMessageMaxLength) {
+ throw std::length_error("Invalid message length");
+ }
+
+ std::unique_ptr<char[]> local_array(new char[length]);
+
+ boost::asio::read(fSocket, boost::asio::buffer(local_array.get(), length));
+
+ if(!message.ParseFromArray(local_array.get(), length)) {
+ throw std::invalid_argument("Invalid message format");
+ }
+}
+
+void protobuf_async_message_serialization::encodeMessage(const google::protobuf::MessageLite& message)
+{
+ int bufferSize = message.ByteSize();
+ fBuffer.resize(bufferSize + sizeof(uint32_t));
+ google::protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(bufferSize,
+ reinterpret_cast<google::protobuf::uint8 *>(&fBuffer[0]));
+ if(!message.SerializeToArray(&fBuffer[sizeof(uint32_t)], bufferSize)) {
+ throw std::invalid_argument("Message serialization error");
+ }
+}
+
+protobuf_async_message_deserialization::protobuf_async_message_deserialization()
+{
+ fBuffer.reserve(128);
+}
+
+bool protobuf_async_message_deserialization::decode_received_message(google::protobuf::MessageLite& message)
+{
+ return message.ParseFromArray(&fBuffer[0], fBuffer.size());
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * 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.
+ *
+ ******************************************************************/
+
+#ifndef SHARED_PROTOBUF_ASIO_H_
+#define SHARED_PROTOBUF_ASIO_H_
+
+#include <boost/asio.hpp>
+#include <boost/noncopyable.hpp>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <vector>
+
+static const size_t kDCMMessageMaxLength = 65536;
+
+class protobuf_sync_message_serialization final :
+ boost::noncopyable,
+ google::protobuf::io::CopyingOutputStream
+{
+ boost::asio::local::stream_protocol::socket& fSocket;
+public:
+ protobuf_sync_message_serialization(boost::asio::local::stream_protocol::socket& socket);
+
+ void encodeMessage(const google::protobuf::MessageLite& message);
+
+private:
+ virtual bool Write(const void* buffer, int size) override;
+};
+
+class protobuf_sync_message_deserialization final :
+ boost::noncopyable
+{
+ boost::asio::local::stream_protocol::socket& fSocket;
+public:
+ protobuf_sync_message_deserialization(boost::asio::local::stream_protocol::socket& socket);
+
+ void decodeMessage(google::protobuf::MessageLite& message);
+};
+
+class protobuf_async_message_serialization final : boost::noncopyable
+{
+ std::vector<char> fBuffer;
+public:
+ void encodeMessage(const google::protobuf::MessageLite& message);
+
+ template<typename WriteStream, typename WriteHandler> void async_write(WriteStream& stream, WriteHandler&& handler) {
+ boost::asio::async_write(stream, boost::asio::buffer(fBuffer), handler);
+ }
+};
+
+class protobuf_async_message_deserialization final : public boost::noncopyable
+{
+ std::vector<char> fBuffer;
+ google::protobuf::uint32 fMessageLength = 0;
+public:
+ protobuf_async_message_deserialization();
+
+ template<typename ReadSocket, typename ReadHandler> void read_message(ReadSocket& socket,
+ ReadHandler&& handler) {
+ fBuffer.resize(4);
+ fMessageLength = 0;
+
+ boost::asio::async_read(socket, boost::asio::buffer(fBuffer),
+ [this, handler, &socket](const boost::system::error_code& error, std::size_t bytes_read) {
+ if(!error) {
+ assert(bytes_read == fBuffer.size());
+ assert(fMessageLength == 0);
+
+ google::protobuf::io::CodedInputStream::ReadLittleEndian32FromArray(
+ (const google::protobuf::uint8 *)&fBuffer[0],
+ &fMessageLength);
+
+ if(fMessageLength >= 1 && fMessageLength < kDCMMessageMaxLength) {
+ try {
+ fBuffer.resize(fMessageLength);
+ } catch(...) {
+ handler(
+ boost::system::errc::make_error_code(
+ boost::system::posix::not_enough_memory),
+ 0);
+ return;
+ }
+
+ boost::asio::async_read(socket,
+ boost::asio::buffer(fBuffer),
+ handler);
+ } else {
+ handler(
+ boost::system::errc::make_error_code(
+ boost::system::posix::message_size),
+ 0);
+ }
+ } else {
+ handler(error, 0);
+ }
+ });
+ }
+
+ bool decode_received_message(google::protobuf::MessageLite& message);
+};
+
+#endif /* SHARED_PROTOBUF_ASIO_H_ */
--- /dev/null
+configure_file(device-certificate-manager.service.in
+ ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager.service
+ @ONLY)
+
+configure_file(device-certificate-manager-control.socket.in
+ ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager-control.socket
+ @ONLY)
+
+IF(NOT ("${SYSTEMD_UNIT_DIR}" STREQUAL ""))
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager.service
+ device-certificate-manager.target
+ ${CMAKE_CURRENT_BINARY_DIR}/device-certificate-manager-control.socket
+ DESTINATION
+ ${SYSTEMD_UNIT_DIR})
+
+ENDIF()
--- /dev/null
+[Socket]
+ListenStream=@DCM_UNIX_SOCKET_PATH@
+SocketMode=0777
+SmackLabelIPIn=*
+SmackLabelIPOut=@
+Service=device-certificate-manager.service
+
+[Unit]
+Wants=device-certificate-manager.target
+Before=device-certificate-manager.target
+
+[Install]
+WantedBy=sockets.target
--- /dev/null
+[Unit]
+Description=Start the Device Certificate Manager
+DefaultDependencies=no
+
+[Service]
+User=@USER_NAME@
+Group=@GROUP_NAME@
+SmackProcessLabel=@SMACK_DOMAIN_NAME@
+Type=notify
+ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/device-certificate-managerd
+Sockets=device-certificate-manager-control.socket
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+[Unit]
+Description=Device Certificate Manager sockets
+DefaultDependencies=true
--- /dev/null
+include_directories(../dcm-client)
+include_directories(${CMAKE_BINARY_DIR}/dcm-client)
+
+add_executable(dcm_example_client example_client.cpp)
+target_link_libraries(dcm_example_client device-certificate-manager)
+
+add_executable(dcm_hw_api_test hw_api_test.cpp)
+target_link_libraries(dcm_hw_api_test device-certificate-manager ${MBEDTLS_LIB} ${MBEDCRYPTO_LIB})
+
+install(TARGETS dcm_example_client dcm_hw_api_test
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+#include "dcm_client.h"
+#include <iostream>
+#include <iomanip>
+
+int main(int argc, char ** argv)
+{
+ auto connection(dcm_client_connection::create());
+
+ if(!connection->create_context("example_client", "test_usage", "")) {
+ std::cerr << "Can't create context" << std::endl;
+ return -1;
+ }
+
+ std::cout << "Using key type " << connection->key_type() << std::endl;
+
+ std::vector<uint8_t> cert;
+ connection->get_certificate_chain(cert);
+
+ std::cout << "Cert is " << cert.size() << " bytes" << std::endl;
+
+ cert.push_back('\0');
+
+ std::cout << "Received cert " << ((const char *)&cert[0]) << std::endl;
+
+ std::cout << "Private key is " << connection->key_length() << " bits" << std::endl;
+ std::cout << "Private key is " << connection->key_type() << std::endl;
+
+ std::vector<uint8_t> signature;
+ if(connection->sign_data(MBEDTLS_MD_SHA256, "12345678901234567890123456789012", 32, signature) == 0) {
+ for(auto v : signature) {
+ std::cout << std::hex << std::setw(2) << (unsigned int)v << " ";
+ }
+ std::cout << std::endl;
+ } else {
+ std::cerr << "Signing failure" << std::endl;
+ }
+
+ return 0;
+}
--- /dev/null
+#include "dcm_hw_interface.h"
+#include <iostream>
+#include <iomanip>
+#include <cstring>
+
+#include <mbedtls/debug.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/error.h>
+#include <mbedtls/certs.h>
+
+#include <cassert>
+
+int main()
+{
+ const char *pers = "hw_api_test";
+
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+
+ unsigned char result_sig[MBEDTLS_MPI_MAX_SIZE];
+ size_t result_sig_len;
+
+ mbedtls_entropy_init(&entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+
+ if( mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen( pers ) ) )
+ {
+ std::cerr << "Can't seed RNG" << std::endl;
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+ return -1;
+ }
+
+ std::cout << "Create new DCM key context" << std::endl;
+
+ void * keyContext = DCM_HWGetKeyContext("a", "b", "");
+
+ if(!keyContext) {
+ std::cerr << "Can't create DCM key context" << std::endl;
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+ return -1;
+ }
+
+ mbedtls_pk_context pkey;
+
+ std::cout << "Initialize PK context" << std::endl;
+
+ mbedtls_pk_init(&pkey);
+
+ if(DCM_HWSetupPkContext(&pkey, keyContext) != 0) {
+ std::cerr << "Can't setup key context" << std::endl;
+ DCM_HWFreeKeyContext(keyContext);
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+ return -1;
+ } else {
+ std::cout << "Key context setup OK" << std::endl;
+ std::cout << "Key has " << mbedtls_pk_get_bitlen(&pkey) << " bits" << std::endl;
+ }
+
+ unsigned char * certChain = nullptr;
+ size_t certChainLen = 0;
+
+ if(DCM_HWGetOwnCertificateChain(keyContext, &certChain, &certChainLen)) {
+ std::cerr << "Can't request certificate chain" << std::endl;
+ } else {
+ std::cout << "Certificate received" << std::endl;
+ }
+
+ unsigned char to_sign[32] = {
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 11,11
+ };
+
+ if(mbedtls_pk_sign(&pkey,
+ MBEDTLS_MD_SHA256,
+ to_sign,
+ sizeof(to_sign),
+ result_sig,
+ &result_sig_len,
+ mbedtls_ctr_drbg_random, &ctr_drbg) != 0)
+ {
+ std::cerr << "Can't sign data with key" << std::endl;
+ mbedtls_pk_free(&pkey);
+ DCM_HWFreeKeyContext(keyContext);
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+ return -1;
+ }
+
+
+ std::cout << "Signature = ";
+
+ for(size_t i = 0 ; i < result_sig_len ; ++i) {
+ std::cout << std::hex << std::setw(2) << (unsigned int)result_sig[i] << " ";
+ }
+
+ std::cout << std::endl;
+
+ std::cout << "Freeing PK context" << std::endl;
+ mbedtls_pk_free(&pkey);
+
+ std::cout << "Deleting HW context" << std::endl;
+ DCM_HWFreeKeyContext(keyContext);
+
+ std::cout << "Finished" << std::endl;
+
+ mbedtls_ctr_drbg_free( &ctr_drbg );
+ mbedtls_entropy_free( &entropy );
+
+ return 0;
+}
--- /dev/null
+add_executable(helper_bin2c
+ bin2c.c)
+
\ No newline at end of file
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char** argv) {
+ if(argc != 4)
+ return -1;
+
+ FILE * infile = fopen(argv[1], "rb");
+ FILE * outfile = fopen(argv[2], "wb");
+ size_t i;
+
+ fseek(infile,0,SEEK_END);
+ size_t size = ftell(infile);
+ fseek(infile,0,SEEK_SET);
+
+ char * buffer = (char *)malloc(size);
+
+ fread(buffer, 1, size, infile);
+ fclose(infile);
+
+ fprintf(outfile, "#include <sys/types.h>\nsize_t %s_size = %zd;\nunsigned char %s[]= {\n",
+ argv[3], size, argv[3]);
+
+ for(i = 0 ; i < size ; ++i) {
+ if(!(i % 64)) {
+ fprintf(outfile, "\n");
+ }
+
+ fprintf(outfile, "0x%02X,", (unsigned char)buffer[i]);
+ }
+ fprintf(outfile, "0\n};\n");
+ fclose(outfile);
+ return 0;
+}