1 /*
2  * Copyright (C) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "napi_sign.h"
17 
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21 
22 #include "napi_crypto_framework_defines.h"
23 #include "napi_pri_key.h"
24 #include "napi_pub_key.h"
25 #include "napi_utils.h"
26 
27 namespace OHOS {
28 namespace CryptoFramework {
29 struct SignInitCtx {
30     napi_env env = nullptr;
31 
32     AsyncType asyncType = ASYNC_CALLBACK;
33     napi_ref callback = nullptr;
34     napi_deferred deferred = nullptr;
35     napi_value promise = nullptr;
36     napi_async_work asyncWork = nullptr;
37     napi_ref signRef = nullptr;
38     napi_ref priKeyRef = nullptr;
39 
40     HcfSign *sign = nullptr;
41     HcfParamsSpec *params = nullptr;
42     HcfPriKey *priKey = nullptr;
43 
44     HcfResult errCode = HCF_SUCCESS;
45     const char *errMsg = nullptr;
46 };
47 
48 struct SignUpdateCtx {
49     napi_env env = nullptr;
50 
51     AsyncType asyncType = ASYNC_CALLBACK;
52     napi_ref callback = nullptr;
53     napi_deferred deferred = nullptr;
54     napi_value promise = nullptr;
55     napi_async_work asyncWork = nullptr;
56     napi_ref signRef = nullptr;
57 
58     HcfSign *sign;
59     HcfBlob *data;
60 
61     HcfResult errCode = HCF_SUCCESS;
62     const char *errMsg = nullptr;
63 };
64 
65 struct SignDoFinalCtx {
66     napi_env env = nullptr;
67 
68     AsyncType asyncType = ASYNC_CALLBACK;
69     napi_ref callback = nullptr;
70     napi_deferred deferred = nullptr;
71     napi_value promise = nullptr;
72     napi_async_work asyncWork = nullptr;
73     napi_ref signRef = nullptr;
74 
75     HcfSign *sign;
76     HcfBlob *data;
77 
78     HcfResult errCode = HCF_SUCCESS;
79     const char *errMsg = nullptr;
80     HcfBlob returnSignatureData;
81 };
82 
83 thread_local napi_ref NapiSign::classRef_ = nullptr;
84 
FreeSignInitCtx(napi_env env,SignInitCtx * ctx)85 static void FreeSignInitCtx(napi_env env, SignInitCtx *ctx)
86 {
87     if (ctx == nullptr) {
88         return;
89     }
90 
91     if (ctx->asyncWork != nullptr) {
92         napi_delete_async_work(env, ctx->asyncWork);
93     }
94 
95     if (ctx->callback != nullptr) {
96         napi_delete_reference(env, ctx->callback);
97     }
98 
99     if (ctx->signRef != nullptr) {
100         napi_delete_reference(env, ctx->signRef);
101         ctx->signRef = nullptr;
102     }
103 
104     if (ctx->priKeyRef != nullptr) {
105         napi_delete_reference(env, ctx->priKeyRef);
106         ctx->priKeyRef = nullptr;
107     }
108 
109     HcfFree(ctx);
110 }
111 
FreeSignUpdateCtx(napi_env env,SignUpdateCtx * ctx)112 static void FreeSignUpdateCtx(napi_env env, SignUpdateCtx *ctx)
113 {
114     if (ctx == nullptr) {
115         return;
116     }
117 
118     if (ctx->asyncWork != nullptr) {
119         napi_delete_async_work(env, ctx->asyncWork);
120     }
121 
122     if (ctx->callback != nullptr) {
123         napi_delete_reference(env, ctx->callback);
124     }
125 
126     if (ctx->signRef != nullptr) {
127         napi_delete_reference(env, ctx->signRef);
128         ctx->signRef = nullptr;
129     }
130 
131     HcfBlobDataFree(ctx->data);
132     HcfFree(ctx->data);
133     HcfFree(ctx);
134 }
135 
FreeSignDoFinalCtx(napi_env env,SignDoFinalCtx * ctx)136 static void FreeSignDoFinalCtx(napi_env env, SignDoFinalCtx *ctx)
137 {
138     if (ctx == nullptr) {
139         return;
140     }
141 
142     if (ctx->asyncWork != nullptr) {
143         napi_delete_async_work(env, ctx->asyncWork);
144         ctx->asyncWork = nullptr;
145     }
146 
147     if (ctx->callback != nullptr) {
148         napi_delete_reference(env, ctx->callback);
149         ctx->callback = nullptr;
150     }
151 
152     if (ctx->signRef != nullptr) {
153         napi_delete_reference(env, ctx->signRef);
154         ctx->signRef = nullptr;
155     }
156 
157     if (ctx->returnSignatureData.data != nullptr) {
158         HcfFree(ctx->returnSignatureData.data);
159         ctx->returnSignatureData.data = nullptr;
160         ctx->returnSignatureData.len = 0;
161     }
162 
163     HcfBlobDataFree(ctx->data);
164     HcfFree(ctx->data);
165     HcfFree(ctx);
166 }
167 
BuildSignJsInitCtx(napi_env env,napi_callback_info info,SignInitCtx * ctx)168 static bool BuildSignJsInitCtx(napi_env env, napi_callback_info info, SignInitCtx *ctx)
169 {
170     napi_value thisVar = nullptr;
171     size_t expectedArgc = PARAMS_NUM_TWO;
172     size_t argc = expectedArgc;
173     napi_value argv[PARAMS_NUM_TWO] = { nullptr };
174     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
175     if (argc != expectedArgc && argc != expectedArgc - 1) {
176         LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
177         return false;
178     }
179     ctx->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
180 
181     NapiSign *napiSign = nullptr;
182     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
183     if (status != napi_ok || napiSign == nullptr) {
184         LOGE("failed to unwrap napi sign obj.");
185         return false;
186     }
187 
188     size_t index = 0;
189     NapiPriKey *napiPriKey = nullptr;
190     status = napi_unwrap(env, argv[index], reinterpret_cast<void **>(&napiPriKey));
191     if (status != napi_ok || napiPriKey == nullptr) {
192         LOGE("failed to unwrap napi priKey obj.");
193         return false;
194     }
195 
196     ctx->sign = napiSign->GetSign();
197     ctx->params = nullptr;
198     ctx->priKey = napiPriKey->GetPriKey();
199 
200     if (napi_create_reference(env, thisVar, 1, &ctx->signRef) != napi_ok) {
201         LOGE("create sign ref failed when do sign init!");
202         return false;
203     }
204 
205     if (napi_create_reference(env, argv[PARAM0], 1, &ctx->priKeyRef) != napi_ok) {
206         LOGE("create private key ref failed when do sign init!");
207         return false;
208     }
209 
210     if (ctx->asyncType == ASYNC_PROMISE) {
211         napi_create_promise(env, &ctx->deferred, &ctx->promise);
212         return true;
213     } else {
214         return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback);
215     }
216 }
217 
BuildSignJsUpdateCtx(napi_env env,napi_callback_info info,SignUpdateCtx * ctx)218 static bool BuildSignJsUpdateCtx(napi_env env, napi_callback_info info, SignUpdateCtx *ctx)
219 {
220     napi_value thisVar = nullptr;
221     size_t expectedArgc = PARAMS_NUM_TWO;
222     size_t argc = expectedArgc;
223     napi_value argv[PARAMS_NUM_TWO] = { nullptr };
224     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
225     if ((argc != expectedArgc) && (argc != expectedArgc - 1)) {
226         LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
227         return false;
228     }
229     ctx->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
230 
231     NapiSign *napiSign = nullptr;
232     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
233     if (status != napi_ok || napiSign == nullptr) {
234         LOGE("failed to unwrap napi sign obj.");
235         return false;
236     }
237 
238     size_t index = 0;
239     HcfBlob *blob = GetBlobFromNapiDataBlob(env, argv[index]);
240     if (blob == nullptr) {
241         LOGE("failed to get data.");
242         return false;
243     }
244 
245     ctx->sign = napiSign->GetSign();
246     ctx->data = blob;
247 
248     if (napi_create_reference(env, thisVar, 1, &ctx->signRef) != napi_ok) {
249         LOGE("create sign ref failed when do sign update!");
250         return false;
251     }
252 
253     if (ctx->asyncType == ASYNC_PROMISE) {
254         napi_create_promise(env, &ctx->deferred, &ctx->promise);
255         return true;
256     } else {
257         return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback);
258     }
259 }
260 
BuildSignJsDoFinalCtx(napi_env env,napi_callback_info info,SignDoFinalCtx * ctx)261 static bool BuildSignJsDoFinalCtx(napi_env env, napi_callback_info info, SignDoFinalCtx *ctx)
262 {
263     napi_value thisVar = nullptr;
264     size_t expectedArgc = PARAMS_NUM_TWO;
265     size_t argc = expectedArgc;
266     napi_value argv[PARAMS_NUM_TWO] = { nullptr };
267     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
268     if ((argc != expectedArgc) && (argc != expectedArgc - 1)) {
269         LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
270         return false;
271     }
272     ctx->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
273 
274     NapiSign *napiSign = nullptr;
275     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
276     if (status != napi_ok || napiSign == nullptr) {
277         LOGE("failed to unwrap napi sign obj.");
278         return false;
279     }
280 
281     size_t index = 0;
282     napi_valuetype valueType;
283     napi_typeof(env, argv[index], &valueType);
284     HcfBlob *data = nullptr;
285     if (valueType != napi_null) {
286         data = GetBlobFromNapiDataBlob(env, argv[index]);
287         if (data == nullptr) {
288             LOGE("failed to get data.");
289             return false;
290         }
291     }
292 
293     ctx->sign = napiSign->GetSign();
294     ctx->data = data;
295 
296     if (napi_create_reference(env, thisVar, 1, &ctx->signRef) != napi_ok) {
297         LOGE("create sign ref failed when do sign final!");
298         return false;
299     }
300 
301     if (ctx->asyncType == ASYNC_PROMISE) {
302         napi_create_promise(env, &ctx->deferred, &ctx->promise);
303         return true;
304     } else {
305         return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback);
306     }
307 }
308 
ReturnInitCallbackResult(napi_env env,SignInitCtx * ctx,napi_value result)309 static void ReturnInitCallbackResult(napi_env env, SignInitCtx *ctx, napi_value result)
310 {
311     napi_value businessError = nullptr;
312     if (ctx->errCode != HCF_SUCCESS) {
313         businessError = GenerateBusinessError(env, ctx->errCode, ctx->errMsg);
314     }
315 
316     napi_value params[ARGS_SIZE_ONE] = { businessError };
317 
318     napi_value func = nullptr;
319     napi_get_reference_value(env, ctx->callback, &func);
320 
321     napi_value recv = nullptr;
322     napi_value callFuncRet = nullptr;
323     napi_get_undefined(env, &recv);
324     napi_call_function(env, recv, func, ARGS_SIZE_ONE, params, &callFuncRet);
325 }
326 
ReturnInitPromiseResult(napi_env env,SignInitCtx * ctx,napi_value result)327 static void ReturnInitPromiseResult(napi_env env, SignInitCtx *ctx, napi_value result)
328 {
329     if (ctx->errCode == HCF_SUCCESS) {
330         napi_resolve_deferred(env, ctx->deferred, result);
331     } else {
332         napi_reject_deferred(env, ctx->deferred, GenerateBusinessError(env, ctx->errCode, ctx->errMsg));
333     }
334 }
335 
ReturnUpdateCallbackResult(napi_env env,SignUpdateCtx * ctx,napi_value result)336 static void ReturnUpdateCallbackResult(napi_env env, SignUpdateCtx *ctx, napi_value result)
337 {
338     napi_value businessError = nullptr;
339     if (ctx->errCode != HCF_SUCCESS) {
340         businessError = GenerateBusinessError(env, ctx->errCode, ctx->errMsg);
341     }
342 
343     napi_value params[ARGS_SIZE_ONE] = { businessError };
344 
345     napi_value func = nullptr;
346     napi_get_reference_value(env, ctx->callback, &func);
347 
348     napi_value recv = nullptr;
349     napi_value callFuncRet = nullptr;
350     napi_get_undefined(env, &recv);
351     napi_call_function(env, recv, func, ARGS_SIZE_ONE, params, &callFuncRet);
352 }
353 
ReturnUpdatePromiseResult(napi_env env,SignUpdateCtx * ctx,napi_value result)354 static void ReturnUpdatePromiseResult(napi_env env, SignUpdateCtx *ctx, napi_value result)
355 {
356     if (ctx->errCode == HCF_SUCCESS) {
357         napi_resolve_deferred(env, ctx->deferred, result);
358     } else {
359         napi_reject_deferred(env, ctx->deferred, GenerateBusinessError(env, ctx->errCode, ctx->errMsg));
360     }
361 }
362 
ReturnDoFinalCallbackResult(napi_env env,SignDoFinalCtx * ctx,napi_value result)363 static void ReturnDoFinalCallbackResult(napi_env env, SignDoFinalCtx *ctx, napi_value result)
364 {
365     napi_value businessError = nullptr;
366     if (ctx->errCode != HCF_SUCCESS) {
367         businessError = GenerateBusinessError(env, ctx->errCode, ctx->errMsg);
368     }
369 
370     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
371 
372     napi_value func = nullptr;
373     napi_get_reference_value(env, ctx->callback, &func);
374 
375     napi_value recv = nullptr;
376     napi_value callFuncRet = nullptr;
377     napi_get_undefined(env, &recv);
378     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
379 }
380 
ReturnDoFinalPromiseResult(napi_env env,SignDoFinalCtx * ctx,napi_value result)381 static void ReturnDoFinalPromiseResult(napi_env env, SignDoFinalCtx *ctx, napi_value result)
382 {
383     if (ctx->errCode == HCF_SUCCESS) {
384         napi_resolve_deferred(env, ctx->deferred, result);
385     } else {
386         napi_reject_deferred(env, ctx->deferred, GenerateBusinessError(env, ctx->errCode, ctx->errMsg));
387     }
388 }
389 
SignJsInitAsyncWorkProcess(napi_env env,void * data)390 static void SignJsInitAsyncWorkProcess(napi_env env, void *data)
391 {
392     SignInitCtx *ctx = static_cast<SignInitCtx *>(data);
393 
394     ctx->errCode = ctx->sign->init(ctx->sign, ctx->params, ctx->priKey);
395     if (ctx->errCode != HCF_SUCCESS) {
396         LOGD("[error] sign init fail.");
397         ctx->errMsg = "sign init fail.";
398     }
399 }
400 
SignJsInitAsyncWorkReturn(napi_env env,napi_status status,void * data)401 static void SignJsInitAsyncWorkReturn(napi_env env, napi_status status, void *data)
402 {
403     SignInitCtx *ctx = static_cast<SignInitCtx *>(data);
404 
405     if (ctx->asyncType == ASYNC_CALLBACK) {
406         ReturnInitCallbackResult(env, ctx, NapiGetNull(env));
407     } else {
408         ReturnInitPromiseResult(env, ctx, NapiGetNull(env));
409     }
410     FreeSignInitCtx(env, ctx);
411 }
412 
SignJsUpdateAsyncWorkProcess(napi_env env,void * data)413 static void SignJsUpdateAsyncWorkProcess(napi_env env, void *data)
414 {
415     SignUpdateCtx *ctx = static_cast<SignUpdateCtx *>(data);
416 
417     ctx->errCode = ctx->sign->update(ctx->sign, ctx->data);
418     if (ctx->errCode != HCF_SUCCESS) {
419         LOGD("[error] sign update fail.");
420         ctx->errMsg = "sign update fail.";
421     }
422 }
423 
SignJsUpdateAsyncWorkReturn(napi_env env,napi_status status,void * data)424 static void SignJsUpdateAsyncWorkReturn(napi_env env, napi_status status, void *data)
425 {
426     SignUpdateCtx *ctx = static_cast<SignUpdateCtx *>(data);
427 
428     if (ctx->asyncType == ASYNC_CALLBACK) {
429         ReturnUpdateCallbackResult(env, ctx, NapiGetNull(env));
430     } else {
431         ReturnUpdatePromiseResult(env, ctx, NapiGetNull(env));
432     }
433     FreeSignUpdateCtx(env, ctx);
434 }
435 
SignJsDoFinalAsyncWorkProcess(napi_env env,void * data)436 static void SignJsDoFinalAsyncWorkProcess(napi_env env, void *data)
437 {
438     SignDoFinalCtx *ctx = static_cast<SignDoFinalCtx *>(data);
439 
440     ctx->errCode = ctx->sign->sign(ctx->sign, ctx->data, &ctx->returnSignatureData);
441     if (ctx->errCode != HCF_SUCCESS) {
442         LOGD("[error] sign doFinal fail.");
443         ctx->errMsg = "sign doFinal fail.";
444     }
445 }
446 
SignJsDoFinalAsyncWorkReturn(napi_env env,napi_status status,void * data)447 static void SignJsDoFinalAsyncWorkReturn(napi_env env, napi_status status, void *data)
448 {
449     SignDoFinalCtx *ctx = static_cast<SignDoFinalCtx *>(data);
450 
451     napi_value dataBlob = nullptr;
452     if (ctx->errCode == HCF_SUCCESS) {
453         dataBlob = ConvertBlobToNapiValue(env, &ctx->returnSignatureData);
454     }
455 
456     if (ctx->asyncType == ASYNC_CALLBACK) {
457         ReturnDoFinalCallbackResult(env, ctx, dataBlob);
458     } else {
459         ReturnDoFinalPromiseResult(env, ctx, dataBlob);
460     }
461     FreeSignDoFinalCtx(env, ctx);
462 }
463 
NewSignJsInitAsyncWork(napi_env env,SignInitCtx * ctx)464 static napi_value NewSignJsInitAsyncWork(napi_env env, SignInitCtx *ctx)
465 {
466     napi_value resourceName = nullptr;
467     napi_create_string_utf8(env, "init", NAPI_AUTO_LENGTH, &resourceName);
468 
469     napi_create_async_work(
470         env, nullptr, resourceName,
471         [](napi_env env, void *data) {
472             SignJsInitAsyncWorkProcess(env, data);
473             return;
474         },
475         [](napi_env env, napi_status status, void *data) {
476             SignJsInitAsyncWorkReturn(env, status, data);
477             return;
478         },
479         static_cast<void *>(ctx),
480         &ctx->asyncWork);
481 
482     napi_queue_async_work(env, ctx->asyncWork);
483     if (ctx->asyncType == ASYNC_PROMISE) {
484         return ctx->promise;
485     } else {
486         return NapiGetNull(env);
487     }
488 }
489 
NewSignJsUpdateAsyncWork(napi_env env,SignUpdateCtx * ctx)490 static napi_value NewSignJsUpdateAsyncWork(napi_env env, SignUpdateCtx *ctx)
491 {
492     napi_value resourceName = nullptr;
493     napi_create_string_utf8(env, "update", NAPI_AUTO_LENGTH, &resourceName);
494 
495     napi_create_async_work(
496         env, nullptr, resourceName,
497         [](napi_env env, void *data) {
498             SignJsUpdateAsyncWorkProcess(env, data);
499             return;
500         },
501         [](napi_env env, napi_status status, void *data) {
502             SignJsUpdateAsyncWorkReturn(env, status, data);
503             return;
504         },
505         static_cast<void *>(ctx),
506         &ctx->asyncWork);
507 
508     napi_queue_async_work(env, ctx->asyncWork);
509     if (ctx->asyncType == ASYNC_PROMISE) {
510         return ctx->promise;
511     } else {
512         return NapiGetNull(env);
513     }
514 }
515 
NewSignJsDoFinalAsyncWork(napi_env env,SignDoFinalCtx * ctx)516 static napi_value NewSignJsDoFinalAsyncWork(napi_env env, SignDoFinalCtx *ctx)
517 {
518     napi_value resourceName = nullptr;
519     napi_create_string_utf8(env, "sign", NAPI_AUTO_LENGTH, &resourceName);
520 
521     napi_create_async_work(
522         env, nullptr, resourceName,
523         [](napi_env env, void *data) {
524             SignJsDoFinalAsyncWorkProcess(env, data);
525             return;
526         },
527         [](napi_env env, napi_status status, void *data) {
528             SignJsDoFinalAsyncWorkReturn(env, status, data);
529             return;
530         },
531         static_cast<void *>(ctx),
532         &ctx->asyncWork);
533 
534     napi_queue_async_work(env, ctx->asyncWork);
535     if (ctx->asyncType == ASYNC_PROMISE) {
536         return ctx->promise;
537     } else {
538         return NapiGetNull(env);
539     }
540 }
541 
NapiSign(HcfSign * sign)542 NapiSign::NapiSign(HcfSign *sign)
543 {
544     this->sign_ = sign;
545 }
546 
~NapiSign()547 NapiSign::~NapiSign()
548 {
549     HcfObjDestroy(this->sign_);
550 }
551 
GetSign()552 HcfSign *NapiSign::GetSign()
553 {
554     return this->sign_;
555 }
556 
JsInit(napi_env env,napi_callback_info info)557 napi_value NapiSign::JsInit(napi_env env, napi_callback_info info)
558 {
559     SignInitCtx *ctx = static_cast<SignInitCtx *>(HcfMalloc(sizeof(SignInitCtx), 0));
560     if (ctx == nullptr) {
561         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail."));
562         LOGE("create context fail.");
563         return nullptr;
564     }
565 
566     if (!BuildSignJsInitCtx(env, info, ctx)) {
567         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
568         LOGE("build context fail.");
569         FreeSignInitCtx(env, ctx);
570         return nullptr;
571     }
572 
573     return NewSignJsInitAsyncWork(env, ctx);
574 }
575 
JsInitSync(napi_env env,napi_callback_info info)576 napi_value NapiSign::JsInitSync(napi_env env, napi_callback_info info)
577 {
578     napi_value thisVar = nullptr;
579     size_t expectedArgc = PARAMS_NUM_ONE;
580     size_t argc = expectedArgc;
581     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
582     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
583     if (argc != PARAMS_NUM_ONE) {
584         LOGE("wrong argument num. require %d arguments. [Argc]: %zu!", PARAMS_NUM_ONE, argc);
585         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "wrong argument num."));
586         return nullptr;
587     }
588 
589     NapiSign *napiSign = nullptr;
590     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
591     if (status != napi_ok || napiSign == nullptr) {
592         LOGE("failed to unwrap napi sign obj.");
593         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napi sign obj."));
594         return nullptr;
595     }
596 
597     NapiPriKey *napiPriKey = nullptr;
598     status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&napiPriKey));
599     if (status != napi_ok || napiPriKey == nullptr) {
600         LOGE("failed to unwrap napi priKey obj.");
601         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napi priKey obj."));
602         return nullptr;
603     }
604 
605     HcfSign *sign = napiSign->GetSign();
606     HcfPriKey *priKey = napiPriKey->GetPriKey();
607     HcfResult ret = sign->init(sign, nullptr, priKey);
608     if (ret != HCF_SUCCESS) {
609         LOGD("sign init fail.");
610         napi_throw(env, GenerateBusinessError(env, ret, "sign init fail."));
611         return nullptr;
612     }
613     napi_value instance = NapiGetNull(env);
614     return instance;
615 }
616 
JsUpdate(napi_env env,napi_callback_info info)617 napi_value NapiSign::JsUpdate(napi_env env, napi_callback_info info)
618 {
619     SignUpdateCtx *ctx = static_cast<SignUpdateCtx *>(HcfMalloc(sizeof(SignUpdateCtx), 0));
620     if (ctx == nullptr) {
621         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail."));
622         LOGE("create context fail.");
623         return nullptr;
624     }
625 
626     if (!BuildSignJsUpdateCtx(env, info, ctx)) {
627         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
628         LOGE("build context fail.");
629         FreeSignUpdateCtx(env, ctx);
630         return nullptr;
631     }
632 
633     return NewSignJsUpdateAsyncWork(env, ctx);
634 }
635 
JsUpdateSync(napi_env env,napi_callback_info info)636 napi_value NapiSign::JsUpdateSync(napi_env env, napi_callback_info info)
637 {
638     napi_value thisVar = nullptr;
639     size_t argc = PARAMS_NUM_ONE;
640     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
641     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
642     if (argc != PARAMS_NUM_ONE) {
643         LOGE("wrong argument num. require %d arguments. [Argc]: %zu!", PARAMS_NUM_ONE, argc);
644         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "wrong argument num."));
645         return nullptr;
646     }
647 
648     NapiSign *napiSign = nullptr;
649     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
650     if (status != napi_ok || napiSign == nullptr) {
651         LOGE("failed to unwrap napi sign obj.");
652         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napi sign obj."));
653         return nullptr;
654     }
655 
656     HcfBlob blob = { 0 };
657     HcfResult ret = GetBlobFromNapiValue(env, argv[PARAM0], &blob);
658     if (ret != HCF_SUCCESS) {
659         LOGE("failed to get input blob!");
660         napi_throw(env, GenerateBusinessError(env, ret, "failed to get data."));
661         return nullptr;
662     }
663 
664     HcfSign *sign = napiSign->GetSign();
665     ret = sign->update(sign, &blob);
666     HcfBlobDataFree(&blob);
667     if (ret != HCF_SUCCESS) {
668         LOGD("sign update fail.");
669         napi_throw(env, GenerateBusinessError(env, ret, "sign update fail."));
670         return nullptr;
671     }
672     napi_value instance = NapiGetNull(env);
673     return instance;
674 }
675 
JsSign(napi_env env,napi_callback_info info)676 napi_value NapiSign::JsSign(napi_env env, napi_callback_info info)
677 {
678     SignDoFinalCtx *ctx = static_cast<SignDoFinalCtx *>(HcfMalloc(sizeof(SignDoFinalCtx), 0));
679     if (ctx == nullptr) {
680         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "create context fail."));
681         LOGE("create context fail.");
682         return nullptr;
683     }
684 
685     if (!BuildSignJsDoFinalCtx(env, info, ctx)) {
686         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
687         LOGE("build context fail.");
688         FreeSignDoFinalCtx(env, ctx);
689         return nullptr;
690     }
691 
692     return NewSignJsDoFinalAsyncWork(env, ctx);
693 }
694 
JsSignSync(napi_env env,napi_callback_info info)695 napi_value NapiSign::JsSignSync(napi_env env, napi_callback_info info)
696 {
697     napi_value thisVar = nullptr;
698     size_t argc = PARAMS_NUM_ONE;
699     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
700     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
701     if (argc != PARAMS_NUM_ONE) {
702         LOGE("wrong argument num. require %d arguments. [Argc]: %zu!", PARAMS_NUM_ONE, argc);
703         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "wrong argument num."));
704         return nullptr;
705     }
706 
707     NapiSign *napiSign = nullptr;
708     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
709     if (status != napi_ok || napiSign == nullptr) {
710         LOGE("failed to unwrap napi sign obj.");
711         napi_throw(env, GenerateBusinessError(env, HCF_ERR_NAPI, "failed to unwrap napi sign obj."));
712         return nullptr;
713     }
714 
715     napi_valuetype valueType;
716     napi_typeof(env, argv[PARAM0], &valueType);
717     HcfBlob *data = nullptr;
718     HcfBlob blob = { 0 };
719     if (valueType != napi_null) {
720         HcfResult ret = GetBlobFromNapiValue(env, argv[PARAM0], &blob);
721         if (ret != HCF_SUCCESS) {
722             LOGE("failed to get data.");
723             napi_throw(env, GenerateBusinessError(env, ret, "failed to get data."));
724             return nullptr;
725         }
726         data = &blob;
727     }
728 
729     HcfSign *sign = napiSign->GetSign();
730     HcfBlob returnSignatureData = { .data = nullptr, .len = 0 };
731     HcfResult ret = sign->sign(sign, data, &returnSignatureData);
732     HcfBlobDataFree(data);
733     if (ret != HCF_SUCCESS) {
734         LOGD("sign doFinal fail.");
735         napi_throw(env, GenerateBusinessError(env, ret, "sign doFinal fail."));
736         return nullptr;
737     }
738 
739     napi_value instance = nullptr;
740     ret = ConvertDataBlobToNapiValue(env, &returnSignatureData, &instance);
741     HcfBlobDataFree(&returnSignatureData);
742     if (ret != HCF_SUCCESS) {
743         LOGE("sign convert dataBlob to napi_value failed!");
744         napi_throw(env, GenerateBusinessError(env, ret, "sign convert dataBlob to napi_value failed!"));
745         return nullptr;
746     }
747 
748     return instance;
749 }
750 
SignConstructor(napi_env env,napi_callback_info info)751 napi_value NapiSign::SignConstructor(napi_env env, napi_callback_info info)
752 {
753     napi_value thisVar = nullptr;
754     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
755     return thisVar;
756 }
757 
NapiWrapSign(napi_env env,napi_value instance,NapiSign * napiSign)758 static napi_value NapiWrapSign(napi_env env, napi_value instance, NapiSign *napiSign)
759 {
760     napi_status status = napi_wrap(
761         env, instance, napiSign,
762         [](napi_env env, void *data, void *hint) {
763             NapiSign *napiSign = static_cast<NapiSign *>(data);
764             delete napiSign;
765             return;
766         }, nullptr, nullptr);
767     if (status != napi_ok) {
768         LOGE("failed to wrap napiSign obj!");
769         delete napiSign;
770         return nullptr;
771     }
772     return instance;
773 }
774 
CreateJsSign(napi_env env,napi_callback_info info)775 napi_value NapiSign::CreateJsSign(napi_env env, napi_callback_info info)
776 {
777     size_t expectedArgc = PARAMS_NUM_ONE;
778     size_t argc = expectedArgc;
779     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
780     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
781 
782     if (argc != expectedArgc) {
783         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
784         LOGE("The input args num is invalid.");
785         return nullptr;
786     }
787 
788     napi_value instance;
789     napi_value constructor = nullptr;
790     napi_get_reference_value(env, classRef_, &constructor);
791     napi_new_instance(env, constructor, argc, argv, &instance);
792 
793     std::string algName;
794     if (!GetStringFromJSParams(env, argv[0], algName)) {
795         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get algName fail."));
796         return nullptr;
797     }
798 
799     HcfSign *sign = nullptr;
800     HcfResult ret = HcfSignCreate(algName.c_str(), &sign);
801     if (ret != HCF_SUCCESS) {
802         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "create c sign fail."));
803         LOGE("create c sign fail.");
804         return nullptr;
805     }
806 
807     NapiSign *napiSign = new (std::nothrow) NapiSign(sign);
808     if (napiSign == nullptr) {
809         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napi sign failed"));
810         LOGE("new napi sign failed");
811         HcfObjDestroy(sign);
812         return nullptr;
813     }
814 
815     napi_value napiAlgName = nullptr;
816     napi_create_string_utf8(env, algName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
817     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
818 
819     return NapiWrapSign(env, instance, napiSign);
820 }
821 
SetSignUserIdUintArray(napi_env env,napi_value * argv,HcfSign * sign)822 static HcfResult SetSignUserIdUintArray(napi_env env, napi_value *argv, HcfSign *sign)
823 {
824     HcfBlob *blob = nullptr;
825     blob = GetBlobFromNapiUint8Arr(env, argv[1]);
826     if (blob == nullptr) {
827         LOGE("failed to get blob.");
828         return HCF_INVALID_PARAMS;
829     }
830     HcfResult ret = sign->setSignSpecUint8Array(sign, SM2_USER_ID_UINT8ARR, *blob);
831     if (ret != HCF_SUCCESS) {
832         HcfBlobDataFree(blob);
833         HcfFree(blob);
834         LOGE("c setSignSpecUint8Array failed.");
835         return HCF_INVALID_PARAMS;
836     }
837     HcfBlobDataFree(blob);
838     HcfFree(blob);
839     return ret;
840 }
841 
SetSignSaltLenInt(napi_env env,napi_value * argv,HcfSign * sign)842 static HcfResult SetSignSaltLenInt(napi_env env, napi_value *argv, HcfSign *sign)
843 {
844     int32_t saltLen = 0;
845     if (napi_get_value_int32(env, argv[1], &saltLen) != napi_ok) {
846         LOGE("get signSpec saltLen failed!");
847         return HCF_INVALID_PARAMS;
848     }
849     HcfResult ret = HCF_SUCCESS;
850     ret = sign->setSignSpecInt(sign, PSS_SALT_LEN_INT, saltLen);
851     if (ret != HCF_SUCCESS) {
852         LOGE("c setSignSpecNumber fail.");
853         return HCF_INVALID_PARAMS;
854     }
855     return ret;
856 }
857 
SetDetailSignSpec(napi_env env,napi_value * argv,SignSpecItem item,HcfSign * sign)858 static HcfResult SetDetailSignSpec(napi_env env, napi_value *argv, SignSpecItem item, HcfSign *sign)
859 {
860     HcfResult result = HCF_INVALID_PARAMS;
861 
862     switch (item) {
863         case SM2_USER_ID_UINT8ARR:
864             result = SetSignUserIdUintArray(env, argv, sign);
865             break;
866         case PSS_SALT_LEN_INT:
867             result = SetSignSaltLenInt(env, argv, sign);
868             break;
869         default:
870             LOGE("specItem not support.");
871             break;
872     }
873     return result;
874 }
875 
876 // sign setSignSpec(itemType :signSpecItem, itemValue : number|string)
JsSetSignSpec(napi_env env,napi_callback_info info)877 napi_value NapiSign::JsSetSignSpec(napi_env env, napi_callback_info info)
878 {
879     napi_value thisVar = nullptr;
880     NapiSign *napiSign = nullptr;
881     size_t expectedArgc = ARGS_SIZE_TWO;
882     size_t argc = ARGS_SIZE_TWO;
883     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
884     // thisVar means the js this argument for the call (sign.() means this = sign)
885     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
886     if (argc != expectedArgc) {
887         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
888         LOGE("wrong argument num. require 2 arguments. [Argc]: %zu!", argc);
889         return nullptr;
890     }
891     SignSpecItem item;
892     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
893         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get signSpecItem failed!"));
894         LOGE("get signspecitem failed!");
895         return nullptr;
896     }
897     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
898     if (status != napi_ok || napiSign == nullptr) {
899         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiSign obj!"));
900         LOGE("failed to unwrap napiSign obj!");
901         return nullptr;
902     }
903     HcfSign *sign = napiSign->GetSign();
904     if (SetDetailSignSpec(env, argv, item, sign) != HCF_SUCCESS) {
905         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to set sign spec!"));
906         LOGE("failed to set sign spec!");
907         return nullptr;
908     }
909     return thisVar;
910 }
911 
GetSignSpecString(napi_env env,SignSpecItem item,HcfSign * sign)912 static napi_value GetSignSpecString(napi_env env, SignSpecItem item, HcfSign *sign)
913 {
914     char *returnString = nullptr;
915     HcfResult ret = sign->getSignSpecString(sign, item, &returnString);
916     if (ret != HCF_SUCCESS) {
917         napi_throw(env, GenerateBusinessError(env, ret, "C getSignSpecString failed."));
918         LOGE("c getSignSpecString fail.");
919         return nullptr;
920     }
921 
922     napi_value instance = nullptr;
923     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
924     HcfFree(returnString);
925     return instance;
926 }
927 
GetSignSpecNumber(napi_env env,SignSpecItem item,HcfSign * sign)928 static napi_value GetSignSpecNumber(napi_env env, SignSpecItem item, HcfSign *sign)
929 {
930     int returnInt;
931     HcfResult ret = sign->getSignSpecInt(sign, item, &returnInt);
932     if (ret != HCF_SUCCESS) {
933         napi_throw(env, GenerateBusinessError(env, ret, "C getSignSpecInt failed."));
934         LOGE("c getSignSpecInt fail.");
935         return nullptr;
936     }
937 
938     napi_value instance = nullptr;
939     napi_create_int32(env, returnInt, &instance);
940     return instance;
941 }
942 
JsGetSignSpec(napi_env env,napi_callback_info info)943 napi_value NapiSign::JsGetSignSpec(napi_env env, napi_callback_info info)
944 {
945     napi_value thisVar = nullptr;
946     NapiSign *napiSign = nullptr;
947     size_t expectedArgc = ARGS_SIZE_ONE;
948     size_t argc = ARGS_SIZE_ONE;
949     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
950     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
951     if (argc != expectedArgc) {
952         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "init failed for wrong argument num."));
953         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
954         return nullptr;
955     }
956     SignSpecItem item;
957     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
958         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get signSpecItem failed!"));
959         LOGE("get signSpecItem failed!");
960         return nullptr;
961     }
962 
963     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSign));
964     if (status != napi_ok || napiSign == nullptr) {
965         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiSign obj!"));
966         LOGE("failed to unwrap napiSign obj!");
967         return nullptr;
968     }
969     HcfSign *sign = napiSign->GetSign();
970     if (sign == nullptr) {
971         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get sign obj!"));
972         LOGE("failed to get sign obj!");
973         return nullptr;
974     }
975 
976     int32_t type = GetSignSpecType(item);
977     if (type == SPEC_ITEM_TYPE_STR) {
978         return GetSignSpecString(env, item, sign);
979     } else if (type == SPEC_ITEM_TYPE_NUM) {
980         return GetSignSpecNumber(env, item, sign);
981     } else {
982         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "signSpecItem not support!"));
983         return nullptr;
984     }
985 }
986 
DefineSignJSClass(napi_env env,napi_value exports)987 void NapiSign::DefineSignJSClass(napi_env env, napi_value exports)
988 {
989     napi_property_descriptor desc[] = {
990         DECLARE_NAPI_FUNCTION("createSign", NapiSign::CreateJsSign),
991     };
992     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
993 
994     napi_property_descriptor classDesc[] = {
995         DECLARE_NAPI_FUNCTION("init", NapiSign::JsInit),
996         DECLARE_NAPI_FUNCTION("update", NapiSign::JsUpdate),
997         DECLARE_NAPI_FUNCTION("sign", NapiSign::JsSign),
998         DECLARE_NAPI_FUNCTION("initSync", NapiSign::JsInitSync),
999         DECLARE_NAPI_FUNCTION("updateSync", NapiSign::JsUpdateSync),
1000         DECLARE_NAPI_FUNCTION("signSync", NapiSign::JsSignSync),
1001         DECLARE_NAPI_FUNCTION("setSignSpec", NapiSign::JsSetSignSpec),
1002         DECLARE_NAPI_FUNCTION("getSignSpec", NapiSign::JsGetSignSpec),
1003     };
1004     napi_value constructor = nullptr;
1005     napi_define_class(env, "Sign", NAPI_AUTO_LENGTH, NapiSign::SignConstructor, nullptr,
1006         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
1007     napi_create_reference(env, constructor, 1, &classRef_);
1008 }
1009 } // CryptoFramework
1010 } // OHOS
1011