1 /*
2 * Copyright (C) 2023-2024 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_pri_key.h"
17
18 #include "log.h"
19 #include "memory.h"
20 #include "napi_crypto_framework_defines.h"
21 #include "napi_utils.h"
22 #include "securec.h"
23 #include "key.h"
24
25 namespace OHOS {
26 namespace CryptoFramework {
27 thread_local napi_ref NapiPriKey::classRef_ = nullptr;
28
NapiPriKey(HcfPriKey * priKey)29 NapiPriKey::NapiPriKey(HcfPriKey *priKey) : NapiKey(reinterpret_cast<HcfKey *>(priKey)) {}
30
~NapiPriKey()31 NapiPriKey::~NapiPriKey() {}
32
GetPriKey()33 HcfPriKey *NapiPriKey::GetPriKey()
34 {
35 return reinterpret_cast<HcfPriKey *>(NapiKey::GetHcfKey());
36 }
37
PriKeyConstructor(napi_env env,napi_callback_info info)38 napi_value NapiPriKey::PriKeyConstructor(napi_env env, napi_callback_info info)
39 {
40 napi_value thisVar = nullptr;
41 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
42 return thisVar;
43 }
44
FreeEncodeParamsSpec(HcfParamsSpec * paramsSpec)45 static void FreeEncodeParamsSpec(HcfParamsSpec *paramsSpec)
46 {
47 if (paramsSpec == nullptr) {
48 return;
49 }
50 HcfKeyEncodingParamsSpec *spec = reinterpret_cast<HcfKeyEncodingParamsSpec *>(paramsSpec);
51 if (spec->password != nullptr) {
52 size_t pwdLen = strlen(spec->password);
53 (void)memset_s((void*)spec->password, pwdLen, 0, pwdLen);
54 HcfFree(static_cast<void *>(spec->password));
55 spec->password = nullptr;
56 }
57 if (spec->cipher != nullptr) {
58 HcfFree(static_cast<void *>(spec->cipher));
59 spec->cipher = nullptr;
60 }
61 HcfFree(paramsSpec);
62 paramsSpec = nullptr;
63 }
64
ConvertToJsPriKey(napi_env env)65 napi_value NapiPriKey::ConvertToJsPriKey(napi_env env)
66 {
67 napi_value instance;
68 napi_value constructor = nullptr;
69 napi_get_reference_value(env, classRef_, &constructor);
70 napi_new_instance(env, constructor, 0, nullptr, &instance);
71
72 const char *algName = this->GetPriKey()->base.getAlgorithm(&(this->GetPriKey()->base));
73 const char *format = this->GetPriKey()->base.getFormat(&(this->GetPriKey()->base));
74
75 napi_value napiAlgName = nullptr;
76 napi_create_string_utf8(env, algName, NAPI_AUTO_LENGTH, &napiAlgName);
77 napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
78
79 napi_value napiFormat = nullptr;
80 napi_create_string_utf8(env, format, NAPI_AUTO_LENGTH, &napiFormat);
81 napi_set_named_property(env, instance, CRYPTO_TAG_FORMAT.c_str(), napiFormat);
82 return instance;
83 }
84
JsGetEncoded(napi_env env,napi_callback_info info)85 napi_value NapiPriKey::JsGetEncoded(napi_env env, napi_callback_info info)
86 {
87 napi_value thisVar = nullptr;
88 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
89 NapiPriKey *napiPriKey = nullptr;
90 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
91 if (status != napi_ok || napiPriKey == nullptr) {
92 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
93 LOGE("failed to unwrap napiPriKey obj!");
94 return nullptr;
95 }
96
97 HcfPriKey *priKey = napiPriKey->GetPriKey();
98 if (priKey == nullptr) {
99 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
100 LOGE("failed to get priKey obj!");
101 return nullptr;
102 }
103
104 HcfBlob returnBlob;
105 HcfResult res = priKey->base.getEncoded(&priKey->base, &returnBlob);
106 if (res != HCF_SUCCESS) {
107 napi_throw(env, GenerateBusinessError(env, res, "c getEncoded fail."));
108 LOGD("[error] c getEncoded fail.");
109 return nullptr;
110 }
111
112 napi_value instance = ConvertBlobToNapiValue(env, &returnBlob);
113 if (instance == nullptr) {
114 HcfBlobDataFree(&returnBlob);
115 napi_throw(env, GenerateBusinessError(env, res, "covert blob to napi value failed."));
116 LOGE("covert blob to napi value failed.");
117 return nullptr;
118 }
119 HcfBlobDataClearAndFree(&returnBlob);
120 return instance;
121 }
122
ValidateAndGetParams(napi_env env,napi_callback_info info,std::string & format,HcfParamsSpec ** paramsSpec,NapiPriKey ** napiPriKey)123 static bool ValidateAndGetParams(napi_env env, napi_callback_info info, std::string &format,
124 HcfParamsSpec **paramsSpec, NapiPriKey **napiPriKey)
125 {
126 size_t expectedArgc = PARAMS_NUM_TWO;
127 size_t argc = expectedArgc;
128 napi_value thisVar = nullptr;
129 napi_value argv[PARAMS_NUM_TWO] = { nullptr };
130 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
131 if ((argc != expectedArgc) && (argc != (expectedArgc - 1))) {
132 LOGE("The input args num is invalid.");
133 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
134 return false;
135 }
136
137 if (!GetStringFromJSParams(env, argv[0], format)) {
138 LOGE("failed to get formatStr.");
139 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get formatStr."));
140 return false;
141 }
142
143 if (argc == expectedArgc) {
144 if (!GetEncodingParamsSpec(env, argv[1], paramsSpec)) {
145 LOGE("get params failed!");
146 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "get napi paramsSpec failed!"));
147 return false;
148 }
149 }
150
151 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(napiPriKey));
152 if (status != napi_ok || napiPriKey == nullptr) {
153 LOGE("failed to unwrap napiPriKey obj!");
154 FreeEncodeParamsSpec(*paramsSpec);
155 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
156 return false;
157 }
158 return true;
159 }
160
JsGetEncodedPem(napi_env env,napi_callback_info info)161 napi_value NapiPriKey::JsGetEncodedPem(napi_env env, napi_callback_info info)
162 {
163 std::string format;
164 HcfParamsSpec *paramsSpec = nullptr;
165 NapiPriKey *napiPriKey = nullptr;
166 if (!ValidateAndGetParams(env, info, format, ¶msSpec, &napiPriKey)) {
167 return NapiGetNull(env);
168 }
169
170 HcfPriKey *priKey = napiPriKey->GetPriKey();
171 if (priKey == nullptr) {
172 FreeEncodeParamsSpec(paramsSpec);
173 paramsSpec = nullptr;
174 LOGE("failed to get priKey obj!");
175 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
176 return nullptr;
177 }
178
179 char *returnString = nullptr;
180 HcfResult res = priKey->getEncodedPem(priKey, paramsSpec, format.c_str(), &returnString);
181 if (res != HCF_SUCCESS) {
182 FreeEncodeParamsSpec(paramsSpec);
183 paramsSpec = nullptr;
184 LOGE("getEncodedPem fail.");
185 napi_throw(env, GenerateBusinessError(env, res, "getEncodedPem fail."));
186 return nullptr;
187 }
188 napi_value instance = nullptr;
189 napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
190 HcfFree(returnString);
191 returnString = nullptr;
192 FreeEncodeParamsSpec(paramsSpec);
193 paramsSpec = nullptr;
194 return instance;
195 }
196
JsClearMem(napi_env env,napi_callback_info info)197 napi_value NapiPriKey::JsClearMem(napi_env env, napi_callback_info info)
198 {
199 napi_value thisVar = nullptr;
200 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
201 NapiPriKey *napiPriKey = nullptr;
202 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
203 if (status != napi_ok || napiPriKey == nullptr) {
204 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
205 LOGE("failed to unwrap napiPriKey obj!");
206 return nullptr;
207 }
208
209 HcfPriKey *priKey = napiPriKey->GetPriKey();
210 if (priKey == nullptr) {
211 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
212 LOGE("failed to get priKey obj!");
213 return nullptr;
214 }
215
216 priKey->clearMem(priKey);
217 return nullptr;
218 }
219
GetAsyKeySpecBigInt(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)220 static napi_value GetAsyKeySpecBigInt(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
221 {
222 HcfBigInteger returnBigInteger = { 0 };
223 HcfResult res = priKey->getAsyKeySpecBigInteger(priKey, item, &returnBigInteger);
224 if (res != HCF_SUCCESS) {
225 napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecBigInteger failed."));
226 LOGE("C getAsyKeySpecBigInteger failed.");
227 return nullptr;
228 }
229
230 napi_value instance = ConvertBigIntToNapiValue(env, &returnBigInteger);
231 (void)memset_s(returnBigInteger.data, returnBigInteger.len, 0, returnBigInteger.len);
232 HcfFree(returnBigInteger.data);
233 returnBigInteger.data = nullptr;
234 if (instance == nullptr) {
235 napi_throw(env, GenerateBusinessError(env, res, "covert bigInt to napi value failed."));
236 LOGE("covert bigInt to napi value failed.");
237 return nullptr;
238 }
239 return instance;
240 }
241
GetAsyKeySpecNumber(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)242 static napi_value GetAsyKeySpecNumber(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
243 {
244 int returnInt = 0;
245 HcfResult res = priKey->getAsyKeySpecInt(priKey, item, &returnInt);
246 if (res != HCF_SUCCESS) {
247 napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecInt failed."));
248 LOGE("C getAsyKeySpecInt fail.");
249 return nullptr;
250 }
251
252 napi_value instance = nullptr;
253 napi_create_int32(env, returnInt, &instance);
254 return instance;
255 }
256
GetAsyKeySpecString(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)257 static napi_value GetAsyKeySpecString(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
258 {
259 char *returnString = nullptr;
260 HcfResult res = priKey->getAsyKeySpecString(priKey, item, &returnString);
261 if (res != HCF_SUCCESS) {
262 napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecString failed."));
263 LOGE("c getAsyKeySpecString fail.");
264 return nullptr;
265 }
266
267 napi_value instance = nullptr;
268 napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
269 HcfFree(returnString);
270 returnString = nullptr;
271 return instance;
272 }
273
JsGetAsyKeySpec(napi_env env,napi_callback_info info)274 napi_value NapiPriKey::JsGetAsyKeySpec(napi_env env, napi_callback_info info)
275 {
276 napi_value thisVar = nullptr;
277 NapiPriKey *napiPriKey = nullptr;
278 size_t expectedArgc = ARGS_SIZE_ONE;
279 size_t argc = ARGS_SIZE_ONE;
280 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
281 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
282 if (argc != expectedArgc) {
283 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "JsGetAsyKeySpec fail, wrong argument num."));
284 LOGE("wrong argument num. require 1 arguments. [Argc]: %{public}zu!", argc);
285 return nullptr;
286 }
287
288 AsyKeySpecItem item;
289 if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
290 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "JsGetAsyKeySpec failed!"));
291 LOGE("JsGetAsyKeySpec failed!");
292 return nullptr;
293 }
294
295 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
296 if (status != napi_ok || napiPriKey == nullptr) {
297 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
298 LOGE("failed to unwrap napiPriKey obj!");
299 return nullptr;
300 }
301 HcfPriKey *priKey = napiPriKey->GetPriKey();
302 if (priKey == nullptr) {
303 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
304 LOGE("failed to get priKey obj!");
305 return nullptr;
306 }
307 LOGD("prepare priKey ok.");
308
309 int32_t type = GetAsyKeySpecType(item);
310 if (type == SPEC_ITEM_TYPE_BIG_INT) {
311 return GetAsyKeySpecBigInt(env, item, priKey);
312 } else if (type == SPEC_ITEM_TYPE_NUM) {
313 return GetAsyKeySpecNumber(env, item, priKey);
314 } else if (type == SPEC_ITEM_TYPE_STR) {
315 return GetAsyKeySpecString(env, item, priKey);
316 } else {
317 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "AsyKeySpecItem not support!"));
318 return nullptr;
319 }
320 }
321
JsGetEncodedDer(napi_env env,napi_callback_info info)322 napi_value NapiPriKey::JsGetEncodedDer(napi_env env, napi_callback_info info)
323 {
324 napi_value thisVar = nullptr;
325 NapiPriKey *napiPriKey = nullptr;
326 size_t argc = ARGS_SIZE_ONE;
327 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
328 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
329 if (argc != ARGS_SIZE_ONE) {
330 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "wrong argument num."));
331 LOGE("wrong argument num. require 1 arguments. [Argc]: %{public}zu!", argc);
332 return nullptr;
333 }
334 std::string format;
335 if (!GetStringFromJSParams(env, argv[0], format)) {
336 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get format."));
337 LOGE("get format fail.");
338 return nullptr;
339 }
340 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
341 if (status != napi_ok || napiPriKey == nullptr) {
342 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap private key obj!"));
343 LOGE("failed to unwrap private key obj!");
344 return nullptr;
345 }
346 HcfPriKey *priKey = napiPriKey->GetPriKey();
347 if (priKey == nullptr) {
348 napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get private key obj!"));
349 LOGE("failed to get private key obj!");
350 return nullptr;
351 }
352 HcfBlob returnBlob = { .data = nullptr, .len = 0 };
353 HcfResult res = priKey->getEncodedDer(priKey, format.c_str(), &returnBlob);
354 if (res != HCF_SUCCESS) {
355 napi_throw(env, GenerateBusinessError(env, res, "get private key encodedDer fail."));
356 LOGE("get private key encodeDer fail.");
357 return nullptr;
358 }
359
360 napi_value instance = ConvertBlobToNapiValue(env, &returnBlob);
361 HcfBlobDataClearAndFree(&returnBlob);
362 return instance;
363 }
364
DefinePriKeyJSClass(napi_env env)365 void NapiPriKey::DefinePriKeyJSClass(napi_env env)
366 {
367 napi_property_descriptor classDesc[] = {
368 DECLARE_NAPI_FUNCTION("getEncoded", NapiPriKey::JsGetEncoded),
369 DECLARE_NAPI_FUNCTION("getEncodedDer", NapiPriKey::JsGetEncodedDer),
370 DECLARE_NAPI_FUNCTION("getEncodedPem", NapiPriKey::JsGetEncodedPem),
371 DECLARE_NAPI_FUNCTION("clearMem", NapiPriKey::JsClearMem),
372 DECLARE_NAPI_FUNCTION("getAsyKeySpec", NapiPriKey::JsGetAsyKeySpec),
373 };
374 napi_value constructor = nullptr;
375 napi_define_class(env, "PriKey", NAPI_AUTO_LENGTH, NapiPriKey::PriKeyConstructor, nullptr,
376 sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
377 napi_create_reference(env, constructor, 1, &classRef_);
378 }
379 } // CryptoFramework
380 } // OHOS
381