Release 0.1.66
[platform/core/security/key-manager.git] / unit-tests / test_db_crypto.cpp
1 /*
2  *  Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
3  *
4  *  Contact: Kyungwook Tak <k.tak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  *
18  * @file        test_db_crypto.cpp
19  * @author      Maciej Karpiuk (m.karpiuk2@samsung.com)
20  * @version
21  * @brief
22  */
23 #include <boost_macros_wrapper.h>
24 #include <ckm/ckm-type.h>
25 #include <protocols.h>
26 #include <test_common.h>
27 #include <DBFixture.h>
28
29 using namespace CKM;
30
31 namespace {
32
33 void addRow(DB::RowVector& rows, DataType::Type type)
34 {
35         DB::Row row = DBFixture::create_default_row(DBFixture::m_default_name,
36                                                     DBFixture::m_default_owner,
37                                                     type);
38         row.data = RawBuffer(100, 20);
39         row.dataSize = row.data.size();
40         row.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
41         rows.push_back(std::move(row));
42 };
43
44 } // namespace anonymous
45
46 BOOST_FIXTURE_TEST_SUITE(DBCRYPTO_TEST, DBFixture)
47 POSITIVE_TEST_CASE(DBtestSimple)
48 {
49         DB::Row rowPattern = create_default_row();
50         rowPattern.data = RawBuffer(32, 1);
51         rowPattern.dataSize = rowPattern.data.size();
52         rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
53
54         check_DB_integrity(rowPattern);
55
56         rowPattern.data = createBigBlob(4096);
57         rowPattern.dataSize = rowPattern.data.size();
58
59         check_DB_integrity(rowPattern);
60 }
61
62 POSITIVE_TEST_CASE(DBtestTransaction)
63 {
64         DB::Row rowPattern = create_default_row();
65         rowPattern.data = RawBuffer(100, 20);
66         rowPattern.dataSize = rowPattern.data.size();
67         rowPattern.tag = RawBuffer(AES_GCM_TAG_SIZE, 1);
68         DB::Crypto::Transaction transaction(&m_db);
69
70         BOOST_REQUIRE_NO_THROW(m_db.saveRow(rowPattern));
71         BOOST_REQUIRE_NO_THROW(transaction.rollback());
72
73         DB::Crypto::RowOptional row_optional;
74         BOOST_REQUIRE_NO_THROW(row_optional = m_db.getRow(m_default_name,
75                                                                                   m_default_owner,
76                                                                                   DataType::BINARY_DATA));
77         BOOST_CHECK_MESSAGE(!row_optional, "Row still present after rollback");
78 }
79
80 POSITIVE_TEST_CASE(DBtestMove)
81 {
82         struct TestCrypto : public DB::Crypto {
83                 explicit TestCrypto(DB::Crypto orig) : DB::Crypto(std::move(orig)) {}
84
85                 bool empty() const { return !m_connection; }
86         };
87
88         TestCrypto tmp(std::move(m_db));
89         BOOST_REQUIRE(!tmp.empty());
90
91         BOOST_REQUIRE_NO_THROW(tmp = std::move(tmp));
92         BOOST_REQUIRE(!tmp.empty());
93
94         m_db = std::move(tmp);
95         BOOST_REQUIRE(tmp.empty());
96 }
97
98 POSITIVE_TEST_CASE(DBtestSaveRows)
99 {
100         DB::RowVector rows;
101
102         addRow(rows, DataType::KEY_RSA_PRIVATE);
103         addRow(rows, DataType::KEY_RSA_PUBLIC);
104         addRow(rows, DataType::CERTIFICATE);
105         addRow(rows, DataType::CHAIN_CERT_0);
106         addRow(rows, DataType::CHAIN_CERT_1);
107         addRow(rows, DataType::CHAIN_CERT_2);
108
109         BOOST_REQUIRE_NO_THROW(m_db.saveRows(m_default_name, m_default_owner, rows));
110
111         BOOST_REQUIRE(m_db.isNameOwnerPresent(m_default_name, m_default_owner));
112
113         rows.clear();
114         BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
115                                             m_default_owner,
116                                             DataType::KEY_RSA_PUBLIC,
117                                             DataType::KEY_RSA_PRIVATE,
118                                             rows));
119         BOOST_REQUIRE(rows.size() == 2);
120         BOOST_REQUIRE(rows[0].dataType.isKey() && rows[1].dataType.isKey());
121
122         rows.clear();
123         BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
124                                             m_default_owner,
125                                             DataType::KEY_DSA_PRIVATE,
126                                             rows));
127         BOOST_REQUIRE(rows.empty());
128 }
129
130 NEGATIVE_TEST_CASE(DBtestSaveRowsDuplicated)
131 {
132         DB::RowVector rows;
133
134         addRow(rows, DataType::KEY_RSA_PRIVATE);
135         addRow(rows, DataType::KEY_RSA_PUBLIC);
136         addRow(rows, DataType::CERTIFICATE);
137         addRow(rows, DataType::CHAIN_CERT_0);
138         addRow(rows, DataType::CHAIN_CERT_1);
139         addRow(rows, DataType::CHAIN_CERT_1);
140
141         // duplicated type
142         DB::Crypto::Transaction transaction(&m_db);
143         BOOST_REQUIRE_THROW(m_db.saveRows(m_default_name, m_default_owner, rows),
144                             Exc::DatabaseFailed);
145         transaction.rollback();
146
147         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
148 }
149
150 NEGATIVE_TEST_CASE(DBtestSaveRowsEmpty)
151 {
152         BOOST_REQUIRE_NO_THROW(m_db.saveRows(m_default_name, m_default_owner, DB::RowVector()));
153
154         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
155 }
156
157 NEGATIVE_TEST_CASE(DBtestSaveRowDuplicated)
158 {
159         DB::Row row = create_default_binary_row();
160
161         BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
162         BOOST_REQUIRE_THROW(m_db.saveRow(row), Exc::DatabaseFailed);
163 }
164
165 NEGATIVE_TEST_CASE(DBtestGetRowsNonExisting)
166 {
167         DB::RowVector rows;
168         BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
169                                             m_default_owner,
170                                             DataType::DB_FIRST,
171                                             DataType::DB_LAST,
172                                             rows));
173         BOOST_REQUIRE(rows.empty());
174 }
175
176 POSITIVE_TEST_CASE(DBtestUpdateRow)
177 {
178         DB::Row row = create_default_binary_row();
179
180         BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
181
182         row.dataSize--;
183         row.data.resize(row.dataSize);
184         BOOST_REQUIRE_NO_THROW(m_db.updateRow(row));
185
186         DB::Crypto::RowOptional rowOpt;
187         BOOST_REQUIRE_NO_THROW(rowOpt = m_db.getRow(row.name, row.owner, DataType::BINARY_DATA));
188         BOOST_REQUIRE(rowOpt);
189         BOOST_REQUIRE(rowOpt->dataSize == row.dataSize);
190         BOOST_REQUIRE(rowOpt->data == row.data);
191 }
192
193 NEGATIVE_TEST_CASE(DBtestUpdateRowNotExisting)
194 {
195         DB::Row row = create_default_binary_row();
196         BOOST_REQUIRE_NO_THROW(m_db.updateRow(row));
197         BOOST_REQUIRE(!m_db.isNameOwnerPresent(row.name, row.owner));
198
199         BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
200
201         row.name = "non-existent name";
202         BOOST_REQUIRE_NO_THROW(m_db.updateRow(row));
203         BOOST_REQUIRE(!m_db.isNameOwnerPresent(row.name, row.owner));
204 }
205
206 POSITIVE_TEST_CASE(DBtestDeleteRow)
207 {
208         DB::Row row = create_default_binary_row();
209         BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
210         BOOST_REQUIRE(m_db.isNameOwnerPresent(row.name, row.owner));
211         BOOST_REQUIRE(m_db.deleteRow(row.name, row.owner));
212         BOOST_REQUIRE(!m_db.isNameOwnerPresent(row.name, row.owner));
213 }
214
215 NEGATIVE_TEST_CASE(DBtestDeleteRowNotExisting)
216 {
217         DB::Row row = create_default_binary_row();
218         BOOST_REQUIRE(!m_db.isNameOwnerPresent(row.name, row.owner));
219         BOOST_REQUIRE(!m_db.deleteRow(row.name, row.owner));
220 }
221
222 POSITIVE_TEST_CASE(DBtestIsNameOwnerPresent)
223 {
224         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
225
226         insert_row(m_default_name, m_default_owner);
227
228         BOOST_REQUIRE(m_db.isNameOwnerPresent(m_default_name, m_default_owner));
229         BOOST_REQUIRE(!m_db.isNameOwnerPresent("non-existent name", m_default_owner));
230         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, "non-existent owner"));
231         BOOST_REQUIRE(!m_db.isNameOwnerPresent("non-existent name", "non-existent owner"));
232         BOOST_REQUIRE(!m_db.isNameOwnerPresent("", ""));
233
234         delete_row(m_default_name, m_default_owner);
235
236         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
237 }
238
239 NEGATIVE_TEST_CASE(DBtestIsNameOwnerPresentSqlInjectionAttempt)
240 {
241         insert_row(m_default_name, m_default_owner);
242
243         BOOST_REQUIRE(!m_db.isNameOwnerPresent("name'; DROP TABLE NAMES; --", m_default_owner));
244         BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, "owner'; DROP TABLE NAMES; --"));
245         BOOST_REQUIRE(m_db.isNameOwnerPresent(m_default_name, m_default_owner));
246 }
247
248 POSITIVE_TEST_CASE(DBtestPermissions)
249 {
250         constexpr char OTHER_OWNER[] = "other owner";
251         insert_row(m_default_name, m_default_owner);
252
253         auto checkPermission = [&](const char* accessor, PermissionMask perm)
254         {
255                 PermissionMaskOptional maskOpt;
256                 BOOST_REQUIRE_NO_THROW(maskOpt = m_db.getPermissionRow(m_default_name,
257                                                                        m_default_owner,
258                                                                        accessor));
259                 BOOST_REQUIRE(!!maskOpt == (perm != Permission::NONE));
260                 if (perm != Permission::NONE)
261                         BOOST_REQUIRE(*maskOpt == perm);
262
263         };
264
265         checkPermission(m_default_owner, Permission::READ | Permission::REMOVE);
266
267         checkPermission(OTHER_OWNER, Permission::NONE);
268
269         BOOST_REQUIRE_NO_THROW(m_db.setPermission(m_default_name,
270                                                   m_default_owner,
271                                                   OTHER_OWNER,
272                                                   Permission::READ));
273
274         checkPermission(OTHER_OWNER, Permission::READ);
275
276         BOOST_REQUIRE_NO_THROW(m_db.setPermission(m_default_name,
277                                                   m_default_owner,
278                                                   OTHER_OWNER,
279                                                   Permission::NONE));
280
281         checkPermission(OTHER_OWNER, Permission::NONE);
282 }
283
284 NEGATIVE_TEST_CASE(DBtestPermissionsNonExisting)
285 {
286         PermissionMaskOptional maskOpt;
287         BOOST_REQUIRE_NO_THROW(maskOpt = m_db.getPermissionRow(m_default_name,
288                                                                                                                    m_default_owner,
289                                                                                                                    m_default_owner));
290         BOOST_REQUIRE(!maskOpt);
291 }
292
293 POSITIVE_TEST_CASE(DBtestClientKey)
294 {
295         DB::Crypto::RawBufferOptional keyOpt;
296         RawBuffer key = createRandom(16);
297
298         BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
299         BOOST_REQUIRE(!keyOpt);
300
301         BOOST_REQUIRE_NO_THROW(m_db.saveKey(m_default_owner, key));
302
303         BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
304         BOOST_REQUIRE(keyOpt);
305         BOOST_REQUIRE(*keyOpt == key);
306
307         constexpr size_t NAME_CNT = 4;
308         constexpr const char* NAMES[NAME_CNT] = { "name1", "name2", "name3", "name4" };
309         for (auto name : NAMES)
310                 insert_row(name, m_default_owner);
311
312         AliasInfoVector aliasInfoVector;
313         BOOST_REQUIRE_NO_THROW(m_db.listInfos(m_default_owner, aliasInfoVector, DataType::BINARY_DATA));
314         BOOST_REQUIRE(aliasInfoVector.size() == NAME_CNT);
315
316         BOOST_REQUIRE_NO_THROW(m_db.deleteKey(m_default_owner));
317
318         aliasInfoVector.clear();
319         BOOST_REQUIRE_NO_THROW(m_db.listInfos(m_default_owner, aliasInfoVector, DataType::BINARY_DATA));
320         BOOST_REQUIRE(aliasInfoVector.empty());
321
322         BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
323         BOOST_REQUIRE(!keyOpt);
324 }
325
326 NEGATIVE_TEST_CASE(DBtestClientKey)
327 {
328         DB::Crypto::RawBufferOptional keyOpt;
329         RawBuffer key = createRandom(16);
330
331         BOOST_REQUIRE_NO_THROW(m_db.deleteKey(m_default_owner));
332
333         BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
334         BOOST_REQUIRE(!keyOpt);
335
336         BOOST_REQUIRE_NO_THROW(m_db.saveKey(m_default_owner, key));
337         BOOST_REQUIRE_THROW(m_db.saveKey(m_default_owner, key), Exc::DatabaseFailed);
338 }
339
340 BOOST_AUTO_TEST_SUITE_END()
341
342
343 BOOST_AUTO_TEST_SUITE(DBCRYPTO_CTOR_TEST)
344
345 NEGATIVE_TEST_CASE(DBtestCryptoWrongPasswordLegacy)
346 {
347         BOOST_REQUIRE_THROW(DB::Crypto(DB_TEST_DIR "/testme_ver3.db", "", CKM::RawBuffer(16)),
348                             Exc::DatabaseFailed);
349 }
350
351 NEGATIVE_TEST_CASE(DBtestCryptoWrongPasswordCurrent)
352 {
353         BOOST_REQUIRE_THROW(DB::Crypto("", DB_TEST_DIR "/testme0_ver4.db", CKM::RawBuffer(16)),
354                             Exc::DatabaseFailed);
355 }
356
357 NEGATIVE_TEST_CASE(DBtestCryptoNonExistingBoth)
358 {
359         BOOST_REQUIRE_THROW(DB::Crypto("/not/existing.db", "/not/existing.db", defaultPass),
360                             Exc::DatabaseFailed);
361 }
362
363 NEGATIVE_TEST_CASE(DBtestCryptoNonExistingCurrent)
364 {
365         BOOST_REQUIRE_THROW(DB::Crypto(DB_TEST_DIR "/testme_ver3.db", "/not/existing.db", defaultPass),
366                             Exc::DatabaseFailed);
367 }
368
369 NEGATIVE_TEST_CASE(DBtestCryptoNotDatabaseLegacy)
370 {
371         BOOST_REQUIRE_THROW(DB::Crypto("/usr/bin/yes", "", defaultPass), Exc::DatabaseFailed);
372 }
373
374 NEGATIVE_TEST_CASE(DBtestCryptoNotDatabaseCurrent)
375 {
376         BOOST_REQUIRE_THROW(DB::Crypto("", "/usr/bin/yes", defaultPass), Exc::DatabaseFailed);
377 }
378
379 BOOST_AUTO_TEST_SUITE_END()
380
381
382 BOOST_AUTO_TEST_SUITE(DBCRYPTO_MIGRATION_TEST)
383 namespace {
384 const unsigned migration_names = 16107;
385 const unsigned migration_owners = 273;
386 const unsigned migration_reference_owner_idx = 0;
387 const unsigned migration_accessed_element_idx = 7;
388
389 void verifyDBisValid(DBFixture &fixture)
390 {
391         /**
392          * There are (migration_owners), each having (migration_names)/(migration_owners)
393          * entries. Reference owner (migration_reference_owner_idx) exists such that
394          * it has access to all other owners' elements with index
395          * (migration_accessed_element_idx).
396          *
397          * Example:
398          * - migration_owner_63 has access to all items owned by migration_owner_63,
399          *   which gives (migration_names)/(migration_owners) entries.
400          *
401          * - migration_owner_0 (0 is the reference owner) has access to all items
402          *   owned by migration_owner_0 and all other owners' elements with index 7,
403          *   which gives (migration_names)/(migration_owners)  + (migration_owners-1) entries.
404          *
405          */
406         ClientId reference_owner;
407         fixture.generate_owner(migration_reference_owner_idx, reference_owner);
408
409         // check number of elements accessible to the reference owner
410         AliasInfoVector ret_list;
411         BOOST_REQUIRE_NO_THROW(fixture.m_db.listInfos(reference_owner, ret_list,
412                                                    DataType::BINARY_DATA));
413         BOOST_REQUIRE((migration_names / migration_owners)/*own items*/ +
414                                   (migration_owners - 1)/*other owners'*/ == ret_list.size());
415         ret_list.clear();
416
417         // check number of elements accessible to the other owners
418         for (unsigned int l = 0; l < migration_owners; l++) {
419                 // bypass the reference owner
420                 if (l == migration_reference_owner_idx)
421                         continue;
422
423                 ClientId current_owner;
424                 fixture.generate_owner(l, current_owner);
425                 BOOST_REQUIRE_NO_THROW(fixture.m_db.listInfos(current_owner, ret_list,
426                                                            DataType::BINARY_DATA));
427                 BOOST_REQUIRE((migration_names / migration_owners) == ret_list.size());
428
429                 for (auto& it : ret_list)
430                         BOOST_REQUIRE(CKM::AliasSupport(it.alias).getOwner() == current_owner);
431
432                 ret_list.clear();
433         }
434 }
435
436 void verifyDBisValid(const char *legacyDb, const char *db)
437 {
438         DBFixture DB(legacyDb, db);
439         verifyDBisValid(DB);
440 }
441 }
442
443 POSITIVE_TEST_CASE(DBMigrationDBVer1)
444 {
445         verifyDBisValid(DB_TEST_DIR "/testme_ver1.db", nullptr);
446 }
447
448 POSITIVE_TEST_CASE(DBMigrationDBVer2)
449 {
450         verifyDBisValid(DB_TEST_DIR "/testme_ver2.db", nullptr);
451 }
452
453 POSITIVE_TEST_CASE(DBMigrationDBVer3)
454 {
455         verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", nullptr);
456 }
457
458 POSITIVE_TEST_CASE(DBMigrationDBVer3UncleanBoot)
459 {
460         verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", DB_TEST_DIR "/testme_ver3.db");
461 }
462
463 POSITIVE_TEST_CASE(DB0MigrationDBVer4)
464 {
465         verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver4.db");
466 }
467
468 NEGATIVE_TEST_CASE(DBMigrationInvalid)
469 {
470         DBFixture(DB_TEST_DIR "/testme0_ver4.db", nullptr, DBFixture::DBCryptoThrows::yes);
471 }
472
473 NEGATIVE_TEST_CASE(DBMigrationInvalidUncleanBoot)
474 {
475         DBFixture(DB_TEST_DIR "/testme0_ver4.db", DB_TEST_DIR "/testme_ver3.db",
476                         DBFixture::DBCryptoThrows::yes);
477 }
478
479 NEGATIVE_TEST_CASE(DBMigrationInvalid0)
480 {
481         DBFixture(nullptr, DB_TEST_DIR "/testme_ver3.db", DBFixture::DBCryptoThrows::yes);
482 }
483
484 POSITIVE_TEST_CASE(DB0MigrationDBVer5)
485 {
486         verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver5.db");
487 }
488
489 POSITIVE_TEST_CASE(DBMigrationDBCurrent)
490 {
491         DBFixture currentDB;
492
493         // prepare data using current DB mechanism
494         ClientId reference_owner;
495         currentDB.generate_owner(migration_reference_owner_idx, reference_owner);
496
497         {
498                 currentDB.generate_db(migration_names, migration_names / migration_owners);
499
500                 // only the reference owner has access to the other owners' elements <migration_accessed_element_idx>
501                 for (unsigned int l = 0; l < migration_owners; l++) {
502                         // bypass the reference owner
503                         if (l == migration_reference_owner_idx)
504                                 continue;
505
506                         unsigned element_index = migration_accessed_element_idx + l * migration_names /
507                                                                          migration_owners;
508
509                         // add permission
510                         Name accessed_name;
511                         currentDB.generate_name(element_index, accessed_name);
512                         ClientId current_owner;
513                         currentDB.generate_owner(l, current_owner);
514                         currentDB.add_permission(accessed_name, current_owner, reference_owner);
515                 }
516         }
517
518         verifyDBisValid(currentDB);
519 }
520
521 BOOST_AUTO_TEST_SUITE_END()