1 /*
2  * Copyright (c) 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_x509_distinguished_name.h"
17 
18 #include "cf_log.h"
19 #include "cf_memory.h"
20 #include "cf_object_base.h"
21 #include "cf_result.h"
22 #include "napi/native_api.h"
23 #include "napi/native_common.h"
24 #include "napi_cert_defines.h"
25 #include "napi_cert_utils.h"
26 #include "utils.h"
27 
28 namespace OHOS {
29 namespace CertFramework {
30 thread_local napi_ref NapiX509DistinguishedName::classRef_ = nullptr;
31 
32 struct CfCtx {
33     napi_value promise = nullptr;
34     napi_deferred deferred = nullptr;
35     napi_async_work asyncWork = nullptr;
36     napi_ref cfRef = nullptr;
37 
38     CfBlob *inPara = nullptr;
39     bool paraIsString = true;
40     HcfX509DistinguishedName *x509Name = nullptr;
41     NapiX509DistinguishedName *nameClass = nullptr;
42     int32_t errCode = 0;
43     const char *errMsg = nullptr;
44 };
45 
NapiX509DistinguishedName(HcfX509DistinguishedName * x509Name_)46 NapiX509DistinguishedName::NapiX509DistinguishedName(HcfX509DistinguishedName *x509Name_)
47 {
48     this->x509Name_ = x509Name_;
49 }
50 
~NapiX509DistinguishedName()51 NapiX509DistinguishedName::~NapiX509DistinguishedName()
52 {
53     CfObjDestroy(this->x509Name_);
54 }
55 
FreeCryptoFwkCtx(napi_env env,CfCtx * context)56 static void FreeCryptoFwkCtx(napi_env env, CfCtx *context)
57 {
58     if (context == nullptr) {
59         return;
60     }
61 
62     if (context->asyncWork != nullptr) {
63         napi_delete_async_work(env, context->asyncWork);
64     }
65 
66     if (context->cfRef != nullptr) {
67         napi_delete_reference(env, context->cfRef);
68         context->cfRef = nullptr;
69     }
70 
71     if (context->inPara != nullptr) {
72         CfBlobFree(&(context->inPara));
73     }
74 
75     CfFree(context);
76 }
77 
ReturnPromiseResult(napi_env env,CfCtx * context,napi_value result)78 static void ReturnPromiseResult(napi_env env, CfCtx *context, napi_value result)
79 {
80     if (context->errCode == CF_SUCCESS) {
81         napi_resolve_deferred(env, context->deferred, result);
82     } else {
83         napi_reject_deferred(env, context->deferred,
84             CertGenerateBusinessError(env, context->errCode, context->errMsg));
85     }
86 }
87 
CreateDistinguishedNameExecute(napi_env env,void * data)88 void NapiX509DistinguishedName::CreateDistinguishedNameExecute(napi_env env, void *data)
89 {
90     CfCtx *context = static_cast<CfCtx *>(data);
91 
92     context->errCode = HcfX509DistinguishedNameCreate(context->inPara, context->paraIsString, &context->x509Name);
93     if (context->errCode != CF_SUCCESS) {
94         context->errMsg = "create x509DistinguishedName failed";
95     }
96 }
97 
CreateDistinguishedNameComplete(napi_env env,napi_status status,void * data)98 void NapiX509DistinguishedName::CreateDistinguishedNameComplete(napi_env env, napi_status status, void *data)
99 {
100     CfCtx *context = static_cast<CfCtx *>(data);
101     if (context->errCode != CF_SUCCESS) {
102         LOGE("call create x509DistinguisehdName failed!");
103         ReturnPromiseResult(env, context, nullptr);
104         FreeCryptoFwkCtx(env, context);
105         return;
106     }
107     napi_value instance = CreateX509DistinguishedName(env);
108     NapiX509DistinguishedName *x509NameClass = new (std::nothrow) NapiX509DistinguishedName(context->x509Name);
109     if (x509NameClass == nullptr) {
110         context->errCode = CF_ERR_MALLOC;
111         context->errMsg = "Failed to create x509DistinguisehdName class";
112         LOGE("Failed to create x509DistinguisehdName class");
113         ReturnPromiseResult(env, context, nullptr);
114         CfObjDestroy(context->x509Name);
115         FreeCryptoFwkCtx(env, context);
116         return;
117     }
118     napi_wrap(
119         env, instance, x509NameClass,
120         [](napi_env env, void *data, void *hint) {
121             NapiX509DistinguishedName *nameClass = static_cast<NapiX509DistinguishedName *>(data);
122             delete nameClass;
123             return;
124         },
125         nullptr, nullptr);
126     ReturnPromiseResult(env, context, instance);
127     FreeCryptoFwkCtx(env, context);
128 }
129 
GetEncoded(napi_env env,napi_callback_info info)130 napi_value NapiX509DistinguishedName::GetEncoded(napi_env env, napi_callback_info info)
131 {
132     HcfX509DistinguishedName *x509Name = GetX509DistinguishedName();
133     CfEncodingBlob blob = {nullptr, 0, CF_FORMAT_DER};
134     CfResult ret = x509Name->getEncode(x509Name, &blob);
135     if (ret != CF_SUCCESS) {
136         LOGE("Distinguished Name get encoded failed");
137         napi_throw(env, CertGenerateBusinessError(env, ret, "Distinguished Name get encoded failed"));
138         return nullptr;
139     }
140     napi_value result = ConvertEncodingBlobToNapiValue(env, &blob);
141     CfEncodingBlobDataFree(&blob);
142     return result;
143 }
144 
GetName(napi_env env,napi_callback_info info)145 napi_value NapiX509DistinguishedName::GetName(napi_env env, napi_callback_info info)
146 {
147     size_t argc = ARGS_SIZE_ONE;
148     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
149     napi_value thisVar = nullptr;
150     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
151     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
152         LOGE("CertCheckArgsCount error");
153         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed"));
154         return nullptr;
155     }
156     HcfX509DistinguishedName *x509Name = GetX509DistinguishedName();
157     if (argc == PARAM0) {
158         CfBlob blob = { 0, nullptr };
159         CfResult ret = x509Name->getName(x509Name, NULL, &blob, NULL);
160         if (ret != CF_SUCCESS) {
161             LOGE("Distinguished Name get name failed");
162             napi_throw(env, CertGenerateBusinessError(env, ret, "Distinguished Name get name failed"));
163             return nullptr;
164         }
165 
166         napi_value result = nullptr;
167         napi_create_string_utf8(env, reinterpret_cast<char *>(blob.data), blob.size, &result);
168         CfBlobDataFree(&blob);
169         return result;
170     } else if (argc == ARGS_SIZE_ONE) {
171         CfBlob *inPara = CertGetBlobFromStringJSParams(env, argv[PARAM0]);
172         if (inPara != nullptr) {
173             CfArray outArr = { nullptr, CF_FORMAT_DER, 0 };
174             CfResult ret = x509Name->getName(x509Name, inPara, NULL, &outArr);
175             if (ret != CF_SUCCESS) {
176                 LOGE("Distinguished Name get name failed");
177                 CfBlobFree(&inPara);
178                 napi_throw(env, CertGenerateBusinessError(env, ret, "Distinguished Name get name failed"));
179                 return nullptr;
180             }
181 
182             napi_value result = ConvertArrayStringToNapiValue(env, &outArr);
183             CfBlobFree(&inPara);
184             CfArrayDataClearAndFree(&outArr);
185             return result;
186         }
187     }
188     return nullptr;
189 }
190 
NapiGetEncoded(napi_env env,napi_callback_info info)191 static napi_value NapiGetEncoded(napi_env env, napi_callback_info info)
192 {
193     napi_value thisVar = nullptr;
194     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
195     NapiX509DistinguishedName *x509Name = nullptr;
196     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&x509Name));
197     if (x509Name == nullptr) {
198         LOGE("x509Name is nullptr!");
199         return nullptr;
200     }
201     return x509Name->GetEncoded(env, info);
202 }
203 
NapiGetName(napi_env env,napi_callback_info info)204 static napi_value NapiGetName(napi_env env, napi_callback_info info)
205 {
206     napi_value thisVar = nullptr;
207     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
208     NapiX509DistinguishedName *x509Name = nullptr;
209     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&x509Name));
210     if (x509Name == nullptr) {
211         LOGE("x509Name is nullptr!");
212         return nullptr;
213     }
214     return x509Name->GetName(env, info);
215 }
216 
X509DistinguishedNameConstructor(napi_env env,napi_callback_info info)217 static napi_value X509DistinguishedNameConstructor(napi_env env, napi_callback_info info)
218 {
219     napi_value thisVar = nullptr;
220     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
221     return thisVar;
222 }
223 
NapiCreateX509DistinguishedName(napi_env env,napi_callback_info info)224 napi_value NapiX509DistinguishedName::NapiCreateX509DistinguishedName(napi_env env, napi_callback_info info)
225 {
226     size_t argc = ARGS_SIZE_ONE;
227     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
228     napi_value thisVar = nullptr;
229     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
230     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
231         LOGE("CertCheckArgsCount error");
232         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed"));
233         return nullptr;
234     }
235 
236     CfCtx *context = static_cast<CfCtx *>(CfMalloc(sizeof(CfCtx), 0));
237     if (context == nullptr) {
238         LOGE("malloc context failed!");
239         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "CfMalloc failed"));
240         return nullptr;
241     }
242 
243     napi_create_promise(env, &context->deferred, &context->promise);
244 
245     napi_valuetype valueType;
246     napi_typeof(env, argv[PARAM0], &valueType);
247     if (valueType != napi_string) {
248         context->inPara = CertGetBlobFromUint8ArrJSParams(env, argv[PARAM0]);
249         context->paraIsString = false;
250     } else {
251         context->inPara = CertGetBlobFromStringJSParams(env, argv[PARAM0]);
252         context->paraIsString = true;
253     }
254 
255     if (napi_create_reference(env, thisVar, 1, &context->cfRef) != napi_ok) {
256         LOGE("create reference failed!");
257         FreeCryptoFwkCtx(env, context);
258         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create reference failed"));
259         return nullptr;
260     }
261 
262     napi_create_async_work(env, nullptr, CertGetResourceName(env, "createX500DistinguishedName"),
263         CreateDistinguishedNameExecute,
264         CreateDistinguishedNameComplete,
265         static_cast<void *>(context),
266         &context->asyncWork);
267 
268     napi_queue_async_work(env, context->asyncWork);
269     return context->promise;
270 }
271 
DefineX509DistinguishedNameJSClass(napi_env env,napi_value exports)272 void NapiX509DistinguishedName::DefineX509DistinguishedNameJSClass(napi_env env, napi_value exports)
273 {
274     napi_property_descriptor desc[] = {
275         DECLARE_NAPI_FUNCTION("createX500DistinguishedName", NapiCreateX509DistinguishedName),
276     };
277     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
278 
279     napi_property_descriptor x509NameDesc[] = {
280         DECLARE_NAPI_FUNCTION("getEncoded", NapiGetEncoded),
281         DECLARE_NAPI_FUNCTION("getName", NapiGetName),
282     };
283     napi_value constructor = nullptr;
284     napi_define_class(env, "X500DistinguishedName", NAPI_AUTO_LENGTH, X509DistinguishedNameConstructor, nullptr,
285         sizeof(x509NameDesc) / sizeof(x509NameDesc[0]), x509NameDesc, &constructor);
286     napi_create_reference(env, constructor, 1, &classRef_);
287 }
288 
CreateX509DistinguishedName(napi_env env)289 napi_value NapiX509DistinguishedName::CreateX509DistinguishedName(napi_env env)
290 {
291     napi_value constructor = nullptr;
292     napi_value instance = nullptr;
293     napi_get_reference_value(env, classRef_, &constructor);
294     napi_new_instance(env, constructor, 0, nullptr, &instance);
295     return instance;
296 }
297 } // namespace CertFramework
298 } // namespace OHOS
299