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