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_asy_key_generator.h"
17
18 #include "securec.h"
19 #include "log.h"
20 #include "memory.h"
21
22 #include "napi_crypto_framework_defines.h"
23 #include "napi_utils.h"
24 #include "napi_key_pair.h"
25 #include "napi_pri_key.h"
26 #include "napi_pub_key.h"
27
28 namespace OHOS {
29 namespace CryptoFramework {
30 struct GenKeyPairCtx {
31 napi_env env = nullptr;
32
33 AsyncType asyncType = ASYNC_CALLBACK;
34 napi_ref callback = nullptr;
35 napi_deferred deferred = nullptr;
36 napi_value promise = nullptr;
37 napi_async_work asyncWork = nullptr;
38
39 HcfAsyKeyGenerator *generator;
40 HcfParamsSpec *params;
41
42 HcfResult result;
43 HcfKeyPair *returnKeyPair;
44 };
45
46 struct ConvertKeyCtx {
47 napi_env env = nullptr;
48
49 AsyncType asyncType = ASYNC_CALLBACK;
50 napi_ref callback = nullptr;
51 napi_deferred deferred = nullptr;
52 napi_value promise = nullptr;
53 napi_async_work asyncWork = nullptr;
54
55 HcfAsyKeyGenerator *generator;
56 HcfParamsSpec *params;
57 HcfBlob *pubKey;
58 HcfBlob *priKey;
59
60 HcfResult result;
61 HcfKeyPair *returnKeyPair;
62 };
63
64 thread_local napi_ref NapiAsyKeyGenerator::classRef_ = nullptr;
65
FreeGenKeyPairCtx(napi_env env,GenKeyPairCtx * ctx)66 static void FreeGenKeyPairCtx(napi_env env, GenKeyPairCtx *ctx)
67 {
68 if (ctx == nullptr) {
69 return;
70 }
71
72 if (ctx->asyncWork != nullptr) {
73 napi_delete_async_work(env, ctx->asyncWork);
74 ctx->asyncWork = nullptr;
75 }
76
77 if (ctx->callback != nullptr) {
78 napi_delete_reference(env, ctx->callback);
79 ctx->callback = nullptr;
80 }
81
82 HcfFree(ctx);
83 }
84
FreeConvertKeyCtx(napi_env env,ConvertKeyCtx * ctx)85 static void FreeConvertKeyCtx(napi_env env, ConvertKeyCtx *ctx)
86 {
87 if (ctx == nullptr) {
88 return;
89 }
90
91 if (ctx->asyncWork != nullptr) {
92 napi_delete_async_work(env, ctx->asyncWork);
93 ctx->asyncWork = nullptr;
94 }
95
96 if (ctx->callback != nullptr) {
97 napi_delete_reference(env, ctx->callback);
98 ctx->callback = nullptr;
99 }
100
101 HcfBlobDataFree(ctx->pubKey);
102 HcfFree(ctx->pubKey);
103 HcfBlobDataFree(ctx->priKey);
104 HcfFree(ctx->priKey);
105 HcfFree(ctx);
106 }
107
BuildGenKeyPairCtx(napi_env env,napi_callback_info info,GenKeyPairCtx * ctx)108 static bool BuildGenKeyPairCtx(napi_env env, napi_callback_info info, GenKeyPairCtx *ctx)
109 {
110 napi_value thisVar = nullptr;
111 size_t expectedArgc = PARAMS_NUM_ONE;
112 size_t argc = expectedArgc;
113 napi_value argv[PARAMS_NUM_ONE] = { nullptr };
114 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
115 if (argc != expectedArgc && argc != expectedArgc - 1) {
116 LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
117 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "params num error.", false));
118 return false;
119 }
120 ctx->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
121
122 NapiAsyKeyGenerator *napiGenerator;
123 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiGenerator));
124 if (status != napi_ok) {
125 LOGE("failed to unwrap napi asyKeyGenerator obj.");
126 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[Self]: param unwarp error.", false));
127 return false;
128 }
129
130 ctx->generator = napiGenerator->GetAsyKeyGenerator();
131 ctx->params = nullptr;
132
133 if (ctx->asyncType == ASYNC_PROMISE) {
134 napi_create_promise(env, &ctx->deferred, &ctx->promise);
135 return true;
136 } else {
137 return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback, false);
138 }
139 }
140
GetPkAndSkBlobFromNapiValueIfInput(napi_env env,napi_value pkValue,napi_value skValue,HcfBlob ** returnPubKey,HcfBlob ** returnPriKey)141 static bool GetPkAndSkBlobFromNapiValueIfInput(napi_env env, napi_value pkValue, napi_value skValue,
142 HcfBlob **returnPubKey, HcfBlob **returnPriKey)
143 {
144 napi_valuetype valueType;
145 napi_typeof(env, pkValue, &valueType);
146 HcfBlob *pubKey = nullptr;
147 if (valueType != napi_null) {
148 pubKey = GetBlobFromNapiValue(env, pkValue);
149 if (pubKey == nullptr) {
150 LOGE("failed to get pubKey.");
151 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
152 "[PubKey]: must be of the DataBlob type.", false));
153 return false;
154 }
155 }
156
157 napi_typeof(env, skValue, &valueType);
158 HcfBlob *priKey = nullptr;
159 if (valueType != napi_null) {
160 priKey = GetBlobFromNapiValue(env, skValue);
161 if (priKey == nullptr) {
162 LOGE("failed to get priKey.");
163 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS,
164 "[PriKey]: must be of the DataBlob type.", false));
165 return false;
166 }
167 }
168
169 *returnPubKey = pubKey;
170 *returnPriKey = priKey;
171 return true;
172 }
173
BuildConvertKeyCtx(napi_env env,napi_callback_info info,ConvertKeyCtx * ctx)174 static bool BuildConvertKeyCtx(napi_env env, napi_callback_info info, ConvertKeyCtx *ctx)
175 {
176 napi_value thisVar = nullptr;
177 size_t expectedArgc = PARAMS_NUM_THREE;
178 size_t argc = expectedArgc;
179 napi_value argv[PARAMS_NUM_THREE] = { nullptr };
180 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
181 if (argc != expectedArgc && argc != expectedArgc - 1) {
182 LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
183 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "params num error.", false));
184 return false;
185 }
186 ctx->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
187
188 NapiAsyKeyGenerator *napiGenerator;
189 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiGenerator));
190 if (status != napi_ok) {
191 LOGE("failed to unwrap napi asyKeyGenerator obj.");
192 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[Self]: param unwarp error.", false));
193 return false;
194 }
195
196 HcfBlob *pubKey = nullptr;
197 HcfBlob *priKey = nullptr;
198 if (!GetPkAndSkBlobFromNapiValueIfInput(env, argv[PARAM0], argv[PARAM1], &pubKey, &priKey)) {
199 return false;
200 }
201
202 ctx->generator = napiGenerator->GetAsyKeyGenerator();
203 ctx->params = nullptr;
204 ctx->pubKey = pubKey;
205 ctx->priKey = priKey;
206
207 if (ctx->asyncType == ASYNC_PROMISE) {
208 napi_create_promise(env, &ctx->deferred, &ctx->promise);
209 return true;
210 } else {
211 return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback, false);
212 }
213 }
214
ReturnGenKeyPairCallbackResult(napi_env env,GenKeyPairCtx * ctx,napi_value result)215 static void ReturnGenKeyPairCallbackResult(napi_env env, GenKeyPairCtx *ctx, napi_value result)
216 {
217 napi_value businessError = nullptr;
218 if (ctx->result != HCF_SUCCESS) {
219 businessError = GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false);
220 }
221
222 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
223
224 napi_value func = nullptr;
225 napi_get_reference_value(env, ctx->callback, &func);
226
227 napi_value recv = nullptr;
228 napi_value callFuncRet = nullptr;
229 napi_get_undefined(env, &recv);
230 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
231 }
232
ReturnGenKeyPairPromiseResult(napi_env env,GenKeyPairCtx * ctx,napi_value result)233 static void ReturnGenKeyPairPromiseResult(napi_env env, GenKeyPairCtx *ctx, napi_value result)
234 {
235 if (ctx->result == HCF_SUCCESS) {
236 napi_resolve_deferred(env, ctx->deferred, result);
237 } else {
238 napi_reject_deferred(env, ctx->deferred,
239 GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false));
240 }
241 }
242
ReturnConvertKeyCallbackResult(napi_env env,ConvertKeyCtx * ctx,napi_value result)243 static void ReturnConvertKeyCallbackResult(napi_env env, ConvertKeyCtx *ctx, napi_value result)
244 {
245 napi_value businessError = nullptr;
246 if (ctx->result != HCF_SUCCESS) {
247 businessError = GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false);
248 }
249
250 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
251
252 napi_value func = nullptr;
253 napi_get_reference_value(env, ctx->callback, &func);
254
255 napi_value recv = nullptr;
256 napi_value callFuncRet = nullptr;
257 napi_get_undefined(env, &recv);
258 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
259 }
260
ReturnConvertKeyPromiseResult(napi_env env,ConvertKeyCtx * ctx,napi_value result)261 static void ReturnConvertKeyPromiseResult(napi_env env, ConvertKeyCtx *ctx, napi_value result)
262 {
263 if (ctx->result == HCF_SUCCESS) {
264 napi_resolve_deferred(env, ctx->deferred, result);
265 } else {
266 napi_reject_deferred(env, ctx->deferred,
267 GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false));
268 }
269 }
270
GenKeyPairAsyncWorkProcess(napi_env env,void * data)271 static void GenKeyPairAsyncWorkProcess(napi_env env, void *data)
272 {
273 GenKeyPairCtx *ctx = static_cast<GenKeyPairCtx *>(data);
274
275 HcfResult res = ctx->generator->generateKeyPair(ctx->generator, ctx->params, &(ctx->returnKeyPair));
276
277 ctx->result = res;
278 if (res != HCF_SUCCESS) {
279 LOGE("generate key pair fail.");
280 }
281 }
282
GenKeyPairAsyncWorkReturn(napi_env env,napi_status status,void * data)283 static void GenKeyPairAsyncWorkReturn(napi_env env, napi_status status, void *data)
284 {
285 GenKeyPairCtx *ctx = static_cast<GenKeyPairCtx *>(data);
286
287 napi_value instance = nullptr;
288 if (ctx->result == HCF_SUCCESS) {
289 NapiKeyPair *napiKeyPair = new NapiKeyPair(ctx->returnKeyPair);
290 instance = napiKeyPair->ConvertToJsKeyPair(env);
291
292 napi_wrap(
293 env, instance, napiKeyPair,
294 [](napi_env env, void *data, void *hint) {
295 NapiKeyPair *keyPair = static_cast<NapiKeyPair *>(data);
296 delete keyPair;
297 return;
298 },
299 nullptr, nullptr);
300 }
301
302 if (ctx->asyncType == ASYNC_CALLBACK) {
303 ReturnGenKeyPairCallbackResult(env, ctx, instance);
304 } else {
305 ReturnGenKeyPairPromiseResult(env, ctx, instance);
306 }
307 FreeGenKeyPairCtx(env, ctx);
308 }
309
ConvertKeyAsyncWorkProcess(napi_env env,void * data)310 static void ConvertKeyAsyncWorkProcess(napi_env env, void *data)
311 {
312 ConvertKeyCtx *ctx = static_cast<ConvertKeyCtx *>(data);
313
314 HcfResult res = ctx->generator->convertKey(ctx->generator, ctx->params,
315 ctx->pubKey, ctx->priKey, &(ctx->returnKeyPair));
316
317 ctx->result = res;
318 if (res != HCF_SUCCESS) {
319 LOGE("convert key fail.");
320 }
321 }
322
ConvertKeyAsyncWorkReturn(napi_env env,napi_status status,void * data)323 static void ConvertKeyAsyncWorkReturn(napi_env env, napi_status status, void *data)
324 {
325 ConvertKeyCtx *ctx = static_cast<ConvertKeyCtx *>(data);
326
327 napi_value instance = nullptr;
328 if (ctx->result == HCF_SUCCESS) {
329 NapiKeyPair *napiKeyPair = new NapiKeyPair(ctx->returnKeyPair);
330 instance = napiKeyPair->ConvertToJsKeyPair(env);
331
332 napi_wrap(
333 env, instance, napiKeyPair,
334 [](napi_env env, void *data, void *hint) {
335 NapiKeyPair *keyPair = static_cast<NapiKeyPair *>(data);
336 delete keyPair;
337 return;
338 },
339 nullptr, nullptr);
340 }
341
342 if (ctx->asyncType == ASYNC_CALLBACK) {
343 ReturnConvertKeyCallbackResult(env, ctx, instance);
344 } else {
345 ReturnConvertKeyPromiseResult(env, ctx, instance);
346 }
347 FreeConvertKeyCtx(env, ctx);
348 }
349
NewGenKeyPairAsyncWork(napi_env env,GenKeyPairCtx * ctx)350 static napi_value NewGenKeyPairAsyncWork(napi_env env, GenKeyPairCtx *ctx)
351 {
352 napi_value resourceName = nullptr;
353 napi_create_string_utf8(env, "generatorKeyPair", NAPI_AUTO_LENGTH, &resourceName);
354
355 napi_create_async_work(
356 env, nullptr, resourceName,
357 [](napi_env env, void *data) {
358 GenKeyPairAsyncWorkProcess(env, data);
359 return;
360 },
361 [](napi_env env, napi_status status, void *data) {
362 GenKeyPairAsyncWorkReturn(env, status, data);
363 return;
364 },
365 static_cast<void *>(ctx),
366 &ctx->asyncWork);
367
368 napi_queue_async_work(env, ctx->asyncWork);
369 if (ctx->asyncType == ASYNC_PROMISE) {
370 return ctx->promise;
371 } else {
372 napi_value result = nullptr;
373 napi_get_null(env, &result);
374 return result;
375 }
376 }
377
NewConvertKeyAsyncWork(napi_env env,ConvertKeyCtx * ctx)378 static napi_value NewConvertKeyAsyncWork(napi_env env, ConvertKeyCtx *ctx)
379 {
380 napi_value resourceName = nullptr;
381 napi_create_string_utf8(env, "convertKey", NAPI_AUTO_LENGTH, &resourceName);
382
383 napi_create_async_work(
384 env, nullptr, resourceName,
385 [](napi_env env, void *data) {
386 ConvertKeyAsyncWorkProcess(env, data);
387 return;
388 },
389 [](napi_env env, napi_status status, void *data) {
390 ConvertKeyAsyncWorkReturn(env, status, data);
391 return;
392 },
393 static_cast<void *>(ctx),
394 &ctx->asyncWork);
395
396 napi_queue_async_work(env, ctx->asyncWork);
397 if (ctx->asyncType == ASYNC_PROMISE) {
398 return ctx->promise;
399 } else {
400 napi_value result = nullptr;
401 napi_get_null(env, &result);
402 return result;
403 }
404 }
405
NapiAsyKeyGenerator(HcfAsyKeyGenerator * generator)406 NapiAsyKeyGenerator::NapiAsyKeyGenerator(HcfAsyKeyGenerator *generator)
407 {
408 this->generator_ = generator;
409 }
410
~NapiAsyKeyGenerator()411 NapiAsyKeyGenerator::~NapiAsyKeyGenerator()
412 {
413 HcfObjDestroy(this->generator_);
414 }
415
GetAsyKeyGenerator()416 HcfAsyKeyGenerator *NapiAsyKeyGenerator::GetAsyKeyGenerator()
417 {
418 return this->generator_;
419 }
420
JsGenerateKeyPair(napi_env env,napi_callback_info info)421 napi_value NapiAsyKeyGenerator::JsGenerateKeyPair(napi_env env, napi_callback_info info)
422 {
423 LOGI("enter ...");
424 GenKeyPairCtx *ctx = static_cast<GenKeyPairCtx *>(HcfMalloc(sizeof(GenKeyPairCtx), 0));
425 if (ctx == nullptr) {
426 LOGE("create context fail.");
427 napi_throw(env, GenerateBusinessError(env, HCF_ERR_MALLOC, "malloc ctx fail.", false));
428 return nullptr;
429 }
430
431 if (!BuildGenKeyPairCtx(env, info, ctx)) {
432 LOGE("build context fail.");
433 FreeGenKeyPairCtx(env, ctx);
434 return nullptr;
435 }
436
437 return NewGenKeyPairAsyncWork(env, ctx);
438 }
439
JsConvertKey(napi_env env,napi_callback_info info)440 napi_value NapiAsyKeyGenerator::JsConvertKey(napi_env env, napi_callback_info info)
441 {
442 LOGI("enter ...");
443 ConvertKeyCtx *ctx = static_cast<ConvertKeyCtx *>(HcfMalloc(sizeof(ConvertKeyCtx), 0));
444 if (ctx == nullptr) {
445 LOGE("create context fail.");
446 return nullptr;
447 }
448
449 if (!BuildConvertKeyCtx(env, info, ctx)) {
450 LOGE("build context fail.");
451 FreeConvertKeyCtx(env, ctx);
452 return nullptr;
453 }
454
455 return NewConvertKeyAsyncWork(env, ctx);
456 }
457
AsyKeyGeneratorConstructor(napi_env env,napi_callback_info info)458 napi_value NapiAsyKeyGenerator::AsyKeyGeneratorConstructor(napi_env env, napi_callback_info info)
459 {
460 LOGI("enter ...");
461
462 napi_value thisVar = nullptr;
463 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
464
465 LOGI("out ...");
466 return thisVar;
467 }
468
CreateJsAsyKeyGenerator(napi_env env,napi_callback_info info)469 napi_value NapiAsyKeyGenerator::CreateJsAsyKeyGenerator(napi_env env, napi_callback_info info)
470 {
471 LOGI("enter ...");
472 size_t expectedArgc = PARAMS_NUM_ONE;
473 size_t argc = expectedArgc;
474 napi_value argv[PARAMS_NUM_ONE] = { nullptr };
475 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
476
477 if (argc != expectedArgc) {
478 LOGE("The input args num is invalid.");
479 return NapiGetNull(env);
480 }
481
482 napi_value instance;
483 napi_value constructor = nullptr;
484 napi_get_reference_value(env, classRef_, &constructor);
485 napi_new_instance(env, constructor, argc, argv, &instance);
486
487 std::string algName;
488 if (!GetStringFromJSParams(env, argv[0], algName, false)) {
489 LOGE("failed to get algoName.");
490 return NapiGetNull(env);
491 }
492
493 HcfAsyKeyGenerator *generator = nullptr;
494 int32_t res = HcfAsyKeyGeneratorCreate(algName.c_str(), &generator);
495 if (res != HCF_SUCCESS) {
496 LOGE("create c generator fail.");
497 return NapiGetNull(env);
498 }
499
500 NapiAsyKeyGenerator *napiAsyKeyGenerator = new NapiAsyKeyGenerator(generator);
501
502 napi_wrap(
503 env, instance, napiAsyKeyGenerator,
504 [](napi_env env, void *data, void *hint) {
505 NapiAsyKeyGenerator *napiAsyKeyGenerator = static_cast<NapiAsyKeyGenerator *>(data);
506 delete napiAsyKeyGenerator;
507 return;
508 },
509 nullptr,
510 nullptr);
511
512 napi_value napiAlgName = nullptr;
513 napi_create_string_utf8(env, algName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
514 napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
515
516 LOGI("out ...");
517 return instance;
518 }
519
DefineAsyKeyGeneratorJSClass(napi_env env,napi_value exports)520 void NapiAsyKeyGenerator::DefineAsyKeyGeneratorJSClass(napi_env env, napi_value exports)
521 {
522 napi_property_descriptor desc[] = {
523 DECLARE_NAPI_FUNCTION("createAsyKeyGenerator", NapiAsyKeyGenerator::CreateJsAsyKeyGenerator),
524 };
525 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
526
527 napi_property_descriptor classDesc[] = {
528 DECLARE_NAPI_FUNCTION("generateKeyPair", NapiAsyKeyGenerator::JsGenerateKeyPair),
529 DECLARE_NAPI_FUNCTION("convertKey", NapiAsyKeyGenerator::JsConvertKey),
530 };
531 napi_value constructor = nullptr;
532 napi_define_class(env, "AsyKeyGenerator", NAPI_AUTO_LENGTH, NapiAsyKeyGenerator::AsyKeyGeneratorConstructor,
533 nullptr, sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
534 napi_create_reference(env, constructor, 1, &classRef_);
535 }
536 } // CryptoFramework
537 } // OHOS
538