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