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