• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "libfscrypt/key_control.h"
24 #include "storage_service_log.h"
25 
26 namespace OHOS {
27 namespace StorageDaemon {
28 static const std::string CRYPTO_NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt"};
29 
ActiveKey(uint32_t flag,const std::string & mnt)30 bool FscryptKeyV1::ActiveKey(uint32_t flag, const std::string &mnt)
31 {
32     (void)mnt;
33     LOGD("enter");
34     if (!GenerateKeyDesc()) {
35         LOGE("GenerateKeyDesc failed");
36         return false;
37     }
38 
39     if (!fscryptV1Ext.ActiveKeyExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size)) {
40         LOGE("fscryptV1Ext ActiveKeyExtfailed");
41         return false;
42     }
43     if (!InstallKeyToKeyring()) {
44         LOGE("InstallKeyToKeyring failed");
45         return false;
46     }
47     LOGD("success");
48     return true;
49 }
50 
InstallKeyToKeyring()51 bool FscryptKeyV1::InstallKeyToKeyring()
52 {
53     fscrypt_key fskey;
54     fskey.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
55     fskey.size = keyInfo_.key.size;
56     auto err = memcpy_s(fskey.raw, FS_MAX_KEY_SIZE, keyInfo_.key.data.get(), keyInfo_.key.size);
57     if (err != EOK) {
58         LOGE("memcpy failed ret %{public}d", err);
59         return false;
60     }
61 
62     key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
63     if (krid == -1) {
64         LOGI("no session keyring for fscrypt");
65         krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
66         if (krid == -1) {
67             LOGE("failed to add session keyring");
68             return false;
69         }
70     }
71     for (auto prefix : CRYPTO_NAME_PREFIXES) {
72         std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
73         key_serial_t ks =
74             KeyCtrlAddKeyEx("logon", keyref.c_str(), &fskey, krid);
75         if (ks == -1) {
76             // Addkey failed, need to process the error
77             LOGE("Failed to AddKey %{public}s into keyring %{public}d, errno %{public}d", keyref.c_str(), krid,
78                 errno);
79         }
80     }
81     if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
82         return false;
83     }
84     keyInfo_.key.Clear();
85     LOGD("success");
86     return true;
87 }
88 
InactiveKey(uint32_t flag,const std::string & mnt)89 bool FscryptKeyV1::InactiveKey(uint32_t flag, const std::string &mnt)
90 {
91     (void)mnt;
92     LOGD("enter");
93     bool ret = true;
94 
95     if (!UninstallKeyToKeyring()) {
96         LOGE("UninstallKeyToKeyring failed");
97         ret = false;
98     }
99     if (!fscryptV1Ext.InactiveKeyExt(flag)) {
100         LOGE("fscryptV1Ext InactiveKeyExt failed");
101         ret = false;
102     }
103     DropCachesIfNeed();
104     LOGD("finish");
105     return ret;
106 }
107 
DropCachesIfNeed()108 void FscryptKeyV1::DropCachesIfNeed()
109 {
110     int fd = open(MNT_DATA.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
111     if (fd < 0 || syncfs(fd)) {
112         sync();
113     }
114     if (!SaveStringToFile("/proc/sys/vm/drop_caches", "2")) {
115         LOGE("Failed to drop cache during key eviction");
116     }
117     (void)close(fd);
118     LOGI("drop cache success");
119 }
120 
UninstallKeyToKeyring()121 bool FscryptKeyV1::UninstallKeyToKeyring()
122 {
123     if (keyInfo_.keyDesc.IsEmpty()) {
124         LOGE("keyDesc is null, key not installed?");
125         return false;
126     }
127 
128     key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
129     if (krid == -1) {
130         LOGE("Error searching session keyring for fscrypt-provisioning key for fscrypt");
131         return false;
132     }
133     for (auto prefix : CRYPTO_NAME_PREFIXES) {
134         std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
135         key_serial_t ks = KeyCtrlSearch(krid, "logon", keyref.c_str(), 0);
136         if (KeyCtrlUnlink(ks, krid) != 0) {
137             LOGE("Failed to unlink key with serial %{public}d ref %{public}s", krid, keyref.c_str());
138         }
139     }
140 
141     LOGD("success");
142     return true;
143 }
144 
GenerateKeyDesc()145 bool FscryptKeyV1::GenerateKeyDesc()
146 {
147     if (keyInfo_.key.IsEmpty()) {
148         LOGE("key is empty");
149         return false;
150     }
151     SHA512_CTX c;
152 
153     SHA512_Init(&c);
154     SHA512_Update(&c, keyInfo_.key.data.get(), keyInfo_.key.size);
155     uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
156     SHA512_Final(keyRef1, &c);
157 
158     SHA512_Init(&c);
159     SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
160     uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
161     SHA512_Final(keyRef2, &c);
162 
163     static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
164     keyInfo_.keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
165     auto err = memcpy_s(keyInfo_.keyDesc.data.get(), keyInfo_.keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
166     if (err != EOK) {
167         LOGE("memcpy failed ret %{public}d", err);
168         return false;
169     }
170     return true;
171 }
172 } // namespace StorageDaemon
173 } // namespace OHOS
174