• 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     std::string baseDir = "/data/service/el1/public/database/rekey";
81     mkdir(baseDir.c_str(), (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH));
82 }
83 
TearDown(void)84 void StoreFactoryTest::TearDown(void)
85 {
86     DeleteKVStore();
87     (void)remove("/data/service/el1/public/database/rekey");
88 }
89 
DeleteKVStore()90 void StoreFactoryTest::DeleteKVStore()
91 {
92     StoreManager::GetInstance().Delete(appId, storeId, options.baseDir);
93 }
94 
GetDate(const std::string & name,const std::string & path)95 std::chrono::system_clock::time_point StoreFactoryTest::GetDate(const std::string &name, const std::string &path)
96 {
97     std::chrono::system_clock::time_point timePoint;
98     auto keyPath = path + "/key/" + name + ".key";
99     if (!OHOS::FileExists(keyPath)) {
100         return timePoint;
101     }
102 
103     std::vector<char> content;
104     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
105     if (!loaded) {
106         return timePoint;
107     }
108     constexpr uint32_t DATE_FILE_OFFSET = 1;
109     constexpr uint32_t DATE_FILE_LENGTH = sizeof(time_t) / sizeof(uint8_t);
110     std::vector<uint8_t> date;
111     date.assign(content.begin() + DATE_FILE_OFFSET, content.begin() + DATE_FILE_LENGTH + DATE_FILE_OFFSET);
112     timePoint = std::chrono::system_clock::from_time_t(*reinterpret_cast<time_t *>(const_cast<uint8_t *>(&date[0])));
113     return timePoint;
114 }
115 
ChangeKeyDate(const std::string & name,const std::string & path,int duration)116 bool StoreFactoryTest::ChangeKeyDate(const std::string &name, const std::string &path, int duration)
117 {
118     auto keyPath = path + "/key/" + name + ".key";
119     if (!OHOS::FileExists(keyPath)) {
120         return false;
121     }
122 
123     std::vector<char> content;
124     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
125     if (!loaded) {
126         return false;
127     }
128     auto time = std::chrono::system_clock::to_time_t(
129         std::chrono::system_clock::system_clock::now() - std::chrono::hours(duration));
130     std::vector<char> date(reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time));
131     std::copy(date.begin(), date.end(), ++content.begin());
132 
133     auto saved = OHOS::SaveBufferToFile(keyPath, content);
134     return saved;
135 }
136 
MoveToRekeyPath(Options options,StoreId storeId)137 bool StoreFactoryTest::MoveToRekeyPath(Options options, StoreId storeId)
138 {
139     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
140     std::string rekeyFileName = options.baseDir + "/rekey/key/" + storeId.storeId + ".new.key";
141     bool result = StoreUtil::Rename(keyFileName, rekeyFileName);
142     if (!result) {
143         return false;
144     }
145     result = StoreUtil::Remove(keyFileName);
146     return result;
147 }
148 
GetDBManager(const std::string & path,const AppId & appId)149 std::shared_ptr<StoreFactoryTest::DBManager> StoreFactoryTest::GetDBManager(const std::string &path, const AppId &appId)
150 {
151     std::string fullPath = path + "/kvdb";
152     StoreUtil::InitPath(fullPath);
153     std::shared_ptr<DBManager> dbManager = std::make_shared<DBManager>(appId.appId, "default");
154     dbManager->SetKvStoreConfig({ fullPath });
155     BackupManager::GetInstance().Init(path);
156     return dbManager;
157 }
158 
GetOption(const Options & options,const DBPassword & dbPassword)159 StoreFactoryTest::DBOption StoreFactoryTest::GetOption(const Options &options, const DBPassword &dbPassword)
160 {
161     DBOption dbOption;
162     dbOption.syncDualTupleMode = true; // tuple of (appid+storeid)
163     dbOption.createIfNecessary = options.createIfMissing;
164     dbOption.isNeedRmCorruptedDb = options.rebuild;
165     dbOption.isMemoryDb = (!options.persistent);
166     dbOption.isEncryptedDb = options.encrypt;
167     if (options.encrypt) {
168         dbOption.cipher = DistributedDB::CipherType::AES_256_GCM;
169         dbOption.passwd = dbPassword.password;
170     }
171 
172     dbOption.conflictResolvePolicy = options.kvStoreType == KvStoreType::SINGLE_VERSION
173                                          ? DistributedDB::LAST_WIN
174                                          : DistributedDB::DEVICE_COLLABORATION;
175 
176     dbOption.schema = options.schema;
177     dbOption.createDirByStoreIdOnly = true;
178     dbOption.secOption = StoreUtil::GetDBSecurity(options.securityLevel);
179     return dbOption;
180 }
181 
ChangeKVStoreDate(const std::string & storeId,std::shared_ptr<DBManager> dbManager,const Options & options,DBPassword & dbPassword,int time)182 StoreFactoryTest::DBStatus StoreFactoryTest::ChangeKVStoreDate(const std::string &storeId,
183     std::shared_ptr<DBManager> dbManager, const Options &options, DBPassword &dbPassword, int time)
184 {
185     DBStatus status;
186     const auto dbOption = GetOption(options, dbPassword);
187     DBStore *store = nullptr;
188     dbManager->GetKvStore(storeId, dbOption, [&status, &store](auto dbStatus, auto *dbStore) {
189         status = dbStatus;
190         store = dbStore;
191     });
192     if (!ChangeKeyDate(storeId, options.baseDir, time)) {
193         std::cout << "failed" << std::endl;
194     }
195     dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
196     auto dbStatus = store->Rekey(dbPassword.password);
197     dbManager->CloseKvStore(store);
198     return dbStatus;
199 }
200 
ModifyDate(int time)201 bool StoreFactoryTest::ModifyDate(int time)
202 {
203     auto dbPassword = SecurityManager::GetInstance().GetDBPassword(storeId, options.baseDir, false);
204     auto dbManager = GetDBManager(options.baseDir, appId);
205     auto dbstatus = ChangeKVStoreDate(storeId, dbManager, options, dbPassword, time);
206     return StoreUtil::ConvertStatus(dbstatus) == SUCCESS;
207 }
208 
209 /**
210 * @tc.name: Rekey
211 * @tc.desc: test rekey function
212 * @tc.type: FUNC
213 * @tc.require:
214 * @tc.author: Cui Renjie
215 */
216 HWTEST_F(StoreFactoryTest, Rekey, TestSize.Level1)
217 {
218     Status status = DB_ERROR;
219     options.autoRekey = true;
220     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
221     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
222     ASSERT_EQ(status, SUCCESS);
223 
224     ASSERT_TRUE(ModifyDate(OUTDATED_TIME));
225 
226     auto oldKeyTime = GetDate(storeId, options.baseDir);
227     ASSERT_FALSE(std::chrono::system_clock::now() - oldKeyTime < std::chrono::seconds(2));
228 
229     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
230     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
231     ASSERT_EQ(status, SUCCESS);
232 
233     auto newKeyTime = GetDate(storeId, options.baseDir);
234     ASSERT_TRUE(std::chrono::system_clock::now() - newKeyTime < std::chrono::seconds(2));
235 }
236 
237 /**
238 * @tc.name: RekeyNotOutdated
239 * @tc.desc: try to rekey kvstore with not outdated password
240 * @tc.type: FUNC
241 * @tc.require:
242 * @tc.author: Cui Renjie
243 */
244 HWTEST_F(StoreFactoryTest, RekeyNotOutdated, TestSize.Level1)
245 {
246     Status status = DB_ERROR;
247     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
248     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
249     ASSERT_EQ(status, SUCCESS);
250 
251     ASSERT_TRUE(ModifyDate(NOT_OUTDATED_TIME));
252     auto oldKeyTime = GetDate(storeId, options.baseDir);
253 
254     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
255     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
256     ASSERT_EQ(status, SUCCESS);
257 
258     auto newKeyTime = GetDate(storeId, options.baseDir);
259     ASSERT_EQ(oldKeyTime, newKeyTime);
260 }
261 
262 /**
263 * @tc.name: RekeyInterrupted0
264 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
265 *           which caused key file lost but rekey key file exist.
266 * @tc.type: FUNC
267 * @tc.require:
268 * @tc.author: Cui Renjie
269 */
270 HWTEST_F(StoreFactoryTest, RekeyInterruptedWhileChangeKeyFile, TestSize.Level1)
271 {
272     Status status = DB_ERROR;
273     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
274     ASSERT_EQ(status, SUCCESS);
275     auto oldKeyTime = GetDate(storeId, options.baseDir);
276 
277     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
278     ASSERT_EQ(status, SUCCESS);
279     ASSERT_TRUE(MoveToRekeyPath(options, storeId));
280 
281     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
282     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
283     ASSERT_EQ(status, SUCCESS);
284     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
285     auto isKeyExist = StoreUtil::IsFileExist(keyFileName);
286     ASSERT_TRUE(isKeyExist);
287 
288     auto newKeyTime = GetDate(storeId, options.baseDir);
289     ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
290 }
291 
292 /**
293 * @tc.name: RekeyInterrupted1
294 * @tc.desc: mock the situation that open store after rekey was interrupted last time,
295 *           which caused key file not changed but rekey key file exist.
296 * @tc.type: FUNC
297 * @tc.require:
298 * @tc.author: Cui Renjie
299 */
300 HWTEST_F(StoreFactoryTest, RekeyInterruptedBeforeChangeKeyFile, TestSize.Level1)
301 {
302     Status status = DB_ERROR;
303     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
304     ASSERT_EQ(status, SUCCESS);
305     auto oldKeyTime = GetDate(storeId, options.baseDir);
306 
307     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
308     ASSERT_EQ(status, SUCCESS);
309     ASSERT_EQ(MoveToRekeyPath(options, storeId), true);
310 
311     StoreId newStoreId = { "newStore" };
312     StoreManager::GetInstance().GetKVStore(appId, newStoreId, options, status);
313 
314     std::string keyFileName = options.baseDir + "/key/" + storeId.storeId + ".key";
315     std::string mockKeyFileName = options.baseDir + "/key/" + newStoreId.storeId + ".key";
316     StoreUtil::Rename(mockKeyFileName, keyFileName);
317     StoreUtil::Remove(mockKeyFileName);
318     auto isKeyExist = StoreUtil::IsFileExist(mockKeyFileName);
319     ASSERT_FALSE(isKeyExist);
320     isKeyExist = StoreUtil::IsFileExist(keyFileName);
321     ASSERT_TRUE(isKeyExist);
322 
323     StoreManager::GetInstance().GetKVStore(appId, storeId, options, status);
324     status = StoreManager::GetInstance().CloseKVStore(appId, storeId);
325     ASSERT_EQ(status, SUCCESS);
326 
327     isKeyExist = StoreUtil::IsFileExist(keyFileName);
328     ASSERT_TRUE(isKeyExist);
329 
330     auto newKeyTime = GetDate(storeId, options.baseDir);
331     ASSERT_TRUE(newKeyTime - oldKeyTime < std::chrono::seconds(2));
332 }
333 
334 /**
335 * @tc.name: RekeyNoPwdFile
336 * @tc.desc: try to open kvstore and execute RekeyRecover() without key and rekey key files.
337 * @tc.type: FUNC
338 * @tc.require:
339 * @tc.author: Cui Renjie
340 */
341 HWTEST_F(StoreFactoryTest, RekeyNoPwdFile, TestSize.Level1)
342 {
343     Status status = DB_ERROR;
344     options.autoRekey = false;
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, SUCCESS);
358 
359     isKeyExist = StoreUtil::IsFileExist(keyFileName);
360     ASSERT_EQ(isKeyExist, true);
361 }
362 }