• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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