fix build bread due to Werror=maybe-uninitialized
[platform/core/security/device-certificate-manager.git] / tests / api_test.cpp
1 /******************************************************************
2  *
3  * Copyright 2017 - 2021 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 <boost/algorithm/hex.hpp>
20 #include <cstring>
21 #include <iomanip>
22 #include <iostream>
23 #include <sys/smack.h> // SMACK_LABEL_LEN
24
25 #include "dcm_client.h"
26 #include "device_certificate_manager.h"
27 #include "device_certificate_manager_ext.h"
28 #include "device_certificate_manager_ext_types.h"
29 #include "test_macros.h"
30
31 namespace {
32 class allocation_disabler {
33 public:
34     allocation_disabler(size_t n = 0) { enabled = true; allowed_allocs_n = n; }
35     ~allocation_disabler() { enabled = false; allowed_allocs_n = 0; }
36
37     static bool alloc_disabled() {
38         if (!enabled)
39             return false;
40
41         if (allowed_allocs_n == 0)
42             return true;
43
44         allowed_allocs_n--;
45         return false;
46     }
47 private:
48     inline static bool enabled;
49     inline static size_t allowed_allocs_n;
50 };
51
52 template<typename... Arguments>
53 auto test_no_mem_envir(size_t allowed_allocs, Arguments&&... args) {
54     auto _ = allocation_disabler(allowed_allocs);
55     return std::invoke(std::forward<Arguments>(args)...);
56 }
57
58 extern "C" void *__libc_malloc(size_t size);
59
60 extern "C" void *malloc(size_t size) {
61     if (allocation_disabler::alloc_disabled())
62         return nullptr;
63
64     return __libc_malloc(size);
65 }
66
67 class Fd {
68     int fd;
69 public:
70     explicit Fd(int fd) : fd(fd) { BOOST_REQUIRE_GE(fd, 0); }
71     operator int() const { return fd; }
72     ~Fd() { BOOST_CHECK_EQUAL(close(fd), 0); }
73 };
74
75 class OverrideSmackLabel {
76     Fd fd;
77     char old_label[SMACK_LABEL_LEN];
78     boost::uint_value_t<SMACK_LABEL_LEN>::least old_label_len;
79 public:
80     explicit OverrideSmackLabel(const char *override_label)
81     : fd(open("/proc/thread-self/attr/current", O_RDWR)) {
82         const auto ret = read(fd, old_label, sizeof old_label);
83         BOOST_REQUIRE_GT(ret, 0);
84         BOOST_REQUIRE_LE(ret, sizeof old_label);
85         old_label_len = ret;
86
87         // subsequent write()s fail without the seek
88         BOOST_REQUIRE_EQUAL(lseek(fd, 0, SEEK_SET), 0);
89
90         const auto len = strlen(override_label);
91         BOOST_REQUIRE_EQUAL(write(fd, override_label, len), len);
92     }
93
94     ~OverrideSmackLabel() {
95         BOOST_CHECK_EQUAL(write(fd, old_label, old_label_len), old_label_len);
96     }
97 };
98
99 } // namespace
100
101 BOOST_AUTO_TEST_SUITE(API_TEST)
102
103 POSITIVE_TEST_CASE(test01_dcm_create_key_context)
104 {
105     void *ctx;
106     int ret = dcm_create_key_context(NULL, NULL, NULL, &ctx);
107     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
108     BOOST_CHECK(ctx);
109     ret = dcm_free_key_context(ctx);
110     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
111
112     ctx = NULL;
113     ret = dcm_create_key_context("", "", NULL, &ctx);
114     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
115     BOOST_CHECK(ctx);
116     ret = dcm_free_key_context(ctx);
117     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
118
119     ctx = NULL;
120     ret = dcm_create_key_context("a", NULL, NULL, &ctx);
121     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
122     BOOST_CHECK(ctx);
123     ret = dcm_free_key_context(ctx);
124     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
125
126     ctx = NULL;
127     ret = dcm_create_key_context(NULL, "a", NULL, &ctx);
128     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
129     BOOST_CHECK(ctx);
130     ret = dcm_free_key_context(ctx);
131     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
132
133     ctx = NULL;
134     ret = dcm_create_key_context("a", "a", NULL, &ctx);
135     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
136     BOOST_CHECK(ctx);
137     ret = dcm_free_key_context(ctx);
138     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
139
140     ctx = NULL;
141     ret = dcm_create_key_context("a", "b", "UNEXISTING", &ctx);
142     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NO_DATA);
143     BOOST_CHECK(!ctx);
144     ret = dcm_free_key_context(ctx);
145     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
146 }
147
148 POSITIVE_TEST_CASE(test02_dcm_get_certificate_chain)
149 {
150     void *ctx;
151     char *cert;
152     size_t cert_len;
153
154     int ret = dcm_create_key_context("a", "b", NULL, &ctx);
155     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
156     BOOST_CHECK(ctx);
157
158     ret = dcm_get_certificate_chain(ctx, NULL, &cert_len);
159     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
160
161     ret = dcm_get_certificate_chain(ctx, &cert, NULL);
162     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
163
164     ret = dcm_get_certificate_chain(NULL, &cert, &cert_len);
165     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
166
167     ret = dcm_get_certificate_chain(ctx, &cert, &cert_len);
168     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
169     BOOST_CHECK(cert);
170     BOOST_REQUIRE(cert_len > 0);
171
172     ret = dcm_free_key_context(ctx);
173     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
174
175     free(cert);
176 }
177
178 POSITIVE_TEST_CASE(test03_dcm_get_key_bit_length)
179 {
180     int ret;
181     void *ctx;
182     size_t key_len = 0;
183
184     ret = dcm_get_key_bit_length(NULL, &key_len);
185     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
186
187     ret = dcm_create_key_context("a", "b", "ECDSA", &ctx);
188     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
189     BOOST_CHECK(ctx);
190
191     ret = dcm_get_key_bit_length(ctx, &key_len);
192     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
193     BOOST_REQUIRE(key_len > 0);
194
195     ret = dcm_free_key_context(ctx);
196     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
197 }
198
199 POSITIVE_TEST_CASE(test04_dcm_get_key_type)
200 {
201     int ret;
202     void *ctx;
203     char *key_type;
204
205     ret = dcm_get_key_type(NULL, &key_type);
206     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
207
208     ret = dcm_create_key_context("a", "b", "ECDSA", &ctx);
209     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
210     BOOST_CHECK(ctx);
211
212     ret = dcm_get_key_type(ctx, &key_type);
213     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
214     BOOST_CHECK(key_type);
215     BOOST_CHECK(strcmp(key_type, "ECDSA") == 0);
216
217     ret = dcm_free_key_context(ctx);
218     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
219     free(key_type);
220 }
221
222 POSITIVE_TEST_CASE(test05_dcm_create_signature)
223 {
224     int ret;
225     void *ctx;
226     char *signature;
227     size_t signature_len;
228     char data[32] = {0,};
229
230     ret = dcm_create_signature(NULL, DCM_DIGEST_SHA256, data, sizeof(data), &signature, &signature_len);
231     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
232
233     ret = dcm_create_key_context("a", "b", "ECDSA", &ctx);
234     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
235     BOOST_CHECK(ctx);
236
237     ret = dcm_create_signature(ctx, DCM_DIGEST_SHA256, data, sizeof(data), NULL, &signature_len);
238     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
239
240     ret = dcm_create_signature(ctx, DCM_DIGEST_SHA256, data, sizeof(data), &signature, NULL);
241     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_INVALID_PARAMETER);
242
243     std::cout << "Data to sign = ";
244     boost::algorithm::hex(std::begin(data), std::end(data), std::ostream_iterator<char>(std::cout));
245     std::cout << std::endl;
246
247     ret = dcm_create_signature(ctx, DCM_DIGEST_SHA256, data, sizeof(data), &signature, &signature_len);
248     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
249     BOOST_CHECK(signature);
250     BOOST_REQUIRE(signature_len > 0);
251
252     std::cout << "Signature = ";
253     boost::algorithm::hex(signature, signature + signature_len, std::ostream_iterator<char>(std::cout));
254     std::cout << std::endl;
255
256     ret = dcm_free_key_context(ctx);
257     BOOST_REQUIRE_EQUAL(ret, DCM_ERROR_NONE);
258
259     free(signature);
260 }
261
262 NEGATIVE_TEST_CASE(test06_dcm_ext_api_invalid_params_on_client_side)
263 {
264     int ret = dcm_ext_call_api(NULL, NULL, 0, NULL, NULL);
265     BOOST_REQUIRE_EQUAL(ret, DCM_EXT_ERROR_INVALID_PARAMETER);
266 }
267
268 NEGATIVE_TEST_CASE(test07_dcm_ext_api_invalid_method_name)
269 {
270     int ret = dcm_ext_call_api("method-not-existing", NULL, 0, NULL, NULL);
271     BOOST_REQUIRE_EQUAL(ret, DCM_EXT_ERROR_INVALID_PARAMETER);
272 }
273
274 NEGATIVE_TEST_CASE(test08_dcm_ext_api_no_privilege)
275 {
276     // This test seems to require the System::Privileged label because it
277     // relies on a particular cynara rule concerning System::Privileged and the
278     // underlying "http://tizen.org/privilege/internal/sysadmin" privilege
279     // checked during the "method-with-a-privilege-not-granted" call.
280     // Grep backend code for /method-with-a-privilege-not-granted/ for details.
281     //
282     // Sdb uses User::Shell but one can switch to System::Privileged, then back.
283     OverrideSmackLabel _("System::Privileged");
284
285     int ret = dcm_ext_call_api("method-with-a-privilege-not-granted", NULL, 0, NULL, NULL);
286     BOOST_REQUIRE_EQUAL(ret, DCM_EXT_ERROR_PERMISSION_DENIED);
287 }
288
289 POSITIVE_TEST_CASE(test09_dcm_ext_api_normal_call)
290 {
291     size_t out_size;
292     char* output = NULL;
293     int input = 5;
294     int ret = dcm_ext_call_api("square-int-method", (char*)&input, sizeof(input), &output , &out_size);
295     BOOST_REQUIRE_EQUAL(ret, DCM_EXT_ERROR_NONE);
296     BOOST_REQUIRE_EQUAL(out_size, sizeof(int));
297     BOOST_REQUIRE_EQUAL((int)(*output), 25);
298     free(output);
299 }
300
301 NEGATIVE_TEST_CASE(test10_dcm_ext_api_no_buffer_ptr_provided) {
302     int input = 5;
303     int ret = dcm_ext_call_api("square-int-method", (char*)&input, sizeof(input), nullptr, nullptr);
304     BOOST_REQUIRE(ret == DCM_EXT_ERROR_INVALID_PARAMETER);
305 }
306
307
308 POSITIVE_TEST_CASE(test11_cpp_dcm_client_api_hash_size) {
309     auto conn = dcm_client_connection::create();
310     std::vector<uint8_t> chain, digest;
311     constexpr char hash_data[] = "01234567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef";
312
313     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_NONE);
314
315     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_MD5, hash_data, 16, digest) == DCM_ERROR_NONE);
316     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA1, hash_data, 20, digest) == DCM_ERROR_NONE);
317     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA224, hash_data, 28, digest) == DCM_ERROR_NONE);
318     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA256, hash_data, 32, digest) == DCM_ERROR_NONE);
319     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA384, hash_data, 48, digest) == DCM_ERROR_NONE);
320     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA512, hash_data, 64, digest) == DCM_ERROR_NONE);
321     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_RIPEMD160, hash_data, 20, digest) == DCM_ERROR_NONE);
322 }
323
324 POSITIVE_TEST_CASE(test12_cpp_dcm_client_api_key_type) {
325     auto conn = dcm_client_connection::create();
326     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_NONE);
327     BOOST_REQUIRE(conn->key_type() == "RSA");
328
329     conn = dcm_client_connection::create();
330     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "ECDSA") == DCM_ERROR_NONE);
331     BOOST_REQUIRE(conn->key_type() == "ECDSA");
332 }
333
334 NEGATIVE_TEST_CASE(test13_cpp_dcm_client_api_key_type) {
335     auto conn = dcm_client_connection::create();
336     BOOST_REQUIRE(conn->key_type() == "UNKNOWN");
337 }
338
339 NEGATIVE_TEST_CASE(test14_dcm_client_api_cookie_exists) {
340     auto conn = dcm_client_connection::create();
341
342     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_NONE);
343     // cookie already exists error
344     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_SOCKET);
345 }
346
347 NEGATIVE_TEST_CASE(test15_dcm_client_api_no_cookie) {
348     auto conn = dcm_client_connection::create();
349     std::vector<uint8_t> chain, digest;
350     constexpr char hash_data[] = "01234567890abcdef";
351
352     // no cookie error
353     BOOST_REQUIRE(conn->get_certificate_chain(chain) == DCM_ERROR_SOCKET);
354     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_SHA1, hash_data, sizeof(hash_data), digest) == DCM_ERROR_SOCKET);
355 }
356
357 NEGATIVE_TEST_CASE(test16_dcm_client_api_invalid_hash_size) {
358     auto conn = dcm_client_connection::create();
359     std::vector<uint8_t> chain, digest;
360     constexpr char hash_data[] = "01234567890abcdef";
361
362     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_NONE);
363
364     // hash_size == 0 and md == DCM_DIGEST_NONE
365     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_NONE, hash_data, 0, digest) == DCM_ERROR_INVALID_PARAMETER);
366
367     // hash size mismatch
368     BOOST_REQUIRE(conn->sign_data(DCM_DIGEST_MD5, hash_data, 1, digest) == DCM_ERROR_INVALID_PARAMETER);
369 }
370
371 NEGATIVE_TEST_CASE(test17_dcm_ext_api_no_mem) {
372     size_t out_size;
373     char* output = NULL;
374     int input = 5;
375
376     BOOST_REQUIRE(test_no_mem_envir(2, &dcm_ext_call_api, "square-int-method", (char*)&input,
377             sizeof(input), &output , &out_size) == DCM_EXT_ERROR_SOCKET);
378
379     BOOST_REQUIRE(test_no_mem_envir(10, &dcm_ext_call_api, "square-int-method", (char*)&input,
380             sizeof(input), &output , &out_size) == DCM_EXT_ERROR_SOCKET);
381
382     BOOST_REQUIRE(test_no_mem_envir(15, &dcm_ext_call_api, "square-int-method", (char*)&input,
383             sizeof(input), &output , &out_size) == DCM_EXT_ERROR_OUT_OF_MEMORY);
384 }
385
386 NEGATIVE_TEST_CASE(test18_cpp_dcm_client_api_no_mem) {
387     auto conn = dcm_client_connection::create();
388     std::vector<uint8_t> chain, digest;
389     constexpr char hash_data[] = "01234567890abcdef";
390
391     BOOST_REQUIRE(test_no_mem_envir(0, &dcm_client_connection::create_context, conn,
392             "S", "U", "K") == DCM_ERROR_SOCKET);
393
394     BOOST_REQUIRE(test_no_mem_envir(10, &dcm_client_connection::create_context, conn,
395             "S", "U", "K") == DCM_ERROR_SOCKET);
396
397     BOOST_REQUIRE(conn->create_context("TEST", "TEST", "RSA") == DCM_ERROR_NONE);
398
399     BOOST_REQUIRE(test_no_mem_envir(1, &dcm_client_connection::get_certificate_chain, conn,
400             chain) == DCM_ERROR_OUT_OF_MEMORY);
401
402     BOOST_REQUIRE(test_no_mem_envir(1, &dcm_client_connection::sign_data, conn,
403             DCM_DIGEST_MD5, hash_data, 0, digest) == DCM_ERROR_OUT_OF_MEMORY);
404 }
405
406 NEGATIVE_TEST_CASE(test19_dcm_api_no_mem) {
407     void *ctx;
408
409     BOOST_REQUIRE(test_no_mem_envir(0, &dcm_create_key_context,
410             nullptr, nullptr, nullptr, &ctx) == DCM_ERROR_UNKNOWN);
411 }
412
413 BOOST_AUTO_TEST_SUITE_END()