2 * Copyright (c) 2016-2020 Samsung Electronics Co., Ltd. All rights reserved
4 * Contact: Kyungwook Tak <k.tak@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * @file test_db_crypto.cpp
19 * @author Maciej Karpiuk (m.karpiuk2@samsung.com)
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>
33 void addRow(DB::RowVector& rows, DataType::Type type)
35 DB::Row row = DBFixture::create_default_row(DBFixture::m_default_name,
36 DBFixture::m_default_owner,
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));
44 } // namespace anonymous
46 BOOST_FIXTURE_TEST_SUITE(DBCRYPTO_TEST, DBFixture)
47 POSITIVE_TEST_CASE(DBtestSimple)
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);
54 check_DB_integrity(rowPattern);
56 rowPattern.data = createBigBlob(4096);
57 rowPattern.dataSize = rowPattern.data.size();
59 check_DB_integrity(rowPattern);
62 POSITIVE_TEST_CASE(DBtestTransaction)
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);
70 BOOST_REQUIRE_NO_THROW(m_db.saveRow(rowPattern));
71 BOOST_REQUIRE_NO_THROW(transaction.rollback());
73 DB::Crypto::RowOptional row_optional;
74 BOOST_REQUIRE_NO_THROW(row_optional = m_db.getRow(m_default_name,
76 DataType::BINARY_DATA));
77 BOOST_CHECK_MESSAGE(!row_optional, "Row still present after rollback");
80 POSITIVE_TEST_CASE(DBtestMove)
82 struct TestCrypto : public DB::Crypto {
83 explicit TestCrypto(DB::Crypto orig) : DB::Crypto(std::move(orig)) {}
85 bool empty() const { return !m_connection; }
88 TestCrypto tmp(std::move(m_db));
89 BOOST_REQUIRE(!tmp.empty());
91 BOOST_REQUIRE_NO_THROW(tmp = std::move(tmp));
92 BOOST_REQUIRE(!tmp.empty());
94 m_db = std::move(tmp);
95 BOOST_REQUIRE(tmp.empty());
98 POSITIVE_TEST_CASE(DBtestSaveRows)
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);
109 BOOST_REQUIRE_NO_THROW(m_db.saveRows(m_default_name, m_default_owner, rows));
111 BOOST_REQUIRE(m_db.isNameOwnerPresent(m_default_name, m_default_owner));
114 BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
116 DataType::KEY_RSA_PUBLIC,
117 DataType::KEY_RSA_PRIVATE,
119 BOOST_REQUIRE(rows.size() == 2);
120 BOOST_REQUIRE(rows[0].dataType.isKey() && rows[1].dataType.isKey());
123 BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
125 DataType::KEY_DSA_PRIVATE,
127 BOOST_REQUIRE(rows.empty());
130 NEGATIVE_TEST_CASE(DBtestSaveRowsDuplicated)
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);
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();
147 BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
150 NEGATIVE_TEST_CASE(DBtestSaveRowsEmpty)
152 BOOST_REQUIRE_NO_THROW(m_db.saveRows(m_default_name, m_default_owner, DB::RowVector()));
154 BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
157 NEGATIVE_TEST_CASE(DBtestSaveRowDuplicated)
159 DB::Row row = create_default_binary_row();
161 BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
162 BOOST_REQUIRE_THROW(m_db.saveRow(row), Exc::DatabaseFailed);
165 NEGATIVE_TEST_CASE(DBtestGetRowsNonExisting)
168 BOOST_REQUIRE_NO_THROW(m_db.getRows(m_default_name,
173 BOOST_REQUIRE(rows.empty());
176 POSITIVE_TEST_CASE(DBtestUpdateRow)
178 DB::Row row = create_default_binary_row();
180 BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
183 row.data.resize(row.dataSize);
184 BOOST_REQUIRE_NO_THROW(m_db.updateRow(row));
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);
193 NEGATIVE_TEST_CASE(DBtestUpdateRowNotExisting)
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));
199 BOOST_REQUIRE_NO_THROW(m_db.saveRow(row));
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));
206 POSITIVE_TEST_CASE(DBtestDeleteRow)
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));
215 NEGATIVE_TEST_CASE(DBtestDeleteRowNotExisting)
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));
222 POSITIVE_TEST_CASE(DBtestIsNameOwnerPresent)
224 BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
226 insert_row(m_default_name, m_default_owner);
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("", ""));
234 delete_row(m_default_name, m_default_owner);
236 BOOST_REQUIRE(!m_db.isNameOwnerPresent(m_default_name, m_default_owner));
239 NEGATIVE_TEST_CASE(DBtestIsNameOwnerPresentSqlInjectionAttempt)
241 insert_row(m_default_name, m_default_owner);
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));
248 POSITIVE_TEST_CASE(DBtestPermissions)
250 constexpr char OTHER_OWNER[] = "other owner";
251 insert_row(m_default_name, m_default_owner);
253 auto checkPermission = [&](const char* accessor, PermissionMask perm)
255 PermissionMaskOptional maskOpt;
256 BOOST_REQUIRE_NO_THROW(maskOpt = m_db.getPermissionRow(m_default_name,
259 BOOST_REQUIRE(!!maskOpt == (perm != Permission::NONE));
260 if (perm != Permission::NONE)
261 BOOST_REQUIRE(*maskOpt == perm);
265 checkPermission(m_default_owner, Permission::READ | Permission::REMOVE);
267 checkPermission(OTHER_OWNER, Permission::NONE);
269 BOOST_REQUIRE_NO_THROW(m_db.setPermission(m_default_name,
274 checkPermission(OTHER_OWNER, Permission::READ);
276 BOOST_REQUIRE_NO_THROW(m_db.setPermission(m_default_name,
281 checkPermission(OTHER_OWNER, Permission::NONE);
284 NEGATIVE_TEST_CASE(DBtestPermissionsNonExisting)
286 PermissionMaskOptional maskOpt;
287 BOOST_REQUIRE_NO_THROW(maskOpt = m_db.getPermissionRow(m_default_name,
290 BOOST_REQUIRE(!maskOpt);
293 POSITIVE_TEST_CASE(DBtestClientKey)
295 DB::Crypto::RawBufferOptional keyOpt;
296 RawBuffer key = createRandom(16);
298 BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
299 BOOST_REQUIRE(!keyOpt);
301 BOOST_REQUIRE_NO_THROW(m_db.saveKey(m_default_owner, key));
303 BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
304 BOOST_REQUIRE(keyOpt);
305 BOOST_REQUIRE(*keyOpt == key);
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);
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);
316 BOOST_REQUIRE_NO_THROW(m_db.deleteKey(m_default_owner));
318 aliasInfoVector.clear();
319 BOOST_REQUIRE_NO_THROW(m_db.listInfos(m_default_owner, aliasInfoVector, DataType::BINARY_DATA));
320 BOOST_REQUIRE(aliasInfoVector.empty());
322 BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
323 BOOST_REQUIRE(!keyOpt);
326 NEGATIVE_TEST_CASE(DBtestClientKey)
328 DB::Crypto::RawBufferOptional keyOpt;
329 RawBuffer key = createRandom(16);
331 BOOST_REQUIRE_NO_THROW(m_db.deleteKey(m_default_owner));
333 BOOST_REQUIRE_NO_THROW(keyOpt = m_db.getKey(m_default_owner));
334 BOOST_REQUIRE(!keyOpt);
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);
340 BOOST_AUTO_TEST_SUITE_END()
343 BOOST_AUTO_TEST_SUITE(DBCRYPTO_CTOR_TEST)
345 NEGATIVE_TEST_CASE(DBtestCryptoWrongPasswordLegacy)
347 BOOST_REQUIRE_THROW(DB::Crypto(DB_TEST_DIR "/testme_ver3.db", "", CKM::RawBuffer(16)),
348 Exc::DatabaseFailed);
351 NEGATIVE_TEST_CASE(DBtestCryptoWrongPasswordCurrent)
353 BOOST_REQUIRE_THROW(DB::Crypto("", DB_TEST_DIR "/testme0_ver4.db", CKM::RawBuffer(16)),
354 Exc::DatabaseFailed);
357 NEGATIVE_TEST_CASE(DBtestCryptoNonExistingBoth)
359 BOOST_REQUIRE_THROW(DB::Crypto("/not/existing.db", "/not/existing.db", defaultPass),
360 Exc::DatabaseFailed);
363 NEGATIVE_TEST_CASE(DBtestCryptoNonExistingCurrent)
365 BOOST_REQUIRE_THROW(DB::Crypto(DB_TEST_DIR "/testme_ver3.db", "/not/existing.db", defaultPass),
366 Exc::DatabaseFailed);
369 NEGATIVE_TEST_CASE(DBtestCryptoNotDatabaseLegacy)
371 BOOST_REQUIRE_THROW(DB::Crypto("/usr/bin/yes", "", defaultPass), Exc::DatabaseFailed);
374 NEGATIVE_TEST_CASE(DBtestCryptoNotDatabaseCurrent)
376 BOOST_REQUIRE_THROW(DB::Crypto("", "/usr/bin/yes", defaultPass), Exc::DatabaseFailed);
379 BOOST_AUTO_TEST_SUITE_END()
382 BOOST_AUTO_TEST_SUITE(DBCRYPTO_MIGRATION_TEST)
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;
389 void verifyDBisValid(DBFixture &fixture)
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).
398 * - migration_owner_63 has access to all items owned by migration_owner_63,
399 * which gives (migration_names)/(migration_owners) entries.
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.
406 ClientId reference_owner;
407 fixture.generate_owner(migration_reference_owner_idx, reference_owner);
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());
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)
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());
429 for (auto& it : ret_list)
430 BOOST_REQUIRE(CKM::AliasSupport(it.alias).getOwner() == current_owner);
436 void verifyDBisValid(const char *legacyDb, const char *db)
438 DBFixture DB(legacyDb, db);
443 POSITIVE_TEST_CASE(DBMigrationDBVer1)
445 verifyDBisValid(DB_TEST_DIR "/testme_ver1.db", nullptr);
448 POSITIVE_TEST_CASE(DBMigrationDBVer2)
450 verifyDBisValid(DB_TEST_DIR "/testme_ver2.db", nullptr);
453 POSITIVE_TEST_CASE(DBMigrationDBVer3)
455 verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", nullptr);
458 POSITIVE_TEST_CASE(DBMigrationDBVer3UncleanBoot)
460 verifyDBisValid(DB_TEST_DIR "/testme_ver3.db", DB_TEST_DIR "/testme_ver3.db");
463 POSITIVE_TEST_CASE(DB0MigrationDBVer4)
465 verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver4.db");
468 NEGATIVE_TEST_CASE(DBMigrationInvalid)
470 DBFixture(DB_TEST_DIR "/testme0_ver4.db", nullptr, DBFixture::DBCryptoThrows::yes);
473 NEGATIVE_TEST_CASE(DBMigrationInvalidUncleanBoot)
475 DBFixture(DB_TEST_DIR "/testme0_ver4.db", DB_TEST_DIR "/testme_ver3.db",
476 DBFixture::DBCryptoThrows::yes);
479 NEGATIVE_TEST_CASE(DBMigrationInvalid0)
481 DBFixture(nullptr, DB_TEST_DIR "/testme_ver3.db", DBFixture::DBCryptoThrows::yes);
484 POSITIVE_TEST_CASE(DB0MigrationDBVer5)
486 verifyDBisValid(nullptr, DB_TEST_DIR "/testme0_ver5.db");
489 POSITIVE_TEST_CASE(DBMigrationDBCurrent)
493 // prepare data using current DB mechanism
494 ClientId reference_owner;
495 currentDB.generate_owner(migration_reference_owner_idx, reference_owner);
498 currentDB.generate_db(migration_names, migration_names / migration_owners);
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)
506 unsigned element_index = migration_accessed_element_idx + l * migration_names /
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);
518 verifyDBisValid(currentDB);
521 BOOST_AUTO_TEST_SUITE_END()