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.h"
17
18 #include <fcntl.h>
19 #include <openssl/sha.h>
20 #include <unistd.h>
21
22 #include "file_ex.h"
23 #include "key_backup.h"
24 #include "libfscrypt/key_control.h"
25 #include "storage_service_log.h"
26
27 namespace OHOS {
28 namespace StorageDaemon {
29 static const std::string CRYPTO_NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt"};
30
ActiveKey(uint32_t flag,const std::string & mnt)31 bool FscryptKeyV1::ActiveKey(uint32_t flag, const std::string &mnt)
32 {
33 uint32_t elType;
34 (void)mnt;
35 LOGI("enter");
36 if (!GenerateKeyDesc()) {
37 keyInfo_.key.Clear();
38 LOGE("GenerateKeyDesc failed");
39 return false;
40 }
41 LOGE("ActiveKey key is empty: %{public}u", keyInfo_.key.IsEmpty());
42 if (!fscryptV1Ext.ActiveKeyExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size, elType)) {
43 keyInfo_.key.Clear();
44 LOGE("fscryptV1Ext ActiveKeyExtfailed");
45 return false;
46 }
47 if (elType == TYPE_EL3 || elType == TYPE_EL4) {
48 uint32_t sdpClass;
49 if (elType == TYPE_EL3) {
50 sdpClass = FSCRYPT_SDP_SECE_CLASS;
51 } else {
52 sdpClass = FSCRYPT_SDP_ECE_CLASS;
53 }
54 if (!InstallEceSeceKeyToKeyring(sdpClass)) {
55 keyInfo_.key.Clear();
56 LOGE("InstallEceSeceKeyToKeyring failed");
57 return false;
58 }
59 } else {
60 if (!InstallKeyToKeyring()) {
61 keyInfo_.key.Clear();
62 LOGE("InstallKeyToKeyring failed");
63 return false;
64 }
65 }
66 keyInfo_.key.Clear();
67 LOGI("success");
68 return true;
69 }
70
GenerateAppkey(uint32_t userId,uint32_t hashId,std::string & keyDesc)71 bool FscryptKeyV1::GenerateAppkey(uint32_t userId, uint32_t hashId, std::string &keyDesc)
72 {
73 KeyBlob appKey(FBEX_KEYID_SIZE);
74 if (!fscryptV1Ext.GenerateAppkey(userId, hashId, appKey.data, appKey.size)) {
75 LOGE("fscryptV1Ext GenerateAppkey failed");
76 return false;
77 }
78 // The ioctl does not support EL5, return empty character string
79 if (appKey.data.get() == nullptr) {
80 LOGE("appKey.data.get() is nullptr");
81 keyDesc = "";
82 return true;
83 }
84 if (!GenerateAppKeyDesc(appKey)) {
85 LOGE("GenerateAppKeyDesc failed");
86 return false;
87 }
88 if (!InstallKeyForAppKeyToKeyring(appKey)) {
89 LOGE("InstallKeyForAppKeyToKeyring failed");
90 return false;
91 }
92 appKey.Clear();
93 keyDesc = keyInfo_.keyDesc.ToString();
94 keyInfo_.keyDesc.Clear();
95 LOGI("success");
96 return true;
97 }
98
InstallKeyForAppKeyToKeyring(KeyBlob & appKey)99 bool FscryptKeyV1::InstallKeyForAppKeyToKeyring(KeyBlob &appKey)
100 {
101 LOGI("InstallKeyForAppKeyToKeyring enter");
102 EncryptAsdpKey fskey;
103 fskey.size = appKey.size;
104 fskey.version = 0;
105 auto err = memcpy_s(fskey.raw, FSCRYPT_MAX_KEY_SIZE, appKey.data.get(), appKey.size);
106 if (err != EOK) {
107 LOGE("memcpy failed ret %{public}d", err);
108 return false;
109 }
110 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
111 if (krid < 0) {
112 LOGI("no session keyring for fscrypt");
113 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
114 if (krid < 0) {
115 LOGE("failed to add session keyring");
116 return false;
117 }
118 }
119 for (auto prefix : CRYPTO_NAME_PREFIXES) {
120 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
121 key_serial_t ks =
122 KeyCtrlAddAppAsdpKey("logon", keyref.c_str(), &fskey, krid);
123 if (ks < 0) {
124 // Addkey failed, need to process the error
125 LOGE("Failed to AddKey into keyring, errno %{public}d", errno);
126 }
127 }
128 LOGI("success");
129 return true;
130 }
131
DeleteAppkey(const std::string KeyId)132 bool FscryptKeyV1::DeleteAppkey(const std::string KeyId)
133 {
134 LOGI("DeleteAppkey enter");
135 if (!UninstallKeyForAppKeyToKeyring(KeyId)) {
136 LOGE("FscryptKeyV1 Delete Appkey2 failed");
137 return false;
138 }
139 LOGI("success");
140 return true;
141 }
142
UninstallKeyForAppKeyToKeyring(const std::string keyId)143 bool FscryptKeyV1::UninstallKeyForAppKeyToKeyring(const std::string keyId)
144 {
145 LOGI("UninstallKeyForAppKeyToKeyring enter");
146 if (keyId.length() == 0) {
147 LOGE("keyId is null, does not need to be installed?");
148 return false;
149 }
150 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
151 if (krid == -1) {
152 LOGE("Error searching session keyring for fscrypt-provisioning key for fscrypt");
153 return false;
154 }
155 for (auto prefix : CRYPTO_NAME_PREFIXES) {
156 std::string keyref = prefix + ":" + keyId;
157 key_serial_t ks = KeyCtrlSearch(krid, "logon", keyref.c_str(), 0);
158 if (KeyCtrlUnlink(ks, krid) != 0) {
159 LOGE("Failed to unlink key !");
160 }
161 }
162 LOGI("success");
163 return true;
164 }
165
UnlockUserScreen(uint32_t flag,uint32_t sdpClass,const std::string & mnt)166 bool FscryptKeyV1::UnlockUserScreen(uint32_t flag, uint32_t sdpClass, const std::string &mnt)
167 {
168 (void)mnt;
169 LOGI("enter");
170 if (!GenerateKeyDesc()) {
171 keyInfo_.key.Clear();
172 LOGE("GenerateKeyDesc failed");
173 return false;
174 }
175 LOGI("keyInfo empty: %{public}u:", keyInfo_.key.IsEmpty());
176 if (!fscryptV1Ext.UnlockUserScreenExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size)) {
177 keyInfo_.key.Clear();
178 LOGE("fscryptV1Ext UnlockUserScreenExtfailed");
179 return false;
180 }
181 if (sdpClass == FSCRYPT_SDP_ECE_CLASS) {
182 if (!InstallEceSeceKeyToKeyring(sdpClass)) {
183 keyInfo_.key.Clear();
184 LOGE("UnlockUserScreen InstallKeyToKeyring failed");
185 return false;
186 }
187 }
188 keyInfo_.key.Clear();
189 LOGI("success");
190 return true;
191 }
192
AddClassE(bool & isNeedEncryptClassE,bool & isSupport,uint32_t status)193 bool FscryptKeyV1::AddClassE(bool &isNeedEncryptClassE, bool &isSupport, uint32_t status)
194 {
195 LOGI("AddClassE enter");
196 if (!fscryptV1Ext.AddClassE(isNeedEncryptClassE, isSupport, status)) {
197 LOGE("fscryptV1Ext AddClassE failed");
198 return false;
199 }
200 LOGI("AddClassE finish");
201 return true;
202 }
203
DeleteClassEPinCode(uint32_t userId)204 bool FscryptKeyV1::DeleteClassEPinCode(uint32_t userId)
205 {
206 LOGI("DeleteClassE enter");
207 if (!fscryptV1Ext.DeleteClassEPinCode(userId)) {
208 LOGE("fscryptV1Ext DeleteClassE failed");
209 return false;
210 }
211 LOGI("DeleteClassE finish");
212 return true;
213 }
214
ChangePinCodeClassE(bool & isFbeSupport,uint32_t userId)215 bool FscryptKeyV1::ChangePinCodeClassE(bool &isFbeSupport, uint32_t userId)
216 {
217 LOGI("ChangePinCodeClassE enter, userId: %{public}d", userId);
218 if (!fscryptV1Ext.ChangePinCodeClassE(userId, isFbeSupport)) {
219 LOGE("fscryptV1Ext ChangePinCodeClassE failed");
220 return false;
221 }
222 LOGI("ChangePinCodeClassE finish");
223 return true;
224 }
225
DecryptClassE(const UserAuth & auth,bool & isSupport,bool & eBufferStatue,uint32_t user,uint32_t status)226 bool FscryptKeyV1::DecryptClassE(const UserAuth &auth, bool &isSupport,
227 bool &eBufferStatue, uint32_t user, uint32_t status)
228 {
229 LOGI("enter");
230 KeyBlob eSecretFBE(AES_256_HASH_RANDOM_SIZE + GCM_MAC_BYTES + GCM_NONCE_BYTES);
231 bool isFbeSupport = true;
232 if (!fscryptV1Ext.ReadClassE(status, eSecretFBE.data, eSecretFBE.size, isFbeSupport)) {
233 LOGE("fscryptV1Ext ReadClassE failed");
234 return false;
235 }
236 if ((auth.token.IsEmpty() && auth.secret.IsEmpty()) || eSecretFBE.IsEmpty()) {
237 LOGE("Token and secret is invalid, do not deal.");
238 eBufferStatue = eSecretFBE.IsEmpty();
239 eSecretFBE.Clear();
240 return true;
241 }
242 if (!isFbeSupport) {
243 LOGE("fbe not support uece, skip!");
244 isSupport = false;
245 return true;
246 }
247 LOGI("Decrypt keyPath is %{public}s", (dir_ + PATH_LATEST).c_str());
248 KeyBlob decryptedKey(AES_256_HASH_RANDOM_SIZE);
249 if (KeyBackup::GetInstance().TryRestoreUeceKey(shared_from_this(), auth, eSecretFBE, decryptedKey) != 0) {
250 LOGE("DecryptKeyBlob Decrypt failed");
251 eSecretFBE.Clear();
252 return false;
253 }
254 eSecretFBE.Clear();
255 LOGI("Decrypt end!");
256 if (!fscryptV1Ext.WriteClassE(status, decryptedKey.data.get(), decryptedKey.size)) {
257 LOGE("fscryptV1Ext WriteClassE failed");
258 return false;
259 }
260 decryptedKey.Clear();
261 LOGI("finish");
262 return true;
263 }
264
EncryptClassE(const UserAuth & auth,bool & isSupport,uint32_t user,uint32_t status)265 bool FscryptKeyV1::EncryptClassE(const UserAuth &auth, bool &isSupport, uint32_t user, uint32_t status)
266 {
267 LOGI("enter");
268 KeyBlob eSecretFBE(AES_256_HASH_RANDOM_SIZE);
269 bool isFbeSupport = true;
270 if (!fscryptV1Ext.ReadClassE(status, eSecretFBE.data, eSecretFBE.size, isFbeSupport)) {
271 LOGE("fscryptV1Ext ReadClassE failed");
272 return false;
273 }
274 if (!isFbeSupport) {
275 LOGE("fbe not support E type, skip!");
276 isSupport = false;
277 return true;
278 }
279 KeyBlob encryptedKey(AES_256_HASH_RANDOM_SIZE + GCM_MAC_BYTES + GCM_NONCE_BYTES);
280 if (!EncryptKeyBlob(auth, dir_ + PATH_LATEST, eSecretFBE, encryptedKey)) {
281 LOGE("EncryptKeyBlob Decrypt failed");
282 eSecretFBE.Clear();
283 return false;
284 }
285 eSecretFBE.Clear();
286 if (!RenameKeyPath(dir_ + PATH_LATEST)) {
287 LOGE("RenameKeyPath failed");
288 return false;
289 }
290 LOGI("encrypt end");
291 if (!fscryptV1Ext.WriteClassE(status, encryptedKey.data.get(), encryptedKey.size)) {
292 LOGE("fscryptV1Ext WriteClassE failed");
293 return false;
294 }
295 encryptedKey.Clear();
296 LOGI("finish");
297 return true;
298 }
299
InstallKeyToKeyring()300 bool FscryptKeyV1::InstallKeyToKeyring()
301 {
302 fscrypt_key fskey;
303 fskey.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
304 fskey.size = keyInfo_.key.size;
305 auto err = memcpy_s(fskey.raw, FS_MAX_KEY_SIZE, keyInfo_.key.data.get(), keyInfo_.key.size);
306 if (err != EOK) {
307 LOGE("memcpy failed ret %{public}d", err);
308 return false;
309 }
310
311 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
312 if (krid == -1) {
313 LOGI("no session keyring for fscrypt");
314 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
315 if (krid == -1) {
316 LOGE("failed to add session keyring");
317 return false;
318 }
319 }
320 for (auto prefix : CRYPTO_NAME_PREFIXES) {
321 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
322 key_serial_t ks =
323 KeyCtrlAddKeyEx("logon", keyref.c_str(), &fskey, krid);
324 if (ks == -1) {
325 // Addkey failed, need to process the error
326 LOGE("Failed to AddKey into keyring, errno %{public}d", errno);
327 }
328 }
329 if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
330 return false;
331 }
332 keyInfo_.key.Clear();
333 LOGI("success");
334 return true;
335 }
336
InstallEceSeceKeyToKeyring(uint32_t sdpClass)337 bool FscryptKeyV1::InstallEceSeceKeyToKeyring(uint32_t sdpClass)
338 {
339 EncryptionKeySdp fskey;
340 if (keyInfo_.key.size != sizeof(fskey.raw)) {
341 LOGE("Wrong key size is %{public}d", keyInfo_.key.size);
342 return false;
343 }
344 fskey.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
345 auto err = memcpy_s(fskey.raw, sizeof(fskey.raw), keyInfo_.key.data.get(), keyInfo_.key.size);
346 if (err != EOK) {
347 LOGE("memcpy failed ret %{public}d", err);
348 return false;
349 }
350 fskey.size = EXT4_AES_256_XTS_KEY_SIZE_TO_KEYRING;
351 fskey.sdpClass = sdpClass;
352 fskey.version = 0;
353 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
354 if (krid == -1) {
355 LOGI("no session keyring for fscrypt");
356 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
357 if (krid == -1) {
358 LOGE("failed to add session keyring");
359 return false;
360 }
361 }
362 for (auto prefix : CRYPTO_NAME_PREFIXES) {
363 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
364 key_serial_t ks =
365 KeyCtrlAddKeySdp("logon", keyref.c_str(), &fskey, krid);
366 if (ks == -1) {
367 // Addkey failed, need to process the error
368 LOGE("Failed to AddKey into keyring, errno %{public}d", errno);
369 }
370 }
371 if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
372 return false;
373 }
374 LOGI("success");
375 return true;
376 }
377
InactiveKey(uint32_t flag,const std::string & mnt)378 bool FscryptKeyV1::InactiveKey(uint32_t flag, const std::string &mnt)
379 {
380 (void)mnt;
381 LOGI("enter");
382 bool ret = true;
383
384 if (!keyInfo_.keyDesc.IsEmpty() && !UninstallKeyToKeyring()) {
385 LOGE("UninstallKeyToKeyring failed");
386 ret = false;
387 }
388 if (!fscryptV1Ext.InactiveKeyExt(flag)) {
389 LOGE("fscryptV1Ext InactiveKeyExt failed");
390 ret = false;
391 }
392 DropCachesIfNeed();
393 LOGI("finish");
394 return ret;
395 }
396
DropCachesIfNeed()397 void FscryptKeyV1::DropCachesIfNeed()
398 {
399 int fd = open(MNT_DATA.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
400 if (fd < 0 || syncfs(fd)) {
401 sync();
402 }
403 LOGI("drop cache start.");
404 if (!SaveStringToFile("/proc/sys/vm/drop_caches", "2")) {
405 LOGE("Failed to drop cache during key eviction");
406 }
407 (void)close(fd);
408 LOGI("drop cache success");
409 }
410
LockUserScreen(uint32_t flag,uint32_t sdpClass,const std::string & mnt)411 bool FscryptKeyV1::LockUserScreen(uint32_t flag, uint32_t sdpClass, const std::string &mnt)
412 {
413 uint32_t elType;
414 (void)mnt;
415 LOGI("enter");
416 bool ret = true;
417 if (!fscryptV1Ext.LockUserScreenExt(flag, elType)) {
418 LOGE("fscryptV1Ext InactiveKeyExt failed");
419 ret = false;
420 }
421 if (elType == TYPE_EL4) {
422 if (!UninstallKeyToKeyring()) {
423 LOGE("UninstallKeyToKeyring failed");
424 ret = false;
425 }
426 }
427 LOGI("finish");
428 return ret;
429 }
430
LockUece(bool & isFbeSupport)431 bool FscryptKeyV1::LockUece(bool &isFbeSupport)
432 {
433 LOGI("enter");
434 bool ret = true;
435 if (!fscryptV1Ext.LockUeceExt(isFbeSupport)) {
436 LOGE("fscryptV1Ext InactiveKeyExt failed");
437 ret = false;
438 }
439 LOGI("finish");
440 return ret;
441 }
442
UninstallKeyToKeyring()443 bool FscryptKeyV1::UninstallKeyToKeyring()
444 {
445 if (keyInfo_.keyDesc.IsEmpty()) {
446 LOGE("keyDesc is null, key not installed?");
447 return false;
448 }
449
450 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
451 if (krid == -1) {
452 LOGE("Error searching session keyring for fscrypt-provisioning key for fscrypt");
453 return false;
454 }
455 for (auto prefix : CRYPTO_NAME_PREFIXES) {
456 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
457 key_serial_t ks = KeyCtrlSearch(krid, "logon", keyref.c_str(), 0);
458 if (KeyCtrlUnlink(ks, krid) != 0) {
459 LOGE("Failed to unlink key !");
460 }
461 }
462 LOGI("success");
463 return true;
464 }
465
GenerateKeyDesc()466 bool FscryptKeyV1::GenerateKeyDesc()
467 {
468 if (keyInfo_.key.IsEmpty()) {
469 LOGE("key is empty");
470 return false;
471 }
472 SHA512_CTX c;
473
474 SHA512_Init(&c);
475 SHA512_Update(&c, keyInfo_.key.data.get(), keyInfo_.key.size);
476 uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
477 SHA512_Final(keyRef1, &c);
478
479 SHA512_Init(&c);
480 SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
481 uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
482 SHA512_Final(keyRef2, &c);
483
484 static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
485 keyInfo_.keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
486 auto err = memcpy_s(keyInfo_.keyDesc.data.get(), keyInfo_.keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
487 if (err != EOK) {
488 LOGE("memcpy failed ret %{public}d", err);
489 return false;
490 }
491 return true;
492 }
493
GenerateAppKeyDesc(KeyBlob appKey)494 bool FscryptKeyV1::GenerateAppKeyDesc(KeyBlob appKey)
495 {
496 if (appKey.IsEmpty()) {
497 LOGE("key is empty");
498 return false;
499 }
500 SHA512_CTX c;
501 SHA512_Init(&c);
502 SHA512_Update(&c, appKey.data.get(), appKey.size - 1);
503 uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
504 SHA512_Final(keyRef1, &c);
505
506 SHA512_Init(&c);
507 SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
508 uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
509 SHA512_Final(keyRef2, &c);
510
511 static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
512 keyInfo_.keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
513 auto err = memcpy_s(keyInfo_.keyDesc.data.get(), keyInfo_.keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
514 if (err != EOK) {
515 LOGE("memcpy failed ret %{public}d", err);
516 return false;
517 }
518 LOGE("GenerateAppKeyDesc keyDesc : %{private}s", keyInfo_.keyDesc.ToString().c_str());
519 return true;
520 }
521 } // namespace StorageDaemon
522 } // namespace OHOS
523