• 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_sym_key_generator.h"
17 
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21 #include "napi_sym_key.h"
22 #include "napi_utils.h"
23 #include "napi_crypto_framework_defines.h"
24 
25 namespace OHOS {
26 namespace CryptoFramework {
27 thread_local napi_ref NapiSymKeyGenerator::classRef_ = nullptr;
28 
29 struct SymKeyGeneratorFwkCtxT {
30     napi_env env = nullptr;
31     AsyncType asyncType = ASYNC_CALLBACK;
32     napi_ref callback = nullptr;
33     napi_deferred deferred = nullptr;
34     napi_value promise = nullptr;
35     napi_async_work asyncWork = nullptr;
36 
37     HcfResult errCode = HCF_SUCCESS;
38     HcfSymKey *returnSymKey = nullptr;
39     const char *errMsg = nullptr;
40 
41     HcfSymKeyGenerator *generator = nullptr;
42     HcfBlob keyMaterial = { .data = nullptr, .len = 0 };
43 };
44 
45 using SymKeyGeneratorFwkCtx = SymKeyGeneratorFwkCtxT *;
46 
FreeSymKeyGeneratorFwkCtx(napi_env env,SymKeyGeneratorFwkCtx & context)47 static void FreeSymKeyGeneratorFwkCtx(napi_env env, SymKeyGeneratorFwkCtx &context)
48 {
49     if (context == nullptr) {
50         return;
51     }
52 
53     if (context->asyncWork != nullptr) {
54         napi_delete_async_work(env, context->asyncWork);
55         context->asyncWork = nullptr;
56     }
57 
58     if (context->callback != nullptr) {
59         napi_delete_reference(env, context->callback);
60         context->callback = nullptr;
61     }
62 
63     if (context->keyMaterial.data != nullptr) {
64         (void)memset_s(context->keyMaterial.data, context->keyMaterial.len, 0, context->keyMaterial.len);
65         HcfFree(context->keyMaterial.data);
66         context->keyMaterial.data = nullptr;
67         context->keyMaterial.len = 0;
68     }
69     context->errMsg = nullptr;
70 
71     HcfFree(context);
72     context = nullptr;
73 }
74 
BuildContextForGenerateKey(napi_env env,napi_callback_info info,SymKeyGeneratorFwkCtx context)75 static bool BuildContextForGenerateKey(napi_env env, napi_callback_info info, SymKeyGeneratorFwkCtx context)
76 {
77     napi_value thisVar = nullptr;
78     size_t expectedArgc = ARGS_SIZE_ONE;
79     size_t argc = ARGS_SIZE_ONE;
80     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
81     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
82     if (argc != expectedArgc && argc != expectedArgc - 1) {
83         LOGE("wrong argument num. require 0 or 1 arguments. [Argc]: %zu!", argc);
84         return false;
85     }
86     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
87     NapiSymKeyGenerator *napiGenerator;
88     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiGenerator));
89     if (status != napi_ok || napiGenerator == nullptr) {
90         LOGE("failed to unwrap NapiSymKeyGenerator obj!");
91         return false;
92     }
93 
94     context->generator = napiGenerator->GetSymKeyGenerator();
95     if (context->generator == nullptr) {
96         LOGE("failed to get generator obj!");
97         return false;
98     }
99     if (context->asyncType == ASYNC_PROMISE) {
100         napi_create_promise(env, &context->deferred, &context->promise);
101         return true;
102     } else {
103         return GetCallbackFromJSParams(env, argv[0], &context->callback);
104     }
105 }
106 
BuildContextForConvertKey(napi_env env,napi_callback_info info,SymKeyGeneratorFwkCtx context)107 static bool BuildContextForConvertKey(napi_env env, napi_callback_info info, SymKeyGeneratorFwkCtx context)
108 {
109     napi_value thisVar = nullptr;
110     size_t expectedArgc = ARGS_SIZE_TWO;
111     size_t argc = ARGS_SIZE_TWO;
112     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
113     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
114     if (argc != expectedArgc && argc != expectedArgc - 1) {
115         LOGE("wrong argument num. require 1 or 2 arguments. [Argc]: %zu!", argc);
116         return false;
117     }
118     context->asyncType = isCallback(env, argv[expectedArgc - 1], argc, expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
119 
120     NapiSymKeyGenerator *napiGenerator;
121     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiGenerator));
122     if (status != napi_ok || napiGenerator == nullptr) {
123         LOGE("failed to unwrap NapiSymKeyGenerator obj!");
124         return false;
125     }
126 
127     context->generator = napiGenerator->GetSymKeyGenerator();
128     if (context->generator == nullptr) {
129         LOGE("failed to get generator obj!");
130         return false;
131     }
132 
133     size_t index = 0;
134     HcfBlob *blob = GetBlobFromNapiDataBlob(env, argv[index++]);
135     if (blob == nullptr) {
136         LOGE("get keyMaterial failed!");
137         return false;
138     }
139     context->keyMaterial = *blob;
140     HcfFree(blob);
141     if (context->asyncType == ASYNC_PROMISE) {
142         napi_create_promise(env, &context->deferred, &context->promise);
143         return true;
144     } else {
145         return GetCallbackFromJSParams(env, argv[index], &context->callback);
146     }
147 }
148 
ReturnPromiseResult(napi_env env,SymKeyGeneratorFwkCtx context,napi_value result)149 static void ReturnPromiseResult(napi_env env, SymKeyGeneratorFwkCtx context, napi_value result)
150 {
151     if (context->errCode == HCF_SUCCESS) {
152         napi_resolve_deferred(env, context->deferred, result);
153     } else {
154         napi_reject_deferred(env, context->deferred,
155             GenerateBusinessError(env, context->errCode, context->errMsg));
156     }
157 }
158 
ReturnCallbackResult(napi_env env,SymKeyGeneratorFwkCtx context,napi_value result)159 static void ReturnCallbackResult(napi_env env, SymKeyGeneratorFwkCtx context, napi_value result)
160 {
161     napi_value businessError = nullptr;
162     if (context->errCode != HCF_SUCCESS) {
163         businessError = GenerateBusinessError(env, context->errCode, context->errMsg);
164     }
165     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
166 
167     napi_value func = nullptr;
168     napi_get_reference_value(env, context->callback, &func);
169 
170     napi_value recv = nullptr;
171     napi_value callFuncRet = nullptr;
172     napi_get_undefined(env, &recv);
173     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
174 }
175 
AsyncGenKeyProcess(napi_env env,void * data)176 static void AsyncGenKeyProcess(napi_env env, void *data)
177 {
178     SymKeyGeneratorFwkCtx context = static_cast<SymKeyGeneratorFwkCtx>(data);
179     HcfSymKeyGenerator *generator = context->generator;
180 
181     HcfSymKey *key = nullptr;
182     context->errCode = generator->generateSymKey(generator, &key);
183     if (context->errCode != HCF_SUCCESS) {
184         LOGD("[error] generate sym key failed.");
185         context->errMsg = "generate sym key failed.";
186         return;
187     }
188 
189     context->errCode = HCF_SUCCESS;
190     context->returnSymKey = key;
191 }
192 
AsyncKeyReturn(napi_env env,napi_status status,void * data)193 static void AsyncKeyReturn(napi_env env, napi_status status, void *data)
194 {
195     napi_value instance = NapiSymKey::CreateSymKey(env);
196     SymKeyGeneratorFwkCtx context = static_cast<SymKeyGeneratorFwkCtx>(data);
197     NapiSymKey *napiSymKey = new (std::nothrow) NapiSymKey(context->returnSymKey);
198     if (napiSymKey == nullptr) {
199         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napi sym key failed."));
200         FreeSymKeyGeneratorFwkCtx(env, context);
201         LOGE("new napi sym key failed.");
202         return;
203     }
204 
205     napi_status ret = napi_wrap(env, instance, napiSymKey,
206         [](napi_env env, void *data, void *hint) {
207             NapiSymKey *napiSymKey = static_cast<NapiSymKey *>(data);
208             delete napiSymKey;
209             return;
210         }, nullptr, nullptr);
211     if (ret != napi_ok) {
212         LOGE("failed to wrap napiSymKey obj!");
213         context->errCode = HCF_INVALID_PARAMS;
214         context->errMsg = "failed to wrap napiSymKey obj!";
215         delete napiSymKey;
216     }
217 
218     if (context->asyncType == ASYNC_CALLBACK) {
219         ReturnCallbackResult(env, context, instance);
220     } else {
221         ReturnPromiseResult(env, context, instance);
222     }
223     FreeSymKeyGeneratorFwkCtx(env, context);
224 }
225 
AsyncConvertKeyProcess(napi_env env,void * data)226 static void AsyncConvertKeyProcess(napi_env env, void *data)
227 {
228     SymKeyGeneratorFwkCtx context = static_cast<SymKeyGeneratorFwkCtx>(data);
229     HcfSymKeyGenerator *generator = context->generator;
230 
231     HcfSymKey *key = nullptr;
232     context->errCode = generator->convertSymKey(generator, &context->keyMaterial, &key);
233     if (context->errCode != HCF_SUCCESS) {
234         LOGD("[error] convertSymKey key failed!");
235         context->errMsg = "convert sym key failed.";
236         return;
237     }
238 
239     context->returnSymKey = key;
240 }
241 
NewConvertKeyAsyncWork(napi_env env,SymKeyGeneratorFwkCtx context)242 static napi_value NewConvertKeyAsyncWork(napi_env env, SymKeyGeneratorFwkCtx context)
243 {
244     napi_value resourceName = nullptr;
245     napi_create_string_utf8(env, "convertSymKey", NAPI_AUTO_LENGTH, &resourceName);
246 
247     napi_create_async_work(
248         env,
249         nullptr,
250         resourceName,
251         [](napi_env env, void *data) {
252             AsyncConvertKeyProcess(env, data);
253             return;
254         },
255         [](napi_env env, napi_status status, void *data) {
256             AsyncKeyReturn(env, status, data);
257             return;
258         },
259         static_cast<void *>(context),
260         &context->asyncWork);
261 
262     napi_queue_async_work(env, context->asyncWork);
263     if (context->asyncType == ASYNC_PROMISE) {
264         return context->promise;
265     } else {
266         return NapiGetNull(env);
267     }
268 }
269 
NewGenKeyAsyncWork(napi_env env,SymKeyGeneratorFwkCtx context)270 static napi_value NewGenKeyAsyncWork(napi_env env, SymKeyGeneratorFwkCtx context)
271 {
272     napi_value resourceName = nullptr;
273     napi_create_string_utf8(env, "generatorSymKey", NAPI_AUTO_LENGTH, &resourceName);
274 
275     napi_create_async_work(
276         env,
277         nullptr,
278         resourceName,
279         [](napi_env env, void *data) {
280             AsyncGenKeyProcess(env, data);
281             return;
282         },
283         [](napi_env env, napi_status status, void *data) {
284             AsyncKeyReturn(env, status, data);
285             return;
286         },
287         static_cast<void *>(context),
288         &context->asyncWork);
289 
290     napi_queue_async_work(env, context->asyncWork);
291     if (context->asyncType == ASYNC_PROMISE) {
292         return context->promise;
293     } else {
294         return NapiGetNull(env);
295     }
296 }
297 
NapiSymKeyGenerator(HcfSymKeyGenerator * generator)298 NapiSymKeyGenerator::NapiSymKeyGenerator(HcfSymKeyGenerator *generator)
299 {
300     this->generator_ = generator;
301 }
302 
~NapiSymKeyGenerator()303 NapiSymKeyGenerator::~NapiSymKeyGenerator()
304 {
305     HcfObjDestroy(this->generator_);
306 }
307 
GetSymKeyGenerator() const308 HcfSymKeyGenerator *NapiSymKeyGenerator::GetSymKeyGenerator() const
309 {
310     return this->generator_;
311 }
312 
JsGenerateSymKey(napi_env env,napi_callback_info info)313 napi_value NapiSymKeyGenerator::JsGenerateSymKey(napi_env env, napi_callback_info info)
314 {
315     SymKeyGeneratorFwkCtx context = static_cast<SymKeyGeneratorFwkCtx>(HcfMalloc(sizeof(SymKeyGeneratorFwkCtxT), 0));
316     if (context == nullptr) {
317         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "Create context failed!"));
318         LOGE("Create context failed!");
319         return nullptr;
320     }
321 
322     if (!BuildContextForGenerateKey(env, info, context)) {
323         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "Build context fail."));
324         LOGE("Build context fail.");
325         FreeSymKeyGeneratorFwkCtx(env, context);
326         return nullptr;
327     }
328 
329     napi_value result = NewGenKeyAsyncWork(env, context);
330     if (result == nullptr) {
331         LOGE("NewGenKeyAsyncWork failed!");
332         FreeSymKeyGeneratorFwkCtx(env, context);
333         return nullptr;
334     }
335     return result;
336 }
337 
JsConvertKey(napi_env env,napi_callback_info info)338 napi_value NapiSymKeyGenerator::JsConvertKey(napi_env env, napi_callback_info info)
339 {
340     SymKeyGeneratorFwkCtx context = static_cast<SymKeyGeneratorFwkCtx>(HcfMalloc(sizeof(SymKeyGeneratorFwkCtxT), 0));
341     if (context == nullptr) {
342         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc SymKeyGeneratorFwkCtx failed!"));
343         LOGE("malloc SymKeyGeneratorFwkCtx failed!");
344         return nullptr;
345     }
346 
347     if (!BuildContextForConvertKey(env, info, context)) {
348         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "BuildContextForConvertKey failed!"));
349         LOGE("BuildContextForConvertKey failed!");
350         FreeSymKeyGeneratorFwkCtx(env, context);
351         return nullptr;
352     }
353 
354     napi_value result = NewConvertKeyAsyncWork(env, context);
355     if (result == nullptr) {
356         LOGE("Get deviceauth async work failed!");
357         FreeSymKeyGeneratorFwkCtx(env, context);
358         return nullptr;
359     }
360     return result;
361 }
362 
SymKeyGeneratorConstructor(napi_env env,napi_callback_info info)363 napi_value NapiSymKeyGenerator::SymKeyGeneratorConstructor(napi_env env, napi_callback_info info)
364 {
365     napi_value thisVar = nullptr;
366     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
367     return thisVar;
368 }
369 
CreateSymKeyGenerator(napi_env env,napi_callback_info info)370 napi_value NapiSymKeyGenerator::CreateSymKeyGenerator(napi_env env, napi_callback_info info)
371 {
372     LOGD("Enter CreateSymKeyGenerator...");
373     size_t expectedArgc = ARGS_SIZE_ONE;
374     size_t argc = ARGS_SIZE_ONE;
375     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
376     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
377 
378     if (argc != expectedArgc) {
379         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
380         LOGE("The input args num is invalid.");
381         return nullptr;
382     }
383 
384     napi_value instance;
385     napi_value constructor = nullptr;
386     napi_get_reference_value(env, classRef_, &constructor);
387     napi_new_instance(env, constructor, argc, argv, &instance);
388 
389     std::string algoName;
390     if (!GetStringFromJSParams(env, argv[0], algoName)) {
391         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get algoName."));
392         LOGE("failed to get algoName.");
393         return nullptr;
394     }
395 
396     HcfSymKeyGenerator *generator = nullptr;
397     HcfResult res = HcfSymKeyGeneratorCreate(algoName.c_str(), &generator);
398     if (res != HCF_SUCCESS) {
399         napi_throw(env, GenerateBusinessError(env, res, "create C generator fail."));
400         LOGE("create C generator fail.");
401         return nullptr;
402     }
403     NapiSymKeyGenerator *napiSymKeyGenerator = new (std::nothrow) NapiSymKeyGenerator(generator);
404     if (napiSymKeyGenerator == nullptr) {
405         napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "new napi sym key generator failed."));
406         LOGE("new napi sym key generator failed!");
407         HcfObjDestroy(generator);
408         return nullptr;
409     }
410 
411     napi_status status = napi_wrap(env, instance, napiSymKeyGenerator,
412         [](napi_env env, void *data, void *hint) {
413             NapiSymKeyGenerator *napiSymKeyGenerator = static_cast<NapiSymKeyGenerator *>(data);
414             delete napiSymKeyGenerator;
415             return;
416         }, nullptr, nullptr);
417     if (status != napi_ok) {
418         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to wrap napiSymKeyGenerator obj!"));
419         LOGE("failed to wrap napiSymKeyGenerator obj!");
420         delete napiSymKeyGenerator;
421         return nullptr;
422     }
423     return instance;
424 }
425 
JsGetAlgorithm(napi_env env,napi_callback_info info)426 napi_value NapiSymKeyGenerator::JsGetAlgorithm(napi_env env, napi_callback_info info)
427 {
428     napi_value thisVar = nullptr;
429     NapiSymKeyGenerator *napiSymKeyGenerator = nullptr;
430     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
431     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiSymKeyGenerator));
432     if (status != napi_ok || napiSymKeyGenerator == nullptr) {
433         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiSymKeyGenerator obj!"));
434         LOGE("failed to unwrap napiSymKeyGenerator obj!");
435         return nullptr;
436     }
437     HcfSymKeyGenerator *generator = napiSymKeyGenerator->GetSymKeyGenerator();
438 
439     const char *algo = generator->getAlgoName(generator);
440     napi_value instance = nullptr;
441     napi_create_string_utf8(env, algo, NAPI_AUTO_LENGTH, &instance);
442     return instance;
443 }
444 
DefineSymKeyGeneratorJSClass(napi_env env,napi_value exports)445 void NapiSymKeyGenerator::DefineSymKeyGeneratorJSClass(napi_env env, napi_value exports)
446 {
447     napi_property_descriptor desc[] = {
448         DECLARE_NAPI_FUNCTION("createSymKeyGenerator", NapiSymKeyGenerator::CreateSymKeyGenerator),
449     };
450     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
451 
452     napi_property_descriptor classDesc[] = {
453         DECLARE_NAPI_FUNCTION("generateSymKey", NapiSymKeyGenerator::JsGenerateSymKey),
454         DECLARE_NAPI_FUNCTION("convertKey", NapiSymKeyGenerator::JsConvertKey),
455         { .utf8name = "algName", .getter = NapiSymKeyGenerator::JsGetAlgorithm },
456     };
457     napi_value constructor = nullptr;
458     napi_define_class(env, "SymKeyGenerator", NAPI_AUTO_LENGTH,
459         NapiSymKeyGenerator::SymKeyGeneratorConstructor, nullptr,
460         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
461     napi_create_reference(env, constructor, 1, &classRef_);
462 }
463 } // CryptoFramework
464 } // OHOS