• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "store_factory.h"
16 
17 #include <cerrno>
18 #include <cstdio>
19 #include <gtest/gtest.h>
20 #include <sys/types.h>
21 #include <vector>
22 
23 #include "backup_manager.h"
24 #include "file_ex.h"
25 #include "store_manager.h"
26 #include "store_util.h"
27 #include "sys/stat.h"
28 #include "types.h"
29 namespace {
30 using namespace testing::ext;
31 using namespace OHOS::DistributedKv;
32 
33 static StoreId storeId = { "single_test" };
34 static AppId appId = { "rekey" };
35 static Options options = {
36     .encrypt = true,
37     .securityLevel = S1,
38     .area = EL1,
39     .kvStoreType = SINGLE_VERSION,
40     .baseDir = "/data/service/el1/public/database/rekey",
41 };
42 
43 class StoreFactoryTest : public testing::Test {
44 public:
45     using DBStore = DistributedDB::KvStoreNbDelegate;
46     using DBManager = DistributedDB::KvStoreDelegateManager;
47     using DBOption = DistributedDB::KvStoreNbDelegate::Option;
48     using DBPassword = SecurityManager::DBPassword;
49     using DBStatus = DistributedDB::DBStatus;
50 
51     static constexpr int OUTDATED_TIME = (24 * 500);
52     static constexpr int NOT_OUTDATED_TIME = (24 * 50);
53 
54     static void SetUpTestCase(void);
55     static void TearDownTestCase(void);
56     void SetUp();
57     void TearDown();
58 
59     std::chrono::system_clock::time_point GetDate(const std::string &name, const std::string &path);
60     bool ChangeKeyDate(const std::string &name, const std::string &path, int duration);
61     bool MoveToRekeyPath(Options options, StoreId storeId);
62     std::shared_ptr<StoreFactoryTest::DBManager> GetDBManager(const std::string &path, const AppId &appId);
63     DBOption GetOption(const Options &options, const DBPassword &dbPassword);
64     DBStatus ChangeKVStoreDate(const std::string &storeId, std::shared_ptr<DBManager> dbManager,
65         const Options &options, DBPassword &dbPassword, int time);
66     bool ModifyDate(int time);
67     static void DeleteKVStore();
68 };
69 
SetUpTestCase(void)70 void StoreFactoryTest::SetUpTestCase(void)
71 {
72 }
73 
TearDownTestCase(void)74 void StoreFactoryTest::TearDownTestCase(void)
75 {
76 }
77 
SetUp(void)78 void StoreFactoryTest::SetUp(void)
79 {
80     OHOS::SaveStringToFile("/sys/fs/selinux/enforce", "0");
81     std::string baseDir = "/data/service/el1/public/database/rekey";
82     mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH));
83 }
84 
TearDown(void)85 void StoreFactoryTest::TearDown(void)
86 {
87     OHOS::SaveStringToFile("/sys/fs/selinux/enforce", "1");
88     DeleteKVStore();
89     (void)remove("/data/service/el1/public/database/rekey");
90 }
91 
DeleteKVStore()92 void StoreFactoryTest::DeleteKVStore()
93 {
94     StoreManager::GetInstance().Delete(appId, storeId, options.baseDir);
95 }
96 
GetDate(const std::string & name,const std::string & path)97 std::chrono::system_clock::time_point StoreFactoryTest::GetDate(const std::string &name, const std::string &path)
98 {
99     std::chrono::system_clock::time_point timePoint;
100     auto keyPath = path + "/key/" + name + ".key";
101     if (!OHOS::FileExists(keyPath)) {
102         return timePoint;
103     }
104 
105     std::vector<char> content;
106     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
107     if (!loaded) {
108         return timePoint;
109     }
110     constexpr uint32_t DATE_FILE_OFFSET = 1;
111     constexpr uint32_t DATE_FILE_LENGTH = sizeof(time_t) / sizeof(uint8_t);
112     std::vector<uint8_t> date;
113     date.assign(content.begin() + DATE_FILE_OFFSET, content.begin() + DATE_FILE_LENGTH + DATE_FILE_OFFSET);
114     timePoint = std::chrono::system_clock::from_time_t(*reinterpret_cast<time_t *>(const_cast<uint8_t *>(&date[0])));
115     return timePoint;
116 }
117 
ChangeKeyDate(const std::string & name,const std::string & path,int duration)118 bool StoreFactoryTest::ChangeKeyDate(const std::string &name, const std::string &path, int duration)
119 {
120     auto keyPath = path + "/key/" + name + ".key";
121     if (!OHOS::FileExists(keyPath)) {
122         return false;
123     }
124 
125     std::vector<char> content;
126     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
127     if (!loaded) {
128         return false;
129     }
130     auto time = std::chrono::system_clock::to_time_t(
131         std::chrono::system_clock::system_clock::now() - std::chrono::hours(duration));
132     std::vector<char> date(reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time));
133     std::copy(date.begin(), date.end(), ++content.begin());
134 
135     auto saved = OHOS::SaveBufferToFile(keyPath, content);
136     return saved;
137 }
138 
MoveToRekeyPath(Options options,StoreId storeId)139 bool StoreFactoryTest::MoveToRekeyPath(Options options, StoreId storeId)
140 {
141     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
142     std::string rekeyFileName = options.baseDir + "/rekey/key/" + storeId.storeId + ".new.key";
143     bool result = StoreUtil::Rename(keyFileName, rekeyFileName);
144     if (!result) {
145         return false;
146     }
147     result = StoreUtil::Remove(keyFileName);
148     return result;
149 }
150 
GetDBManager(const std::string & path,const AppId & appId)151 std::shared_ptr<StoreFactoryTest::DBManager> StoreFactoryTest::GetDBManager(const std::string &path, const AppId &appId)
152 {
153     std::string fullPath = path + "/kvdb";
154     StoreUtil::InitPath(fullPath);
155     std::shared_ptr<DBManager> dbManager = std::make_shared<DBManager>(appId.appId, "default");
156     dbManager->SetKvStoreConfig({ fullPath });
157     BackupManager::GetInstance().Init(path);
158     return dbManager;
159 }
160 
GetOption(const Options & options,const DBPassword & dbPassword)161 StoreFactoryTest::DBOption StoreFactoryTest::GetOption(const Options &options, const DBPassword &dbPassword)
162 {
163     DBOption dbOption;
164     dbOption.syncDualTupleMode = true; // tuple of (appid+storeid)
165     dbOption.createIfNecessary = options.createIfMissing;
166     dbOption.isNeedRmCorruptedDb = options.rebuild;
167     dbOption.isMemoryDb = (!options.persistent);
168     dbOption.isEncryptedDb = options.encrypt;
169     if (options.encrypt) {
170         dbOption.cipher = DistributedDB::CipherType::AES_256_GCM;
171         dbOption.passwd = dbPassword.password;
172     }
173 
174     dbOption.conflictResolvePolicy = options.kvStoreType == KvStoreType::SINGLE_VERSION
175                                          ? DistributedDB::LAST_WIN
176                                          : DistributedDB::DEVICE_COLLABORATION;
177 
178     dbOption.schema = options.schema;
179     dbOption.createDirByStoreIdOnly = true;
180     dbOption.secOption = StoreUtil::GetDBSecurity(options.securityLevel);
181     return dbOption;
182 }
183 
ChangeKVStoreDate(const std::string & storeId,std::shared_ptr<DBManager> dbManager,const Options & options,DBPassword & dbPassword,int time)184 StoreFactoryTest::DBStatus StoreFactoryTest::ChangeKVStoreDate(const std::string &storeId,
185     std::shared_ptr<DBManager> dbManager, const Options &options, DBPassword &dbPassword, int time)
186 {
187     DBStatus status;
188     const auto dbOption = GetOption(options, dbPassword);
189     DBStore *store = nullptr;
190     dbManager->GetKvStore(storeId, dbOption, [&status, &store](auto dbStatus, auto *dbStore) {
191         status = dbStatus;
192         store = dbStore;
193     });
194     if (!ChangeKeyDate(storeId, options.baseDir, time)) {
195         std::cout << "failed" << std::endl;
196     }
197     dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
198     auto dbStatus = store->Rekey(dbPassword.password);
199     dbManager->CloseKvStore(store);
200     return dbStatus;
201 }
202 
ModifyDate(int time)203 bool StoreFactoryTest::ModifyDate(int time)
204 {
205     auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
206     auto dbManager = GetDBManager(options.baseDir, appId);
207     auto dbstatus = ChangeKVStoreDate(storeId, dbManager, options, dbPassword, time);
208     return StoreUtil::ConvertStatus(dbstatus) == SUCCESS;
209 }
210 
211 /**
212 * @tc.name: Rekey
213 * @tc.desc: test rekey function
214 * @tc.type: FUNC
215 * @tc.require:
216 * @tc.author: Cui Renjie
217 */
218 HWTEST_F(StoreFactoryTest, Rekey, TestSize.Level1)
219 {
220     Status status = DB_ERROR;
221     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
222     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
223     ASSERT_EQ(status, SUCCESS);
224 
225     ASSERT_TRUE(ModifyDate(OUTDATED_TIME));
226 
227     auto oldKeyTime = GetDate(storeId, options.baseDir);
228     ASSERT_FALSE(std::chrono::system_clock::now() - oldKeyTime < std::chrono::seconds(2));
229 
230     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
231     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
232     ASSERT_EQ(status, SUCCESS);
233 
234     auto newKeyTime = GetDate(storeId, options.baseDir);
235     ASSERT_TRUE(std::chrono::system_clock::now() - newKeyTime < std::chrono::seconds(2));
236 }
237 
238 /**
239 * @tc.name: RekeyNotOutdated
240 * @tc.desc: try to rekey kvstore with not outdated password
241 * @tc.type: FUNC
242 * @tc.require:
243 * @tc.author: Cui Renjie
244 */
245 HWTEST_F(StoreFactoryTest, RekeyNotOutdated, TestSize.Level1)
246 {
247     Status status = DB_ERROR;
248     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
249     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
250     ASSERT_EQ(status, SUCCESS);
251 
252     ASSERT_TRUE(ModifyDate(NOT_OUTDATED_TIME));
253     auto oldKeyTime = GetDate(storeId, options.baseDir);
254 
255     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
256     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
257     ASSERT_EQ(status, SUCCESS);
258 
259     auto newKeyTime = GetDate(storeId, options.baseDir);
260     ASSERT_EQ(oldKeyTime, newKeyTime);
261 }
262 
263 /**
264 * @tc.name: RekeyInterrupted0
265 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
266 *           which caused key file lost but rekey key file exist.
267 * @tc.type: FUNC
268 * @tc.require:
269 * @tc.author: Cui Renjie
270 */
271 HWTEST_F(StoreFactoryTest, RekeyInterruptedWhileChangeKeyFile, TestSize.Level1)
272 {
273     Status status = DB_ERROR;
274     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
275     ASSERT_EQ(status, SUCCESS);
276     auto oldKeyTime = GetDate(storeId, options.baseDir);
277 
278     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
279     ASSERT_EQ(status, SUCCESS);
280     ASSERT_TRUE(MoveToRekeyPath(options, storeId));
281 
282     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
283     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
284     ASSERT_EQ(status, SUCCESS);
285     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
286     auto isKeyExist = StoreUtil::IsFileExist(keyFileName);
287     ASSERT_TRUE(isKeyExist);
288 
289     auto newKeyTime = GetDate(storeId, options.baseDir);
290     ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
291 }
292 
293 /**
294 * @tc.name: RekeyInterrupted1
295 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
296 *           which caused key file not changed but rekey key file exist.
297 * @tc.type: FUNC
298 * @tc.require:
299 * @tc.author: Cui Renjie
300 */
301 HWTEST_F(StoreFactoryTest, RekeyInterruptedBeforeChangeKeyFile, TestSize.Level1)
302 {
303     Status status = DB_ERROR;
304     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
305     ASSERT_EQ(status, SUCCESS);
306     auto oldKeyTime = GetDate(storeId, options.baseDir);
307 
308     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
309     ASSERT_EQ(status, SUCCESS);
310     ASSERT_EQ(MoveToRekeyPath(options, storeId), true);
311 
312     StoreId newStoreId = { "newStore" };
313     StoreManager::GetInstance().GetKVStore(appId, newStoreId, options, status);
314 
315     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
316     std::string mockKeyFileName = options.baseDir + "/key/" + newStoreId.storeId + ".key";
317     StoreUtil::Rename(mockKeyFileName, keyFileName);
318     StoreUtil::Remove(mockKeyFileName);
319     auto isKeyExist = StoreUtil::IsFileExist(mockKeyFileName);
320     ASSERT_FALSE(isKeyExist);
321     isKeyExist = StoreUtil::IsFileExist(keyFileName);
322     ASSERT_TRUE(isKeyExist);
323 
324     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
325     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
326     ASSERT_EQ(status, SUCCESS);
327 
328     isKeyExist = StoreUtil::IsFileExist(keyFileName);
329     ASSERT_TRUE(isKeyExist);
330 
331     auto newKeyTime = GetDate(storeId, options.baseDir);
332     ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
333 }
334 
335 /**
336 * @tc.name: RekeyNoPwdFile
337 * @tc.desc: try to open kvstore and execute RekeyRecover() without key and rekey key files.
338 * @tc.type: FUNC
339 * @tc.require:
340 * @tc.author: Cui Renjie
341 */
342 HWTEST_F(StoreFactoryTest, RekeyNoPwdFile, TestSize.Level1)
343 {
344     Status status = DB_ERROR;
345     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
346     ASSERT_EQ(status, SUCCESS);
347 
348     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
349     ASSERT_EQ(status, SUCCESS);
350     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
351     StoreUtil::Remove(keyFileName);
352 
353     auto isKeyExist = StoreUtil::IsFileExist(keyFileName);
354     ASSERT_EQ(isKeyExist, false);
355 
356     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
357     ASSERT_EQ(status, CRYPT_ERROR);
358 }
359 }
360