Check if DCM feature is supported on the device
[platform/core/security/device-certificate-manager.git] / src / dcm-client / device_certificate_manager.cpp
1 /******************************************************************
2  *
3  * Copyright 2017 - 2020 Samsung Electronics All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  ******************************************************************/
18
19 #include <vector>
20 #include <cstring>
21 #include <cstdlib>
22 #include <cassert>
23 #include <mutex>
24
25 #include <system_info.h>
26
27 #include "device_certificate_manager.h"
28 #include "dcm_client.h"
29 #include "log.h"
30 #include "bundle.h"
31
32 #ifndef API_DEVICE_CERTIFICATE_MANAGER_EXPORT
33 #define API_DEVICE_CERTIFICATE_MANAGER_EXPORT __attribute__((visibility("default")))
34 #endif
35
36 std::once_flag check_flag;
37 static int check_result;
38
39 void check_feature(void)
40 {
41         bool is_supported;
42         if (SYSTEM_INFO_ERROR_NONE != system_info_get_platform_bool(
43                 "http://tizen.org/feature/security.device_certificate", &is_supported))
44                 check_result = DCM_ERROR_UNKNOWN;
45         else if (!is_supported)
46                 check_result = DCM_ERROR_NOT_SUPPORTED;
47         else
48                 check_result = DCM_ERROR_NONE;
49 }
50
51 #define CHECK_FEATURE_SUPPORTED \
52         do { \
53                 try { \
54                         std::call_once(check_flag, check_feature); \
55                         if (check_result != DCM_ERROR_NONE) \
56                                 return check_result; \
57                 } catch (...) { \
58                         return DCM_ERROR_UNKNOWN; \
59                 } \
60         } while (0)
61
62 struct dcm_key_context_internal {
63         std::shared_ptr<dcm_client_connection> connection;
64 };
65
66 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
67 int dcm_create_key_context(const char *service, const char *usage, const char *key_type, void **key_ctx)
68 {
69         CHECK_FEATURE_SUPPORTED;
70
71         try {
72                 if(!key_ctx)
73                         return DCM_ERROR_INVALID_PARAMETER;
74
75                 std::unique_ptr<dcm_key_context_internal> context(new dcm_key_context_internal());
76
77                 std::string service_string(service ? service : "");
78                 std::string usage_string(usage ? usage : "");
79                 std::string keytype_string(key_type ? key_type : "");
80
81                 context->connection = dcm_client_connection::create();
82
83                 int result = context->connection->create_context(service_string, usage_string, keytype_string);
84                 if(result != DCM_ERROR_NONE) {
85                         LOGE("Can't create connection context");
86                         return result;
87                 }
88
89                 *key_ctx = context.release();
90         } catch(std::exception& ex) {
91                 LOGE("Context creation failure: %s", ex.what());
92                 return DCM_ERROR_UNKNOWN;
93         } catch(...) {
94                 LOGE("Context creation failure");
95                 return DCM_ERROR_UNKNOWN;
96         }
97
98         return DCM_ERROR_NONE;
99 }
100
101 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
102 int dcm_free_key_context(void *key_ctx)
103 {
104         CHECK_FEATURE_SUPPORTED;
105
106         if(!key_ctx)
107                 return DCM_ERROR_NONE;
108
109         delete reinterpret_cast<dcm_key_context_internal *>(key_ctx);
110
111         return DCM_ERROR_NONE;
112 }
113
114 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
115 int dcm_get_certificate_chain(const void *key_ctx, char **cert_chain, size_t *cert_chain_len)
116 {
117         CHECK_FEATURE_SUPPORTED;
118
119         if(!key_ctx || !cert_chain || !cert_chain_len)
120                 return DCM_ERROR_INVALID_PARAMETER;
121
122         const dcm_key_context_internal *context =
123                 reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
124
125         std::vector<uint8_t> cert;
126         int result = context->connection->get_certificate_chain(cert);
127         if(result == DCM_ERROR_NONE) {
128                 *cert_chain = (char*)malloc(sizeof(uint8_t) * cert.size());
129                 if(*cert_chain == NULL)
130                         return DCM_ERROR_OUT_OF_MEMORY;
131                 memcpy(*cert_chain, cert.data(), cert.size());
132                 *cert_chain_len = cert.size();
133         }
134
135         return result;
136 }
137
138 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
139 int dcm_get_key_bit_length(const void *key_ctx, size_t *key_bit_len)
140 {
141         CHECK_FEATURE_SUPPORTED;
142
143         if(!key_ctx || !key_bit_len)
144                 return DCM_ERROR_INVALID_PARAMETER;
145
146         const dcm_key_context_internal *context =
147                 reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
148         *key_bit_len = context->connection->key_length();
149
150         return DCM_ERROR_NONE;
151 }
152
153 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
154 int dcm_get_key_type(const void *key_ctx, char **key_type)
155 {
156         CHECK_FEATURE_SUPPORTED;
157
158         if(!key_ctx || !key_type)
159                 return DCM_ERROR_INVALID_PARAMETER;
160
161         const dcm_key_context_internal *context =
162                 reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
163
164         std::string type = context->connection->key_type();
165         *key_type = (char*)malloc(sizeof(char) * (type.length() + 1));
166         if(*key_type == NULL)
167                 return DCM_ERROR_OUT_OF_MEMORY;
168         memcpy(*key_type, type.c_str(), type.length() + 1);
169
170         return DCM_ERROR_NONE;
171 }
172
173 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
174 int dcm_create_signature(const void *key_ctx, dcm_digest_algorithm_e md,
175         const char *message, size_t message_len,
176         char **signature, size_t *signature_len)
177 {
178         CHECK_FEATURE_SUPPORTED;
179
180         if(!key_ctx || !signature || !signature_len)
181                 return DCM_ERROR_INVALID_PARAMETER;
182
183         const dcm_key_context_internal *context =
184                 reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
185
186         std::vector<uint8_t> digest;
187         int result = context->connection->sign_data(md, message, message_len, digest);
188         if(result == DCM_ERROR_NONE) {
189                 *signature = (char*)malloc(sizeof(uint8_t) * digest.size());
190                 if(*signature == NULL)
191                         return DCM_ERROR_OUT_OF_MEMORY;
192                 memcpy(*signature, digest.data(), digest.size());
193                 *signature_len = digest.size();
194         }
195
196         return result;
197 }
198
199 /**
200  * @brief Struct containing E2EE message bundle. Message = platform | pkg_id | payload.
201  * @remarks The platform and pkg_id are NULL terminated strings. The payload is a sequence of bytes.
202  * @since_tizen 6.5
203  */
204 struct dcm_e2ee_bundle_s {
205         unsigned char *message; /**< Byte array containing whole message */
206         size_t message_len;     /**< The size of the message */
207         size_t pkg_id_offset;   /**< Package id offset */
208         size_t payload_offset;  /**< Payload offset */
209 };
210
211 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
212 int dcm_e2ee_create_bundle(unsigned char *message,
213         size_t message_len,
214         dcm_e2ee_bundle_h* bundle)
215 {
216         CHECK_FEATURE_SUPPORTED;
217
218         if (message == NULL || bundle == NULL)
219                 return DCM_ERROR_INVALID_PARAMETER;
220
221         struct dcm_e2ee_bundle_s *tmp = static_cast<struct dcm_e2ee_bundle_s*>(
222                 malloc(sizeof(struct dcm_e2ee_bundle_s)));
223
224         if (tmp == NULL)
225                 return DCM_ERROR_OUT_OF_MEMORY;
226
227         int ret = decompose_e2ee_message(message, message_len, tmp->pkg_id_offset, tmp->payload_offset);
228         if (ret != DCM_ERROR_NONE) {
229                 free(tmp);
230                 return ret;
231         }
232
233         tmp->message_len = message_len;
234         tmp->message = message;
235
236         *bundle = tmp;
237         return DCM_ERROR_NONE;
238 }
239
240 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
241 void dcm_e2ee_free_bundle(dcm_e2ee_bundle_h bundle)
242 {
243         if (bundle == NULL)
244                 return;
245
246         free(bundle->message);
247         free(bundle);
248 }
249
250 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
251 int dcm_e2ee_get_bundle_message(const dcm_e2ee_bundle_h bundle,
252         const unsigned char** message,
253         size_t* message_len)
254 {
255         CHECK_FEATURE_SUPPORTED;
256
257         if (bundle == NULL || message == NULL || message_len == NULL)
258                 return DCM_ERROR_INVALID_PARAMETER;
259
260         assert(bundle->message != NULL);
261
262         *message = bundle->message;
263         *message_len = bundle->message_len;
264         return DCM_ERROR_NONE;
265 }
266
267 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
268 int dcm_e2ee_get_bundle_platform(const dcm_e2ee_bundle_h bundle, const char** platform)
269 {
270         CHECK_FEATURE_SUPPORTED;
271
272         if (bundle == NULL || platform == NULL)
273                 return DCM_ERROR_INVALID_PARAMETER;
274
275         assert(bundle->message != NULL);
276
277         *platform = reinterpret_cast<const char*>(bundle->message);
278         return DCM_ERROR_NONE;
279 }
280
281 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
282 int dcm_e2ee_get_bundle_pkg_id(const dcm_e2ee_bundle_h bundle, const char** pkg_id)
283 {
284         CHECK_FEATURE_SUPPORTED;
285
286         if (bundle == NULL || pkg_id == NULL)
287                 return DCM_ERROR_INVALID_PARAMETER;
288
289         assert(bundle->message != NULL);
290
291         *pkg_id = reinterpret_cast<const char*>(&bundle->message[bundle->pkg_id_offset]);
292         return DCM_ERROR_NONE;
293 }
294
295 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
296 int dcm_e2ee_get_bundle_payload(const dcm_e2ee_bundle_h bundle,
297         const unsigned char** payload,
298         size_t* payload_len)
299 {
300         CHECK_FEATURE_SUPPORTED;
301
302         if (bundle == NULL || payload == NULL || payload_len == NULL)
303                 return DCM_ERROR_INVALID_PARAMETER;
304
305         assert(bundle->message != NULL);
306
307         *payload = &bundle->message[bundle->payload_offset];
308         *payload_len = bundle->message_len - bundle->payload_offset;
309         return DCM_ERROR_NONE;
310 }
311
312 API_DEVICE_CERTIFICATE_MANAGER_EXPORT
313 int dcm_e2ee_create_signed_bundle(const void *key_ctx,
314         dcm_digest_algorithm_e md,
315         const unsigned char *payload,
316         size_t payload_len,
317         dcm_e2ee_bundle_h *bundle,
318         char **signature,
319         size_t *signature_len)
320 {
321         CHECK_FEATURE_SUPPORTED;
322
323         if (key_ctx == NULL || payload == NULL || bundle == NULL || signature == NULL ||
324                 signature_len == NULL)
325                 return DCM_ERROR_INVALID_PARAMETER;
326
327         const dcm_key_context_internal *context =
328                 reinterpret_cast<const dcm_key_context_internal *>(key_ctx);
329
330         std::vector<uint8_t> digest;
331         std::vector<uint8_t> message;
332         int result = context->connection->e2ee_sign_data(md, payload, payload_len, message, digest);
333         if(result == DCM_ERROR_NONE) {
334                 *signature = static_cast<char*>(malloc(sizeof(uint8_t) * digest.size()));
335                 if(*signature == NULL)
336                         return DCM_ERROR_OUT_OF_MEMORY;
337                 memcpy(*signature, digest.data(), digest.size());
338                 *signature_len = digest.size();
339
340                 auto message_dup = static_cast<unsigned char*>(malloc(sizeof(uint8_t)*message.size()));
341                 if(message_dup == NULL) {
342                         free(signature);
343                         return DCM_ERROR_OUT_OF_MEMORY;
344                 }
345                 memcpy(message_dup, message.data(), message.size());
346
347                 result = dcm_e2ee_create_bundle(message_dup, message.size(), bundle);
348                 assert(result == DCM_ERROR_NONE);
349         }
350
351         return result;
352 }