• 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_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     AsyncType asyncType = ASYNC_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     std::string algoName = "";
40     HcfBlob *inBlob = nullptr;
41 
42     HcfResult errCode = HCF_SUCCESS;
43     const char *errMsg = nullptr;
44     HcfBlob *outBlob = nullptr;
45     HcfMd *md = 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     context->md = nullptr;
77     HcfFree(context);
78     context = nullptr;
79 }
80 
ReturnCallbackResult(napi_env env,MdCtx * context,napi_value result)81 static void ReturnCallbackResult(napi_env env, MdCtx *context, napi_value result)
82 {
83     napi_value businessError = nullptr;
84     if (context->errCode != HCF_SUCCESS) {
85         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
86     }
87     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
88     napi_value func = nullptr;
89     napi_get_reference_value(env, context->callback, &func);
90 
91     napi_value recv = nullptr;
92     napi_value callFuncRet = nullptr;
93     napi_get_undefined(env, &recv);
94     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
95 }
96 
ReturnPromiseResult(napi_env env,MdCtx * context,napi_value result)97 static void ReturnPromiseResult(napi_env env, MdCtx *context, napi_value result)
98 {
99     if (context->errCode == HCF_SUCCESS) {
100         napi_resolve_deferred(env, context->deferred, result);
101     } else {
102         napi_reject_deferred(env, context->deferred,
103             GenerateBusinessError(env, context->errCode, context->errMsg));
104     }
105 }
106 
MdUpdateExecute(napi_env env,void * data)107 static void MdUpdateExecute(napi_env env, void *data)
108 {
109     MdCtx *context = static_cast<MdCtx *>(data);
110     HcfMd *mdObj = context->md;
111     context->errCode = mdObj->update(mdObj, context->inBlob);
112     if (context->errCode != HCF_SUCCESS) {
113         LOGD("[error] update failed!");
114         context->errMsg = "update failed";
115     }
116 }
117 
MdDoFinalExecute(napi_env env,void * data)118 static void MdDoFinalExecute(napi_env env, void *data)
119 {
120     MdCtx *context = static_cast<MdCtx *>(data);
121     HcfMd *mdObj = context->md;
122     HcfBlob *outBlob = reinterpret_cast<HcfBlob *>(HcfMalloc(sizeof(HcfBlob), 0));
123     if (outBlob == nullptr) {
124         LOGE("outBlob is null!");
125         context->errCode = HCF_ERR_MALLOC;
126         context->errMsg = "malloc data blob failed";
127         return;
128     }
129     context->errCode = mdObj->doFinal(mdObj, outBlob);
130     if (context->errCode != HCF_SUCCESS) {
131         HcfFree(outBlob);
132         LOGD("[error] doFinal failed!");
133         context->errMsg = "doFinal failed";
134         return;
135     }
136     context->outBlob = outBlob;
137 }
138 
MdUpdateComplete(napi_env env,napi_status status,void * data)139 static void MdUpdateComplete(napi_env env, napi_status status, void *data)
140 {
141     MdCtx *context = static_cast<MdCtx *>(data);
142     napi_value nullInstance = nullptr;
143     napi_get_null(env, &nullInstance);
144     if (context->asyncType == ASYNC_CALLBACK) {
145         ReturnCallbackResult(env, context, nullInstance);
146     } else {
147         ReturnPromiseResult(env, context, nullInstance);
148     }
149     FreeCryptoFwkCtx(env, context);
150 }
151 
MdDoFinalComplete(napi_env env,napi_status status,void * data)152 static void MdDoFinalComplete(napi_env env, napi_status status, void *data)
153 {
154     MdCtx *context = static_cast<MdCtx *>(data);
155     napi_value returnOutBlob = ConvertBlobToNapiValue(env, context->outBlob);
156     if (returnOutBlob == nullptr) {
157         LOGE("returnOutBlob is nullptr!");
158         returnOutBlob = NapiGetNull(env);
159     }
160     if (context->asyncType == ASYNC_CALLBACK) {
161         ReturnCallbackResult(env, context, returnOutBlob);
162     } else {
163         ReturnPromiseResult(env, context, returnOutBlob);
164     }
165     FreeCryptoFwkCtx(env, context);
166 }
167 
BuildMdJsUpdateCtx(napi_env env,napi_callback_info info,MdCtx * context)168 static bool BuildMdJsUpdateCtx(napi_env env, napi_callback_info info, MdCtx *context)
169 {
170     napi_value thisVar = nullptr;
171     NapiMd *napiMd = nullptr;
172     size_t expectedArgsCount = ARGS_SIZE_TWO;
173     size_t argc = expectedArgsCount;
174     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
175     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
176     if (!CheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
177         return false;
178     }
179 
180     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
181         ASYNC_CALLBACK : ASYNC_PROMISE;
182     context->inBlob = GetBlobFromNapiDataBlob(env, argv[PARAM0]);
183     if (context->inBlob == nullptr) {
184         LOGE("inBlob is null!");
185         return false;
186     }
187     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMd));
188     if (status != napi_ok || napiMd == nullptr) {
189         LOGE("failed to unwrap NapiMd obj!");
190         return false;
191     }
192 
193     context->md = napiMd->GetMd();
194 
195     if (context->asyncType == ASYNC_PROMISE) {
196         napi_create_promise(env, &context->deferred, &context->promise);
197         return true;
198     } else {
199         return GetCallbackFromJSParams(env, argv[PARAM1], &context->callback);
200     }
201 }
202 
BuildMdJsDoFinalCtx(napi_env env,napi_callback_info info,MdCtx * context)203 static bool BuildMdJsDoFinalCtx(napi_env env, napi_callback_info info, MdCtx *context)
204 {
205     napi_value thisVar = nullptr;
206     NapiMd *napiMd = nullptr;
207     size_t expectedArgsCount = ARGS_SIZE_ONE;
208     size_t argc = expectedArgsCount;
209     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
210     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
211     if (!CheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
212         return false;
213     }
214 
215     context->asyncType = isCallback(env, argv[expectedArgsCount - 1], argc, expectedArgsCount) ?
216         ASYNC_CALLBACK : ASYNC_PROMISE;
217 
218     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMd));
219     if (status != napi_ok || napiMd == nullptr) {
220         LOGE("failed to unwrap NapiMd obj!");
221         return false;
222     }
223 
224     context->md = napiMd->GetMd();
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[PARAM0], &context->callback);
231     }
232 }
233 
NewMdJsUpdateAsyncWork(napi_env env,MdCtx * context)234 static napi_value NewMdJsUpdateAsyncWork(napi_env env, MdCtx *context)
235 {
236     napi_create_async_work(
237         env, nullptr, GetResourceName(env, "MdUpdate"),
238         [](napi_env env, void *data) {
239             MdUpdateExecute(env, data);
240             return;
241         },
242         [](napi_env env, napi_status status, void *data) {
243             MdUpdateComplete(env, status, data);
244             return;
245         },
246         static_cast<void *>(context),
247         &context->asyncWork);
248 
249     napi_queue_async_work(env, context->asyncWork);
250     if (context->asyncType == ASYNC_PROMISE) {
251         return context->promise;
252     } else {
253         return NapiGetNull(env);
254     }
255 }
256 
NewMdJsDoFinalAsyncWork(napi_env env,MdCtx * context)257 static napi_value NewMdJsDoFinalAsyncWork(napi_env env, MdCtx *context)
258 {
259     napi_create_async_work(
260         env, nullptr, GetResourceName(env, "MdDoFinal"),
261         [](napi_env env, void *data) {
262             MdDoFinalExecute(env, data);
263             return;
264         },
265         [](napi_env env, napi_status status, void *data) {
266             MdDoFinalComplete(env, status, data);
267             return;
268         },
269         static_cast<void *>(context),
270         &context->asyncWork);
271 
272     napi_queue_async_work(env, context->asyncWork);
273     if (context->asyncType == ASYNC_PROMISE) {
274         return context->promise;
275     } else {
276         return NapiGetNull(env);
277     }
278 }
279 
NapiMd(HcfMd * mdObj)280 NapiMd::NapiMd(HcfMd *mdObj)
281 {
282     this->mdObj_ = mdObj;
283 }
284 
~NapiMd()285 NapiMd::~NapiMd()
286 {
287     HcfObjDestroy(this->mdObj_);
288 }
289 
GetMd()290 HcfMd *NapiMd::GetMd()
291 {
292     return this->mdObj_;
293 }
294 
JsMdUpdate(napi_env env,napi_callback_info info)295 napi_value NapiMd::JsMdUpdate(napi_env env, napi_callback_info info)
296 {
297     MdCtx *context = static_cast<MdCtx *>(HcfMalloc(sizeof(MdCtx), 0));
298     if (context == nullptr) {
299         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
300         LOGE("malloc context failed!");
301         return nullptr;
302     }
303 
304     if (!BuildMdJsUpdateCtx(env, info, context)) {
305         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
306         LOGE("build context fail.");
307         FreeCryptoFwkCtx(env, context);
308         return nullptr;
309     }
310 
311     return NewMdJsUpdateAsyncWork(env, context);
312 }
313 
JsMdDoFinal(napi_env env,napi_callback_info info)314 napi_value NapiMd::JsMdDoFinal(napi_env env, napi_callback_info info)
315 {
316     MdCtx *context = static_cast<MdCtx *>(HcfMalloc(sizeof(MdCtx), 0));
317     if (context == nullptr) {
318         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc context failed"));
319         LOGE("malloc context failed!");
320         return nullptr;
321     }
322 
323     if (!BuildMdJsDoFinalCtx(env, info, context)) {
324         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "build context fail."));
325         LOGE("build context fail.");
326         FreeCryptoFwkCtx(env, context);
327         return nullptr;
328     }
329 
330     return NewMdJsDoFinalAsyncWork(env, context);
331 }
332 
JsGetMdLength(napi_env env,napi_callback_info info)333 napi_value NapiMd::JsGetMdLength(napi_env env, napi_callback_info info)
334 {
335     napi_value thisVar = nullptr;
336     NapiMd *napiMd = nullptr;
337 
338     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
339 
340     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiMd));
341     if (status != napi_ok || napiMd == nullptr) {
342         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap NapiMd obj!"));
343         LOGE("failed to unwrap NapiMd obj!");
344         return nullptr;
345     }
346 
347     HcfMd *md = napiMd->GetMd();
348     if (md == nullptr) {
349         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "fail to get md obj!"));
350         LOGE("fail to get md obj!");
351         return nullptr;
352     }
353 
354     uint32_t retLen = md->getMdLength(md);
355     napi_value napiLen = nullptr;
356     napi_create_uint32(env, retLen, &napiLen);
357     return napiLen;
358 }
359 
MdConstructor(napi_env env,napi_callback_info info)360 napi_value NapiMd::MdConstructor(napi_env env, napi_callback_info info)
361 {
362     napi_value thisVar = nullptr;
363     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
364     return thisVar;
365 }
366 
NapiWrapMd(napi_env env,napi_value instance,NapiMd * mdNapiObj)367 static napi_value NapiWrapMd(napi_env env, napi_value instance, NapiMd *mdNapiObj)
368 {
369     napi_status status = napi_wrap(
370         env, instance, mdNapiObj,
371         [](napi_env env, void *data, void *hint) {
372             NapiMd *md = static_cast<NapiMd *>(data);
373             delete md;
374             return;
375         }, nullptr, nullptr);
376     if (status != napi_ok) {
377         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap NapiMd obj!"));
378         delete mdNapiObj;
379         mdNapiObj = nullptr;
380         LOGE("failed to wrap NapiMd obj!");
381         return nullptr;
382     }
383     return instance;
384 }
385 
CreateMd(napi_env env,napi_callback_info info)386 napi_value NapiMd::CreateMd(napi_env env, napi_callback_info info)
387 {
388     LOGD("Enter CreateMd...");
389     size_t expectedArgc = ARGS_SIZE_ONE;
390     size_t argc = expectedArgc;
391     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
392     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
393     if (argc != expectedArgc) {
394         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
395         LOGE("The input args num is invalid.");
396         return nullptr;
397     }
398     std::string algoName;
399     if (!GetStringFromJSParams(env, argv[PARAM0], algoName)) {
400         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Failed to get algorithm."));
401         LOGE("Failed to get algorithm.");
402         return nullptr;
403     }
404     HcfMd *mdObj = nullptr;
405     HcfResult res = HcfMdCreate(algoName.c_str(), &mdObj);
406     if (res != HCF_SUCCESS) {
407         napi_throw(env, GenerateBusinessError(env, res, "create C obj failed."));
408         LOGE("create c mdObj failed.");
409         return nullptr;
410     }
411     napi_value napiAlgName = nullptr;
412     napi_create_string_utf8(env, algoName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
413     napi_value instance = nullptr;
414     napi_value constructor = nullptr;
415     napi_get_reference_value(env, classRef_, &constructor);
416     napi_new_instance(env, constructor, argc, argv, &instance);
417     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
418     NapiMd *mdNapiObj = new (std::nothrow) NapiMd(mdObj);
419     if (mdNapiObj == nullptr) {
420         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new md napi obj failed!"));
421         HcfObjDestroy(mdObj);
422         LOGE("create md napi obj failed!");
423         return nullptr;
424     }
425 
426     return NapiWrapMd(env, instance, mdNapiObj);
427 }
428 
DefineMdJSClass(napi_env env,napi_value exports)429 void NapiMd::DefineMdJSClass(napi_env env, napi_value exports)
430 {
431     napi_property_descriptor desc[] = {
432         DECLARE_NAPI_FUNCTION("createMd", NapiMd::CreateMd),
433     };
434     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
435     napi_property_descriptor classDesc[] = {
436         DECLARE_NAPI_FUNCTION("update", NapiMd::JsMdUpdate),
437         DECLARE_NAPI_FUNCTION("digest", NapiMd::JsMdDoFinal),
438         DECLARE_NAPI_FUNCTION("getMdLength", NapiMd::JsGetMdLength),
439     };
440     napi_value constructor = nullptr;
441     napi_define_class(env, "Md", NAPI_AUTO_LENGTH, MdConstructor, nullptr,
442         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
443     napi_create_reference(env, constructor, 1, &classRef_);
444 }
445 } // CryptoFramework
446 } // OHOS