1 /*
2  * Copyright (c) 2022-2024 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 "fscrypt_key_v1_ext.h"
17 
18 #include <filesystem>
19 #include <vector>
20 
21 #include "fbex.h"
22 #include "file_ex.h"
23 #include "storage_service_log.h"
24 #include "string_ex.h"
25 
26 namespace OHOS {
27 namespace StorageDaemon {
28 static const std::string NEED_RESTORE_PATH = "/data/service/el0/storage_daemon/sd/latest/need_restore";
29 static const uint32_t DEFAULT_SINGLE_FIRST_USER_ID = 100;
30 static const uint32_t USER_ID_DIFF = 91;
31 
32 /* sec_fbe_drv module saved userId, type and IV in ioctl FBEX_IOC_ADD_IV process.
33  * In Upgrade Scenario, before upgrade user id 0 and after upgrade  user id 100, ioctl
34  * FBEX_IOC_ADD_IV will return error.
35  * so, to solve this problem, when el3/el4 ioctl FBEX_IOC_ADD_IV, userId need be mapped
36  * in Upgrade Scenario.
37  * user id mapped as:
38  * src-userId  mapped-userId    diff
39  * 0               100          100
40  * 10              101           91
41  * 11              102           91
42  * 12              103           91
43  * ...             ...           91
44  * 128             219           91
45  * 129             220           91
46  * ...             ...           91
47  */
GetMappedUserId(uint32_t userId,uint32_t type)48 uint32_t FscryptKeyV1Ext::GetMappedUserId(uint32_t userId, uint32_t type)
49 {
50     std::error_code errCode;
51     if (!std::filesystem::exists(NEED_RESTORE_PATH, errCode)) {
52         LOGE("restore path not exists, errCode = %{public}d", errCode.value());
53         return userId;
54     }
55     if (type == TYPE_EL2 || type == TYPE_EL3 || type == TYPE_EL4 || type == TYPE_EL5) {
56         if (userId == DEFAULT_SINGLE_FIRST_USER_ID) {
57             return 0;
58         }
59 
60         if (userId > DEFAULT_SINGLE_FIRST_USER_ID) {
61             return userId - USER_ID_DIFF;
62         }
63     }
64 
65     return userId;
66 }
67 
GetMappedDeUserId(uint32_t userId)68 uint32_t FscryptKeyV1Ext::GetMappedDeUserId(uint32_t userId)
69 {
70     if (userId == DEFAULT_SINGLE_FIRST_USER_ID) {
71         return 0;
72     }
73 
74     if (userId > DEFAULT_SINGLE_FIRST_USER_ID) {
75         return userId - USER_ID_DIFF;
76     }
77     return userId;
78 }
79 
ActiveKeyExt(uint32_t flag,uint8_t * iv,uint32_t size,uint32_t & elType)80 bool FscryptKeyV1Ext::ActiveKeyExt(uint32_t flag, uint8_t *iv, uint32_t size, uint32_t &elType)
81 {
82     if (!FBEX::IsFBEXSupported()) {
83         return true;
84     }
85 
86     LOGD("enter");
87     std::error_code errCode;
88     std::string updateVersion;
89     int ret = OHOS::LoadStringFromFile(NEED_RESTORE_PATH, updateVersion);
90     const int BASE = 2;
91     LOGI("restore version: %{public}s, ret: %{public}d", updateVersion.c_str(), ret);
92     if (type_ == TYPE_EL1 && std::filesystem::exists(NEED_RESTORE_PATH, errCode) &&
93         std::atoi(updateVersion.c_str()) % BASE == 0) {
94         LOGI("restore path exists, deal double DE, errCode = %{public}d", errCode.value());
95         return ActiveDoubleKeyExt(flag, iv, size, elType);
96     }
97     uint32_t user = GetMappedUserId(userId_, type_);
98     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
99     // iv buffer returns derived keys
100     if (FBEX::InstallKeyToKernel(user, type_, iv, size, static_cast<uint8_t>(flag)) != 0) {
101         LOGE("InstallKeyToKernel failed, user %{public}d, type %{public}d, flag %{public}u", user, type_, flag);
102         return false;
103     }
104 
105     //Used to associate el3 and el4 kernels.
106     elType = type_;
107     return true;
108 }
109 
ActiveDoubleKeyExt(uint32_t flag,uint8_t * iv,uint32_t size,uint32_t & elType)110 bool FscryptKeyV1Ext::ActiveDoubleKeyExt(uint32_t flag, uint8_t *iv, uint32_t size, uint32_t &elType)
111 {
112     LOGI("enter");
113     UserIdToFbeStr userIdToFbe = { .userIds = { userId_, GetMappedDeUserId(userId_) }, .size = USER_ID_SIZE };
114     if (FBEX::InstallDoubleDeKeyToKernel(userIdToFbe, iv, size, flag)) {
115         LOGE("DoubleDeKeyToKernel failed, user %{public}d, type %{public}d, flag %{public}u", userId_, type_, flag);
116         return false;
117     }
118     elType = type_;
119     return true;
120 }
121 
UnlockUserScreenExt(uint32_t flag,uint8_t * iv,uint32_t size)122 bool FscryptKeyV1Ext::UnlockUserScreenExt(uint32_t flag, uint8_t *iv, uint32_t size)
123 {
124     if (!FBEX::IsFBEXSupported()) {
125         return true;
126     }
127     LOGD("enter");
128     uint32_t user = GetMappedUserId(userId_, type_);
129     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
130     if (FBEX::UnlockScreenToKernel(user, type_, iv, size)) {
131         LOGE("UnlockScreenToKernel failed, userId %{public}d, %{public}d", userId_, flag);
132         return false;
133     }
134     return true;
135 }
136 
GenerateAppkey(uint32_t user,uint32_t hashId,std::unique_ptr<uint8_t[]> & appKey,uint32_t size)137 bool FscryptKeyV1Ext::GenerateAppkey(uint32_t user, uint32_t hashId, std::unique_ptr<uint8_t[]> &appKey, uint32_t size)
138 {
139     if (!FBEX::IsFBEXSupported()) {
140         return true;
141     }
142     LOGD("enter");
143     LOGI("map userId %{public}u to %{public}u", userId_, user);
144     // 0--single id, 1--double id
145     UserIdToFbeStr userIdToFbe = { .userIds = { userId_, GetMappedUserId(userId_, type_) }, .size = USER_ID_SIZE };
146     if (FBEX::GenerateAppkey(userIdToFbe, hashId, appKey, size)) {
147         LOGE("GenerateAppkey failed, user %{public}d", user);
148         return false;
149     }
150     return true;
151 }
152 
AddClassE(bool & isNeedEncryptClassE,bool & isSupport,uint32_t status)153 bool FscryptKeyV1Ext::AddClassE(bool &isNeedEncryptClassE, bool &isSupport, uint32_t status)
154 {
155     if (!FBEX::IsFBEXSupported()) {
156         return true;
157     }
158     LOGD("enter");
159     uint32_t userIdDouble = GetMappedUserId(userId_, type_);
160     LOGI("map userId %{public}u to %{public}u", userId_, userIdDouble);
161     if (FBEX::InstallEL5KeyToKernel(userId_, userIdDouble, status, isSupport, isNeedEncryptClassE)) {
162         LOGE("AddESecret failed, userId_ %{public}d, status is %{public}d", userId_, status);
163         return false;
164     }
165     return true;
166 }
167 
DeleteClassEPinCode(uint32_t userId)168 bool FscryptKeyV1Ext::DeleteClassEPinCode(uint32_t userId)
169 {
170     if (!FBEX::IsFBEXSupported()) {
171         return true;
172     }
173     LOGD("enter");
174     uint32_t userIdDouble = GetMappedUserId(userId_, type_);
175     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, userIdDouble);
176     if (FBEX::DeleteClassEPinCode(userId_, userIdDouble)) {
177         LOGE("UninstallOrLockUserKeyForEL5ToKernel failed, userId_ %{public}d", userId_);
178         return false;
179     }
180     return true;
181 }
182 
ChangePinCodeClassE(uint32_t userId,bool & isFbeSupport)183 bool FscryptKeyV1Ext::ChangePinCodeClassE(uint32_t userId, bool &isFbeSupport)
184 {
185     if (!FBEX::IsFBEXSupported()) {
186         return true;
187     }
188     uint32_t userIdDouble = GetMappedUserId(userId_, type_);
189     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, userIdDouble);
190     if (FBEX::ChangePinCodeClassE(userId_, userIdDouble, isFbeSupport)) {
191         LOGE("ChangePinCodeClassE failed, userId_ %{public}d", userId);
192         return false;
193     }
194     return true;
195 }
196 
ReadClassE(uint32_t status,std::unique_ptr<uint8_t[]> & classEBuffer,uint32_t length,bool & isFbeSupport)197 bool FscryptKeyV1Ext::ReadClassE(uint32_t status, std::unique_ptr<uint8_t[]> &classEBuffer, uint32_t length,
198                                  bool &isFbeSupport)
199 {
200     if (!FBEX::IsFBEXSupported()) {
201         return true;
202     }
203     LOGD("enter");
204     // 0--single id, 1--double id
205     UserIdToFbeStr userIdToFbe = { .userIds = { userId_, GetMappedUserId(userId_, type_) }, .size = USER_ID_SIZE };
206     LOGI("type_: %{public}u, userId %{public}u to %{public}u", type_, userId_, userIdToFbe.userIds[DOUBLE_ID_INDEX]);
207     if (FBEX::ReadESecretToKernel(userIdToFbe, status, classEBuffer, length, isFbeSupport)) {
208         LOGE("ReadESecret failed, user %{public}d, status: %{public}d", userIdToFbe.userIds[DOUBLE_ID_INDEX], status);
209         return false;
210     }
211     return true;
212 }
213 
WriteClassE(uint32_t status,uint8_t * classEBuffer,uint32_t length)214 bool FscryptKeyV1Ext::WriteClassE(uint32_t status, uint8_t *classEBuffer, uint32_t length)
215 {
216     if (!FBEX::IsFBEXSupported()) {
217         return true;
218     }
219     LOGD("enter");
220     // 0--single id, 1--double id
221     UserIdToFbeStr userIdToFbe = { .userIds = { userId_, GetMappedUserId(userId_, type_) }, .size = USER_ID_SIZE };
222     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u",
223          type_, userId_, userIdToFbe.userIds[DOUBLE_ID_INDEX]);
224     if (FBEX::WriteESecretToKernel(userIdToFbe, status, classEBuffer, length)) {
225         LOGE("WriteESecret failed,user %{public}d, status: %{public}d", userIdToFbe.userIds[DOUBLE_ID_INDEX], status);
226         return false;
227     }
228     return true;
229 }
230 
InactiveKeyExt(uint32_t flag)231 bool FscryptKeyV1Ext::InactiveKeyExt(uint32_t flag)
232 {
233     if (!FBEX::IsFBEXSupported()) {
234         return true;
235     }
236 
237     LOGD("enter");
238     bool destroy = !!flag;
239     if ((type_ != TYPE_EL2) && !destroy) {
240         LOGD("not el2, no need to inactive");
241         return true;
242     }
243     uint8_t buf[FBEX_IV_SIZE] = {0};
244     buf[0] = 0xfb; // fitst byte const to kernel
245     buf[1] = 0x30; // second byte const to kernel
246 
247     // When double update single, el5 use single user id, like: 100  101  102 ...
248     // el1-el4 use double id, like 0 10 11 12 ...
249     uint32_t user = type_ == TYPE_EL5 ? userId_ : GetMappedUserId(userId_, type_);
250     LOGI("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
251     if (FBEX::UninstallOrLockUserKeyToKernel(user, type_, buf, FBEX_IV_SIZE, destroy) != 0) {
252         LOGE("UninstallOrLockUserKeyToKernel failed, userId %{public}d, type %{public}d, destroy %{public}u",
253              userId_, type_, destroy);
254         return false;
255     }
256     return true;
257 }
258 
LockUserScreenExt(uint32_t flag,uint32_t & elType)259 bool FscryptKeyV1Ext::LockUserScreenExt(uint32_t flag, uint32_t &elType)
260 {
261     if (!FBEX::IsFBEXSupported()) {
262         return true;
263     }
264     LOGD("enter");
265     uint32_t user = GetMappedUserId(userId_, type_);
266     LOGD("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, user);
267     if (FBEX::LockScreenToKernel(user)) {
268         LOGE("LockScreenToKernel failed, userId %{public}d", user);
269         return false;
270     }
271     //Used to associate el3 and el4 kernels.
272     elType = type_;
273     return true;
274 }
275 
LockUeceExt(bool & isFbeSupport)276 bool FscryptKeyV1Ext::LockUeceExt(bool &isFbeSupport)
277 {
278     if (!FBEX::IsFBEXSupported()) {
279         return true;
280     }
281     LOGD("enter");
282     uint32_t userIdDouble = GetMappedUserId(userId_, type_);
283     LOGD("type_ is %{public}u, map userId %{public}u to %{public}u", type_, userId_, userIdDouble);
284     if (FBEX::LockUece(userId_, userIdDouble, isFbeSupport)) {
285         LOGE("LockUeceExt failed, userId");
286         return false;
287     }
288     return true;
289 }
290 
GetUserIdFromDir()291 uint32_t FscryptKeyV1Ext::GetUserIdFromDir()
292 {
293     int userId = USERID_GLOBAL_EL1; // default to global el1
294 
295     // fscrypt key dir is like `/data/foo/bar/el1/100`
296     auto slashIndex = dir_.rfind('/');
297     if (slashIndex != std::string::npos) {
298         std::string last = dir_.substr(slashIndex + 1);
299         (void)OHOS::StrToInt(last, userId);
300     }
301 
302     LOGI("dir_: %{public}s, get userId is %{public}d", dir_.c_str(), userId);
303     return static_cast<uint32_t>(userId);
304 }
305 
GetTypeFromDir()306 uint32_t FscryptKeyV1Ext::GetTypeFromDir()
307 {
308     static const std::vector<std::pair<std::string, uint32_t>> typeStrs = {
309         {"el1", TYPE_EL1},
310         {"el2", TYPE_EL2},
311         {"el3", TYPE_EL3},
312         {"el4", TYPE_EL4},
313         {"el5", TYPE_EL5},
314     };
315     uint32_t type = TYPE_GLOBAL_EL1; // default to global el1
316 
317     // fscrypt key dir is like `/data/foo/bar/el1/100`
318     auto slashIndex = dir_.rfind('/');
319     if (slashIndex == std::string::npos) {
320         LOGE("bad dir %{public}s", dir_.c_str());
321         return type;
322     }
323 
324     if (slashIndex == 0) {
325         LOGE("bad dir %{public}s", dir_.c_str());
326         return type;
327     }
328 
329     slashIndex = dir_.rfind('/', slashIndex - 1);
330     if (slashIndex == std::string::npos) {
331         LOGE("bad dir %{public}s", dir_.c_str());
332         return type;
333     }
334 
335     std::string el = dir_.substr(slashIndex + 1); // el string is like `el1/100`
336     for (const auto &it : typeStrs) {
337         if (el.find(it.first) != std::string::npos) {
338             type = it.second;
339             break;
340         }
341     }
342     LOGI("el string is %{public}s, parse type %{public}d", el.c_str(), type);
343     return type;
344 }
345 } // namespace StorageDaemon
346 } // namespace OHOS
347