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