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