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