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 uint32_t elType;
33 uint32_t sdpClass;
34 (void)mnt;
35 LOGD("enter");
36 if (!GenerateKeyDesc()) {
37 LOGE("GenerateKeyDesc failed");
38 return false;
39 }
40 KeyBlob keys(keyInfo_.key);
41 if (!fscryptV1Ext.ActiveKeyExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size, elType)) {
42 LOGE("fscryptV1Ext ActiveKeyExtfailed");
43 return false;
44 }
45 if (elType == TYPE_EL3 || elType == TYPE_EL4) {
46 if (elType == TYPE_EL3) {
47 sdpClass = FSCRYPT_SDP_SECE_CLASS;
48 } else {
49 sdpClass = FSCRYPT_SDP_ECE_CLASS;
50 }
51 if (!InstallEceSeceKeyToKeyring(sdpClass)) {
52 LOGE("InstallEceSeceKeyToKeyring failed");
53 return false;
54 }
55 } else {
56 if (!InstallKeyToKeyring()) {
57 LOGE("InstallKeyToKeyring failed");
58 return false;
59 }
60 }
61 keyInfo_.key = std::move(keys);
62 LOGD("success");
63 return true;
64 }
65
UnlockUserScreen(uint32_t flag,uint32_t sdpClass,const std::string & mnt)66 bool FscryptKeyV1::UnlockUserScreen(uint32_t flag, uint32_t sdpClass, const std::string &mnt)
67 {
68 (void)mnt;
69 LOGD("enter");
70 if (!GenerateKeyDesc()) {
71 LOGE("GenerateKeyDesc failed");
72 return false;
73 }
74 KeyBlob keys(keyInfo_.key);
75 if (!fscryptV1Ext.UnlockUserScreenExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size)) {
76 LOGE("fscryptV1Ext UnlockUserScreenExtfailed");
77 return false;
78 }
79 if (sdpClass == FSCRYPT_SDP_ECE_CLASS) {
80 if (!InstallEceSeceKeyToKeyring(sdpClass)) {
81 LOGE("UnlockUserScreen InstallKeyToKeyring failed");
82 return false;
83 }
84 }
85 keyInfo_.key = std::move(keys);
86 LOGD("success");
87 return true;
88 }
89
InstallKeyToKeyring()90 bool FscryptKeyV1::InstallKeyToKeyring()
91 {
92 fscrypt_key fskey;
93 fskey.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
94 fskey.size = keyInfo_.key.size;
95 auto err = memcpy_s(fskey.raw, FS_MAX_KEY_SIZE, keyInfo_.key.data.get(), keyInfo_.key.size);
96 if (err != EOK) {
97 LOGE("memcpy failed ret %{public}d", err);
98 return false;
99 }
100
101 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
102 if (krid == -1) {
103 LOGI("no session keyring for fscrypt");
104 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
105 if (krid == -1) {
106 LOGE("failed to add session keyring");
107 return false;
108 }
109 }
110 for (auto prefix : CRYPTO_NAME_PREFIXES) {
111 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
112 LOGI("InstallKeyToKeyring: keyref: %{public}s", keyref.c_str());
113 LOGI("InstallKeyToKeyring: keyref length: %{public}zu", keyref.length());
114 key_serial_t ks =
115 KeyCtrlAddKeyEx("logon", keyref.c_str(), &fskey, krid);
116 if (ks == -1) {
117 // Addkey failed, need to process the error
118 LOGE("Failed to AddKey %{public}s into keyring %{public}d, errno %{public}d", keyref.c_str(), krid,
119 errno);
120 }
121 }
122 if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
123 return false;
124 }
125 keyInfo_.key.Clear();
126 LOGD("success");
127 return true;
128 }
129
InstallEceSeceKeyToKeyring(uint32_t sdpClass)130 bool FscryptKeyV1::InstallEceSeceKeyToKeyring(uint32_t sdpClass)
131 {
132 EncryptionKeySdp fskey;
133 if (keyInfo_.key.size != sizeof(fskey.raw)) {
134 LOGE("Wrong key size is %{public}d", keyInfo_.key.size);
135 return false;
136 }
137 fskey.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
138 auto err = memcpy_s(fskey.raw, sizeof(fskey.raw), keyInfo_.key.data.get(), keyInfo_.key.size);
139 if (err != EOK) {
140 LOGE("memcpy failed ret %{public}d", err);
141 return false;
142 }
143 fskey.size = EXT4_AES_256_XTS_KEY_SIZE_TO_KEYRING;
144 fskey.sdpClass = sdpClass;
145 fskey.version = 0;
146 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
147 if (krid == -1) {
148 LOGI("no session keyring for fscrypt");
149 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
150 if (krid == -1) {
151 LOGE("failed to add session keyring");
152 return false;
153 }
154 }
155 for (auto prefix : CRYPTO_NAME_PREFIXES) {
156 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
157 key_serial_t ks =
158 KeyCtrlAddKeySdp("logon", keyref.c_str(), &fskey, krid);
159 if (ks == -1) {
160 // Addkey failed, need to process the error
161 LOGE("Failed to AddKey %{public}s into keyring %{public}d, errno %{public}d", keyref.c_str(), krid,
162 errno);
163 }
164 }
165 if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
166 return false;
167 }
168 LOGD("success");
169 return true;
170 }
171
InactiveKey(uint32_t flag,const std::string & mnt)172 bool FscryptKeyV1::InactiveKey(uint32_t flag, const std::string &mnt)
173 {
174 (void)mnt;
175 LOGD("enter");
176 bool ret = true;
177
178 if (!UninstallKeyToKeyring()) {
179 LOGE("UninstallKeyToKeyring failed");
180 ret = false;
181 }
182 if (!fscryptV1Ext.InactiveKeyExt(flag)) {
183 LOGE("fscryptV1Ext InactiveKeyExt failed");
184 ret = false;
185 }
186 DropCachesIfNeed();
187 LOGD("finish");
188 return ret;
189 }
190
DropCachesIfNeed()191 void FscryptKeyV1::DropCachesIfNeed()
192 {
193 int fd = open(MNT_DATA.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
194 if (fd < 0 || syncfs(fd)) {
195 sync();
196 }
197 if (!SaveStringToFile("/proc/sys/vm/drop_caches", "2")) {
198 LOGE("Failed to drop cache during key eviction");
199 }
200 (void)close(fd);
201 LOGI("drop cache success");
202 }
203
LockUserScreen(uint32_t flag,uint32_t sdpClass,const std::string & mnt)204 bool FscryptKeyV1::LockUserScreen(uint32_t flag, uint32_t sdpClass, const std::string &mnt)
205 {
206 uint32_t elType;
207 (void)mnt;
208 LOGD("enter");
209 bool ret = true;
210 if (!fscryptV1Ext.LockUserScreenExt(flag, elType)) {
211 LOGE("fscryptV1Ext InactiveKeyExt failed");
212 ret = false;
213 }
214 if (elType == TYPE_EL4) {
215 if (!UninstallKeyToKeyring()) {
216 LOGE("UninstallKeyToKeyring failed");
217 ret = false;
218 }
219 }
220 LOGD("finish");
221 return ret;
222 }
223
UninstallKeyToKeyring()224 bool FscryptKeyV1::UninstallKeyToKeyring()
225 {
226 if (keyInfo_.keyDesc.IsEmpty()) {
227 LOGE("keyDesc is null, key not installed?");
228 return false;
229 }
230
231 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
232 if (krid == -1) {
233 LOGE("Error searching session keyring for fscrypt-provisioning key for fscrypt");
234 return false;
235 }
236 for (auto prefix : CRYPTO_NAME_PREFIXES) {
237 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
238 key_serial_t ks = KeyCtrlSearch(krid, "logon", keyref.c_str(), 0);
239 if (KeyCtrlUnlink(ks, krid) != 0) {
240 LOGE("Failed to unlink key with serial %{public}d ref %{public}s", krid, keyref.c_str());
241 }
242 }
243
244 LOGD("success");
245 return true;
246 }
247
GenerateKeyDesc()248 bool FscryptKeyV1::GenerateKeyDesc()
249 {
250 if (keyInfo_.key.IsEmpty()) {
251 LOGE("key is empty");
252 return false;
253 }
254 SHA512_CTX c;
255
256 SHA512_Init(&c);
257 SHA512_Update(&c, keyInfo_.key.data.get(), keyInfo_.key.size);
258 uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
259 SHA512_Final(keyRef1, &c);
260
261 SHA512_Init(&c);
262 SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
263 uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
264 SHA512_Final(keyRef2, &c);
265
266 static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
267 keyInfo_.keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
268 auto err = memcpy_s(keyInfo_.keyDesc.data.get(), keyInfo_.keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
269 if (err != EOK) {
270 LOGE("memcpy failed ret %{public}d", err);
271 return false;
272 }
273 return true;
274 }
275 } // namespace StorageDaemon
276 } // namespace OHOS
277