• 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     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