1 /*
2  * Copyright (c) 2022-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 "huks_napi_common_item.h"
17 
18 #include <string>
19 #include <vector>
20 
21 #include "hks_errcode_adapter.h"
22 #include "hks_log.h"
23 #include "hks_param.h"
24 #include "hks_type.h"
25 #include "securec.h"
26 
27 namespace HuksNapiItem {
28 namespace {
29 constexpr int HKS_MAX_DATA_LEN = 0x6400000; // The maximum length is 100M
30 constexpr size_t ASYNCCALLBACK_ARGC = 2;
31 }  // namespace
32 
ParseKeyAlias(napi_env env,napi_value object,HksBlob * & alias)33 napi_value ParseKeyAlias(napi_env env, napi_value object, HksBlob *&alias)
34 {
35     napi_valuetype valueType = napi_valuetype::napi_undefined;
36     NAPI_CALL(env, napi_typeof(env, object, &valueType));
37 
38     if (valueType != napi_valuetype::napi_string) {
39         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "the type of alias isn't string");
40         HKS_LOG_E("no string type");
41         return nullptr;
42     }
43 
44     size_t length = 0;
45     napi_status status = napi_get_value_string_utf8(env, object, nullptr, 0, &length);
46     if (status != napi_ok) {
47         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "could not get string length");
48         HKS_LOG_E("could not get string length %" LOG_PUBLIC "d", status);
49         return nullptr;
50     }
51 
52     if (length > HKS_MAX_DATA_LEN) {
53         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "the length of alias is too long");
54         HKS_LOG_E("input key alias length %" LOG_PUBLIC "zu too large", length);
55         return nullptr;
56     }
57 
58     char *data = static_cast<char *>(HksMalloc(length + 1));
59     if (data == nullptr) {
60         HksNapiThrowInsufficientMemory(env);
61         HKS_LOG_E("could not alloc memory");
62         return nullptr;
63     }
64     (void)memset_s(data, length + 1, 0, length + 1);
65 
66     size_t result = 0;
67     status = napi_get_value_string_utf8(env, object, data, length + 1, &result);
68     if (status != napi_ok) {
69         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "could not get string");
70         HKS_FREE(data);
71         HKS_LOG_E("could not get string %" LOG_PUBLIC "d", status);
72         return nullptr;
73     }
74 
75     alias = static_cast<HksBlob *>(HksMalloc(sizeof(HksBlob)));
76     if (alias == nullptr) {
77         HksNapiThrowInsufficientMemory(env);
78         HKS_FREE(data);
79         HKS_LOG_E("could not alloc memory");
80         return nullptr;
81     }
82     alias->data = reinterpret_cast<uint8_t *>(data);
83     alias->size = static_cast<uint32_t>(length & UINT32_MAX);
84 
85     return GetInt32(env, 0);
86 }
87 
GetUint8Array(napi_env env,napi_value object,HksBlob & arrayBlob)88 napi_value GetUint8Array(napi_env env, napi_value object, HksBlob &arrayBlob)
89 {
90     napi_typedarray_type arrayType;
91     napi_value arrayBuffer = nullptr;
92     size_t length = 0;
93     size_t offset = 0;
94     void *rawData = nullptr;
95 
96     NAPI_CALL(
97         env, napi_get_typedarray_info(env, object, &arrayType, &length, &rawData, &arrayBuffer, &offset));
98     if (arrayType != napi_uint8_array) {
99         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
100             "the type of data is not Uint8Array");
101         HKS_LOG_E("the type of  data is not Uint8Array");
102         return nullptr;
103     }
104 
105     if (length > HKS_MAX_DATA_LEN) {
106         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
107             "the length of data is too long");
108         HKS_LOG_E("data len is too large, len = %" LOG_PUBLIC "zx", length);
109         return nullptr;
110     }
111     if (length == 0) {
112         HKS_LOG_I("the created memory length just 1 Byte");
113         // the created memory length just 1 Byte
114         arrayBlob.data = static_cast<uint8_t *>(HksMalloc(1));
115     } else {
116         arrayBlob.data = static_cast<uint8_t *>(HksMalloc(length));
117     }
118     if (arrayBlob.data == nullptr) {
119         return nullptr;
120     }
121 
122     (void)memcpy_s(arrayBlob.data, length, rawData, length);
123     arrayBlob.size = static_cast<uint32_t>(length);
124     napi_value result = GetInt32(env, 0);
125     if (result == nullptr) {
126         memset_s(arrayBlob.data, length, 0, length);
127         HKS_FREE_BLOB(arrayBlob);
128     }
129     return result;
130 }
131 
CheckParamValueType(napi_env env,uint32_t tag,napi_value value)132 static napi_value CheckParamValueType(napi_env env, uint32_t tag, napi_value value)
133 {
134     napi_value result = nullptr;
135     napi_valuetype valueType = napi_valuetype::napi_undefined;
136     NAPI_CALL(env, napi_typeof(env, value, &valueType));
137 
138     switch (tag & HKS_TAG_TYPE_MASK) {
139         case HKS_TAG_TYPE_INT:
140             if (valueType == napi_valuetype::napi_number) {
141                 result = GetInt32(env, 0);
142             }
143             break;
144         case HKS_TAG_TYPE_UINT:
145             if (valueType == napi_valuetype::napi_number) {
146                 result = GetInt32(env, 0);
147             }
148             break;
149         case HKS_TAG_TYPE_ULONG:
150             if (valueType == napi_valuetype::napi_number) {
151                 result = GetInt32(env, 0);
152             }
153             break;
154         case HKS_TAG_TYPE_BOOL:
155             if (valueType == napi_valuetype::napi_boolean) {
156                 result = GetInt32(env, 0);
157             }
158             break;
159         case HKS_TAG_TYPE_BYTES:
160             if (valueType == napi_valuetype::napi_object) {
161                 result = GetInt32(env, 0);
162             }
163             break;
164         default:
165             HKS_LOG_E("invalid tag value 0x%" LOG_PUBLIC "x", tag);
166             break;
167     }
168 
169     if (result == nullptr) {
170         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
171             "the value of the tag is of an incorrect type");
172         HKS_LOG_E("invalid tag or the type of value, tag = 0x%" LOG_PUBLIC "x, type = %" LOG_PUBLIC "u",
173             tag, valueType);
174     }
175     return result;
176 }
177 
GetHksParam(napi_env env,napi_value object,HksParam & param)178 static napi_value GetHksParam(napi_env env, napi_value object, HksParam &param)
179 {
180     napi_value tag = GetPropertyFromOptions(env, object, HKS_PARAM_PROPERTY_TAG);
181     if (tag == nullptr) {
182         HKS_LOG_E("get param tag failed");
183         return nullptr;
184     }
185     NAPI_CALL(env, napi_get_value_uint32(env, tag, &param.tag));
186 
187     napi_value value = GetPropertyFromOptions(env, object, HKS_PARAM_PROPERTY_VALUE);
188     if (value == nullptr) {
189         HKS_LOG_E("get param value failed");
190         return nullptr;
191     }
192 
193     if (CheckParamValueType(env, param.tag, value) == nullptr) {
194         return nullptr;
195     }
196 
197     napi_value result = nullptr;
198     switch (param.tag & HKS_TAG_TYPE_MASK) {
199         case HKS_TAG_TYPE_INT:
200             NAPI_CALL(env, napi_get_value_int32(env, value, &param.int32Param));
201             result = GetInt32(env, 0);
202             break;
203         case HKS_TAG_TYPE_UINT:
204             NAPI_CALL(env, napi_get_value_uint32(env, value, &param.uint32Param));
205             result = GetInt32(env, 0);
206             break;
207         case HKS_TAG_TYPE_ULONG:
208             NAPI_CALL(env, napi_get_value_int64(env, value, reinterpret_cast<int64_t *>(&param.uint64Param)));
209             result = GetInt32(env, 0);
210             break;
211         case HKS_TAG_TYPE_BOOL:
212             NAPI_CALL(env, napi_get_value_bool(env, value, &param.boolParam));
213             result = GetInt32(env, 0);
214             break;
215         case HKS_TAG_TYPE_BYTES:
216             result = GetUint8Array(env, value, param.blob);
217             if (result == nullptr) {
218                 HKS_LOG_E("get uint8 array fail.");
219             } else {
220                 HKS_LOG_D("tag 0x%" LOG_PUBLIC "x, len 0x%" LOG_PUBLIC "x", param.tag, param.blob.size);
221             }
222             break;
223         default:
224             HKS_LOG_E("invalid tag value 0x%" LOG_PUBLIC "x", param.tag);
225             break;
226     }
227 
228     return result;
229 }
230 
FreeParsedParams(std::vector<HksParam> & params)231 void FreeParsedParams(std::vector<HksParam> &params)
232 {
233     for (HksParam &p : params) {
234         if (GetTagType(static_cast<HksTag>(p.tag)) == HKS_TAG_TYPE_BYTES) {
235             HKS_FREE_BLOB(p.blob);
236         }
237     }
238 }
239 
ParseParams(napi_env env,napi_value object,std::vector<HksParam> & params)240 napi_value ParseParams(napi_env env, napi_value object, std::vector<HksParam> &params)
241 {
242     bool hasNextElement = false;
243     napi_value result = nullptr;
244     size_t index = 0;
245     while ((napi_has_element(env, object, index, &hasNextElement) == napi_ok) && hasNextElement) {
246         napi_value element = nullptr;
247         NAPI_CALL(env, napi_get_element(env, object, index, &element));
248 
249         HksParam param = { 0 };
250         result = GetHksParam(env, element, param);
251         if (result == nullptr) {
252             HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "GetHksParam fail");
253             HKS_LOG_E("get param failed when parse input params.");
254             return nullptr;
255         }
256 
257         params.push_back(param);
258         index++;
259     }
260     return GetInt32(env, 0);
261 }
262 
ParseHksParamSetAndAddParam(napi_env env,napi_value object,HksParamSet * & paramSet,const std::vector<HksParam> & addParams)263 napi_value ParseHksParamSetAndAddParam(napi_env env, napi_value object, HksParamSet *&paramSet,
264     const std::vector<HksParam> &addParams)
265 {
266     if (paramSet != nullptr) {
267         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "paramSet is nullptr");
268         HKS_LOG_E("param input invalid");
269         return nullptr;
270     }
271 
272     std::vector<HksParam> params{};
273     HksParamSet *outParamSet = nullptr;
274     do {
275         if (HksInitParamSet(&outParamSet) != HKS_SUCCESS) {
276             HksNapiThrowInsufficientMemory(env);
277             HKS_LOG_E("paramset init failed");
278             break;
279         }
280 
281         if (ParseParams(env, object, params) == nullptr) {
282             HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "ParseParams fail");
283             HKS_LOG_E("parse params failed");
284             break;
285         }
286 
287         if (!addParams.empty()) {
288             // the memory of some blobs in addParams is allocated before stepping into current function,
289             // and we will FreeParsedParams(params) later, therefore we can not append addParams into params.
290             if (HksAddParams(outParamSet, addParams.data(), addParams.size()) != HKS_SUCCESS) {
291                 HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "HksAddParams addParams fail");
292                 HKS_LOG_E("add params addParams failed");
293                 break;
294             }
295         }
296 
297         if (!params.empty()) {
298             if (HksAddParams(outParamSet, params.data(), params.size()) != HKS_SUCCESS) {
299                 HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "HksAddParams fail");
300                 HKS_LOG_E("add params failed");
301                 break;
302             }
303         }
304 
305         if (HksBuildParamSet(&outParamSet) != HKS_SUCCESS) {
306             HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "HksBuildParamSet fail");
307             HKS_LOG_E("HksBuildParamSet failed");
308             break;
309         }
310 
311         FreeParsedParams(params);
312         paramSet = outParamSet;
313         return GetInt32(env, 0);
314     } while (0);
315 
316     HksFreeParamSet(&outParamSet);
317     FreeParsedParams(params);
318     return nullptr;
319 }
320 
ParseHksParamSetWithToken(napi_env env,struct HksBlob * & token,napi_value object,HksParamSet * & paramSet)321 napi_value ParseHksParamSetWithToken(napi_env env, struct HksBlob *&token, napi_value object, HksParamSet *&paramSet)
322 {
323     std::vector<HksParam> params {};
324     if (CheckBlob(token) == HKS_SUCCESS) { /* has token param */
325         params.emplace_back(HksParam{
326             .tag = HKS_TAG_AUTH_TOKEN,
327             .blob = *token
328         });
329     }
330     return ParseHksParamSetAndAddParam(env, object, paramSet, params);
331 }
332 
GetCallback(napi_env env,napi_value object)333 napi_ref GetCallback(napi_env env, napi_value object)
334 {
335     napi_valuetype valueType = napi_valuetype::napi_undefined;
336     NAPI_CALL(env, napi_typeof(env, object, &valueType));
337 
338     if (valueType != napi_valuetype::napi_function) {
339         HKS_LOG_I("no callback fun, process as promise func");
340         return nullptr;
341     }
342 
343     napi_ref ref = nullptr;
344     napi_status status = napi_create_reference(env, object, 1, &ref);
345     if (status != napi_ok) {
346         HKS_LOG_E("could not create reference");
347         return nullptr;
348     }
349     return ref;
350 }
351 
GenerateArrayBuffer(napi_env env,uint8_t * data,uint32_t size)352 static napi_value GenerateArrayBuffer(napi_env env, uint8_t *data, uint32_t size)
353 {
354     uint8_t *buffer = static_cast<uint8_t *>(HksMalloc(size));
355     if (buffer == nullptr) {
356         return nullptr;
357     }
358 
359     napi_value outBuffer = nullptr;
360     (void)memcpy_s(buffer, size, data, size);
361 
362     napi_status status = napi_create_external_arraybuffer(
363         env, buffer, size, [](napi_env env, void *data, void *hint) { HKS_FREE(data); }, nullptr, &outBuffer);
364     if (status == napi_ok) {
365         // free by finalize callback
366         buffer = nullptr;
367     } else {
368         HKS_FREE(buffer);
369     }
370 
371     return outBuffer;
372 }
373 
GenerateHksParam(napi_env env,const HksParam & param)374 static napi_value GenerateHksParam(napi_env env, const HksParam &param)
375 {
376     napi_value hksParam = nullptr;
377     NAPI_CALL(env, napi_create_object(env, &hksParam));
378 
379     napi_value tag = nullptr;
380     NAPI_CALL(env, napi_create_uint32(env, param.tag, &tag));
381     NAPI_CALL(env, napi_set_named_property(env, hksParam, HKS_PARAM_PROPERTY_TAG.c_str(), tag));
382 
383     napi_value value = nullptr;
384     switch (param.tag & HKS_TAG_TYPE_MASK) {
385         case HKS_TAG_TYPE_INT:
386             NAPI_CALL(env, napi_create_int32(env, param.int32Param, &value));
387             break;
388         case HKS_TAG_TYPE_UINT:
389             NAPI_CALL(env, napi_create_uint32(env, param.uint32Param, &value));
390             break;
391         case HKS_TAG_TYPE_ULONG:
392             NAPI_CALL(env, napi_create_int64(env, param.uint64Param, &value));
393             break;
394         case HKS_TAG_TYPE_BOOL:
395             NAPI_CALL(env, napi_get_boolean(env, param.boolParam, &value));
396             break;
397         case HKS_TAG_TYPE_BYTES:
398             value = GenerateArrayBuffer(env, param.blob.data, param.blob.size);
399             break;
400         default:
401             value = GetNull(env);
402             break;
403     }
404     NAPI_CALL(env, napi_set_named_property(env, hksParam, HKS_PARAM_PROPERTY_VALUE.c_str(), value));
405 
406     return hksParam;
407 }
408 
GenerateHksParamArray(napi_env env,const HksParamSet & paramSet)409 static napi_value GenerateHksParamArray(napi_env env, const HksParamSet &paramSet)
410 {
411     napi_value paramArray = nullptr;
412     NAPI_CALL(env, napi_create_array(env, &paramArray));
413 
414     for (uint32_t i = 0; i < paramSet.paramsCnt; i++) {
415         napi_value element = nullptr;
416         element = GenerateHksParam(env, paramSet.params[i]);
417         napi_set_element(env, paramArray, i, element);
418     }
419 
420     return paramArray;
421 }
422 
GenerateStringArray(napi_env env,const struct HksBlob * blob,uint32_t blobCount)423 static napi_value GenerateStringArray(napi_env env, const struct HksBlob *blob, uint32_t blobCount)
424 {
425     if (blobCount == 0 || blob == nullptr) {
426         return nullptr;
427     }
428     napi_value array = nullptr;
429     NAPI_CALL(env, napi_create_array(env, &array));
430     for (uint32_t i = 0; i < blobCount; i++) {
431         napi_value element = nullptr;
432         napi_create_string_latin1(env, reinterpret_cast<const char *>(blob[i].data), blob[i].size, &element);
433         napi_set_element(env, array, i, element);
434     }
435     return array;
436 }
437 
FreeHksCertChain(HksCertChain * & certChain,uint32_t certChainCapacity)438 void FreeHksCertChain(HksCertChain *&certChain, uint32_t certChainCapacity)
439 {
440     if (certChain == nullptr) {
441         return;
442     }
443 
444     if (certChainCapacity > 0 && certChain->certs != nullptr) {
445         for (uint32_t i = 0; i < certChainCapacity; i++) {
446             if (certChain->certs[i].data != nullptr) {
447                 HKS_FREE(certChain->certs[i].data);
448                 certChain->certs[i].data = nullptr;
449             }
450         }
451     }
452     HKS_FREE(certChain->certs);
453     HKS_FREE(certChain);
454     certChain = nullptr;
455 }
456 
FreeHksKeyAliasSet(HksKeyAliasSet * & keyAliasSet,uint32_t cnt)457 void FreeHksKeyAliasSet(HksKeyAliasSet *&keyAliasSet, uint32_t cnt)
458 {
459     if (keyAliasSet == nullptr) {
460         return;
461     }
462 
463     if (cnt > 0 && keyAliasSet->aliases != nullptr) {
464         for (uint32_t i = 0; i < cnt; i++) {
465             HKS_FREE_BLOB(keyAliasSet->aliases[i]);
466         }
467     }
468     HKS_FREE(keyAliasSet->aliases);
469     HKS_FREE(keyAliasSet);
470     keyAliasSet = nullptr;
471 }
472 
GetHandleValue(napi_env env,napi_value object,struct HksBlob * & handleBlob)473 napi_value GetHandleValue(napi_env env, napi_value object, struct HksBlob *&handleBlob)
474 {
475     if (handleBlob != nullptr) {
476         HKS_LOG_E("param input invalid");
477         return nullptr;
478     }
479 
480     napi_valuetype valueType = napi_valuetype::napi_undefined;
481     NAPI_CALL(env, napi_typeof(env, object, &valueType));
482 
483     if (valueType != napi_valuetype::napi_number) {
484         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
485             "the type of handle isn't number");
486         return nullptr;
487     }
488 
489     uint32_t handleTmp = 0;
490     napi_status status = napi_get_value_uint32(env, object, &handleTmp);
491     if (status != napi_ok) {
492         HKS_LOG_E("Retrieve field failed");
493         return nullptr;
494     }
495 
496     uint64_t handle = static_cast<uint64_t>(handleTmp);
497 
498     handleBlob = static_cast<struct HksBlob *>(HksMalloc(sizeof(struct HksBlob)));
499     if (handleBlob == nullptr) {
500         HKS_LOG_E("could not alloc memory");
501         return nullptr;
502     }
503 
504     handleBlob->data = static_cast<uint8_t *>(HksMalloc(sizeof(uint64_t)));
505     if (handleBlob->data == nullptr) {
506         HKS_FREE(handleBlob);
507         HKS_LOG_E("could not alloc memory");
508         return nullptr;
509     }
510     handleBlob->size = sizeof(uint64_t);
511 
512     if (memcpy_s(handleBlob->data, sizeof(uint64_t), &handle, sizeof(uint64_t)) != EOK) {
513         // the memory of handleBlob free by finalize callback
514         return nullptr;
515     }
516 
517     return GetInt32(env, 0);
518 }
519 
GetUserIdValue(napi_env env,napi_value object,int & userId)520 napi_value GetUserIdValue(napi_env env, napi_value object, int &userId)
521 {
522     napi_valuetype valueType = napi_valuetype::napi_undefined;
523     NAPI_CALL(env, napi_typeof(env, object, &valueType));
524 
525     if (valueType != napi_valuetype::napi_number) {
526         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "the type of userId isn't number");
527         HKS_LOG_E("valueType %" LOG_PUBLIC "d not napi_number", valueType);
528         return nullptr;
529     }
530 
531     napi_status status = napi_get_value_int32(env, object, &userId);
532     if (status != napi_ok) {
533         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "get int32 userId failed");
534         HKS_LOG_E("get int32 userId failed %" LOG_PUBLIC "d", status);
535         return nullptr;
536     }
537 
538     return GetInt32(env, 0);
539 }
540 
DeleteCommonAsyncContext(napi_env env,napi_async_work & asyncWork,napi_ref & callback,struct HksBlob * & blob,struct HksParamSet * & paramSet)541 void DeleteCommonAsyncContext(napi_env env, napi_async_work &asyncWork, napi_ref &callback,
542     struct HksBlob *&blob, struct HksParamSet *&paramSet)
543 {
544     if (asyncWork != nullptr) {
545         napi_delete_async_work(env, asyncWork);
546         asyncWork = nullptr;
547     }
548 
549     if (callback != nullptr) {
550         napi_delete_reference(env, callback);
551         callback = nullptr;
552     }
553 
554     if (blob != nullptr) {
555         FreeHksBlob(blob);
556     }
557 
558     if (paramSet != nullptr) {
559         HksFreeParamSet(&paramSet);
560     }
561 }
562 
GetPropertyFromOptions(napi_env env,napi_value value,const std::string propertyStr)563 napi_value GetPropertyFromOptions(napi_env env, napi_value value, const std::string propertyStr)
564 {
565     napi_valuetype valueType = napi_valuetype::napi_undefined;
566     NAPI_CALL(env, napi_typeof(env, value, &valueType));
567 
568     if (valueType != napi_valuetype::napi_object) {
569         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
570             "the type is not object");
571         HKS_LOG_E("no object type");
572         return nullptr;
573     }
574 
575     napi_value property = nullptr;
576     napi_status status = napi_get_named_property(env, value,
577         propertyStr.c_str(), &property);
578     if (status != napi_ok || property == nullptr) {
579         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT,
580             "get value failed, maybe the target does not exist");
581         HKS_LOG_E("could not get property %" LOG_PUBLIC "s", propertyStr.c_str());
582         return nullptr;
583     }
584 
585     return property;
586 }
587 
ParseGetHksParamSet(napi_env env,napi_value value,HksParamSet * & paramSet)588 napi_value ParseGetHksParamSet(napi_env env, napi_value value, HksParamSet *&paramSet)
589 {
590     napi_value property = GetPropertyFromOptions(env, value, HKS_OPTIONS_PROPERTY_PROPERTIES);
591     if (property == nullptr) {
592         return nullptr;
593     }
594 
595     napi_value result = ParseHksParamSetAndAddParam(env, property, paramSet);
596     if (result == nullptr) {
597         HKS_LOG_E("could not get paramset");
598         return nullptr;
599     }
600 
601     return GetInt32(env, 0);
602 }
603 
ParseGetHksParamSetAsUser(napi_env env,int userId,napi_value value,HksParamSet * & paramSet)604 static napi_value ParseGetHksParamSetAsUser(napi_env env, int userId, napi_value value, HksParamSet *&paramSet)
605 {
606     napi_value property = GetPropertyFromOptions(env, value, HKS_OPTIONS_PROPERTY_PROPERTIES);
607     if (property == nullptr) {
608         return nullptr;
609     }
610 
611     napi_value result = ParseHksParamSetAndAddParam(env, property, paramSet,
612         {{.tag = HKS_TAG_SPECIFIC_USER_ID, .int32Param = userId}});
613     if (result == nullptr) {
614         HKS_LOG_E("could not get paramset");
615         return nullptr;
616     }
617 
618     return GetInt32(env, 0);
619 }
620 
ParseKeyAliasAndHksParamSet(napi_env env,napi_value * argv,size_t & index,HksBlob * & keyAliasBlob,HksParamSet * & paramSet)621 napi_value ParseKeyAliasAndHksParamSet(napi_env env, napi_value *argv, size_t &index,
622     HksBlob *&keyAliasBlob, HksParamSet *&paramSet)
623 {
624     // the index is controlled by the caller and needs to ensure that it does not overflow
625     if (argv == nullptr || keyAliasBlob != nullptr || paramSet != nullptr) {
626         HKS_LOG_E("param input invalid");
627         return nullptr;
628     }
629 
630     napi_value result = ParseKeyAlias(env, argv[index], keyAliasBlob);
631     if (result == nullptr) {
632         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "could not get key alias");
633         HKS_LOG_E("could not get keyAlias");
634         return nullptr;
635     }
636 
637     index++;
638     result = ParseGetHksParamSet(env, argv[index], paramSet);
639     if (result == nullptr) {
640         HKS_LOG_E("get hksParamSet failed");
641         return nullptr;
642     }
643 
644     return GetInt32(env, 0);
645 }
646 
ParseKeyAliasAndHksParamSetAsUser(napi_env env,int userId,napi_value * argv,size_t & index,std::pair<HksBlob * &,HksParamSet * &> out)647 napi_value ParseKeyAliasAndHksParamSetAsUser(napi_env env, int userId, napi_value *argv, size_t &index,
648     std::pair<HksBlob *&, HksParamSet *&> out)
649 {
650     auto &[ keyAliasBlob, paramSet ] = out;
651     // the index is controlled by the caller and needs to ensure that it does not overflow
652     if (argv == nullptr || keyAliasBlob != nullptr || paramSet != nullptr) {
653         HKS_LOG_E("param input invalid");
654         return nullptr;
655     }
656 
657     napi_value result = ParseKeyAlias(env, argv[index], keyAliasBlob);
658     if (result == nullptr) {
659         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "could not get key alias");
660         HKS_LOG_E("could not get keyAlias");
661         return nullptr;
662     }
663 
664     index++;
665     result = ParseGetHksParamSetAsUser(env, userId, argv[index], paramSet);
666     if (result == nullptr) {
667         HKS_LOG_E("get hksParamSet failed");
668         return nullptr;
669     }
670 
671     return GetInt32(env, 0);
672 }
673 
ParseKeyData(napi_env env,napi_value value,HksBlob * & keyDataBlob)674 napi_value ParseKeyData(napi_env env, napi_value value, HksBlob *&keyDataBlob)
675 {
676     if (keyDataBlob != nullptr) {
677         HKS_LOG_E("param input invalid");
678         return nullptr;
679     }
680 
681     napi_value inData = GetPropertyFromOptions(env, value, HKS_OPTIONS_PROPERTY_INDATA);
682     if (inData == nullptr) {
683         HKS_LOG_E("get indata property failed");
684         return nullptr;
685     }
686 
687     keyDataBlob = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
688     if (keyDataBlob == nullptr) {
689         HKS_LOG_E("could not alloc memory");
690         return nullptr;
691     }
692     (void)memset_s(keyDataBlob, sizeof(HksBlob), 0, sizeof(HksBlob));
693 
694     if (GetUint8Array(env, inData, *keyDataBlob) == nullptr) {
695         FreeHksBlob(keyDataBlob);
696         HKS_LOG_E("could not get indata");
697         return nullptr;
698     }
699 
700     return GetInt32(env, 0);
701 }
702 
AddHandleOrChallenge(napi_env env,napi_value & object,const struct HksBlob * handle,const struct HksBlob * challenge)703 static napi_value AddHandleOrChallenge(napi_env env, napi_value &object,
704     const struct HksBlob *handle, const struct HksBlob *challenge)
705 {
706     napi_value addResult = nullptr;
707 
708     // add handle
709     if ((handle != nullptr) && (handle->data != nullptr) && (handle->size == sizeof(uint64_t))) {
710         void *handleData = static_cast<void *>(handle->data);
711         uint64_t tempHandle = *(static_cast<uint64_t *>(handleData));
712         uint32_t handleValue = static_cast<uint32_t>(tempHandle); /* Temporarily only use 32 bit handle */
713         napi_value handlejs = nullptr;
714         NAPI_CALL(env, napi_create_uint32(env, handleValue, &handlejs));
715         NAPI_CALL(env, napi_set_named_property(env, object, HKS_HANDLE_PROPERTY_HANDLE.c_str(), handlejs));
716         addResult = GetInt32(env, 0);
717     }
718 
719     // add challenge
720     if ((challenge != nullptr) && (challenge->size != 0) && (challenge->data != nullptr)) {
721         napi_value challengejs = nullptr;
722         napi_value outBuffer = GenerateArrayBuffer(env, challenge->data, challenge->size);
723         if (outBuffer == nullptr) {
724             HKS_LOG_E("add token failed");
725             return nullptr;
726         }
727 
728         NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, challenge->size, outBuffer, 0, &challengejs));
729         NAPI_CALL(env, napi_set_named_property(env, object, HKS_HANDLE_PROPERTY_CHALLENGE.c_str(), challengejs));
730         addResult = GetInt32(env, 0);
731     }
732 
733     return addResult;
734 }
735 
AddOutDataParamSetOrCertChain(napi_env env,napi_value & object,const struct HksBlob * outData,const HksParamSet * paramSet,const struct HksCertChain * certChain)736 static napi_value AddOutDataParamSetOrCertChain(napi_env env, napi_value &object,
737     const struct HksBlob *outData, const HksParamSet *paramSet, const struct HksCertChain *certChain)
738 {
739     napi_value addResult = nullptr;
740 
741     // add outData
742     if ((outData != nullptr) && (outData->data != nullptr) && (outData->size != 0)) {
743         napi_value outDataJs = nullptr;
744         napi_value outBuffer = GenerateArrayBuffer(env, outData->data, outData->size);
745         if (outBuffer == nullptr) {
746             HKS_LOG_E("add outData failed");
747             return nullptr;
748         }
749         NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, outData->size, outBuffer, 0, &outDataJs));
750         NAPI_CALL(env, napi_set_named_property(env, object, HKS_RESULT_PROPERTY_OUTDATA.c_str(), outDataJs));
751         addResult = GetInt32(env, 0);
752     }
753 
754     // add paramSet
755     if (paramSet != nullptr) {
756         napi_value properties = nullptr;
757         properties = GenerateHksParamArray(env, *paramSet);
758         if (properties == nullptr) {
759             HKS_LOG_E("add paramSet failed");
760             return nullptr;
761         }
762         NAPI_CALL(env, napi_set_named_property(env, object, HKS_RESULT_PRPPERTY_PROPERTIES.c_str(), properties));
763         addResult = GetInt32(env, 0);
764     }
765 
766     // add certChain
767     if ((certChain != nullptr) && (certChain->certs != nullptr) && (certChain->certsCount != 0)) {
768         napi_value certChainJs = GenerateStringArray(env, certChain->certs, certChain->certsCount);
769         if (certChainJs == nullptr) {
770             HKS_LOG_E("add certChain failed");
771             return nullptr;
772         }
773         NAPI_CALL(env, napi_set_named_property(env, object, HKS_RESULT_PRPPERTY_CERTCHAINS.c_str(), certChainJs));
774         addResult = GetInt32(env, 0);
775     }
776 
777     return addResult;
778 }
779 
GenerateResult(napi_env env,const struct HksSuccessReturnResult resultData)780 static napi_value GenerateResult(napi_env env, const struct HksSuccessReturnResult resultData)
781 {
782     napi_value result = nullptr;
783 
784     if (resultData.isOnlyReturnBoolResult) {
785         if (napi_get_boolean(env, resultData.boolReturned, &result) != napi_ok) {
786             return GetNull(env);
787         }
788         return result;
789     }
790 
791     if (napi_create_object(env, &result) != napi_ok) {
792         return GetNull(env);
793     }
794 
795     napi_value status1 = AddHandleOrChallenge(env, result, resultData.handle, resultData.challenge);
796     napi_value status2 = AddOutDataParamSetOrCertChain(env, result,
797         resultData.outData, resultData.paramSet, resultData.certChain);
798     if (status1 == nullptr && status2 == nullptr) {
799         return GetNull(env);
800     }
801 
802     return result;
803 }
804 
GenerateBusinessError(napi_env env,int32_t errorCode)805 static napi_value GenerateBusinessError(napi_env env, int32_t errorCode)
806 {
807     napi_value businessError = nullptr;
808     napi_status status = napi_create_object(env, &businessError);
809     if (status != napi_ok) {
810         HKS_LOG_E("create object failed");
811         return GetNull(env);
812     }
813 
814     struct HksResult errInfo = HksConvertErrCode(errorCode);
815     // add errorCode
816     napi_value code = nullptr;
817     status = napi_create_int32(env, errInfo.errorCode, &code);
818     if (status != napi_ok || code == nullptr) {
819         code = GetNull(env);
820     }
821     status = napi_set_named_property(env, businessError, BUSINESS_ERROR_PROPERTY_CODE.c_str(), code);
822     if (status != napi_ok) {
823         HKS_LOG_E("set errorCode failed");
824         return GetNull(env);
825     }
826 
827     // add errorMessage
828     napi_value msg = GetNull(env);
829     if (errInfo.errorMsg != nullptr) {
830 #ifdef HUKS_NAPI_ERRORCODE_WITH_MESSAGE
831         uint32_t errorMsgLen = strlen(errInfo.errorMsg);
832         uint8_t errorMsgBuf[errorMsgLen];
833         (void)memcpy_s(errorMsgBuf, errorMsgLen, errInfo.errorMsg, errorMsgLen);
834         struct HksBlob msgBlob = { errorMsgLen, errorMsgBuf };
835         msg = GenerateStringArray(env, &msgBlob, 1);
836         msg = ((msg == nullptr) ? GetNull(env) : msg);
837 #endif
838     }
839     status = napi_set_named_property(env, businessError, BUSINESS_ERROR_PROPERTY_MESSAGE.c_str(), msg);
840     if (status != napi_ok) {
841         HKS_LOG_E("set errorMsg failed");
842         return GetNull(env);
843     }
844 
845     // add errorData
846     napi_value data = GetNull(env);
847     status = napi_set_named_property(env, businessError, BUSINESS_ERROR_PROPERTY_DATA.c_str(), data);
848     if (status != napi_ok) {
849         HKS_LOG_E("set errorData failed");
850         return GetNull(env);
851     }
852 
853     return businessError;
854 }
855 
CallbackResultFailure(napi_env env,napi_ref callback,int32_t error)856 static void CallbackResultFailure(napi_env env, napi_ref callback, int32_t error)
857 {
858     if (error == HKS_SUCCESS) {
859         HKS_LOG_E("callback: failure cannot be executed");
860         return;
861     }
862 
863     napi_value func = nullptr;
864     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, callback, &func));
865 
866     napi_value recv = nullptr;
867     napi_value result = nullptr;
868     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &recv));
869 
870     napi_value businessError = GenerateBusinessError(env, error);
871     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, recv, func, 1, &businessError, &result));
872 }
873 
CallbackResultSuccess(napi_env env,napi_ref callback,const struct HksSuccessReturnResult resultData)874 static void CallbackResultSuccess(napi_env env, napi_ref callback, const struct HksSuccessReturnResult resultData)
875 {
876     napi_value params[ASYNCCALLBACK_ARGC] = { GetNull(env), GenerateResult(env, resultData) };
877     napi_value func = nullptr;
878     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, callback, &func));
879 
880     napi_value recv = nullptr;
881     napi_value result = nullptr;
882     NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &recv));
883     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, recv, func, ASYNCCALLBACK_ARGC, params, &result));
884 }
885 
PromiseResultFailure(napi_env env,napi_deferred deferred,int32_t error)886 static void PromiseResultFailure(napi_env env, napi_deferred deferred, int32_t error)
887 {
888     if (error == HKS_SUCCESS) {
889         HKS_LOG_E("promise: failure cannot be executed");
890         return;
891     }
892     napi_value result = nullptr;
893     result = GenerateBusinessError(env, error);
894     napi_reject_deferred(env, deferred, result);
895 }
896 
PromiseResultSuccess(napi_env env,napi_deferred deferred,const struct HksSuccessReturnResult resultData)897 static void PromiseResultSuccess(napi_env env, napi_deferred deferred,
898     const struct HksSuccessReturnResult resultData)
899 {
900     napi_value result = nullptr;
901     result = GenerateResult(env, resultData);
902     napi_resolve_deferred(env, deferred, result);
903 }
904 
SuccessReturnResultInit(struct HksSuccessReturnResult & resultData)905 void SuccessReturnResultInit(struct HksSuccessReturnResult &resultData)
906 {
907     resultData.isOnlyReturnBoolResult = false;
908     resultData.boolReturned = false;
909     resultData.handle = nullptr;
910     resultData.challenge = nullptr;
911     resultData.outData = nullptr;
912     resultData.paramSet = nullptr;
913     resultData.certChain = nullptr;
914 }
915 
SuccessListAliasesReturnResultInit(struct HksSuccessListAliasesResult & resultData)916 void SuccessListAliasesReturnResultInit(struct HksSuccessListAliasesResult &resultData)
917 {
918     resultData.aliasSet = nullptr;
919 }
920 
HksReturnNapiResult(napi_env env,napi_ref callback,napi_deferred deferred,int32_t errorCode,const struct HksSuccessReturnResult resultData)921 void HksReturnNapiResult(napi_env env, napi_ref callback, napi_deferred deferred, int32_t errorCode,
922     const struct HksSuccessReturnResult resultData)
923 {
924     if (callback == nullptr) {
925         if (errorCode == HKS_SUCCESS) {
926             PromiseResultSuccess(env, deferred, resultData);
927         } else {
928             PromiseResultFailure(env, deferred, errorCode);
929         }
930     } else {
931         if (errorCode == HKS_SUCCESS) {
932             CallbackResultSuccess(env, callback, resultData);
933         } else {
934             CallbackResultFailure(env, callback, errorCode);
935         }
936     }
937 }
938 
HksReturnKeyExistResult(napi_env env,napi_ref callback,napi_deferred deferred,int32_t errorCode,const struct HksSuccessReturnResult resultData)939 void HksReturnKeyExistResult(napi_env env, napi_ref callback, napi_deferred deferred, int32_t errorCode,
940     const struct HksSuccessReturnResult resultData)
941 {
942     if (callback == nullptr) {
943         if (errorCode == HKS_SUCCESS || errorCode == HKS_ERROR_NOT_EXIST) {
944             PromiseResultSuccess(env, deferred, resultData);
945         } else {
946             PromiseResultFailure(env, deferred, errorCode);
947         }
948     } else {
949         if (errorCode == HKS_SUCCESS || errorCode == HKS_ERROR_NOT_EXIST) {
950             CallbackResultSuccess(env, callback, resultData);
951         } else {
952             CallbackResultFailure(env, callback, errorCode);
953         }
954     }
955 }
956 
CreateJsError(napi_env env,int32_t errCode,const char * errorMsg)957 napi_value CreateJsError(napi_env env, int32_t errCode, const char *errorMsg)
958 {
959     napi_value code = nullptr;
960     NAPI_CALL(env, napi_create_int32(env, errCode, &code));
961 
962     napi_value message = nullptr;
963     NAPI_CALL(env, napi_create_string_utf8(env, errorMsg, strlen(errorMsg), &message));
964 
965     napi_value result = nullptr;
966     NAPI_CALL(env, napi_create_error(env, code, message, &result));
967     return result;
968 }
969 
GenerateListAliasesResult(napi_env env,const struct HksSuccessListAliasesResult resultData)970 static napi_value GenerateListAliasesResult(napi_env env, const struct HksSuccessListAliasesResult resultData)
971 {
972     napi_value result = nullptr;
973 
974     if (napi_create_object(env, &result) != napi_ok) {
975         return GetNull(env);
976     }
977     // add aliases
978     if ((resultData.aliasSet != nullptr) && (resultData.aliasSet->aliases != nullptr) &&
979         (resultData.aliasSet->aliasesCnt != 0)) {
980         napi_value keyAliasesJs = GenerateStringArray(env, resultData.aliasSet->aliases,
981             resultData.aliasSet->aliasesCnt);
982         if (keyAliasesJs == nullptr) {
983             HKS_LOG_E("add keyAliases failed");
984             return GetNull(env);
985         }
986         NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PRPPERTY_ALIASES.c_str(), keyAliasesJs));
987     } else {
988         napi_value array = nullptr;
989         NAPI_CALL(env, napi_create_array(env, &array));
990         NAPI_CALL(env, napi_set_named_property(env, result, HKS_RESULT_PRPPERTY_ALIASES.c_str(), array));
991     }
992     return result;
993 }
994 
PromiseListAliasesResultSuccess(napi_env env,napi_deferred deferred,const struct HksSuccessListAliasesResult resultData)995 static void PromiseListAliasesResultSuccess(napi_env env, napi_deferred deferred,
996     const struct HksSuccessListAliasesResult resultData)
997 {
998     napi_value result = nullptr;
999     result = GenerateListAliasesResult(env, resultData);
1000     napi_resolve_deferred(env, deferred, result);
1001 }
1002 
HksReturnListAliasesResult(napi_env env,napi_ref callback,napi_deferred deferred,int32_t errorCode,const struct HksSuccessListAliasesResult resultData)1003 void HksReturnListAliasesResult(napi_env env, napi_ref callback, napi_deferred deferred, int32_t errorCode,
1004     const struct HksSuccessListAliasesResult resultData)
1005 {
1006     // now not support callback
1007     if (callback == nullptr) {
1008         if (errorCode == HKS_SUCCESS) {
1009             PromiseListAliasesResultSuccess(env, deferred, resultData);
1010         } else {
1011             PromiseResultFailure(env, deferred, errorCode);
1012         }
1013     }
1014 }
1015 }  // namespace HuksNapiItem
1016