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