• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_x509_cert_chain.h"
17 
18 #include "cert_crl_common.h"
19 #include "cf_api.h"
20 #include "cf_log.h"
21 #include "cf_memory.h"
22 #include "cf_param.h"
23 #include "cf_result.h"
24 #include "napi/native_api.h"
25 #include "napi/native_common.h"
26 #include "napi_cert_crl_common.h"
27 #include "napi_cert_defines.h"
28 #include "napi_cert_utils.h"
29 #include "napi_common.h"
30 #include "napi_object.h"
31 #include "napi_x509_cert_chain_validate_params.h"
32 #include "napi_x509_cert_chain_validate_result.h"
33 #include "napi_x509_cert_match_parameters.h"
34 #include "napi_x509_trust_anchor.h"
35 #include "securec.h"
36 #include "x509_cert_chain.h"
37 #include "x509_cert_chain_validate_params.h"
38 #include "x509_certificate.h"
39 
40 namespace OHOS {
41 namespace CertFramework {
42 thread_local napi_ref NapiX509CertChain::classRef_ = nullptr;
43 thread_local napi_ref NapiX509CertChainBulidResult::classRef_ = nullptr;
44 
45 struct CfCtx {
46     AsyncCtx async;
47     napi_ref cfRef = nullptr;
48     napi_ref certChainValidateParamsRef = nullptr;
49     NapiX509CertChain *certChainClass = nullptr;
50     HcfCertChain *certChain = nullptr;
51     CfEncodingBlob *encodingBlob = nullptr;
52     HcfX509CertChainValidateParams params;
53     HcfX509CertChainValidateResult result;
54     HcfX509CertChainBuildParameters *bulidParams = nullptr;
55     HcfX509CertChainBuildResult *buildResult = nullptr;
56     CfBlob *keyStore = nullptr;
57     CfBlob *pwd = nullptr;
58     HcfX509TrustAnchorArray *trustAnchorArray = nullptr;
59 };
60 
NapiX509CertChain(HcfCertChain * certChain)61 NapiX509CertChain::NapiX509CertChain(HcfCertChain *certChain)
62 {
63     this->certChain_ = certChain;
64 }
65 
~NapiX509CertChain()66 NapiX509CertChain::~NapiX509CertChain()
67 {
68     CfObjDestroy(this->certChain_);
69 }
70 
NapiX509CertChainBulidResult(HcfX509CertChainBuildResult * buildResult)71 NapiX509CertChainBulidResult::NapiX509CertChainBulidResult(HcfX509CertChainBuildResult *buildResult)
72 {
73     this->buildResult_ = buildResult;
74 }
75 
~NapiX509CertChainBulidResult()76 NapiX509CertChainBulidResult::~NapiX509CertChainBulidResult()
77 {
78     CfObjDestroy(this->buildResult_);
79 }
80 
BuildCertChainContext()81 static CfCtx *BuildCertChainContext()
82 {
83     CfCtx *context = static_cast<CfCtx *>(CfMalloc(sizeof(CfCtx), 0));
84     if (context == nullptr) {
85         LOGE("malloc cf ctx failed!");
86         return nullptr;
87     }
88     context->async = static_cast<AsyncCtx>(CfMalloc(sizeof(AsyncContext), 0));
89     if (context->async == nullptr) {
90         LOGE("malloc async ctx failed!");
91         CfFree(context);
92         return nullptr;
93     }
94     return context;
95 }
96 
DeleteCertChainContext(napi_env env,CfCtx * & context,bool freeCertFlag=false)97 static void DeleteCertChainContext(napi_env env, CfCtx *&context, bool freeCertFlag = false)
98 {
99     if (context == nullptr) {
100         return;
101     }
102 
103     FreeAsyncContext(env, context->async);
104 
105     if (context->cfRef != nullptr) {
106         napi_delete_reference(env, context->cfRef);
107         context->cfRef = nullptr;
108     }
109     if (context->certChainValidateParamsRef != nullptr) {
110         napi_delete_reference(env, context->certChainValidateParamsRef);
111         context->certChainValidateParamsRef = nullptr;
112     }
113 
114     if (context->encodingBlob != nullptr) {
115         CfEncodingBlobDataFree(context->encodingBlob);
116         CF_FREE_PTR(context->encodingBlob);
117     }
118 
119     FreeTrustAnchorArray(context->trustAnchorArray, freeCertFlag);
120     FreeX509CertChainValidateParams(context->params);
121     FreeX509CertChainValidateResult(context->result, freeCertFlag);
122 
123     CfBlobFree(&(context->keyStore));
124     CfBlobDataClearAndFree(context->pwd);
125     CfFree(context->pwd);
126 
127     CF_FREE_PTR(context);
128 }
129 
CreateCertChainJSInstance(napi_env env)130 static napi_value CreateCertChainJSInstance(napi_env env)
131 {
132     napi_value constructor = nullptr;
133     napi_value instance = nullptr;
134     napi_get_reference_value(env, NapiX509CertChain::classRef_, &constructor);
135     napi_new_instance(env, constructor, 0, nullptr, &instance);
136     return instance;
137 }
138 
CreateCallbackAndPromise(napi_env env,CfCtx * context,size_t argc,size_t maxCount,napi_value callbackValue)139 static bool CreateCallbackAndPromise(
140     napi_env env, CfCtx *context, size_t argc, size_t maxCount, napi_value callbackValue)
141 {
142     context->async->asyncType = GetAsyncType(env, argc, maxCount, callbackValue);
143     if (context->async->asyncType == ASYNC_TYPE_CALLBACK) {
144         if (!CertGetCallbackFromJSParams(env, callbackValue, &context->async->callback)) {
145             LOGE("x509 certificate: get callback failed!");
146             return false;
147         }
148     } else {
149         napi_create_promise(env, &context->async->deferred, &context->async->promise);
150     }
151     return true;
152 }
153 
CreateCertChainExecute(napi_env env,void * data)154 static void CreateCertChainExecute(napi_env env, void *data)
155 {
156     CfCtx *context = static_cast<CfCtx *>(data);
157     context->async->errCode = HcfCertChainCreate(context->encodingBlob, nullptr, &context->certChain);
158     if (context->async->errCode != CF_SUCCESS) {
159         context->async->errMsg = "create cert chain failed";
160     }
161 }
162 
BuildX509CertChainExecute(napi_env env,void * data)163 static void BuildX509CertChainExecute(napi_env env, void *data)
164 {
165     CfCtx *context = static_cast<CfCtx *>(data);
166     context->async->errCode = HcfCertChainBuildResultCreate(context->bulidParams, &context->buildResult);
167     if (context->async->errCode == CF_SUCCESS) {
168         HcfCertChain *certChain = context->buildResult->certChain;
169         context->async->errCode = certChain->validate(
170             certChain, &(context->bulidParams->validateParameters), &(context->buildResult->validateResult));
171     }
172 
173     if (context->async->errCode != CF_SUCCESS) {
174         context->async->errMsg = "create cert chain failed";
175     }
176 }
177 
BuildCreateInstance(napi_env env,HcfCertChain * certChain)178 static napi_value BuildCreateInstance(napi_env env, HcfCertChain *certChain)
179 {
180     napi_value instance = CreateCertChainJSInstance(env);
181     NapiX509CertChain *napiObject = new (std::nothrow) NapiX509CertChain(certChain);
182     if (napiObject == nullptr) {
183         LOGE("new napi object failed.");
184         return nullptr;
185     }
186     napi_wrap(
187         env, instance, napiObject,
188         [](napi_env env, void *data, void *hint) {
189             NapiX509CertChain *certchain = static_cast<NapiX509CertChain *>(data);
190             delete certchain;
191             return;
192         },
193         nullptr, nullptr);
194     return instance;
195 }
196 
CreateCertChainComplete(napi_env env,napi_status status,void * data)197 static void CreateCertChainComplete(napi_env env, napi_status status, void *data)
198 {
199     CfCtx *context = static_cast<CfCtx *>(data);
200     if (context->async->errCode != CF_SUCCESS) {
201         ReturnJSResult(env, context->async, nullptr);
202         DeleteCertChainContext(env, context, false);
203         return;
204     }
205 
206     napi_value instance = BuildCreateInstance(env, context->certChain);
207     if (instance == nullptr) {
208         context->async->errCode = CF_ERR_MALLOC;
209         context->async->errMsg = "Failed to create napi cert chain class";
210         LOGE("Failed to create napi cert chain class");
211         CfObjDestroy(context->certChain);
212         context->certChain = nullptr;
213     }
214     ReturnJSResult(env, context->async, instance);
215     DeleteCertChainContext(env, context);
216 }
217 
BuildCreateInstanceByBulidRlt(napi_env env,CfCtx * ctx)218 static napi_value BuildCreateInstanceByBulidRlt(napi_env env, CfCtx *ctx)
219 {
220     napi_value returnValue = nullptr;
221     napi_create_object(env, &returnValue);
222     if (ctx->buildResult != nullptr) {
223         napi_value insCertChain = BuildCreateInstance(env, ctx->buildResult->certChain);
224         if (insCertChain == nullptr) {
225             LOGE("Build cert chain instance failed!");
226             return nullptr;
227         }
228         napi_set_named_property(env, returnValue, CERT_CHAIN_BUILD_RESULLT_TAG_CERTCHAIN.c_str(), insCertChain);
229 
230         napi_value insValitateRes = BuildX509CertChainValidateResultJS(env, &(ctx->buildResult->validateResult));
231         if (insValitateRes == nullptr) {
232             LOGE("Build cert validate result failed!");
233             return nullptr;
234         }
235         napi_set_named_property(env, returnValue, CERT_CHAIN_BUILD_RESULLT_TAG_VALIDATERESULT.c_str(), insValitateRes);
236     }
237 
238     return returnValue;
239 }
240 
BuildX509CertChainComplete(napi_env env,napi_status status,void * data)241 static void BuildX509CertChainComplete(napi_env env, napi_status status, void *data)
242 {
243     CfCtx *context = static_cast<CfCtx *>(data);
244     if (context->async->errCode != CF_SUCCESS) {
245         ReturnJSResult(env, context->async, nullptr);
246         DeleteCertChainContext(env, context, false);
247         return;
248     }
249 
250     napi_value instance = BuildCreateInstanceByBulidRlt(env, context);
251     if (instance == nullptr) {
252         context->async->errCode = CF_ERR_MALLOC;
253         context->async->errMsg = "Failed to create napi cert chain class";
254         LOGE("Failed to create napi cert chain class");
255         CfObjDestroy(context->buildResult->certChain);
256         context->certChain = nullptr;
257     }
258     ReturnJSResult(env, context->async, instance);
259     DeleteCertChainContext(env, context);
260 }
261 
CreateCertChainAsyncWork(napi_env env,CfCtx * context)262 static napi_value CreateCertChainAsyncWork(napi_env env, CfCtx *context)
263 {
264     napi_create_async_work(env, nullptr, GetResourceName(env, "createX509CertChain"), CreateCertChainExecute,
265         CreateCertChainComplete, static_cast<void *>(context), &context->async->asyncWork);
266 
267     napi_queue_async_work(env, context->async->asyncWork);
268     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
269         return context->async->promise;
270     } else {
271         return NapiGetNull(env);
272     }
273 }
274 
CreateCertChainExtAsyncWork(napi_env env,CfCtx * context)275 static napi_value CreateCertChainExtAsyncWork(napi_env env, CfCtx *context)
276 {
277     napi_create_async_work(env, nullptr, GetResourceName(env, "buildX509CertChain"), BuildX509CertChainExecute,
278         BuildX509CertChainComplete, static_cast<void *>(context), &context->async->asyncWork);
279 
280     napi_queue_async_work(env, context->async->asyncWork);
281     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
282         return context->async->promise;
283     } else {
284         return NapiGetNull(env);
285     }
286 }
287 
ValidateExecute(napi_env env,void * data)288 static void ValidateExecute(napi_env env, void *data)
289 {
290     CfCtx *context = static_cast<CfCtx *>(data);
291     context->async->errCode = context->certChain->validate(context->certChain, &context->params, &context->result);
292     if (context->async->errCode != CF_SUCCESS) {
293         context->async->errMsg = "create cert chain failed";
294     }
295 }
296 
ValidateComplete(napi_env env,napi_status status,void * data)297 static void ValidateComplete(napi_env env, napi_status status, void *data)
298 {
299     CfCtx *context = static_cast<CfCtx *>(data);
300     if (context->async->errCode != CF_SUCCESS) {
301         ReturnJSResult(env, context->async, nullptr);
302         DeleteCertChainContext(env, context, false);
303         return;
304     }
305     napi_value instance = BuildX509CertChainValidateResultJS(env, &context->result);
306     if (instance == nullptr) {
307         LOGE("validate ret failed");
308         context->async->errCode = CF_ERR_MALLOC;
309         context->async->errMsg = "build return obj failed!";
310         ReturnJSResult(env, context->async, nullptr);
311         DeleteCertChainContext(env, context, true);
312         return;
313     }
314 
315     ReturnJSResult(env, context->async, instance);
316     DeleteCertChainContext(env, context);
317 }
318 
ValidateAsyncWork(napi_env env,CfCtx * context)319 static napi_value ValidateAsyncWork(napi_env env, CfCtx *context)
320 {
321     napi_create_async_work(env, nullptr, GetResourceName(env, "Validate"), ValidateExecute, ValidateComplete,
322         static_cast<void *>(context), &context->async->asyncWork);
323 
324     napi_queue_async_work(env, context->async->asyncWork);
325     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
326         return context->async->promise;
327     } else {
328         return NapiGetNull(env);
329     }
330 }
331 
Validate(napi_env env,napi_callback_info info)332 napi_value NapiX509CertChain::Validate(napi_env env, napi_callback_info info)
333 {
334     size_t argc = ARGS_SIZE_TWO;
335     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
336     napi_value thisVar = nullptr;
337     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
338     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
339         LOGE("check args count failed.");
340         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "check args count failed!"));
341         return nullptr;
342     }
343 
344     CfCtx *context = BuildCertChainContext();
345     if (context == nullptr) {
346         LOGE("malloc context failed.");
347         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc context failed!"));
348         return nullptr;
349     }
350 
351     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
352         DeleteCertChainContext(env, context);
353         LOGE("CreateCallbackAndPromise failed!");
354         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CreateCallbackAndPromise failed!"));
355         return nullptr;
356     }
357     context->certChainClass = this;
358     context->certChain = GetCertChain();
359     if (!BuildX509CertChainValidateParams(env, argv[PARAM0], context->params)) {
360         LOGE("BuildX509CertChainValidateParams failed!");
361         DeleteCertChainContext(env, context);
362         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "BuildX509CertChainValidateParams failed!"));
363         return nullptr;
364     }
365 
366     if (napi_create_reference(env, thisVar, 1, &context->cfRef) != napi_ok) {
367         LOGE("create reference failed!");
368         DeleteCertChainContext(env, context);
369         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create reference failed!"));
370         return nullptr;
371     }
372     if (napi_create_reference(env, argv[PARAM0], 1, &context->certChainValidateParamsRef) != napi_ok) {
373         LOGE("create param ref failed!");
374         DeleteCertChainContext(env, context);
375         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "create param ref failed!"));
376         return nullptr;
377     }
378 
379     return ValidateAsyncWork(env, context);
380 }
381 
ToString(napi_env env,napi_callback_info info)382 napi_value NapiX509CertChain::ToString(napi_env env, napi_callback_info info)
383 {
384     HcfCertChain *certChain = GetCertChain();
385     CfBlob blob = { 0, nullptr };
386     CfResult result = certChain->toString(certChain, &blob);
387     if (result != CF_SUCCESS) {
388         LOGE("toString failed!");
389         napi_throw(env, CertGenerateBusinessError(env, result, "toString failed"));
390         return nullptr;
391     }
392 
393     napi_value returnBlob = nullptr;
394     napi_create_string_utf8(env, reinterpret_cast<char *>(blob.data), blob.size, &returnBlob);
395     CfBlobDataFree(&blob);
396     return returnBlob;
397 }
398 
HashCode(napi_env env,napi_callback_info info)399 napi_value NapiX509CertChain::HashCode(napi_env env, napi_callback_info info)
400 {
401     HcfCertChain *certChain = GetCertChain();
402     CfBlob blob = { 0, nullptr };
403     CfResult result = certChain->hashCode(certChain, &blob);
404     if (result != CF_SUCCESS) {
405         LOGE("hashCode failed!");
406         napi_throw(env, CertGenerateBusinessError(env, result, "hashCode failed"));
407         return nullptr;
408     }
409     napi_value returnBlob = ConvertBlobToUint8ArrNapiValue(env, &blob);
410     CfBlobDataFree(&blob);
411     return returnBlob;
412 }
413 
CreateX509CertChainByArray(napi_env env,napi_value param)414 static napi_value CreateX509CertChainByArray(napi_env env, napi_value param)
415 {
416     HcfX509CertificateArray certs = { nullptr, 0 };
417     if (param != nullptr && !GetArrayCertFromNapiValue(env, param, &certs, false)) {
418         LOGE("get array cert from data failed!");
419         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert arr failed!"));
420         return nullptr;
421     }
422 
423     HcfCertChain *certChain = nullptr;
424     CfResult res = HcfCertChainCreate(nullptr, &certs, &certChain);
425     if (res != CF_SUCCESS) {
426         LOGE("HcfCertChainCreate failed!");
427         CF_FREE_PTR(certs.data);
428         napi_throw(env, CertGenerateBusinessError(env, res, "create cert chain by arr failed!"));
429         return nullptr;
430     }
431     napi_value instance = BuildCreateInstance(env, certChain);
432     if (instance == nullptr) {
433         LOGE("BuildCreateInstance failed!");
434         CfObjDestroy(certChain);
435         CF_FREE_PTR(certs.data);
436         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "build create instance failed!"));
437         return nullptr;
438     }
439     return instance;
440 }
441 
CreateX509CertChainByEncodingBlob(napi_env env,size_t argc,napi_value param1,napi_value param2)442 static napi_value CreateX509CertChainByEncodingBlob(napi_env env, size_t argc, napi_value param1, napi_value param2)
443 {
444     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
445         LOGE("CertCheckArgsCount failed");
446         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
447         return nullptr;
448     }
449     CfCtx *context = BuildCertChainContext();
450     if (context == nullptr) {
451         LOGE("context is nullptr");
452         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
453         return nullptr;
454     }
455 
456     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, param2)) {
457         LOGE("Create Callback Promise failed");
458         DeleteCertChainContext(env, context);
459         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create Callback Promise failed!"));
460         return nullptr;
461     }
462     if (!GetEncodingBlobFromValue(env, param1, &context->encodingBlob)) {
463         LOGE("Get Encoding Blob failed");
464         DeleteCertChainContext(env, context);
465         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Get Encoding Blob failed!"));
466         return nullptr;
467     }
468 
469     return CreateCertChainAsyncWork(env, context);
470 }
471 
NapiCreateX509CertChain(napi_env env,napi_callback_info info)472 napi_value NapiCreateX509CertChain(napi_env env, napi_callback_info info)
473 {
474     size_t argc = ARGS_SIZE_TWO;
475     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
476     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
477 
478     bool flag = false;
479     napi_is_array(env, argv[PARAM0], &flag);
480     napi_value instance = nullptr;
481     if (flag) {
482         if (argc != ARGS_SIZE_ONE) {
483             LOGE("arg size is not correct");
484             napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "arg size is not correct!"));
485             return nullptr;
486         }
487         LOGI("NapiCreateX509CertChain : Array<X509Cert>!");
488         instance = CreateX509CertChainByArray(env, argv[PARAM0]);
489     } else {
490         LOGI("NapiCreateX509CertChain : inStream: EncodingBlob!");
491         instance = CreateX509CertChainByEncodingBlob(env, argc, argv[PARAM0], argv[PARAM1]);
492     }
493     return instance;
494 }
495 
CreateTrustAnchorsWithKeyStoreExecute(napi_env env,void * data)496 static void CreateTrustAnchorsWithKeyStoreExecute(napi_env env, void *data)
497 {
498     CfCtx *context = static_cast<CfCtx *>(data);
499     if (context == nullptr) {
500         LOGE("context is nullptr");
501         return;
502     }
503     context->async->errCode =
504         HcfCreateTrustAnchorWithKeyStore(context->keyStore, context->pwd, &context->trustAnchorArray);
505     if (context->async->errCode != CF_SUCCESS) {
506         context->async->errMsg = "Failed to create trust anchor from p12!";
507     }
508 }
509 
ConvertX509CertToNapiValue(napi_env env,HcfX509Certificate * cert)510 static napi_value ConvertX509CertToNapiValue(napi_env env, HcfX509Certificate *cert)
511 {
512     if (cert == nullptr) {
513         LOGE("ConvertX509CertToNapiValue:cert is nullptr.");
514         return nullptr;
515     }
516     CfObject *certObj = nullptr;
517     CfResult res = GetCertObject(cert, &certObj);
518     if (res != CF_SUCCESS) {
519         LOGE("GetCertObject failed.");
520         return nullptr;
521     }
522     NapiX509Certificate *x509Cert = new (std::nothrow) NapiX509Certificate(cert, certObj);
523     if (x509Cert == nullptr) {
524         LOGE("new x509Cert failed!");
525         certObj->destroy(&certObj);
526         return nullptr;
527     }
528     napi_value instance = NapiX509Certificate::CreateX509Cert(env);
529     napi_status status = napi_wrap(
530         env, instance, x509Cert,
531         [](napi_env env, void *data, void *hint) {
532             NapiX509Certificate *certClass = static_cast<NapiX509Certificate *>(data);
533             delete certClass;
534             return;
535         },
536         nullptr, nullptr);
537     if (status != napi_ok) {
538         LOGE("Failed to wrap x509Cert obj!");
539         delete x509Cert;
540         return nullptr;
541     }
542 
543     return instance;
544 }
545 
ConvertBlobToUint8ArrayNapiValue(napi_env env,CfBlob * blob)546 static napi_value ConvertBlobToUint8ArrayNapiValue(napi_env env, CfBlob *blob)
547 {
548     if (blob == NULL) {
549         LOGE("ConvertCfBlobToNapiValue:blob is nullptr.");
550         return nullptr;
551     }
552     uint8_t *buffer = static_cast<uint8_t *>(CfMalloc(blob->size, 0));
553     if (buffer == nullptr) {
554         LOGE("malloc uint8 array buffer failed!");
555         return nullptr;
556     }
557 
558     if (memcpy_s(buffer, blob->size, blob->data, blob->size) != EOK) {
559         LOGE("memcpy_s data to buffer failed!");
560         CfFree(buffer);
561         return nullptr;
562     }
563 
564     napi_value outBuffer = nullptr;
565     napi_status status = napi_create_external_arraybuffer(
566         env, buffer, blob->size, [](napi_env env, void *data, void *hint) { CfFree(data); }, nullptr, &outBuffer);
567     if (status != napi_ok) {
568         LOGE("create uint8 array buffer failed!");
569         CfFree(buffer);
570         return nullptr;
571     }
572     buffer = nullptr;
573 
574     napi_value outData = nullptr;
575     napi_create_typedarray(env, napi_uint8_array, blob->size, outBuffer, 0, &outData);
576     return outData;
577 }
578 
BuildCreateInstanceByTrustAnchorArray(napi_env env,HcfX509TrustAnchorArray * trustAnchorArray)579 static napi_value BuildCreateInstanceByTrustAnchorArray(napi_env env, HcfX509TrustAnchorArray *trustAnchorArray)
580 {
581     if (trustAnchorArray == nullptr) {
582         LOGE("Input data is null!");
583         return nullptr;
584     }
585     napi_value instance;
586     napi_create_array(env, &instance);
587     if (instance == nullptr) {
588         LOGE("Create return instance failed!");
589         return nullptr;
590     }
591     int elementIdx = 0;
592     for (uint32_t i = 0; i < trustAnchorArray->count; ++i) {
593         napi_value element = NapiX509Certificate::CreateX509Cert(env);
594         if (instance == nullptr) {
595             LOGE("Create x509Cert failed!");
596             return nullptr;
597         }
598         napi_value valueCACert = ConvertX509CertToNapiValue(env, trustAnchorArray->data[i]->CACert);
599         if (valueCACert == nullptr) {
600             LOGI("The CACert value is null, return to js is an enpty object!");
601         } else {
602             trustAnchorArray->data[i]->CACert = nullptr;
603         }
604         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CACERT.c_str(), valueCACert);
605 
606         napi_value valuePubKey = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->CAPubKey);
607         if (valuePubKey == nullptr) {
608             LOGI("The PubKey value is null, return to js is an enpty object!");
609         }
610         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CAPUBKEY.c_str(), valuePubKey);
611 
612         napi_value valueSub = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->CASubject);
613         if (valueSub == nullptr) {
614             LOGI("The CASubject value is null, return to js is an enpty object!");
615         }
616         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CASUBJECT.c_str(), valueSub);
617 
618         napi_value valueName = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->nameConstraints);
619         if (valueName == nullptr) {
620             LOGI("The nameConsteaints value is null, return to js is an enpty object!");
621         }
622         napi_set_named_property(env, element, CERT_MATCH_TAG_NAME_CONSTRAINTS.c_str(), valueName);
623 
624         if (element != nullptr) {
625             napi_set_element(env, instance, elementIdx++, element);
626         }
627     }
628     return instance;
629 }
630 
CreateTrustAnchorsWithKeyStoreComplete(napi_env env,napi_status status,void * data)631 static void CreateTrustAnchorsWithKeyStoreComplete(napi_env env, napi_status status, void *data)
632 {
633     CfCtx *context = static_cast<CfCtx *>(data);
634     if (context->async->errCode != CF_SUCCESS) {
635         ReturnJSResult(env, context->async, nullptr);
636         DeleteCertChainContext(env, context, false);
637         return;
638     }
639     napi_value instance = BuildCreateInstanceByTrustAnchorArray(env, context->trustAnchorArray);
640     if (instance == nullptr) {
641         context->async->errCode = CF_ERR_MALLOC;
642         context->async->errMsg = "Failed to create trust anchor with KeyStore";
643         LOGE("Failed to create trust anchor with KeyStore");
644     }
645     ReturnJSResult(env, context->async, instance);
646     DeleteCertChainContext(env, context, true);
647 }
648 
CreateTrustAnchorsWithKeyStoreAsyncWork(napi_env env,CfCtx * context)649 static napi_value CreateTrustAnchorsWithKeyStoreAsyncWork(napi_env env, CfCtx *context)
650 {
651     napi_create_async_work(env, nullptr, GetResourceName(env, "createTrustAnchorsWithKeyStore"),
652         CreateTrustAnchorsWithKeyStoreExecute, CreateTrustAnchorsWithKeyStoreComplete, static_cast<void *>(context),
653         &context->async->asyncWork);
654 
655     napi_queue_async_work(env, context->async->asyncWork);
656     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
657         return context->async->promise;
658     } else {
659         return NapiGetNull(env);
660     }
661 }
662 
CreateTrustAnchorsWithKeyStore(napi_env env,size_t argc,napi_value param1,napi_value param2)663 static napi_value CreateTrustAnchorsWithKeyStore(napi_env env, size_t argc, napi_value param1, napi_value param2)
664 {
665     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
666         LOGE("CertCheckArgsCount failed");
667         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
668         return nullptr;
669     }
670     CfCtx *context = BuildCertChainContext();
671     if (context == nullptr) {
672         LOGE("context is nullptr");
673         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
674         return nullptr;
675     }
676 
677     context->async->asyncType = GetAsyncType(env, argc, ARGS_SIZE_TWO, nullptr);
678     if (context->async->asyncType == ASYNC_TYPE_CALLBACK) {
679         LOGE("ASYNC_TYPE_CALLBACK is not supported.");
680         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "ASYNC_TYPE_CALLBACK is not supported."));
681         DeleteCertChainContext(env, context);
682         return nullptr;
683     }
684     napi_create_promise(env, &context->async->deferred, &context->async->promise);
685 
686     context->keyStore = CertGetBlobFromUint8ArrJSParams(env, param1);
687     if (context->keyStore == nullptr) {
688         DeleteCertChainContext(env, context);
689         return nullptr;
690     }
691     context->pwd = CertGetBlobFromStringJSParams(env, param2);
692     if (context->pwd == nullptr) {
693         DeleteCertChainContext(env, context);
694         return nullptr;
695     }
696 
697     return CreateTrustAnchorsWithKeyStoreAsyncWork(env, context);
698 }
699 
NapiCreateTrustAnchorsWithKeyStore(napi_env env,napi_callback_info info)700 napi_value NapiCreateTrustAnchorsWithKeyStore(napi_env env, napi_callback_info info)
701 {
702     size_t argc = ARGS_SIZE_TWO;
703     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
704     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
705     napi_value instance = CreateTrustAnchorsWithKeyStore(env, argc, argv[PARAM0], argv[PARAM1]);
706     return instance;
707 }
708 
GetCertMatchParameters(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)709 bool GetCertMatchParameters(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
710 {
711     napi_value data = nullptr;
712     napi_status status = napi_get_named_property(env, obj, CERT_TAG_CERT_MATCH_PARAMS.c_str(), &data);
713     if (status != napi_ok) {
714         LOGE("failed to get cert match params!");
715         return false;
716     }
717     HcfX509CertMatchParams *param = &((*bulidParams)->certMatchParameters);
718     if (!BuildX509CertMatchParams(env, data, param)) {
719         LOGE("BuildX509CertMatchParams failed!");
720         return false;
721     }
722     return true;
723 }
724 
GetMaxlength(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)725 bool GetMaxlength(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
726 {
727     napi_value data = nullptr;
728     napi_status status = napi_get_named_property(env, obj, CERT_TAG_MAX_LENGTH.c_str(), &data);
729     if (status != napi_ok) {
730         LOGE("failed to get max length!");
731         return false;
732     }
733     napi_valuetype valueType;
734     napi_typeof(env, data, &valueType);
735     if ((valueType != napi_number) && (valueType != napi_undefined) && (valueType != napi_null)) {
736         LOGE("%s valueType is null or undefined.", CERT_TAG_MAX_LENGTH.c_str());
737         return false;
738     }
739     napi_get_value_uint32(env, data, reinterpret_cast<uint32_t *>(&((*bulidParams)->maxlength)));
740     return true;
741 }
742 
GetValidateParameters(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)743 bool GetValidateParameters(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
744 {
745     napi_value data = nullptr;
746     napi_status status = napi_get_named_property(env, obj, CERT_TAG_VALIDATE_PARAMS.c_str(), &data);
747     if (status != napi_ok) {
748         LOGE("failed to get cert validate params!");
749         return false;
750     }
751     if (!BuildX509CertChainValidateParams(env, data, (*bulidParams)->validateParameters)) {
752         LOGE("BuildX509CertChainValidateParams failed!");
753         return false;
754     }
755     return true;
756 }
757 
GetChainBuildParametersFromValue(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)758 bool GetChainBuildParametersFromValue(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
759 {
760     HcfX509CertChainBuildParameters *buildParam =
761         static_cast<HcfX509CertChainBuildParameters *>(CfMalloc(sizeof(HcfX509CertChainBuildParameters), 0));
762     if (buildParam == nullptr) {
763         LOGE("malloc cert chain build parameters failed!");
764         return false;
765     }
766     buildParam->maxlength = -1;
767 
768     if (!GetCertMatchParameters(env, obj, &buildParam)) {
769         LOGE("failed to get cert match parameters!");
770         CfFree(buildParam);
771         return false;
772     }
773     if (!GetMaxlength(env, obj, &buildParam)) {
774         LOGE("failed to get max length!");
775         CfFree(buildParam);
776         return false;
777     }
778     if (!GetValidateParameters(env, obj, &buildParam)) {
779         LOGE("failed to get validate parameters!");
780         CfFree(buildParam);
781         return false;
782     }
783 
784     *bulidParams = buildParam;
785     return true;
786 }
787 
CreateX509CertChainExtReturn(napi_env env,size_t argc,napi_value param)788 static napi_value CreateX509CertChainExtReturn(napi_env env, size_t argc, napi_value param)
789 {
790     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
791         LOGE("CertCheckArgsCount failed");
792         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
793         return nullptr;
794     }
795     CfCtx *context = BuildCertChainContext();
796     if (context == nullptr) {
797         LOGE("context is nullptr");
798         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
799         return nullptr;
800     }
801 
802     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_ONE, nullptr)) {
803         LOGE("Create Callback Promise failed");
804         DeleteCertChainContext(env, context);
805         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create Callback Promise failed!"));
806         return nullptr;
807     }
808     if (napi_create_reference(env, param, 1, &context->async->paramRef) != napi_ok) {
809         LOGE("create param ref failed!");
810         DeleteCertChainContext(env, context);
811         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create param ref failed"));
812         return nullptr;
813     }
814     if (!GetChainBuildParametersFromValue(env, param, &context->bulidParams)) {
815         LOGE("Get Cert Chain Build Parameters failed!");
816         DeleteCertChainContext(env, context);
817         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Get Cert Chain Build Parameters failed!"));
818         return nullptr;
819     }
820 
821     return CreateCertChainExtAsyncWork(env, context);
822 }
823 
NapiBuildX509CertChain(napi_env env,napi_callback_info info)824 napi_value NapiBuildX509CertChain(napi_env env, napi_callback_info info)
825 {
826     size_t argc = ARGS_SIZE_ONE;
827     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
828     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
829 
830     napi_value instance = nullptr;
831     instance = CreateX509CertChainExtReturn(env, argc, argv[PARAM0]);
832     return instance;
833 }
834 
NapiGetCertList(napi_env env,napi_callback_info info)835 napi_value NapiGetCertList(napi_env env, napi_callback_info info)
836 {
837     napi_value thisVar = nullptr;
838     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
839     NapiX509CertChain *napiCertChainObj = nullptr;
840     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
841     if (napiCertChainObj == nullptr) {
842         LOGE("napi cert chain object is nullptr!");
843         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
844         return nullptr;
845     }
846     HcfCertChain *certChain = napiCertChainObj->GetCertChain();
847     HcfX509CertificateArray certs = { nullptr, 0 };
848     CfResult res = certChain->getCertList(certChain, &certs);
849     if (res != CF_SUCCESS) {
850         LOGE("napi getCertList failed!");
851         napi_throw(env, CertGenerateBusinessError(env, res, "get cert list failed!"));
852         return nullptr;
853     }
854     napi_value instance = ConvertCertArrToNapiValue(env, &certs);
855     if (instance == nullptr) {
856         LOGE("convert arr to instance failed!");
857         FreeCertArrayData(&certs);
858         napi_throw(env, CertGenerateBusinessError(env, res, "convert arr to instance failed!"));
859         return nullptr;
860     }
861     CF_FREE_PTR(certs.data);
862     return instance;
863 }
864 
NapiValidate(napi_env env,napi_callback_info info)865 napi_value NapiValidate(napi_env env, napi_callback_info info)
866 {
867     napi_value thisVar = nullptr;
868     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
869     NapiX509CertChain *napiCertChainObj = nullptr;
870     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
871     if (napiCertChainObj == nullptr) {
872         LOGE("napi cert chain object is nullptr!");
873         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
874         return nullptr;
875     }
876     return napiCertChainObj->Validate(env, info);
877 }
878 
NapiToString(napi_env env,napi_callback_info info)879 napi_value NapiToString(napi_env env, napi_callback_info info)
880 {
881     napi_value thisVar = nullptr;
882     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
883     NapiX509CertChain *napiCertChainObj = nullptr;
884     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
885     if (napiCertChainObj == nullptr) {
886         LOGE("napi cert chain object is nullptr!");
887         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
888         return nullptr;
889     }
890     return napiCertChainObj->ToString(env, info);
891 }
892 
NapiHashCode(napi_env env,napi_callback_info info)893 napi_value NapiHashCode(napi_env env, napi_callback_info info)
894 {
895     napi_value thisVar = nullptr;
896     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
897     NapiX509CertChain *napiCertChainObj = nullptr;
898     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
899     if (napiCertChainObj == nullptr) {
900         LOGE("napi cert chain object is nullptr!");
901         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
902         return nullptr;
903     }
904     return napiCertChainObj->HashCode(env, info);
905 }
906 
CertChainConstructor(napi_env env,napi_callback_info info)907 static napi_value CertChainConstructor(napi_env env, napi_callback_info info)
908 {
909     napi_value thisVar = nullptr;
910     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
911     return thisVar;
912 }
913 
Constructor(napi_env env,napi_callback_info info)914 napi_value NapiX509CertChain::Constructor(napi_env env, napi_callback_info info)
915 {
916     return CertChainConstructor(env, info);
917 }
918 
ConvertToJsCertChain(napi_env env)919 napi_value NapiX509CertChain::ConvertToJsCertChain(napi_env env)
920 {
921     napi_value instance;
922     napi_value constructor = nullptr;
923     napi_get_reference_value(env, classRef_, &constructor);
924     napi_new_instance(env, constructor, 0, nullptr, &instance);
925 
926     return instance;
927 }
928 
Constructor(napi_env env,napi_callback_info info)929 napi_value NapiX509CertChainBulidResult::Constructor(napi_env env, napi_callback_info info)
930 {
931     return CertChainConstructor(env, info);
932 }
933 
ConvertToJsBuildResult(napi_env env)934 napi_value NapiX509CertChainBulidResult::ConvertToJsBuildResult(napi_env env)
935 {
936     napi_value instance;
937     napi_value constructor = nullptr;
938     napi_get_reference_value(env, classRef_, &constructor);
939     napi_new_instance(env, constructor, 0, nullptr, &instance);
940 
941     if (this->buildResult_ != nullptr && this->buildResult_->certChain != nullptr) {
942         NapiX509CertChain *napiObject = new (std::nothrow) NapiX509CertChain(this->buildResult_->certChain);
943         if (napiObject == nullptr) {
944             LOGE("new napi object failed.");
945             return nullptr;
946         }
947         napi_value certChain = napiObject->ConvertToJsCertChain(env);
948         napi_status status = napi_wrap(
949             env, certChain, napiObject,
950             [](napi_env env, void *data, void *hint) {
951                 NapiX509CertChain *napiObject = static_cast<NapiX509CertChain *>(data);
952                 delete napiObject;
953                 return;
954             },
955             nullptr, nullptr);
956         if (status != napi_ok) {
957             LOGE("failed to wrap certChain obj!");
958             delete napiObject;
959             return nullptr;
960         }
961         napi_set_named_property(env, instance, "certChain", certChain);
962     }
963 
964     if (this->buildResult_ != nullptr) {
965         napi_value validateResult = BuildX509CertChainValidateResultJS(env, &(this->buildResult_->validateResult));
966         napi_set_named_property(env, instance, "validateResult", validateResult);
967     }
968     return instance;
969 }
970 
DefineX509CertChainJsClass(napi_env env,napi_value exports)971 void NapiX509CertChain::DefineX509CertChainJsClass(napi_env env, napi_value exports)
972 {
973     napi_property_descriptor desc[] = {
974         DECLARE_NAPI_FUNCTION("createX509CertChain", NapiCreateX509CertChain),
975         DECLARE_NAPI_FUNCTION("createTrustAnchorsWithKeyStore", NapiCreateTrustAnchorsWithKeyStore),
976     };
977     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
978 
979     napi_property_descriptor CertChainDesc[] = {
980         DECLARE_NAPI_FUNCTION("getCertList", NapiGetCertList),
981         DECLARE_NAPI_FUNCTION("validate", NapiValidate),
982         DECLARE_NAPI_FUNCTION("toString", NapiToString),
983         DECLARE_NAPI_FUNCTION("hashCode", NapiHashCode),
984     };
985 
986     napi_value constructor = nullptr;
987     napi_define_class(env, "X509CertChain", NAPI_AUTO_LENGTH, CertChainConstructor, nullptr,
988         sizeof(CertChainDesc) / sizeof(CertChainDesc[0]), CertChainDesc, &constructor);
989     napi_create_reference(env, constructor, 1, &classRef_);
990 }
991 
DefineX509CertChainBuildResultJsClass(napi_env env,napi_value exports)992 void NapiX509CertChainBulidResult::DefineX509CertChainBuildResultJsClass(napi_env env, napi_value exports)
993 {
994     napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("buildX509CertChain", NapiBuildX509CertChain) };
995     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
996 
997     napi_property_descriptor CertChainBuildResultDesc[] = {};
998     napi_value constructor = nullptr;
999     napi_define_class(env, "CertChainBuildResult", NAPI_AUTO_LENGTH, NapiX509CertChainBulidResult::Constructor, nullptr,
1000         sizeof(CertChainBuildResultDesc) / sizeof(CertChainBuildResultDesc[0]), CertChainBuildResultDesc, &constructor);
1001     napi_create_reference(env, constructor, 1, &classRef_);
1002 }
1003 } // namespace CertFramework
1004 } // namespace OHOS
1005