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