Initial source commit 63/163263/1
authorJarek Pelczar <j.pelczar@samsung.com>
Tue, 21 Nov 2017 13:07:48 +0000 (14:07 +0100)
committerJaroslaw Pelczar <j.pelczar@samsung.com>
Mon, 4 Dec 2017 05:02:29 +0000 (06:02 +0100)
Change-Id: Ia5a0abd9f6b64e37aca07ecfb0b3b7476a0f7394
Signed-off-by: Jaroslaw Pelczar <j.pelczar@samsung.com>
58 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
cmake/CStandard.cmake [new file with mode: 0644]
cmake/CheckFrameworks.cmake [new file with mode: 0644]
cmake/dcm_build_config.h.in [new file with mode: 0644]
dcm-client/CMakeLists.txt [new file with mode: 0644]
dcm-client/dcm_client.h [new file with mode: 0644]
dcm-client/dcm_client_p.h [new file with mode: 0644]
dcm-client/dcm_hw_interface.cpp [new file with mode: 0644]
dcm-client/dcm_hw_interface.h [new file with mode: 0644]
dcm-client/dcm_support.proto [new file with mode: 0644]
dcm-client/dcmclient.cpp [new file with mode: 0644]
dcm-client/device-certificate-manager.pc.in [new file with mode: 0644]
dcm-daemon/CMakeLists.txt [new file with mode: 0644]
dcm-daemon/abstractcryptobackend.cpp [new file with mode: 0644]
dcm-daemon/abstractcryptobackend.h [new file with mode: 0644]
dcm-daemon/abstractcryptobackendcontext.cpp [new file with mode: 0644]
dcm-daemon/abstractcryptobackendcontext.h [new file with mode: 0644]
dcm-daemon/cryptobackendroster.cpp [new file with mode: 0644]
dcm-daemon/cryptobackendroster.h [new file with mode: 0644]
dcm-daemon/dcmserver.cpp [new file with mode: 0644]
dcm-daemon/dcmserver.h [new file with mode: 0644]
dcm-daemon/dcmsession.cpp [new file with mode: 0644]
dcm-daemon/dcmsession.h [new file with mode: 0644]
dcm-daemon/dllresolver.cpp [new file with mode: 0644]
dcm-daemon/dllresolver.h [new file with mode: 0644]
dcm-daemon/dummy-backend/CMakeLists.txt [new file with mode: 0644]
dcm-daemon/dummy-backend/dummycryptobackend.cpp [new file with mode: 0644]
dcm-daemon/dummy-backend/dummycryptobackend.h [new file with mode: 0644]
dcm-daemon/dummy-backend/dummycryptobackendcontext.cpp [new file with mode: 0644]
dcm-daemon/dummy-backend/dummycryptobackendcontext.h [new file with mode: 0644]
dcm-daemon/exception_translator.h [new file with mode: 0644]
dcm-daemon/logging.h [new file with mode: 0644]
dcm-daemon/main.cpp [new file with mode: 0644]
dcm-daemon/see-backend/CMakeLists.txt [new file with mode: 0644]
dcm-daemon/see-backend/artik_security.h [new file with mode: 0644]
dcm-daemon/see-backend/seebackend.cpp [new file with mode: 0644]
dcm-daemon/see-backend/seebackend.h [new file with mode: 0644]
dcm-daemon/see-backend/seebackendcontext.cpp [new file with mode: 0644]
dcm-daemon/see-backend/seebackendcontext.h [new file with mode: 0644]
dcm-daemon/serviceadapter.cpp [new file with mode: 0644]
dcm-daemon/serviceadapter.h [new file with mode: 0644]
packaging/device-certificate-manager-devel.manifest [new file with mode: 0644]
packaging/device-certificate-manager-tests.manifest.in [new file with mode: 0644]
packaging/device-certificate-manager.manifest [new file with mode: 0644]
packaging/device-certificate-manager.spec [new file with mode: 0644]
shared/boost_log_dlog_sink.h [new file with mode: 0644]
shared/protobuf_asio.cpp [new file with mode: 0644]
shared/protobuf_asio.h [new file with mode: 0644]
systemd/CMakeLists.txt [new file with mode: 0644]
systemd/device-certificate-manager-control.socket.in [new file with mode: 0644]
systemd/device-certificate-manager.service.in [new file with mode: 0644]
systemd/device-certificate-manager.target [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/example_client.cpp [new file with mode: 0644]
tests/hw_api_test.cpp [new file with mode: 0644]
tools/CMakeLists.txt [new file with mode: 0644]
tools/bin2c.c [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5027e44
--- /dev/null
@@ -0,0 +1,59 @@
+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)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..8534b2c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+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.
diff --git a/cmake/CStandard.cmake b/cmake/CStandard.cmake
new file mode 100644 (file)
index 0000000..dd407d9
--- /dev/null
@@ -0,0 +1,65 @@
+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)
diff --git a/cmake/CheckFrameworks.cmake b/cmake/CheckFrameworks.cmake
new file mode 100644 (file)
index 0000000..ff961e0
--- /dev/null
@@ -0,0 +1,60 @@
+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)
diff --git a/cmake/dcm_build_config.h.in b/cmake/dcm_build_config.h.in
new file mode 100644 (file)
index 0000000..fe814a1
--- /dev/null
@@ -0,0 +1,5 @@
+#cmakedefine HAVE_PKIX_INTERFACE
+#cmakedefine HAVE_ARTIK_SECURITY_LIBRARY
+#cmakedefine HAVE_FORK
+
+#define PROJECT_VERSION                "@PROJECT_VERSION@"
diff --git a/dcm-client/CMakeLists.txt b/dcm-client/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cb61bc4
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# 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)
diff --git a/dcm-client/dcm_client.h b/dcm-client/dcm_client.h
new file mode 100644 (file)
index 0000000..1531f81
--- /dev/null
@@ -0,0 +1,82 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-client/dcm_client_p.h b/dcm-client/dcm_client_p.h
new file mode 100644 (file)
index 0000000..f468e39
--- /dev/null
@@ -0,0 +1,67 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-client/dcm_hw_interface.cpp b/dcm-client/dcm_hw_interface.cpp
new file mode 100644 (file)
index 0000000..3e2ad58
--- /dev/null
@@ -0,0 +1,325 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-client/dcm_hw_interface.h b/dcm-client/dcm_hw_interface.h
new file mode 100644 (file)
index 0000000..55239a0
--- /dev/null
@@ -0,0 +1,91 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-client/dcm_support.proto b/dcm-client/dcm_support.proto
new file mode 100644 (file)
index 0000000..3487971
--- /dev/null
@@ -0,0 +1,81 @@
+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;
+       }
+}
diff --git a/dcm-client/dcmclient.cpp b/dcm-client/dcmclient.cpp
new file mode 100644 (file)
index 0000000..22f9bb9
--- /dev/null
@@ -0,0 +1,385 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-client/device-certificate-manager.pc.in b/dcm-client/device-certificate-manager.pc.in
new file mode 100644 (file)
index 0000000..eb07416
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/dcm-daemon/CMakeLists.txt b/dcm-daemon/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bfddd42
--- /dev/null
@@ -0,0 +1,116 @@
+#
+# 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})
diff --git a/dcm-daemon/abstractcryptobackend.cpp b/dcm-daemon/abstractcryptobackend.cpp
new file mode 100644 (file)
index 0000000..7978ada
--- /dev/null
@@ -0,0 +1,27 @@
+/******************************************************************
+ *
+ * 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() {
+}
diff --git a/dcm-daemon/abstractcryptobackend.h b/dcm-daemon/abstractcryptobackend.h
new file mode 100644 (file)
index 0000000..90683fd
--- /dev/null
@@ -0,0 +1,48 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/abstractcryptobackendcontext.cpp b/dcm-daemon/abstractcryptobackendcontext.cpp
new file mode 100644 (file)
index 0000000..4e0bdc1
--- /dev/null
@@ -0,0 +1,27 @@
+/******************************************************************
+ *
+ * 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() {
+}
diff --git a/dcm-daemon/abstractcryptobackendcontext.h b/dcm-daemon/abstractcryptobackendcontext.h
new file mode 100644 (file)
index 0000000..0f8fdc9
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/cryptobackendroster.cpp b/dcm-daemon/cryptobackendroster.cpp
new file mode 100644 (file)
index 0000000..bc30fbb
--- /dev/null
@@ -0,0 +1,31 @@
+#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;
+}
diff --git a/dcm-daemon/cryptobackendroster.h b/dcm-daemon/cryptobackendroster.h
new file mode 100644 (file)
index 0000000..2514412
--- /dev/null
@@ -0,0 +1,48 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/dcmserver.cpp b/dcm-daemon/dcmserver.cpp
new file mode 100644 (file)
index 0000000..ba7a6dd
--- /dev/null
@@ -0,0 +1,80 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/dcmserver.h b/dcm-daemon/dcmserver.h
new file mode 100644 (file)
index 0000000..2835619
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/dcmsession.cpp b/dcm-daemon/dcmsession.cpp
new file mode 100644 (file)
index 0000000..068c76e
--- /dev/null
@@ -0,0 +1,431 @@
+/******************************************************************
+ *
+ * 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);
+}
diff --git a/dcm-daemon/dcmsession.h b/dcm-daemon/dcmsession.h
new file mode 100644 (file)
index 0000000..a2458cf
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/dllresolver.cpp b/dcm-daemon/dllresolver.cpp
new file mode 100644 (file)
index 0000000..a709f98
--- /dev/null
@@ -0,0 +1,107 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/dllresolver.h b/dcm-daemon/dllresolver.h
new file mode 100644 (file)
index 0000000..8b40118
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/dummy-backend/CMakeLists.txt b/dcm-daemon/dummy-backend/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4b858d1
--- /dev/null
@@ -0,0 +1,54 @@
+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()
diff --git a/dcm-daemon/dummy-backend/dummycryptobackend.cpp b/dcm-daemon/dummy-backend/dummycryptobackend.cpp
new file mode 100644 (file)
index 0000000..059e37b
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/dummy-backend/dummycryptobackend.h b/dcm-daemon/dummy-backend/dummycryptobackend.h
new file mode 100644 (file)
index 0000000..8e7211d
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/dummy-backend/dummycryptobackendcontext.cpp b/dcm-daemon/dummy-backend/dummycryptobackendcontext.cpp
new file mode 100644 (file)
index 0000000..6981fe5
--- /dev/null
@@ -0,0 +1,175 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/dummy-backend/dummycryptobackendcontext.h b/dcm-daemon/dummy-backend/dummycryptobackendcontext.h
new file mode 100644 (file)
index 0000000..0422a87
--- /dev/null
@@ -0,0 +1,48 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/exception_translator.h b/dcm-daemon/exception_translator.h
new file mode 100644 (file)
index 0000000..1395888
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/logging.h b/dcm-daemon/logging.h
new file mode 100644 (file)
index 0000000..3445945
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/main.cpp b/dcm-daemon/main.cpp
new file mode 100644 (file)
index 0000000..7012b3a
--- /dev/null
@@ -0,0 +1,204 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/see-backend/CMakeLists.txt b/dcm-daemon/see-backend/CMakeLists.txt
new file mode 100644 (file)
index 0000000..42b718b
--- /dev/null
@@ -0,0 +1,8 @@
+IF(ARTIK_SECURITY_FOUND)
+       add_library(see-backend
+               OBJECT
+               seebackend.cpp
+               seebackendcontext.cpp)
+               
+       add_dependencies(see-backend protobuf_generated)                
+ENDIF()
diff --git a/dcm-daemon/see-backend/artik_security.h b/dcm-daemon/see-backend/artik_security.h
new file mode 100644 (file)
index 0000000..bebd5d7
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * Workaround for broken header definitions
+ */
+#undef public
+#define public
+#include <artik/security.h>
+#undef public
diff --git a/dcm-daemon/see-backend/seebackend.cpp b/dcm-daemon/see-backend/seebackend.cpp
new file mode 100644 (file)
index 0000000..b51615a
--- /dev/null
@@ -0,0 +1,103 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/see-backend/seebackend.h b/dcm-daemon/see-backend/seebackend.h
new file mode 100644 (file)
index 0000000..919629d
--- /dev/null
@@ -0,0 +1,59 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/see-backend/seebackendcontext.cpp b/dcm-daemon/see-backend/seebackendcontext.cpp
new file mode 100644 (file)
index 0000000..2ebb4a8
--- /dev/null
@@ -0,0 +1,146 @@
+/******************************************************************
+ *
+ * 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;
+}
diff --git a/dcm-daemon/see-backend/seebackendcontext.h b/dcm-daemon/see-backend/seebackendcontext.h
new file mode 100644 (file)
index 0000000..14d7ad8
--- /dev/null
@@ -0,0 +1,46 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/dcm-daemon/serviceadapter.cpp b/dcm-daemon/serviceadapter.cpp
new file mode 100644 (file)
index 0000000..c7df4aa
--- /dev/null
@@ -0,0 +1,102 @@
+/******************************************************************
+ *
+ * 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
+}
diff --git a/dcm-daemon/serviceadapter.h b/dcm-daemon/serviceadapter.h
new file mode 100644 (file)
index 0000000..946b188
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/packaging/device-certificate-manager-devel.manifest b/packaging/device-certificate-manager-devel.manifest
new file mode 100644 (file)
index 0000000..5530a2e
--- /dev/null
@@ -0,0 +1,7 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
+
+
diff --git a/packaging/device-certificate-manager-tests.manifest.in b/packaging/device-certificate-manager-tests.manifest.in
new file mode 100644 (file)
index 0000000..3b8c320
--- /dev/null
@@ -0,0 +1,9 @@
+<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>
diff --git a/packaging/device-certificate-manager.manifest b/packaging/device-certificate-manager.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/device-certificate-manager.spec b/packaging/device-certificate-manager.spec
new file mode 100644 (file)
index 0000000..3660733
--- /dev/null
@@ -0,0 +1,119 @@
+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
diff --git a/shared/boost_log_dlog_sink.h b/shared/boost_log_dlog_sink.h
new file mode 100644 (file)
index 0000000..9ebd4f7
--- /dev/null
@@ -0,0 +1,108 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/shared/protobuf_asio.cpp b/shared/protobuf_asio.cpp
new file mode 100644 (file)
index 0000000..9a4155a
--- /dev/null
@@ -0,0 +1,97 @@
+/******************************************************************
+ *
+ * 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());
+}
diff --git a/shared/protobuf_asio.h b/shared/protobuf_asio.h
new file mode 100644 (file)
index 0000000..9716357
--- /dev/null
@@ -0,0 +1,119 @@
+/******************************************************************
+ *
+ * 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_ */
diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4c62027
--- /dev/null
@@ -0,0 +1,17 @@
+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()
diff --git a/systemd/device-certificate-manager-control.socket.in b/systemd/device-certificate-manager-control.socket.in
new file mode 100644 (file)
index 0000000..7ae61d5
--- /dev/null
@@ -0,0 +1,13 @@
+[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
diff --git a/systemd/device-certificate-manager.service.in b/systemd/device-certificate-manager.service.in
new file mode 100644 (file)
index 0000000..bce74b8
--- /dev/null
@@ -0,0 +1,14 @@
+[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
diff --git a/systemd/device-certificate-manager.target b/systemd/device-certificate-manager.target
new file mode 100644 (file)
index 0000000..c51564b
--- /dev/null
@@ -0,0 +1,3 @@
+[Unit]
+Description=Device Certificate Manager sockets
+DefaultDependencies=true
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7214699
--- /dev/null
@@ -0,0 +1,11 @@
+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})
diff --git a/tests/example_client.cpp b/tests/example_client.cpp
new file mode 100644 (file)
index 0000000..91183d7
--- /dev/null
@@ -0,0 +1,39 @@
+#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;
+}
diff --git a/tests/hw_api_test.cpp b/tests/hw_api_test.cpp
new file mode 100644 (file)
index 0000000..70e21ce
--- /dev/null
@@ -0,0 +1,119 @@
+#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;
+}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644 (file)
index 0000000..064d1a4
--- /dev/null
@@ -0,0 +1,3 @@
+add_executable(helper_bin2c
+       bin2c.c)
+       
\ No newline at end of file
diff --git a/tools/bin2c.c b/tools/bin2c.c
new file mode 100644 (file)
index 0000000..4d09136
--- /dev/null
@@ -0,0 +1,34 @@
+#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;
+}