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 
ConvertToJsPriKey(napi_env env)45 napi_value NapiPriKey::ConvertToJsPriKey(napi_env env)
46 {
47     napi_value instance;
48     napi_value constructor = nullptr;
49     napi_get_reference_value(env, classRef_, &constructor);
50     napi_new_instance(env, constructor, 0, nullptr, &instance);
51 
52     const char *algName = this->GetPriKey()->base.getAlgorithm(&(this->GetPriKey()->base));
53     const char *format = this->GetPriKey()->base.getFormat(&(this->GetPriKey()->base));
54 
55     napi_value napiAlgName = nullptr;
56     napi_create_string_utf8(env, algName, NAPI_AUTO_LENGTH, &napiAlgName);
57     napi_set_named_property(env, instance, CRYPTO_TAG_ALG_NAME.c_str(), napiAlgName);
58 
59     napi_value napiFormat = nullptr;
60     napi_create_string_utf8(env, format, NAPI_AUTO_LENGTH, &napiFormat);
61     napi_set_named_property(env, instance, CRYPTO_TAG_FORMAT.c_str(), napiFormat);
62     return instance;
63 }
64 
JsGetEncoded(napi_env env,napi_callback_info info)65 napi_value NapiPriKey::JsGetEncoded(napi_env env, napi_callback_info info)
66 {
67     napi_value thisVar = nullptr;
68     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
69     NapiPriKey *napiPriKey = nullptr;
70     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
71     if (status != napi_ok || napiPriKey == nullptr) {
72         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
73         LOGE("failed to unwrap napiPriKey obj!");
74         return nullptr;
75     }
76 
77     HcfPriKey *priKey = napiPriKey->GetPriKey();
78     if (priKey == nullptr) {
79         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
80         LOGE("failed to get priKey obj!");
81         return nullptr;
82     }
83 
84     HcfBlob returnBlob;
85     HcfResult res = priKey->base.getEncoded(&priKey->base, &returnBlob);
86     if (res != HCF_SUCCESS) {
87         napi_throw(env, GenerateBusinessError(env, res, "c getEncoded fail."));
88         LOGD("[error] c getEncoded fail.");
89         return nullptr;
90     }
91 
92     napi_value instance = ConvertBlobToNapiValue(env, &returnBlob);
93     if (instance == nullptr) {
94         HcfBlobDataFree(&returnBlob);
95         napi_throw(env, GenerateBusinessError(env, res, "covert blob to napi value failed."));
96         LOGE("covert blob to napi value failed.");
97         return nullptr;
98     }
99     HcfBlobDataClearAndFree(&returnBlob);
100     return instance;
101 }
102 
JsGetEncodedPem(napi_env env,napi_callback_info info)103 napi_value NapiPriKey::JsGetEncodedPem(napi_env env, napi_callback_info info)
104 {
105     size_t expectedArgc = PARAMS_NUM_ONE;
106     size_t argc = expectedArgc;
107     napi_value argv[PARAMS_NUM_ONE] = { nullptr };
108     napi_value thisVar = nullptr;
109     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
110     if (argc != expectedArgc) {
111         LOGE("The input args num is invalid.");
112         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "The input args num is invalid."));
113         return NapiGetNull(env);
114     }
115 
116     std::string format = "";
117     if (!GetStringFromJSParams(env, argv[0], format)) {
118         LOGE("failed to get formatStr.");
119         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get formatStr."));
120         return NapiGetNull(env);
121     }
122 
123     NapiPriKey *napiPriKey = nullptr;
124     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
125     if (status != napi_ok || napiPriKey == nullptr) {
126         LOGE("failed to unwrap napiPriKey obj!");
127         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
128         return nullptr;
129     }
130 
131     HcfPriKey *priKey = napiPriKey->GetPriKey();
132     if (priKey == nullptr) {
133         LOGE("failed to get priKey obj!");
134         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
135         return nullptr;
136     }
137 
138     char *returnString = nullptr;
139     HcfResult res = priKey->base.getEncodedPem(&priKey->base, format.c_str(), &returnString);
140     if (res != HCF_SUCCESS) {
141         LOGE("getEncodedPem fail.");
142         napi_throw(env, GenerateBusinessError(env, res, "getEncodedPem fail."));
143         return nullptr;
144     }
145     napi_value instance = nullptr;
146     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
147     HcfFree(returnString);
148     return instance;
149 }
150 
JsClearMem(napi_env env,napi_callback_info info)151 napi_value NapiPriKey::JsClearMem(napi_env env, napi_callback_info info)
152 {
153     napi_value thisVar = nullptr;
154     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
155     NapiPriKey *napiPriKey = nullptr;
156     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
157     if (status != napi_ok || napiPriKey == nullptr) {
158         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
159         LOGE("failed to unwrap napiPriKey obj!");
160         return nullptr;
161     }
162 
163     HcfPriKey *priKey = napiPriKey->GetPriKey();
164     if (priKey == nullptr) {
165         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
166         LOGE("failed to get priKey obj!");
167         return nullptr;
168     }
169 
170     priKey->clearMem(priKey);
171     return nullptr;
172 }
173 
GetAsyKeySpecBigInt(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)174 static napi_value GetAsyKeySpecBigInt(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
175 {
176     HcfBigInteger returnBigInteger = { 0 };
177     HcfResult res = priKey->getAsyKeySpecBigInteger(priKey, item, &returnBigInteger);
178     if (res != HCF_SUCCESS) {
179         napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecBigInteger failed."));
180         LOGE("C getAsyKeySpecBigInteger failed.");
181         return nullptr;
182     }
183 
184     napi_value instance = ConvertBigIntToNapiValue(env, &returnBigInteger);
185     (void)memset_s(returnBigInteger.data, returnBigInteger.len, 0, returnBigInteger.len);
186     HcfFree(returnBigInteger.data);
187     if (instance == nullptr) {
188         napi_throw(env, GenerateBusinessError(env, res, "covert bigInt to napi value failed."));
189         LOGE("covert bigInt to napi value failed.");
190         return nullptr;
191     }
192     return instance;
193 }
194 
GetAsyKeySpecNumber(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)195 static napi_value GetAsyKeySpecNumber(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
196 {
197     int returnInt = 0;
198     HcfResult res = priKey->getAsyKeySpecInt(priKey, item, &returnInt);
199     if (res != HCF_SUCCESS) {
200         napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecInt failed."));
201         LOGE("C getAsyKeySpecInt fail.");
202         return nullptr;
203     }
204 
205     napi_value instance = nullptr;
206     napi_create_int32(env, returnInt, &instance);
207     return instance;
208 }
209 
GetAsyKeySpecString(napi_env env,AsyKeySpecItem item,HcfPriKey * priKey)210 static napi_value GetAsyKeySpecString(napi_env env, AsyKeySpecItem item, HcfPriKey *priKey)
211 {
212     char *returnString = nullptr;
213     HcfResult res = priKey->getAsyKeySpecString(priKey, item, &returnString);
214     if (res != HCF_SUCCESS) {
215         napi_throw(env, GenerateBusinessError(env, res, "C getAsyKeySpecString failed."));
216         LOGE("c getAsyKeySpecString fail.");
217         return nullptr;
218     }
219 
220     napi_value instance = nullptr;
221     napi_create_string_utf8(env, returnString, NAPI_AUTO_LENGTH, &instance);
222     HcfFree(returnString);
223     return instance;
224 }
225 
JsGetAsyKeySpec(napi_env env,napi_callback_info info)226 napi_value NapiPriKey::JsGetAsyKeySpec(napi_env env, napi_callback_info info)
227 {
228     napi_value thisVar = nullptr;
229     NapiPriKey *napiPriKey = nullptr;
230     size_t expectedArgc = ARGS_SIZE_ONE;
231     size_t argc = ARGS_SIZE_ONE;
232     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
233     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
234     if (argc != expectedArgc) {
235         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "JsGetAsyKeySpec fail, wrong argument num."));
236         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
237         return nullptr;
238     }
239 
240     AsyKeySpecItem item;
241     if (napi_get_value_uint32(env, argv[0], reinterpret_cast<uint32_t *>(&item)) != napi_ok) {
242         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "JsGetAsyKeySpec failed!"));
243         LOGE("JsGetAsyKeySpec failed!");
244         return nullptr;
245     }
246 
247     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
248     if (status != napi_ok || napiPriKey == nullptr) {
249         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap napiPriKey obj!"));
250         LOGE("failed to unwrap napiPriKey obj!");
251         return nullptr;
252     }
253     HcfPriKey *priKey = napiPriKey->GetPriKey();
254     if (priKey == nullptr) {
255         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get priKey obj!"));
256         LOGE("failed to get priKey obj!");
257         return nullptr;
258     }
259     LOGD("prepare priKey ok.");
260 
261     int32_t type = GetAsyKeySpecType(item);
262     if (type == SPEC_ITEM_TYPE_BIG_INT) {
263         return GetAsyKeySpecBigInt(env, item, priKey);
264     } else if (type == SPEC_ITEM_TYPE_NUM) {
265         return GetAsyKeySpecNumber(env, item, priKey);
266     } else if (type == SPEC_ITEM_TYPE_STR) {
267         return GetAsyKeySpecString(env, item, priKey);
268     } else {
269         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "AsyKeySpecItem not support!"));
270         return nullptr;
271     }
272 }
273 
JsGetEncodedDer(napi_env env,napi_callback_info info)274 napi_value NapiPriKey::JsGetEncodedDer(napi_env env, napi_callback_info info)
275 {
276     napi_value thisVar = nullptr;
277     NapiPriKey *napiPriKey = nullptr;
278     size_t argc = ARGS_SIZE_ONE;
279     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
280     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
281     if (argc != ARGS_SIZE_ONE) {
282         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "wrong argument num."));
283         LOGE("wrong argument num. require 1 arguments. [Argc]: %zu!", argc);
284         return nullptr;
285     }
286     std::string format;
287     if (!GetStringFromJSParams(env, argv[0], format)) {
288         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get format."));
289         LOGE("get format fail.");
290         return nullptr;
291     }
292     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiPriKey));
293     if (status != napi_ok || napiPriKey == nullptr) {
294         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to unwrap private key obj!"));
295         LOGE("failed to unwrap private key obj!");
296         return nullptr;
297     }
298     HcfPriKey *priKey = napiPriKey->GetPriKey();
299     if (priKey == nullptr) {
300         napi_throw(env, GenerateBusinessError(env, HCF_INVALID_PARAMS, "failed to get private key obj!"));
301         LOGE("failed to get private key obj!");
302         return nullptr;
303     }
304     HcfBlob returnBlob = { .data = nullptr, .len = 0 };
305     HcfResult res = priKey->getEncodedDer(priKey, format.c_str(), &returnBlob);
306     if (res != HCF_SUCCESS) {
307         napi_throw(env, GenerateBusinessError(env, res, "get private key encodedDer fail."));
308         LOGE("get private key encodeDer fail.");
309         return nullptr;
310     }
311 
312     napi_value instance = ConvertBlobToNapiValue(env, &returnBlob);
313     HcfBlobDataClearAndFree(&returnBlob);
314     return instance;
315 }
316 
DefinePriKeyJSClass(napi_env env)317 void NapiPriKey::DefinePriKeyJSClass(napi_env env)
318 {
319     napi_property_descriptor classDesc[] = {
320         DECLARE_NAPI_FUNCTION("getEncoded", NapiPriKey::JsGetEncoded),
321         DECLARE_NAPI_FUNCTION("getEncodedDer", NapiPriKey::JsGetEncodedDer),
322         DECLARE_NAPI_FUNCTION("getEncodedPem", NapiPriKey::JsGetEncodedPem),
323         DECLARE_NAPI_FUNCTION("clearMem", NapiPriKey::JsClearMem),
324         DECLARE_NAPI_FUNCTION("getAsyKeySpec", NapiPriKey::JsGetAsyKeySpec),
325     };
326     napi_value constructor = nullptr;
327     napi_define_class(env, "PriKey", NAPI_AUTO_LENGTH, NapiPriKey::PriKeyConstructor, nullptr,
328         sizeof(classDesc) / sizeof(classDesc[0]), classDesc, &constructor);
329     napi_create_reference(env, constructor, 1, &classRef_);
330 }
331 } // CryptoFramework
332 } // OHOS
333