1 /*
2 * Copyright (c) 2021-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 "hks_ipc_slice.h"
17 #include "hks_ipc_serialization.h"
18 #include "hks_log.h"
19 #include "hks_mem.h"
20 #include "hks_param.h"
21 #include "hks_request.h"
22
23 #define CMD_INIT_OFFSET 1 /* offset from base cmd to init cmd. */
24 #define CMD_UPDATE_OFFSET 2 /* offset from base cmd to update cmd. */
25 #define CMD_FINAL_OFFSET 3 /* offset from base cmd to final cmd. */
26
27 struct SliceParam {
28 uint64_t operationHandle;
29 struct HksBlob *inData;
30 struct HksBlob *outData;
31 const struct HksParamSet *paramSet;
32 };
33
IsSliceCmd(uint32_t cmdId)34 static bool IsSliceCmd(uint32_t cmdId)
35 {
36 return (cmdId == HKS_MSG_SIGN) || (cmdId == HKS_MSG_VERIFY) || (cmdId == HKS_MSG_ENCRYPT) ||
37 (cmdId == HKS_MSG_DECRYPT) || (cmdId == HKS_MSG_MAC);
38 }
39
GetBlobBufSize(const struct HksBlob * blob,uint32_t * bufSize)40 static uint32_t GetBlobBufSize(const struct HksBlob *blob, uint32_t *bufSize)
41 {
42 if (IsAdditionOverflow(blob->size, DEFAULT_ALIGN_MASK_SIZE)) {
43 return HKS_ERROR_INVALID_ARGUMENT;
44 }
45 if (IsAdditionOverflow(ALIGN_SIZE(blob->size), sizeof(blob->size))) {
46 return HKS_ERROR_INVALID_ARGUMENT;
47 }
48 *bufSize = ALIGN_SIZE(blob->size) + sizeof(blob->size);
49 return HKS_SUCCESS;
50 }
51
GetParamSize(const struct HksBlob * key,const struct HksParamSet * paramSet,uint32_t * bufSize)52 static uint32_t GetParamSize(const struct HksBlob *key, const struct HksParamSet *paramSet, uint32_t *bufSize)
53 {
54 if ((key->size > MAX_PROCESS_SIZE) || (paramSet->paramSetSize > MAX_PROCESS_SIZE)) {
55 return HKS_ERROR_INVALID_ARGUMENT;
56 }
57
58 *bufSize = ALIGN_SIZE(key->size) + sizeof(key->size) + ALIGN_SIZE(paramSet->paramSetSize);
59 return HKS_SUCCESS;
60 }
61
GetDataSize(uint32_t cmdId,const struct HksBlob * inData,const struct HksBlob * outData,uint32_t * bufSize)62 static uint32_t GetDataSize(uint32_t cmdId, const struct HksBlob *inData, const struct HksBlob *outData,
63 uint32_t *bufSize)
64 {
65 uint32_t inBuffData;
66 if (GetBlobBufSize(inData, &inBuffData) != HKS_SUCCESS) {
67 return HKS_ERROR_INVALID_ARGUMENT;
68 }
69
70 uint32_t bufOutDataSize;
71 if (cmdId == HKS_MSG_VERIFY) {
72 if (GetBlobBufSize(outData, &bufOutDataSize) != HKS_SUCCESS) {
73 return HKS_ERROR_INVALID_ARGUMENT;
74 }
75 } else {
76 bufOutDataSize = sizeof(outData->size);
77 }
78
79 if (IsAdditionOverflow(inBuffData, bufOutDataSize)) {
80 return HKS_ERROR_INVALID_ARGUMENT;
81 }
82 *bufSize = inBuffData + bufOutDataSize;
83 return HKS_SUCCESS;
84 }
85
ProcessDataOnce(uint32_t cmdId,const struct HksBlob * key,const struct HksParamSet * paramSet,struct HksBlob * inData,struct HksBlob * outData)86 static int32_t ProcessDataOnce(uint32_t cmdId, const struct HksBlob *key, const struct HksParamSet *paramSet,
87 struct HksBlob *inData, struct HksBlob *outData)
88 {
89 HKS_LOG_I("invoke ProcessOnce cmdId %u", cmdId);
90
91 uint32_t paramBufSize, dataBufSize;
92 if ((GetParamSize(key, paramSet, ¶mBufSize) != HKS_SUCCESS) ||
93 (GetDataSize(cmdId, inData, outData, &dataBufSize) != HKS_SUCCESS)) {
94 return HKS_ERROR_INVALID_ARGUMENT;
95 }
96 uint32_t totalBufSize = paramBufSize + dataBufSize;
97 uint8_t *buffer = (uint8_t *)HksMalloc(totalBufSize);
98 if (buffer == NULL) {
99 return HKS_ERROR_MALLOC_FAIL;
100 }
101 struct HksBlob ipcBlob = { totalBufSize, buffer };
102
103 uint32_t offset = 0;
104 int32_t ret = HksOnceParamPack(&ipcBlob, key, paramSet, &offset);
105 if (ret != HKS_SUCCESS) {
106 HKS_LOG_E("HksOnceParamPack fail");
107 HKS_FREE_BLOB(ipcBlob);
108 return ret;
109 }
110
111 if (cmdId == HKS_MSG_VERIFY) {
112 ret = HksOnceDataPack(&ipcBlob, inData, outData, NULL, &offset);
113 } else {
114 ret = HksOnceDataPack(&ipcBlob, inData, NULL, outData, &offset);
115 }
116 if (ret != HKS_SUCCESS) {
117 HKS_LOG_E("HksOnceDataPack fail");
118 HKS_FREE_BLOB(ipcBlob);
119 return ret;
120 }
121
122 if (cmdId == HKS_MSG_VERIFY) {
123 ret = HksSendRequest(cmdId, &ipcBlob, NULL, paramSet);
124 } else {
125 ret = HksSendRequest(cmdId, &ipcBlob, outData, paramSet);
126 }
127 HKS_FREE_BLOB(ipcBlob);
128 return ret;
129 }
130
SliceDataInit(uint32_t cmdId,const struct HksBlob * key,struct SliceParam * sliceParam)131 static int32_t SliceDataInit(uint32_t cmdId, const struct HksBlob *key, struct SliceParam *sliceParam)
132 {
133 HKS_LOG_I("ProcessInit cmdId %u", cmdId);
134
135 uint32_t bufSize;
136 if (GetParamSize(key, sliceParam->paramSet, &bufSize) != HKS_SUCCESS) {
137 return HKS_ERROR_INVALID_ARGUMENT;
138 }
139 uint8_t *buffer = (uint8_t *)HksMalloc(bufSize);
140 if (buffer == NULL) {
141 return HKS_ERROR_MALLOC_FAIL;
142 }
143
144 struct HksBlob inBlob = { bufSize, buffer };
145 struct HksBlob outBlob = { sizeof(sliceParam->operationHandle), (uint8_t *)&sliceParam->operationHandle };
146 int32_t ret = HksInitPack(&inBlob, key, sliceParam->paramSet);
147 if (ret != HKS_SUCCESS) {
148 HKS_LOG_E("HksInitPack fail");
149 HKS_FREE_BLOB(inBlob);
150 return ret;
151 }
152
153 ret = HksSendRequest(cmdId, &inBlob, &outBlob, sliceParam->paramSet);
154 HKS_FREE_BLOB(inBlob);
155 return ret;
156 }
157
GetUpdateParamSize(uint64_t operationHandle,const struct HksBlob * inData,const struct HksBlob * outData,uint32_t * bufSize)158 static int32_t GetUpdateParamSize(uint64_t operationHandle, const struct HksBlob *inData,
159 const struct HksBlob *outData, uint32_t *bufSize)
160 {
161 /* update size is guaranteed to be align */
162 *bufSize = sizeof(operationHandle) + sizeof(inData->size) + inData->size;
163 if (outData->size > 0) {
164 *bufSize += outData->size;
165 }
166 return HKS_SUCCESS;
167 }
168
SliceDataUpdate(uint32_t cmdId,struct SliceParam * sliceParam,uint32_t * outSize)169 static int32_t SliceDataUpdate(uint32_t cmdId, struct SliceParam *sliceParam, uint32_t *outSize)
170 {
171 uint32_t cnt = (sliceParam->inData->size - 1) / MAX_PROCESS_SIZE; /* inSize has been checked: greater than 0 */
172 struct HksBlob tmpInData = *(sliceParam->inData);
173 tmpInData.size = MAX_PROCESS_SIZE;
174 struct HksBlob tmpOutData = { 0, NULL };
175 if (sliceParam->outData != NULL) {
176 tmpOutData.data = sliceParam->outData->data;
177 tmpOutData.size = MAX_PROCESS_SIZE;
178 }
179
180 struct HksBlob ipcBlob = { 0, NULL };
181 if (GetUpdateParamSize(sliceParam->operationHandle, &tmpInData, &tmpOutData, &ipcBlob.size) != HKS_SUCCESS) {
182 return HKS_ERROR_INVALID_ARGUMENT;
183 }
184 ipcBlob.data = (uint8_t *)HksMalloc(ipcBlob.size);
185 if (ipcBlob.data == NULL) {
186 return HKS_ERROR_MALLOC_FAIL;
187 }
188
189 uint32_t updateSize = 0;
190 for (uint32_t i = 0; i < cnt; i++) {
191 HKS_LOG_I("ProcessUpdate cmdId %u", cmdId);
192
193 int32_t ret = HksUpdatePack(&ipcBlob, sliceParam->operationHandle, &tmpInData, &tmpOutData);
194 if (ret != HKS_SUCCESS) {
195 HKS_LOG_E("HksUpdatePack fail");
196 HKS_FREE_BLOB(ipcBlob);
197 return ret;
198 }
199
200 ret = HksSendRequest(cmdId, &ipcBlob, &tmpOutData, sliceParam->paramSet);
201 if (ret != HKS_SUCCESS) {
202 HKS_LOG_E("fail to process update");
203 HKS_FREE_BLOB(ipcBlob);
204 return HKS_ERROR_BAD_STATE;
205 }
206 tmpInData.data += MAX_PROCESS_SIZE;
207 tmpOutData.data += tmpOutData.size;
208 updateSize += MAX_PROCESS_SIZE;
209 }
210
211 sliceParam->inData->data += updateSize;
212 sliceParam->inData->size -= updateSize;
213 if ((sliceParam->outData != NULL) && (outSize != NULL)) {
214 sliceParam->outData->data += updateSize;
215 sliceParam->outData->size -= updateSize;
216 *outSize = updateSize;
217 }
218 HKS_FREE_BLOB(ipcBlob);
219 return HKS_SUCCESS;
220 }
221
GetFinalParamSize(uint32_t cmdId,uint64_t operationHandle,const struct HksBlob * inData,const struct HksBlob * outData,uint32_t * bufSize)222 static int32_t GetFinalParamSize(uint32_t cmdId, uint64_t operationHandle, const struct HksBlob *inData,
223 const struct HksBlob *outData, uint32_t *bufSize)
224 {
225 if ((inData->size > MAX_PROCESS_SIZE) || (outData->size > MAX_PROCESS_SIZE)) {
226 return HKS_ERROR_INVALID_ARGUMENT;
227 }
228
229 if (cmdId == HKS_MSG_VERIFY_FINAL) {
230 *bufSize = sizeof(operationHandle) + sizeof(inData->size) + ALIGN_SIZE(inData->size) +
231 sizeof(outData->size) + ALIGN_SIZE(outData->size);
232 } else {
233 *bufSize = sizeof(operationHandle) + sizeof(inData->size) + ALIGN_SIZE(inData->size) +
234 sizeof(outData->size);
235 }
236 return HKS_SUCCESS;
237 }
238
SliceDataFinal(uint32_t cmdId,struct SliceParam * sliceParam)239 static int32_t SliceDataFinal(uint32_t cmdId, struct SliceParam *sliceParam)
240 {
241 HKS_LOG_I("enter SliceDataFinal cmdId %u", cmdId);
242
243 struct HksBlob tmpInData = *(sliceParam->inData);
244 uint32_t bufSize;
245 if (GetFinalParamSize(cmdId, sliceParam->operationHandle, &tmpInData, sliceParam->outData,
246 &bufSize) != HKS_SUCCESS) {
247 return HKS_ERROR_INVALID_ARGUMENT;
248 }
249 uint8_t *buffer = (uint8_t *)HksMalloc(bufSize);
250 if (buffer == NULL) {
251 return HKS_ERROR_MALLOC_FAIL;
252 }
253
254 struct HksBlob ipcBlob = { bufSize, buffer };
255 int32_t ret;
256 if (cmdId == HKS_MSG_VERIFY_FINAL) {
257 ret = HksFinalPack(&ipcBlob, sliceParam->operationHandle, &tmpInData, sliceParam->outData, NULL);
258 } else {
259 ret = HksFinalPack(&ipcBlob, sliceParam->operationHandle, &tmpInData, NULL, sliceParam->outData);
260 }
261 if (ret != HKS_SUCCESS) {
262 HKS_LOG_E("HksFinalPack fail");
263 HKS_FREE_BLOB(ipcBlob);
264 return ret;
265 }
266
267 if (cmdId == HKS_MSG_VERIFY_FINAL) {
268 ret = HksSendRequest(cmdId, &ipcBlob, NULL, sliceParam->paramSet);
269 } else {
270 ret = HksSendRequest(cmdId, &ipcBlob, sliceParam->outData, sliceParam->paramSet);
271 }
272 HKS_FREE_BLOB(ipcBlob);
273 return ret;
274 }
275
SliceData(uint32_t cmdId,const struct HksBlob * key,const struct HksParamSet * paramSet,struct HksBlob * inData,struct HksBlob * outData)276 static int32_t SliceData(uint32_t cmdId, const struct HksBlob *key, const struct HksParamSet *paramSet,
277 struct HksBlob *inData, struct HksBlob *outData)
278 {
279 HKS_LOG_I("enter SliceData, cmdId %u", cmdId);
280
281 struct SliceParam sliceParam = {
282 .operationHandle = 0,
283 .inData = inData,
284 .outData = outData,
285 .paramSet = paramSet
286 };
287 int32_t ret = SliceDataInit(cmdId + CMD_INIT_OFFSET, key, &sliceParam);
288 if (ret != HKS_SUCCESS) {
289 HKS_LOG_E("SliceDataInit fail %d", ret);
290 return ret;
291 }
292
293 uint32_t outSize = 0;
294 if ((cmdId == HKS_MSG_ENCRYPT) || (cmdId == HKS_MSG_DECRYPT)) {
295 ret = SliceDataUpdate(cmdId + CMD_UPDATE_OFFSET, &sliceParam, &outSize);
296 } else {
297 sliceParam.outData = NULL;
298 ret = SliceDataUpdate(cmdId + CMD_UPDATE_OFFSET, &sliceParam, NULL);
299 sliceParam.outData = outData;
300 }
301 if (ret != HKS_SUCCESS) {
302 HKS_LOG_E("SliceDataUpdate fail %d", ret);
303 return ret;
304 }
305
306 ret = SliceDataFinal(cmdId + CMD_FINAL_OFFSET, &sliceParam);
307 if (ret != HKS_SUCCESS) {
308 HKS_LOG_E("SliceDataFinal fail %d", ret);
309 return ret;
310 }
311
312 if (IsAdditionOverflow(outData->size, outSize)) {
313 return HKS_ERROR_INVALID_ARGUMENT;
314 }
315 outData->size += outSize;
316 return ret;
317 }
318
CheckRsaMode(uint32_t cmdId,const struct HksParamSet * paramSet)319 static int32_t CheckRsaMode(uint32_t cmdId, const struct HksParamSet *paramSet)
320 {
321 if ((cmdId == HKS_MSG_ENCRYPT) || (cmdId == HKS_MSG_DECRYPT)) {
322 struct HksParam *algParam = NULL;
323 if (HksGetParam(paramSet, HKS_TAG_ALGORITHM, &algParam) != HKS_SUCCESS) {
324 HKS_LOG_E("HksGetParam failed! No algorithm tag!");
325 return HKS_ERROR_CHECK_GET_ALG_FAIL;
326 }
327 if (algParam->uint32Param == HKS_ALG_RSA) {
328 HKS_LOG_E("Slice does not support RSA encrypt!");
329 return HKS_ERROR_INVALID_ARGUMENT;
330 }
331 }
332 return HKS_SUCCESS;
333 }
334
HksSliceDataEntry(uint32_t cmdId,const struct HksBlob * key,const struct HksParamSet * paramSet,struct HksBlob * inData,struct HksBlob * outData)335 int32_t HksSliceDataEntry(uint32_t cmdId, const struct HksBlob *key, const struct HksParamSet *paramSet,
336 struct HksBlob *inData, struct HksBlob *outData)
337 {
338 if (!IsSliceCmd(cmdId)) {
339 HKS_LOG_E("cmd %u not support slice!", cmdId);
340 return HKS_ERROR_INVALID_ARGUMENT;
341 }
342
343 uint32_t paramBufSize;
344 uint32_t dataBufSize;
345 if ((GetParamSize(key, paramSet, ¶mBufSize) != HKS_SUCCESS) ||
346 (GetDataSize(cmdId, inData, outData, &dataBufSize) != HKS_SUCCESS)) {
347 return HKS_ERROR_INVALID_ARGUMENT;
348 }
349 if (IsAdditionOverflow(paramBufSize, dataBufSize)) {
350 return HKS_ERROR_INVALID_ARGUMENT;
351 }
352
353 uint32_t totalBufSize = paramBufSize + dataBufSize;
354 if (totalBufSize <= MAX_PROCESS_SIZE) {
355 return ProcessDataOnce(cmdId, key, paramSet, inData, outData);
356 }
357
358 int32_t ret = CheckRsaMode(cmdId, paramSet);
359 if (ret != HKS_SUCCESS) {
360 return ret;
361 }
362 return SliceData(cmdId, key, paramSet, inData, outData);
363 }
364