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