• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_cert_chain.h"
17 
18 #include "cf_api.h"
19 #include "cf_log.h"
20 #include "cf_memory.h"
21 #include "cf_param.h"
22 #include "cf_result.h"
23 #include "napi/native_api.h"
24 #include "napi/native_node_api.h"
25 #include "napi_cert_defines.h"
26 #include "napi_cert_utils.h"
27 #include "napi_common.h"
28 #include "napi_object.h"
29 #include "napi_x509_cert_chain_validate_params.h"
30 #include "napi_x509_cert_chain_validate_result.h"
31 #include "napi_x509_trust_anchor.h"
32 #include "napi_cert_crl_common.h"
33 #include "securec.h"
34 #include "x509_cert_chain_validate_params.h"
35 #include "x509_certificate.h"
36 #include "x509_cert_chain.h"
37 #include "cert_crl_common.h"
38 
39 namespace OHOS {
40 namespace CertFramework {
41 thread_local napi_ref NapiX509CertChain::classRef_ = nullptr;
42 
43 struct CfCtx {
44     AsyncCtx async;
45     NapiX509CertChain *certChainClass = nullptr;
46     HcfCertChain *certChain = nullptr;
47     CfEncodingBlob *encodingBlob = nullptr;
48     HcfX509CertChainValidateParams params;
49     HcfX509CertChainValidateResult result;
50 };
51 
NapiX509CertChain(HcfCertChain * certChain)52 NapiX509CertChain::NapiX509CertChain(HcfCertChain *certChain)
53 {
54     this->certChain_ = certChain;
55 }
56 
~NapiX509CertChain()57 NapiX509CertChain::~NapiX509CertChain()
58 {
59     CfObjDestroy(this->certChain_);
60 }
61 
BuildCertChainContext()62 static CfCtx *BuildCertChainContext()
63 {
64     CfCtx *context = static_cast<CfCtx *>(HcfMalloc(sizeof(CfCtx), 0));
65     if (context == nullptr) {
66         LOGE("malloc context failed!");
67         return nullptr;
68     }
69     context->async = static_cast<AsyncCtx>(HcfMalloc(sizeof(AsyncContext), 0));
70     if (context->async == nullptr) {
71         LOGE("malloc context failed!");
72         CfFree(context);
73         return nullptr;
74     }
75     return context;
76 }
77 
DeleteCertChainContext(napi_env env,CfCtx * & context,bool freeCertFlag=false)78 static void DeleteCertChainContext(napi_env env, CfCtx *&context, bool freeCertFlag = false)
79 {
80     if (context == nullptr) {
81         return;
82     }
83 
84     FreeAsyncContext(env, context->async);
85 
86     if (context->encodingBlob != nullptr) {
87         CfEncodingBlobDataFree(context->encodingBlob);
88         CF_FREE_PTR(context->encodingBlob);
89     }
90 
91     FreeX509CertChainValidateParams(context->params);
92     FreeX509CertChainValidateResult(context->result, freeCertFlag);
93 
94     CF_FREE_PTR(context);
95 }
96 
CreateCertChainJSInstance(napi_env env)97 static napi_value CreateCertChainJSInstance(napi_env env)
98 {
99     napi_value constructor = nullptr;
100     napi_value instance = nullptr;
101     napi_get_reference_value(env, NapiX509CertChain::classRef_, &constructor);
102     napi_new_instance(env, constructor, 0, nullptr, &instance);
103     return instance;
104 }
105 
CreateCallbackAndPromise(napi_env env,CfCtx * context,size_t argc,size_t maxCount,napi_value callbackValue)106 static bool CreateCallbackAndPromise(
107     napi_env env, CfCtx *context, size_t argc, size_t maxCount, napi_value callbackValue)
108 {
109     context->async->asyncType = GetAsyncType(env, argc, maxCount, callbackValue);
110     if (context->async->asyncType == ASYNC_TYPE_CALLBACK) {
111         if (!CertGetCallbackFromJSParams(env, callbackValue, &context->async->callback)) {
112             LOGE("x509 certificate: get callback failed!");
113             return false;
114         }
115     } else {
116         napi_create_promise(env, &context->async->deferred, &context->async->promise);
117     }
118     return true;
119 }
120 
CreateCertChainExecute(napi_env env,void * data)121 static void CreateCertChainExecute(napi_env env, void *data)
122 {
123     CfCtx *context = static_cast<CfCtx *>(data);
124     context->async->errCode = HcfCertChainCreate(context->encodingBlob, nullptr, &context->certChain);
125     if (context->async->errCode != CF_SUCCESS) {
126         context->async->errMsg = "create cert chain failed";
127     }
128 }
129 
BuildCreateInstance(napi_env env,HcfCertChain * certChain)130 static napi_value BuildCreateInstance(napi_env env, HcfCertChain *certChain)
131 {
132     napi_value instance = CreateCertChainJSInstance(env);
133     NapiX509CertChain *napiObject = new (std::nothrow) NapiX509CertChain(certChain);
134     if (napiObject == nullptr) {
135         LOGE("new napi object failed.");
136         return nullptr;
137     }
138     napi_wrap(
139         env, instance, napiObject,
140         [](napi_env env, void *data, void *hint) {
141             NapiX509CertChain *certchain = static_cast<NapiX509CertChain *>(data);
142             delete certchain;
143             return;
144         },
145         nullptr, nullptr);
146     return instance;
147 }
148 
CreateCertChainComplete(napi_env env,napi_status status,void * data)149 static void CreateCertChainComplete(napi_env env, napi_status status, void *data)
150 {
151     CfCtx *context = static_cast<CfCtx *>(data);
152     if (context->async->errCode != CF_SUCCESS) {
153         ReturnJSResult(env, context->async, nullptr);
154         DeleteCertChainContext(env, context, false);
155         return;
156     }
157 
158     napi_value instance = BuildCreateInstance(env, context->certChain);
159     if (instance == nullptr) {
160         context->async->errCode = CF_ERR_MALLOC;
161         context->async->errMsg = "Failed to create napi cert chain class";
162         LOGE("Failed to create napi cert chain class");
163         CfObjDestroy(context->certChain);
164         context->certChain = nullptr;
165     }
166     ReturnJSResult(env, context->async, instance);
167     DeleteCertChainContext(env, context);
168 }
169 
CreateCertChainAsyncWork(napi_env env,CfCtx * context)170 static napi_value CreateCertChainAsyncWork(napi_env env, CfCtx *context)
171 {
172     napi_create_async_work(env, nullptr, GetResourceName(env, "createX509CertChain"), CreateCertChainExecute,
173         CreateCertChainComplete, static_cast<void *>(context), &context->async->asyncWork);
174 
175     napi_queue_async_work(env, context->async->asyncWork);
176     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
177         return context->async->promise;
178     } else {
179         return NapiGetNull(env);
180     }
181 }
182 
ValidateExecute(napi_env env,void * data)183 static void ValidateExecute(napi_env env, void *data)
184 {
185     LOGI("enter");
186     CfCtx *context = static_cast<CfCtx *>(data);
187     context->async->errCode = context->certChain->validate(context->certChain, &context->params, &context->result);
188     if (context->async->errCode != CF_SUCCESS) {
189         context->async->errMsg = "create cert chain failed";
190     }
191 }
192 
ValidateComplete(napi_env env,napi_status status,void * data)193 static void ValidateComplete(napi_env env, napi_status status, void *data)
194 {
195     LOGI("enter");
196     CfCtx *context = static_cast<CfCtx *>(data);
197     if (context->async->errCode != CF_SUCCESS) {
198         ReturnJSResult(env, context->async, nullptr);
199         DeleteCertChainContext(env, context, false);
200         return;
201     }
202     napi_value instance = BuildX509CertChainValidateResultJS(env, &context->result);
203     if (instance == nullptr) {
204         LOGE("validate ret failed");
205         context->async->errCode = CF_ERR_MALLOC;
206         context->async->errMsg = "build return obj failed!";
207         ReturnJSResult(env, context->async, nullptr);
208         DeleteCertChainContext(env, context, true);
209         return;
210     }
211 
212     ReturnJSResult(env, context->async, instance);
213     DeleteCertChainContext(env, context);
214 }
215 
ValidateAsyncWork(napi_env env,CfCtx * context)216 static napi_value ValidateAsyncWork(napi_env env, CfCtx *context)
217 {
218     napi_create_async_work(env, nullptr, GetResourceName(env, "Validate"), ValidateExecute, ValidateComplete,
219         static_cast<void *>(context), &context->async->asyncWork);
220 
221     napi_queue_async_work(env, context->async->asyncWork);
222     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
223         return context->async->promise;
224     } else {
225         return NapiGetNull(env);
226     }
227 }
228 
Validate(napi_env env,napi_callback_info info)229 napi_value NapiX509CertChain::Validate(napi_env env, napi_callback_info info)
230 {
231     LOGI("enter");
232     size_t argc = ARGS_SIZE_TWO;
233     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
234     napi_value thisVar = nullptr;
235     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
236     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
237         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "check args count failed!"));
238         LOGE("check args count failed.");
239         return nullptr;
240     }
241 
242     CfCtx *context = BuildCertChainContext();
243     if (context == nullptr) {
244         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc context failed!"));
245         LOGE("malloc context failed.");
246         return nullptr;
247     }
248 
249     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
250         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CreateCallbackAndPromise failed!"));
251         DeleteCertChainContext(env, context);
252         LOGE("CreateCallbackAndPromise failed!");
253         return nullptr;
254     }
255     context->certChainClass = this;
256     context->certChain = GetCertChain();
257     if (!BuildX509CertChainValidateParams(env, argv[PARAM0], context->params)) {
258         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "BuildX509CertChainValidateParams failed!"));
259         LOGE("BuildX509CertChainValidateParams failed!");
260         DeleteCertChainContext(env, context);
261         return nullptr;
262     }
263 
264     return ValidateAsyncWork(env, context);
265 }
266 
CreateX509CertChainByArray(napi_env env,napi_value param)267 static napi_value CreateX509CertChainByArray(napi_env env, napi_value param)
268 {
269     HcfX509CertificateArray certs = { nullptr, 0 };
270     if (param != nullptr && !GetArrayCertFromNapiValue(env, param, &certs, false)) {
271         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert arr failed!"));
272         LOGE("get array cert from data failed!");
273         return nullptr;
274     }
275 
276     HcfCertChain *certChain = nullptr;
277     CfResult res = HcfCertChainCreate(nullptr, &certs, &certChain);
278     if (res != CF_SUCCESS) {
279         LOGE("HcfCertChainCreate failed!");
280         napi_throw(env, CertGenerateBusinessError(env, res, "create cert chain by arr failed!"));
281         CF_FREE_PTR(certs.data);
282         return nullptr;
283     }
284     napi_value instance = BuildCreateInstance(env, certChain);
285     if (instance == nullptr) {
286         LOGE("HcfCertChainCreate failed!");
287         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "create instance failed!"));
288         CfObjDestroy(certChain);
289         CF_FREE_PTR(certs.data);
290         return nullptr;
291     }
292     return instance;
293 }
294 
CreateX509CertChainByEncodingBlob(napi_env env,size_t argc,napi_value param1,napi_value param2)295 static napi_value CreateX509CertChainByEncodingBlob(napi_env env, size_t argc, napi_value param1, napi_value param2)
296 {
297     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
298         LOGE("CertCheckArgsCount failed");
299         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
300         return nullptr;
301     }
302     CfCtx *context = BuildCertChainContext();
303     if (context == nullptr) {
304         LOGE("context is nullptr");
305         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
306         return nullptr;
307     }
308 
309     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, param2)) {
310         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create Callback Promise failed!"));
311         LOGE("Create Callback Promise failed");
312         DeleteCertChainContext(env, context);
313         return nullptr;
314     }
315     if (!GetEncodingBlobFromValue(env, param1, &context->encodingBlob)) {
316         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Get Encoding Blob failed!"));
317         LOGE("Get Encoding Blob failed");
318         DeleteCertChainContext(env, context);
319         return nullptr;
320     }
321 
322     return CreateCertChainAsyncWork(env, context);
323 }
324 
NapiCreateX509CertChain(napi_env env,napi_callback_info info)325 napi_value NapiCreateX509CertChain(napi_env env, napi_callback_info info)
326 {
327     size_t argc = ARGS_SIZE_TWO;
328     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
329     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
330 
331     bool flag = false;
332     napi_is_array(env, argv[PARAM0], &flag);
333     napi_value instance = nullptr;
334     if (flag) {
335         if (argc != ARGS_SIZE_ONE) {
336             LOGE("arg size is not correct");
337             napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "arg size is not correct!"));
338             return nullptr;
339         }
340         LOGI("NapiCreateX509CertChain : Array<X509Cert>!");
341         instance = CreateX509CertChainByArray(env, argv[PARAM0]);
342     } else {
343         LOGI("NapiCreateX509CertChain : inStream: EncodingBlob!");
344         instance = CreateX509CertChainByEncodingBlob(env, argc, argv[PARAM0], argv[PARAM1]);
345     }
346     return instance;
347 }
348 
NapiGetCertList(napi_env env,napi_callback_info info)349 napi_value NapiGetCertList(napi_env env, napi_callback_info info)
350 {
351     napi_value thisVar = nullptr;
352     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
353     NapiX509CertChain *napiCertChainObj = nullptr;
354     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
355     if (napiCertChainObj == nullptr) {
356         LOGE("napi cert chain object is nullptr!");
357         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
358         return nullptr;
359     }
360     HcfCertChain *certChain = napiCertChainObj->GetCertChain();
361     HcfX509CertificateArray certs = { nullptr, 0 };
362     CfResult res = certChain->getCertList(certChain, &certs);
363     if (res != CF_SUCCESS) {
364         LOGE("napi getCertList failed!");
365         napi_throw(env, CertGenerateBusinessError(env, res, "get cert list failed!"));
366         return nullptr;
367     }
368     napi_value instance = ConvertCertArrToNapiValue(env, &certs);
369     if (instance == nullptr) {
370         LOGE("convert arr to instance failed!");
371         napi_throw(env, CertGenerateBusinessError(env, res, "convert arr to instance failed!"));
372         FreeCertArrayData(&certs);
373         return nullptr;
374     }
375     CF_FREE_PTR(certs.data);
376     return instance;
377 }
378 
NapiValidate(napi_env env,napi_callback_info info)379 napi_value NapiValidate(napi_env env, napi_callback_info info)
380 {
381     napi_value thisVar = nullptr;
382     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
383     NapiX509CertChain *napiCertChainObj = nullptr;
384     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
385     if (napiCertChainObj == nullptr) {
386         LOGE("napi cert chain object is nullptr!");
387         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
388         return nullptr;
389     }
390     return napiCertChainObj->Validate(env, info);
391 }
392 
CertChainConstructor(napi_env env,napi_callback_info info)393 static napi_value CertChainConstructor(napi_env env, napi_callback_info info)
394 {
395     napi_value thisVar = nullptr;
396     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
397     return thisVar;
398 }
399 
DefineX509CertChainJsClass(napi_env env,napi_value exports)400 void NapiX509CertChain::DefineX509CertChainJsClass(napi_env env, napi_value exports)
401 {
402     napi_property_descriptor desc[] = {
403         DECLARE_NAPI_FUNCTION("createX509CertChain", NapiCreateX509CertChain),
404     };
405     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
406 
407     napi_property_descriptor CertChainDesc[] = {
408         DECLARE_NAPI_FUNCTION("getCertList", NapiGetCertList),
409         DECLARE_NAPI_FUNCTION("validate", NapiValidate),
410     };
411 
412     napi_value constructor = nullptr;
413     napi_define_class(env, "X509CertChain", NAPI_AUTO_LENGTH, CertChainConstructor, nullptr,
414         sizeof(CertChainDesc) / sizeof(CertChainDesc[0]), CertChainDesc, &constructor);
415     napi_create_reference(env, constructor, 1, &classRef_);
416 }
417 } // namespace CertFramework
418 } // namespace OHOS
419