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         DeleteCertChainContext(env, context, true);
258     }
259     ReturnJSResult(env, context->async, instance);
260     DeleteCertChainContext(env, context);
261 }
262 
CreateCertChainAsyncWork(napi_env env,CfCtx * context)263 static napi_value CreateCertChainAsyncWork(napi_env env, CfCtx *context)
264 {
265     napi_create_async_work(env, nullptr, GetResourceName(env, "createX509CertChain"), CreateCertChainExecute,
266         CreateCertChainComplete, static_cast<void *>(context), &context->async->asyncWork);
267 
268     napi_queue_async_work(env, context->async->asyncWork);
269     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
270         return context->async->promise;
271     } else {
272         return NapiGetNull(env);
273     }
274 }
275 
CreateCertChainExtAsyncWork(napi_env env,CfCtx * context)276 static napi_value CreateCertChainExtAsyncWork(napi_env env, CfCtx *context)
277 {
278     napi_create_async_work(env, nullptr, GetResourceName(env, "buildX509CertChain"), BuildX509CertChainExecute,
279         BuildX509CertChainComplete, static_cast<void *>(context), &context->async->asyncWork);
280 
281     napi_queue_async_work(env, context->async->asyncWork);
282     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
283         return context->async->promise;
284     } else {
285         return NapiGetNull(env);
286     }
287 }
288 
ValidateExecute(napi_env env,void * data)289 static void ValidateExecute(napi_env env, void *data)
290 {
291     CfCtx *context = static_cast<CfCtx *>(data);
292     context->async->errCode = context->certChain->validate(context->certChain, &context->params, &context->result);
293     if (context->async->errCode != CF_SUCCESS) {
294         context->async->errMsg = "create cert chain failed";
295     }
296 }
297 
ValidateComplete(napi_env env,napi_status status,void * data)298 static void ValidateComplete(napi_env env, napi_status status, void *data)
299 {
300     CfCtx *context = static_cast<CfCtx *>(data);
301     if (context->async->errCode != CF_SUCCESS) {
302         ReturnJSResult(env, context->async, nullptr);
303         DeleteCertChainContext(env, context, false);
304         return;
305     }
306     napi_value instance = BuildX509CertChainValidateResultJS(env, &context->result);
307     if (instance == nullptr) {
308         LOGE("validate ret failed");
309         context->async->errCode = CF_ERR_MALLOC;
310         context->async->errMsg = "build return obj failed!";
311         ReturnJSResult(env, context->async, nullptr);
312         DeleteCertChainContext(env, context, true);
313         return;
314     }
315 
316     ReturnJSResult(env, context->async, instance);
317     DeleteCertChainContext(env, context);
318 }
319 
ValidateAsyncWork(napi_env env,CfCtx * context)320 static napi_value ValidateAsyncWork(napi_env env, CfCtx *context)
321 {
322     napi_create_async_work(env, nullptr, GetResourceName(env, "Validate"), ValidateExecute, ValidateComplete,
323         static_cast<void *>(context), &context->async->asyncWork);
324 
325     napi_queue_async_work(env, context->async->asyncWork);
326     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
327         return context->async->promise;
328     } else {
329         return NapiGetNull(env);
330     }
331 }
332 
Validate(napi_env env,napi_callback_info info)333 napi_value NapiX509CertChain::Validate(napi_env env, napi_callback_info info)
334 {
335     size_t argc = ARGS_SIZE_TWO;
336     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
337     napi_value thisVar = nullptr;
338     napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
339     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
340         LOGE("check args count failed.");
341         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "check args count failed!"));
342         return nullptr;
343     }
344 
345     CfCtx *context = BuildCertChainContext();
346     if (context == nullptr) {
347         LOGE("malloc context failed.");
348         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc context failed!"));
349         return nullptr;
350     }
351 
352     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, argv[PARAM1])) {
353         DeleteCertChainContext(env, context);
354         LOGE("CreateCallbackAndPromise failed!");
355         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CreateCallbackAndPromise failed!"));
356         return nullptr;
357     }
358     context->certChainClass = this;
359     context->certChain = GetCertChain();
360     if (!BuildX509CertChainValidateParams(env, argv[PARAM0], context->params)) {
361         LOGE("BuildX509CertChainValidateParams failed!");
362         DeleteCertChainContext(env, context);
363         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "BuildX509CertChainValidateParams failed!"));
364         return nullptr;
365     }
366 
367     if (napi_create_reference(env, thisVar, 1, &context->cfRef) != napi_ok) {
368         LOGE("create reference failed!");
369         DeleteCertChainContext(env, context);
370         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create reference failed!"));
371         return nullptr;
372     }
373     if (napi_create_reference(env, argv[PARAM0], 1, &context->certChainValidateParamsRef) != napi_ok) {
374         LOGE("create param ref failed!");
375         DeleteCertChainContext(env, context);
376         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "create param ref failed!"));
377         return nullptr;
378     }
379 
380     return ValidateAsyncWork(env, context);
381 }
382 
ToString(napi_env env,napi_callback_info info)383 napi_value NapiX509CertChain::ToString(napi_env env, napi_callback_info info)
384 {
385     HcfCertChain *certChain = GetCertChain();
386     CfBlob blob = { 0, nullptr };
387     CfResult result = certChain->toString(certChain, &blob);
388     if (result != CF_SUCCESS) {
389         LOGE("toString failed!");
390         napi_throw(env, CertGenerateBusinessError(env, result, "toString failed"));
391         return nullptr;
392     }
393 
394     napi_value returnBlob = nullptr;
395     napi_create_string_utf8(env, reinterpret_cast<char *>(blob.data), blob.size, &returnBlob);
396     CfBlobDataFree(&blob);
397     return returnBlob;
398 }
399 
HashCode(napi_env env,napi_callback_info info)400 napi_value NapiX509CertChain::HashCode(napi_env env, napi_callback_info info)
401 {
402     HcfCertChain *certChain = GetCertChain();
403     CfBlob blob = { 0, nullptr };
404     CfResult result = certChain->hashCode(certChain, &blob);
405     if (result != CF_SUCCESS) {
406         LOGE("hashCode failed!");
407         napi_throw(env, CertGenerateBusinessError(env, result, "hashCode failed"));
408         return nullptr;
409     }
410     napi_value returnBlob = ConvertBlobToUint8ArrNapiValue(env, &blob);
411     CfBlobDataFree(&blob);
412     return returnBlob;
413 }
414 
CreateX509CertChainByArray(napi_env env,napi_value param)415 static napi_value CreateX509CertChainByArray(napi_env env, napi_value param)
416 {
417     HcfX509CertificateArray certs = { nullptr, 0 };
418     if (param != nullptr && !GetArrayCertFromNapiValue(env, param, &certs, false)) {
419         LOGE("get array cert from data failed!");
420         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert arr failed!"));
421         return nullptr;
422     }
423 
424     HcfCertChain *certChain = nullptr;
425     CfResult res = HcfCertChainCreate(nullptr, &certs, &certChain);
426     if (res != CF_SUCCESS) {
427         LOGE("HcfCertChainCreate failed!");
428         CF_FREE_PTR(certs.data);
429         napi_throw(env, CertGenerateBusinessError(env, res, "create cert chain by arr failed!"));
430         return nullptr;
431     }
432     napi_value instance = BuildCreateInstance(env, certChain);
433     if (instance == nullptr) {
434         LOGE("BuildCreateInstance failed!");
435         CfObjDestroy(certChain);
436         CF_FREE_PTR(certs.data);
437         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "build create instance failed!"));
438         return nullptr;
439     }
440     return instance;
441 }
442 
CreateX509CertChainByEncodingBlob(napi_env env,size_t argc,napi_value param1,napi_value param2)443 static napi_value CreateX509CertChainByEncodingBlob(napi_env env, size_t argc, napi_value param1, napi_value param2)
444 {
445     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
446         LOGE("CertCheckArgsCount failed");
447         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
448         return nullptr;
449     }
450     CfCtx *context = BuildCertChainContext();
451     if (context == nullptr) {
452         LOGE("context is nullptr");
453         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
454         return nullptr;
455     }
456 
457     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_TWO, param2)) {
458         LOGE("Create Callback Promise failed");
459         DeleteCertChainContext(env, context);
460         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create Callback Promise failed!"));
461         return nullptr;
462     }
463     if (!GetEncodingBlobFromValue(env, param1, &context->encodingBlob)) {
464         LOGE("Get Encoding Blob failed");
465         DeleteCertChainContext(env, context);
466         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Get Encoding Blob failed!"));
467         return nullptr;
468     }
469 
470     return CreateCertChainAsyncWork(env, context);
471 }
472 
NapiCreateX509CertChain(napi_env env,napi_callback_info info)473 napi_value NapiCreateX509CertChain(napi_env env, napi_callback_info info)
474 {
475     size_t argc = ARGS_SIZE_TWO;
476     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
477     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
478 
479     bool flag = false;
480     napi_is_array(env, argv[PARAM0], &flag);
481     napi_value instance = nullptr;
482     if (flag) {
483         if (argc != ARGS_SIZE_ONE) {
484             LOGE("arg size is not correct");
485             napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "arg size is not correct!"));
486             return nullptr;
487         }
488         LOGI("NapiCreateX509CertChain : Array<X509Cert>!");
489         instance = CreateX509CertChainByArray(env, argv[PARAM0]);
490     } else {
491         LOGI("NapiCreateX509CertChain : inStream: EncodingBlob!");
492         instance = CreateX509CertChainByEncodingBlob(env, argc, argv[PARAM0], argv[PARAM1]);
493     }
494     return instance;
495 }
496 
CreateTrustAnchorsWithKeyStoreExecute(napi_env env,void * data)497 static void CreateTrustAnchorsWithKeyStoreExecute(napi_env env, void *data)
498 {
499     CfCtx *context = static_cast<CfCtx *>(data);
500     if (context == nullptr) {
501         LOGE("context is nullptr");
502         return;
503     }
504     context->async->errCode =
505         HcfCreateTrustAnchorWithKeyStore(context->keyStore, context->pwd, &context->trustAnchorArray);
506     if (context->async->errCode != CF_SUCCESS) {
507         context->async->errMsg = "Failed to create trust anchor from p12!";
508     }
509 }
510 
ConvertX509CertToNapiValue(napi_env env,HcfX509Certificate * cert)511 static napi_value ConvertX509CertToNapiValue(napi_env env, HcfX509Certificate *cert)
512 {
513     if (cert == nullptr) {
514         LOGE("ConvertX509CertToNapiValue:cert is nullptr.");
515         return nullptr;
516     }
517     CfObject *certObj = nullptr;
518     CfResult res = GetCertObject(cert, &certObj);
519     if (res != CF_SUCCESS) {
520         LOGE("GetCertObject failed.");
521         return nullptr;
522     }
523     NapiX509Certificate *x509Cert = new (std::nothrow) NapiX509Certificate(cert, certObj);
524     if (x509Cert == nullptr) {
525         LOGE("new x509Cert failed!");
526         certObj->destroy(&certObj);
527         return nullptr;
528     }
529     napi_value instance = NapiX509Certificate::CreateX509Cert(env);
530     napi_status status = napi_wrap(
531         env, instance, x509Cert,
532         [](napi_env env, void *data, void *hint) {
533             NapiX509Certificate *certClass = static_cast<NapiX509Certificate *>(data);
534             delete certClass;
535             return;
536         },
537         nullptr, nullptr);
538     if (status != napi_ok) {
539         LOGE("Failed to wrap x509Cert obj!");
540         delete x509Cert;
541         return nullptr;
542     }
543 
544     return instance;
545 }
546 
ConvertBlobToUint8ArrayNapiValue(napi_env env,CfBlob * blob)547 static napi_value ConvertBlobToUint8ArrayNapiValue(napi_env env, CfBlob *blob)
548 {
549     if (blob == NULL) {
550         LOGE("ConvertCfBlobToNapiValue:blob is nullptr.");
551         return nullptr;
552     }
553     uint8_t *buffer = static_cast<uint8_t *>(CfMalloc(blob->size, 0));
554     if (buffer == nullptr) {
555         LOGE("malloc uint8 array buffer failed!");
556         return nullptr;
557     }
558 
559     if (memcpy_s(buffer, blob->size, blob->data, blob->size) != EOK) {
560         LOGE("memcpy_s data to buffer failed!");
561         CfFree(buffer);
562         return nullptr;
563     }
564 
565     napi_value outBuffer = nullptr;
566     napi_status status = napi_create_external_arraybuffer(
567         env, buffer, blob->size, [](napi_env env, void *data, void *hint) { CfFree(data); }, nullptr, &outBuffer);
568     if (status != napi_ok) {
569         LOGE("create uint8 array buffer failed!");
570         CfFree(buffer);
571         return nullptr;
572     }
573     buffer = nullptr;
574 
575     napi_value outData = nullptr;
576     napi_create_typedarray(env, napi_uint8_array, blob->size, outBuffer, 0, &outData);
577     return outData;
578 }
579 
BuildCreateInstanceByTrustAnchorArray(napi_env env,HcfX509TrustAnchorArray * trustAnchorArray)580 static napi_value BuildCreateInstanceByTrustAnchorArray(napi_env env, HcfX509TrustAnchorArray *trustAnchorArray)
581 {
582     if (trustAnchorArray == nullptr) {
583         LOGE("Input data is null!");
584         return nullptr;
585     }
586     napi_value instance;
587     napi_create_array(env, &instance);
588     if (instance == nullptr) {
589         LOGE("Create return instance failed!");
590         return nullptr;
591     }
592     int elementIdx = 0;
593     for (uint32_t i = 0; i < trustAnchorArray->count; ++i) {
594         napi_value element = NapiX509Certificate::CreateX509Cert(env);
595         if (instance == nullptr) {
596             LOGE("Create x509Cert failed!");
597             return nullptr;
598         }
599         napi_value valueCACert = ConvertX509CertToNapiValue(env, trustAnchorArray->data[i]->CACert);
600         if (valueCACert == nullptr) {
601             LOGI("The CACert value is null, return to js is an enpty object!");
602         } else {
603             trustAnchorArray->data[i]->CACert = nullptr;
604         }
605         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CACERT.c_str(), valueCACert);
606 
607         napi_value valuePubKey = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->CAPubKey);
608         if (valuePubKey == nullptr) {
609             LOGI("The PubKey value is null, return to js is an enpty object!");
610         }
611         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CAPUBKEY.c_str(), valuePubKey);
612 
613         napi_value valueSub = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->CASubject);
614         if (valueSub == nullptr) {
615             LOGI("The CASubject value is null, return to js is an enpty object!");
616         }
617         napi_set_named_property(env, element, CERT_CHAIN_TRUSTANCHOR_TAG_CASUBJECT.c_str(), valueSub);
618 
619         napi_value valueName = ConvertBlobToUint8ArrayNapiValue(env, trustAnchorArray->data[i]->nameConstraints);
620         if (valueName == nullptr) {
621             LOGI("The nameConsteaints value is null, return to js is an enpty object!");
622         }
623         napi_set_named_property(env, element, CERT_MATCH_TAG_NAME_CONSTRAINTS.c_str(), valueName);
624 
625         if (element != nullptr) {
626             napi_set_element(env, instance, elementIdx++, element);
627         }
628     }
629     return instance;
630 }
631 
CreateTrustAnchorsWithKeyStoreComplete(napi_env env,napi_status status,void * data)632 static void CreateTrustAnchorsWithKeyStoreComplete(napi_env env, napi_status status, void *data)
633 {
634     CfCtx *context = static_cast<CfCtx *>(data);
635     if (context->async->errCode != CF_SUCCESS) {
636         ReturnJSResult(env, context->async, nullptr);
637         DeleteCertChainContext(env, context, false);
638         return;
639     }
640     napi_value instance = BuildCreateInstanceByTrustAnchorArray(env, context->trustAnchorArray);
641     if (instance == nullptr) {
642         context->async->errCode = CF_ERR_MALLOC;
643         context->async->errMsg = "Failed to create trust anchor with KeyStore";
644         LOGE("Failed to create trust anchor with KeyStore");
645     }
646     ReturnJSResult(env, context->async, instance);
647     DeleteCertChainContext(env, context, true);
648 }
649 
CreateTrustAnchorsWithKeyStoreAsyncWork(napi_env env,CfCtx * context)650 static napi_value CreateTrustAnchorsWithKeyStoreAsyncWork(napi_env env, CfCtx *context)
651 {
652     napi_create_async_work(env, nullptr, GetResourceName(env, "createTrustAnchorsWithKeyStore"),
653         CreateTrustAnchorsWithKeyStoreExecute, CreateTrustAnchorsWithKeyStoreComplete, static_cast<void *>(context),
654         &context->async->asyncWork);
655 
656     napi_queue_async_work(env, context->async->asyncWork);
657     if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
658         return context->async->promise;
659     } else {
660         return NapiGetNull(env);
661     }
662 }
663 
CreateTrustAnchorsWithKeyStore(napi_env env,size_t argc,napi_value param1,napi_value param2)664 static napi_value CreateTrustAnchorsWithKeyStore(napi_env env, size_t argc, napi_value param1, napi_value param2)
665 {
666     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
667         LOGE("CertCheckArgsCount failed");
668         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
669         return nullptr;
670     }
671     CfCtx *context = BuildCertChainContext();
672     if (context == nullptr) {
673         LOGE("context is nullptr");
674         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
675         return nullptr;
676     }
677 
678     context->async->asyncType = GetAsyncType(env, argc, ARGS_SIZE_TWO, nullptr);
679     if (context->async->asyncType == ASYNC_TYPE_CALLBACK) {
680         LOGE("ASYNC_TYPE_CALLBACK is not supported.");
681         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "ASYNC_TYPE_CALLBACK is not supported."));
682         DeleteCertChainContext(env, context);
683         return nullptr;
684     }
685     napi_create_promise(env, &context->async->deferred, &context->async->promise);
686 
687     context->keyStore = CertGetBlobFromUint8ArrJSParams(env, param1);
688     if (context->keyStore == nullptr) {
689         DeleteCertChainContext(env, context);
690         return nullptr;
691     }
692     context->pwd = CertGetBlobFromStringJSParams(env, param2);
693     if (context->pwd == nullptr) {
694         DeleteCertChainContext(env, context);
695         return nullptr;
696     }
697 
698     return CreateTrustAnchorsWithKeyStoreAsyncWork(env, context);
699 }
700 
NapiCreateTrustAnchorsWithKeyStore(napi_env env,napi_callback_info info)701 napi_value NapiCreateTrustAnchorsWithKeyStore(napi_env env, napi_callback_info info)
702 {
703     size_t argc = ARGS_SIZE_TWO;
704     napi_value argv[ARGS_SIZE_TWO] = { nullptr };
705     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
706     napi_value instance = CreateTrustAnchorsWithKeyStore(env, argc, argv[PARAM0], argv[PARAM1]);
707     return instance;
708 }
709 
GetCertMatchParameters(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)710 bool GetCertMatchParameters(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
711 {
712     napi_value data = nullptr;
713     napi_status status = napi_get_named_property(env, obj, CERT_TAG_CERT_MATCH_PARAMS.c_str(), &data);
714     if (status != napi_ok) {
715         LOGE("failed to get cert match params!");
716         return false;
717     }
718     HcfX509CertMatchParams *param = &((*bulidParams)->certMatchParameters);
719     if (!BuildX509CertMatchParams(env, data, param)) {
720         LOGE("BuildX509CertMatchParams failed!");
721         return false;
722     }
723     return true;
724 }
725 
GetMaxlength(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)726 bool GetMaxlength(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
727 {
728     napi_value data = nullptr;
729     napi_status status = napi_get_named_property(env, obj, CERT_TAG_MAX_LENGTH.c_str(), &data);
730     if (status != napi_ok) {
731         LOGE("failed to get max length!");
732         return false;
733     }
734     napi_valuetype valueType;
735     napi_typeof(env, data, &valueType);
736     if ((valueType != napi_number) && (valueType != napi_undefined) && (valueType != napi_null)) {
737         LOGE("%s valueType is null or undefined.", CERT_TAG_MAX_LENGTH.c_str());
738         return false;
739     }
740     napi_get_value_uint32(env, data, reinterpret_cast<uint32_t *>(&((*bulidParams)->maxlength)));
741     return true;
742 }
743 
GetValidateParameters(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)744 bool GetValidateParameters(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
745 {
746     napi_value data = nullptr;
747     napi_status status = napi_get_named_property(env, obj, CERT_TAG_VALIDATE_PARAMS.c_str(), &data);
748     if (status != napi_ok) {
749         LOGE("failed to get cert validate params!");
750         return false;
751     }
752     if (!BuildX509CertChainValidateParams(env, data, (*bulidParams)->validateParameters)) {
753         LOGE("BuildX509CertChainValidateParams failed!");
754         return false;
755     }
756     return true;
757 }
758 
GetChainBuildParametersFromValue(napi_env env,napi_value obj,HcfX509CertChainBuildParameters ** bulidParams)759 bool GetChainBuildParametersFromValue(napi_env env, napi_value obj, HcfX509CertChainBuildParameters **bulidParams)
760 {
761     HcfX509CertChainBuildParameters *buildParam =
762         static_cast<HcfX509CertChainBuildParameters *>(CfMalloc(sizeof(HcfX509CertChainBuildParameters), 0));
763     if (buildParam == nullptr) {
764         LOGE("malloc cert chain build parameters failed!");
765         return false;
766     }
767     buildParam->maxlength = -1;
768 
769     if (!GetCertMatchParameters(env, obj, &buildParam)) {
770         LOGE("failed to get cert match parameters!");
771         CfFree(buildParam);
772         return false;
773     }
774     if (!GetMaxlength(env, obj, &buildParam)) {
775         LOGE("failed to get max length!");
776         CfFree(buildParam);
777         return false;
778     }
779     if (!GetValidateParameters(env, obj, &buildParam)) {
780         LOGE("failed to get validate parameters!");
781         CfFree(buildParam);
782         return false;
783     }
784 
785     *bulidParams = buildParam;
786     return true;
787 }
788 
CreateX509CertChainExtReturn(napi_env env,size_t argc,napi_value param)789 static napi_value CreateX509CertChainExtReturn(napi_env env, size_t argc, napi_value param)
790 {
791     if (!CertCheckArgsCount(env, argc, ARGS_SIZE_ONE, false)) {
792         LOGE("CertCheckArgsCount failed");
793         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "CertCheckArgsCount failed!"));
794         return nullptr;
795     }
796     CfCtx *context = BuildCertChainContext();
797     if (context == nullptr) {
798         LOGE("context is nullptr");
799         napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "context is nullptr!"));
800         return nullptr;
801     }
802 
803     if (!CreateCallbackAndPromise(env, context, argc, ARGS_SIZE_ONE, nullptr)) {
804         LOGE("Create Callback Promise failed");
805         DeleteCertChainContext(env, context);
806         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create Callback Promise failed!"));
807         return nullptr;
808     }
809     if (napi_create_reference(env, param, 1, &context->async->paramRef) != napi_ok) {
810         LOGE("create param ref failed!");
811         DeleteCertChainContext(env, context);
812         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Create param ref failed"));
813         return nullptr;
814     }
815     if (!GetChainBuildParametersFromValue(env, param, &context->bulidParams)) {
816         LOGE("Get Cert Chain Build Parameters failed!");
817         DeleteCertChainContext(env, context);
818         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "Get Cert Chain Build Parameters failed!"));
819         return nullptr;
820     }
821 
822     return CreateCertChainExtAsyncWork(env, context);
823 }
824 
NapiBuildX509CertChain(napi_env env,napi_callback_info info)825 napi_value NapiBuildX509CertChain(napi_env env, napi_callback_info info)
826 {
827     size_t argc = ARGS_SIZE_ONE;
828     napi_value argv[ARGS_SIZE_ONE] = { nullptr };
829     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
830 
831     napi_value instance = nullptr;
832     instance = CreateX509CertChainExtReturn(env, argc, argv[PARAM0]);
833     return instance;
834 }
835 
NapiGetCertList(napi_env env,napi_callback_info info)836 napi_value NapiGetCertList(napi_env env, napi_callback_info info)
837 {
838     napi_value thisVar = nullptr;
839     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
840     NapiX509CertChain *napiCertChainObj = nullptr;
841     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
842     if (napiCertChainObj == nullptr) {
843         LOGE("napi cert chain object is nullptr!");
844         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
845         return nullptr;
846     }
847     HcfCertChain *certChain = napiCertChainObj->GetCertChain();
848     HcfX509CertificateArray certs = { nullptr, 0 };
849     CfResult res = certChain->getCertList(certChain, &certs);
850     if (res != CF_SUCCESS) {
851         LOGE("napi getCertList failed!");
852         napi_throw(env, CertGenerateBusinessError(env, res, "get cert list failed!"));
853         return nullptr;
854     }
855     napi_value instance = ConvertCertArrToNapiValue(env, &certs);
856     if (instance == nullptr) {
857         LOGE("convert arr to instance failed!");
858         FreeCertArrayData(&certs);
859         napi_throw(env, CertGenerateBusinessError(env, res, "convert arr to instance failed!"));
860         return nullptr;
861     }
862     CF_FREE_PTR(certs.data);
863     return instance;
864 }
865 
NapiValidate(napi_env env,napi_callback_info info)866 napi_value NapiValidate(napi_env env, napi_callback_info info)
867 {
868     napi_value thisVar = nullptr;
869     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
870     NapiX509CertChain *napiCertChainObj = nullptr;
871     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
872     if (napiCertChainObj == nullptr) {
873         LOGE("napi cert chain object is nullptr!");
874         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
875         return nullptr;
876     }
877     return napiCertChainObj->Validate(env, info);
878 }
879 
NapiToString(napi_env env,napi_callback_info info)880 napi_value NapiToString(napi_env env, napi_callback_info info)
881 {
882     napi_value thisVar = nullptr;
883     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
884     NapiX509CertChain *napiCertChainObj = nullptr;
885     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
886     if (napiCertChainObj == nullptr) {
887         LOGE("napi cert chain object is nullptr!");
888         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
889         return nullptr;
890     }
891     return napiCertChainObj->ToString(env, info);
892 }
893 
NapiHashCode(napi_env env,napi_callback_info info)894 napi_value NapiHashCode(napi_env env, napi_callback_info info)
895 {
896     napi_value thisVar = nullptr;
897     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
898     NapiX509CertChain *napiCertChainObj = nullptr;
899     napi_unwrap(env, thisVar, reinterpret_cast<void **>(&napiCertChainObj));
900     if (napiCertChainObj == nullptr) {
901         LOGE("napi cert chain object is nullptr!");
902         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "napi cert chain object is nullptr!"));
903         return nullptr;
904     }
905     return napiCertChainObj->HashCode(env, info);
906 }
907 
CertChainConstructor(napi_env env,napi_callback_info info)908 static napi_value CertChainConstructor(napi_env env, napi_callback_info info)
909 {
910     napi_value thisVar = nullptr;
911     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
912     return thisVar;
913 }
914 
Constructor(napi_env env,napi_callback_info info)915 napi_value NapiX509CertChain::Constructor(napi_env env, napi_callback_info info)
916 {
917     return CertChainConstructor(env, info);
918 }
919 
ConvertToJsCertChain(napi_env env)920 napi_value NapiX509CertChain::ConvertToJsCertChain(napi_env env)
921 {
922     napi_value instance;
923     napi_value constructor = nullptr;
924     napi_get_reference_value(env, classRef_, &constructor);
925     napi_new_instance(env, constructor, 0, nullptr, &instance);
926 
927     return instance;
928 }
929 
Constructor(napi_env env,napi_callback_info info)930 napi_value NapiX509CertChainBulidResult::Constructor(napi_env env, napi_callback_info info)
931 {
932     return CertChainConstructor(env, info);
933 }
934 
ConvertToJsBuildResult(napi_env env)935 napi_value NapiX509CertChainBulidResult::ConvertToJsBuildResult(napi_env env)
936 {
937     napi_value instance;
938     napi_value constructor = nullptr;
939     napi_get_reference_value(env, classRef_, &constructor);
940     napi_new_instance(env, constructor, 0, nullptr, &instance);
941 
942     if (this->buildResult_ != nullptr && this->buildResult_->certChain != nullptr) {
943         NapiX509CertChain *napiObject = new (std::nothrow) NapiX509CertChain(this->buildResult_->certChain);
944         if (napiObject == nullptr) {
945             LOGE("new napi object failed.");
946             return nullptr;
947         }
948         napi_value certChain = napiObject->ConvertToJsCertChain(env);
949         napi_status status = napi_wrap(
950             env, certChain, napiObject,
951             [](napi_env env, void *data, void *hint) {
952                 NapiX509CertChain *napiObject = static_cast<NapiX509CertChain *>(data);
953                 delete napiObject;
954                 return;
955             },
956             nullptr, nullptr);
957         if (status != napi_ok) {
958             LOGE("failed to wrap certChain obj!");
959             delete napiObject;
960             return nullptr;
961         }
962         napi_set_named_property(env, instance, "certChain", certChain);
963     }
964 
965     if (this->buildResult_ != nullptr) {
966         napi_value validateResult = BuildX509CertChainValidateResultJS(env, &(this->buildResult_->validateResult));
967         napi_set_named_property(env, instance, "validateResult", validateResult);
968     }
969     return instance;
970 }
971 
DefineX509CertChainJsClass(napi_env env,napi_value exports)972 void NapiX509CertChain::DefineX509CertChainJsClass(napi_env env, napi_value exports)
973 {
974     napi_property_descriptor desc[] = {
975         DECLARE_NAPI_FUNCTION("createX509CertChain", NapiCreateX509CertChain),
976         DECLARE_NAPI_FUNCTION("createTrustAnchorsWithKeyStore", NapiCreateTrustAnchorsWithKeyStore),
977     };
978     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
979 
980     napi_property_descriptor CertChainDesc[] = {
981         DECLARE_NAPI_FUNCTION("getCertList", NapiGetCertList),
982         DECLARE_NAPI_FUNCTION("validate", NapiValidate),
983         DECLARE_NAPI_FUNCTION("toString", NapiToString),
984         DECLARE_NAPI_FUNCTION("hashCode", NapiHashCode),
985     };
986 
987     napi_value constructor = nullptr;
988     napi_define_class(env, "X509CertChain", NAPI_AUTO_LENGTH, CertChainConstructor, nullptr,
989         sizeof(CertChainDesc) / sizeof(CertChainDesc[0]), CertChainDesc, &constructor);
990     napi_create_reference(env, constructor, 1, &classRef_);
991 }
992 
DefineX509CertChainBuildResultJsClass(napi_env env,napi_value exports)993 void NapiX509CertChainBulidResult::DefineX509CertChainBuildResultJsClass(napi_env env, napi_value exports)
994 {
995     napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("buildX509CertChain", NapiBuildX509CertChain) };
996     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
997 
998     napi_property_descriptor CertChainBuildResultDesc[] = {};
999     napi_value constructor = nullptr;
1000     napi_define_class(env, "CertChainBuildResult", NAPI_AUTO_LENGTH, NapiX509CertChainBulidResult::Constructor, nullptr,
1001         sizeof(CertChainBuildResultDesc) / sizeof(CertChainBuildResultDesc[0]), CertChainBuildResultDesc, &constructor);
1002     napi_create_reference(env, constructor, 1, &classRef_);
1003 }
1004 } // namespace CertFramework
1005 } // namespace OHOS
1006