1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "napi_cert_chain_validator.h"
17
18 #include "napi/native_node_api.h"
19 #include "napi/native_api.h"
20 #include "cf_log.h"
21 #include "cf_memory.h"
22 #include "utils.h"
23 #include "cf_result.h"
24 #include "cf_object_base.h"
25 #include "napi_cert_defines.h"
26 #include "napi_cert_utils.h"
27
28 namespace OHOS {
29 namespace CertFramework {
30 thread_local napi_ref NapiCertChainValidator::classRef_ = nullptr;
31
32 struct CfCtx {
33 AsyncType asyncType = ASYNC_TYPE_CALLBACK;
34 napi_ref callback = nullptr;
35 napi_deferred deferred = nullptr;
36 napi_async_work asyncWork = nullptr;
37
38 NapiCertChainValidator *ccvClass = nullptr;
39 HcfCertChainData *certChainData = nullptr;
40
41 int32_t errCode = 0;
42 const char *errMsg = nullptr;
43 };
44
NapiCertChainValidator(HcfCertChainValidator * certChainValidator)45 NapiCertChainValidator::NapiCertChainValidator(HcfCertChainValidator *certChainValidator)
46 {
47 this->certChainValidator_ = certChainValidator;
48 }
49
~NapiCertChainValidator()50 NapiCertChainValidator::~NapiCertChainValidator()
51 {
52 CfObjDestroy(this->certChainValidator_);
53 }
54
FreeCryptoFwkCtx(napi_env env,CfCtx * context)55 static void FreeCryptoFwkCtx(napi_env env, CfCtx *context)
56 {
57 if (context == nullptr) {
58 return;
59 }
60
61 if (context->asyncWork != nullptr) {
62 napi_delete_async_work(env, context->asyncWork);
63 }
64
65 if (context->callback != nullptr) {
66 napi_delete_reference(env, context->callback);
67 }
68
69 if (context->certChainData != nullptr) {
70 CfFree(context->certChainData->data);
71 context->certChainData->data = nullptr;
72 CfFree(context->certChainData);
73 context->certChainData = nullptr;
74 }
75
76 CfFree(context);
77 }
78
ReturnCallbackResult(napi_env env,CfCtx * context,napi_value result)79 static void ReturnCallbackResult(napi_env env, CfCtx *context, napi_value result)
80 {
81 napi_value businessError = nullptr;
82 if (context->errCode != CF_SUCCESS) {
83 businessError = CertGenerateBusinessError(env, context->errCode, context->errMsg);
84 }
85 napi_value params[ARGS_SIZE_TWO] = { businessError, result };
86
87 napi_value func = nullptr;
88 napi_get_reference_value(env, context->callback, &func);
89
90 napi_value recv = nullptr;
91 napi_value callFuncRet = nullptr;
92 napi_get_undefined(env, &recv);
93 napi_call_function(env, recv, func, ARGS_SIZE_TWO, params, &callFuncRet);
94 }
95
ReturnPromiseResult(napi_env env,CfCtx * context,napi_value result)96 static void ReturnPromiseResult(napi_env env, CfCtx *context, napi_value result)
97 {
98 if (context->errCode == CF_SUCCESS) {
99 napi_resolve_deferred(env, context->deferred, result);
100 } else {
101 napi_reject_deferred(env, context->deferred,
102 CertGenerateBusinessError(env, context->errCode, context->errMsg));
103 }
104 }
105
ReturnResult(napi_env env,CfCtx * context,napi_value result)106 static void ReturnResult(napi_env env, CfCtx *context, napi_value result)
107 {
108 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
109 ReturnCallbackResult(env, context, result);
110 } else {
111 ReturnPromiseResult(env, context, result);
112 }
113 }
114
ValidateExecute(napi_env env,void * data)115 static void ValidateExecute(napi_env env, void *data)
116 {
117 CfCtx *context = static_cast<CfCtx *>(data);
118 HcfCertChainValidator *validator = context->ccvClass->GetCertChainValidator();
119 context->errCode = validator->validate(validator, context->certChainData);
120 if (context->errCode != CF_SUCCESS) {
121 LOGE("validate cert chain failed!");
122 context->errMsg = "validate cert chain failed";
123 }
124 }
125
ValidateComplete(napi_env env,napi_status status,void * data)126 static void ValidateComplete(napi_env env, napi_status status, void *data)
127 {
128 CfCtx *context = static_cast<CfCtx *>(data);
129 ReturnResult(env, context, CertNapiGetNull(env));
130 FreeCryptoFwkCtx(env, context);
131 }
132
Validate(napi_env env,napi_callback_info info)133 napi_value NapiCertChainValidator::Validate(napi_env env, napi_callback_info info)
134 {
135 size_t argc = ARGS_SIZE_TWO;
136 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
137 napi_value thisVar = nullptr;
138 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
139 if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
140 return nullptr;
141 }
142 CfCtx *context = static_cast<CfCtx *>(HcfMalloc(sizeof(CfCtx), 0));
143 if (context == nullptr) {
144 LOGE("malloc context failed!");
145 return nullptr;
146 }
147 context->ccvClass = this;
148
149 context->asyncType = GetAsyncType(env, argc, ARGS_SIZE_TWO, argv[PARAM1]);
150 if (!GetCertChainFromValue(env, argv[PARAM0], &context->certChainData)) {
151 LOGE("get cert chain data from napi value failed!");
152 FreeCryptoFwkCtx(env, context);
153 return nullptr;
154 }
155 napi_value promise = nullptr;
156 if (context->asyncType == ASYNC_TYPE_CALLBACK) {
157 if (!CertGetCallbackFromJSParams(env, argv[PARAM1], &context->callback)) {
158 LOGE("get callback failed!");
159 FreeCryptoFwkCtx(env, context);
160 return nullptr;
161 }
162 } else {
163 napi_create_promise(env, &context->deferred, &promise);
164 }
165
166 napi_create_async_work(
167 env, nullptr, CertGetResourceName(env, "Validate"),
168 ValidateExecute,
169 ValidateComplete,
170 static_cast<void *>(context),
171 &context->asyncWork);
172
173 napi_queue_async_work(env, context->asyncWork);
174 if (context->asyncType == ASYNC_TYPE_PROMISE) {
175 return promise;
176 } else {
177 return CertNapiGetNull(env);
178 }
179 }
180
NapiValidate(napi_env env,napi_callback_info info)181 static napi_value NapiValidate(napi_env env, napi_callback_info info)
182 {
183 LOGI("start to validate cert chain.");
184 napi_value thisVar = nullptr;
185 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
186 NapiCertChainValidator *certChainValidator = nullptr;
187 napi_unwrap(env, thisVar, reinterpret_cast<void **>(&certChainValidator));
188 if (certChainValidator == nullptr) {
189 LOGE("certChainValidator is nullptr!");
190 return nullptr;
191 }
192 return certChainValidator->Validate(env, info);
193 }
194
CertChainValidatorConstructor(napi_env env,napi_callback_info info)195 static napi_value CertChainValidatorConstructor(napi_env env, napi_callback_info info)
196 {
197 napi_value thisVar = nullptr;
198 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
199 return thisVar;
200 }
201
CreateCertChainValidator(napi_env env,napi_callback_info info)202 napi_value NapiCertChainValidator::CreateCertChainValidator(napi_env env, napi_callback_info info)
203 {
204 LOGI("start to create cert chain validator.");
205 napi_value thisVar = nullptr;
206 size_t argc = ARGS_SIZE_ONE;
207 napi_value argv[ARGS_SIZE_ONE] = { nullptr };
208 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
209
210 if (argc != ARGS_SIZE_ONE) {
211 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "invalid params count"));
212 LOGE("invalid params count!");
213 return nullptr;
214 }
215
216 std::string algorithm;
217 if (!CertGetStringFromJSParams(env, argv[PARAM0], algorithm)) {
218 LOGE("Failed to get algorithm.");
219 return nullptr;
220 }
221 HcfCertChainValidator *certChainValidator = nullptr;
222 CfResult res = HcfCertChainValidatorCreate(algorithm.c_str(), &certChainValidator);
223 if (res != CF_SUCCESS) {
224 napi_throw(env, CertGenerateBusinessError(env, res, "create cert chain validator failed"));
225 LOGE("Failed to create c cert chain validator.");
226 return nullptr;
227 }
228 const char *returnAlgorithm = certChainValidator->getAlgorithm(certChainValidator);
229 napi_value algValue = nullptr;
230 napi_create_string_utf8(env, returnAlgorithm, NAPI_AUTO_LENGTH, &algValue);
231 napi_value constructor = nullptr;
232 napi_value validatorInstance = nullptr;
233 napi_get_reference_value(env, classRef_, &constructor);
234 napi_new_instance(env, constructor, 0, nullptr, &validatorInstance);
235 napi_set_named_property(env, validatorInstance, CERT_TAG_ALGORITHM.c_str(), algValue);
236 NapiCertChainValidator *ccvClass = new (std::nothrow) NapiCertChainValidator(certChainValidator);
237 if (ccvClass == nullptr) {
238 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "Failed to create a ccv class"));
239 LOGE("Failed to create a ccv class");
240 CfObjDestroy(certChainValidator);
241 return nullptr;
242 }
243 napi_wrap(
244 env, validatorInstance, ccvClass,
245 [](napi_env env, void* data, void *hint) {
246 NapiCertChainValidator *ccv = static_cast<NapiCertChainValidator *>(data);
247 delete ccv;
248 },
249 nullptr,
250 nullptr);
251
252 return validatorInstance;
253 }
254
DefineCertChainValidatorJSClass(napi_env env,napi_value exports)255 void NapiCertChainValidator::DefineCertChainValidatorJSClass(napi_env env, napi_value exports)
256 {
257 napi_property_descriptor desc[] = {
258 DECLARE_NAPI_FUNCTION("createCertChainValidator", CreateCertChainValidator),
259 };
260 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
261
262 napi_property_descriptor validatorDesc[] = {
263 DECLARE_NAPI_FUNCTION("validate", NapiValidate),
264 };
265 napi_value constructor = nullptr;
266 napi_define_class(env, "CertChainValidator", NAPI_AUTO_LENGTH, CertChainValidatorConstructor, nullptr,
267 sizeof(validatorDesc) / sizeof(validatorDesc[0]), validatorDesc, &constructor);
268 napi_create_reference(env, constructor, 1, &classRef_);
269 }
270 } // namespace CertFramework
271 } // namespace OHOS