• 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     CfAsyncType asyncType = ASYNC_TYPE_CALLBACK;
34     napi_ref callback = nullptr;
35     napi_deferred deferred = nullptr;
36     napi_value promise = nullptr;
37     napi_async_work asyncWork = nullptr;
38 
39     NapiMac *macClass = nullptr;
40     std::string algoName = "";
41     HcfSymKey *symKey = nullptr;
42     HcfBlob *inBlob = nullptr;
43 
44     HcfResult errCode = HCF_SUCCESS;
45     const char *errMsg = nullptr;
46     HcfBlob *outBlob = 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     HcfFree(context);
79     context = nullptr;
80 }
81 
ReturnCallbackResult(napi_env env,MacCtx * context,napi_value result)82 static void ReturnCallbackResult(napi_env env, MacCtx *context, napi_value result)
83 {
84     napi_value businessError = nullptr;
85     if (context->errCode != HCF_SUCCESS) {
86         businessError = GenerateBusinessError(env, context->errCode, context->errMsg, false);
87     }
88     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
89 
90     napi_value func = nullptr;
91     napi_get_reference_value(env, context->callback, &func);
92 
93     napi_value recv = nullptr;
94     napi_value callFuncRet = nullptr;
95     napi_get_undefined(env, &recv);
96     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
97 }
98 
ReturnPromiseResult(napi_env env,MacCtx * context,napi_value result)99 static void ReturnPromiseResult(napi_env env, MacCtx *context, napi_value result)
100 {
101     if (context->errCode == HCF_SUCCESS) {
102         napi_resolve_deferred(env, context->deferred, result);
103     } else {
104         napi_reject_deferred(env, context->deferred,
105             GenerateBusinessError(env, context->errCode, context->errMsg, false));
106     }
107 }
108 
CreateCallbackAndPromise(napi_env env,MacCtx * context,size_t argc,size_t maxCount,napi_value callbackValue)109 static bool CreateCallbackAndPromise(napi_env env, MacCtx *context, size_t argc,
110     size_t maxCount, napi_value callbackValue)
111 {
112     context->asyncType = (argc == maxCount) ? ASYNC_TYPE_CALLBACK : ASYNC_TYPE_PROMISE;
113     if (context->asyncType == ASYNC_TYPE_CALLBACK) {
114         if (!GetCallbackFromJSParams(env, callbackValue, &context->callback, false)) {
115             LOGE("get callback failed!");
116             return false;
117         }
118     } else {
119         napi_create_promise(env, &context->deferred, &context->promise);
120     }
121     return true;
122 }
123 
NapiMac(HcfMac * macObj)124 NapiMac::NapiMac(HcfMac *macObj)
125 {
126     this->macObj_ = macObj;
127 }
128 
~NapiMac()129 NapiMac::~NapiMac()
130 {
131     HcfObjDestroy(this->macObj_);
132 }
133 
MacInitExecute(napi_env env,void * data)134 static void MacInitExecute(napi_env env, void *data)
135 {
136     MacCtx *context = static_cast<MacCtx *>(data);
137     NapiMac *macClass = context->macClass;
138     HcfMac *macObj = macClass->GetMac();
139     HcfSymKey *symKey = context->symKey;
140     context->errCode = macObj->init(macObj, symKey);
141     if (context->errCode != HCF_SUCCESS) {
142         LOGE("init failed!");
143         context->errMsg = "init failed";
144     }
145 }
146 
MacInitComplete(napi_env env,napi_status status,void * data)147 static void MacInitComplete(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_TYPE_CALLBACK) {
153         ReturnCallbackResult(env, context, nullInstance);
154     } else {
155         ReturnPromiseResult(env, context, nullInstance);
156     }
157     FreeCryptoFwkCtx(env, context);
158 }
159 
MacUpdateExecute(napi_env env,void * data)160 static void MacUpdateExecute(napi_env env, void *data)
161 {
162     MacCtx *context = static_cast<MacCtx *>(data);
163     NapiMac *macClass = context->macClass;
164     HcfMac *macObj = macClass->GetMac();
165     HcfBlob *inBlob = reinterpret_cast<HcfBlob *>(context->inBlob);
166     context->errCode = macObj->update(macObj, inBlob);
167     if (context->errCode != HCF_SUCCESS) {
168         LOGE("update failed!");
169         context->errMsg = "update failed";
170     }
171 }
172 
MacUpdateComplete(napi_env env,napi_status status,void * data)173 static void MacUpdateComplete(napi_env env, napi_status status, void *data)
174 {
175     MacCtx *context = static_cast<MacCtx *>(data);
176     napi_value nullInstance = nullptr;
177     napi_get_null(env, &nullInstance);
178     if (context->asyncType == ASYNC_TYPE_CALLBACK) {
179         ReturnCallbackResult(env, context, nullInstance);
180     } else {
181         ReturnPromiseResult(env, context, nullInstance);
182     }
183     FreeCryptoFwkCtx(env, context);
184 }
185 
MacDoFinalExecute(napi_env env,void * data)186 static void MacDoFinalExecute(napi_env env, void *data)
187 {
188     MacCtx *context = static_cast<MacCtx *>(data);
189     NapiMac *macClass = context->macClass;
190     HcfMac *macObj = macClass->GetMac();
191     HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
192     if (outBlob == nullptr) {
193         LOGE("outBlob is null!");
194         context->errCode = HCF_ERR_MALLOC;
195         context->errMsg = "malloc data blob failed";
196         return;
197     }
198     context->errCode = macObj->doFinal(macObj, outBlob);
199     if (context->errCode != HCF_SUCCESS) {
200         LOGE("doFinal failed!");
201         context->errMsg = "doFinal failed";
202         HcfFree(outBlob);
203         outBlob = nullptr;
204         return;
205     }
206     context->outBlob = outBlob;
207 }
208 
MacDoFinalComplete(napi_env env,napi_status status,void * data)209 static void MacDoFinalComplete(napi_env env, napi_status status, void *data)
210 {
211     MacCtx *context = static_cast<MacCtx *>(data);
212     napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
213     if (returnOutBlob == nullptr) {
214         LOGE("returnOutBlob is nullptr!");
215         returnOutBlob = NapiGetNull(env);
216     }
217     if (context->asyncType == ASYNC_TYPE_CALLBACK) {
218         ReturnCallbackResult(env, context, returnOutBlob);
219     } else {
220         ReturnPromiseResult(env, context, returnOutBlob);
221     }
222     FreeCryptoFwkCtx(env, context);
223 }
224 
MacInit(napi_env env,napi_callback_info info)225 napi_value NapiMac::MacInit(napi_env env, napi_callback_info info)
226 {
227     size_t expectedArgsCount = ARGS_SIZE_TWO;
228     size_t argc = expectedArgsCount;
229     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
230     napi_value thisVar = nullptr;
231     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
232     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false, false)) {
233         return nullptr;
234     }
235     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
236     if (context == nullptr) {
237         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
238         LOGE("malloc context failed!");
239         return nullptr;
240     }
241     context->macClass = this;
242     NapiSymKey *symKey = nullptr;
243     napi_unwrap(env, argv[PARAM0], reinterpret_cast<void **>(&symKey));
244     if (symKey == nullptr) {
245         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "symKey is null", false));
246         LOGE("symKey is null!");
247         FreeCryptoFwkCtx(env, context);
248         return nullptr;
249     }
250     context->symKey = symKey->GetSymKey();
251     context->asyncType = (argc == expectedArgsCount) ? ASYNC_TYPE_CALLBACK : ASYNC_TYPE_PROMISE;
252     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
253         FreeCryptoFwkCtx(env, context);
254         return nullptr;
255     }
256     napi_create_async_work(
257         env, nullptr, GetResourceName(env, "Init"),
258         MacInitExecute,
259         MacInitComplete,
260         static_cast<void *>(context),
261         &context->asyncWork);
262     napi_queue_async_work(env, context->asyncWork);
263     if (context->asyncType == ASYNC_TYPE_PROMISE) {
264         return context->promise;
265     } else {
266         return NapiGetNull(env);
267     }
268 }
269 
MacUpdate(napi_env env,napi_callback_info info)270 napi_value NapiMac::MacUpdate(napi_env env, napi_callback_info info)
271 {
272     size_t expectedArgsCount = ARGS_SIZE_TWO;
273     size_t argc = expectedArgsCount;
274     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
275     napi_value thisVar = nullptr;
276     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
277     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false, false)) {
278         return nullptr;
279     }
280     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
281     if (context == nullptr) {
282         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
283         LOGE("malloc context failed!");
284         return nullptr;
285     }
286     context->macClass = this;
287     context->inBlob = GetBlobFromNapiValue(env, argv[PARAM0]);
288     if (context->inBlob == nullptr) {
289         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "inBlob is null", false));
290         LOGE("inBlob is null!");
291         FreeCryptoFwkCtx(env, context);
292         return nullptr;
293     }
294     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
295         FreeCryptoFwkCtx(env, context);
296         return nullptr;
297     }
298     napi_create_async_work(
299         env, nullptr, GetResourceName(env, "MacUpate"),
300         MacUpdateExecute,
301         MacUpdateComplete,
302         static_cast<void *>(context),
303         &context->asyncWork);
304     napi_queue_async_work(env, context->asyncWork);
305     if (context->asyncType == ASYNC_TYPE_PROMISE) {
306         return context->promise;
307     } else {
308         return NapiGetNull(env);
309     }
310 }
311 
MacDoFinal(napi_env env,napi_callback_info info)312 napi_value NapiMac::MacDoFinal(napi_env env, napi_callback_info info)
313 {
314     size_t expectedArgsCount = ARGS_SIZE_ONE;
315     size_t argc = expectedArgsCount;
316     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
317     napi_value thisVar = nullptr;
318     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
319     if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false, false)) {
320         return nullptr;
321     }
322     MacCtx *context = static_cast<MacCtx *>(HcfMalloc(sizeof(MacCtx), 0));
323     if (context == nullptr) {
324         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
325         LOGE("malloc context failed!");
326         return nullptr;
327     }
328     context->macClass = this;
329     context->asyncType = (argc == expectedArgsCount) ? ASYNC_TYPE_CALLBACK : ASYNC_TYPE_PROMISE;
330     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_ONE, argv[PARAM0])) {
331         FreeCryptoFwkCtx(env, context);
332         return nullptr;
333     }
334     napi_create_async_work(
335         env, nullptr, GetResourceName(env, "MacDoFinal"),
336         MacDoFinalExecute,
337         MacDoFinalComplete,
338         static_cast<void *>(context),
339         &context->asyncWork);
340     napi_queue_async_work(env, context->asyncWork);
341     if (context->asyncType == ASYNC_TYPE_PROMISE) {
342         return context->promise;
343     } else {
344         return NapiGetNull(env);
345     }
346 }
347 
GetMacLength(napi_env env,napi_callback_info info)348 napi_value NapiMac::GetMacLength(napi_env env, napi_callback_info info)
349 {
350     HcfMac *macObj = GetMac();
351     uint32_t retLen = macObj->getMacLength(macObj);
352     napi_value napiLen = nullptr;
353     napi_create_uint32(env, retLen, &napiLen);
354     return napiLen;
355 }
356 
NapiMacInit(napi_env env,napi_callback_info info)357 static napi_value NapiMacInit(napi_env env, napi_callback_info info)
358 {
359     napi_value thisVar = nullptr;
360     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
361     NapiMac *macObj = nullptr;
362     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&macObj));
363     if (macObj == nullptr) {
364         LOGE("macObj is nullptr!");
365         return NapiGetNull(env);
366     }
367     return macObj->MacInit(env, info);
368 }
369 
NapiMacUpdate(napi_env env,napi_callback_info info)370 static napi_value NapiMacUpdate(napi_env env, napi_callback_info info)
371 {
372     napi_value thisVar = nullptr;
373     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
374     NapiMac *macObj = nullptr;
375     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&macObj));
376     if (macObj == nullptr) {
377         LOGE("macObj is nullptr!");
378         return NapiGetNull(env);
379     }
380     return macObj->MacUpdate(env, info);
381 }
382 
NapiMacDoFinal(napi_env env,napi_callback_info info)383 static napi_value NapiMacDoFinal(napi_env env, napi_callback_info info)
384 {
385     napi_value thisVar = nullptr;
386     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
387     NapiMac *macObj = nullptr;
388     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&macObj));
389     if (macObj == nullptr) {
390         LOGE("macObj is nullptr!");
391         return NapiGetNull(env);
392     }
393     return macObj->MacDoFinal(env, info);
394 }
395 
NapiGetMacLength(napi_env env,napi_callback_info info)396 static napi_value NapiGetMacLength(napi_env env, napi_callback_info info)
397 {
398     napi_value thisVar = nullptr;
399     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
400     NapiMac *macObj = nullptr;
401     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&macObj));
402     if (macObj == nullptr) {
403         LOGE("macObj is nullptr!");
404         return NapiGetNull(env);
405     }
406     return macObj->GetMacLength(env, info);
407 }
408 
MacConstructor(napi_env env,napi_callback_info info)409 napi_value NapiMac::MacConstructor(napi_env env, napi_callback_info info)
410 {
411     napi_value thisVar = nullptr;
412     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
413     return thisVar;
414 }
415 
CreateMac(napi_env env,napi_callback_info info)416 napi_value NapiMac::CreateMac(napi_env env, napi_callback_info info)
417 {
418     size_t expectedArgc = ARGS_SIZE_ONE;
419     size_t argc = expectedArgc;
420     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
421     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
422     if (argc != expectedArgc) {
423         LOGE("The input args num is invalid.");
424         return nullptr;
425     }
426     std::string algoName;
427     if (!GetStringFromJSParams(env, argv[PARAM0], algoName, false)) {
428         LOGE("Failed to get algorithm.");
429         return nullptr;
430     }
431     HcfMac *macObj = nullptr;
432     HcfResult res = HcfMacCreate(algoName.c_str(), &macObj);
433     if (res != HCF_SUCCESS) {
434         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed.", false));
435         LOGE("create c macObj failed.");
436         return nullptr;
437     }
438     napi_value napiAlgName = nullptr;
439     napi_create_string_utf8(env, algoName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
440     napi_value instance = nullptr;
441     napi_value constructor = nullptr;
442     napi_get_reference_value(env, classRef_, &constructor);
443     napi_new_instance(env, constructor, argc, argv, &instance);
444     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
445     NapiMac *macNapiObj = new (std::nothrow) NapiMac(macObj);
446     if (macNapiObj == nullptr) {
447         LOGE("create napi obj failed");
448         return nullptr;
449     }
450     napi_wrap(
451         env, instance, macNapiObj,
452         [](napi_env env, void *data, void *hint) {
453             NapiMac *mac = static_cast<NapiMac *>(data);
454             delete mac;
455             return;
456         },
457         nullptr,
458         nullptr);
459     return instance;
460 }
461 
DefineMacJSClass(napi_env env,napi_value exports)462 void NapiMac::DefineMacJSClass(napi_env env, napi_value exports)
463 {
464     napi_property_descriptor desc[] = {
465         DECLARE_NAPI_FUNCTION("createMac", CreateMac),
466     };
467     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
468     napi_property_descriptor classDesc[] = {
469         DECLARE_NAPI_FUNCTION("init", NapiMacInit),
470         DECLARE_NAPI_FUNCTION("update", NapiMacUpdate),
471         DECLARE_NAPI_FUNCTION("doFinal", NapiMacDoFinal),
472         DECLARE_NAPI_FUNCTION("getMacLength", NapiGetMacLength),
473     };
474     napi_value constructor = nullptr;
475     napi_define_class(env, "Mac", NAPI_AUTO_LENGTH, MacConstructor, nullptr,
476         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
477     napi_create_reference(env, constructor, 1, &classRef_);
478 }
479 } // CryptoFramework
480 } // OHOS