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 "huks_napi_common.h"
17
18 #include "securec.h"
19
20 #include "hks_log.h"
21 #include "hks_param.h"
22 #include "hks_type.h"
23
24 namespace HuksNapi {
25 namespace {
26 constexpr int HKS_MAX_DATA_LEN = 0x6400000; // The maximum length is 100M
27 constexpr size_t ASYNCCALLBACK_ARGC = 2;
28 } // namespace
29
ParseKeyAlias(napi_env env,napi_value object,HksBlob * & alias)30 napi_value ParseKeyAlias(napi_env env, napi_value object, HksBlob *&alias)
31 {
32 size_t length = 0;
33 napi_status status = napi_get_value_string_utf8(env, object, nullptr, 0, &length);
34 if (status != napi_ok) {
35 GET_AND_THROW_LAST_ERROR((env));
36 HKS_LOG_E("could not get string length");
37 return nullptr;
38 }
39
40 if (length > HKS_MAX_DATA_LEN) {
41 HKS_LOG_E("input key alias length too large");
42 return nullptr;
43 }
44
45 char *data = (char *)HksMalloc(length + 1);
46 if (data == nullptr) {
47 napi_throw_error(env, NULL, "could not alloc memory");
48 HKS_LOG_E("could not alloc memory");
49 return nullptr;
50 }
51 (void)memset_s(data, length + 1, 0, length + 1);
52
53 size_t result = 0;
54 status = napi_get_value_string_utf8(env, object, data, length + 1, &result);
55 if (status != napi_ok) {
56 HksFree(data);
57 GET_AND_THROW_LAST_ERROR((env));
58 HKS_LOG_E("could not get string");
59 return nullptr;
60 }
61
62 alias = (HksBlob *)HksMalloc(sizeof(HksBlob));
63 if (alias == nullptr) {
64 HksFree(data);
65 napi_throw_error(env, NULL, "could not alloc memory");
66 HKS_LOG_E("could not alloc memory");
67 return nullptr;
68 }
69 alias->data = (uint8_t *)data;
70 alias->size = (uint32_t)(length & UINT32_MAX);
71
72 return GetInt32(env, 0);
73 }
74
GetUint8Array(napi_env env,napi_value object,HksBlob & arrayBlob)75 napi_value GetUint8Array(napi_env env, napi_value object, HksBlob &arrayBlob)
76 {
77 napi_typedarray_type arrayType;
78 napi_value arrayBuffer = nullptr;
79 size_t length = 0;
80 size_t offset = 0;
81 void *rawData = nullptr;
82
83 NAPI_CALL(
84 env, napi_get_typedarray_info(env, object, &arrayType, &length, (void **)&rawData, &arrayBuffer, &offset));
85 NAPI_ASSERT(env, arrayType == napi_uint8_array, "it's not uint8 array");
86
87 if (length > HKS_MAX_DATA_LEN) {
88 HKS_LOG_E("data len is too large, len = %x", length);
89 return nullptr;
90 }
91 if (length == 0) {
92 HKS_LOG_I("the created memory length just 1 Byte");
93 // the created memory length just 1 Byte
94 arrayBlob.data = (uint8_t *)HksMalloc(1);
95 } else {
96 arrayBlob.data = (uint8_t *)HksMalloc(length);
97 }
98 if (arrayBlob.data == nullptr) {
99 return nullptr;
100 }
101 (void)memcpy_s(arrayBlob.data, length, rawData, length);
102 arrayBlob.size = (uint32_t)length;
103
104 return GetInt32(env, 0);
105 }
106
GetHksParam(napi_env env,napi_value object,HksParam & param)107 static napi_value GetHksParam(napi_env env, napi_value object, HksParam ¶m)
108 {
109 napi_value tag = nullptr;
110 NAPI_CALL(env, napi_get_named_property(env, object, HKS_PARAM_PROPERTY_TAG.c_str(), &tag));
111 NAPI_CALL(env, napi_get_value_uint32(env, tag, ¶m.tag));
112
113 napi_value value = nullptr;
114 NAPI_CALL(env, napi_get_named_property(env, object, HKS_PARAM_PROPERTY_VALUE.c_str(), &value));
115
116 napi_value result = nullptr;
117
118 switch (param.tag & HKS_TAG_TYPE_MASK) {
119 case HKS_TAG_TYPE_INT:
120 NAPI_CALL(env, napi_get_value_int32(env, value, ¶m.int32Param));
121 result = GetInt32(env, 0);
122 break;
123 case HKS_TAG_TYPE_UINT:
124 NAPI_CALL(env, napi_get_value_uint32(env, value, ¶m.uint32Param));
125 result = GetInt32(env, 0);
126 break;
127 case HKS_TAG_TYPE_ULONG:
128 NAPI_CALL(env, napi_get_value_int64(env, value, (int64_t *)¶m.uint64Param));
129 result = GetInt32(env, 0);
130 break;
131 case HKS_TAG_TYPE_BOOL:
132 NAPI_CALL(env, napi_get_value_bool(env, value, ¶m.boolParam));
133 result = GetInt32(env, 0);
134 break;
135 case HKS_TAG_TYPE_BYTES:
136 result = GetUint8Array(env, value, param.blob);
137 if (result == nullptr) {
138 HKS_LOG_E("get uint8 array fail.");
139 } else {
140 HKS_LOG_D("tag 0x%x, len 0x%x", param.tag, param.blob.size);
141 }
142 break;
143 default:
144 HKS_LOG_E("invalid tag value 0x%x", param.tag);
145 break;
146 }
147
148 return result;
149 }
150
ParseHksParamSet(napi_env env,napi_value object,HksParamSet * & paramSet)151 napi_value ParseHksParamSet(napi_env env, napi_value object, HksParamSet *¶mSet)
152 {
153 if (HksInitParamSet(¶mSet) != HKS_SUCCESS) {
154 napi_throw_error(env, NULL, "native error");
155 HKS_LOG_E("init paramset failed");
156 return nullptr;
157 }
158
159 size_t index = 0;
160 bool hasNextElement = false;
161 napi_value result = nullptr;
162 while ((napi_has_element(env, object, index, &hasNextElement) == napi_ok) && hasNextElement) {
163 napi_value element = nullptr;
164 NAPI_CALL(env, napi_get_element(env, object, index, &element));
165
166 HksParam param = {0};
167 result = GetHksParam(env, element, param);
168 if (result == nullptr) {
169 HKS_LOG_E("GetHksParam failed.");
170 HksFreeParamSet(¶mSet);
171 return nullptr;
172 }
173
174 if (HksAddParams(paramSet, ¶m, 1) != HKS_SUCCESS) {
175 HKS_LOG_E("HksAddParams failed.");
176 HksFreeParamSet(¶mSet);
177 return nullptr;
178 }
179 index++;
180 }
181
182 if (HksBuildParamSet(¶mSet) != HKS_SUCCESS) {
183 HKS_LOG_E("HksBuildParamSet failed.");
184 HksFreeParamSet(¶mSet);
185 return nullptr;
186 }
187
188 return GetInt32(env, 0);
189 }
190
GetCallback(napi_env env,napi_value object)191 napi_ref GetCallback(napi_env env, napi_value object)
192 {
193 napi_valuetype valueType = napi_undefined;
194 napi_status status = napi_typeof(env, object, &valueType);
195 if (status != napi_ok) {
196 GET_AND_THROW_LAST_ERROR((env));
197 HKS_LOG_E("could not get object type");
198 return nullptr;
199 }
200
201 if (valueType != napi_function) {
202 HKS_LOG_E("invalid type");
203 return nullptr;
204 }
205
206 napi_ref ref = nullptr;
207 status = napi_create_reference(env, object, 1, &ref);
208 if (status != napi_ok) {
209 GET_AND_THROW_LAST_ERROR((env));
210 HKS_LOG_E("could not create reference");
211 return nullptr;
212 }
213 return ref;
214 }
215
GenerateAarrayBuffer(napi_env env,uint8_t * data,uint32_t size)216 static napi_value GenerateAarrayBuffer(napi_env env, uint8_t *data, uint32_t size)
217 {
218 uint8_t *buffer = (uint8_t *)HksMalloc(size);
219 if (buffer == nullptr) {
220 return nullptr;
221 }
222
223 napi_value outBuffer = nullptr;
224 (void)memcpy_s(buffer, size, data, size);
225
226 napi_status status = napi_create_external_arraybuffer(
227 env, buffer, size, [](napi_env env, void *data, void *hint) { HksFree(data); }, nullptr, &outBuffer);
228 if (status == napi_ok) {
229 // free by finalize callback
230 buffer = nullptr;
231 } else {
232 HksFree(buffer);
233 GET_AND_THROW_LAST_ERROR((env));
234 }
235
236 return outBuffer;
237 }
238
GenerateHksParam(napi_env env,const HksParam & param)239 static napi_value GenerateHksParam(napi_env env, const HksParam ¶m)
240 {
241 napi_value hksParam = nullptr;
242 NAPI_CALL(env, napi_create_object(env, &hksParam));
243
244 napi_value tag = nullptr;
245 NAPI_CALL(env, napi_create_uint32(env, param.tag, &tag));
246 NAPI_CALL(env, napi_set_named_property(env, hksParam, HKS_PARAM_PROPERTY_TAG.c_str(), tag));
247
248 napi_value value = nullptr;
249 switch (param.tag & HKS_TAG_TYPE_MASK) {
250 case HKS_TAG_TYPE_INT:
251 NAPI_CALL(env, napi_create_int32(env, param.int32Param, &value));
252 break;
253 case HKS_TAG_TYPE_UINT:
254 NAPI_CALL(env, napi_create_uint32(env, param.uint32Param, &value));
255 break;
256 case HKS_TAG_TYPE_ULONG:
257 NAPI_CALL(env, napi_create_int64(env, param.uint64Param, &value));
258 break;
259 case HKS_TAG_TYPE_BOOL:
260 NAPI_CALL(env, napi_get_boolean(env, param.boolParam, &value));
261 break;
262 case HKS_TAG_TYPE_BYTES:
263 value = GenerateAarrayBuffer(env, param.blob.data, param.blob.size);
264 break;
265 default:
266 value = GetNull(env);
267 break;
268 }
269 NAPI_CALL(env, napi_set_named_property(env, hksParam, HKS_PARAM_PROPERTY_VALUE.c_str(), value));
270
271 return hksParam;
272 }
273
GenerateHksParamArray(napi_env env,const HksParamSet & paramSet)274 static napi_value GenerateHksParamArray(napi_env env, const HksParamSet ¶mSet)
275 {
276 napi_value paramArray = nullptr;
277 NAPI_CALL(env, napi_create_array(env, ¶mArray));
278
279 for (uint32_t i = 0; i < paramSet.paramsCnt; i++) {
280 napi_value element = nullptr;
281 element = GenerateHksParam(env, paramSet.params[i]);
282 napi_set_element(env, paramArray, i, element);
283 }
284
285 return paramArray;
286 }
287
GenerateHksResult(napi_env env,int32_t error)288 napi_value GenerateHksResult(napi_env env, int32_t error)
289 {
290 napi_value result = nullptr;
291 NAPI_CALL(env, napi_create_object(env, &result));
292
293 napi_value errorCode = nullptr;
294 NAPI_CALL(env, napi_create_int32(env, error, &errorCode));
295 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_ERRORCODE.c_str(), errorCode));
296
297 napi_value outData = GetNull(env);
298 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_OUTDATA.c_str(), outData));
299
300 napi_value properties = GetNull(env);
301 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PRPPERTY_PROPERTIES.c_str(), properties));
302
303 return result;
304 }
305
GenerateHksResult(napi_env env,int32_t error,uint8_t * data,uint32_t size)306 napi_value GenerateHksResult(napi_env env, int32_t error, uint8_t *data, uint32_t size)
307 {
308 napi_value result = nullptr;
309 NAPI_CALL(env, napi_create_object(env, &result));
310
311 napi_value errorCode = nullptr;
312 NAPI_CALL(env, napi_create_int32(env, error, &errorCode));
313 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_ERRORCODE.c_str(), errorCode));
314
315 napi_value outData = nullptr;
316 if (data != nullptr && size != 0) {
317 napi_value outBuffer = GenerateAarrayBuffer(env, data, size);
318 if (outBuffer != nullptr) {
319 NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, size, outBuffer, 0, &outData));
320 }
321 } else {
322 outData = GetNull(env);
323 }
324 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_OUTDATA.c_str(), outData));
325
326 napi_value properties = GetNull(env);
327 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PRPPERTY_PROPERTIES.c_str(), properties));
328
329 return result;
330 }
331
GenerateHksResult(napi_env env,int32_t error,uint8_t * data,uint32_t size,const HksParamSet & paramSet)332 napi_value GenerateHksResult(napi_env env, int32_t error, uint8_t *data, uint32_t size, const HksParamSet ¶mSet)
333 {
334 napi_value result = nullptr;
335 NAPI_CALL(env, napi_create_object(env, &result));
336
337 napi_value errorCode = nullptr;
338 NAPI_CALL(env, napi_create_int32(env, error, &errorCode));
339 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_ERRORCODE.c_str(), errorCode));
340
341 napi_value outData = nullptr;
342 if (data != nullptr && size != 0) {
343 napi_value outBuffer = GenerateAarrayBuffer(env, data, size);
344 if (outBuffer != nullptr) {
345 NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, size, outBuffer, 0, &outData));
346 }
347 } else {
348 outData = GetNull(env);
349 }
350 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PROPERTY_OUTDATA.c_str(), outData));
351
352 napi_value properties = GenerateHksParamArray(env, paramSet);
353 NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PRPPERTY_PROPERTIES.c_str(), properties));
354
355 return result;
356 }
357
GenerateBusinessError(napi_env env,int32_t errorCode)358 static napi_value GenerateBusinessError(napi_env env, int32_t errorCode)
359 {
360 napi_value businessError = nullptr;
361 NAPI_CALL(env, napi_create_object(env, &businessError));
362
363 napi_value code = nullptr;
364 NAPI_CALL(env, napi_create_int32(env, errorCode, &code));
365 NAPI_CALL(env, napi_set_named_property(env, businessError, BUSINESS_ERROR_PROPERTY_CODE.c_str(), code));
366
367 return businessError;
368 }
369
CallAsyncCallback(napi_env env,napi_ref callback,int32_t error,napi_value data)370 void CallAsyncCallback(napi_env env, napi_ref callback, int32_t error, napi_value data)
371 {
372 napi_value businessError = GenerateBusinessError(env, error);
373
374 napi_value params[ASYNCCALLBACK_ARGC] = { businessError, data };
375
376 napi_value func = nullptr;
377 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, callback, &func));
378
379 napi_value recv = nullptr;
380 napi_value result = nullptr;
381 NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &recv));
382 NAPI_CALL_RETURN_VOID(env, napi_call_function(env, recv, func, ASYNCCALLBACK_ARGC, params, &result));
383 }
384
GenerateStringArray(napi_env env,const struct HksBlob * blob,const uint32_t blobCount)385 napi_value GenerateStringArray(napi_env env, const struct HksBlob *blob, const uint32_t blobCount)
386 {
387 if (blobCount == 0 || blob == nullptr) {
388 return nullptr;
389 }
390 napi_value array = nullptr;
391 NAPI_CALL(env, napi_create_array(env, &array));
392 for (uint32_t i = 0; i < blobCount; i++) {
393 napi_value element = nullptr;
394 napi_create_string_latin1(env, (const char *)blob[i].data, blob[i].size, &element);
395 napi_set_element(env, array, i, element);
396 }
397 return array;
398 }
399
FreeHksCertChain(HksCertChain * & certChain)400 void FreeHksCertChain(HksCertChain *&certChain)
401 {
402 if (certChain == nullptr) {
403 return;
404 }
405
406 if (certChain->certsCount > 0 && certChain->certs != nullptr) {
407 for (uint32_t i = 0; i < certChain->certsCount; i++) {
408 if (certChain->certs[i].data != nullptr) {
409 HksFree(certChain->certs[i].data);
410 certChain->certs[i].data = nullptr;
411 }
412 }
413 }
414
415 HksFree(certChain);
416 certChain = nullptr;
417 }
418
GenerateHksHandle(napi_env env,int32_t error,uint8_t * data,uint32_t size)419 napi_value GenerateHksHandle(napi_env env, int32_t error, uint8_t *data, uint32_t size)
420 {
421 napi_value result = nullptr;
422 NAPI_CALL(env, napi_create_object(env, &result));
423
424 napi_value errorCode = nullptr;
425 NAPI_CALL(env, napi_create_int32(env, error, &errorCode));
426 NAPI_CALL(env, napi_set_named_property(env, result, HKS_HANDLE_PROPERTY_ERRORCODE.c_str(), errorCode));
427
428 if (data == nullptr) {
429 HKS_LOG_E("data: invalid pointer");
430 return result;
431 }
432
433 uint64_t tempHandle = *(uint64_t *)data;
434 uint32_t handle = (uint32_t)tempHandle; /* Temporarily only use 32 bit handle */
435 HKS_LOG_I("init handle:%u", handle);
436
437 napi_value handlejs = nullptr;
438 NAPI_CALL(env, napi_create_uint32(env, handle, &handlejs));
439 NAPI_CALL(env, napi_set_named_property(env, result, HKS_HANDLE_PROPERTY_HANDLE.c_str(), handlejs));
440
441 return result;
442 }
443 } // namespace HuksNapi
444