• 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 #include <string>
18 #include <sys/types.h>
19 
20 #include "common.h"
21 #include "file_ex.h"
22 #include "rdb_errno.h"
23 #include "rdb_helper.h"
24 #include "rdb_open_callback.h"
25 #include "rdb_security_manager.h"
26 #include "sqlite_utils.h"
27 
28 using namespace testing::ext;
29 using namespace OHOS::NativeRdb;
30 class RdbRekeyTest : public testing::Test {
31 public:
32     static void SetUpTestCase();
33     static void TearDownTestCase();
34     void SetUp() override;
35     void TearDown() override;
36 
37     static std::string RemoveSuffix(const std::string &name);
38     static std::chrono::system_clock::time_point GetKeyFileDate(const std::string &dbName);
39     static bool ChangeKeyFileDate(const std::string &dbName, int rep);
40     static RdbStoreConfig GetRdbConfig(const std::string &name);
41     static void InsertData(std::shared_ptr<RdbStore> &store);
42     static void CheckQueryData(std::shared_ptr<RdbStore> &store);
43 
44     static const std::string encryptedDatabaseName;
45     static const std::string encryptedDatabasePath;
46     static const std::string encryptedDatabaseKeyDir;
47     static const std::string encryptedDatabaseMockName;
48     static const std::string encryptedDatabaseMockPath;
49     static constexpr int HOURS_EXPIRED = (24 * 365) + 1;
50     static constexpr int HOURS_NOT_EXPIRED = (24 * 30);
51 };
52 
53 const std::string RdbRekeyTest::encryptedDatabaseName = "encrypted.db";
54 const std::string RdbRekeyTest::encryptedDatabasePath = RDB_TEST_PATH + encryptedDatabaseName;
55 const std::string RdbRekeyTest::encryptedDatabaseKeyDir = RDB_TEST_PATH + "key/";
56 const std::string RdbRekeyTest::encryptedDatabaseMockName = "encrypted_mock.db";
57 const std::string RdbRekeyTest::encryptedDatabaseMockPath = RDB_TEST_PATH + encryptedDatabaseMockName;
58 
59 class RekeyTestOpenCallback : public RdbOpenCallback {
60 public:
61     int OnCreate(RdbStore &store) override;
62     int OnUpgrade(RdbStore &store, int oldVersion, int newVersion) override;
63     static const std::string createTableTest;
64 };
65 
66 std::string const RekeyTestOpenCallback::createTableTest = "CREATE TABLE IF NOT EXISTS test "
67                                                            "(id INTEGER PRIMARY KEY "
68                                                            "AUTOINCREMENT, "
69                                                            "name TEXT NOT NULL, age INTEGER, "
70                                                            "salary "
71                                                            "REAL, blobType BLOB)";
72 
OnCreate(RdbStore & store)73 int RekeyTestOpenCallback::OnCreate(RdbStore &store)
74 {
75     return store.ExecuteSql(createTableTest);
76 }
77 
OnUpgrade(RdbStore & store,int oldVersion,int newVersion)78 int RekeyTestOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion)
79 {
80     return E_OK;
81 }
82 
SetUpTestCase()83 void RdbRekeyTest::SetUpTestCase() {}
84 
TearDownTestCase()85 void RdbRekeyTest::TearDownTestCase() {}
86 
SetUp()87 void RdbRekeyTest::SetUp()
88 {
89     RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath);
90     RekeyTestOpenCallback helper;
91     int errCode;
92     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
93     EXPECT_NE(store, nullptr);
94     InsertData(store);
95     store.reset();
96     RdbHelper::ClearCache();
97 }
98 
TearDown()99 void RdbRekeyTest::TearDown()
100 {
101     RdbHelper::ClearCache();
102     RdbHelper::DeleteRdbStore(RdbRekeyTest::encryptedDatabasePath);
103 }
104 
RemoveSuffix(const string & name)105 std::string RdbRekeyTest::RemoveSuffix(const string &name)
106 {
107     std::string suffix(".db");
108     auto pos = name.rfind(suffix);
109     if (pos == std::string::npos || pos < name.length() - suffix.length()) {
110         return name;
111     }
112     return { name, 0, pos };
113 }
114 
GetKeyFileDate(const std::string & dbName)115 std::chrono::system_clock::time_point RdbRekeyTest::GetKeyFileDate(const std::string &dbName)
116 {
117     std::chrono::system_clock::time_point timePoint;
118     std::string name = RemoveSuffix(dbName);
119     auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
120     if (!OHOS::FileExists(keyPath)) {
121         return timePoint;
122     }
123     std::vector<char> content;
124     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
125     if (!loaded) {
126         return timePoint;
127     }
128     auto iter = content.begin();
129     iter++;
130     constexpr uint32_t dateFileLength = sizeof(time_t) / sizeof(uint8_t);
131     std::vector<uint8_t> date;
132     date.assign(iter, iter + dateFileLength);
133     timePoint = std::chrono::system_clock::from_time_t(*reinterpret_cast<time_t *>(const_cast<uint8_t *>(&date[0])));
134     return timePoint;
135 }
136 
ChangeKeyFileDate(const std::string & dbName,int rep)137 bool RdbRekeyTest::ChangeKeyFileDate(const std::string &dbName, int rep)
138 {
139     std::string name = RemoveSuffix(dbName);
140     auto keyPath = RDB_TEST_PATH + "key/" + name + ".pub_key";
141     if (!OHOS::FileExists(keyPath)) {
142         return false;
143     }
144     std::vector<char> content;
145     auto loaded = OHOS::LoadBufferFromFile(keyPath, content);
146     if (!loaded) {
147         return false;
148     }
149     auto time =
150         std::chrono::system_clock::to_time_t(std::chrono::system_clock::system_clock::now() - std::chrono::hours(rep));
151     std::vector<char> date(reinterpret_cast<uint8_t *>(&time), reinterpret_cast<uint8_t *>(&time) + sizeof(time));
152     std::copy(date.begin(), date.end(), ++content.begin());
153 
154     auto saved = OHOS::SaveBufferToFile(keyPath, content);
155     return saved;
156 }
157 
GetRdbConfig(const std::string & name)158 RdbStoreConfig RdbRekeyTest::GetRdbConfig(const std::string &name)
159 {
160     RdbStoreConfig config(name);
161     config.SetEncryptStatus(true);
162     config.SetBundleName("com.example.test_rekey");
163     return config;
164 }
165 
InsertData(std::shared_ptr<RdbStore> & store)166 void RdbRekeyTest::InsertData(std::shared_ptr<RdbStore> &store)
167 {
168     int64_t id;
169     ValuesBucket values;
170     std::string name = "zhangsan";
171     int age = 18;
172     double salary = 100.5;
173     std::vector<uint8_t> blob{ 1, 2, 3 };
174     values.PutString("name", name);
175     values.PutInt("age", age);
176     values.PutDouble("salary", salary);
177     values.PutBlob("blobType", blob);
178     int insertRet = store->Insert(id, "test", values);
179     EXPECT_EQ(insertRet, E_OK);
180 }
181 
CheckQueryData(std::shared_ptr<RdbStore> & store)182 void RdbRekeyTest::CheckQueryData(std::shared_ptr<RdbStore> &store)
183 {
184     std::shared_ptr<ResultSet> resultSet =
185         store->QuerySql("SELECT * FROM test WHERE name = ?", std::vector<std::string>{ "zhangsan" });
186     EXPECT_NE(resultSet, nullptr);
187     int result = resultSet->GoToFirstRow();
188     EXPECT_EQ(result, E_OK);
189     int columnIndex;
190     std::string strVal;
191     ColumnType columnType;
192     result = resultSet->GetColumnIndex("name", columnIndex);
193     EXPECT_EQ(result, E_OK);
194     result = resultSet->GetColumnType(columnIndex, columnType);
195     EXPECT_EQ(result, E_OK);
196     EXPECT_EQ(columnType, ColumnType::TYPE_STRING);
197     result = resultSet->GetString(columnIndex, strVal);
198     EXPECT_EQ(result, E_OK);
199     EXPECT_EQ("zhangsan", strVal);
200 
201     result = resultSet->Close();
202     EXPECT_EQ(result, E_OK);
203 }
204 
205 /**
206 * @tc.name: Rdb_Rekey_Test_001
207 * @tc.desc: test RdbStore rekey function
208 * @tc.type: FUNC
209 */
210 HWTEST_F(RdbRekeyTest, Rdb_Rekey_01, TestSize.Level1)
211 {
212     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
213     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
214 
215     bool isFileExists = OHOS::FileExists(keyPath);
216     ASSERT_TRUE(isFileExists);
217 
218     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_EXPIRED);
219     ASSERT_TRUE(isFileDateChanged);
220 
221     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
222     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_EXPIRED));
223 
224     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
225     RekeyTestOpenCallback helper;
226     int errCode;
227     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
228     ASSERT_NE(store, nullptr);
229 
230     isFileExists = OHOS::FileExists(keyPath);
231     ASSERT_TRUE(isFileExists);
232     isFileExists = OHOS::FileExists(newKeyPath);
233     ASSERT_FALSE(isFileExists);
234 
235     auto newDate = GetKeyFileDate(encryptedDatabaseName);
236     ASSERT_TRUE(std::chrono::system_clock::now() - newDate < std::chrono::seconds(2));
237     CheckQueryData(store);
238 }
239 
240 /**
241 * @tc.name: Rdb_Rekey_Test_002
242 * @tc.desc: test RdbStore with not outdated password
243 * @tc.type: FUNC
244 */
245 HWTEST_F(RdbRekeyTest, Rdb_Rekey_02, TestSize.Level1)
246 {
247     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
248     bool isFileExists = OHOS::FileExists(keyPath);
249     ASSERT_TRUE(isFileExists);
250 
251     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, RdbRekeyTest::HOURS_NOT_EXPIRED);
252     ASSERT_TRUE(isFileDateChanged);
253 
254     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
255     ASSERT_TRUE(std::chrono::system_clock::now() - changedDate > std::chrono::hours(RdbRekeyTest::HOURS_NOT_EXPIRED));
256 
257     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
258     RekeyTestOpenCallback helper;
259     int errCode;
260     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
261     ASSERT_NE(store, nullptr);
262     CheckQueryData(store);
263 }
264 
265 /**
266 * @tc.name: Rdb_Rekey_Test_003
267 * @tc.desc: try to open store and execute RekeyRecover() without key and new key files.
268 * @tc.type: FUNC
269 */
270 HWTEST_F(RdbRekeyTest, Rdb_Rekey_03, TestSize.Level1)
271 {
272     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
273     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
274 
275     bool isFileExists = OHOS::FileExists(keyPath);
276     ASSERT_TRUE(isFileExists);
277 
278     SqliteUtils::DeleteFile(keyPath);
279     isFileExists = OHOS::FileExists(keyPath);
280     ASSERT_FALSE(isFileExists);
281     isFileExists = OHOS::FileExists(newKeyPath);
282     ASSERT_FALSE(isFileExists);
283 
284     RekeyTestOpenCallback helper;
285     int errCode;
286     RdbStoreConfig config = GetRdbConfig(encryptedDatabasePath);
287     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
288     ASSERT_EQ(store, nullptr);
289 }
290 
291 /**
292 * @tc.name: Rdb_Rekey_Test_004
293 * @tc.desc: try to open store and modify create date to a future time.
294 * @tc.type: FUNC
295 */
296 HWTEST_F(RdbRekeyTest, Rdb_Rekey_04, TestSize.Level1)
297 {
298     std::string keyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key";
299     std::string newKeyPath = encryptedDatabaseKeyDir + RemoveSuffix(encryptedDatabaseName) + ".pub_key.new";
300 
301     bool isFileExists = OHOS::FileExists(keyPath);
302     ASSERT_TRUE(isFileExists);
303 
304     auto keyFileDate = GetKeyFileDate(encryptedDatabaseName);
305 
306     bool isFileDateChanged = ChangeKeyFileDate(encryptedDatabaseName, -RdbRekeyTest::HOURS_EXPIRED);
307     ASSERT_TRUE(isFileDateChanged);
308 
309     auto changedDate = GetKeyFileDate(encryptedDatabaseName);
310     ASSERT_GT(changedDate, keyFileDate);
311 
312     RdbStoreConfig config = GetRdbConfig(RdbRekeyTest::encryptedDatabasePath);
313     RekeyTestOpenCallback helper;
314     int errCode;
315     std::shared_ptr<RdbStore> store = RdbHelper::GetRdbStore(config, 1, helper, errCode);
316     ASSERT_NE(store, nullptr);
317 
318     isFileExists = OHOS::FileExists(keyPath);
319     ASSERT_TRUE(isFileExists);
320     isFileExists = OHOS::FileExists(newKeyPath);
321     ASSERT_FALSE(isFileExists);
322 
323     keyFileDate = GetKeyFileDate(encryptedDatabaseName);
324     ASSERT_EQ(changedDate, keyFileDate);
325 
326     CheckQueryData(store);
327 }