• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022-2023 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_mac.h"
17 
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21 
22 #include "napi_sym_key.h"
23 #include "napi_utils.h"
24 #include "napi_crypto_framework_defines.h"
25 
26 namespace OHOS {
27 namespace CryptoFramework {
28 thread_local napi_ref NapiMac::classRef_ = nullptr;
29 
30 struct MacCtx {
31     napi_env env = nullptr;
32 
33     AsyncType asyncType = ASYNC_CALLBACK;
34     napi_ref callback = nullptr;
35     napi_deferred deferred = nullptr;
36     napi_value promise = nullptr;
37     napi_async_work asyncWork = nullptr;
38 
39     std::string algoName = "";
40     HcfSymKey *symKey = nullptr;
41     HcfBlob *inBlob = nullptr;
42 
43     HcfResult errCode = HCF_SUCCESS;
44     const char *errMsg = nullptr;
45     HcfBlob *outBlob = nullptr;
46     HcfMac *mac = nullptr;
47 };
48 
FreeCryptoFwkCtx(napi_env env,MacCtx * context)49 static void FreeCryptoFwkCtx(napi_env env, MacCtx *context)
50 {
51     if (context == nullptr) {
52         return;
53     }
54     if (context->asyncWork != nullptr) {
55         napi_delete_async_work(env, context->asyncWork);
56         context->asyncWork = nullptr;
57     }
58     if (context->callback != nullptr) {
59         napi_delete_reference(env, context->callback);
60         context->callback = nullptr;
61     }
62     context->symKey = nullptr;
63     if (context->inBlob != nullptr) {
64         HcfFree(context->inBlob->data);
65         context->inBlob->data = nullptr;
66         context->inBlob->len = 0;
67         HcfFree(context->inBlob);
68         context->inBlob = nullptr;
69     }
70     if (context->outBlob != nullptr) {
71         HcfFree(context->outBlob->data);
72         context->outBlob->data = nullptr;
73         context->outBlob->len = 0;
74         HcfFree(context->outBlob);
75         context->outBlob = nullptr;
76     }
77     context->errMsg = nullptr;
78     context->mac = nullptr;
79     HcfFree(context);
80     context = nullptr;
81 }
82 
ReturnCallbackResult(napi_env env,MacCtx * context,napi_value result)83 static void ReturnCallbackResult(napi_env env, MacCtx *context, napi_value result)
84 {
85     napi_value businessError = nullptr;
86     if (context->errCode != HCF_SUCCESS) {
87         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
88     }
89     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
90 
91     napi_value func = nullptr;
92     napi_get_reference_value(env, context->callback, &func);
93 
94     napi_value recv = nullptr;
95     napi_value callFuncRet = nullptr;
96     napi_get_undefined(env, &recv);
97     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
98 }
99 
ReturnPromiseResult(napi_env env,MacCtx * context,napi_value result)100 static void ReturnPromiseResult(napi_env env, MacCtx *context, napi_value result)
101 {
102     if (context->errCode == HCF_SUCCESS) {
103         napi_resolve_deferred(env, context->deferred, result);
104     } else {
105         napi_reject_deferred(env, context->deferred,
106             GenerateBusinessError(env, context->errCode, context->errMsg));
107     }
108 }
109 
MacInitExecute(napi_env env,void * data)110 static void MacInitExecute(napi_env env, void *data)
111 {
112     MacCtx *context = static_cast<MacCtx *>(data);
113     HcfMac *macObj = context->mac;
114     HcfSymKey *symKey = context->symKey;
115     context->errCode = macObj->init(macObj, symKey);
116     if (context->errCode != HCF_SUCCESS) {
117         LOGD("[error] init failed!");
118         context->errMsg = "init failed";
119     }
120 }
121 
MacInitComplete(napi_env env,napi_status status,void * data)122 static void MacInitComplete(napi_env env, napi_status status, void *data)
123 {
124     MacCtx *context = static_cast<MacCtx *>(data);
125     napi_value nullInstance = nullptr;
126     napi_get_null(env, &nullInstance);
127     if (context->asyncType == ASYNC_CALLBACK) {
128         ReturnCallbackResult(env, context, nullInstance);
129     } else {
130         ReturnPromiseResult(env, context, nullInstance);
131     }
132     FreeCryptoFwkCtx(env, context);
133 }
134 
MacUpdateExecute(napi_env env,void * data)135 static void MacUpdateExecute(napi_env env, void *data)
136 {
137     MacCtx *context = static_cast<MacCtx *>(data);
138     HcfMac *macObj = context->mac;
139     HcfBlob *inBlob = reinterpret_cast<HcfBlob *>(context->inBlob);
140     context->errCode = macObj->update(macObj, inBlob);
141     if (context->errCode != HCF_SUCCESS) {
142         LOGD("[error] update failed!");
143         context->errMsg = "update failed";
144     }
145 }
146 
MacUpdateComplete(napi_env env,napi_status status,void * data)147 static void MacUpdateComplete(napi_env env, napi_status status, void *data)
148 {
149     MacCtx *context = static_cast<MacCtx *>(data);
150     napi_value nullInstance = nullptr;
151     napi_get_null(env, &nullInstance);
152     if (context->asyncType == ASYNC_CALLBACK) {
153         ReturnCallbackResult(env, context, nullInstance);
154     } else {
155         ReturnPromiseResult(env, context, nullInstance);
156     }
157     FreeCryptoFwkCtx(env, context);
158 }
159 
MacDoFinalExecute(napi_env env,void * data)160 static void MacDoFinalExecute(napi_env env, void *data)
161 {
162     MacCtx *context = static_cast<MacCtx *>(data);
163     HcfMac *macObj = context->mac;
164     HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
165     if (outBlob == nullptr) {
166         LOGD("[error] outBlob is null!");
167         context->errCode = HCF_ERR_MALLOC;
168         context->errMsg = "malloc data blob failed";
169         return;
170     }
171     context->errCode = macObj->doFinal(macObj, outBlob);
172     if (context->errCode != HCF_SUCCESS) {
173         HcfFree(outBlob);
174         LOGE("doFinal failed!");
175         context->errMsg = "doFinal failed";
176         return;
177     }
178     context->outBlob = outBlob;
179 }
180 
MacDoFinalComplete(napi_env env,napi_status status,void * data)181 static void MacDoFinalComplete(napi_env env, napi_status status, void *data)
182 {
183     MacCtx *context = static_cast<MacCtx *>(data);
184     napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
185     if (returnOutBlob == nullptr) {
186         LOGE("returnOutBlob is nullptr!");
187         returnOutBlob = NapiGetNull(env);
188     }
189     if (context->asyncType == ASYNC_CALLBACK) {
190         ReturnCallbackResult(env, context, returnOutBlob);
191     } else {
192         ReturnPromiseResult(env, context, returnOutBlob);
193     }
194     FreeCryptoFwkCtx(env, context);
195 }
196 
BuildMacJsInitCtx(napi_env env,napi_callback_info info,MacCtx * context)197 static bool BuildMacJsInitCtx(napi_env env, napi_callback_info info, MacCtx *context)
198 {
199     napi_value thisVar = nullptr;
200     NapiMac *napiMac = nullptr;
201     size_t expectedArgsCount = ARGS_SIZE_TWO;
202     size_t argc = expectedArgsCount;
203     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
204     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
205     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
206         return false;
207     }
208 
209     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
210         ASYNC_CALLBACK : ASYNC_PROMISE;
211     NapiSymKey *symKey = nullptr;
212     napi_status status = napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&symKey));
213     if (status != napi_ok || symKey == nullptr) {
214         LOGE("symKey is null!");
215         return false;
216     }
217     context->symKey = symKey->GetSymKey();
218     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
219     if (status != napi_ok || napiMac == nullptr) {
220         LOGE("failed to unwrap napiMac obj!");
221         return false;
222     }
223 
224     context->mac = napiMac->GetMac();
225 
226     if (context->asyncType == ASYNC_PROMISE) {
227         napi_create_promise(env, &context->deferred, &context->promise);
228         return true;
229     } else {
230         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
231     }
232 }
233 
BuildMacJsUpdateCtx(napi_env env,napi_callback_info info,MacCtx * context)234 static bool BuildMacJsUpdateCtx(napi_env env, napi_callback_info info, MacCtx *context)
235 {
236     napi_value thisVar = nullptr;
237     NapiMac *napiMac = nullptr;
238     size_t expectedArgsCount = ARGS_SIZE_TWO;
239     size_t argc = expectedArgsCount;
240     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
241     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
242     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
243         return false;
244     }
245 
246     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
247         ASYNC_CALLBACK : ASYNC_PROMISE;
248     context->inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
249     if (context->inBlob == nullptr) {
250         LOGE("inBlob is null!");
251         return false;
252     }
253     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
254     if (status != napi_ok || napiMac == nullptr) {
255         LOGE("failed to unwrap napiMac obj!");
256         return false;
257     }
258 
259     context->mac = napiMac->GetMac();
260 
261     if (context->asyncType == ASYNC_PROMISE) {
262         napi_create_promise(env, &context->deferred, &context->promise);
263         return true;
264     } else {
265         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
266     }
267 }
268 
BuildMacJsDoFinalCtx(napi_env env,napi_callback_info info,MacCtx * context)269 static bool BuildMacJsDoFinalCtx(napi_env env, napi_callback_info info, MacCtx *context)
270 {
271     napi_value thisVar = nullptr;
272     NapiMac *napiMac = nullptr;
273     size_t expectedArgsCount = ARGS_SIZE_ONE;
274     size_t argc = expectedArgsCount;
275     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
276     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
277     if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
278         return false;
279     }
280 
281     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
282         ASYNC_CALLBACK : ASYNC_PROMISE;
283     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
284     if (status != napi_ok || napiMac == nullptr) {
285         LOGE("failed to unwrap napiMac obj!");
286         return false;
287     }
288 
289     context->mac = napiMac->GetMac();
290 
291     if (context->asyncType == ASYNC_PROMISE) {
292         napi_create_promise(env, &context->deferred, &context->promise);
293         return true;
294     } else {
295         return GetCallbackFromJSParams(env, argv[PARAM0], &context->callback);
296     }
297 }
298 
NewMacJsInitAsyncWork(napi_env env,MacCtx * context)299 static napi_value NewMacJsInitAsyncWork(napi_env env, MacCtx *context)
300 {
301     napi_create_async_work(
302         env, nullptr, GetResourceName(env, "MacInit"),
303         [](napi_env env, void *data) {
304             MacInitExecute(env, data);
305             return;
306         },
307         [](napi_env env, napi_status status, void *data) {
308             MacInitComplete(env, status, data);
309             return;
310         },
311         static_cast<void *>(context),
312         &context->asyncWork);
313 
314     napi_queue_async_work(env, context->asyncWork);
315     if (context->asyncType == ASYNC_PROMISE) {
316         return context->promise;
317     } else {
318         return NapiGetNull(env);
319     }
320 }
321 
NewMacJsUpdateAsyncWork(napi_env env,MacCtx * context)322 static napi_value NewMacJsUpdateAsyncWork(napi_env env, MacCtx *context)
323 {
324     napi_create_async_work(
325         env, nullptr, GetResourceName(env, "MacUpdate"),
326         [](napi_env env, void *data) {
327             MacUpdateExecute(env, data);
328             return;
329         },
330         [](napi_env env, napi_status status, void *data) {
331             MacUpdateComplete(env, status, data);
332             return;
333         },
334         static_cast<void *>(context),
335         &context->asyncWork);
336 
337     napi_queue_async_work(env, context->asyncWork);
338     if (context->asyncType == ASYNC_PROMISE) {
339         return context->promise;
340     } else {
341         return NapiGetNull(env);
342     }
343 }
344 
NewMacJsDoFinalAsyncWork(napi_env env,MacCtx * context)345 static napi_value NewMacJsDoFinalAsyncWork(napi_env env, MacCtx *context)
346 {
347     napi_create_async_work(
348         env, nullptr, GetResourceName(env, "MacDoFinal"),
349         [](napi_env env, void *data) {
350             MacDoFinalExecute(env, data);
351             return;
352         },
353         [](napi_env env, napi_status status, void *data) {
354             MacDoFinalComplete(env, status, data);
355             return;
356         },
357         static_cast<void *>(context),
358         &context->asyncWork);
359 
360     napi_queue_async_work(env, context->asyncWork);
361     if (context->asyncType == ASYNC_PROMISE) {
362         return context->promise;
363     } else {
364         return NapiGetNull(env);
365     }
366 }
367 
368 
NapiMac(HcfMac * macObj)369 NapiMac::NapiMac(HcfMac *macObj)
370 {
371     this->macObj_ = macObj;
372 }
373 
~NapiMac()374 NapiMac::~NapiMac()
375 {
376     HcfObjDestroy(this->macObj_);
377 }
378 
GetMac()379 HcfMac *NapiMac::GetMac()
380 {
381     return this->macObj_;
382 }
383 
JsMacInit(napi_env env,napi_callback_info info)384 napi_value NapiMac::JsMacInit(napi_env env, napi_callback_info info)
385 {
386     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
387     if (context == nullptr) {
388         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
389         LOGE("malloc context failed!");
390         return nullptr;
391     }
392 
393     if (!BuildMacJsInitCtx(env, info, context)) {
394         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
395         LOGE("build context fail.");
396         FreeCryptoFwkCtx(env, context);
397         return nullptr;
398     }
399 
400     return NewMacJsInitAsyncWork(env, context);
401 }
402 
JsMacUpdate(napi_env env,napi_callback_info info)403 napi_value NapiMac::JsMacUpdate(napi_env env, napi_callback_info info)
404 {
405     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
406     if (context == nullptr) {
407         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
408         LOGE("malloc context failed!");
409         return nullptr;
410     }
411 
412     if (!BuildMacJsUpdateCtx(env, info, context)) {
413         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
414         LOGE("build context fail.");
415         FreeCryptoFwkCtx(env, context);
416         return nullptr;
417     }
418 
419     return NewMacJsUpdateAsyncWork(env, context);
420 }
421 
JsMacDoFinal(napi_env env,napi_callback_info info)422 napi_value NapiMac::JsMacDoFinal(napi_env env, napi_callback_info info)
423 {
424     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
425     if (context == nullptr) {
426         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
427         LOGE("malloc context failed!");
428         return nullptr;
429     }
430 
431     if (!BuildMacJsDoFinalCtx(env, info, context)) {
432         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
433         LOGE("build context fail.");
434         FreeCryptoFwkCtx(env, context);
435         return nullptr;
436     }
437 
438     return NewMacJsDoFinalAsyncWork(env, context);
439 }
440 
JsGetMacLength(napi_env env,napi_callback_info info)441 napi_value NapiMac::JsGetMacLength(napi_env env, napi_callback_info info)
442 {
443     napi_value thisVar = nullptr;
444     NapiMac *napiMac = nullptr;
445 
446     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
447     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMac));
448     if (status != napi_ok || napiMac == nullptr) {
449         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiMac obj!"));
450         LOGE("failed to unwrap napiMac obj!");
451         return nullptr;
452     }
453 
454     HcfMac *mac = napiMac->GetMac();
455     if (mac == nullptr) {
456         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get mac obj!"));
457         LOGE("fail to get mac obj!");
458         return nullptr;
459     }
460 
461     uint32_t retLen = mac->getMacLength(mac);
462     napi_value napiLen = nullptr;
463     napi_create_uint32(env, retLen, &napiLen);
464     return napiLen;
465 }
466 
MacConstructor(napi_env env,napi_callback_info info)467 napi_value NapiMac::MacConstructor(napi_env env, napi_callback_info info)
468 {
469     napi_value thisVar = nullptr;
470     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
471     return thisVar;
472 }
473 
NapiWrapMac(napi_env env,napi_value instance,NapiMac * macNapiObj)474 static napi_value NapiWrapMac(napi_env env, napi_value instance, NapiMac *macNapiObj)
475 {
476     napi_status status = napi_wrap(
477         env, instance, macNapiObj,
478         [](napi_env env, void *data, void *hint) {
479             NapiMac *mac = static_cast<NapiMac *>(data);
480             delete mac;
481             return;
482         }, nullptr, nullptr);
483     if (status != napi_ok) {
484         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiMac obj!"));
485         delete macNapiObj;
486         macNapiObj = nullptr;
487         LOGE("failed to wrap NapiMac obj!");
488         return nullptr;
489     }
490     return instance;
491 }
492 
CreateMac(napi_env env,napi_callback_info info)493 napi_value NapiMac::CreateMac(napi_env env, napi_callback_info info)
494 {
495     LOGD("Enter CreateMac...");
496     size_t expectedArgc = ARGS_SIZE_ONE;
497     size_t argc = expectedArgc;
498     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
499     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
500     if (argc != expectedArgc) {
501         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
502         LOGE("The input args num is invalid.");
503         return nullptr;
504     }
505     std::string algoName;
506     if (!GetStringFromJSParams(env, argv[PARAM0], algoName)) {
507         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
508         LOGE("Failed to get algorithm.");
509         return nullptr;
510     }
511     HcfMac *macObj = nullptr;
512     HcfResult res = HcfMacCreate(algoName.c_str(), &macObj);
513     if (res != HCF_SUCCESS) {
514         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
515         LOGE("create c macObj failed.");
516         return nullptr;
517     }
518     napi_value napiAlgName = nullptr;
519     napi_create_string_utf8(env, algoName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
520     napi_value instance = nullptr;
521     napi_value constructor = nullptr;
522     napi_get_reference_value(env, classRef_, &constructor);
523     napi_new_instance(env, constructor, argc, argv, &instance);
524     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
525     NapiMac *macNapiObj = new (std::nothrow) NapiMac(macObj);
526     if (macNapiObj == nullptr) {
527         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new mac napi obj failed."));
528         HcfObjDestroy(macObj);
529         LOGE("create napi obj failed");
530         return nullptr;
531     }
532 
533     return NapiWrapMac(env, instance, macNapiObj);
534 }
535 
DefineMacJSClass(napi_env env,napi_value exports)536 void NapiMac::DefineMacJSClass(napi_env env, napi_value exports)
537 {
538     napi_property_descriptor desc[] = {
539         DECLARE_NAPI_FUNCTION("createMac", NapiMac::CreateMac),
540     };
541     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
542     napi_property_descriptor classDesc[] = {
543         DECLARE_NAPI_FUNCTION("init", NapiMac::JsMacInit),
544         DECLARE_NAPI_FUNCTION("update", NapiMac::JsMacUpdate),
545         DECLARE_NAPI_FUNCTION("doFinal", NapiMac::JsMacDoFinal),
546         DECLARE_NAPI_FUNCTION("getMacLength", NapiMac::JsGetMacLength),
547     };
548     napi_value constructor = nullptr;
549     napi_define_class(env, "Mac", NAPI_AUTO_LENGTH, MacConstructor, nullptr,
550         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
551     napi_create_reference(env, constructor, 1, &classRef_);
552 }
553 } // CryptoFramework
554 } // OHOS