1 /*
2  * Copyright (c) 2023 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_lite_api_common.h"
17 #include "hks_lite_api.h"
18 #include "hks_log.h"
19 #include "hks_errcode_adapter.h"
20 #include "jsi.h"
21 #include "jsi_types.h"
22 #include "js_app_context.h"
23 
24 #include "hks_api.h"
25 #include "hks_param.h"
26 #include "hks_template.h"
27 #include "hks_type_inner.h"
28 
29 #include "securec.h"
30 
31 #include <cstring>
32 #include <vector>
33 
34 namespace OHOS {
35 namespace ACELite {
36 #define RELEASE_JSI_VALUE_IF_NOT_NULL(jsiValue) \
37 do { \
38     if ((jsiValue) != nullptr) { \
39         JSI::ReleaseValue(jsiValue); \
40         jsiValue = nullptr; \
41     } \
42 } while (0)
43 
44 #define RELEASE_JSI_STRING_IF_NOT_NULL(jsiString) \
45 do { \
46     if ((jsiString) != nullptr) { \
47         JSI::ReleaseString(jsiString); \
48         jsiString = nullptr; \
49     } \
50 } while (0)
51 
CheckIsNumberAndAssignIntParam(const JSIValue paramProperty,uint32_t paramTag,struct HksParam * outParam)52 static int32_t CheckIsNumberAndAssignIntParam(const JSIValue paramProperty, uint32_t paramTag,
53     struct HksParam *outParam)
54 {
55     int32_t ret = HKS_ERROR_INVALID_ARGUMENT;
56     JSIValue valueJSIValue = JSI::GetNamedProperty(paramProperty, HKS_PARAM_PROPERTY_VALUE);
57     if (JSI::ValueIsNumber(valueJSIValue)) {
58         int32_t paramValue = (int32_t)JSI::ValueToNumber(valueJSIValue);
59         outParam->tag = paramTag;
60         outParam->int32Param = paramValue;
61         ret = HKS_SUCCESS;
62     }
63     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
64     return ret;
65 }
66 
CheckIsNumberAndAssignUintParam(const JSIValue paramProperty,uint32_t paramTag,struct HksParam * outParam)67 static int32_t CheckIsNumberAndAssignUintParam(const JSIValue paramProperty, uint32_t paramTag,
68     struct HksParam *outParam)
69 {
70     int32_t ret = HKS_ERROR_INVALID_ARGUMENT;
71     JSIValue valueJSIValue = JSI::GetNamedProperty(paramProperty, HKS_PARAM_PROPERTY_VALUE);
72     if (JSI::ValueIsNumber(valueJSIValue)) {
73         uint32_t paramValue = (uint32_t)JSI::ValueToNumber(valueJSIValue);
74         outParam->tag = paramTag;
75         outParam->uint32Param = paramValue;
76         ret = HKS_SUCCESS;
77     }
78     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
79     return ret;
80 }
81 
CheckIsNumberAndAssignUlongParam(const JSIValue paramProperty,uint32_t paramTag,struct HksParam * outParam)82 static int32_t CheckIsNumberAndAssignUlongParam(const JSIValue paramProperty, uint32_t paramTag,
83     struct HksParam *outParam)
84 {
85     int32_t ret = HKS_ERROR_INVALID_ARGUMENT;
86     JSIValue valueJSIValue = JSI::GetNamedProperty(paramProperty, HKS_PARAM_PROPERTY_VALUE);
87     if (JSI::ValueIsNumber(valueJSIValue)) {
88         uint64_t paramValue = (uint64_t)JSI::ValueToNumber(valueJSIValue);
89         outParam->tag = paramTag;
90         outParam->uint64Param = paramValue;
91         ret = HKS_SUCCESS;
92     }
93     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
94     return ret;
95 }
96 
CheckIsBoolAndAssignBoolParam(const JSIValue paramProperty,uint32_t paramTag,struct HksParam * outParam)97 static int32_t CheckIsBoolAndAssignBoolParam(const JSIValue paramProperty, uint32_t paramTag,
98     struct HksParam *outParam)
99 {
100     int32_t ret = HKS_ERROR_INVALID_ARGUMENT;
101     JSIValue valueJSIValue = JSI::GetNamedProperty(paramProperty, HKS_PARAM_PROPERTY_VALUE);
102     if (JSI::ValueIsBoolean(valueJSIValue)) {
103         bool paramValue = (bool)JSI::ValueToBoolean(valueJSIValue);
104         outParam->tag = paramTag;
105         outParam->boolParam = paramValue;
106         ret = HKS_SUCCESS;
107     }
108     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
109     return ret;
110 }
111 
ParseUint8ArrayToHksBlob(JSIValue value,struct HksBlob * outData)112 static int32_t ParseUint8ArrayToHksBlob(JSIValue value, struct HksBlob *outData)
113 {
114     if (!JSI::ValueIsTypedArray(value)) {
115         HKS_LOG_E("value is not a typed array");
116         return HKS_ERROR_INVALID_ARGUMENT;
117     }
118     TypedArrayType arrayType;
119     size_t arraySize = 0;
120     size_t byteOffset = 0;
121     JSIValue arrayBuffer;
122     uint8_t *dataArray;
123     int32_t ret = HKS_SUCCESS;
124     do {
125         dataArray = JSI::GetTypedArrayInfo(value, arrayType, arraySize, arrayBuffer, byteOffset);
126         if (dataArray == nullptr) {
127             ret = HKS_FAILURE;
128             break;
129         }
130         if (arrayType != TypedArrayType::JSI_UINT8_ARRAY) {
131             HKS_LOG_E("value is not a uint8 array");
132             ret = HKS_ERROR_INVALID_ARGUMENT;
133             break;
134         }
135         outData->data = (uint8_t *)HksMalloc(arraySize);
136         if (outData->data == nullptr) {
137             ret = HKS_ERROR_MALLOC_FAIL;
138             break;
139         }
140         memcpy_s(outData->data, arraySize, dataArray + byteOffset, arraySize);
141         outData->size = arraySize;
142     } while (0);
143     RELEASE_JSI_VALUE_IF_NOT_NULL(arrayBuffer);
144     return ret;
145 }
146 
CheckIsBytesAndAssignBlobParam(const JSIValue paramProperty,uint32_t paramTag,struct HksParam * outParam)147 static int32_t CheckIsBytesAndAssignBlobParam(const JSIValue paramProperty, uint32_t paramTag,
148     struct HksParam *outParam)
149 {
150     int32_t ret = HKS_ERROR_INVALID_ARGUMENT;
151     JSIValue valueJSIValue = JSI::GetNamedProperty(paramProperty, HKS_PARAM_PROPERTY_VALUE);
152     do {
153         if (!JSI::ValueIsTypedArray(valueJSIValue)) {
154             HKS_LOG_E("value is not array");
155             ret = HKS_ERROR_INVALID_ARGUMENT;
156             break;
157         }
158         ret = ParseUint8ArrayToHksBlob(valueJSIValue, &(outParam->blob));
159         outParam->tag = paramTag;
160     } while (0);
161     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
162     return ret;
163 }
164 
HksParseParam(const JSIValue paramProperty,struct HksParam * outParam)165 static int32_t HksParseParam(const JSIValue paramProperty, struct HksParam *outParam)
166 {
167     uint32_t paramTag = (uint32_t)JSI::GetNumberProperty(paramProperty, HKS_PARAM_PROPERTY_TAG);
168     int32_t ret;
169     switch (paramTag & HKS_TAG_TYPE_MASK) {
170         case HKS_TAG_TYPE_INT:
171             ret = CheckIsNumberAndAssignIntParam(paramProperty, paramTag, outParam);
172             break;
173         case HKS_TAG_TYPE_UINT:
174             ret = CheckIsNumberAndAssignUintParam(paramProperty, paramTag, outParam);
175             break;
176         case HKS_TAG_TYPE_ULONG:
177             ret = CheckIsNumberAndAssignUlongParam(paramProperty, paramTag, outParam);
178             break;
179         case HKS_TAG_TYPE_BOOL:
180             ret = CheckIsBoolAndAssignBoolParam(paramProperty, paramTag, outParam);
181             break;
182         case HKS_TAG_TYPE_BYTES:
183             ret = CheckIsBytesAndAssignBlobParam(paramProperty, paramTag, outParam);
184             break;
185         default:
186             HKS_LOG_E("invalid tag value 0x%" LOG_PUBLIC "x", paramTag);
187             ret = HKS_ERROR_INVALID_ARGUMENT;
188             break;
189     }
190     return ret;
191 }
192 
HksParseParamsToVector(const JSIValue paramSetValue,std::vector<HksParam> & params)193 static int32_t HksParseParamsToVector(const JSIValue paramSetValue, std::vector<HksParam> &params)
194 {
195     int32_t ret = HKS_SUCCESS;
196     do {
197         if (!JSI::ValueIsArray(paramSetValue)) {
198             ret = HKS_ERROR_INVALID_ARGUMENT;
199             break;
200         }
201         uint32_t paramCnt = JSI::GetArrayLength(paramSetValue);
202         if (paramCnt == 0) {
203             break;
204         }
205         for (uint32_t i = 0; i < paramCnt; ++i) {
206             JSIValue paramProperty = JSI::GetPropertyByIndex(paramSetValue, i);
207             struct HksParam param = { 0 };
208             ret = HksParseParam(paramProperty, &param);
209             if (ret != HKS_SUCCESS) {
210                 RELEASE_JSI_VALUE_IF_NOT_NULL(paramProperty);
211                 break;
212             }
213             params.push_back(param);
214             RELEASE_JSI_VALUE_IF_NOT_NULL(paramProperty);
215         }
216     } while (0);
217     return ret;
218 }
219 
HksReleaseParamVectors(std::vector<HksParam> & params)220 static void HksReleaseParamVectors(std::vector<HksParam> &params)
221 {
222     struct HksParam *param = params.data();
223     size_t paramCount = params.size();
224     if (param == nullptr) {
225         return;
226     }
227     while (paramCount > 0) {
228         paramCount--;
229         if ((param->tag & HKS_TAG_TYPE_MASK) == HKS_TAG_TYPE_BYTES) {
230             HKS_FREE(param->blob.data);
231             param->blob.size = 0;
232         }
233         ++param;
234     }
235 }
236 
HksParseParamsToParamSet(const std::vector<HksParam> & paramsVector,struct HksParamSet ** outParamSet)237 static int32_t HksParseParamsToParamSet(const std::vector<HksParam> &paramsVector, struct HksParamSet **outParamSet)
238 {
239     int32_t ret;
240     struct HksParamSet *paramSet = nullptr;
241     do {
242         ret = HksInitParamSet(&paramSet);
243         HKS_IF_NOT_SUCC_BREAK(ret)
244         for (auto &param : paramsVector) {
245             ret = HksAddParams(paramSet, &param, 1);
246             if (ret != HKS_SUCCESS) {
247                 HKS_LOG_E("add param.tag[%" LOG_PUBLIC "u] failed", param.tag);
248                 break;
249             }
250         }
251         ret = HksBuildParamSet(&paramSet);
252         *outParamSet = paramSet;
253     } while (0);
254     if (ret != HKS_SUCCESS) {
255         HksFreeParamSet(&paramSet);
256     }
257     return ret;
258 }
259 
GetAndPushBundleNameToVector(std::vector<HksParam> & paramsVector)260 static int32_t GetAndPushBundleNameToVector(std::vector<HksParam> &paramsVector)
261 {
262     JsAppContext *appContext = JsAppContext::GetInstance();
263     if (appContext == nullptr) {
264         HKS_LOG_E("appContext is null.");
265         return HKS_FAILURE;
266     }
267     const char *curBundleName = appContext->GetCurrentBundleName();
268     if (curBundleName == nullptr) {
269         return HKS_FAILURE;
270     }
271 
272     struct HksParam curBundleNameParam = { 0 };
273     curBundleNameParam.tag = HKS_TAG_BUNDLE_NAME;
274     curBundleNameParam.blob.data = (uint8_t *)HksMalloc(strlen(curBundleName) + 1);
275     if (curBundleNameParam.blob.data == nullptr) {
276         return HKS_ERROR_MALLOC_FAIL;
277     }
278     curBundleNameParam.blob.size = strlen(curBundleName) + 1; // the last \0 need to be counted
279 
280     (void)memcpy_s(curBundleNameParam.blob.data, strlen(curBundleName), curBundleName, strlen(curBundleName));
281     curBundleNameParam.blob.data[strlen(curBundleName)] = '\0';
282     paramsVector.push_back(curBundleNameParam);
283     return HKS_SUCCESS;
284 }
285 
HksParseParamSetWithAdd(const JSIValue * args,uint32_t index,struct HksParamSet ** outParamSet,struct HksParam * paramsToAdd,uint32_t paramsToAddSize)286 int32_t HksParseParamSetWithAdd(const JSIValue* args, uint32_t index, struct HksParamSet **outParamSet,
287     struct HksParam *paramsToAdd, uint32_t paramsToAddSize)
288 {
289     std::vector<HksParam> paramsVector;
290 
291     JSIValue paramSetValue = nullptr;
292     int32_t ret;
293     do {
294         paramSetValue = JSI::GetNamedProperty(args[index], HKS_OPTIONS_PROPERTY_PROPERTIES);
295         if (paramSetValue == nullptr) {
296             HKS_LOG_I("no properties setted, but it is tolerable");
297         } else {
298             ret = HksParseParamsToVector(paramSetValue, paramsVector);
299             if (ret != HKS_SUCCESS) {
300                 HKS_LOG_E("parse params to vector failed");
301                 break;
302             }
303         }
304 
305         ret = GetAndPushBundleNameToVector(paramsVector);
306         if (ret != HKS_SUCCESS) {
307             HKS_LOG_E("add bundle name failed");
308             break;
309         }
310 
311         if (paramsToAdd != nullptr && paramsToAddSize != 0) {
312             for (uint32_t i = 0; i < paramsToAddSize; ++i) {
313                 paramsVector.push_back(paramsToAdd[i]);
314             }
315         }
316 
317         ret = HksParseParamsToParamSet(paramsVector, outParamSet);
318     } while (0);
319     HksReleaseParamVectors(paramsVector);
320     RELEASE_JSI_VALUE_IF_NOT_NULL(paramSetValue);
321     return ret;
322 }
323 
HksParseKeyAlias(const JSIValue * args,uint32_t index,struct HksBlob * outKeyAliasBlob)324 int32_t HksParseKeyAlias(const JSIValue* args, uint32_t index, struct HksBlob *outKeyAliasBlob)
325 {
326     if (!JSI::ValueIsString(args[index])) {
327         HKS_LOG_E("keyAlias is not a string");
328         return HKS_ERROR_INVALID_ARGUMENT;
329     }
330     char *keyAlias = JSI::ValueToString(args[index]);
331     if (keyAlias == nullptr) {
332         HKS_LOG_E("convert keyAlias jsivalue to string failed");
333         return HKS_FAILURE;
334     }
335     outKeyAliasBlob->size = strlen(keyAlias);
336     outKeyAliasBlob->data = (uint8_t *)HksMalloc(outKeyAliasBlob->size);
337     if (outKeyAliasBlob->data == nullptr) {
338         RELEASE_JSI_STRING_IF_NOT_NULL(keyAlias);
339         return HKS_ERROR_MALLOC_FAIL;
340     }
341     (void)memcpy_s(outKeyAliasBlob->data, outKeyAliasBlob->size, keyAlias, outKeyAliasBlob->size);
342     RELEASE_JSI_STRING_IF_NOT_NULL(keyAlias);
343     return HKS_SUCCESS;
344 }
345 
HksParseHandle(const JSIValue * args,uint32_t index,struct HksBlob * outHandle)346 int32_t HksParseHandle(const JSIValue* args, uint32_t index, struct HksBlob *outHandle)
347 {
348     if (!JSI::ValueIsNumber(args[index])) {
349         HKS_LOG_E("handle is not a number");
350         return HKS_ERROR_INVALID_ARGUMENT;
351     }
352     uint64_t handle = (uint64_t)JSI::ValueToNumber(args[index]);
353     outHandle->data = (uint8_t *)HksMalloc(sizeof(uint64_t));
354     if (outHandle->data == nullptr) {
355         return HKS_ERROR_MALLOC_FAIL;
356     }
357     (void)memcpy_s(outHandle->data, sizeof(uint64_t), &handle, sizeof(uint64_t));
358     outHandle->size = sizeof(uint64_t);
359     return HKS_SUCCESS;
360 }
361 
HksParseInData(const JSIValue * args,uint32_t index,struct HksBlob * outInData)362 int32_t HksParseInData(const JSIValue* args, uint32_t index, struct HksBlob *outInData)
363 {
364     JSIValue valueJSIValue = JSI::GetNamedProperty(args[index], HKS_OPTIONS_PROPERTY_INDATA);
365     int32_t ret = ParseUint8ArrayToHksBlob(valueJSIValue, outInData);
366     RELEASE_JSI_VALUE_IF_NOT_NULL(valueJSIValue);
367     return ret;
368 }
369 
370 // convert from huks inner error code to jsi err
HksConvertErrorCodeToError(int32_t rawErrorCode)371 JSIValue HksConvertErrorCodeToError(int32_t rawErrorCode)
372 {
373     struct HksResult result = HksConvertErrCode(rawErrorCode);
374     JSIValue res = JSI::CreateObject();
375     JSI::SetNumberProperty(res, BUSINESS_ERROR_PROPERTY_CODE, (double)result.errorCode);
376     JSI::SetStringProperty(res, BUSINESS_ERROR_PROPERTY_MESSAGE, result.errorMsg);
377     return res;
378 }
379 
380 // HuksReturnResult, only outData is used in lite system
HksConstructJSIReturnResult(const struct HksLiteApiResult * result)381 JSIValue HksConstructJSIReturnResult(const struct HksLiteApiResult *result)
382 {
383     if (result->isBoolean) {
384         // the only possible res for result is boolean only for success case is the true
385         return JSI::CreateBoolean(true);
386     }
387     JSIValue res;
388     do {
389         res = JSI::CreateObject();
390         if (res == nullptr) {
391             break;
392         }
393         if (result->outData != nullptr) {
394             uint8_t *arrayBuffer = nullptr;
395             JSIValue buffer = JSI::CreateArrayBuffer(result->outData->size, arrayBuffer);
396             if (arrayBuffer == nullptr) {
397                 HKS_LOG_E("create jsi array buffer failed");
398                 JSI::ReleaseValue(buffer);
399                 return res;
400             }
401             (void)memcpy_s(arrayBuffer, result->outData->size, result->outData->data, result->outData->size);
402             JSIValue typedArray = JSI::CreateTypedArray(TypedArrayType::JSI_UINT8_ARRAY, result->outData->size,
403                 buffer, 0);
404             JSI::ReleaseValue(buffer);
405             JSI::SetNamedProperty(res, HKS_RESULT_PROPERTY_OUTDATA, typedArray);
406         }
407         if (result->handle != nullptr) {
408             JSI::SetNumberProperty(res, HKS_HANDLE_PROPERTY_HANDLE, *((uint64_t *)result->handle->data));
409         }
410     } while (0);
411     return res;
412 }
413 
HksCallbackResultFailure(const JSIValue thisVal,const JSIValue callback,int32_t error)414 void HksCallbackResultFailure(const JSIValue thisVal, const JSIValue callback, int32_t error)
415 {
416     JSIValue params[2] = { HksConvertErrorCodeToError(error), JSI::CreateNull()};
417     JSI::CallFunction(callback, thisVal, params, HKS_ARRAY_SIZE(params));
418     RELEASE_JSI_VALUE_IF_NOT_NULL(params[0]);
419     RELEASE_JSI_VALUE_IF_NOT_NULL(params[1]);
420 }
421 
HksCallbackResultSuccess(const JSIValue thisVal,JSIValue callback,const struct HksLiteApiResult * result)422 void HksCallbackResultSuccess(const JSIValue thisVal, JSIValue callback, const struct HksLiteApiResult *result)
423 {
424     JSIValue params[2] = { JSI::CreateNull(), HksConstructJSIReturnResult(result) };
425     JSI::CallFunction(callback, thisVal, params, HKS_ARRAY_SIZE(params));
426     RELEASE_JSI_VALUE_IF_NOT_NULL(params[0]);
427     RELEASE_JSI_VALUE_IF_NOT_NULL(params[1]);
428 }
429 
InitHuksModule(void)430 int32_t InitHuksModule(void)
431 {
432     return HksInitialize();
433 }
434 }
435 }