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_md.h"
17
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21
22 #include "napi_utils.h"
23 #include "napi_crypto_framework_defines.h"
24
25 namespace OHOS {
26 namespace CryptoFramework {
27 thread_local napi_ref NapiMd::classRef_ = nullptr;
28
29 struct MdCtx {
30 napi_env env = nullptr;
31
32 CfAsyncType asyncType = ASYNC_TYPE_CALLBACK;
33 napi_ref callback = nullptr;
34 napi_deferred deferred = nullptr;
35 napi_value promise = nullptr;
36
37 napi_async_work asyncWork = nullptr;
38
39 NapiMd *mdClass = nullptr;
40 std::string algoName = "";
41 HcfBlob *inBlob = nullptr;
42
43 HcfResult errCode = HCF_SUCCESS;
44 const char *errMsg = nullptr;
45 HcfBlob *outBlob = nullptr;
46 };
47
FreeCryptoFwkCtx(napi_env env,MdCtx * context)48 static void FreeCryptoFwkCtx(napi_env env, MdCtx *context)
49 {
50 if (context == nullptr) {
51 return;
52 }
53 if (context->asyncWork != nullptr) {
54 napi_delete_async_work(env, context->asyncWork);
55 context->asyncWork = nullptr;
56 }
57 if (context->callback != nullptr) {
58 napi_delete_reference(env, context->callback);
59 context->callback = nullptr;
60 }
61 if (context->inBlob != nullptr) {
62 HcfFree(context->inBlob->data);
63 context->inBlob->data = nullptr;
64 context->inBlob->len = 0;
65 HcfFree(context->inBlob);
66 context->inBlob = nullptr;
67 }
68 if (context->outBlob != nullptr) {
69 HcfFree(context->outBlob->data);
70 context->outBlob->data = nullptr;
71 context->outBlob->len = 0;
72 HcfFree(context->outBlob);
73 context->outBlob = nullptr;
74 }
75 context->errMsg = nullptr;
76 HcfFree(context);
77 context = nullptr;
78 }
79
ReturnCallbackResult(napi_env env,MdCtx * context,napi_value result)80 static void ReturnCallbackResult(napi_env env, MdCtx *context, napi_value result)
81 {
82 napi_value businessError = nullptr;
83 if (context->errCode != HCF_SUCCESS) {
84 businessError = GenerateBusinessError(env, context->errCode, context->errMsg, false);
85 }
86 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
87 napi_value func = nullptr;
88 napi_get_reference_value(env, context->callback, &func);
89
90 napi_value recv = nullptr;
91 napi_value callFuncRet = nullptr;
92 napi_get_undefined(env, &recv);
93 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
94 }
95
ReturnPromiseResult(napi_env env,MdCtx * context,napi_value result)96 static void ReturnPromiseResult(napi_env env, MdCtx *context, napi_value result)
97 {
98 if (context->errCode == HCF_SUCCESS) {
99 napi_resolve_deferred(env, context->deferred, result);
100 } else {
101 napi_reject_deferred(env, context->deferred,
102 GenerateBusinessError(env, context->errCode, context->errMsg, false));
103 }
104 }
105
CreateCallbackAndPromise(napi_env env,MdCtx * context,size_t argc,size_t maxCount,napi_value callbackValue)106 static bool CreateCallbackAndPromise(napi_env env, MdCtx *context, size_t argc,
107 size_t maxCount, napi_value callbackValue)
108 {
109 context->asyncType = (argc == maxCount) ? ASYNC_TYPE_CALLBACK : ASYNC_TYPE_PROMISE;
110 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
111 if (!GetCallbackFromJSParams(env, callbackValue, &context->callback, false)) {
112 LOGE("get callback failed!");
113 return false;
114 }
115 } else {
116 napi_create_promise(env, &context->deferred, &context->promise);
117 }
118 return true;
119 }
120
NapiMd(HcfMd * mdObj)121 NapiMd::NapiMd(HcfMd *mdObj)
122 {
123 this->mdObj_ = mdObj;
124 }
125
~NapiMd()126 NapiMd::~NapiMd()
127 {
128 HcfObjDestroy(this->mdObj_);
129 }
130
MdUpdateExecute(napi_env env,void * data)131 static void MdUpdateExecute(napi_env env, void *data)
132 {
133 MdCtx *context = static_cast<MdCtx *>(data);
134 NapiMd *mdClass = context->mdClass;
135 HcfMd *mdObj = mdClass->GetMd();
136 context->errCode = mdObj->update(mdObj, context->inBlob);
137 if (context->errCode != HCF_SUCCESS) {
138 LOGE("update failed!");
139 context->errMsg = "update failed";
140 }
141 }
142
MdUpdateComplete(napi_env env,napi_status status,void * data)143 static void MdUpdateComplete(napi_env env, napi_status status, void *data)
144 {
145 MdCtx *context = static_cast<MdCtx *>(data);
146 napi_value nullInstance = nullptr;
147 napi_get_null(env, &nullInstance);
148 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
149 ReturnCallbackResult(env, context, nullInstance);
150 } else {
151 ReturnPromiseResult(env, context, nullInstance);
152 }
153 FreeCryptoFwkCtx(env, context);
154 }
155
MdDoFinalExecute(napi_env env,void * data)156 static void MdDoFinalExecute(napi_env env, void *data)
157 {
158 MdCtx *context = static_cast<MdCtx *>(data);
159 NapiMd *mdClass = context->mdClass;
160 HcfMd *mdObj = mdClass->GetMd();
161 HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
162 if (outBlob == nullptr) {
163 LOGE("outBlob is null!");
164 context->errCode = HCF_ERR_MALLOC;
165 context->errMsg = "malloc data blob failed";
166 return;
167 }
168 context->errCode = mdObj->doFinal(mdObj, outBlob);
169 if (context->errCode != HCF_SUCCESS) {
170 LOGE("doFinal failed!");
171 context->errMsg = "doFinal failed";
172 HcfFree(outBlob);
173 outBlob = nullptr;
174 return;
175 }
176 context->outBlob = outBlob;
177 }
178
MdDoFinalComplete(napi_env env,napi_status status,void * data)179 static void MdDoFinalComplete(napi_env env, napi_status status, void *data)
180 {
181 MdCtx *context = static_cast<MdCtx *>(data);
182 napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
183 if (returnOutBlob == nullptr) {
184 LOGE("returnOutBlob is nullptr!");
185 returnOutBlob = NapiGetNull(env);
186 }
187 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
188 ReturnCallbackResult(env, context, returnOutBlob);
189 } else {
190 ReturnPromiseResult(env, context, returnOutBlob);
191 }
192 FreeCryptoFwkCtx(env, context);
193 }
194
MdUpdate(napi_env env,napi_callback_info info)195 napi_value NapiMd::MdUpdate(napi_env env, napi_callback_info info)
196 {
197 // check param count
198 size_t argc = ARGS_SIZE_TWO;
199 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
200 napi_value thisVar = nullptr;
201 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
202 if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false, false)) {
203 return nullptr;
204 }
205 MdCtx *context = static_cast<MdCtx *>(HcfMalloc(sizeof(MdCtx), 0));
206 if (context == nullptr) {
207 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
208 LOGE("malloc context failed!");
209 return nullptr;
210 }
211 context->mdClass = this;
212 context->inBlob = GetBlobFromNapiValue(env, argv[PARAM0]);
213 if (context->inBlob == nullptr) {
214 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "inBlob is null", false));
215 LOGE("inBlob is null!");
216 FreeCryptoFwkCtx(env, context);
217 return nullptr;
218 }
219 if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
220 FreeCryptoFwkCtx(env, context);
221 return nullptr;
222 }
223 napi_create_async_work(
224 env, nullptr, GetResourceName(env, "MdUpdate"),
225 MdUpdateExecute,
226 MdUpdateComplete,
227 static_cast<void *>(context),
228 &context->asyncWork);
229 napi_queue_async_work(env, context->asyncWork);
230 if (context->asyncType == ASYNC_TYPE_PROMISE) {
231 return context->promise;
232 } else {
233 return NapiGetNull(env);
234 }
235 }
236
MdDoFinal(napi_env env,napi_callback_info info)237 napi_value NapiMd::MdDoFinal(napi_env env, napi_callback_info info)
238 {
239 size_t expectedArgsCount = ARGS_SIZE_ONE;
240 size_t argc = expectedArgsCount;
241 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
242 napi_value thisVar = nullptr;
243 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
244 if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false, false)) {
245 return nullptr;
246 }
247 MdCtx *context = static_cast<MdCtx *>(HcfMalloc(sizeof(MdCtx), 0));
248 if (context == nullptr) {
249 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed", false));
250 LOGE("malloc context failed!");
251 return nullptr;
252 }
253 context->mdClass = this;
254 if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_ONE, argv[PARAM0])) {
255 FreeCryptoFwkCtx(env, context);
256 return nullptr;
257 }
258 napi_create_async_work(
259 env, nullptr, GetResourceName(env, "MdDoFinal"),
260 MdDoFinalExecute,
261 MdDoFinalComplete,
262 static_cast<void *>(context),
263 &context->asyncWork);
264 napi_queue_async_work(env, context->asyncWork);
265 if (context->asyncType == ASYNC_TYPE_PROMISE) {
266 return context->promise;
267 } else {
268 return NapiGetNull(env);
269 }
270 }
271
GetMdLength(napi_env env,napi_callback_info info)272 napi_value NapiMd::GetMdLength(napi_env env, napi_callback_info info)
273 {
274 HcfMd *mdObj = GetMd();
275 uint32_t retLen = mdObj->getMdLength(mdObj);
276 napi_value napiLen = nullptr;
277 napi_create_uint32(env, retLen, &napiLen);
278 return napiLen;
279 }
280
NapiMdUpdate(napi_env env,napi_callback_info info)281 static napi_value NapiMdUpdate(napi_env env, napi_callback_info info)
282 {
283 napi_value thisVar = nullptr;
284 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
285 NapiMd *mdObj = nullptr;
286 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&mdObj));
287 if (mdObj == nullptr) {
288 LOGE("mdObj is nullptr!");
289 return NapiGetNull(env);
290 }
291 return mdObj->MdUpdate(env, info);
292 }
293
NapiMdDoFinal(napi_env env,napi_callback_info info)294 static napi_value NapiMdDoFinal(napi_env env, napi_callback_info info)
295 {
296 napi_value thisVar = nullptr;
297 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
298 NapiMd *mdObj = nullptr;
299 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&mdObj));
300 if (mdObj == nullptr) {
301 LOGE("mdObj is nullptr!");
302 return NapiGetNull(env);
303 }
304 return mdObj->MdDoFinal(env, info);
305 }
306
NapiGetMdLength(napi_env env,napi_callback_info info)307 static napi_value NapiGetMdLength(napi_env env, napi_callback_info info)
308 {
309 napi_value thisVar = nullptr;
310 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
311 NapiMd *mdObj = nullptr;
312 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&mdObj));
313 if (mdObj == nullptr) {
314 LOGE("mdObj is nullptr!");
315 return NapiGetNull(env);
316 }
317 return mdObj->GetMdLength(env, info);
318 }
319
MdConstructor(napi_env env,napi_callback_info info)320 napi_value NapiMd::MdConstructor(napi_env env, napi_callback_info info)
321 {
322 napi_value thisVar = nullptr;
323 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
324 return thisVar;
325 }
326
CreateMd(napi_env env,napi_callback_info info)327 napi_value NapiMd::CreateMd(napi_env env, napi_callback_info info)
328 {
329 size_t expectedArgc = ARGS_SIZE_ONE;
330 size_t argc = expectedArgc;
331 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
332 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
333 if (argc != expectedArgc) {
334 LOGE("The input args num is invalid.");
335 return nullptr;
336 }
337 std::string algoName;
338 if (!GetStringFromJSParams(env, argv[PARAM0], algoName, false)) {
339 LOGE("Failed to get algorithm.");
340 return nullptr;
341 }
342 HcfMd *mdObj = nullptr;
343 HcfResult res = HcfMdCreate(algoName.c_str(), &mdObj);
344 if (res != HCF_SUCCESS) {
345 napi_throw(env, GenerateBusinessError(env, res, "create C obj failed.", false));
346 LOGE("create c mdObj failed.");
347 return nullptr;
348 }
349 napi_value napiAlgName = nullptr;
350 napi_create_string_utf8(env, algoName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
351 napi_value instance = nullptr;
352 napi_value constructor = nullptr;
353 napi_get_reference_value(env, classRef_, &constructor);
354 napi_new_instance(env, constructor, argc, argv, &instance);
355 napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
356 NapiMd *mdNapiObj = new (std::nothrow) NapiMd(mdObj);
357 if (mdNapiObj == nullptr) {
358 LOGE("create napi obj failed");
359 return nullptr;
360 }
361 napi_wrap(
362 env, instance, mdNapiObj,
363 [](napi_env env, void *data, void *hint) {
364 NapiMd *md = static_cast<NapiMd *>(data);
365 delete md;
366 return;
367 },
368 nullptr,
369 nullptr);
370 return instance;
371 }
372
DefineMdJSClass(napi_env env,napi_value exports)373 void NapiMd::DefineMdJSClass(napi_env env, napi_value exports)
374 {
375 napi_property_descriptor desc[] = {
376 DECLARE_NAPI_FUNCTION("createMd", CreateMd),
377 };
378 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
379 napi_property_descriptor classDesc[] = {
380 DECLARE_NAPI_FUNCTION("update", NapiMdUpdate),
381 DECLARE_NAPI_FUNCTION("digest", NapiMdDoFinal),
382 DECLARE_NAPI_FUNCTION("getMdLength", NapiGetMdLength),
383 };
384 napi_value constructor = nullptr;
385 napi_define_class(env, "Md", NAPI_AUTO_LENGTH, MdConstructor, nullptr,
386 sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
387 napi_create_reference(env, constructor, 1, &classRef_);
388 }
389 } // CryptoFramework
390 } // OHOS