• 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     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