• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2023 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 
16 #include <gtest/gtest.h>
17 
18 #include <fstream>
19 #include <iostream>
20 #include <string>
21 
22 #include "common.h"
23 #include "file_ex.h"
24 #include "rdb_errno.h"
25 #include "rdb_helper.h"
26 #include "rdb_open_callback.h"
27 #include "rdb_security_manager.h"
28 #include "sqlite_utils.h"
29 
30 using namespace testing::ext;
31 using namespace OHOS::NativeRdb;
32 class RdbRekeyTest : public testing::Test {
33 public:
34     static void SetUpTestCase();
35     static void TearDownTestCase();
36     void SetUp() override;
37     void TearDown() override;
38 
39     static std::string RemoveSuffix(const std::string &name);
40     static std::chrono::system_clock::time_point GetKeyFileDate(const std::string &dbName);
41     static bool ChangeKeyFileDate(const std::string &dbName, int rep);
42     static bool SaveNewKey(const std::string &dbName);
43     static RdbStoreConfig GetRdbConfig(const std::string &name);
44     static RdbStoreConfig GetRdbNotRekeyConfig(const std::string &name);
45     static void InsertData(std::shared_ptr<RdbStore> &store);
46     static void CheckQueryData(std::shared_ptr<RdbStore> &store);
47 
48     static const std::string encryptedDatabaseName;
49     static const std::string encryptedDatabasePath;
50     static const std::string encryptedDatabaseKeyDir;
51     static const std::string encryptedDatabaseMockName;
52     static const std::string encryptedDatabaseMockPath;
53     static constexpr int HOURS_EXPIRED = (24 * 365) + 1;
54     static constexpr int HOURS_LONG_LONG_AGO = 30 * (24 * 365);
55     static constexpr int HOURS_NOT_EXPIRED = (24 * 30);
56 };
57 
58 const std::string RdbRekeyTest::encryptedDatabaseName = "encrypted.db";
59 const std::string RdbRekeyTest::encryptedDatabasePath = RDB_TEST_PATH + encryptedDatabaseName;
60 const std::string RdbRekeyTest::encryptedDatabaseKeyDir = RDB_TEST_PATH + "key/";
61 const std::string RdbRekeyTest::encryptedDatabaseMockName = "encrypted_mock.db";
62 const std::string RdbRekeyTest::encryptedDatabaseMockPath = RDB_TEST_PATH + encryptedDatabaseMockName;
63 
64 class RekeyTestOpenCallback : public RdbOpenCallback {
65 public:
66     int OnCreate(RdbStore &store) override;
67     int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
68     static const std::string createTableTest;
69 };
70 
71 std::string const RekeyTestOpenCallback::createTableTest = "CREATE TABLE IF NOT EXISTS test "
72                                                            "(id INTEGER PRIMARY KEY "
73                                                            "AUTOINCREMENT, "
74                                                            "name TEXT NOT NULL, age INTEGER, "
75                                                            "salary "
76                                                            "REAL, blobType BLOB)";
77 
OnCreate(RdbStore & store)78 int RekeyTestOpenCallback::OnCreate(RdbStore &store)
79 {
80     return store.ExecuteSql(createTableTest);
81 }
82 
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)83 int RekeyTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
84 {
85     return E_OK;
86 }
87 
SetUpTestCase()88 void RdbRekeyTest::SetUpTestCase()
89 {
90 }
91 
TearDownTestCase()92 void RdbRekeyTest::TearDownTestCase()
93 {
94 }
95 
SetUp()96 void RdbRekeyTest::SetUp()
97 {
98     RdbHelper::ClearCache();
99     RdbHelper::DeleteRdbStore(RdbRekeyTest::encryptedDatabasePath);
100     RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath);
101     RekeyTestOpenCallback helper;
102     int errCode;
103     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
104     EXPECT_NE(store, nullptr);
105     InsertData(store);
106     store.reset();
107     RdbHelper::ClearCache();
108 }
109 
TearDown()110 void RdbRekeyTest::TearDown()
111 {
112     RdbHelper::ClearCache();
113     RdbHelper::DeleteRdbStore(RdbRekeyTest::encryptedDatabasePath);
114 }
115 
RemoveSuffix(const std::string & name)116 std::string RdbRekeyTest::RemoveSuffix(const std::string &name)
117 {
118     std::string suffix(".db");
119     auto pos = name.rfind(suffix);
120     if (pos == std::string::npos || pos < name.length() - suffix.length()) {
121         return name;
122     }
123     return { name, 0, pos };
124 }
125 
GetKeyFileDate(const std::string & dbName)126 std::chrono::system_clock::time_point RdbRekeyTest::GetKeyFileDate(const std::string &dbName)
127 {
128     std::chrono::system_clock::time_point timePoint;
129     std::string name = RemoveSuffix(dbName);
130     auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
131     if (!OHOS::FileExists(keyPath)) {
132         return timePoint;
133     }
134     std::vector<char> content;
135     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
136     if (!loaded) {
137         return timePoint;
138     }
139     auto iter = content.begin();
140     iter++;
141     constexpr uint32_t dateFileLength = sizeof(time_t) / sizeof(uint8_t);
142     std::vector<uint8_t> date;
143     date.assign(iter, iter + dateFileLength);
144     timePoint = std::chrono::system_clock::from_time_t(*reinterpret_cast<time_t *>(const_cast<uint8_t *>(&date[0])));
145     return timePoint;
146 }
147 
ChangeKeyFileDate(const std::string & dbName,int rep)148 bool RdbRekeyTest::ChangeKeyFileDate(const std::string &dbName, int rep)
149 {
150     std::string name = RemoveSuffix(dbName);
151     auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
152     if (!OHOS::FileExists(keyPath)) {
153         return false;
154     }
155     std::vector<char> content;
156     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
157     if (!loaded) {
158         return false;
159     }
160     auto time =
161         std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now() - std::chrono::hours(rep));
162     std::vector<char> date(reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time));
163     std::copy(date.begin(), date.end(), ++content.begin());
164 
165     auto saved = OHOS::SaveBufferToFile(keyPath, content);
166     return saved;
167 }
168 
SaveNewKey(const string & dbName)169 bool RdbRekeyTest::SaveNewKey(const string &dbName)
170 {
171     std::string name = RemoveSuffix(dbName);
172     auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
173     auto newKeyPath = RDB_TEST_PATH + "key/" + name + ".pub_key.new";
174     if (!OHOS::FileExists(keyPath)) {
175         return false;
176     }
177     std::vector<char> content;
178     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
179     if (!loaded) {
180         return false;
181     }
182     OHOS::SaveBufferToFile(newKeyPath, content);
183     content[content.size() - 1] = 'E';
184     return OHOS::SaveBufferToFile(keyPath, content);
185 }
186 
GetRdbConfig(const std::string & name)187 RdbStoreConfig RdbRekeyTest::GetRdbConfig(const std::string &name)
188 {
189     RdbStoreConfig config(name);
190     config.SetEncryptStatus(true);
191     config.SetBundleName("com.example.test_rekey");
192     config.EnableRekey(true);
193     return config;
194 }
195 
GetRdbNotRekeyConfig(const std::string & name)196 RdbStoreConfig RdbRekeyTest::GetRdbNotRekeyConfig(const std::string &name)
197 {
198     RdbStoreConfig config(name);
199     config.SetEncryptStatus(true);
200     config.SetBundleName("com.example.test_rekey");
201     config.EnableRekey(false);
202     return config;
203 }
204 
InsertData(std::shared_ptr<RdbStore> & store)205 void RdbRekeyTest::InsertData(std::shared_ptr<RdbStore> &store)
206 {
207     int64_t id;
208     ValuesBucket values;
209     std::string name = "zhangsan";
210     int age = 18;
211     double salary = 100.5;
212     std::vector<uint8_t> blob{ 1, 2, 3 };
213     values.PutString("name", name);
214     values.PutInt("age", age);
215     values.PutDouble("salary", salary);
216     values.PutBlob("blobType", blob);
217     int insertRet = store->Insert(id, "test", values);
218     EXPECT_EQ(insertRet, E_OK);
219 }
220 
CheckQueryData(std::shared_ptr<RdbStore> & store)221 void RdbRekeyTest::CheckQueryData(std::shared_ptr<RdbStore> &store)
222 {
223     std::shared_ptr<ResultSet> resultSet =
224         store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
225     EXPECT_NE(resultSet, nullptr);
226     int result = resultSet->GoToFirstRow();
227     EXPECT_EQ(result, E_OK);
228     int columnIndex;
229     std::string strVal;
230     ColumnType columnType;
231     result = resultSet->GetColumnIndex("name", columnIndex);
232     EXPECT_EQ(result, E_OK);
233     result = resultSet->GetColumnType(columnIndex, columnType);
234     EXPECT_EQ(result, E_OK);
235     EXPECT_EQ(columnType, ColumnType::TYPE_STRING);
236     result = resultSet->GetString(columnIndex, strVal);
237     EXPECT_EQ(result, E_OK);
238     EXPECT_EQ("zhangsan", strVal);
239 
240     result = resultSet->Close();
241     EXPECT_EQ(result, E_OK);
242 }
243 
244 /**
245 * @tc.name: Rdb_Rekey_Test_001
246 * @tc.desc: test RdbStore rekey function
247 * @tc.type: FUNC
248 */
249 HWTEST_F(RdbRekeyTest, Rdb_Rekey_01, TestSize.Level1)
250 {
251     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
252     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
253 
254     bool isFileExists = OHOS::FileExists(keyPath);
255     ASSERT_TRUE(isFileExists);
256 
257     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_EXPIRED);
258     ASSERT_TRUE(isFileDateChanged);
259 
260     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
261     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_EXPIRED));
262 
263     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
264     RekeyTestOpenCallback helper;
265     int errCode = E_OK;
266     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
267     ASSERT_NE(store, nullptr);
268     ASSERT_EQ(errCode, E_OK);
269 
270     isFileExists = OHOS::FileExists(keyPath);
271     ASSERT_TRUE(isFileExists);
272     isFileExists = OHOS::FileExists(newKeyPath);
273     ASSERT_FALSE(isFileExists);
274 
275     auto newDate = GetKeyFileDate(encryptedDatabaseName);
276     ASSERT_TRUE(std::chrono::system_clock::now() - newDate < std::chrono::seconds(2));
277     CheckQueryData(store);
278 }
279 
280 /**
281 * @tc.name: Rdb_Rekey_Test_002
282 * @tc.desc: test RdbStore with not outdated password
283 * @tc.type: FUNC
284 */
285 HWTEST_F(RdbRekeyTest, Rdb_Rekey_02, TestSize.Level1)
286 {
287     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
288     bool isFileExists = OHOS::FileExists(keyPath);
289     ASSERT_TRUE(isFileExists);
290 
291     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_NOT_EXPIRED);
292     ASSERT_TRUE(isFileDateChanged);
293 
294     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
295     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_NOT_EXPIRED));
296 
297     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
298     RekeyTestOpenCallback helper;
299     int errCode = E_OK;
300     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
301     ASSERT_NE(store, nullptr);
302     ASSERT_EQ(errCode, E_OK);
303     CheckQueryData(store);
304 }
305 
306 /**
307 * @tc.name: Rdb_Rekey_Test_003
308 * @tc.desc: try to open store and execute RekeyRecover() without key and new key files.
309 * @tc.type: FUNC
310 */
311 HWTEST_F(RdbRekeyTest, Rdb_Rekey_03, TestSize.Level1)
312 {
313     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
314     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
315 
316     bool isFileExists = OHOS::FileExists(keyPath);
317     ASSERT_TRUE(isFileExists);
318 
319     SqliteUtils::DeleteFile(keyPath);
320     isFileExists = OHOS::FileExists(keyPath);
321     ASSERT_FALSE(isFileExists);
322     isFileExists = OHOS::FileExists(newKeyPath);
323     ASSERT_FALSE(isFileExists);
324 
325     RekeyTestOpenCallback helper;
326     int errCode = E_OK;
327     RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath);
328     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
329     ASSERT_NE(store, nullptr);
330     ASSERT_EQ(errCode, E_OK);
331     store = nullptr;
332     store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
333     ASSERT_NE(store, nullptr);
334     ASSERT_EQ(errCode, E_OK);
335 }
336 
337 /**
338 * @tc.name: Rdb_Rekey_Test_004
339 * @tc.desc: try to open store and modify create date to a future time.
340 * @tc.type: FUNC
341 */
342 HWTEST_F(RdbRekeyTest, Rdb_Rekey_04, TestSize.Level1)
343 {
344     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
345     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
346 
347     bool isFileExists = OHOS::FileExists(keyPath);
348     ASSERT_TRUE(isFileExists);
349 
350     auto keyFileDate = GetKeyFileDate(encryptedDatabaseName);
351 
352     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, -RdbRekeyTest::HOURS_EXPIRED);
353     ASSERT_TRUE(isFileDateChanged);
354 
355     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
356     ASSERT_GT(changedDate, keyFileDate);
357 
358     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
359     RekeyTestOpenCallback helper;
360     int errCode;
361     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
362     ASSERT_NE(store, nullptr);
363 
364     isFileExists = OHOS::FileExists(keyPath);
365     ASSERT_TRUE(isFileExists);
366     isFileExists = OHOS::FileExists(newKeyPath);
367     ASSERT_FALSE(isFileExists);
368 
369     keyFileDate = GetKeyFileDate(encryptedDatabaseName);
370     ASSERT_EQ(changedDate, keyFileDate);
371 
372     CheckQueryData(store);
373 }
374 
375 /**
376 * @tc.name: Rdb_Rekey_RenameFailed_05
377 * @tc.desc: re key and rename failed the new key file.
378 * @tc.type: FUNC
379 */
380 HWTEST_F(RdbRekeyTest, Rdb_Rekey_RenameFailed_05, TestSize.Level1)
381 {
382     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
383     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
384 
385     bool isFileExists = OHOS::FileExists(keyPath);
386     ASSERT_TRUE(isFileExists);
387 
388     auto keyFileDate = GetKeyFileDate(encryptedDatabaseName);
389 
390     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_LONG_LONG_AGO);
391     ASSERT_TRUE(isFileDateChanged);
392 
393     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
394     ASSERT_GT(keyFileDate, changedDate);
395 
396     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
397     RekeyTestOpenCallback helper;
398     int errCode = E_OK;
399     for (int i = 0; i < 50; ++i) {
400         auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
401         ASSERT_NE(store, nullptr);
402         ASSERT_EQ(errCode, E_OK);
403         store = nullptr;
404         SaveNewKey(encryptedDatabaseName);
405     }
406 
407     auto store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
408     CheckQueryData(store);
409 }
410 
411 /**
412 * @tc.name: Rdb_Delete_Rekey_Test_06
413 * @tc.desc: test RdbStore rekey function
414 * @tc.type: FUNC
415 */
416 HWTEST_F(RdbRekeyTest, Rdb_Rekey_06, TestSize.Level1)
417 {
418     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
419     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
420 
421     bool isFileExists = OHOS::FileExists(keyPath);
422     ASSERT_TRUE(isFileExists);
423 
424     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_EXPIRED);
425     ASSERT_TRUE(isFileDateChanged);
426 
427     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
428     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_EXPIRED));
429 
430     RdbStoreConfig config = GetRdbNotRekeyConfig(RdbRekeyTest::encryptedDatabasePath);
431     RekeyTestOpenCallback helper;
432     int errCode = E_OK;
433     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
434     ASSERT_NE(store, nullptr);
435     ASSERT_EQ(errCode, E_OK);
436 
437     isFileExists = OHOS::FileExists(keyPath);
438     ASSERT_TRUE(isFileExists);
439     isFileExists = OHOS::FileExists(newKeyPath);
440     ASSERT_FALSE(isFileExists);
441 
442     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_EXPIRED));
443     CheckQueryData(store);
444 }