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