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