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