• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "cm_napi_sign_verify.h"
17 
18 #include "securec.h"
19 
20 #include "cert_manager_api.h"
21 #include "cm_log.h"
22 #include "cm_mem.h"
23 #include "cm_type.h"
24 #include "cm_napi_common.h"
25 
26 namespace CMNapi {
27 namespace {
28 constexpr int CM_NAPI_INIT_ARGS_CNT = 3;
29 constexpr int CM_NAPI_UPDATE_ARGS_CNT = 3;
30 constexpr int CM_NAPI_FINISH_ARGS_CNT = 3;
31 constexpr int CM_NAPI_ABORT_ARGS_CNT = 2;
32 
33 constexpr int CM_NAPI_CALLBACK_ARG_CNT = 1;
34 constexpr int CM_NAPI_SIGNATURE_ARG_CNT = 1;
35 
36 constexpr uint32_t OUT_SIGNATURE_SIZE = 1000;
37 constexpr uint32_t OUT_HANLDE_SIZE = 8;
38 } // namespace
39 
40 struct SignVerifyAsyncContextT {
41     napi_async_work asyncWork = nullptr;
42     napi_deferred deferred = nullptr;
43     napi_ref callback = nullptr;
44 
45     int32_t errCode = 0;
46     bool isSign = false;
47     struct CmBlob *authUri = nullptr;
48     struct CmBlob *handle = nullptr;
49     struct CmBlob *inData = nullptr;
50     struct CmBlob *signature = nullptr;
51     struct CmSignatureSpec *spec = nullptr;
52 };
53 using SignVerifyAsyncContext = SignVerifyAsyncContextT *;
54 
InitSignVerifyAsyncContext(void)55 static SignVerifyAsyncContext InitSignVerifyAsyncContext(void)
56 {
57     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(CmMalloc(sizeof(SignVerifyAsyncContextT)));
58     if (context != nullptr) {
59         (void)memset_s(context, sizeof(SignVerifyAsyncContextT), 0, sizeof(SignVerifyAsyncContextT));
60     }
61     return context;
62 }
63 
FreeSignVerifyAsyncContext(napi_env env,SignVerifyAsyncContext & context)64 static void FreeSignVerifyAsyncContext(napi_env env, SignVerifyAsyncContext &context)
65 {
66     if (context == nullptr) {
67         return;
68     }
69 
70     DeleteNapiContext(env, context->asyncWork, context->callback);
71     FreeCmBlob(context->authUri);
72     FreeCmBlob(context->handle);
73     FreeCmBlob(context->inData);
74     FreeCmBlob(context->signature);
75     CM_FREE_PTR(context->spec);
76     CM_FREE_PTR(context);
77 }
78 
79 struct CmJSKeyPaddingCmKeyPaddingMap {
80     CmJSKeyPadding key;
81     CmKeyPadding retPadding;
82 };
83 
84 const struct CmJSKeyPaddingCmKeyPaddingMap PADDING_MAP[] = {
85     { CM_JS_PADDING_NONE, CM_PADDING_NONE },
86     { CM_JS_PADDING_PSS, CM_PADDING_PSS },
87     { CM_JS_PADDING_PKCS1_V1_5, CM_PADDING_PKCS1_V1_5 },
88 };
89 
90 struct CmJSKeyDigestCmKeyDigestMap {
91     CmJSKeyDigest key;
92     CmKeyDigest retDigest;
93 };
94 
95 const struct CmJSKeyDigestCmKeyDigestMap DIGEST_MAP[] = {
96     { CM_JS_DIGEST_NONE, CM_DIGEST_NONE },
97     { CM_JS_DIGEST_MD5, CM_DIGEST_MD5 },
98     { CM_JS_DIGEST_SHA1, CM_DIGEST_SHA1 },
99     { CM_JS_DIGEST_SHA224, CM_DIGEST_SHA224 },
100     { CM_JS_DIGEST_SHA256, CM_DIGEST_SHA256 },
101     { CM_JS_DIGEST_SHA384, CM_DIGEST_SHA384 },
102     { CM_JS_DIGEST_SHA512, CM_DIGEST_SHA512 },
103 };
104 
GetPadding(napi_env env,napi_value object,uint32_t * paddingRet)105 static napi_value GetPadding(napi_env env, napi_value object, uint32_t *paddingRet)
106 {
107     napi_value padding = nullptr;
108     napi_status status = napi_get_named_property(env, object, "padding", &padding);
109     if (status != napi_ok || padding == nullptr) {
110         CM_LOG_E("get padding failed");
111         return nullptr;
112     }
113 
114     napi_valuetype type = napi_undefined;
115     NAPI_CALL(env, napi_typeof(env, padding, &type));
116     if (type == napi_undefined) {
117         CM_LOG_D("padding is undefined, set padding value is default");
118         *paddingRet = CM_PADDING_PSS;
119         return GetInt32(env, 0);
120     }
121 
122     if (type != napi_number) {
123         ThrowParamsError(env, PARAM_ERROR, "arguments invalid, type of param padding is not number");
124         CM_LOG_E("arguments invalid, type of param padding is not number");
125         return nullptr;
126     }
127 
128     uint32_t paddingValue = 0;
129     status = napi_get_value_uint32(env, padding, &paddingValue);
130     if (status != napi_ok) {
131         CM_LOG_E("get padding value failed");
132         ThrowParamsError(env, PARAM_ERROR, "arguments invalid, get padding value failed");
133         return nullptr;
134     }
135 
136     bool findFlag = false;
137     for (uint32_t i = 0; i < (sizeof(PADDING_MAP) / sizeof(PADDING_MAP[0])); i++) {
138         if (paddingValue == PADDING_MAP[i].key) {
139             *paddingRet = PADDING_MAP[i].retPadding;
140             findFlag = true;
141             break;
142         }
143     }
144     if (!findFlag) {
145         ThrowParamsError(env, PARAM_ERROR, "padding do not exist in PADDING_MAP");
146         CM_LOG_E("padding do not exist in PADDING_MAP.");
147         return nullptr;
148     }
149 
150     return GetInt32(env, 0);
151 }
152 
GetDigest(napi_env env,napi_value object,uint32_t * digestRet)153 static napi_value GetDigest(napi_env env, napi_value object, uint32_t *digestRet)
154 {
155     napi_value digest = nullptr;
156     napi_status status = napi_get_named_property(env, object, "digest", &digest);
157     if (status != napi_ok || digest == nullptr) {
158         CM_LOG_E("get digest failed");
159         return nullptr;
160     }
161     napi_valuetype type = napi_undefined;
162     NAPI_CALL(env, napi_typeof(env, digest, &type));
163     if (type == napi_undefined) {
164         CM_LOG_D("digest is undefined, set digest value is default");
165         *digestRet = CM_DIGEST_SHA256;
166         return GetInt32(env, 0);
167     }
168 
169     if (type != napi_number) {
170         ThrowParamsError(env, PARAM_ERROR, "arguments invalid, type of param digest is not number");
171         CM_LOG_E("arguments invalid, type of param digest is not number.");
172         return nullptr;
173     }
174 
175     uint32_t digestValue = 0;
176     status = napi_get_value_uint32(env, digest, &digestValue);
177     if (status != napi_ok) {
178         ThrowParamsError(env, PARAM_ERROR, "arguments invalid, get digest value failed");
179         CM_LOG_E("arguments invalid,get digest value failed.");
180         return nullptr;
181     }
182     bool findFlag = false;
183     for (uint32_t i = 0; i < (sizeof(DIGEST_MAP) / sizeof(DIGEST_MAP[0])); i++) {
184         if (digestValue == DIGEST_MAP[i].key) {
185             *digestRet = DIGEST_MAP[i].retDigest;
186             findFlag = true;
187             break;
188         }
189     }
190     if (!findFlag) {
191         ThrowParamsError(env, PARAM_ERROR, "digest do not exist in DIGEST_MAP");
192         CM_LOG_E("digest do not exist in DIGEST_MAP.");
193         return nullptr;
194     }
195 
196     return GetInt32(env, 0);
197 }
198 
ParseSpec(napi_env env,napi_value object,CmSignatureSpec * & spec)199 static napi_value ParseSpec(napi_env env, napi_value object, CmSignatureSpec *&spec)
200 {
201     napi_valuetype type = napi_undefined;
202     NAPI_CALL(env, napi_typeof(env, object, &type));
203     if (type != napi_object) {
204         CM_LOG_E("type of param spec is not object");
205         return nullptr;
206     }
207 
208     napi_value purpose = nullptr;
209     napi_status status = napi_get_named_property(env, object, "purpose", &purpose);
210     if (status != napi_ok || purpose == nullptr) {
211         CM_LOG_E("get purpose failed");
212         return nullptr;
213     }
214 
215     NAPI_CALL(env, napi_typeof(env, purpose, &type));
216     if (type != napi_number) {
217         CM_LOG_E("type of param purpose is not number");
218         return nullptr;
219     }
220 
221     uint32_t purposeValue = 0;
222     status = napi_get_value_uint32(env, purpose, &purposeValue);
223     if (status != napi_ok) {
224         CM_LOG_E("get purpose value failed");
225         return nullptr;
226     }
227 
228     spec = static_cast<CmSignatureSpec *>(CmMalloc(sizeof(CmSignatureSpec)));
229     if (spec == nullptr) {
230         CM_LOG_E("malloc spec struct failed");
231         return nullptr;
232     }
233     spec->purpose = purposeValue;
234 
235     /* padding */
236     napi_value result = GetPadding(env, object, &spec->padding);
237     if (result == nullptr) {
238         CM_LOG_E("get padding failed when using GetPadding function");
239         CM_FREE_PTR(spec);
240         return nullptr;
241     }
242 
243     /* digest */
244     result = GetDigest(env, object, &spec->digest);
245     if (result == nullptr) {
246         CM_LOG_E("get digest failed when using GetDigest function");
247         CM_FREE_PTR(spec);
248         return nullptr;
249     }
250 
251     return GetInt32(env, 0);
252 }
253 
GetBlob(napi_env env,napi_value object,CmBlob * & blob)254 static napi_value GetBlob(napi_env env, napi_value object, CmBlob *&blob)
255 {
256     blob = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
257     if (blob == nullptr) {
258         CM_LOG_E("malloc blob failed");
259         return nullptr;
260     }
261     (void)memset_s(blob, sizeof(CmBlob), 0, sizeof(CmBlob));
262 
263     napi_value result = GetUint8Array(env, object, *blob);
264     if (result == nullptr) {
265         CM_LOG_E("parse blob data failed");
266         return nullptr;
267     }
268 
269     return GetInt32(env, 0);
270 }
271 
ParseCMInitParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)272 static napi_value ParseCMInitParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
273 {
274     size_t argc = CM_NAPI_INIT_ARGS_CNT;
275     napi_value argv[CM_NAPI_INIT_ARGS_CNT] = { nullptr };
276     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
277 
278     if ((argc != CM_NAPI_INIT_ARGS_CNT) && (argc != (CM_NAPI_INIT_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
279         ThrowParamsError(env, PARAM_ERROR, "init arguments count invalid");
280         CM_LOG_E("init arguments count is not expected");
281         return nullptr;
282     }
283 
284     size_t index = 0;
285     napi_value result = ParseString(env, argv[index], context->authUri);
286     if (result == nullptr) {
287         ThrowParamsError(env, PARAM_ERROR, "get authUri type error");
288         CM_LOG_E("get uri failed when using init function");
289         return nullptr;
290     }
291 
292     index++;
293     result = ParseSpec(env, argv[index], context->spec);
294     if (result == nullptr) {
295         ThrowParamsError(env, PARAM_ERROR, "get spec type error");
296         CM_LOG_E("get sepc failed when using init function");
297         return nullptr;
298     }
299 
300     index++;
301     if (index < argc) {
302         int32_t ret = GetCallback(env, argv[index], context->callback);
303         if (ret != CM_SUCCESS) {
304             ThrowParamsError(env, PARAM_ERROR, "Get callback type failed.");
305             CM_LOG_E("get callback function failed when using init function");
306             return nullptr;
307         }
308     }
309 
310     return GetInt32(env, 0);
311 }
312 
ParseCMUpdateParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)313 static napi_value ParseCMUpdateParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
314 {
315     size_t argc = CM_NAPI_UPDATE_ARGS_CNT;
316     napi_value argv[CM_NAPI_UPDATE_ARGS_CNT] = { nullptr };
317     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
318 
319     if ((argc != CM_NAPI_UPDATE_ARGS_CNT) && (argc != (CM_NAPI_UPDATE_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
320         ThrowParamsError(env, PARAM_ERROR, "update arguments count invalid");
321         CM_LOG_E("update arguments count is not expected");
322         return nullptr;
323     }
324 
325     size_t index = 0;
326     napi_value result = GetBlob(env, argv[index], context->handle);
327     if (result == nullptr) {
328         ThrowParamsError(env, PARAM_ERROR, "get handle type error");
329         CM_LOG_E("get handle failed when using update function");
330         return nullptr;
331     }
332 
333     index++;
334     result = GetBlob(env, argv[index], context->inData);
335     if (result == nullptr) {
336         ThrowParamsError(env, PARAM_ERROR, "get inData type error");
337         CM_LOG_E("get inData failed when using update function");
338         return nullptr;
339     }
340 
341     index++;
342     if (index < argc) {
343         int32_t ret = GetCallback(env, argv[index], context->callback);
344         if (ret != CM_SUCCESS) {
345             ThrowParamsError(env, PARAM_ERROR, "get callback type error");
346             CM_LOG_E("get callback function failed when using update function");
347             return nullptr;
348         }
349     }
350 
351     return GetInt32(env, 0);
352 }
353 
MallocFinishOutData(napi_env env,SignVerifyAsyncContext context)354 static napi_value MallocFinishOutData(napi_env env, SignVerifyAsyncContext context)
355 {
356     context->signature = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
357     if (context->signature == nullptr) { /* signature will free after all process */
358         CM_LOG_E("malloc outData failed when process sign finish");
359         ThrowParamsError(env, PARAM_ERROR, "malloc failed");
360         return nullptr;
361     }
362     (void)memset_s(context->signature, sizeof(CmBlob), 0, sizeof(CmBlob));
363 
364     uint8_t *data = static_cast<uint8_t *>(CmMalloc(OUT_SIGNATURE_SIZE));
365     if (data == nullptr) {
366         CM_LOG_E("malloc outData.data failed when process sign finish");
367         ThrowParamsError(env, PARAM_ERROR, "malloc failed");
368         return nullptr;
369     }
370     (void)memset_s(data, OUT_SIGNATURE_SIZE, 0, OUT_SIGNATURE_SIZE);
371 
372     context->signature->data = data;
373     context->signature->size = OUT_SIGNATURE_SIZE;
374     return GetInt32(env, 0);
375 }
376 
ProcessFinishOneParam(napi_env env,SignVerifyAsyncContext context)377 static napi_value ProcessFinishOneParam(napi_env env, SignVerifyAsyncContext context)
378 {
379     /* promise: sign */
380     context->isSign = true;
381     return MallocFinishOutData(env, context);
382 }
383 
CheckIsCallback(napi_env env,napi_value object,bool & isFunc)384 static int32_t CheckIsCallback(napi_env env, napi_value object, bool &isFunc)
385 {
386     isFunc = false;
387     napi_valuetype valueType = napi_undefined;
388     napi_status status = napi_typeof(env, object, &valueType);
389     if (status != napi_ok) {
390         CM_LOG_E("could not get object type");
391         return CMR_ERROR_INVALID_ARGUMENT;
392     }
393 
394     if (valueType == napi_function) {
395         isFunc = true;
396     }
397     return CM_SUCCESS;
398 }
399 
ProcessFinishTwoParam(napi_env env,napi_value * argv,SignVerifyAsyncContext context,size_t curIndex,size_t maxIndex)400 static napi_value ProcessFinishTwoParam(napi_env env, napi_value *argv, SignVerifyAsyncContext context,
401     size_t curIndex, size_t maxIndex)
402 {
403     curIndex++;
404     if (curIndex >= maxIndex) {
405         return nullptr; /* not possible */
406     }
407 
408     /*
409      * check wether arg 2 is callback: if true, get callback function and return: callback sign.
410      * else is promise verify, then get arg 2 as signature
411      */
412     bool isFunc = false;
413     int32_t ret = CheckIsCallback(env, argv[curIndex], isFunc);
414     if (ret != CM_SUCCESS) {
415         return nullptr;
416     }
417 
418     napi_value result = nullptr;
419     if (isFunc) {
420         /* callback: sign */
421         context->isSign = true;
422         result = MallocFinishOutData(env, context);
423         if (result == nullptr) {
424             return nullptr;
425         }
426 
427         ret = GetCallback(env, argv[curIndex], context->callback);
428         if (ret != CM_SUCCESS) {
429             ThrowParamsError(env, PARAM_ERROR, "Get callback type failed.");
430             CM_LOG_E("arg2 is callback: get sign callback function failed when using finish function");
431             return nullptr;
432         }
433 
434         return GetInt32(env, 0);
435     }
436 
437     /* promise verify */
438     context->isSign = false;
439     result = GetBlob(env, argv[curIndex], context->signature);
440     if (result == nullptr) {
441         ThrowParamsError(env, PARAM_ERROR, "get signature type error");
442         CM_LOG_E("get signature failed when process promise verify");
443         return nullptr;
444     }
445 
446     return GetInt32(env, 0);
447 }
448 
ProcessFinishThreeParam(napi_env env,napi_value * argv,SignVerifyAsyncContext context,size_t curIndex,size_t maxIndex)449 static napi_value ProcessFinishThreeParam(napi_env env, napi_value *argv, SignVerifyAsyncContext context,
450     size_t curIndex, size_t maxIndex)
451 {
452     /* callback: verify */
453     context->isSign = false;
454 
455     curIndex++;
456     if (curIndex >= maxIndex) {
457         return nullptr; /* not possible */
458     }
459 
460     napi_value result = GetBlob(env, argv[curIndex], context->signature);
461     if (result == nullptr) {
462         ThrowParamsError(env, PARAM_ERROR, "get signature type error");
463         CM_LOG_E("get signature failed when process callback verify");
464         return nullptr;
465     }
466 
467     curIndex++;
468     if (curIndex >= maxIndex) {
469         return nullptr; /* not possible */
470     }
471 
472     int32_t ret = GetCallback(env, argv[curIndex], context->callback);
473     if (ret != CM_SUCCESS) {
474         ThrowParamsError(env, PARAM_ERROR, "Get callback type failed.");
475         CM_LOG_E("get verify callback function failed when using finish function");
476         return nullptr;
477     }
478 
479     return GetInt32(env, 0);
480 }
481 
ParseCMFinishParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)482 static napi_value ParseCMFinishParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
483 {
484     size_t argc = CM_NAPI_FINISH_ARGS_CNT;
485     napi_value argv[CM_NAPI_FINISH_ARGS_CNT] = { nullptr };
486     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
487 
488     if ((argc != CM_NAPI_FINISH_ARGS_CNT) && (argc != (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT)) &&
489         (argc != (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT - CM_NAPI_SIGNATURE_ARG_CNT))) {
490         ThrowParamsError(env, PARAM_ERROR, "finish arguments count invalid");
491         CM_LOG_E("finish arguments count is not expected");
492         return nullptr;
493     }
494 
495     size_t index = 0;
496     napi_value result = GetBlob(env, argv[index], context->handle);
497     if (result == nullptr) {
498         ThrowParamsError(env, PARAM_ERROR, "get handle type error");
499         CM_LOG_E("get handle failed when using finish function");
500         return nullptr;
501     }
502 
503     if (argc == CM_NAPI_FINISH_ARGS_CNT) {
504         return ProcessFinishThreeParam(env, argv, context, index, argc);
505     } else if (argc == (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT)) {
506         return ProcessFinishTwoParam(env, argv, context, index, argc);
507     } else {
508  /* only this 3 types */
509         return ProcessFinishOneParam(env, context);
510     }
511 }
512 
ParseCMAbortParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)513 static napi_value ParseCMAbortParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
514 {
515     size_t argc = CM_NAPI_ABORT_ARGS_CNT;
516     napi_value argv[CM_NAPI_ABORT_ARGS_CNT] = { nullptr };
517     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
518 
519     if ((argc != CM_NAPI_ABORT_ARGS_CNT) && (argc != (CM_NAPI_ABORT_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
520         ThrowParamsError(env, PARAM_ERROR, "abort arguments count invalid");
521         CM_LOG_E("abort arguments count is not expected");
522         return nullptr;
523     }
524 
525     size_t index = 0;
526     napi_value result = GetBlob(env, argv[index], context->handle);
527     if (result == nullptr) {
528         ThrowParamsError(env, PARAM_ERROR, "get handle type error");
529         CM_LOG_E("get handle failed when using abort function");
530         return nullptr;
531     }
532 
533     index++;
534     if (index < argc) {
535         int32_t ret = GetCallback(env, argv[index], context->callback);
536         if (ret != CM_SUCCESS) {
537             ThrowParamsError(env, PARAM_ERROR, "get callback type failed.");
538             CM_LOG_E("get callback function failed when using abort function");
539             return nullptr;
540         }
541     }
542 
543     return GetInt32(env, 0);
544 }
545 
InitExecute(napi_env env,void * data)546 static void InitExecute(napi_env env, void *data)
547 {
548     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
549     context->handle = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
550     if (context->handle == nullptr) {
551         CM_LOG_E("malloc handle out failed");
552         context->errCode = CMR_ERROR_MALLOC_FAIL;
553         return;
554     }
555     (void)memset_s(context->handle, sizeof(CmBlob), 0, sizeof(CmBlob));
556 
557     context->handle->data = static_cast<uint8_t *>(CmMalloc(OUT_HANLDE_SIZE));
558     if (context->handle->data == nullptr) {
559         CM_LOG_E("malloc handle.data failed");
560         context->errCode = CMR_ERROR_MALLOC_FAIL;
561         return;
562     }
563     (void)memset_s(context->handle->data, OUT_HANLDE_SIZE, 0, OUT_HANLDE_SIZE);
564     context->handle->size = OUT_HANLDE_SIZE;
565 
566     context->errCode = CmInit(context->authUri, context->spec, context->handle);
567 }
568 
GenerateArrayBuffer(napi_env env,uint8_t * data,uint32_t size)569 static napi_value GenerateArrayBuffer(napi_env env, uint8_t *data, uint32_t size)
570 {
571     uint8_t *tempBuf = static_cast<uint8_t *>(CmMalloc(size));
572     if (tempBuf == nullptr) {
573         CM_LOG_E("malloc outbuf failed");
574         return nullptr;
575     }
576     (void)memcpy_s(tempBuf, size, data, size);
577 
578     napi_value outBuffer = nullptr;
579     napi_status status = napi_create_external_arraybuffer(
580         env, tempBuf, size, [](napi_env env, void *data, void *hint) { CmFree(data); }, nullptr, &outBuffer);
581     if (status == napi_ok) {
582         tempBuf = nullptr; /* free by finalize callback */
583     } else {
584         CM_LOG_E("create external array buffer failed");
585         CM_FREE_PTR(tempBuf);
586         GET_AND_THROW_LAST_ERROR((env));
587     }
588 
589     return outBuffer;
590 }
591 
ConvertResultHandle(napi_env env,const CmBlob * handle)592 static napi_value ConvertResultHandle(napi_env env, const CmBlob *handle)
593 {
594     napi_value result = nullptr;
595     NAPI_CALL(env, napi_create_object(env, &result));
596 
597     napi_value handleNapi = nullptr;
598     napi_value handleBuf = GenerateArrayBuffer(env, handle->data, handle->size);
599     if (handleBuf != nullptr) {
600         NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, handle->size, handleBuf, 0, &handleNapi));
601     } else {
602         handleNapi = GetNull(env);
603     }
604     NAPI_CALL(env, napi_set_named_property(env, result, "handle", handleNapi));
605 
606     return result;
607 }
608 
InitComplete(napi_env env,napi_status status,void * data)609 static void InitComplete(napi_env env, napi_status status, void *data)
610 {
611     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
612     napi_value result[RESULT_NUMBER] = { nullptr };
613     if (context->errCode == CM_SUCCESS) {
614         napi_create_uint32(env, 0, &result[0]);
615         result[1] = ConvertResultHandle(env, context->handle);
616     } else {
617         result[0] = GenerateBusinessError(env, context->errCode, "init failed");
618         napi_get_undefined(env, &result[1]);
619     }
620 
621     if (context->deferred != nullptr) {
622         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
623     } else {
624         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
625     }
626     FreeSignVerifyAsyncContext(env, context);
627 }
628 
UpdateExecute(napi_env env,void * data)629 static void UpdateExecute(napi_env env, void *data)
630 {
631     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
632     context->errCode = CmUpdate(context->handle, context->inData);
633 }
634 
UpdateOrAbortComplete(napi_env env,napi_status status,void * data)635 static void UpdateOrAbortComplete(napi_env env, napi_status status, void *data)
636 {
637     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
638     napi_value result[RESULT_NUMBER] = { nullptr };
639     if (context->errCode == CM_SUCCESS) {
640         napi_create_uint32(env, 0, &result[0]);
641         napi_get_undefined(env, &result[1]);
642     } else {
643         result[0] = GenerateBusinessError(env, context->errCode, "update or abort process failed");
644         napi_get_undefined(env, &result[1]);
645     }
646 
647     if (context->deferred != nullptr) {
648         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
649     } else {
650         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
651     }
652     FreeSignVerifyAsyncContext(env, context);
653 }
654 
FinishExecute(napi_env env,void * data)655 static void FinishExecute(napi_env env, void *data)
656 {
657     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
658     if (context->isSign) {
659         CmBlob inData = { 0, nullptr };
660         context->errCode = CmFinish(context->handle, &inData, context->signature);
661         return;
662     }
663 
664     CmBlob outData = { 0, nullptr };
665     context->errCode = CmFinish(context->handle, context->signature, &outData);
666 }
667 
ConvertResultSignature(napi_env env,bool isSign,const CmBlob * sign)668 static napi_value ConvertResultSignature(napi_env env, bool isSign, const CmBlob *sign)
669 {
670     napi_value result = nullptr;
671     NAPI_CALL(env, napi_create_object(env, &result));
672 
673     napi_value signResultNapi = nullptr;
674     if (isSign) {
675         napi_value signBuf = GenerateArrayBuffer(env, sign->data, sign->size);
676         if (signBuf != nullptr) {
677             NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, sign->size, signBuf, 0, &signResultNapi));
678         } else {
679             signResultNapi = GetNull(env);
680         }
681     } else {
682         signResultNapi = GetNull(env);
683     }
684     NAPI_CALL(env, napi_set_named_property(env, result, "outData", signResultNapi));
685 
686     return result;
687 }
688 
FinishComplete(napi_env env,napi_status status,void * data)689 static void FinishComplete(napi_env env, napi_status status, void *data)
690 {
691     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
692     napi_value result[RESULT_NUMBER] = { nullptr };
693     if (context->errCode == CM_SUCCESS) {
694         napi_create_uint32(env, 0, &result[0]);
695         result[1] = ConvertResultSignature(env, context->isSign, context->signature);
696     } else {
697         result[0] = GenerateBusinessError(env, context->errCode, "finish failed");
698         napi_get_undefined(env, &result[1]);
699     }
700 
701     if (context->deferred != nullptr) {
702         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
703     } else {
704         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
705     }
706     FreeSignVerifyAsyncContext(env, context);
707 }
708 
AbortExecute(napi_env env,void * data)709 static void AbortExecute(napi_env env, void *data)
710 {
711     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
712     context->errCode = CmAbort(context->handle);
713 }
714 
CMInitAsyncWork(napi_env env,SignVerifyAsyncContext context)715 static napi_value CMInitAsyncWork(napi_env env, SignVerifyAsyncContext context)
716 {
717     napi_value promise = nullptr;
718     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
719 
720     napi_value resourceName = nullptr;
721     NAPI_CALL(env, napi_create_string_latin1(env, "cminit", NAPI_AUTO_LENGTH, &resourceName));
722 
723     NAPI_CALL(env, napi_create_async_work(
724         env, nullptr, resourceName,
725         InitExecute,
726         InitComplete,
727         static_cast<void *>(context),
728         &context->asyncWork));
729 
730     napi_status status = napi_queue_async_work(env, context->asyncWork);
731     if (status != napi_ok) {
732         ThrowParamsError(env, PARAM_ERROR, "queue async work error");
733         CM_LOG_E("queue async work failed when using init function");
734         return nullptr;
735     }
736     return promise;
737 }
738 
CMUpdateAsyncWork(napi_env env,SignVerifyAsyncContext context)739 static napi_value CMUpdateAsyncWork(napi_env env, SignVerifyAsyncContext context)
740 {
741     napi_value promise = nullptr;
742     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
743 
744     napi_value resourceName = nullptr;
745     NAPI_CALL(env, napi_create_string_latin1(env, "cmupdate", NAPI_AUTO_LENGTH, &resourceName));
746 
747     NAPI_CALL(env, napi_create_async_work(
748         env, nullptr, resourceName,
749         UpdateExecute,
750         UpdateOrAbortComplete,
751         static_cast<void *>(context),
752         &context->asyncWork));
753 
754     napi_status status = napi_queue_async_work(env, context->asyncWork);
755     if (status != napi_ok) {
756         ThrowParamsError(env, PARAM_ERROR, "queue async work error");
757         CM_LOG_E("queue async work failed when using update function");
758         return nullptr;
759     }
760     return promise;
761 }
762 
CMFinishAsyncWork(napi_env env,SignVerifyAsyncContext context)763 static napi_value CMFinishAsyncWork(napi_env env, SignVerifyAsyncContext context)
764 {
765     napi_value promise = nullptr;
766     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
767 
768     napi_value resourceName = nullptr;
769     NAPI_CALL(env, napi_create_string_latin1(env, "cmfinish", NAPI_AUTO_LENGTH, &resourceName));
770 
771     NAPI_CALL(env, napi_create_async_work(
772         env, nullptr, resourceName,
773         FinishExecute,
774         FinishComplete,
775         static_cast<void *>(context),
776         &context->asyncWork));
777 
778     napi_status status = napi_queue_async_work(env, context->asyncWork);
779     if (status != napi_ok) {
780         ThrowParamsError(env, PARAM_ERROR, "queue async work error");
781         CM_LOG_E("queue async work failed when using finish function");
782         return nullptr;
783     }
784     return promise;
785 }
786 
CMAbortAsyncWork(napi_env env,SignVerifyAsyncContext context)787 static napi_value CMAbortAsyncWork(napi_env env, SignVerifyAsyncContext context)
788 {
789     napi_value promise = nullptr;
790     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
791 
792     napi_value resourceName = nullptr;
793     NAPI_CALL(env, napi_create_string_latin1(env, "cmabort", NAPI_AUTO_LENGTH, &resourceName));
794 
795     NAPI_CALL(env, napi_create_async_work(
796         env, nullptr, resourceName,
797         AbortExecute,
798         UpdateOrAbortComplete,
799         static_cast<void *>(context),
800         &context->asyncWork));
801 
802     napi_status status = napi_queue_async_work(env, context->asyncWork);
803     if (status != napi_ok) {
804         ThrowParamsError(env, PARAM_ERROR, "queue async work error");
805         CM_LOG_E("queue async work failed when using abort function");
806         return nullptr;
807     }
808     return promise;
809 }
810 
CMNapiInit(napi_env env,napi_callback_info info)811 napi_value CMNapiInit(napi_env env, napi_callback_info info)
812 {
813     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
814     if (context == nullptr) {
815         CM_LOG_E("init cm init context failed");
816         return nullptr;
817     }
818 
819     napi_value result = ParseCMInitParams(env, info, context);
820     if (result == nullptr) {
821         CM_LOG_E("parse cm init params failed");
822         FreeSignVerifyAsyncContext(env, context);
823         return nullptr;
824     }
825 
826     result = CMInitAsyncWork(env, context);
827     if (result == nullptr) {
828         CM_LOG_E("start cm init async work failed");
829         FreeSignVerifyAsyncContext(env, context);
830         return nullptr;
831     }
832 
833     return result;
834 }
835 
CMNapiUpdate(napi_env env,napi_callback_info info)836 napi_value CMNapiUpdate(napi_env env, napi_callback_info info)
837 {
838     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
839     if (context == nullptr) {
840         CM_LOG_E("init cm update context failed");
841         return nullptr;
842     }
843 
844     napi_value result = ParseCMUpdateParams(env, info, context);
845     if (result == nullptr) {
846         CM_LOG_E("parse cm update params failed");
847         FreeSignVerifyAsyncContext(env, context);
848         return nullptr;
849     }
850 
851     result = CMUpdateAsyncWork(env, context);
852     if (result == nullptr) {
853         CM_LOG_E("start cm update async work failed");
854         FreeSignVerifyAsyncContext(env, context);
855         return nullptr;
856     }
857 
858     return result;
859 }
860 
CMNapiFinish(napi_env env,napi_callback_info info)861 napi_value CMNapiFinish(napi_env env, napi_callback_info info)
862 {
863     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
864     if (context == nullptr) {
865         CM_LOG_E("init cm finish context failed");
866         return nullptr;
867     }
868 
869     napi_value result = ParseCMFinishParams(env, info, context);
870     if (result == nullptr) {
871         CM_LOG_E("parse cm finish params failed");
872         FreeSignVerifyAsyncContext(env, context);
873         return nullptr;
874     }
875 
876     result = CMFinishAsyncWork(env, context);
877     if (result == nullptr) {
878         CM_LOG_E("start cm finish async work failed");
879         FreeSignVerifyAsyncContext(env, context);
880         return nullptr;
881     }
882 
883     return result;
884 }
885 
CMNapiAbort(napi_env env,napi_callback_info info)886 napi_value CMNapiAbort(napi_env env, napi_callback_info info)
887 {
888     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
889     if (context == nullptr) {
890         CM_LOG_E("init cm abort context failed");
891         return nullptr;
892     }
893 
894     napi_value result = ParseCMAbortParams(env, info, context);
895     if (result == nullptr) {
896         CM_LOG_E("parse cm abort params failed");
897         FreeSignVerifyAsyncContext(env, context);
898         return nullptr;
899     }
900 
901     result = CMAbortAsyncWork(env, context);
902     if (result == nullptr) {
903         CM_LOG_E("start cm abort async work failed");
904         FreeSignVerifyAsyncContext(env, context);
905         return nullptr;
906     }
907 
908     return result;
909 }
910 }  // namespace CMNapi
911 
912