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         ThrowError(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         ThrowError(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         ThrowError(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         ThrowError(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         ThrowError(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         ThrowError(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         ThrowError(env, PARAM_ERROR, "init arguments count invalid, arguments count need between 2 and 3.");
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         ThrowError(env, PARAM_ERROR, "authUri is not a string or the length is 0 or too long.");
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         ThrowError(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             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
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         ThrowError(env, PARAM_ERROR, "update arguments count invalid, arguments count need between 2 and 3.");
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         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
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         ThrowError(env, PARAM_ERROR, "inData is not a uint8Array or the length is 0 or too long.");
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             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
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         ThrowError(env, INNER_FAILURE, "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         ThrowError(env, INNER_FAILURE, "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             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
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         ThrowError(env, PARAM_ERROR, "signature is not a uint8Array or the length is 0 or too long.");
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         ThrowError(env, PARAM_ERROR, "signature is not a uint8Array or the length is 0 or too long.");
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         ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
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         ThrowError(env, PARAM_ERROR, "finish arguments count invalid, arguments count need between 1 and 3.");
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         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
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 { /* only three types */
508         return ProcessFinishOneParam(env, context);
509     }
510 }
511 
ParseCMAbortParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)512 static napi_value ParseCMAbortParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
513 {
514     size_t argc = CM_NAPI_ABORT_ARGS_CNT;
515     napi_value argv[CM_NAPI_ABORT_ARGS_CNT] = { nullptr };
516     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
517 
518     if ((argc != CM_NAPI_ABORT_ARGS_CNT) && (argc != (CM_NAPI_ABORT_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
519         ThrowError(env, PARAM_ERROR, "abort arguments count invalid, arguments count need between 1 and 2.");
520         CM_LOG_E("abort arguments count is not expected");
521         return nullptr;
522     }
523 
524     size_t index = 0;
525     napi_value result = GetBlob(env, argv[index], context->handle);
526     if (result == nullptr) {
527         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
528         CM_LOG_E("get handle failed when using abort function");
529         return nullptr;
530     }
531 
532     index++;
533     if (index < argc) {
534         int32_t ret = GetCallback(env, argv[index], context->callback);
535         if (ret != CM_SUCCESS) {
536             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
537             CM_LOG_E("get callback function failed when using abort function");
538             return nullptr;
539         }
540     }
541 
542     return GetInt32(env, 0);
543 }
544 
InitExecute(napi_env env,void * data)545 static void InitExecute(napi_env env, void *data)
546 {
547     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
548     context->handle = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
549     if (context->handle == nullptr) {
550         CM_LOG_E("malloc handle out failed");
551         context->errCode = CMR_ERROR_MALLOC_FAIL;
552         return;
553     }
554     (void)memset_s(context->handle, sizeof(CmBlob), 0, sizeof(CmBlob));
555 
556     context->handle->data = static_cast<uint8_t *>(CmMalloc(OUT_HANLDE_SIZE));
557     if (context->handle->data == nullptr) {
558         CM_LOG_E("malloc handle.data failed");
559         context->errCode = CMR_ERROR_MALLOC_FAIL;
560         return;
561     }
562     (void)memset_s(context->handle->data, OUT_HANLDE_SIZE, 0, OUT_HANLDE_SIZE);
563     context->handle->size = OUT_HANLDE_SIZE;
564 
565     context->errCode = CmInit(context->authUri, context->spec, context->handle);
566 }
567 
GenerateArrayBuffer(napi_env env,uint8_t * data,uint32_t size)568 static napi_value GenerateArrayBuffer(napi_env env, uint8_t *data, uint32_t size)
569 {
570     uint8_t *tempBuf = static_cast<uint8_t *>(CmMalloc(size));
571     if (tempBuf == nullptr) {
572         CM_LOG_E("malloc outbuf failed");
573         return nullptr;
574     }
575     (void)memcpy_s(tempBuf, size, data, size);
576 
577     napi_value outBuffer = nullptr;
578     napi_status status = napi_create_external_arraybuffer(
579         env, tempBuf, size, [](napi_env env, void *data, void *hint) { CmFree(data); }, nullptr, &outBuffer);
580     if (status == napi_ok) {
581         tempBuf = nullptr; /* free by finalize callback */
582     } else {
583         CM_LOG_E("create external array buffer failed");
584         CM_FREE_PTR(tempBuf);
585         GET_AND_THROW_LAST_ERROR((env));
586     }
587 
588     return outBuffer;
589 }
590 
ConvertResultHandle(napi_env env,const CmBlob * handle)591 static napi_value ConvertResultHandle(napi_env env, const CmBlob *handle)
592 {
593     napi_value result = nullptr;
594     NAPI_CALL(env, napi_create_object(env, &result));
595 
596     napi_value handleNapi = nullptr;
597     napi_value handleBuf = GenerateArrayBuffer(env, handle->data, handle->size);
598     if (handleBuf != nullptr) {
599         NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, handle->size, handleBuf, 0, &handleNapi));
600     } else {
601         handleNapi = GetNull(env);
602     }
603     NAPI_CALL(env, napi_set_named_property(env, result, "handle", handleNapi));
604 
605     return result;
606 }
607 
InitComplete(napi_env env,napi_status status,void * data)608 static void InitComplete(napi_env env, napi_status status, void *data)
609 {
610     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
611     napi_value result[RESULT_NUMBER] = { nullptr };
612     if (context->errCode == CM_SUCCESS) {
613         napi_create_uint32(env, 0, &result[0]);
614         result[1] = ConvertResultHandle(env, context->handle);
615     } else {
616         result[0] = GenerateBusinessError(env, context->errCode);
617         napi_get_undefined(env, &result[1]);
618     }
619 
620     if (context->deferred != nullptr) {
621         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
622     } else {
623         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
624     }
625     FreeSignVerifyAsyncContext(env, context);
626 }
627 
UpdateExecute(napi_env env,void * data)628 static void UpdateExecute(napi_env env, void *data)
629 {
630     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
631     context->errCode = CmUpdate(context->handle, context->inData);
632 }
633 
UpdateOrAbortComplete(napi_env env,napi_status status,void * data)634 static void UpdateOrAbortComplete(napi_env env, napi_status status, void *data)
635 {
636     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
637     napi_value result[RESULT_NUMBER] = { nullptr };
638     if (context->errCode == CM_SUCCESS) {
639         napi_create_uint32(env, 0, &result[0]);
640         napi_get_undefined(env, &result[1]);
641     } else {
642         result[0] = GenerateBusinessError(env, context->errCode);
643         napi_get_undefined(env, &result[1]);
644     }
645 
646     if (context->deferred != nullptr) {
647         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
648     } else {
649         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
650     }
651     FreeSignVerifyAsyncContext(env, context);
652 }
653 
FinishExecute(napi_env env,void * data)654 static void FinishExecute(napi_env env, void *data)
655 {
656     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
657     if (context->isSign) {
658         CmBlob inData = { 0, nullptr };
659         context->errCode = CmFinish(context->handle, &inData, context->signature);
660         return;
661     }
662 
663     CmBlob outData = { 0, nullptr };
664     context->errCode = CmFinish(context->handle, context->signature, &outData);
665 }
666 
ConvertResultSignature(napi_env env,bool isSign,const CmBlob * sign)667 static napi_value ConvertResultSignature(napi_env env, bool isSign, const CmBlob *sign)
668 {
669     napi_value result = nullptr;
670     NAPI_CALL(env, napi_create_object(env, &result));
671 
672     napi_value signResultNapi = nullptr;
673     if (isSign) {
674         napi_value signBuf = GenerateArrayBuffer(env, sign->data, sign->size);
675         if (signBuf != nullptr) {
676             NAPI_CALL(env, napi_create_typedarray(env, napi_uint8_array, sign->size, signBuf, 0, &signResultNapi));
677         } else {
678             signResultNapi = GetNull(env);
679         }
680     } else {
681         signResultNapi = GetNull(env);
682     }
683     NAPI_CALL(env, napi_set_named_property(env, result, "outData", signResultNapi));
684 
685     return result;
686 }
687 
FinishComplete(napi_env env,napi_status status,void * data)688 static void FinishComplete(napi_env env, napi_status status, void *data)
689 {
690     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
691     napi_value result[RESULT_NUMBER] = { nullptr };
692     if (context->errCode == CM_SUCCESS) {
693         napi_create_uint32(env, 0, &result[0]);
694         result[1] = ConvertResultSignature(env, context->isSign, context->signature);
695     } else {
696         result[0] = GenerateBusinessError(env, context->errCode);
697         napi_get_undefined(env, &result[1]);
698     }
699 
700     if (context->deferred != nullptr) {
701         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
702     } else {
703         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
704     }
705     FreeSignVerifyAsyncContext(env, context);
706 }
707 
AbortExecute(napi_env env,void * data)708 static void AbortExecute(napi_env env, void *data)
709 {
710     SignVerifyAsyncContext context = static_cast<SignVerifyAsyncContext>(data);
711     context->errCode = CmAbort(context->handle);
712 }
713 
CMInitAsyncWork(napi_env env,SignVerifyAsyncContext context)714 static napi_value CMInitAsyncWork(napi_env env, SignVerifyAsyncContext context)
715 {
716     napi_value promise = nullptr;
717     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
718 
719     napi_value resourceName = nullptr;
720     NAPI_CALL(env, napi_create_string_latin1(env, "cminit", NAPI_AUTO_LENGTH, &resourceName));
721 
722     NAPI_CALL(env, napi_create_async_work(
723         env, nullptr, resourceName,
724         InitExecute,
725         InitComplete,
726         static_cast<void *>(context),
727         &context->asyncWork));
728 
729     napi_status status = napi_queue_async_work(env, context->asyncWork);
730     if (status != napi_ok) {
731         ThrowError(env, PARAM_ERROR, "queue async work error");
732         CM_LOG_E("queue async work failed when using init function");
733         return nullptr;
734     }
735     return promise;
736 }
737 
CMUpdateAsyncWork(napi_env env,SignVerifyAsyncContext context)738 static napi_value CMUpdateAsyncWork(napi_env env, SignVerifyAsyncContext context)
739 {
740     napi_value promise = nullptr;
741     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
742 
743     napi_value resourceName = nullptr;
744     NAPI_CALL(env, napi_create_string_latin1(env, "cmupdate", NAPI_AUTO_LENGTH, &resourceName));
745 
746     NAPI_CALL(env, napi_create_async_work(
747         env, nullptr, resourceName,
748         UpdateExecute,
749         UpdateOrAbortComplete,
750         static_cast<void *>(context),
751         &context->asyncWork));
752 
753     napi_status status = napi_queue_async_work(env, context->asyncWork);
754     if (status != napi_ok) {
755         ThrowError(env, PARAM_ERROR, "queue async work error");
756         CM_LOG_E("queue async work failed when using update function");
757         return nullptr;
758     }
759     return promise;
760 }
761 
CMFinishAsyncWork(napi_env env,SignVerifyAsyncContext context)762 static napi_value CMFinishAsyncWork(napi_env env, SignVerifyAsyncContext context)
763 {
764     napi_value promise = nullptr;
765     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
766 
767     napi_value resourceName = nullptr;
768     NAPI_CALL(env, napi_create_string_latin1(env, "cmfinish", NAPI_AUTO_LENGTH, &resourceName));
769 
770     NAPI_CALL(env, napi_create_async_work(
771         env, nullptr, resourceName,
772         FinishExecute,
773         FinishComplete,
774         static_cast<void *>(context),
775         &context->asyncWork));
776 
777     napi_status status = napi_queue_async_work(env, context->asyncWork);
778     if (status != napi_ok) {
779         ThrowError(env, PARAM_ERROR, "queue async work error");
780         CM_LOG_E("queue async work failed when using finish function");
781         return nullptr;
782     }
783     return promise;
784 }
785 
CMAbortAsyncWork(napi_env env,SignVerifyAsyncContext context)786 static napi_value CMAbortAsyncWork(napi_env env, SignVerifyAsyncContext context)
787 {
788     napi_value promise = nullptr;
789     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
790 
791     napi_value resourceName = nullptr;
792     NAPI_CALL(env, napi_create_string_latin1(env, "cmabort", NAPI_AUTO_LENGTH, &resourceName));
793 
794     NAPI_CALL(env, napi_create_async_work(
795         env, nullptr, resourceName,
796         AbortExecute,
797         UpdateOrAbortComplete,
798         static_cast<void *>(context),
799         &context->asyncWork));
800 
801     napi_status status = napi_queue_async_work(env, context->asyncWork);
802     if (status != napi_ok) {
803         ThrowError(env, PARAM_ERROR, "queue async work error");
804         CM_LOG_E("queue async work failed when using abort function");
805         return nullptr;
806     }
807     return promise;
808 }
809 
CMNapiInit(napi_env env,napi_callback_info info)810 napi_value CMNapiInit(napi_env env, napi_callback_info info)
811 {
812     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
813     if (context == nullptr) {
814         CM_LOG_E("init cm init context failed");
815         return nullptr;
816     }
817 
818     napi_value result = ParseCMInitParams(env, info, context);
819     if (result == nullptr) {
820         CM_LOG_E("parse cm init params failed");
821         FreeSignVerifyAsyncContext(env, context);
822         return nullptr;
823     }
824 
825     result = CMInitAsyncWork(env, context);
826     if (result == nullptr) {
827         CM_LOG_E("start cm init async work failed");
828         FreeSignVerifyAsyncContext(env, context);
829         return nullptr;
830     }
831 
832     return result;
833 }
834 
CMNapiUpdate(napi_env env,napi_callback_info info)835 napi_value CMNapiUpdate(napi_env env, napi_callback_info info)
836 {
837     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
838     if (context == nullptr) {
839         CM_LOG_E("init cm update context failed");
840         return nullptr;
841     }
842 
843     napi_value result = ParseCMUpdateParams(env, info, context);
844     if (result == nullptr) {
845         CM_LOG_E("parse cm update params failed");
846         FreeSignVerifyAsyncContext(env, context);
847         return nullptr;
848     }
849 
850     result = CMUpdateAsyncWork(env, context);
851     if (result == nullptr) {
852         CM_LOG_E("start cm update async work failed");
853         FreeSignVerifyAsyncContext(env, context);
854         return nullptr;
855     }
856 
857     return result;
858 }
859 
CMNapiFinish(napi_env env,napi_callback_info info)860 napi_value CMNapiFinish(napi_env env, napi_callback_info info)
861 {
862     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
863     if (context == nullptr) {
864         CM_LOG_E("init cm finish context failed");
865         return nullptr;
866     }
867 
868     napi_value result = ParseCMFinishParams(env, info, context);
869     if (result == nullptr) {
870         CM_LOG_E("parse cm finish params failed");
871         FreeSignVerifyAsyncContext(env, context);
872         return nullptr;
873     }
874 
875     result = CMFinishAsyncWork(env, context);
876     if (result == nullptr) {
877         CM_LOG_E("start cm finish async work failed");
878         FreeSignVerifyAsyncContext(env, context);
879         return nullptr;
880     }
881 
882     return result;
883 }
884 
CMNapiAbort(napi_env env,napi_callback_info info)885 napi_value CMNapiAbort(napi_env env, napi_callback_info info)
886 {
887     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
888     if (context == nullptr) {
889         CM_LOG_E("init cm abort context failed");
890         return nullptr;
891     }
892 
893     napi_value result = ParseCMAbortParams(env, info, context);
894     if (result == nullptr) {
895         CM_LOG_E("parse cm abort params failed");
896         FreeSignVerifyAsyncContext(env, context);
897         return nullptr;
898     }
899 
900     result = CMAbortAsyncWork(env, context);
901     if (result == nullptr) {
902         CM_LOG_E("start cm abort async work failed");
903         FreeSignVerifyAsyncContext(env, context);
904         return nullptr;
905     }
906 
907     return result;
908 }
909 }  // namespace CMNapi
910 
911