• 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_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