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