1 /*
2 * Copyright (C) 2021 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 #include "key_ctrl.h"
16
17 #include <vector>
18 #include <map>
19 #include <sys/syscall.h>
20 #include <cerrno>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <unistd.h>
24 #include <linux/fs.h>
25 #include <linux/keyctl.h>
26
27 #include "storage_service_log.h"
28 #include "securec.h"
29 #include "file_ex.h"
30 #include "string_ex.h"
31 #include "parameter.h"
32
33 namespace {
34 constexpr uint32_t INDEX_FSCRYPT_VERSION = 0;
35 constexpr uint32_t INDEX_FSCRYPT_FILENAME = 1;
36 constexpr uint32_t INDEX_FSCRYPT_CONTENT = 2;
37 }
38
39 namespace OHOS {
40 namespace StorageDaemon {
41 struct EncryptPolicy g_policyOption = DEFAULT_POLICY;
42 bool g_fscryptEnable = false;
43 const std::string FSCRYPT_POLICY_KEY = "fscrypt.policy.config";
44 constexpr uint32_t FSCRYPT_POLICY_BUFFER_SIZE = 100;
45
AddKey(const std::string & type,const std::string & description,const key_serial_t ringId)46 key_serial_t KeyCtrl::AddKey(const std::string &type, const std::string &description, const key_serial_t ringId)
47 {
48 return syscall(__NR_add_key, type.c_str(), description.c_str(), nullptr, 0, ringId);
49 }
AddKey(const std::string & type,const std::string & description,fscrypt_key & fsKey,const key_serial_t ringId)50 key_serial_t KeyCtrl::AddKey(const std::string &type, const std::string &description, fscrypt_key &fsKey,
51 const key_serial_t ringId)
52 {
53 return syscall(__NR_add_key, type.c_str(), description.c_str(), static_cast<void *>(&fsKey), sizeof(fsKey),
54 ringId);
55 }
56
GetKeyring(key_serial_t id,int create)57 key_serial_t KeyCtrl::GetKeyring(key_serial_t id, int create)
58 {
59 return syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, id, create);
60 }
61
Revoke(key_serial_t id)62 long KeyCtrl::Revoke(key_serial_t id)
63 {
64 return syscall(__NR_keyctl, KEYCTL_REVOKE, id);
65 }
66
Search(key_serial_t ringId,const std::string & type,const std::string & description,key_serial_t destRingId)67 long KeyCtrl::Search(key_serial_t ringId, const std::string &type, const std::string &description,
68 key_serial_t destRingId)
69 {
70 return syscall(__NR_keyctl, KEYCTL_SEARCH, ringId, type.data(), description.data(), destRingId);
71 }
72
SetPermission(key_serial_t id,int permissions)73 long KeyCtrl::SetPermission(key_serial_t id, int permissions)
74 {
75 return syscall(__NR_keyctl, KEYCTL_SETPERM, id, permissions);
76 }
77
Unlink(key_serial_t key,key_serial_t keyring)78 long KeyCtrl::Unlink(key_serial_t key, key_serial_t keyring)
79 {
80 return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
81 }
82
RestrictKeyring(key_serial_t keyring,const std::string & type,const std::string & restriction)83 long KeyCtrl::RestrictKeyring(key_serial_t keyring, const std::string &type, const std::string &restriction)
84 {
85 return syscall(__NR_keyctl, KEYCTL_RESTRICT_KEYRING, keyring, type.data(), restriction.data());
86 }
87
GetSecurity(key_serial_t id,std::string & buffer)88 long KeyCtrl::GetSecurity(key_serial_t id, std::string &buffer)
89 {
90 return syscall(__NR_keyctl, KEYCTL_GET_SECURITY, id, buffer.data(), buffer.length());
91 }
92
CheckRealPath(const std::string & path)93 std::string CheckRealPath(const std::string &path)
94 {
95 std::string realp(PATH_MAX + 1, '\0');
96 if (path.length() > PATH_MAX || realpath(path.c_str(), realp.data()) == nullptr) {
97 LOGE("realpath failed, path: %{public}s, errno: %{public}d", path.c_str(), errno);
98 return "";
99 }
100 return realp;
101 }
102
FsIoctl(const std::string & mnt,unsigned long cmd,void * arg)103 bool FsIoctl(const std::string &mnt, unsigned long cmd, void *arg)
104 {
105 std::string realp = CheckRealPath(mnt);
106 int fd = open(realp.c_str(), O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
107 if (fd < 0) {
108 LOGE("open %{public}s failed, errno:%{public}d", realp.c_str(), errno);
109 return false;
110 }
111 if (ioctl(fd, cmd, arg) != 0) {
112 LOGE("ioctl to %{public}s failed, errno:%{public}d", realp.c_str(), errno);
113 close(fd);
114 return false;
115 }
116 close(fd);
117 LOGD("success");
118 return true;
119 }
120
InstallKey(const std::string & mnt,fscrypt_add_key_arg & arg)121 bool KeyCtrl::InstallKey(const std::string &mnt, fscrypt_add_key_arg &arg)
122 {
123 LOGD("enter");
124 return FsIoctl(mnt, FS_IOC_ADD_ENCRYPTION_KEY, reinterpret_cast<void *>(&arg));
125 }
126
RemoveKey(const std::string & mnt,fscrypt_remove_key_arg & arg)127 bool KeyCtrl::RemoveKey(const std::string &mnt, fscrypt_remove_key_arg &arg)
128 {
129 LOGD("enter");
130 return FsIoctl(mnt, FS_IOC_REMOVE_ENCRYPTION_KEY, reinterpret_cast<void *>(&arg));
131 }
132
GetKeyStatus(const std::string & mnt,fscrypt_get_key_status_arg & arg)133 bool KeyCtrl::GetKeyStatus(const std::string &mnt, fscrypt_get_key_status_arg &arg)
134 {
135 LOGD("enter");
136 return FsIoctl(mnt, FS_IOC_GET_ENCRYPTION_KEY_STATUS, reinterpret_cast<void *>(&arg));
137 }
138
SetPolicy(const std::string & path,FscryptPolicy & policy)139 bool KeyCtrl::SetPolicy(const std::string &path, FscryptPolicy &policy)
140 {
141 LOGD("enter");
142 return FsIoctl(path, FS_IOC_SET_ENCRYPTION_POLICY, reinterpret_cast<void *>(&policy));
143 }
144
GetPolicy(const std::string & path,fscrypt_policy & policy)145 bool KeyCtrl::GetPolicy(const std::string &path, fscrypt_policy &policy)
146 {
147 LOGD("enter");
148 return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY, reinterpret_cast<void *>(&policy));
149 }
150
GetPolicy(const std::string & path,fscrypt_get_policy_ex_arg & policy)151 bool KeyCtrl::GetPolicy(const std::string &path, fscrypt_get_policy_ex_arg &policy)
152 {
153 LOGD("enter");
154 return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY_EX, reinterpret_cast<void *>(&policy));
155 }
156
ParseOption(const std::map<std::string,uint8_t> & policy,const std::string & option,uint8_t & value)157 static bool ParseOption(const std::map<std::string, uint8_t> &policy, const std::string &option, uint8_t &value)
158 {
159 if (policy.find(option) != policy.end()) {
160 LOGI("use option: %{public}s", option.c_str());
161 value = policy.at(option);
162 return true;
163 }
164
165 LOGE("bad option: %{public}s, value not filled!", option.c_str());
166 return false;
167 }
168
SetPolicyLegacy(const std::string & keyDescPath,const std::string & toEncrypt,FscryptPolicy & arg)169 static bool SetPolicyLegacy(const std::string &keyDescPath, const std::string &toEncrypt, FscryptPolicy &arg)
170 {
171 std::string keyDesc;
172 if (OHOS::LoadStringFromFile(keyDescPath, keyDesc) == false || keyDesc.length() != FSCRYPT_KEY_DESCRIPTOR_SIZE) {
173 LOGE("bad key_desc file content, length=%{public}u", static_cast<uint32_t>(keyDesc.length()));
174 return false;
175 }
176
177 arg.v1.version = FSCRYPT_POLICY_V1;
178 auto ret = memcpy_s(arg.v1.master_key_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE, keyDesc.data(),
179 keyDesc.length());
180 if (ret) {
181 LOGE("memcpy_s failed ret %{public}d", ret);
182 return false;
183 }
184 return KeyCtrl::SetPolicy(toEncrypt, arg);
185 }
186
SetPolicyV2(const std::string & keyIdPath,const std::string & toEncrypt,FscryptPolicy & arg)187 static bool SetPolicyV2(const std::string &keyIdPath, const std::string &toEncrypt, FscryptPolicy &arg)
188 {
189 std::string keyId;
190 if (OHOS::LoadStringFromFile(keyIdPath, keyId) == false || keyId.length() != FSCRYPT_KEY_IDENTIFIER_SIZE) {
191 LOGE("bad key_id file content, length=%{public}u", static_cast<uint32_t>(keyId.length()));
192 return false;
193 }
194
195 arg.v2.version = FSCRYPT_POLICY_V2;
196 (void)memcpy_s(arg.v2.master_key_identifier, FSCRYPT_KEY_IDENTIFIER_SIZE, keyId.data(), keyId.length());
197 return KeyCtrl::SetPolicy(toEncrypt, arg);
198 }
199
LoadAndSetPolicy(const std::string & keyPath,const std::string & toEncrypt)200 bool KeyCtrl::LoadAndSetPolicy(const std::string &keyPath, const std::string &toEncrypt)
201 {
202 LOGD("enter");
203
204 FscryptPolicy arg;
205 (void)memset_s(&arg, sizeof(arg), 0, sizeof(arg));
206 // the modes and flags shares the same offset in the struct
207 ParseOption(FILENAME_MODES, g_policyOption.fileName, arg.v1.filenames_encryption_mode);
208 ParseOption(CONTENTS_MODES, g_policyOption.content, arg.v1.contents_encryption_mode);
209 ParseOption(POLICY_FLAGS, g_policyOption.flags, arg.v1.flags);
210
211 auto ver = LoadVersion(keyPath);
212 if (ver == FSCRYPT_V1) {
213 return SetPolicyLegacy(keyPath + PATH_KEYDESC, toEncrypt, arg);
214 } else if (ver == FSCRYPT_V2) {
215 return SetPolicyV2(keyPath + PATH_KEYID, toEncrypt, arg);
216 }
217 LOGE("SetPolicy fail, unknown version");
218 return false;
219 }
220
LoadVersion(const std::string & keyPath)221 uint8_t KeyCtrl::LoadVersion(const std::string &keyPath)
222 {
223 std::string buf;
224 int ver = 0;
225 auto path = keyPath + PATH_FSCRYPT_VER;
226 if (!OHOS::LoadStringFromFile(path, buf)) {
227 LOGE("load version from %{public}s failed", path.c_str());
228 return FSCRYPT_INVALID;
229 }
230 if (IsNumericStr(buf) && StrToInt(buf, ver) && (ver == FSCRYPT_V1 || ver == FSCRYPT_V2)) {
231 LOGD("version %{public}d loaded", ver);
232 return ver;
233 }
234
235 LOGE("bad version content: %{public}s", buf.c_str());
236 return FSCRYPT_INVALID;
237 }
238
CheckKernelFscrypt(const std::string & mnt)239 static uint8_t CheckKernelFscrypt(const std::string &mnt)
240 {
241 std::string realp = CheckRealPath(mnt);
242 int fd = open(realp.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
243 if (fd < 0) {
244 LOGE("open %{public}s failed, errno: %{public}d", realp.c_str(), errno);
245 return FSCRYPT_INVALID;
246 }
247
248 errno = 0;
249 (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, nullptr);
250 close(fd);
251 if (errno == EOPNOTSUPP) {
252 LOGE("Kernel doesn't support fscrypt v1 or v2.");
253 return FSCRYPT_INVALID;
254 } else if (errno == ENOTTY) {
255 LOGE("Kernel doesn't support fscrypt v2, pls use v1.");
256 return FSCRYPT_V1;
257 } else if (errno == EFAULT) {
258 LOGI("Kernel is support fscrypt v2.");
259 return FSCRYPT_V2;
260 }
261 LOGW("Unexpected errno: %{public}d", errno);
262 return FSCRYPT_INVALID;
263 }
264
GetFscryptVersion(const std::string & mnt)265 uint8_t KeyCtrl::GetFscryptVersion(const std::string &mnt)
266 {
267 static auto version = CheckKernelFscrypt(mnt);
268 return version;
269 }
270
GetEncryptedVersion(const std::string & dir)271 uint8_t KeyCtrl::GetEncryptedVersion(const std::string &dir)
272 {
273 std::string realp = CheckRealPath(dir);
274 int fd = open(realp.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC);
275 if (fd < 0) {
276 LOGE("open %{public}s failed, errno:%{public}d", realp.c_str(), errno);
277 return FSCRYPT_INVALID;
278 }
279
280 fscrypt_policy_v1 policy;
281 if (ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) == 0) {
282 LOGI("%{public}s is encrypted with v1 policy", realp.c_str());
283 close(fd);
284 return FSCRYPT_V1;
285 }
286 close(fd);
287
288 if (errno == EINVAL) {
289 LOGI("%{public}s is encrypted with v2 policy", realp.c_str());
290 return FSCRYPT_V2;
291 } else if (errno == ENODATA) {
292 LOGI("%{public}s is not encrypted", realp.c_str());
293 } else {
294 LOGE("%{public}s unexpected errno: %{public}d", realp.c_str(), errno);
295 }
296 return FSCRYPT_INVALID;
297 }
298
InitFscryptPolicy()299 int32_t KeyCtrl::InitFscryptPolicy()
300 {
301 LOGD("enter");
302 char tmp[FSCRYPT_POLICY_BUFFER_SIZE] = { 0 };
303 int ret = GetParameter(FSCRYPT_POLICY_KEY.c_str(), "", tmp, FSCRYPT_POLICY_BUFFER_SIZE);
304 if (ret < 0) {
305 LOGI("fscrypt config parameter not set, not enable fscrypt");
306 g_fscryptEnable = false;
307 return -ENOTSUP;
308 }
309
310 std::string config(tmp);
311 std::vector<std::string> strs;
312 std::string sep = ":";
313 LOGI("enable fscrypt policy from config: %{public}s", config.c_str());
314 SplitStr(config, sep, strs, false, false);
315 if (strs.size() != FSCRYPT_OPTIONS_TABLE.size()) {
316 LOGI("bad policy size, just use the default policy");
317 g_fscryptEnable = true;
318 g_policyOption = DEFAULT_POLICY;
319 return 0;
320 }
321
322 for (size_t index = 0; index < strs.size(); index++) {
323 auto item = FSCRYPT_OPTIONS_TABLE[index];
324 if (item.find(strs[index]) == item.end()) {
325 LOGI("bad policy option %{public}s, just use the default policy", strs[index].c_str());
326 g_fscryptEnable = true;
327 g_policyOption = DEFAULT_POLICY;
328 return 0;
329 }
330 }
331 g_policyOption.version = strs[INDEX_FSCRYPT_VERSION];
332 g_policyOption.fileName = strs[INDEX_FSCRYPT_FILENAME];
333 g_policyOption.content = strs[INDEX_FSCRYPT_CONTENT];
334 g_fscryptEnable = true;
335 LOGI("fscrypt policy init success");
336
337 return 0;
338 }
339
SetFscryptSyspara(const std::string & config)340 int32_t KeyCtrl::SetFscryptSyspara(const std::string &config)
341 {
342 LOGD("start set parameter: %{public}s", config.c_str());
343 std::vector<std::string> strs;
344 std::string sep = ":";
345 SplitStr(config, sep, strs, false, false);
346 if (strs.size() != FSCRYPT_OPTIONS_TABLE.size()) {
347 LOGE("bad policy size, not to set the parameter");
348 return -EINVAL;
349 }
350
351 for (size_t index = 0; index < strs.size(); index++) {
352 auto item = FSCRYPT_OPTIONS_TABLE[index];
353 if (item.find(strs[index]) == item.end()) {
354 LOGE("bad policy option %{public}s, not to set the parameter", strs[index].c_str());
355 return -EINVAL;
356 }
357 }
358
359 int ret = SetParameter(FSCRYPT_POLICY_KEY.c_str(), config.c_str());
360 if (ret < 0) {
361 LOGE("SetParameter failed ret = %{public}d", ret);
362 return -ENOTSUP;
363 }
364 LOGI("fscrypt config parameter set success");
365
366 return 0;
367 }
368
HasFscryptSyspara()369 bool KeyCtrl::HasFscryptSyspara()
370 {
371 LOGD("enter");
372 char tmp[FSCRYPT_POLICY_BUFFER_SIZE] = { 0 };
373 int ret = GetParameter(FSCRYPT_POLICY_KEY.c_str(), "", tmp, FSCRYPT_POLICY_BUFFER_SIZE);
374 if (ret <= 0) {
375 LOGD("fscrypt config parameter not set, not enable fscrypt");
376 return false;
377 }
378
379 return true;
380 }
381 } // namespace StorageDaemon
382 } // namespace OHOS
383