• 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_key_agreement.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_pri_key.h"
24 #include "napi_pub_key.h"
25 #include "napi_utils.h"
26 
27 namespace OHOS {
28 namespace CryptoFramework {
29 struct KeyAgreementCtx {
30     napi_env env = nullptr;
31 
32     AsyncType asyncType = ASYNC_CALLBACK;
33     napi_ref callback = nullptr;
34     napi_deferred deferred = nullptr;
35     napi_value promise = nullptr;
36     napi_async_work asyncWork = nullptr;
37 
38     HcfKeyAgreement *keyAgreement;
39     HcfPriKey *priKey;
40     HcfPubKey *pubKey;
41 
42     HcfResult result;
43     HcfBlob returnSecret;
44 };
45 
46 thread_local napi_ref NapiKeyAgreement::classRef_ = nullptr;
47 
FreeKeyAgreementCtx(napi_env env,KeyAgreementCtx * ctx)48 static void FreeKeyAgreementCtx(napi_env env, KeyAgreementCtx *ctx)
49 {
50     if (ctx == nullptr) {
51         return;
52     }
53 
54     if (ctx->asyncWork != nullptr) {
55         napi_delete_async_work(env, ctx->asyncWork);
56         ctx->asyncWork = nullptr;
57     }
58 
59     if (ctx->callback != nullptr) {
60         napi_delete_reference(env, ctx->callback);
61         ctx->callback = nullptr;
62     }
63 
64     if (ctx->returnSecret.data != nullptr) {
65         HcfFree(ctx->returnSecret.data);
66         ctx->returnSecret.data = nullptr;
67         ctx->returnSecret.len = 0;
68     }
69 
70     HcfFree(ctx);
71 }
72 
BuildKeyAgreementJsCtx(napi_env env,napi_callback_info info,KeyAgreementCtx * ctx)73 static bool BuildKeyAgreementJsCtx(napi_env env, napi_callback_info info, KeyAgreementCtx *ctx)
74 {
75     napi_value thisVar = nullptr;
76     size_t expectedArgc = PARAMS_NUM_THREE;
77     size_t argc = expectedArgc;
78     napi_value argv[PARAMS_NUM_THREE] = { nullptr };
79     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
80     if (argc != expectedArgc && argc != expectedArgc - 1) {
81         LOGE("wrong argument num. require %zu or %zu arguments. [Argc]: %zu!", expectedArgc - 1, expectedArgc, argc);
82         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "params num error.", false));
83         return false;
84     }
85     ctx->asyncType = (argc == expectedArgc) ? ASYNC_CALLBACK : ASYNC_PROMISE;
86 
87     NapiKeyAgreement *napiKeyAgreement = nullptr;
88     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiKeyAgreement));
89     if (status != napi_ok) {
90         LOGE("failed to unwrap napi verify obj.");
91         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[Self]: param unwarp error.", false));
92         return false;
93     }
94 
95     size_t index = 0;
96     NapiPriKey *napiPriKey = nullptr;
97     status = napi_unwrap(env, argv[index], reinterpret_cast<void **>(&napiPriKey));
98     if (status != napi_ok) {
99         LOGE("failed to unwrap priKey verify obj.");
100         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[PriKey]: param unwarp error.", false));
101         return false;
102     }
103 
104     index++;
105     NapiPubKey *napiPubKey = nullptr;
106     status = napi_unwrap(env, argv[index], reinterpret_cast<void **>(&napiPubKey));
107     if (status != napi_ok) {
108         LOGE("failed to unwrap napi pubKey obj.");
109         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "[PubKey]: param unwarp error.", false));
110         return false;
111     }
112 
113     ctx->keyAgreement = napiKeyAgreement->GetKeyAgreement();
114     ctx->priKey = napiPriKey->GetPriKey();
115     ctx->pubKey = napiPubKey->GetPubKey();
116 
117     if (ctx->asyncType == ASYNC_PROMISE) {
118         napi_create_promise(env, &ctx->deferred, &ctx->promise);
119         return true;
120     } else {
121         return GetCallbackFromJSParams(env, argv[expectedArgc - 1], &ctx->callback, false);
122     }
123 }
124 
ReturnCallbackResult(napi_env env,KeyAgreementCtx * ctx,napi_value result)125 static void ReturnCallbackResult(napi_env env, KeyAgreementCtx *ctx, napi_value result)
126 {
127     napi_value businessError = nullptr;
128     if (ctx->result != HCF_SUCCESS) {
129         businessError = GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false);
130     }
131 
132     napi_value params[ARGS_SIZE_TWO] = { businessError, result };
133 
134     napi_value func = nullptr;
135     napi_get_reference_value(env, ctx->callback, &func);
136 
137     napi_value recv = nullptr;
138     napi_value callFuncRet = nullptr;
139     napi_get_undefined(env, &recv);
140     napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
141 }
142 
ReturnPromiseResult(napi_env env,KeyAgreementCtx * ctx,napi_value result)143 static void ReturnPromiseResult(napi_env env, KeyAgreementCtx *ctx, napi_value result)
144 {
145     if (ctx->result == HCF_SUCCESS) {
146         napi_resolve_deferred(env, ctx->deferred, result);
147     } else {
148         napi_reject_deferred(env, ctx->deferred,
149             GenerateBusinessError(env, ctx->result, COMMON_ERR_MSG.c_str(), false));
150     }
151 }
152 
KeyAgreementAsyncWorkProcess(napi_env env,void * data)153 void KeyAgreementAsyncWorkProcess(napi_env env, void *data)
154 {
155     KeyAgreementCtx *ctx = static_cast<KeyAgreementCtx *>(data);
156 
157     HcfResult res = ctx->keyAgreement->generateSecret(ctx->keyAgreement,
158         ctx->priKey, ctx->pubKey, &ctx->returnSecret);
159 
160     ctx->result = res;
161     if (res != HCF_SUCCESS) {
162         LOGE("generate secret fail.");
163     }
164 }
165 
KeyAgreementAsyncWorkReturn(napi_env env,napi_status status,void * data)166 void KeyAgreementAsyncWorkReturn(napi_env env, napi_status status, void *data)
167 {
168     KeyAgreementCtx *ctx = static_cast<KeyAgreementCtx *>(data);
169 
170     napi_value dataBlob = nullptr;
171     if (ctx->result == HCF_SUCCESS) {
172         dataBlob = ConvertBlobToNapiValue(env, &ctx->returnSecret);
173     }
174 
175     if (ctx->asyncType == ASYNC_CALLBACK) {
176         ReturnCallbackResult(env, ctx, dataBlob);
177     } else {
178         ReturnPromiseResult(env, ctx, dataBlob);
179     }
180     FreeKeyAgreementCtx(env, ctx);
181 }
182 
NewKeyAgreementAsyncWork(napi_env env,KeyAgreementCtx * ctx)183 static napi_value NewKeyAgreementAsyncWork(napi_env env, KeyAgreementCtx *ctx)
184 {
185     napi_value resourceName = nullptr;
186     napi_create_string_utf8(env, "generateSecret", NAPI_AUTO_LENGTH, &resourceName);
187 
188     napi_create_async_work(
189         env, nullptr, resourceName,
190         [](napi_env env, void *data) {
191             KeyAgreementAsyncWorkProcess(env, data);
192             return;
193         },
194         [](napi_env env, napi_status status, void *data) {
195             KeyAgreementAsyncWorkReturn(env, status, data);
196             return;
197         },
198         static_cast<void *>(ctx),
199         &ctx->asyncWork);
200 
201     napi_queue_async_work(env, ctx->asyncWork);
202     if (ctx->asyncType == ASYNC_PROMISE) {
203         return ctx->promise;
204     } else {
205         napi_value result = nullptr;
206         napi_get_null(env, &result);
207         return result;
208     }
209 }
210 
NapiKeyAgreement(HcfKeyAgreement * keyAgreement)211 NapiKeyAgreement::NapiKeyAgreement(HcfKeyAgreement *keyAgreement)
212 {
213     this->keyAgreement_ = keyAgreement;
214 }
215 
~NapiKeyAgreement()216 NapiKeyAgreement::~NapiKeyAgreement()
217 {
218     HcfObjDestroy(this->keyAgreement_);
219 }
220 
GetKeyAgreement()221 HcfKeyAgreement *NapiKeyAgreement::GetKeyAgreement()
222 {
223     return this->keyAgreement_;
224 }
225 
JsGenerateSecret(napi_env env,napi_callback_info info)226 napi_value NapiKeyAgreement::JsGenerateSecret(napi_env env, napi_callback_info info)
227 {
228     LOGI("enter ...");
229     KeyAgreementCtx *ctx = static_cast<KeyAgreementCtx *>(HcfMalloc(sizeof(KeyAgreementCtx), 0));
230     if (ctx == nullptr) {
231         LOGE("create context fail.");
232         return nullptr;
233     }
234 
235     if (!BuildKeyAgreementJsCtx(env, info, ctx)) {
236         LOGE("build context fail.");
237         FreeKeyAgreementCtx(env, ctx);
238         return nullptr;
239     }
240 
241     return NewKeyAgreementAsyncWork(env, ctx);
242 }
243 
KeyAgreementConstructor(napi_env env,napi_callback_info info)244 napi_value NapiKeyAgreement::KeyAgreementConstructor(napi_env env, napi_callback_info info)
245 {
246     LOGI("enter ...");
247 
248     napi_value thisVar = nullptr;
249     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
250 
251     LOGI("out ...");
252     return thisVar;
253 }
254 
CreateJsKeyAgreement(napi_env env,napi_callback_info info)255 napi_value NapiKeyAgreement::CreateJsKeyAgreement(napi_env env, napi_callback_info info)
256 {
257     LOGI("enter ...");
258     size_t expectedArgc = PARAMS_NUM_ONE;
259     size_t argc = PARAMS_NUM_ONE;
260     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
261     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
262 
263     if (argc != expectedArgc) {
264         LOGE("The input args num is invalid.");
265         return nullptr;
266     }
267 
268     napi_value instance;
269     napi_value constructor = nullptr;
270     napi_get_reference_value(env, classRef_, &constructor);
271     napi_new_instance(env, constructor, argc, argv, &instance);
272 
273     std::string algName;
274     if (!GetStringFromJSParams(env, argv[0], algName, false)) {
275         return nullptr;
276     }
277 
278     HcfKeyAgreement *keyAgreement = nullptr;
279     int32_t res = HcfKeyAgreementCreate(algName.c_str(), &keyAgreement);
280     if (res != HCF_SUCCESS) {
281         LOGE("create c keyAgreement fail.");
282         return nullptr;
283     }
284 
285     NapiKeyAgreement *napiKeyAgreement = new NapiKeyAgreement(keyAgreement);
286 
287     napi_wrap(
288         env, instance, napiKeyAgreement,
289         [](napi_env env, void *data, void *hint) {
290             NapiKeyAgreement *napiKeyAgreement = static_cast<NapiKeyAgreement *>(data);
291             delete napiKeyAgreement;
292             return;
293         },
294         nullptr,
295         nullptr);
296 
297     napi_value napiAlgName = nullptr;
298     napi_create_string_utf8(env, algName.c_str(), NAPI_AUTO_LENGTH, &napiAlgName);
299     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
300 
301     LOGI("out ...");
302     return instance;
303 }
304 
DefineKeyAgreementJSClass(napi_env env,napi_value exports)305 void NapiKeyAgreement::DefineKeyAgreementJSClass(napi_env env, napi_value exports)
306 {
307     napi_property_descriptor desc[] = {
308         DECLARE_NAPI_FUNCTION("createKeyAgreement", NapiKeyAgreement::CreateJsKeyAgreement),
309     };
310     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
311 
312     napi_property_descriptor classDesc[] = {
313         DECLARE_NAPI_FUNCTION("generateSecret", NapiKeyAgreement::JsGenerateSecret),
314     };
315     napi_value constructor = nullptr;
316     napi_define_class(env, "KeyAgreement", NAPI_AUTO_LENGTH, NapiKeyAgreement::KeyAgreementConstructor, nullptr,
317         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
318     napi_create_reference(env, constructor, 1, &classRef_);
319 }
320 } // CryptoFramework
321 } // OHOS
322