1 /*
2 * Copyright (c) 2024 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 "recover_manager.h"
17
18 #include <openssl/sha.h>
19 #include <unistd.h>
20 #include "storage_service_errno.h"
21 #include "storage_service_log.h"
22 #include "utils/storage_radar.h"
23
24 using namespace OHOS::StorageService;
25 namespace OHOS {
26 namespace StorageDaemon {
27 static const std::string CRYPTO_NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt"};
28 #ifdef RECOVER_KEY_TEE_ENVIRONMENT
29 constexpr uint32_t ELX_TYPE_ARR[] = { TYPE_GLOBAL_EL1, USERID_GLOBAL_EL1, TYPE_EL1, TYPE_EL2, TYPE_EL3, TYPE_EL4 };
30 constexpr static uint32_t TEE_PARAM_INDEX_0 = 0;
31 constexpr static uint32_t TEE_PARAM_INDEX_1 = 1;
32 constexpr static int SESSION_START_DEFAULT = 1;
33 constexpr int MAX_RETRY_COUNT = 3;
34 constexpr int RETRY_INTERVAL = 100 * 1000; // 100ms
35 #endif
36
RecoveryManager()37 RecoveryManager::RecoveryManager()
38 {
39 LOGI("enter");
40 isSessionOpened = false;
41 }
42
~RecoveryManager()43 RecoveryManager::~RecoveryManager()
44 {
45 LOGI("enter");
46 }
47
CreateRecoverKey(uint32_t userId,uint32_t userType,const std::vector<uint8_t> & token,const std::vector<uint8_t> & secret,const std::vector<KeyBlob> & originIv)48 int RecoveryManager::CreateRecoverKey(uint32_t userId,
49 uint32_t userType,
50 const std::vector<uint8_t> &token,
51 const std::vector<uint8_t> &secret,
52 const std::vector<KeyBlob> &originIv)
53 {
54 LOGI("enter");
55 #ifdef RECOVER_KEY_TEE_ENVIRONMENT
56 TEEC_Context createKeyContext = {};
57 TEEC_Session createKeySession = {};
58 if (!OpenSession(createKeyContext, createKeySession)) {
59 LOGE("Open session failed !");
60 return E_RECOVERY_KEY_OPEN_SESSION_ERR;
61 }
62 uint32_t createKeyOrigin = 0;
63 TEEC_Operation operation = { 0 };
64 operation.started = SESSION_START_DEFAULT;
65 operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
66 CreateRecoverKeyStr recoverKeyStr = { .userType = userType, .userId = userId,
67 .authTokenLen = static_cast<uint32_t>(token.size()) };
68 if (!token.empty()) {
69 auto err = memcpy_s(recoverKeyStr.authToken, AUTH_TOKEN_LEN, token.data(), token.size());
70 if (err != EOK) {
71 CloseSession(createKeyContext, createKeySession);
72 return E_MEMORY_OPERATION_ERR;
73 }
74 }
75 for (size_t i = 0; i < originIv.size(); ++i) {
76 auto err = memcpy_s(recoverKeyStr.rndToTee[i], RND_AND_KEY2_LEN, originIv[i].data.get(), originIv[i].size);
77 if (err != EOK) {
78 CloseSession(createKeyContext, createKeySession);
79 return E_MEMORY_OPERATION_ERR;
80 }
81 }
82 operation.params[TEE_PARAM_INDEX_0].tmpref.buffer = static_cast<void *>(&recoverKeyStr);
83 operation.params[TEE_PARAM_INDEX_0].tmpref.size = sizeof(recoverKeyStr);
84 TEEC_Result ret = TEEC_InvokeCommand(&createKeySession, TaCmdId::RK_CMD_ID_GEN_RECOVERY_KEY,
85 &operation, &createKeyOrigin);
86 LOGW("InvokeCmd ret: %{public}d, origin: %{public}d, token size: %{public}zu", ret, createKeyOrigin, token.size());
87 if (ret != TEEC_SUCCESS) {
88 LOGE("InvokeCmd failed, ret: %{public}d, origin: %{public}d", ret, createKeyOrigin);
89 CloseSession(createKeyContext, createKeySession);
90 std::string extraData = "cmd=RK_CMD_ID_GEN_RECOVERY_KEY,ret=" + std::to_string(ret) +
91 ",origin=" + std::to_string(createKeyOrigin);
92 StorageRadar::ReportTEEClientResult("TEEC_InvokeCommand", E_TEEC_GEN_RECOVERY_KEY_ERR, userId, extraData);
93 return E_TEEC_GEN_RECOVERY_KEY_ERR;
94 }
95 CloseSession(createKeyContext, createKeySession);
96 #endif
97 LOGI("success");
98 return 0;
99 }
100
SetRecoverKey(const std::vector<uint8_t> & key)101 int RecoveryManager::SetRecoverKey(const std::vector<uint8_t> &key)
102 {
103 #ifdef RECOVER_KEY_TEE_ENVIRONMENT
104 SetRecoverKeyStr setRecoverKeyStr;
105 int ret = SetRecoverKeyToTee(key, setRecoverKeyStr);
106 if (ret != 0) {
107 LOGE("Set recover key to tee failed !");
108 return ret;
109 }
110
111 if (sizeof(setRecoverKeyStr.key2FromTee) != sizeof(setRecoverKeyStr.rndFromTee)) {
112 LOGE("key2 size dose not match iv size !");
113 return E_PARAMS_INVALID;
114 }
115 int rndNum = sizeof(setRecoverKeyStr.rndFromTee) / RND_AND_KEY2_LEN;
116 int key2Num = sizeof(setRecoverKeyStr.key2FromTee) / RND_AND_KEY2_LEN;
117 if (rndNum != RND_AND_KEY2_NUMS || key2Num != RND_AND_KEY2_NUMS) {
118 LOGE("rnd and key2 num is not match ! rndNum: %{public}d, key2Num: %{public}d", rndNum, key2Num);
119 return E_PARAMS_INVALID;
120 }
121
122 for (int i = 0; i < rndNum; ++i) {
123 uint8_t *key2 = setRecoverKeyStr.key2FromTee[i];
124 uint8_t *originIv = setRecoverKeyStr.rndFromTee[i];
125 std::vector<uint8_t> key2Data(key2, key2 + RND_AND_KEY2_LEN);
126 std::vector<uint8_t> ivData(originIv, originIv + RND_AND_KEY2_LEN);
127 KeyBlob ivBlob(ivData);
128 KeyBlob key2Blob(key2Data);
129 KeyBlob keyDesc;
130 auto errNo = GenerateKeyDesc(ivBlob, keyDesc);
131 if (errNo != E_OK) {
132 LOGE("Generate key desc failed !");
133 return errNo;
134 }
135 ret = InstallKeyDescToKeyring(ELX_TYPE_ARR[i], key2Blob, keyDesc);
136 if (ret != E_OK) {
137 ivBlob.Clear();
138 keyDesc.Clear();
139 key2Blob.Clear();
140 LOGE("install type %{public}d to keyring failed !", ELX_TYPE_ARR[i]);
141 return ret;
142 }
143 ivBlob.Clear();
144 keyDesc.Clear();
145 key2Blob.Clear();
146 }
147 #endif
148 LOGI("succeed");
149 return 0;
150 }
151
SetRecoverKeyToTee(const std::vector<uint8_t> & key,SetRecoverKeyStr & setRecoverKeyStr)152 int RecoveryManager::SetRecoverKeyToTee(const std::vector<uint8_t> &key, SetRecoverKeyStr &setRecoverKeyStr)
153 {
154 LOGI("enter");
155 #ifdef RECOVER_KEY_TEE_ENVIRONMENT
156 TEEC_Context setKeyContext = {};
157 TEEC_Session setKeySession = {};
158 if (!OpenSession(setKeyContext, setKeySession)) {
159 LOGE("Open session failed !");
160 return E_RECOVERY_KEY_OPEN_SESSION_ERR;
161 }
162 TEEC_Operation operation = { 0 };
163 operation.started = SESSION_START_DEFAULT;
164 operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE);
165 uint32_t setKeyOrigin;
166 operation.params[TEE_PARAM_INDEX_0].tmpref.buffer = static_cast<void *>(const_cast<unsigned char *>(key.data()));
167 operation.params[TEE_PARAM_INDEX_0].tmpref.size = key.size();
168 operation.params[TEE_PARAM_INDEX_1].tmpref.buffer = static_cast<void *>(&setRecoverKeyStr);
169 operation.params[TEE_PARAM_INDEX_1].tmpref.size = sizeof(setRecoverKeyStr);
170 TEEC_Result ret = TEEC_InvokeCommand(&setKeySession, TaCmdId::RK_CMD_ID_DECRYPT_CLASS_KEY, &operation,
171 &setKeyOrigin);
172 LOGI("InvokeCmd ret: %{public}d, origin: %{public}d", ret, setKeyOrigin);
173 if (ret != TEEC_SUCCESS) {
174 LOGE("InvokeCmd failed, ret: %{public}d, origin: %{public}d", ret, setKeyOrigin);
175 CloseSession(setKeyContext, setKeySession);
176 std::string extraData = "cmd=RK_CMD_ID_DECRYPT_CLASS_KEY,ret=" + std::to_string(ret) +
177 ",origin=" + std::to_string(setKeyOrigin);
178 StorageRadar::ReportTEEClientResult("SetRecoverKeyToTee::TEEC_InvokeCommand", E_TEEC_DECRYPT_CLASS_KEY_ERR,
179 DEFAULT_USERID, extraData);
180 return E_TEEC_DECRYPT_CLASS_KEY_ERR;
181 }
182 CloseSession(setKeyContext, setKeySession);
183 #endif
184 return 0;
185 }
186
187 #ifdef RECOVER_KEY_TEE_ENVIRONMENT
OpenSession(TEEC_Context & context,TEEC_Session & session)188 bool RecoveryManager::OpenSession(TEEC_Context &context, TEEC_Session &session)
189 {
190 LOGI("enter");
191 if (isSessionOpened) {
192 LOGE("Tee session has Opened !");
193 return true;
194 }
195 TEEC_Result ret = TEEC_InitializeContext(NULL, &context);
196 if (ret != TEEC_SUCCESS) {
197 LOGE("recovery tee ctx init failed !");
198 TEEC_FinalizeContext(&context);
199 isSessionOpened = false;
200 StorageRadar::ReportTEEClientResult("OpenSession::TEEC_InitializeContext", ret, DEFAULT_USERID, "");
201 return false;
202 }
203 TEEC_Operation operation;
204 LOGI("Prepare session operation.");
205 operation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
206 if (memset_s(&operation, sizeof(TEEC_Operation), 0, sizeof(TEEC_Operation)) != EOK) {
207 LOGE("[OpenSession] memset_s failed !");
208 TEEC_FinalizeContext(&context);
209 isSessionOpened = false;
210 return false;
211 }
212 LOGI("Prepare open session.");
213 operation.started = SESSION_START_DEFAULT;
214 operation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
215 uint32_t retErr = 0;
216 uint32_t retryCount = 0;
217 while (retryCount < MAX_RETRY_COUNT) {
218 ret = TEEC_OpenSession(&context, &session, recoverUuid_, TEEC_LOGIN_IDENTIFY, nullptr, &operation, &retErr);
219 if (ret == TEEC_SUCCESS) {
220 LOGI("Open session success, has try %{public}u times.", retryCount);
221 break;
222 }
223 retryCount++;
224 LOGE("has retry %{public}d times, ret: %{public}d", retryCount, ret);
225 usleep(RETRY_INTERVAL);
226 }
227
228 if (ret != TEEC_SUCCESS) {
229 LOGE("open session failed !");
230 CloseSession(context, session);
231 StorageRadar::ReportTEEClientResult("OpenSession::TEEC_OpenSession", ret, DEFAULT_USERID, "");
232 return false;
233 }
234 isSessionOpened = true;
235 LOGI("open session success");
236 return true;
237 }
238
CloseSession(TEEC_Context & context,TEEC_Session & session)239 void RecoveryManager::CloseSession(TEEC_Context &context, TEEC_Session &session)
240 {
241 TEEC_CloseSession(&session);
242 TEEC_FinalizeContext(&context);
243 isSessionOpened = false;
244 LOGI("close session success");
245 }
246 #endif
247
GenerateKeyDesc(const KeyBlob & ivBlob,KeyBlob & keyDesc)248 int32_t RecoveryManager::GenerateKeyDesc(const KeyBlob &ivBlob, KeyBlob &keyDesc)
249 {
250 LOGI("enter");
251 if (ivBlob.IsEmpty()) {
252 LOGE("key is empty");
253 return E_KEY_BLOB_ERROR;
254 }
255 SHA512_CTX c;
256
257 SHA512_Init(&c);
258 SHA512_Update(&c, ivBlob.data.get(), ivBlob.size);
259 uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
260 SHA512_Final(keyRef1, &c);
261
262 SHA512_Init(&c);
263 SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
264 uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
265 SHA512_Final(keyRef2, &c);
266
267 static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
268 keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
269 auto err = memcpy_s(keyDesc.data.get(), keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
270 if (err != EOK) {
271 LOGE("memcpy failed ret %{public}d", err);
272 return err;
273 }
274 LOGI("succeed");
275 return E_OK;
276 }
277
InstallKeyDescToKeyring(size_t keyType,const KeyBlob & key2Blob,const KeyBlob & keyDesc)278 int32_t RecoveryManager::InstallKeyDescToKeyring(size_t keyType, const KeyBlob &key2Blob, const KeyBlob &keyDesc)
279 {
280 int ret = E_OK;
281 if (keyType == TYPE_EL3 || keyType == TYPE_EL4) {
282 uint32_t sdpClass;
283 if (keyType == TYPE_EL3) {
284 sdpClass = FSCRYPT_SDP_SECE_CLASS;
285 } else {
286 sdpClass = FSCRYPT_SDP_ECE_CLASS;
287 }
288 ret = InstallEceSece(sdpClass, key2Blob, keyDesc);
289 if (ret != E_OK) {
290 LOGE("InstallKeyDescToKeyring failed");
291 return ret;
292 }
293 } else {
294 ret = InstallDeCe(key2Blob, keyDesc);
295 if (ret != E_OK) {
296 LOGE("InstallKeyToKeyring failed");
297 return ret;
298 }
299 }
300 return E_OK;
301 }
302
303
InstallDeCe(const KeyBlob & key2Blob,const KeyBlob & keyDesc)304 int32_t RecoveryManager::InstallDeCe(const KeyBlob &key2Blob, const KeyBlob &keyDesc)
305 {
306 fscrypt_key fskey;
307 fskey.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
308 fskey.size = key2Blob.size;
309 auto err = memcpy_s(fskey.raw, FS_MAX_KEY_SIZE, key2Blob.data.get(), key2Blob.size);
310 if (err != EOK) {
311 LOGE("memcpy failed ret %{public}d", err);
312 return err;
313 }
314
315 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
316 if (krid == -1) {
317 LOGI("no session keyring for fscrypt");
318 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
319 if (krid == -1) {
320 LOGE("failed to add session keyring");
321 return E_ADD_SESSION_KEYRING_ERROR;
322 }
323 }
324 for (auto prefix : CRYPTO_NAME_PREFIXES) {
325 std::string keyref = prefix + ":" + keyDesc.ToString();
326 LOGI("InstallDeCe: prefix: %{public}s", prefix.c_str());
327 key_serial_t ks = KeyCtrlAddKeyEx("logon", keyref.c_str(), &fskey, krid);
328 if (ks == -1) {
329 // Addkey failed, need to process the error
330 LOGE("Failed to AddKey %{public}s to keyring, errno %{public}d", prefix.c_str(), errno);
331 }
332 }
333 LOGI("success");
334 return E_OK;
335 }
336
InstallEceSece(uint32_t sdpClass,const KeyBlob & key2Blob,const KeyBlob & keyDesc)337 int32_t RecoveryManager::InstallEceSece(uint32_t sdpClass, const KeyBlob &key2Blob, const KeyBlob &keyDesc)
338 {
339 EncryptionKeySdp fskey;
340 if (key2Blob.size != sizeof(fskey.raw)) {
341 LOGE("Wrong key size is %{public}d", key2Blob.size);
342 return E_KEY_BLOB_ERROR;
343 }
344 fskey.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
345 auto err = memcpy_s(fskey.raw, sizeof(fskey.raw), key2Blob.data.get(), key2Blob.size);
346 if (err != EOK) {
347 LOGE("memcpy failed ret %{public}d", err);
348 return err;
349 }
350 fskey.size = EXT4_AES_256_XTS_KEY_SIZE_TO_KEYRING;
351 fskey.sdpClass = sdpClass;
352 fskey.version = 0;
353 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
354 if (krid == -1) {
355 LOGI("no session keyring for fscrypt");
356 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
357 if (krid == -1) {
358 LOGE("failed to add session keyring");
359 return E_ADD_SESSION_KEYRING_ERROR;
360 }
361 }
362 for (auto prefix : CRYPTO_NAME_PREFIXES) {
363 std::string keyref = prefix + ":" + keyDesc.ToString();
364 key_serial_t ks = KeyCtrlAddKeySdp("logon", keyref.c_str(), &fskey, krid);
365 if (ks == -1) {
366 // Addkey failed, need to process the error
367 LOGE("Failed to AddKey %{public}s into keyring, errno %{public}d", prefix.c_str(), errno);
368 }
369 }
370 LOGI("success");
371 return E_OK;
372 }
373 } // namespace StorageDaemon
374 } // namespace HOHS