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