• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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