• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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     { CM_JS_DIGEST_SM3, CM_DIGEST_SM3 },
104 };
105 
GetPadding(napi_env env,napi_value object,uint32_t * paddingRet)106 static napi_value GetPadding(napi_env env, napi_value object, uint32_t *paddingRet)
107 {
108     napi_value padding = nullptr;
109     napi_status status = napi_get_named_property(env, object, "padding", &padding);
110     if (status != napi_ok || padding == nullptr) {
111         CM_LOG_E("get padding failed");
112         return nullptr;
113     }
114 
115     napi_valuetype type = napi_undefined;
116     NAPI_CALL(env, napi_typeof(env, padding, &type));
117     if (type == napi_undefined) {
118         CM_LOG_D("padding is undefined, set padding value is default");
119         *paddingRet = CM_PADDING_PSS;
120         return GetInt32(env, 0);
121     }
122 
123     if (type != napi_number) {
124         ThrowError(env, PARAM_ERROR, "arguments invalid, type of param padding is not number");
125         CM_LOG_E("arguments invalid, type of param padding is not number");
126         return nullptr;
127     }
128 
129     uint32_t paddingValue = 0;
130     status = napi_get_value_uint32(env, padding, &paddingValue);
131     if (status != napi_ok) {
132         CM_LOG_E("get padding value failed");
133         ThrowError(env, PARAM_ERROR, "arguments invalid, get padding value failed");
134         return nullptr;
135     }
136 
137     bool findFlag = false;
138     for (uint32_t i = 0; i < (sizeof(PADDING_MAP) / sizeof(PADDING_MAP[0])); i++) {
139         if (paddingValue == PADDING_MAP[i].key) {
140             *paddingRet = PADDING_MAP[i].retPadding;
141             findFlag = true;
142             break;
143         }
144     }
145     if (!findFlag) {
146         ThrowError(env, PARAM_ERROR, "padding do not exist in PADDING_MAP");
147         CM_LOG_E("padding do not exist in PADDING_MAP.");
148         return nullptr;
149     }
150 
151     return GetInt32(env, 0);
152 }
153 
GetDigest(napi_env env,napi_value object,uint32_t * digestRet)154 static napi_value GetDigest(napi_env env, napi_value object, uint32_t *digestRet)
155 {
156     napi_value digest = nullptr;
157     napi_status status = napi_get_named_property(env, object, "digest", &digest);
158     if (status != napi_ok || digest == nullptr) {
159         CM_LOG_E("get digest failed");
160         return nullptr;
161     }
162     napi_valuetype type = napi_undefined;
163     NAPI_CALL(env, napi_typeof(env, digest, &type));
164     if (type == napi_undefined) {
165         CM_LOG_D("digest is undefined, set digest value is default");
166         *digestRet = CM_DIGEST_SHA256;
167         return GetInt32(env, 0);
168     }
169 
170     if (type != napi_number) {
171         ThrowError(env, PARAM_ERROR, "arguments invalid, type of param digest is not number");
172         CM_LOG_E("arguments invalid, type of param digest is not number.");
173         return nullptr;
174     }
175 
176     uint32_t digestValue = 0;
177     status = napi_get_value_uint32(env, digest, &digestValue);
178     if (status != napi_ok) {
179         ThrowError(env, PARAM_ERROR, "arguments invalid, get digest value failed");
180         CM_LOG_E("arguments invalid,get digest value failed.");
181         return nullptr;
182     }
183     bool findFlag = false;
184     for (uint32_t i = 0; i < (sizeof(DIGEST_MAP) / sizeof(DIGEST_MAP[0])); i++) {
185         if (digestValue == DIGEST_MAP[i].key) {
186             *digestRet = DIGEST_MAP[i].retDigest;
187             findFlag = true;
188             break;
189         }
190     }
191     if (!findFlag) {
192         ThrowError(env, PARAM_ERROR, "digest do not exist in DIGEST_MAP");
193         CM_LOG_E("digest do not exist in DIGEST_MAP.");
194         return nullptr;
195     }
196 
197     return GetInt32(env, 0);
198 }
199 
ParseSpec(napi_env env,napi_value object,CmSignatureSpec * & spec)200 static napi_value ParseSpec(napi_env env, napi_value object, CmSignatureSpec *&spec)
201 {
202     napi_valuetype type = napi_undefined;
203     NAPI_CALL(env, napi_typeof(env, object, &type));
204     if (type != napi_object) {
205         CM_LOG_E("type of param spec is not object");
206         return nullptr;
207     }
208 
209     napi_value purpose = nullptr;
210     napi_status status = napi_get_named_property(env, object, "purpose", &purpose);
211     if (status != napi_ok || purpose == nullptr) {
212         CM_LOG_E("get purpose failed");
213         return nullptr;
214     }
215 
216     NAPI_CALL(env, napi_typeof(env, purpose, &type));
217     if (type != napi_number) {
218         CM_LOG_E("type of param purpose is not number");
219         return nullptr;
220     }
221 
222     uint32_t purposeValue = 0;
223     status = napi_get_value_uint32(env, purpose, &purposeValue);
224     if (status != napi_ok) {
225         CM_LOG_E("get purpose value failed");
226         return nullptr;
227     }
228 
229     spec = static_cast<CmSignatureSpec *>(CmMalloc(sizeof(CmSignatureSpec)));
230     if (spec == nullptr) {
231         CM_LOG_E("malloc spec struct failed");
232         return nullptr;
233     }
234     spec->purpose = purposeValue;
235 
236     /* padding */
237     napi_value result = GetPadding(env, object, &spec->padding);
238     if (result == nullptr) {
239         CM_LOG_E("get padding failed when using GetPadding function");
240         CM_FREE_PTR(spec);
241         return nullptr;
242     }
243 
244     /* digest */
245     result = GetDigest(env, object, &spec->digest);
246     if (result == nullptr) {
247         CM_LOG_E("get digest failed when using GetDigest function");
248         CM_FREE_PTR(spec);
249         return nullptr;
250     }
251 
252     return GetInt32(env, 0);
253 }
254 
GetBlob(napi_env env,napi_value object,CmBlob * & blob)255 static napi_value GetBlob(napi_env env, napi_value object, CmBlob *&blob)
256 {
257     blob = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
258     if (blob == nullptr) {
259         CM_LOG_E("malloc blob failed");
260         return nullptr;
261     }
262     (void)memset_s(blob, sizeof(CmBlob), 0, sizeof(CmBlob));
263 
264     napi_value result = GetUint8Array(env, object, *blob);
265     if (result == nullptr) {
266         CM_LOG_E("parse blob data failed");
267         return nullptr;
268     }
269 
270     return GetInt32(env, 0);
271 }
272 
ParseCMInitParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)273 static napi_value ParseCMInitParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
274 {
275     size_t argc = CM_NAPI_INIT_ARGS_CNT;
276     napi_value argv[CM_NAPI_INIT_ARGS_CNT] = { nullptr };
277     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
278 
279     if ((argc != CM_NAPI_INIT_ARGS_CNT) && (argc != (CM_NAPI_INIT_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
280         ThrowError(env, PARAM_ERROR, "init arguments count invalid, arguments count need between 2 and 3.");
281         CM_LOG_E("init arguments count is not expected");
282         return nullptr;
283     }
284 
285     size_t index = 0;
286     napi_value result = ParseString(env, argv[index], context->authUri);
287     if (result == nullptr) {
288         ThrowError(env, PARAM_ERROR, "authUri is not a string or the length is 0 or too long.");
289         CM_LOG_E("get uri failed when using init function");
290         return nullptr;
291     }
292 
293     index++;
294     result = ParseSpec(env, argv[index], context->spec);
295     if (result == nullptr) {
296         ThrowError(env, PARAM_ERROR, "get spec type error");
297         CM_LOG_E("get sepc failed when using init function");
298         return nullptr;
299     }
300 
301     index++;
302     if (index < argc) {
303         int32_t ret = GetCallback(env, argv[index], context->callback);
304         if (ret != CM_SUCCESS) {
305             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
306             CM_LOG_E("get callback function failed when using init function");
307             return nullptr;
308         }
309     }
310 
311     return GetInt32(env, 0);
312 }
313 
ParseCMUpdateParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)314 static napi_value ParseCMUpdateParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
315 {
316     size_t argc = CM_NAPI_UPDATE_ARGS_CNT;
317     napi_value argv[CM_NAPI_UPDATE_ARGS_CNT] = { nullptr };
318     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
319 
320     if ((argc != CM_NAPI_UPDATE_ARGS_CNT) && (argc != (CM_NAPI_UPDATE_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
321         ThrowError(env, PARAM_ERROR, "update arguments count invalid, arguments count need between 2 and 3.");
322         CM_LOG_E("update arguments count is not expected");
323         return nullptr;
324     }
325 
326     size_t index = 0;
327     napi_value result = GetBlob(env, argv[index], context->handle);
328     if (result == nullptr) {
329         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
330         CM_LOG_E("get handle failed when using update function");
331         return nullptr;
332     }
333 
334     index++;
335     result = GetBlob(env, argv[index], context->inData);
336     if (result == nullptr) {
337         ThrowError(env, PARAM_ERROR, "inData is not a uint8Array or the length is 0 or too long.");
338         CM_LOG_E("get inData failed when using update function");
339         return nullptr;
340     }
341 
342     index++;
343     if (index < argc) {
344         int32_t ret = GetCallback(env, argv[index], context->callback);
345         if (ret != CM_SUCCESS) {
346             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
347             CM_LOG_E("get callback function failed when using update function");
348             return nullptr;
349         }
350     }
351 
352     return GetInt32(env, 0);
353 }
354 
MallocFinishOutData(napi_env env,SignVerifyAsyncContext context)355 static napi_value MallocFinishOutData(napi_env env, SignVerifyAsyncContext context)
356 {
357     context->signature = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
358     if (context->signature == nullptr) { /* signature will free after all process */
359         CM_LOG_E("malloc outData failed when process sign finish");
360         ThrowError(env, INNER_FAILURE, GENERIC_MSG);
361         return nullptr;
362     }
363     (void)memset_s(context->signature, sizeof(CmBlob), 0, sizeof(CmBlob));
364 
365     uint8_t *data = static_cast<uint8_t *>(CmMalloc(OUT_SIGNATURE_SIZE));
366     if (data == nullptr) {
367         CM_LOG_E("malloc outData.data failed when process sign finish");
368         ThrowError(env, INNER_FAILURE, GENERIC_MSG);
369         return nullptr;
370     }
371     (void)memset_s(data, OUT_SIGNATURE_SIZE, 0, OUT_SIGNATURE_SIZE);
372 
373     context->signature->data = data;
374     context->signature->size = OUT_SIGNATURE_SIZE;
375     return GetInt32(env, 0);
376 }
377 
ProcessFinishOneParam(napi_env env,SignVerifyAsyncContext context)378 static napi_value ProcessFinishOneParam(napi_env env, SignVerifyAsyncContext context)
379 {
380     /* promise: sign */
381     context->isSign = true;
382     return MallocFinishOutData(env, context);
383 }
384 
CheckIsCallback(napi_env env,napi_value object,bool & isFunc)385 static int32_t CheckIsCallback(napi_env env, napi_value object, bool &isFunc)
386 {
387     isFunc = false;
388     napi_valuetype valueType = napi_undefined;
389     napi_status status = napi_typeof(env, object, &valueType);
390     if (status != napi_ok) {
391         CM_LOG_E("could not get object type");
392         return CMR_ERROR_INVALID_ARGUMENT;
393     }
394 
395     if (valueType == napi_function) {
396         isFunc = true;
397     }
398     return CM_SUCCESS;
399 }
400 
ProcessFinishTwoParam(napi_env env,napi_value * argv,SignVerifyAsyncContext context,size_t curIndex,size_t maxIndex)401 static napi_value ProcessFinishTwoParam(napi_env env, napi_value *argv, SignVerifyAsyncContext context,
402     size_t curIndex, size_t maxIndex)
403 {
404     curIndex++;
405     if (curIndex >= maxIndex) {
406         return nullptr; /* not possible */
407     }
408 
409     /*
410      * check wether arg 2 is callback: if true, get callback function and return: callback sign.
411      * else is promise verify, then get arg 2 as signature
412      */
413     bool isFunc = false;
414     int32_t ret = CheckIsCallback(env, argv[curIndex], isFunc);
415     if (ret != CM_SUCCESS) {
416         return nullptr;
417     }
418 
419     napi_value result = nullptr;
420     if (isFunc) {
421         /* callback: sign */
422         context->isSign = true;
423         result = MallocFinishOutData(env, context);
424         if (result == nullptr) {
425             return nullptr;
426         }
427 
428         ret = GetCallback(env, argv[curIndex], context->callback);
429         if (ret != CM_SUCCESS) {
430             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
431             CM_LOG_E("arg2 is callback: get sign callback function failed when using finish function");
432             return nullptr;
433         }
434 
435         return GetInt32(env, 0);
436     }
437 
438     /* promise verify */
439     context->isSign = false;
440     result = GetBlob(env, argv[curIndex], context->signature);
441     if (result == nullptr) {
442         ThrowError(env, PARAM_ERROR, "signature is not a uint8Array or the length is 0 or too long.");
443         CM_LOG_E("get signature failed when process promise verify");
444         return nullptr;
445     }
446 
447     return GetInt32(env, 0);
448 }
449 
ProcessFinishThreeParam(napi_env env,napi_value * argv,SignVerifyAsyncContext context,size_t curIndex,size_t maxIndex)450 static napi_value ProcessFinishThreeParam(napi_env env, napi_value *argv, SignVerifyAsyncContext context,
451     size_t curIndex, size_t maxIndex)
452 {
453     /* callback: verify */
454     context->isSign = false;
455 
456     curIndex++;
457     if (curIndex >= maxIndex) {
458         return nullptr; /* not possible */
459     }
460 
461     napi_value result = GetBlob(env, argv[curIndex], context->signature);
462     if (result == nullptr) {
463         ThrowError(env, PARAM_ERROR, "signature is not a uint8Array or the length is 0 or too long.");
464         CM_LOG_E("get signature failed when process callback verify");
465         return nullptr;
466     }
467 
468     curIndex++;
469     if (curIndex >= maxIndex) {
470         return nullptr; /* not possible */
471     }
472 
473     int32_t ret = GetCallback(env, argv[curIndex], context->callback);
474     if (ret != CM_SUCCESS) {
475         ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
476         CM_LOG_E("get verify callback function failed when using finish function");
477         return nullptr;
478     }
479 
480     return GetInt32(env, 0);
481 }
482 
ParseCMFinishParams(napi_env env,napi_callback_info info,SignVerifyAsyncContext context)483 static napi_value ParseCMFinishParams(napi_env env, napi_callback_info info, SignVerifyAsyncContext context)
484 {
485     size_t argc = CM_NAPI_FINISH_ARGS_CNT;
486     napi_value argv[CM_NAPI_FINISH_ARGS_CNT] = { nullptr };
487     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
488 
489     if ((argc != CM_NAPI_FINISH_ARGS_CNT) && (argc != (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT)) &&
490         (argc != (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT - CM_NAPI_SIGNATURE_ARG_CNT))) {
491         ThrowError(env, PARAM_ERROR, "finish arguments count invalid, arguments count need between 1 and 3.");
492         CM_LOG_E("finish arguments count is not expected");
493         return nullptr;
494     }
495 
496     size_t index = 0;
497     napi_value result = GetBlob(env, argv[index], context->handle);
498     if (result == nullptr) {
499         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
500         CM_LOG_E("get handle failed when using finish function");
501         return nullptr;
502     }
503 
504     if (argc == CM_NAPI_FINISH_ARGS_CNT) {
505         return ProcessFinishThreeParam(env, argv, context, index, argc);
506     } else if (argc == (CM_NAPI_FINISH_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT)) {
507         return ProcessFinishTwoParam(env, argv, context, index, argc);
508     } else { /* only three 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         ThrowError(env, PARAM_ERROR, "abort arguments count invalid, arguments count need between 1 and 2.");
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         ThrowError(env, PARAM_ERROR, "handle is not a uint8Array or the length is 0 or too long.");
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             ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
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);
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);
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);
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         ThrowError(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         ThrowError(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         ThrowError(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         ThrowError(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     CM_LOG_I("cm napi init enter");
814 
815     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
816     if (context == nullptr) {
817         CM_LOG_E("init cm init context failed");
818         return nullptr;
819     }
820 
821     napi_value result = ParseCMInitParams(env, info, context);
822     if (result == nullptr) {
823         CM_LOG_E("parse cm init params failed");
824         FreeSignVerifyAsyncContext(env, context);
825         return nullptr;
826     }
827 
828     result = CMInitAsyncWork(env, context);
829     if (result == nullptr) {
830         CM_LOG_E("start cm init async work failed");
831         FreeSignVerifyAsyncContext(env, context);
832         return nullptr;
833     }
834 
835     CM_LOG_I("cm napi init end");
836     return result;
837 }
838 
CMNapiUpdate(napi_env env,napi_callback_info info)839 napi_value CMNapiUpdate(napi_env env, napi_callback_info info)
840 {
841     CM_LOG_I("cm napi update enter");
842     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
843     if (context == nullptr) {
844         CM_LOG_E("init cm update context failed");
845         return nullptr;
846     }
847 
848     napi_value result = ParseCMUpdateParams(env, info, context);
849     if (result == nullptr) {
850         CM_LOG_E("parse cm update params failed");
851         FreeSignVerifyAsyncContext(env, context);
852         return nullptr;
853     }
854 
855     result = CMUpdateAsyncWork(env, context);
856     if (result == nullptr) {
857         CM_LOG_E("start cm update async work failed");
858         FreeSignVerifyAsyncContext(env, context);
859         return nullptr;
860     }
861 
862     CM_LOG_I("cm napi update end");
863     return result;
864 }
865 
CMNapiFinish(napi_env env,napi_callback_info info)866 napi_value CMNapiFinish(napi_env env, napi_callback_info info)
867 {
868     CM_LOG_I("cm napi finish enter");
869     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
870     if (context == nullptr) {
871         CM_LOG_E("init cm finish context failed");
872         return nullptr;
873     }
874 
875     napi_value result = ParseCMFinishParams(env, info, context);
876     if (result == nullptr) {
877         CM_LOG_E("parse cm finish params failed");
878         FreeSignVerifyAsyncContext(env, context);
879         return nullptr;
880     }
881 
882     result = CMFinishAsyncWork(env, context);
883     if (result == nullptr) {
884         CM_LOG_E("start cm finish async work failed");
885         FreeSignVerifyAsyncContext(env, context);
886         return nullptr;
887     }
888 
889     CM_LOG_I("cm napi finish end");
890     return result;
891 }
892 
CMNapiAbort(napi_env env,napi_callback_info info)893 napi_value CMNapiAbort(napi_env env, napi_callback_info info)
894 {
895     CM_LOG_I("cm napi abort enter");
896     SignVerifyAsyncContext context = InitSignVerifyAsyncContext();
897     if (context == nullptr) {
898         CM_LOG_E("init cm abort context failed");
899         return nullptr;
900     }
901 
902     napi_value result = ParseCMAbortParams(env, info, context);
903     if (result == nullptr) {
904         CM_LOG_E("parse cm abort params failed");
905         FreeSignVerifyAsyncContext(env, context);
906         return nullptr;
907     }
908 
909     result = CMAbortAsyncWork(env, context);
910     if (result == nullptr) {
911         CM_LOG_E("start cm abort async work failed");
912         FreeSignVerifyAsyncContext(env, context);
913         return nullptr;
914     }
915 
916     CM_LOG_I("cm napi abort end");
917     return result;
918 }
919 }  // namespace CMNapi
920 
921