SET(DCM_UNIX_SOCKET_PATH "/run/device-certificate-manager.socket")
ADD_DEFINITIONS(-DDCM_UNIX_SOCKET_PATH="${DCM_UNIX_SOCKET_PATH}")
-INCLUDE_DIRECTORIES(shared)
-ADD_SUBDIRECTORY(dcm-client)
-ADD_SUBDIRECTORY(dcm-daemon)
+INCLUDE_DIRECTORIES(src/shared)
+ADD_SUBDIRECTORY(src/dcm-client)
+ADD_SUBDIRECTORY(src/dcm-daemon)
ADD_SUBDIRECTORY(pkgconfig)
ADD_SUBDIRECTORY(rpm)
ADD_SUBDIRECTORY(systemd)
The DCM (tizen.org repository *platform/core/security/device-certificate-manager*) consists of two submodules: the client and the daemon.
The client provides the public DCM API, while the daemon its implementation.
-The implementation is realized with the internal backend API (see the *dcm-daemon/dcm-backend-api.h* header file).
+The implementation is realized with the internal backend API (see the *src/dcm-daemon/dcm-backend-api.h* header file).
Example implementations of this backend API may be found in the tizen.org separate repository: *platform/core/security/device-certificate-manager-backend*.
The DCM backend repository provides two implementations:
1) dedicated for the KONAI SE device,
##Adding a new backend (a new SE device)
-In order to support a new SE device in the DCM, a new backend API implementation must be developed, which means that the plugin developer must provide the implemenation of the plugin header (*dcm-daemon/dcm-backend-api.h*).
+In order to support a new SE device in the DCM, a new backend API implementation must be developed, which means that the plugin developer must provide the implemenation of the plugin header (*src/dcm-daemon/dcm-backend-api.h*).
Such an implementation may be based on the KONAI SE implementation from the *platform/core/security/device-certificate-manager-backend* repository.
The new implementation may be added to this public repository or provided in the separate git repository.
The most important item is to implement the *libdcm-backend-api.so* library and to install it in the system.
+++ /dev/null
-# Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# @file dcm-client/CMakeLists.txt
-# @author Dariusz Michaluk <d.michaluk@samsung.com>
-# @author Jaroslaw Pelczar <j.pelczar@samsung.com>
-
-FIND_PACKAGE(Threads REQUIRED)
-FIND_PACKAGE(Protobuf REQUIRED)
-
-FIND_LIBRARY(MBEDTLS_LIB mbedtls)
-
-FIND_PACKAGE(Boost REQUIRED
- COMPONENTS
- system)
-
-PKG_CHECK_MODULES(CLIENT_DEPS REQUIRED dlog)
-
-INCLUDE_DIRECTORIES(SYSTEM ${CLIENT_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
-LINK_DIRECTORIES(${CLIENT_DEPS_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
-
-PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS dcm_support.proto)
-
-SET(TARGET_CLIENT "device-certificate-manager")
-ADD_LIBRARY(${TARGET_CLIENT}
- SHARED
- dcmclient.cpp
- device_certificate_manager.cpp
- ../shared/protobuf_asio.cpp
- ${PROTO_SRCS}
- ${PROTO_HDRS})
-
-TARGET_LINK_LIBRARIES(${TARGET_CLIENT}
- ${Boost_SYSTEM_LIBRARY}
- ${PROTOBUF_LITE_LIBRARIES}
- ${MBEDTLS_LIB}
- ${CLIENT_DEPS_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT})
-
-SET_PROPERTY(TARGET ${TARGET_CLIENT} APPEND PROPERTY LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.lds")
-SET_TARGET_PROPERTIES(${TARGET_CLIENT}
- PROPERTIES
- VERSION ${PROJECT_VERSION}
- DEFINE_SYMBOL DEVICE_CERTIFICATE_MANAGER_EXPORT
- VISIBILITY_INLINES_HIDDEN TRUE
- C_VISIBILITY_PRESET hidden
- CXX_VISIBILITY_PRESET hidden)
-
-INSTALL(TARGETS ${TARGET_CLIENT}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
-
-INSTALL(FILES
- device_certificate_manager.h
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager)
-
-INSTALL(FILES
- ${CMAKE_CURRENT_BINARY_DIR}/dcm_support.pb.h
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager-backend)
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 <mbedtls/md.h>
-
-#include <memory>
-#include <vector>
-
-class 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();
- ~dcm_client_connection();
-
-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
- */
- virtual int sign_data(mbedtls_md_type_t digestType,
- const void * hash_data, size_t hash_size,
- std::vector<uint8_t>& digest) noexcept = 0;
-};
-
-#endif /* DCM_CLIENT_DCM_CLIENT_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 dcm_client_connection_impl final : public dcm_client_connection
-{
-public:
- dcm_client_connection_impl();
- dcm_client_connection_impl(boost::asio::io_service& ioService);
- virtual ~dcm_client_connection_impl();
-
- bool create_context(const std::string& serviceName,
- const std::string& usage,
- const std::string& key_type) noexcept override;
-
- int get_certificate_chain(std::vector<uint8_t>& chain) noexcept override;
-
- const std::string& key_type() const noexcept override;
-
- unsigned int key_length() const noexcept override;
-
- int sign_data(mbedtls_md_type_t digestType,
- const void * hash_data, size_t hash_size,
- std::vector<uint8_t>& digest) noexcept override;
-
- void sendReceive(RequestMessage& request, ResponseMessage& response);
-
-private:
- void ensureSocketConnected();
-
-
-private:
- boost::asio::io_service fIOService;
- std::mutex fLock;
- uint64_t fCookie = 0;
- std::unique_ptr<boost::asio::local::stream_protocol::socket> fSocket;
- CryptoKeyType fKeyType = CRYPTO_KEY_TYPE_INVALID;
- unsigned int fKeyLength = 0;
-};
-
-#endif /* DCM_CLIENT_DCM_CLIENT_P_H_ */
+++ /dev/null
-syntax = "proto2";
-option optimize_for = LITE_RUNTIME;
-
-/*
- * Type of the crypto key
- */
-enum CryptoKeyType {
- CRYPTO_KEY_TYPE_INVALID = 0;
- CRYPTO_KEY_TYPE_ECDSA = 1;
- CRYPTO_KEY_TYPE_RSA = 2;
-}
-
-/*
- * These values match the mbedtls ones
- */
-enum MessageDigestType {
- MD_NONE = 0;
- MD_MD2 = 1;
- MD_MD4 = 2;
- MD_MD5 = 3;
- MD_SHA1 = 4;
- MD_SHA224 = 5;
- MD_SHA256 = 6;
- MD_SHA384 = 7;
- MD_SHA512 = 8;
- MD_RIPEMD160 = 9;
-}
-
-message AssociateKeyContext
-{
- required string service = 1;
- required string usage = 2;
- required string key_type = 3;
-}
-
-message AssociateKeyContextResponse
-{
- required int32 result = 1;
- optional uint64 context_cookie = 2;
- optional CryptoKeyType key_type = 3;
- optional uint32 key_length = 4;
-}
-
-message RequestCertificateChain
-{
- required uint64 context_cookie = 1;
-}
-
-message RequestCertificateChainResponse
-{
- required int32 result = 1;
- optional bytes cert_chain = 2;
-}
-
-message SignRequest
-{
- required uint64 context_cookie = 1;
- required bytes data_to_sign = 2;
- required MessageDigestType digest_type = 3;
-}
-
-message SignResponse
-{
- required int32 result = 1;
- optional bytes signature = 2;
-}
-
-message RequestMessage {
- oneof request_oneof {
- AssociateKeyContext associate_context = 1;
- RequestCertificateChain request_chain = 2;
- SignRequest sign_data = 3;
- }
-}
-
-message ResponseMessage {
- oneof reply_oneof {
- AssociateKeyContextResponse associate_context = 1;
- RequestCertificateChainResponse request_chain = 2;
- SignResponse sign_data = 3;
- }
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 Samsung Electronics All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************/
-
-#include "dcm_client_p.h"
-#include "dcm_support.pb.h"
-#include "device_certificate_manager.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>
-#include <mbedtls/ssl.h>
-
-#define LOG_TAG "DCM_CLIENT"
-#include <dlog.h>
-
-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()
-{
-}
-
-dcm_client_connection::~dcm_client_connection()
-{
-}
-
-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)
-{
- protobuf_sync_message_serialization(*fSocket).encodeMessage(request);
- protobuf_sync_message_deserialization(*fSocket).decodeMessage(response);
-}
-
-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) {
- LOGE("%s: Cookie has already been requested for session %p", __FUNCTION__, this);
- // Already created
- return false;
- }
-
- if(!fSocket) {
- try {
- ensureSocketConnected();
- } catch(std::exception& ex) {
- LOGE("%s: Caught exception \"%s\" when connecting socket for session %p", __FUNCTION__, ex.what(), this);
- return false;
- } catch(...) {
- LOGE("%s: Caught unknown exception when connecting socket for session %p", __FUNCTION__, this);
- return false;
- }
- }
-
- 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()) {
- LOGE("%s: received response is not context association message in context %p", __FUNCTION__, this);
- return false;
- }
-
- auto& assoc_message(response.associate_context());
-
- if(assoc_message.result() != 0) {
- LOGE("%s: Received context association message with error %d in %p", __FUNCTION__, assoc_message.result(), this);
- return false;
- }
-
- fCookie = assoc_message.context_cookie();
- fKeyType = assoc_message.key_type();
- fKeyLength = assoc_message.key_length();
- } catch(std::exception& ex) {
- LOGE("%s: Caught exception \"%s\" when establishing cookie for session %p", __FUNCTION__, ex.what(), this);
- fSocket.reset();
- return false;
- } catch(...) {
- LOGE("%s: Caught unknown exception when establishing cookie for session %p", __FUNCTION__, this);
- 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) {
- LOGE("%s: Trying to request certificate in session %p without connection", __FUNCTION__, this);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- 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()) {
- LOGE("%s: Response from server is not certificate chain response on session %p", __FUNCTION__, this);
- return DCM_ERROR_NO_DATA;
- }
-
- auto& cert_resp(response.request_chain());
-
- if(cert_resp.result() != 0) {
- LOGE("%s: Server can't respond with certificate chain: error %d in session %p", __FUNCTION__,
- cert_resp.result(), this);
- return DCM_ERROR_NO_DATA;
- }
-
- if(cert_resp.cert_chain().size() == 0) {
- LOGE("%s: Server can't respond with certificate chain: certificate empty", __FUNCTION__);
- return DCM_ERROR_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);
- }
- } catch(std::bad_alloc&) {
- LOGE("%s: Out of memory when requesting certificate for session %p", __FUNCTION__, this);
- return DCM_ERROR_OUT_OF_MEMORY;
- } catch(std::invalid_argument&) {
- LOGE("%s: Invalid argument passed for certificate request for session %p", __FUNCTION__, this);
- return DCM_ERROR_INVALID_PARAMETER;
- } catch(std::exception& ex) {
- LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, ex.what());
- return DCM_ERROR_UNKNOWN;
- } catch(...) {
- LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, "Unknown error");
- return DCM_ERROR_UNKNOWN;
- }
-
- return DCM_ERROR_NONE;
-}
-
-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) {
- LOGE("%s: Trying to request data signing in object %p but there is no connection", __FUNCTION__, this);
- return DCM_ERROR_SOCKET;
- }
-
- /*
- * If hash_size == 0 then hash type must be known
- */
- if(hash_size == 0) {
- if(digestType == MBEDTLS_MD_NONE) {
- LOGE("%s: Digest type is NONE and hash size is 0", __FUNCTION__);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(digestType);
-
- if(!md_info) {
- LOGE("%s: Can't find hash data for digest type %d", __FUNCTION__, digestType);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- hash_size = mbedtls_md_get_size(md_info);
- } else if(hash_size != 0 && digestType != MBEDTLS_MD_NONE) {
- /*
- * If hash_size != 0 then hash type can be specified
- */
- const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(digestType);
-
- if(!md_info) {
- LOGE("%s: Can't find hash data for digest type %d", __FUNCTION__, digestType);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- if(hash_size != mbedtls_md_get_size(md_info)) {
- LOGE("%s: Hash size mismatch. Expected %zd but got %zd", __FUNCTION__, hash_size, (size_t)mbedtls_md_get_size(md_info));
- return DCM_ERROR_INVALID_PARAMETER;
- }
- }
-
- 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()) {
- LOGE("%s: Response for hash signature has no signature data", __FUNCTION__);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- auto& sign_resp(response.sign_data());
-
- if(sign_resp.result() != 0) {
- LOGE("%s: Signature request for session %p received error %d", __FUNCTION__, this, sign_resp.result());
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- const auto& signature = sign_resp.signature();
-
- if(signature.empty()) {
- LOGE("%s: Received signature object is empty for session %p", __FUNCTION__, this);
- return DCM_ERROR_INVALID_PARAMETER;
- }
-
- digest.resize(signature.size());
- memcpy(&digest[0], signature.c_str(), signature.size());
- } catch(std::bad_alloc&) {
- LOGE("%s: Out of memory when processing sign request for session %p", __FUNCTION__, this);
- return DCM_ERROR_OUT_OF_MEMORY;
- } catch(...) {
- LOGE("%s: When processing signature for session %p got exception : %s", __FUNCTION__, this, "Unknown error");
- return DCM_ERROR_UNKNOWN;
- }
-
- return DCM_ERROR_NONE;
-}
-
-unsigned int dcm_client_connection_impl::key_length() const noexcept {
- return fKeyLength;
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 Samsung Electronics All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************/
-
-#include "device_certificate_manager.h"
-#include "dcm_client.h"
-
-#include <mbedtls/pk_internal.h>
-#include <mbedtls/md.h>
-
-#include <vector>
-#include <cstring>
-
-#ifndef API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-#define API_DEVICE_CERTIFICATE_MANAGER_EXPORT __attribute__((visibility("default")))
-#endif
-
-#define LOG_TAG "DCM_CLIENT"
-#include <dlog.h>
-
-static mbedtls_md_type_t to_mbedtls_md_type(dcm_digest_algorithm_e md)
-{
- switch(md) {
- case DCM_DIGEST_NONE:
- return MBEDTLS_MD_NONE;
- case DCM_DIGEST_MD2:
- return MBEDTLS_MD_MD2;
- case DCM_DIGEST_MD4:
- return MBEDTLS_MD_MD4;
- case DCM_DIGEST_MD5:
- return MBEDTLS_MD_MD5;
- case DCM_DIGEST_SHA1:
- return MBEDTLS_MD_SHA1;
- case DCM_DIGEST_SHA224:
- return MBEDTLS_MD_SHA224;
- case DCM_DIGEST_SHA256:
- return MBEDTLS_MD_SHA256;
- case DCM_DIGEST_SHA384:
- return MBEDTLS_MD_SHA384;
- case DCM_DIGEST_SHA512:
- return MBEDTLS_MD_SHA512;
- case DCM_DIGEST_RIPEMD160:
- return MBEDTLS_MD_RIPEMD160;
- default:
- return MBEDTLS_MD_NONE;
- }
-}
-
-struct dcm_key_context_internal {
- std::shared_ptr<dcm_client_connection> connection;
-};
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_create_key_context(const char *service, const char *usage, const char *key_type, void **key_ctx)
-{
- try {
- if(!key_ctx)
- return DCM_ERROR_INVALID_PARAMETER;
-
- 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(key_type ? key_type : "");
-
- context->connection = dcm_client_connection::create();
-
- if(!context->connection->create_context(service_string, usage_string, keytype_string)) {
- LOGE("Can't create connection context");
- return DCM_ERROR_SOCKET;
- }
-
- *key_ctx = context.release();
- return DCM_ERROR_NONE;
- } catch(std::exception& ex) {
- LOGE("Context creation failure: %s", ex.what());
- return DCM_ERROR_UNKNOWN;
- } catch(...) {
- LOGE("Context creation failure");
- return DCM_ERROR_UNKNOWN;
- }
-}
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_free_key_context(void *key_ctx)
-{
- if(!key_ctx)
- return DCM_ERROR_NONE;
-
- delete reinterpret_cast<dcm_key_context_internal *>(key_ctx);
-
- return DCM_ERROR_NONE;
-}
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_get_certificate_chain(const void *key_ctx, char **cert_chain, size_t *cert_chain_len)
-{
- if(!key_ctx || !cert_chain || !cert_chain_len)
- return DCM_ERROR_INVALID_PARAMETER;
-
- const dcm_key_context_internal *context =
- reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
-
- std::vector<uint8_t> cert;
- int result = context->connection->get_certificate_chain(cert);
- if(result == DCM_ERROR_NONE) {
- *cert_chain = (char*)malloc(sizeof(uint8_t) * cert.size());
- if(*cert_chain == NULL)
- return DCM_ERROR_OUT_OF_MEMORY;
- memcpy(*cert_chain, cert.data(), cert.size());
- *cert_chain_len = cert.size();
- }
-
- return result;
-}
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_get_key_bit_length(const void *key_ctx, size_t *key_bit_len)
-{
- if(!key_ctx || !key_bit_len)
- return DCM_ERROR_INVALID_PARAMETER;
-
- const dcm_key_context_internal *context =
- reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
- *key_bit_len = context->connection->key_length();
-
- return DCM_ERROR_NONE;
-}
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_get_key_type(const void *key_ctx, char **key_type)
-{
- if(!key_ctx || !key_type)
- return DCM_ERROR_INVALID_PARAMETER;
-
- const dcm_key_context_internal *context =
- reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
-
- std::string type = context->connection->key_type();
- *key_type = (char*)malloc(sizeof(char) * (type.length() + 1));
- if(*key_type == NULL)
- return DCM_ERROR_OUT_OF_MEMORY;
- memcpy(*key_type, type.c_str(), type.length() + 1);
-
- return DCM_ERROR_NONE;
-}
-
-API_DEVICE_CERTIFICATE_MANAGER_EXPORT
-int dcm_create_signature(const void *key_ctx, dcm_digest_algorithm_e md,
- const char *message, size_t message_len,
- char **signature, size_t *signature_len)
-{
- if(!key_ctx || !signature || !signature_len)
- return DCM_ERROR_INVALID_PARAMETER;
-
- const dcm_key_context_internal *context =
- reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
-
- std::vector<uint8_t> digest;
- int result = context->connection->sign_data(to_mbedtls_md_type(md), message, message_len, digest);
- if(result == DCM_ERROR_NONE) {
- if(digest.size() > MBEDTLS_MPI_MAX_SIZE)
- return DCM_ERROR_INVALID_PARAMETER;
-
- *signature = (char*)malloc(sizeof(uint8_t) * digest.size());
- if(*signature == NULL)
- return DCM_ERROR_OUT_OF_MEMORY;
- memcpy(*signature, digest.data(), digest.size());
- *signature_len = digest.size();
- }
-
- return result;
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2018 Samsung Electronics All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************/
-
-#ifndef __DEVICE_CERTIFICATE_MANAGER_H__
-#define __DEVICE_CERTIFICATE_MANAGER_H__
-
-#include <stddef.h>
-#include <tizen.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @addtogroup CAPI_DEVICE_CERTIFICATE_MANAGER_MODULE
- * @{
- */
-
-
-/**
- * @brief Enumeration for DCM error values.
- * @since_tizen 5.0
- */
-typedef enum {
- DCM_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
- DCM_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid function parameter */
- DCM_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
- DCM_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
- DCM_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Feature needed to run API is not supported */
- DCM_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< No data available */
- DCM_ERROR_UNKNOWN = TIZEN_ERROR_UNKNOWN, /**< Unknown error */
-
- DCM_ERROR_SOCKET = TIZEN_ERROR_DEVICE_CERTIFICATE_MANAGER | 0x01, /**< Socket error between client and server */
-} dcm_error_e;
-
-
-/**
- * @brief Enumeration for DCM message digest algorithms.
- * @since_tizen 5.0
- */
-typedef enum {
- DCM_DIGEST_NONE=0, /**< No message digest algorithm */
- DCM_DIGEST_MD2, /**< Message digest algorithm MD2 */
- DCM_DIGEST_MD4, /**< Message digest algorithm MD4 */
- DCM_DIGEST_MD5, /**< Message digest algorithm MD5 */
- DCM_DIGEST_SHA1, /**< Message digest algorithm SHA1 */
- DCM_DIGEST_SHA224, /**< Message digest algorithm SHA224 */
- DCM_DIGEST_SHA256, /**< Message digest algorithm SHA256 */
- DCM_DIGEST_SHA384, /**< Message digest algorithm SHA384 */
- DCM_DIGEST_SHA512, /**< Message digest algorithm SHA512 */
- DCM_DIGEST_RIPEMD160, /**< Message digest algorithm RIPEMD160 */
-} dcm_digest_algorithm_e;
-
-
-/**
- * @platform
- * @brief Creates a new key context based on specific name indication (service name, key usage, key type).
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @remarks The @a key_ctx should be freed with dcm_free_key_context() after use.
- *
- * @param[in] service Service name indicates first category name (if null, default value is used)
- * @param[in] usage Usage name indicates sub-category name (if null, default value is used)
- * @param[in] key_type Key type name indication (if null, default value is used)
- * @param[out] key_ctx Newly created key context
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- *
- * @see dcm_free_key_context()
- */
-int dcm_create_key_context(const char *service, const char *usage, const char *key_type, void **key_ctx);
-
-
-/**
- * @platform
- * @brief Destroys the key context that was created by calling dcm_create_key_context().
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @param[in] key_ctx Key context object to be deallocated
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_NO_DATA No such key context object
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- *
- * @see dcm_create_key_context()
- */
-int dcm_free_key_context(void *key_ctx);
-
-
-/**
- * @platform
- * @brief Returns a certificate chain which was pre-injected in device.
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @remarks The @a cert_chain should be freed using free().
- *
- * @param[in] key_ctx Key context object that identifies proper certificate chain
- * @param[out] cert_chain Certificate chain in binary, will be allocated by the library
- * @param[out] cert_chain_len The total length of certificate chain
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_NO_DATA No certificate chain available
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- */
-int dcm_get_certificate_chain(const void *key_ctx, char **cert_chain, size_t *cert_chain_len);
-
-
-/**
- * @platform
- * @brief Returns the key size in bits for a given key context.
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @param[in] key_ctx Key context object that identifies proper certificate chain
- * @param[out] key_bit_len Key length in bits
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_NO_DATA No certificate chain available
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- */
-int dcm_get_key_bit_length(const void *key_ctx, size_t *key_bit_len);
-
-
-/**
- * @platform
- * @brief Returns the key type name for a given key context.
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @remarks The @a key_type should be freed using free().
- *
- * @param[in] key_ctx Key context object that identifies proper certificate chain
- * @param[out] key_type Key type name (UNKNOWN, RSA or ECDSA), will be allocated by the library
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_NO_DATA No certificate chain available
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- */
-int dcm_get_key_type(const void *key_ctx, char **key_type);
-
-/**
- * @platform
- * @brief Creates a signature on a given data using a private key and returns the signature.
- * @since_tizen 5.0
- * @privlevel platform
- * @privilege %http://tizen.org/privilege/devicecertificate
- *
- * @remarks The private key is identified by @a key_ctx.
- * @remarks The @a message can be NULL but then @a message_len must be 0.
- * @remarks The @a signature should be freed using free().
- *
- * @param[in] key_ctx Key context object that identifies a proper private key for signing
- * @param[in] md Message digest algorithm used in creating signature
- * @param[in] message Message that is signed with a key
- * @param[in] message_len Length of the message
- * @param[out] signature Newly created signature, will be allocated by the library
- * @param[out] signature_len Length of a newly created signature
- * @return #DCM_ERROR_NONE on success,
- * otherwise a negative error value
- *
- * @retval #DCM_ERROR_NONE Successful
- * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
- * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
- * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
- * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
- * @retval #DCM_ERROR_SOCKET Socket error between client and server
- * @retval #DCM_ERROR_UNKNOWN Unknown error
- */
-int dcm_create_signature(const void *key_ctx, dcm_digest_algorithm_e md,
- const char *message, size_t message_len,
- char **signature, size_t *signature_len);
-
-/**
- * @}
- */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DEVICE_CERTIFICATE_MANAGER_H__ */
+++ /dev/null
-DCMCLIENT_2.0 {
- global:
- dcm_create_key_context;
- dcm_free_key_context;
- dcm_get_certificate_chain;
- dcm_get_key_bit_length;
- dcm_get_key_type;
- dcm_create_signature;
- local:
- *;
-};
+++ /dev/null
-# Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# @file dcm-daemon/CMakeLists.txt
-# @author Dariusz Michaluk <d.michaluk@samsung.com>
-# @author Jaroslaw Pelczar <j.pelczar@samsung.com>
-
-FIND_PACKAGE(Threads REQUIRED)
-FIND_PACKAGE(Protobuf REQUIRED)
-
-FIND_PACKAGE(Boost REQUIRED
- COMPONENTS
- log
- thread
- system)
-
-PKG_CHECK_MODULES(DAEMON_DEPS
- REQUIRED
- libsystemd
- cynara-client
- cynara-creds-socket
- cynara-session
- dlog)
-
-INCLUDE_DIRECTORIES(SYSTEM ${DAEMON_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
-LINK_DIRECTORIES(${DAEMON_DEPS_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
-
-PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ../dcm-client/dcm_support.proto)
-
-ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
-
-SET(TARGET_DAEMON "device-certificate-managerd")
-ADD_EXECUTABLE(${TARGET_DAEMON}
- main.cpp
- dcmserver.cpp
- dcmsession.cpp
- serviceadapter.cpp
- ../shared/protobuf_asio.cpp
- soresolver.cpp
- ${PROTO_SRCS}
- ${PROTO_HDRS})
-
-TARGET_LINK_LIBRARIES(${TARGET_DAEMON}
- ${Boost_LOG_LIBRARY}
- ${Boost_THREAD_LIBRARY}
- ${Boost_SYSTEM_LIBRARY}
- ${PROTOBUF_LITE_LIBRARIES}
- ${DAEMON_DEPS_LIBRARIES}
- ${CMAKE_THREAD_LIBS_INIT}
- dl)
-
-INSTALL(TARGETS ${TARGET_DAEMON}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-
-INSTALL(FILES
- dcm-backend-api.h
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager-backend)
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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>
-
-#include <dlog.h>
-
-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) {
- dlog_print(level, log_domain_.c_str(), "%s", formatted_message.c_str());
- }
-
-public:
- dlog_output_backend()
- {
- }
-
- void consume(boost::log::record_view const& rec, string_type const& formatted_message) {
- if(!level_mapper_) {
- send(DLOG_DEBUG, formatted_message);
- } else {
- send(level_mapper_(rec), formatted_message);
- }
- }
-
- void set_log_domain(const std::string& name)
- {
- log_domain_ = name;
- }
-
- void set_severity_mapper(severity_mapper_type const& mapper)
- {
- level_mapper_ = mapper;
- }
-};
-
-#endif /* SHARED_BOOST_LOG_DLOG_SINK_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2019 Samsung Electronics All Rights Reserved.
- *
- * Author: Pawel Kowalski <p.kowalski2@partner.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_BACKEND_API_H_
-#define DCM_BACKEND_API_H_
-
-#include "dcm_support.pb.h"
-
-#ifndef API_DCM_BACKEND_EXPORT
-#define API_DCM_BACKEND_EXPORT __attribute__((visibility("default")))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct dcm_backend_context {
- void* backend;
-};
-
-API_DCM_BACKEND_EXPORT
-void dcm_backend_create_key_context(dcm_backend_context& ctx,
- const std::string& keyType);
-
-API_DCM_BACKEND_EXPORT
-void dcm_backend_free_key_context(dcm_backend_context& ctx);
-
-API_DCM_BACKEND_EXPORT
-int dcm_backend_request_certificate_chain(dcm_backend_context& ctx,
- std::string& mutable_chain);
-
-API_DCM_BACKEND_EXPORT
-int dcm_backend_sign_crypto_data(dcm_backend_context& ctx,
- MessageDigestType digestType,
- const std::string& dataToSign,
- std::string& digestResult);
-
-API_DCM_BACKEND_EXPORT
-CryptoKeyType dcm_backend_key_type(dcm_backend_context& ctx);
-
-API_DCM_BACKEND_EXPORT
-unsigned int dcm_backend_key_length(dcm_backend_context& ctx);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* DCM_BACKEND_API_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2019 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, std::string lib_backend) :
- fService(io_service),
- fTimer(io_service),
- fAcceptor(std::move(acceptor)),
- fSoResolver(std::make_shared<so_resolver>(lib_backend))
-{
- 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, fTimer, shared_from_this(), fSoResolver);
- } 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";
- session->start_timer();
-
- 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();
- });
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2019 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>
-#include "soresolver.h"
-
-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, std::string lib_backend);
- ~dcm_server();
- void start();
-
-private:
- void do_accept();
-
-private:
- boost::asio::io_service& fService;
- boost::asio::deadline_timer fTimer;
- boost::asio::local::stream_protocol::acceptor fAcceptor;
- std::mutex fLock;
- std::shared_ptr<so_resolver> fSoResolver;
-};
-
-#endif /* DCM_DAEMON_DCMSERVER_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 <iostream>
-#include <cassert>
-#include <map>
-#include <mutex>
-
-#include <cynara-client.h>
-#include <cynara-creds-socket.h>
-#include <cynara-session.h>
-
-extern cynara * gGlobalCynaraInstance;
-
-static inline std::string cynara_error_to_string(int error) {
- char buffer[256];
- int ret = cynara_strerror(error, buffer, sizeof(buffer));
- if(ret == CYNARA_API_SUCCESS)
- return std::string(buffer);
- return std::string("Can't translate error");
-}
-
-unsigned int globalSessionCounter = 0;
-
-dcm_session::dcm_session(boost::asio::io_service& io_service,
- boost::asio::deadline_timer& timer,
- const std::shared_ptr<dcm_server>& server,
- std::shared_ptr<so_resolver> soResolver) :
- fService(io_service),
- fTimer(timer),
- fSocket(io_service),
- fServer(server),
- fSoResolver(soResolver)
-{
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create new session object " << this;
- globalSessionCounter++;
-}
-
-dcm_session::~dcm_session()
-{
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Destroy session object " << this;
-}
-
-struct string_free_deleter {
- void operator()(char * p) const {
- free(p);
- }
-};
-
-bool dcm_session::verify_privileges(int handle)
-{
- BOOST_LOG_FUNCTION();
-
- int ret = 0;
- char * tmp_str;
- pid_t pid = 0;
-
- std::unique_ptr<char, string_free_deleter> user;
- std::unique_ptr<char, string_free_deleter> client;
- std::unique_ptr<char, string_free_deleter> client_session;
-
- /* Get user info */
- tmp_str = nullptr;
- ret = cynara_creds_socket_get_user(handle, USER_METHOD_DEFAULT, &tmp_str);
- if(ret != CYNARA_API_SUCCESS) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get user from socket : " << ret << " - " << cynara_error_to_string(ret);
- return false;
- }
- user.reset(tmp_str);
-
- /* Get client info */
- tmp_str = nullptr;
- ret = cynara_creds_socket_get_client(handle, CLIENT_METHOD_DEFAULT, &tmp_str);
- if(ret != CYNARA_API_SUCCESS) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get client from socket : " << ret << " - " << cynara_error_to_string(ret);
- return false;
- }
- client.reset(tmp_str);
-
-
- /* Get client PID from socket */
- ret = cynara_creds_socket_get_pid(handle, &pid);
- if(ret != CYNARA_API_SUCCESS) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get PID from socket : " << ret << " - " << cynara_error_to_string(ret);
- return false;
- }
-
- client_session.reset(cynara_session_from_pid(pid));
- if(!client_session) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get session identifier from PID";
- return false;
- }
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Got new session from " << pid << " with user " <<
- user.get() << ", client ID " << client.get() << " and session ID " << client_session.get();
-
- ret = cynara_check(gGlobalCynaraInstance,
- client.get(),
- client_session.get(),
- user.get(),
- "http://tizen.org/privilege/devicecertificate");
-
- if(ret != CYNARA_API_ACCESS_ALLOWED) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) <<
- "Application access denied - no internet permission for " <<
- pid <<
- " - " <<
- cynara_error_to_string(ret);
-
- return false;
- }
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Access granted for " << pid;
-
- 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();
-
- if(verify_privileges(handle)) {
- stop_timer();
- do_receive();
- } else {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Client privilege check failure. Disconnect";
- start_timer();
- }
-}
-
-void dcm_session::start_timer()
-{
- globalSessionCounter--;
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Number of active connections: " << globalSessionCounter;
-
- if(globalSessionCounter == 0) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "No active connections, server will be closed after few seconds";
- fTimer.expires_from_now(boost::posix_time::seconds(10));
- /* operation_aborted error is returned whenever we cancel the timer or we reset the timer using expires_from_now function */
- fTimer.async_wait([this](const boost::system::error_code &error) {
- if(error != boost::asio::error::operation_aborted) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "No active connections, server will be closed";
- fService.stop();
- }
- });
- }
-}
-
-void dcm_session::stop_timer()
-{
- globalSessionCounter++;
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Number of active connections: " << globalSessionCounter;
-
- fTimer.cancel();
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Timer cancelled";
-}
-
-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
- start_timer();
- }
- });
- } 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(fBackendContext) {
- 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([&]() {
-
- bool loaded = fSoResolver->ensure_loaded();
- if (loaded) {
- fBackendContext = std::unique_ptr<dcm_backend_context>(new dcm_backend_context);
-
- fSoResolver->invoke<void, dcm_backend_context&, const std::string&>(
- "dcm_backend_create_key_context",
- *fBackendContext,
- message.key_type()
- );
-
- CryptoKeyType crypto_key_type = fSoResolver->invoke<CryptoKeyType, dcm_backend_context&>(
- "dcm_backend_key_type",
- *fBackendContext
- );
- contextResponse->set_key_type(crypto_key_type);
-
- unsigned int crypto_key_length = fSoResolver->invoke<unsigned int, dcm_backend_context&>(
- "dcm_backend_key_length",
- *fBackendContext
- );
- contextResponse->set_key_length(crypto_key_length);
- }
- else {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "No crypto usable backend available";
- throw std::invalid_argument("Unable to find crypto backend");
- }
- fCookie = (uintptr_t)fBackendContext.get();
- contextResponse->set_context_cookie(fCookie);
- });
-
- contextResponse->set_result(error);
-
- reply(msg);
-}
-
-static const std::string sPEMHeader("-----BEGIN CERTIFICATE-----\n");
-
-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(!fBackendContext) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
- certificateResponse->set_result(-EINVAL);
- reply(msg);
- return;
- }
-
- std::string cert_chain;
-
- int error = 0;
- bool loaded = fSoResolver->ensure_loaded();
- if (loaded) {
- error = fSoResolver->invoke<int, dcm_backend_context&, std::string&>(
- "dcm_backend_request_certificate_chain",
- *fBackendContext,
- cert_chain
- );
- }
-
- if(error != 0) {
- certificateResponse->set_result(error);
- reply(msg);
- return;
- }
-
- if(cert_chain.length() >= sPEMHeader.length() &&
- !memcmp(sPEMHeader.c_str(), cert_chain.c_str(), sPEMHeader.size()) &&
- cert_chain[cert_chain.size() - 1] != '\0')
- {
- // Add missing 0
- cert_chain.push_back(0);
- }
-
- *certificateResponse->mutable_cert_chain() = cert_chain;
-
- certificateResponse->set_result(0);
- 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(-EINVAL);
- reply(msg);
- return;
- }
-
- if(!fBackendContext) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
- signingResponse->set_result(-EINVAL);
- reply(msg);
- return;
- }
-
- if(message.data_to_sign().size() == 0) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Data to sign is empty and hash type is NONE";
- signingResponse->set_result(-EINVAL);
- return;
- }
-
- int error = 0;
- bool loaded = fSoResolver->ensure_loaded();
- if (loaded) {
- error = fSoResolver->invoke<int, dcm_backend_context&, MessageDigestType, const std::string&, std::string&>(
- "dcm_backend_sign_crypto_data",
- *fBackendContext,
- message.digest_type(),
- message.data_to_sign(),
- *signingResponse->mutable_signature()
- );
- }
- signingResponse->set_result(error);
-
- reply(msg);
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2019 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 "protobuf_asio.h"
-#include "dcm-backend-api.h"
-#include "soresolver.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, boost::asio::deadline_timer& timer, const std::shared_ptr<dcm_server>& server, std::shared_ptr<so_resolver> soResolver);
- ~dcm_session();
-
- void start();
- void start_timer();
- void stop_timer();
-
- 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 verify_privileges(int handle);
-
- 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::deadline_timer& fTimer;
- 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<dcm_backend_context> fBackendContext;
- std::shared_ptr<so_resolver> fSoResolver;
- uint64_t fCookie = 0;
-};
-
-#endif /* DCM_DAEMON_DCMSESSION_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 Samsung Electronics All Rights Reserved.
- *
- * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************/
-
-#ifndef DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
-#define DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
-
-#include <memory>
-#include <stdexcept>
-#include <cerrno>
-#include <boost/system/system_error.hpp>
-
-template<typename T> inline int run_with_exception_handler(T t) {
- try {
- t();
- } catch(boost::system::system_error& ex) {
- return -ex.code().value();
- } catch(std::bad_alloc&) {
- return -ENOMEM;
- } catch(std::domain_error&) {
- return -EDOM;
- } catch(std::invalid_argument&) {
- return -EINVAL;
- } catch(std::length_error&) {
- return -EINVAL;
- } catch(std::out_of_range&) {
- return -EINVAL;
- } catch(std::range_error&) {
- return -ERANGE;
- } catch(std::overflow_error&) {
- return -EOVERFLOW;
- } catch(std::underflow_error&) {
- return -EOVERFLOW;
- } catch(std::exception&) {
- return -EINVAL;
- } catch(...) {
- return -EFAULT;
- }
-
- return 0;
-}
-
-#endif /* DCM_DAEMON_EXCEPTION_TRANSLATOR_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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>
-
-#define LOG_TAG "DCM_SERVER"
-#include <dlog.h>
-
-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>)
-
-#if defined(NDEBUG) && !defined(DEBUG)
-#else
-#define ENABLE_DEBUG_LOGGING 1
-#endif
-
-#endif /* DCM_DAEMON_LOGGING_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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/asio.hpp>
-
-#include <iostream>
-#include <unistd.h>
-#include <cstdlib>
-#include <sys/stat.h>
-#include <sys/signal.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"
-
-#include <cynara-client.h>
-
-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(LOG_TAG);
-
-#ifndef ENABLE_DEBUG_LOGGING
- 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());
-}
-
-cynara * gGlobalCynaraInstance;
-
-int main()
-{
- int error = 0;
-
- try {
- init_logging();
- } catch(...) {
- std::cerr << "init_logging() failed" << std::endl;
- return EXIT_FAILURE;
- }
-
- BOOST_LOG_FUNCTION();
-
- service_adapter serviceAdapter;
-
- cynara_configuration * cynara_conf = nullptr;
- error = cynara_configuration_create(&cynara_conf);
- if(error != CYNARA_API_SUCCESS) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't initialize Cynara configuration: " << error;
- serviceAdapter.notify_start_failure(error);
- return EXIT_FAILURE;
- }
-
- error = cynara_initialize(&gGlobalCynaraInstance, cynara_conf);
-
- cynara_configuration_destroy(cynara_conf);
-
- if(error != CYNARA_API_SUCCESS) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't initialize Cynara instance: " << error;
- serviceAdapter.notify_start_failure(error);
- return EXIT_FAILURE;
- }
-
- 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 */
- error = chdir("/");
- (void)error; // Don't care
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create platform socket";
-
- std::string lib_backend = "libdcm-backend-api.so.1.0";
- auto server(std::make_shared<dcm_server>(io_service, serviceAdapter.create_platform_socket_acceptor(io_service), lib_backend));
-
- 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;
- }
-
- cynara_finish(gGlobalCynaraInstance);
- gGlobalCynaraInstance = nullptr;
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Server terminated";
-
- return 0;
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 <cstring>
-
-#include <systemd/sd-daemon.h>
-
-service_adapter::service_adapter()
-{
-}
-
-service_adapter::~service_adapter()
-{
-}
-
-boost::asio::local::stream_protocol::acceptor service_adapter::create_platform_socket_acceptor(boost::asio::io_service& io_service)
-{
- BOOST_LOG_FUNCTION();
-
- 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");
-}
-
-void service_adapter::notify_start_complete()
-{
- BOOST_LOG_FUNCTION();
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Notify start completed to systemd";
-
- sd_listen_fds(1);
- sd_notify(0, "READY=1");
- fStartCompleteNotified = true;
-}
-
-void service_adapter::notify_start_failure(int error)
-{
- BOOST_LOG_FUNCTION();
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Notify start failure";
-
- if(!fStartCompleteNotified) {
- char buffer[512];
- buffer[0] = '\0';
- if(!strerror_r(error, buffer, sizeof(buffer)))
- sd_notifyf(0, "STATUS=Failed to start up: %s\nERRNO=%d", buffer, error);
- else
- sd_notifyf(0, "STATUS=Failed to start up: (no message)\nERRNO=%d", error);
- }
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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();
- ~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 = DCM_UNIX_SOCKET_PATH;
- bool fStartCompleteNotified = false;
-};
-
-#endif /* DCM_DAEMON_SERVICEADAPTER_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2019 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 "soresolver.h"
-#include "logging.h"
-#include <dlfcn.h>
-
-so_resolver::so_resolver(const std::string& libraryName) :
- fLibraryName(libraryName),
- fLibraryHandle(nullptr)
-{
-}
-
-so_resolver::~so_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 * so_resolver::resolve_function(const std::string& name) noexcept
-{
- BOOST_LOG_FUNCTION();
-
- std::unique_lock<std::mutex> locker(fCacheLock);
- auto it = fCache.find(name);
-
- 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.c_str());
- if(!sym) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to resolve symbol " << name << " from " <<
- fLibraryName << ": Error is " << dlerror();
- } else {
- try {
- fCache.emplace(name, 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 so_resolver::ensure_loaded() noexcept
-{
- BOOST_LOG_FUNCTION();
-
- std::unique_lock<std::mutex> locker(fCacheLock);
-
- void * handle = fLibraryHandle.load(std::memory_order_acquire);
-
- if(handle)
- return true;
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Loading library " << fLibraryName;
-
- handle = dlopen(fLibraryName.c_str(), RTLD_LAZY | RTLD_LOCAL);
-
- if(!handle) {
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to load library " << fLibraryName << ": " << dlerror();
- return false;
- }
-
- BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Library loaded " << fLibraryName;
-
- void * expectedValue = nullptr;
-
- if(!fLibraryHandle.compare_exchange_strong(expectedValue, handle, std::memory_order_release)) {
- // Someone else have opened the library
- dlclose(handle);
- }
-
- return true;
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2019 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_SORESOLVER_H_
-#define DCM_DAEMON_SORESOLVER_H_
-
-#include <boost/noncopyable.hpp>
-#include <string>
-#include <atomic>
-#include <stdexcept>
-#include <map>
-#include <mutex>
-#include <string>
-
-class so_resolver : public boost::noncopyable {
-public:
- so_resolver(const std::string& libraryName);
- ~so_resolver();
-
- bool ensure_loaded() noexcept;
- void * resolve_function(const std::string& name) noexcept;
-
- template<typename ReturnValue, typename... Args> ReturnValue invoke(const std::string& name, Args... args) {
- typedef ReturnValue (* function_t)(Args...);
- function_t func = (function_t)resolve_function(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<std::string, void *> fCache;
-};
-
-#endif /* DCM_DAEMON_SORESOLVER_H_ */
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 <stdexcept>
-
-#include <google/protobuf/io/coded_stream.h>
-
-#include "protobuf_asio.h"
-
-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.ByteSizeLong());
- 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 > MESSAGE_LENGHT_MAX) {
- 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.ByteSizeLong();
- fBuffer.resize(bufferSize + sizeof(uint32_t));
- google::protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(bufferSize,
- reinterpret_cast<google::protobuf::uint8 *>(&fBuffer[0]));
- if(!message.SerializeToArray(&fBuffer[sizeof(uint32_t)], bufferSize)) {
- throw std::invalid_argument("Message serialization error");
- }
-}
-
-protobuf_async_message_deserialization::protobuf_async_message_deserialization()
-{
- fBuffer.reserve(128);
-}
-
-bool protobuf_async_message_deserialization::decode_received_message(google::protobuf::MessageLite& message)
-{
- return message.ParseFromArray(&fBuffer[0], fBuffer.size());
-}
+++ /dev/null
-/******************************************************************
- *
- * Copyright 2017 - 2020 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 <vector>
-
-#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>
-
-static const size_t MESSAGE_LENGHT_MAX = 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());
- (void)bytes_read;
- assert(fMessageLength == 0);
-
- google::protobuf::io::CodedInputStream::ReadLittleEndian32FromArray(
- (const google::protobuf::uint8 *)&fBuffer[0], &fMessageLength);
-
- if(fMessageLength >= 1 && fMessageLength < MESSAGE_LENGHT_MAX) {
- try {
- fBuffer.resize(fMessageLength);
- } catch(...) {
- handler(boost::system::errc::make_error_code(boost::system::errc::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::errc::message_size), 0);
- }
- } else {
- handler(error, 0);
- }
- });
- }
-
- bool decode_received_message(google::protobuf::MessageLite& message);
-};
-
-#endif /* SHARED_PROTOBUF_ASIO_H_ */
--- /dev/null
+# Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# @file dcm-client/CMakeLists.txt
+# @author Dariusz Michaluk <d.michaluk@samsung.com>
+# @author Jaroslaw Pelczar <j.pelczar@samsung.com>
+
+FIND_PACKAGE(Threads REQUIRED)
+FIND_PACKAGE(Protobuf REQUIRED)
+
+FIND_LIBRARY(MBEDTLS_LIB mbedtls)
+
+FIND_PACKAGE(Boost REQUIRED
+ COMPONENTS
+ system)
+
+PKG_CHECK_MODULES(CLIENT_DEPS REQUIRED dlog)
+
+INCLUDE_DIRECTORIES(SYSTEM ${CLIENT_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+LINK_DIRECTORIES(${CLIENT_DEPS_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
+PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS dcm_support.proto)
+
+SET(TARGET_CLIENT "device-certificate-manager")
+ADD_LIBRARY(${TARGET_CLIENT}
+ SHARED
+ dcmclient.cpp
+ device_certificate_manager.cpp
+ ../shared/protobuf_asio.cpp
+ ${PROTO_SRCS}
+ ${PROTO_HDRS})
+
+TARGET_LINK_LIBRARIES(${TARGET_CLIENT}
+ ${Boost_SYSTEM_LIBRARY}
+ ${PROTOBUF_LITE_LIBRARIES}
+ ${MBEDTLS_LIB}
+ ${CLIENT_DEPS_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT})
+
+SET_PROPERTY(TARGET ${TARGET_CLIENT} APPEND PROPERTY LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.lds")
+SET_TARGET_PROPERTIES(${TARGET_CLIENT}
+ PROPERTIES
+ VERSION ${PROJECT_VERSION}
+ DEFINE_SYMBOL DEVICE_CERTIFICATE_MANAGER_EXPORT
+ VISIBILITY_INLINES_HIDDEN TRUE
+ C_VISIBILITY_PRESET hidden
+ CXX_VISIBILITY_PRESET hidden)
+
+INSTALL(TARGETS ${TARGET_CLIENT}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+INSTALL(FILES
+ device_certificate_manager.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager)
+
+INSTALL(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/dcm_support.pb.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager-backend)
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 <mbedtls/md.h>
+
+#include <memory>
+#include <vector>
+
+class 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();
+ ~dcm_client_connection();
+
+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
+ */
+ virtual int sign_data(mbedtls_md_type_t digestType,
+ const void * hash_data, size_t hash_size,
+ std::vector<uint8_t>& digest) noexcept = 0;
+};
+
+#endif /* DCM_CLIENT_DCM_CLIENT_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 dcm_client_connection_impl final : public dcm_client_connection
+{
+public:
+ dcm_client_connection_impl();
+ dcm_client_connection_impl(boost::asio::io_service& ioService);
+ virtual ~dcm_client_connection_impl();
+
+ bool create_context(const std::string& serviceName,
+ const std::string& usage,
+ const std::string& key_type) noexcept override;
+
+ int get_certificate_chain(std::vector<uint8_t>& chain) noexcept override;
+
+ const std::string& key_type() const noexcept override;
+
+ unsigned int key_length() const noexcept override;
+
+ int sign_data(mbedtls_md_type_t digestType,
+ const void * hash_data, size_t hash_size,
+ std::vector<uint8_t>& digest) noexcept override;
+
+ void sendReceive(RequestMessage& request, ResponseMessage& response);
+
+private:
+ void ensureSocketConnected();
+
+
+private:
+ boost::asio::io_service fIOService;
+ std::mutex fLock;
+ uint64_t fCookie = 0;
+ std::unique_ptr<boost::asio::local::stream_protocol::socket> fSocket;
+ CryptoKeyType fKeyType = CRYPTO_KEY_TYPE_INVALID;
+ unsigned int fKeyLength = 0;
+};
+
+#endif /* DCM_CLIENT_DCM_CLIENT_P_H_ */
--- /dev/null
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+/*
+ * Type of the crypto key
+ */
+enum CryptoKeyType {
+ CRYPTO_KEY_TYPE_INVALID = 0;
+ CRYPTO_KEY_TYPE_ECDSA = 1;
+ CRYPTO_KEY_TYPE_RSA = 2;
+}
+
+/*
+ * These values match the mbedtls ones
+ */
+enum MessageDigestType {
+ MD_NONE = 0;
+ MD_MD2 = 1;
+ MD_MD4 = 2;
+ MD_MD5 = 3;
+ MD_SHA1 = 4;
+ MD_SHA224 = 5;
+ MD_SHA256 = 6;
+ MD_SHA384 = 7;
+ MD_SHA512 = 8;
+ MD_RIPEMD160 = 9;
+}
+
+message AssociateKeyContext
+{
+ required string service = 1;
+ required string usage = 2;
+ required string key_type = 3;
+}
+
+message AssociateKeyContextResponse
+{
+ required int32 result = 1;
+ optional uint64 context_cookie = 2;
+ optional CryptoKeyType key_type = 3;
+ optional uint32 key_length = 4;
+}
+
+message RequestCertificateChain
+{
+ required uint64 context_cookie = 1;
+}
+
+message RequestCertificateChainResponse
+{
+ required int32 result = 1;
+ optional bytes cert_chain = 2;
+}
+
+message SignRequest
+{
+ required uint64 context_cookie = 1;
+ required bytes data_to_sign = 2;
+ required MessageDigestType digest_type = 3;
+}
+
+message SignResponse
+{
+ required int32 result = 1;
+ optional bytes signature = 2;
+}
+
+message RequestMessage {
+ oneof request_oneof {
+ AssociateKeyContext associate_context = 1;
+ RequestCertificateChain request_chain = 2;
+ SignRequest sign_data = 3;
+ }
+}
+
+message ResponseMessage {
+ oneof reply_oneof {
+ AssociateKeyContextResponse associate_context = 1;
+ RequestCertificateChainResponse request_chain = 2;
+ SignResponse sign_data = 3;
+ }
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "dcm_client_p.h"
+#include "dcm_support.pb.h"
+#include "device_certificate_manager.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>
+#include <mbedtls/ssl.h>
+
+#define LOG_TAG "DCM_CLIENT"
+#include <dlog.h>
+
+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()
+{
+}
+
+dcm_client_connection::~dcm_client_connection()
+{
+}
+
+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)
+{
+ protobuf_sync_message_serialization(*fSocket).encodeMessage(request);
+ protobuf_sync_message_deserialization(*fSocket).decodeMessage(response);
+}
+
+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) {
+ LOGE("%s: Cookie has already been requested for session %p", __FUNCTION__, this);
+ // Already created
+ return false;
+ }
+
+ if(!fSocket) {
+ try {
+ ensureSocketConnected();
+ } catch(std::exception& ex) {
+ LOGE("%s: Caught exception \"%s\" when connecting socket for session %p", __FUNCTION__, ex.what(), this);
+ return false;
+ } catch(...) {
+ LOGE("%s: Caught unknown exception when connecting socket for session %p", __FUNCTION__, this);
+ return false;
+ }
+ }
+
+ 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()) {
+ LOGE("%s: received response is not context association message in context %p", __FUNCTION__, this);
+ return false;
+ }
+
+ auto& assoc_message(response.associate_context());
+
+ if(assoc_message.result() != 0) {
+ LOGE("%s: Received context association message with error %d in %p", __FUNCTION__, assoc_message.result(), this);
+ return false;
+ }
+
+ fCookie = assoc_message.context_cookie();
+ fKeyType = assoc_message.key_type();
+ fKeyLength = assoc_message.key_length();
+ } catch(std::exception& ex) {
+ LOGE("%s: Caught exception \"%s\" when establishing cookie for session %p", __FUNCTION__, ex.what(), this);
+ fSocket.reset();
+ return false;
+ } catch(...) {
+ LOGE("%s: Caught unknown exception when establishing cookie for session %p", __FUNCTION__, this);
+ 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) {
+ LOGE("%s: Trying to request certificate in session %p without connection", __FUNCTION__, this);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ 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()) {
+ LOGE("%s: Response from server is not certificate chain response on session %p", __FUNCTION__, this);
+ return DCM_ERROR_NO_DATA;
+ }
+
+ auto& cert_resp(response.request_chain());
+
+ if(cert_resp.result() != 0) {
+ LOGE("%s: Server can't respond with certificate chain: error %d in session %p", __FUNCTION__,
+ cert_resp.result(), this);
+ return DCM_ERROR_NO_DATA;
+ }
+
+ if(cert_resp.cert_chain().size() == 0) {
+ LOGE("%s: Server can't respond with certificate chain: certificate empty", __FUNCTION__);
+ return DCM_ERROR_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);
+ }
+ } catch(std::bad_alloc&) {
+ LOGE("%s: Out of memory when requesting certificate for session %p", __FUNCTION__, this);
+ return DCM_ERROR_OUT_OF_MEMORY;
+ } catch(std::invalid_argument&) {
+ LOGE("%s: Invalid argument passed for certificate request for session %p", __FUNCTION__, this);
+ return DCM_ERROR_INVALID_PARAMETER;
+ } catch(std::exception& ex) {
+ LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, ex.what());
+ return DCM_ERROR_UNKNOWN;
+ } catch(...) {
+ LOGE("%s: When requesting certificate for session %p received exception : %s", __FUNCTION__, this, "Unknown error");
+ return DCM_ERROR_UNKNOWN;
+ }
+
+ return DCM_ERROR_NONE;
+}
+
+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) {
+ LOGE("%s: Trying to request data signing in object %p but there is no connection", __FUNCTION__, this);
+ return DCM_ERROR_SOCKET;
+ }
+
+ /*
+ * If hash_size == 0 then hash type must be known
+ */
+ if(hash_size == 0) {
+ if(digestType == MBEDTLS_MD_NONE) {
+ LOGE("%s: Digest type is NONE and hash size is 0", __FUNCTION__);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(digestType);
+
+ if(!md_info) {
+ LOGE("%s: Can't find hash data for digest type %d", __FUNCTION__, digestType);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ hash_size = mbedtls_md_get_size(md_info);
+ } else if(hash_size != 0 && digestType != MBEDTLS_MD_NONE) {
+ /*
+ * If hash_size != 0 then hash type can be specified
+ */
+ const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type(digestType);
+
+ if(!md_info) {
+ LOGE("%s: Can't find hash data for digest type %d", __FUNCTION__, digestType);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ if(hash_size != mbedtls_md_get_size(md_info)) {
+ LOGE("%s: Hash size mismatch. Expected %zd but got %zd", __FUNCTION__, hash_size, (size_t)mbedtls_md_get_size(md_info));
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ 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()) {
+ LOGE("%s: Response for hash signature has no signature data", __FUNCTION__);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ auto& sign_resp(response.sign_data());
+
+ if(sign_resp.result() != 0) {
+ LOGE("%s: Signature request for session %p received error %d", __FUNCTION__, this, sign_resp.result());
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ const auto& signature = sign_resp.signature();
+
+ if(signature.empty()) {
+ LOGE("%s: Received signature object is empty for session %p", __FUNCTION__, this);
+ return DCM_ERROR_INVALID_PARAMETER;
+ }
+
+ digest.resize(signature.size());
+ memcpy(&digest[0], signature.c_str(), signature.size());
+ } catch(std::bad_alloc&) {
+ LOGE("%s: Out of memory when processing sign request for session %p", __FUNCTION__, this);
+ return DCM_ERROR_OUT_OF_MEMORY;
+ } catch(...) {
+ LOGE("%s: When processing signature for session %p got exception : %s", __FUNCTION__, this, "Unknown error");
+ return DCM_ERROR_UNKNOWN;
+ }
+
+ return DCM_ERROR_NONE;
+}
+
+unsigned int dcm_client_connection_impl::key_length() const noexcept {
+ return fKeyLength;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#include "device_certificate_manager.h"
+#include "dcm_client.h"
+
+#include <mbedtls/pk_internal.h>
+#include <mbedtls/md.h>
+
+#include <vector>
+#include <cstring>
+
+#ifndef API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+#define API_DEVICE_CERTIFICATE_MANAGER_EXPORT __attribute__((visibility("default")))
+#endif
+
+#define LOG_TAG "DCM_CLIENT"
+#include <dlog.h>
+
+static mbedtls_md_type_t to_mbedtls_md_type(dcm_digest_algorithm_e md)
+{
+ switch(md) {
+ case DCM_DIGEST_NONE:
+ return MBEDTLS_MD_NONE;
+ case DCM_DIGEST_MD2:
+ return MBEDTLS_MD_MD2;
+ case DCM_DIGEST_MD4:
+ return MBEDTLS_MD_MD4;
+ case DCM_DIGEST_MD5:
+ return MBEDTLS_MD_MD5;
+ case DCM_DIGEST_SHA1:
+ return MBEDTLS_MD_SHA1;
+ case DCM_DIGEST_SHA224:
+ return MBEDTLS_MD_SHA224;
+ case DCM_DIGEST_SHA256:
+ return MBEDTLS_MD_SHA256;
+ case DCM_DIGEST_SHA384:
+ return MBEDTLS_MD_SHA384;
+ case DCM_DIGEST_SHA512:
+ return MBEDTLS_MD_SHA512;
+ case DCM_DIGEST_RIPEMD160:
+ return MBEDTLS_MD_RIPEMD160;
+ default:
+ return MBEDTLS_MD_NONE;
+ }
+}
+
+struct dcm_key_context_internal {
+ std::shared_ptr<dcm_client_connection> connection;
+};
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_create_key_context(const char *service, const char *usage, const char *key_type, void **key_ctx)
+{
+ try {
+ if(!key_ctx)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ 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(key_type ? key_type : "");
+
+ context->connection = dcm_client_connection::create();
+
+ if(!context->connection->create_context(service_string, usage_string, keytype_string)) {
+ LOGE("Can't create connection context");
+ return DCM_ERROR_SOCKET;
+ }
+
+ *key_ctx = context.release();
+ return DCM_ERROR_NONE;
+ } catch(std::exception& ex) {
+ LOGE("Context creation failure: %s", ex.what());
+ return DCM_ERROR_UNKNOWN;
+ } catch(...) {
+ LOGE("Context creation failure");
+ return DCM_ERROR_UNKNOWN;
+ }
+}
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_free_key_context(void *key_ctx)
+{
+ if(!key_ctx)
+ return DCM_ERROR_NONE;
+
+ delete reinterpret_cast<dcm_key_context_internal *>(key_ctx);
+
+ return DCM_ERROR_NONE;
+}
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_get_certificate_chain(const void *key_ctx, char **cert_chain, size_t *cert_chain_len)
+{
+ if(!key_ctx || !cert_chain || !cert_chain_len)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ const dcm_key_context_internal *context =
+ reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
+
+ std::vector<uint8_t> cert;
+ int result = context->connection->get_certificate_chain(cert);
+ if(result == DCM_ERROR_NONE) {
+ *cert_chain = (char*)malloc(sizeof(uint8_t) * cert.size());
+ if(*cert_chain == NULL)
+ return DCM_ERROR_OUT_OF_MEMORY;
+ memcpy(*cert_chain, cert.data(), cert.size());
+ *cert_chain_len = cert.size();
+ }
+
+ return result;
+}
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_get_key_bit_length(const void *key_ctx, size_t *key_bit_len)
+{
+ if(!key_ctx || !key_bit_len)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ const dcm_key_context_internal *context =
+ reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
+ *key_bit_len = context->connection->key_length();
+
+ return DCM_ERROR_NONE;
+}
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_get_key_type(const void *key_ctx, char **key_type)
+{
+ if(!key_ctx || !key_type)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ const dcm_key_context_internal *context =
+ reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
+
+ std::string type = context->connection->key_type();
+ *key_type = (char*)malloc(sizeof(char) * (type.length() + 1));
+ if(*key_type == NULL)
+ return DCM_ERROR_OUT_OF_MEMORY;
+ memcpy(*key_type, type.c_str(), type.length() + 1);
+
+ return DCM_ERROR_NONE;
+}
+
+API_DEVICE_CERTIFICATE_MANAGER_EXPORT
+int dcm_create_signature(const void *key_ctx, dcm_digest_algorithm_e md,
+ const char *message, size_t message_len,
+ char **signature, size_t *signature_len)
+{
+ if(!key_ctx || !signature || !signature_len)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ const dcm_key_context_internal *context =
+ reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
+
+ std::vector<uint8_t> digest;
+ int result = context->connection->sign_data(to_mbedtls_md_type(md), message, message_len, digest);
+ if(result == DCM_ERROR_NONE) {
+ if(digest.size() > MBEDTLS_MPI_MAX_SIZE)
+ return DCM_ERROR_INVALID_PARAMETER;
+
+ *signature = (char*)malloc(sizeof(uint8_t) * digest.size());
+ if(*signature == NULL)
+ return DCM_ERROR_OUT_OF_MEMORY;
+ memcpy(*signature, digest.data(), digest.size());
+ *signature_len = digest.size();
+ }
+
+ return result;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2018 Samsung Electronics All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef __DEVICE_CERTIFICATE_MANAGER_H__
+#define __DEVICE_CERTIFICATE_MANAGER_H__
+
+#include <stddef.h>
+#include <tizen.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_DEVICE_CERTIFICATE_MANAGER_MODULE
+ * @{
+ */
+
+
+/**
+ * @brief Enumeration for DCM error values.
+ * @since_tizen 5.0
+ */
+typedef enum {
+ DCM_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ DCM_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid function parameter */
+ DCM_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+ DCM_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+ DCM_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Feature needed to run API is not supported */
+ DCM_ERROR_NO_DATA = TIZEN_ERROR_NO_DATA, /**< No data available */
+ DCM_ERROR_UNKNOWN = TIZEN_ERROR_UNKNOWN, /**< Unknown error */
+
+ DCM_ERROR_SOCKET = TIZEN_ERROR_DEVICE_CERTIFICATE_MANAGER | 0x01, /**< Socket error between client and server */
+} dcm_error_e;
+
+
+/**
+ * @brief Enumeration for DCM message digest algorithms.
+ * @since_tizen 5.0
+ */
+typedef enum {
+ DCM_DIGEST_NONE=0, /**< No message digest algorithm */
+ DCM_DIGEST_MD2, /**< Message digest algorithm MD2 */
+ DCM_DIGEST_MD4, /**< Message digest algorithm MD4 */
+ DCM_DIGEST_MD5, /**< Message digest algorithm MD5 */
+ DCM_DIGEST_SHA1, /**< Message digest algorithm SHA1 */
+ DCM_DIGEST_SHA224, /**< Message digest algorithm SHA224 */
+ DCM_DIGEST_SHA256, /**< Message digest algorithm SHA256 */
+ DCM_DIGEST_SHA384, /**< Message digest algorithm SHA384 */
+ DCM_DIGEST_SHA512, /**< Message digest algorithm SHA512 */
+ DCM_DIGEST_RIPEMD160, /**< Message digest algorithm RIPEMD160 */
+} dcm_digest_algorithm_e;
+
+
+/**
+ * @platform
+ * @brief Creates a new key context based on specific name indication (service name, key usage, key type).
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The @a key_ctx should be freed with dcm_free_key_context() after use.
+ *
+ * @param[in] service Service name indicates first category name (if null, default value is used)
+ * @param[in] usage Usage name indicates sub-category name (if null, default value is used)
+ * @param[in] key_type Key type name indication (if null, default value is used)
+ * @param[out] key_ctx Newly created key context
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ *
+ * @see dcm_free_key_context()
+ */
+int dcm_create_key_context(const char *service, const char *usage, const char *key_type, void **key_ctx);
+
+
+/**
+ * @platform
+ * @brief Destroys the key context that was created by calling dcm_create_key_context().
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @param[in] key_ctx Key context object to be deallocated
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA No such key context object
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ *
+ * @see dcm_create_key_context()
+ */
+int dcm_free_key_context(void *key_ctx);
+
+
+/**
+ * @platform
+ * @brief Returns a certificate chain which was pre-injected in device.
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The @a cert_chain should be freed using free().
+ *
+ * @param[in] key_ctx Key context object that identifies proper certificate chain
+ * @param[out] cert_chain Certificate chain in binary, will be allocated by the library
+ * @param[out] cert_chain_len The total length of certificate chain
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA No certificate chain available
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ */
+int dcm_get_certificate_chain(const void *key_ctx, char **cert_chain, size_t *cert_chain_len);
+
+
+/**
+ * @platform
+ * @brief Returns the key size in bits for a given key context.
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @param[in] key_ctx Key context object that identifies proper certificate chain
+ * @param[out] key_bit_len Key length in bits
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA No certificate chain available
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ */
+int dcm_get_key_bit_length(const void *key_ctx, size_t *key_bit_len);
+
+
+/**
+ * @platform
+ * @brief Returns the key type name for a given key context.
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The @a key_type should be freed using free().
+ *
+ * @param[in] key_ctx Key context object that identifies proper certificate chain
+ * @param[out] key_type Key type name (UNKNOWN, RSA or ECDSA), will be allocated by the library
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA No certificate chain available
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ */
+int dcm_get_key_type(const void *key_ctx, char **key_type);
+
+/**
+ * @platform
+ * @brief Creates a signature on a given data using a private key and returns the signature.
+ * @since_tizen 5.0
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The private key is identified by @a key_ctx.
+ * @remarks The @a message can be NULL but then @a message_len must be 0.
+ * @remarks The @a signature should be freed using free().
+ *
+ * @param[in] key_ctx Key context object that identifies a proper private key for signing
+ * @param[in] md Message digest algorithm used in creating signature
+ * @param[in] message Message that is signed with a key
+ * @param[in] message_len Length of the message
+ * @param[out] signature Newly created signature, will be allocated by the library
+ * @param[out] signature_len Length of a newly created signature
+ * @return #DCM_ERROR_NONE on success,
+ * otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ */
+int dcm_create_signature(const void *key_ctx, dcm_digest_algorithm_e md,
+ const char *message, size_t message_len,
+ char **signature, size_t *signature_len);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DEVICE_CERTIFICATE_MANAGER_H__ */
--- /dev/null
+DCMCLIENT_2.0 {
+ global:
+ dcm_create_key_context;
+ dcm_free_key_context;
+ dcm_get_certificate_chain;
+ dcm_get_key_bit_length;
+ dcm_get_key_type;
+ dcm_create_signature;
+ local:
+ *;
+};
--- /dev/null
+# Copyright (c) 2017 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# @file dcm-daemon/CMakeLists.txt
+# @author Dariusz Michaluk <d.michaluk@samsung.com>
+# @author Jaroslaw Pelczar <j.pelczar@samsung.com>
+
+FIND_PACKAGE(Threads REQUIRED)
+FIND_PACKAGE(Protobuf REQUIRED)
+
+FIND_PACKAGE(Boost REQUIRED
+ COMPONENTS
+ log
+ thread
+ system)
+
+PKG_CHECK_MODULES(DAEMON_DEPS
+ REQUIRED
+ libsystemd
+ cynara-client
+ cynara-creds-socket
+ cynara-session
+ dlog)
+
+INCLUDE_DIRECTORIES(SYSTEM ${DAEMON_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+LINK_DIRECTORIES(${DAEMON_DEPS_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
+PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ../dcm-client/dcm_support.proto)
+
+ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
+
+SET(TARGET_DAEMON "device-certificate-managerd")
+ADD_EXECUTABLE(${TARGET_DAEMON}
+ main.cpp
+ dcmserver.cpp
+ dcmsession.cpp
+ serviceadapter.cpp
+ ../shared/protobuf_asio.cpp
+ soresolver.cpp
+ ${PROTO_SRCS}
+ ${PROTO_HDRS})
+
+TARGET_LINK_LIBRARIES(${TARGET_DAEMON}
+ ${Boost_LOG_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${PROTOBUF_LITE_LIBRARIES}
+ ${DAEMON_DEPS_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ dl)
+
+INSTALL(TARGETS ${TARGET_DAEMON}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+INSTALL(FILES
+ dcm-backend-api.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/device-certificate-manager-backend)
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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>
+
+#include <dlog.h>
+
+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) {
+ dlog_print(level, log_domain_.c_str(), "%s", formatted_message.c_str());
+ }
+
+public:
+ dlog_output_backend()
+ {
+ }
+
+ void consume(boost::log::record_view const& rec, string_type const& formatted_message) {
+ if(!level_mapper_) {
+ send(DLOG_DEBUG, formatted_message);
+ } else {
+ send(level_mapper_(rec), formatted_message);
+ }
+ }
+
+ void set_log_domain(const std::string& name)
+ {
+ log_domain_ = name;
+ }
+
+ void set_severity_mapper(severity_mapper_type const& mapper)
+ {
+ level_mapper_ = mapper;
+ }
+};
+
+#endif /* SHARED_BOOST_LOG_DLOG_SINK_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2019 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Pawel Kowalski <p.kowalski2@partner.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_BACKEND_API_H_
+#define DCM_BACKEND_API_H_
+
+#include "dcm_support.pb.h"
+
+#ifndef API_DCM_BACKEND_EXPORT
+#define API_DCM_BACKEND_EXPORT __attribute__((visibility("default")))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct dcm_backend_context {
+ void* backend;
+};
+
+API_DCM_BACKEND_EXPORT
+void dcm_backend_create_key_context(dcm_backend_context& ctx,
+ const std::string& keyType);
+
+API_DCM_BACKEND_EXPORT
+void dcm_backend_free_key_context(dcm_backend_context& ctx);
+
+API_DCM_BACKEND_EXPORT
+int dcm_backend_request_certificate_chain(dcm_backend_context& ctx,
+ std::string& mutable_chain);
+
+API_DCM_BACKEND_EXPORT
+int dcm_backend_sign_crypto_data(dcm_backend_context& ctx,
+ MessageDigestType digestType,
+ const std::string& dataToSign,
+ std::string& digestResult);
+
+API_DCM_BACKEND_EXPORT
+CryptoKeyType dcm_backend_key_type(dcm_backend_context& ctx);
+
+API_DCM_BACKEND_EXPORT
+unsigned int dcm_backend_key_length(dcm_backend_context& ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DCM_BACKEND_API_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2019 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, std::string lib_backend) :
+ fService(io_service),
+ fTimer(io_service),
+ fAcceptor(std::move(acceptor)),
+ fSoResolver(std::make_shared<so_resolver>(lib_backend))
+{
+ 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, fTimer, shared_from_this(), fSoResolver);
+ } 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";
+ session->start_timer();
+
+ 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();
+ });
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2019 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>
+#include "soresolver.h"
+
+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, std::string lib_backend);
+ ~dcm_server();
+ void start();
+
+private:
+ void do_accept();
+
+private:
+ boost::asio::io_service& fService;
+ boost::asio::deadline_timer fTimer;
+ boost::asio::local::stream_protocol::acceptor fAcceptor;
+ std::mutex fLock;
+ std::shared_ptr<so_resolver> fSoResolver;
+};
+
+#endif /* DCM_DAEMON_DCMSERVER_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 <iostream>
+#include <cassert>
+#include <map>
+#include <mutex>
+
+#include <cynara-client.h>
+#include <cynara-creds-socket.h>
+#include <cynara-session.h>
+
+extern cynara * gGlobalCynaraInstance;
+
+static inline std::string cynara_error_to_string(int error) {
+ char buffer[256];
+ int ret = cynara_strerror(error, buffer, sizeof(buffer));
+ if(ret == CYNARA_API_SUCCESS)
+ return std::string(buffer);
+ return std::string("Can't translate error");
+}
+
+unsigned int globalSessionCounter = 0;
+
+dcm_session::dcm_session(boost::asio::io_service& io_service,
+ boost::asio::deadline_timer& timer,
+ const std::shared_ptr<dcm_server>& server,
+ std::shared_ptr<so_resolver> soResolver) :
+ fService(io_service),
+ fTimer(timer),
+ fSocket(io_service),
+ fServer(server),
+ fSoResolver(soResolver)
+{
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create new session object " << this;
+ globalSessionCounter++;
+}
+
+dcm_session::~dcm_session()
+{
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Destroy session object " << this;
+}
+
+struct string_free_deleter {
+ void operator()(char * p) const {
+ free(p);
+ }
+};
+
+bool dcm_session::verify_privileges(int handle)
+{
+ BOOST_LOG_FUNCTION();
+
+ int ret = 0;
+ char * tmp_str;
+ pid_t pid = 0;
+
+ std::unique_ptr<char, string_free_deleter> user;
+ std::unique_ptr<char, string_free_deleter> client;
+ std::unique_ptr<char, string_free_deleter> client_session;
+
+ /* Get user info */
+ tmp_str = nullptr;
+ ret = cynara_creds_socket_get_user(handle, USER_METHOD_DEFAULT, &tmp_str);
+ if(ret != CYNARA_API_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get user from socket : " << ret << " - " << cynara_error_to_string(ret);
+ return false;
+ }
+ user.reset(tmp_str);
+
+ /* Get client info */
+ tmp_str = nullptr;
+ ret = cynara_creds_socket_get_client(handle, CLIENT_METHOD_DEFAULT, &tmp_str);
+ if(ret != CYNARA_API_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get client from socket : " << ret << " - " << cynara_error_to_string(ret);
+ return false;
+ }
+ client.reset(tmp_str);
+
+
+ /* Get client PID from socket */
+ ret = cynara_creds_socket_get_pid(handle, &pid);
+ if(ret != CYNARA_API_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get PID from socket : " << ret << " - " << cynara_error_to_string(ret);
+ return false;
+ }
+
+ client_session.reset(cynara_session_from_pid(pid));
+ if(!client_session) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't get session identifier from PID";
+ return false;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Got new session from " << pid << " with user " <<
+ user.get() << ", client ID " << client.get() << " and session ID " << client_session.get();
+
+ ret = cynara_check(gGlobalCynaraInstance,
+ client.get(),
+ client_session.get(),
+ user.get(),
+ "http://tizen.org/privilege/devicecertificate");
+
+ if(ret != CYNARA_API_ACCESS_ALLOWED) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) <<
+ "Application access denied - no internet permission for " <<
+ pid <<
+ " - " <<
+ cynara_error_to_string(ret);
+
+ return false;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Access granted for " << pid;
+
+ 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();
+
+ if(verify_privileges(handle)) {
+ stop_timer();
+ do_receive();
+ } else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Client privilege check failure. Disconnect";
+ start_timer();
+ }
+}
+
+void dcm_session::start_timer()
+{
+ globalSessionCounter--;
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Number of active connections: " << globalSessionCounter;
+
+ if(globalSessionCounter == 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "No active connections, server will be closed after few seconds";
+ fTimer.expires_from_now(boost::posix_time::seconds(10));
+ /* operation_aborted error is returned whenever we cancel the timer or we reset the timer using expires_from_now function */
+ fTimer.async_wait([this](const boost::system::error_code &error) {
+ if(error != boost::asio::error::operation_aborted) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "No active connections, server will be closed";
+ fService.stop();
+ }
+ });
+ }
+}
+
+void dcm_session::stop_timer()
+{
+ globalSessionCounter++;
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Number of active connections: " << globalSessionCounter;
+
+ fTimer.cancel();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Timer cancelled";
+}
+
+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
+ start_timer();
+ }
+ });
+ } 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(fBackendContext) {
+ 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([&]() {
+
+ bool loaded = fSoResolver->ensure_loaded();
+ if (loaded) {
+ fBackendContext = std::unique_ptr<dcm_backend_context>(new dcm_backend_context);
+
+ fSoResolver->invoke<void, dcm_backend_context&, const std::string&>(
+ "dcm_backend_create_key_context",
+ *fBackendContext,
+ message.key_type()
+ );
+
+ CryptoKeyType crypto_key_type = fSoResolver->invoke<CryptoKeyType, dcm_backend_context&>(
+ "dcm_backend_key_type",
+ *fBackendContext
+ );
+ contextResponse->set_key_type(crypto_key_type);
+
+ unsigned int crypto_key_length = fSoResolver->invoke<unsigned int, dcm_backend_context&>(
+ "dcm_backend_key_length",
+ *fBackendContext
+ );
+ contextResponse->set_key_length(crypto_key_length);
+ }
+ else {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "No crypto usable backend available";
+ throw std::invalid_argument("Unable to find crypto backend");
+ }
+ fCookie = (uintptr_t)fBackendContext.get();
+ contextResponse->set_context_cookie(fCookie);
+ });
+
+ contextResponse->set_result(error);
+
+ reply(msg);
+}
+
+static const std::string sPEMHeader("-----BEGIN CERTIFICATE-----\n");
+
+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(!fBackendContext) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
+ certificateResponse->set_result(-EINVAL);
+ reply(msg);
+ return;
+ }
+
+ std::string cert_chain;
+
+ int error = 0;
+ bool loaded = fSoResolver->ensure_loaded();
+ if (loaded) {
+ error = fSoResolver->invoke<int, dcm_backend_context&, std::string&>(
+ "dcm_backend_request_certificate_chain",
+ *fBackendContext,
+ cert_chain
+ );
+ }
+
+ if(error != 0) {
+ certificateResponse->set_result(error);
+ reply(msg);
+ return;
+ }
+
+ if(cert_chain.length() >= sPEMHeader.length() &&
+ !memcmp(sPEMHeader.c_str(), cert_chain.c_str(), sPEMHeader.size()) &&
+ cert_chain[cert_chain.size() - 1] != '\0')
+ {
+ // Add missing 0
+ cert_chain.push_back(0);
+ }
+
+ *certificateResponse->mutable_cert_chain() = cert_chain;
+
+ certificateResponse->set_result(0);
+ 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(-EINVAL);
+ reply(msg);
+ return;
+ }
+
+ if(!fBackendContext) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Context not associated with connection";
+ signingResponse->set_result(-EINVAL);
+ reply(msg);
+ return;
+ }
+
+ if(message.data_to_sign().size() == 0) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Data to sign is empty and hash type is NONE";
+ signingResponse->set_result(-EINVAL);
+ return;
+ }
+
+ int error = 0;
+ bool loaded = fSoResolver->ensure_loaded();
+ if (loaded) {
+ error = fSoResolver->invoke<int, dcm_backend_context&, MessageDigestType, const std::string&, std::string&>(
+ "dcm_backend_sign_crypto_data",
+ *fBackendContext,
+ message.digest_type(),
+ message.data_to_sign(),
+ *signingResponse->mutable_signature()
+ );
+ }
+ signingResponse->set_result(error);
+
+ reply(msg);
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2019 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 "protobuf_asio.h"
+#include "dcm-backend-api.h"
+#include "soresolver.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, boost::asio::deadline_timer& timer, const std::shared_ptr<dcm_server>& server, std::shared_ptr<so_resolver> soResolver);
+ ~dcm_session();
+
+ void start();
+ void start_timer();
+ void stop_timer();
+
+ 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 verify_privileges(int handle);
+
+ 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::deadline_timer& fTimer;
+ 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<dcm_backend_context> fBackendContext;
+ std::shared_ptr<so_resolver> fSoResolver;
+ uint64_t fCookie = 0;
+};
+
+#endif /* DCM_DAEMON_DCMSESSION_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 Samsung Electronics All Rights Reserved.
+ *
+ * Author: Jaroslaw Pelczar <j.pelczar@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************/
+
+#ifndef DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
+#define DCM_DAEMON_EXCEPTION_TRANSLATOR_H_
+
+#include <memory>
+#include <stdexcept>
+#include <cerrno>
+#include <boost/system/system_error.hpp>
+
+template<typename T> inline int run_with_exception_handler(T t) {
+ try {
+ t();
+ } catch(boost::system::system_error& ex) {
+ return -ex.code().value();
+ } catch(std::bad_alloc&) {
+ return -ENOMEM;
+ } catch(std::domain_error&) {
+ return -EDOM;
+ } catch(std::invalid_argument&) {
+ return -EINVAL;
+ } catch(std::length_error&) {
+ return -EINVAL;
+ } catch(std::out_of_range&) {
+ return -EINVAL;
+ } catch(std::range_error&) {
+ return -ERANGE;
+ } catch(std::overflow_error&) {
+ return -EOVERFLOW;
+ } catch(std::underflow_error&) {
+ return -EOVERFLOW;
+ } catch(std::exception&) {
+ return -EINVAL;
+ } catch(...) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#endif /* DCM_DAEMON_EXCEPTION_TRANSLATOR_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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>
+
+#define LOG_TAG "DCM_SERVER"
+#include <dlog.h>
+
+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>)
+
+#if defined(NDEBUG) && !defined(DEBUG)
+#else
+#define ENABLE_DEBUG_LOGGING 1
+#endif
+
+#endif /* DCM_DAEMON_LOGGING_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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/asio.hpp>
+
+#include <iostream>
+#include <unistd.h>
+#include <cstdlib>
+#include <sys/stat.h>
+#include <sys/signal.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"
+
+#include <cynara-client.h>
+
+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(LOG_TAG);
+
+#ifndef ENABLE_DEBUG_LOGGING
+ 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());
+}
+
+cynara * gGlobalCynaraInstance;
+
+int main()
+{
+ int error = 0;
+
+ try {
+ init_logging();
+ } catch(...) {
+ std::cerr << "init_logging() failed" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ BOOST_LOG_FUNCTION();
+
+ service_adapter serviceAdapter;
+
+ cynara_configuration * cynara_conf = nullptr;
+ error = cynara_configuration_create(&cynara_conf);
+ if(error != CYNARA_API_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't initialize Cynara configuration: " << error;
+ serviceAdapter.notify_start_failure(error);
+ return EXIT_FAILURE;
+ }
+
+ error = cynara_initialize(&gGlobalCynaraInstance, cynara_conf);
+
+ cynara_configuration_destroy(cynara_conf);
+
+ if(error != CYNARA_API_SUCCESS) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Can't initialize Cynara instance: " << error;
+ serviceAdapter.notify_start_failure(error);
+ return EXIT_FAILURE;
+ }
+
+ 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 */
+ error = chdir("/");
+ (void)error; // Don't care
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Create platform socket";
+
+ std::string lib_backend = "libdcm-backend-api.so.1.0";
+ auto server(std::make_shared<dcm_server>(io_service, serviceAdapter.create_platform_socket_acceptor(io_service), lib_backend));
+
+ 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;
+ }
+
+ cynara_finish(gGlobalCynaraInstance);
+ gGlobalCynaraInstance = nullptr;
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Server terminated";
+
+ return 0;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 <cstring>
+
+#include <systemd/sd-daemon.h>
+
+service_adapter::service_adapter()
+{
+}
+
+service_adapter::~service_adapter()
+{
+}
+
+boost::asio::local::stream_protocol::acceptor service_adapter::create_platform_socket_acceptor(boost::asio::io_service& io_service)
+{
+ BOOST_LOG_FUNCTION();
+
+ 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");
+}
+
+void service_adapter::notify_start_complete()
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::normal) << "Notify start completed to systemd";
+
+ sd_listen_fds(1);
+ sd_notify(0, "READY=1");
+ fStartCompleteNotified = true;
+}
+
+void service_adapter::notify_start_failure(int error)
+{
+ BOOST_LOG_FUNCTION();
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Notify start failure";
+
+ if(!fStartCompleteNotified) {
+ char buffer[512];
+ buffer[0] = '\0';
+ if(!strerror_r(error, buffer, sizeof(buffer)))
+ sd_notifyf(0, "STATUS=Failed to start up: %s\nERRNO=%d", buffer, error);
+ else
+ sd_notifyf(0, "STATUS=Failed to start up: (no message)\nERRNO=%d", error);
+ }
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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();
+ ~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 = DCM_UNIX_SOCKET_PATH;
+ bool fStartCompleteNotified = false;
+};
+
+#endif /* DCM_DAEMON_SERVICEADAPTER_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2019 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 "soresolver.h"
+#include "logging.h"
+#include <dlfcn.h>
+
+so_resolver::so_resolver(const std::string& libraryName) :
+ fLibraryName(libraryName),
+ fLibraryHandle(nullptr)
+{
+}
+
+so_resolver::~so_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 * so_resolver::resolve_function(const std::string& name) noexcept
+{
+ BOOST_LOG_FUNCTION();
+
+ std::unique_lock<std::mutex> locker(fCacheLock);
+ auto it = fCache.find(name);
+
+ 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.c_str());
+ if(!sym) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to resolve symbol " << name << " from " <<
+ fLibraryName << ": Error is " << dlerror();
+ } else {
+ try {
+ fCache.emplace(name, 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 so_resolver::ensure_loaded() noexcept
+{
+ BOOST_LOG_FUNCTION();
+
+ std::unique_lock<std::mutex> locker(fCacheLock);
+
+ void * handle = fLibraryHandle.load(std::memory_order_acquire);
+
+ if(handle)
+ return true;
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Loading library " << fLibraryName;
+
+ handle = dlopen(fLibraryName.c_str(), RTLD_LAZY | RTLD_LOCAL);
+
+ if(!handle) {
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::error) << "Unable to load library " << fLibraryName << ": " << dlerror();
+ return false;
+ }
+
+ BOOST_LOG_SEV(dcm_logger::get(), log_severity::debug) << "Library loaded " << fLibraryName;
+
+ void * expectedValue = nullptr;
+
+ if(!fLibraryHandle.compare_exchange_strong(expectedValue, handle, std::memory_order_release)) {
+ // Someone else have opened the library
+ dlclose(handle);
+ }
+
+ return true;
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2019 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_SORESOLVER_H_
+#define DCM_DAEMON_SORESOLVER_H_
+
+#include <boost/noncopyable.hpp>
+#include <string>
+#include <atomic>
+#include <stdexcept>
+#include <map>
+#include <mutex>
+#include <string>
+
+class so_resolver : public boost::noncopyable {
+public:
+ so_resolver(const std::string& libraryName);
+ ~so_resolver();
+
+ bool ensure_loaded() noexcept;
+ void * resolve_function(const std::string& name) noexcept;
+
+ template<typename ReturnValue, typename... Args> ReturnValue invoke(const std::string& name, Args... args) {
+ typedef ReturnValue (* function_t)(Args...);
+ function_t func = (function_t)resolve_function(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<std::string, void *> fCache;
+};
+
+#endif /* DCM_DAEMON_SORESOLVER_H_ */
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 <stdexcept>
+
+#include <google/protobuf/io/coded_stream.h>
+
+#include "protobuf_asio.h"
+
+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.ByteSizeLong());
+ 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 > MESSAGE_LENGHT_MAX) {
+ 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.ByteSizeLong();
+ fBuffer.resize(bufferSize + sizeof(uint32_t));
+ google::protobuf::io::CodedOutputStream::WriteLittleEndian32ToArray(bufferSize,
+ reinterpret_cast<google::protobuf::uint8 *>(&fBuffer[0]));
+ if(!message.SerializeToArray(&fBuffer[sizeof(uint32_t)], bufferSize)) {
+ throw std::invalid_argument("Message serialization error");
+ }
+}
+
+protobuf_async_message_deserialization::protobuf_async_message_deserialization()
+{
+ fBuffer.reserve(128);
+}
+
+bool protobuf_async_message_deserialization::decode_received_message(google::protobuf::MessageLite& message)
+{
+ return message.ParseFromArray(&fBuffer[0], fBuffer.size());
+}
--- /dev/null
+/******************************************************************
+ *
+ * Copyright 2017 - 2020 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 <vector>
+
+#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>
+
+static const size_t MESSAGE_LENGHT_MAX = 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());
+ (void)bytes_read;
+ assert(fMessageLength == 0);
+
+ google::protobuf::io::CodedInputStream::ReadLittleEndian32FromArray(
+ (const google::protobuf::uint8 *)&fBuffer[0], &fMessageLength);
+
+ if(fMessageLength >= 1 && fMessageLength < MESSAGE_LENGHT_MAX) {
+ try {
+ fBuffer.resize(fMessageLength);
+ } catch(...) {
+ handler(boost::system::errc::make_error_code(boost::system::errc::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::errc::message_size), 0);
+ }
+ } else {
+ handler(error, 0);
+ }
+ });
+ }
+
+ bool decode_received_message(google::protobuf::MessageLite& message);
+};
+
+#endif /* SHARED_PROTOBUF_ASIO_H_ */
INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
-INCLUDE_DIRECTORIES(../dcm-client)
+INCLUDE_DIRECTORIES(../src/dcm-client)
ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)