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_extension.h"
17
18 #include "napi/native_common.h"
19 #include "napi/native_api.h"
20
21 #include "cf_api.h"
22 #include "cf_log.h"
23 #include "cf_memory.h"
24 #include "cf_param.h"
25 #include "cf_result.h"
26
27 #include "napi_cert_defines.h"
28 #include "napi_cert_utils.h"
29 #include "napi_common.h"
30 #include "napi_object.h"
31
32 namespace OHOS {
33 namespace CertFramework {
34 thread_local napi_ref NapiCertExtension::classRef_ = nullptr;
35
36 struct CfExtensionAsyncContext {
37 AsyncCtx async = nullptr;
38
39 CfEncodingBlob *encodingBlob = nullptr;
40 CfObject *extsObj = nullptr;
41 };
42 using ExtsAsyncContext = CfExtensionAsyncContext *;
43
NapiCertExtension(CfObject * object)44 NapiCertExtension::NapiCertExtension(CfObject *object)
45 {
46 this->object_ = object;
47 }
48
~NapiCertExtension()49 NapiCertExtension::~NapiCertExtension()
50 {
51 if (this->object_ != nullptr) {
52 this->object_->destroy(&this->object_);
53 }
54 }
55
NewExtsAsyncContext(void)56 static ExtsAsyncContext NewExtsAsyncContext(void)
57 {
58 ExtsAsyncContext extsAsyncCtx = static_cast<ExtsAsyncContext>(CfMalloc(sizeof(CfExtensionAsyncContext), 0));
59 if (extsAsyncCtx == nullptr) {
60 CF_LOG_E("Failed to malloc extension async context");
61 return nullptr;
62 }
63
64 AsyncCtx asyncCtx = static_cast<AsyncCtx>(CfMalloc(sizeof(AsyncContext), 0));
65 if (asyncCtx == nullptr) {
66 CF_LOG_E("Failed to malloc async context");
67 CfFree(extsAsyncCtx);
68 extsAsyncCtx = nullptr;
69 return nullptr;
70 }
71
72 extsAsyncCtx->async = asyncCtx;
73 return extsAsyncCtx;
74 }
75
DeleteExtsAsyncContext(napi_env env,ExtsAsyncContext & context)76 static void DeleteExtsAsyncContext(napi_env env, ExtsAsyncContext &context)
77 {
78 if (context == nullptr) {
79 return;
80 }
81
82 FreeAsyncContext(env, context->async);
83
84 CfEncodingBlobDataFree(context->encodingBlob);
85 CfFree(context->encodingBlob);
86 context->encodingBlob = nullptr;
87
88 CfFree(context);
89 }
90
ParseCreateExtsJSParams(napi_env env,napi_callback_info info,ExtsAsyncContext context)91 static napi_value ParseCreateExtsJSParams(napi_env env, napi_callback_info info, ExtsAsyncContext context)
92 {
93 size_t argc = ARGS_SIZE_TWO;
94 napi_value argv[ARGS_SIZE_TWO] = { nullptr };
95 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
96 if (!CertCheckArgsCount(env, argc, ARGS_SIZE_TWO, false)) {
97 return nullptr;
98 }
99
100 if (!GetEncodingBlobFromValue(env, argv[PARAM0], &context->encodingBlob)) {
101 CF_LOG_E("get encoding blob from data failed!");
102 return nullptr;
103 }
104
105 context->async->asyncType = GetAsyncType(env, argc, ARGS_SIZE_TWO, argv[PARAM1]);
106 if (!GetCallbackAndPromise(env, context->async, argv[PARAM1])) {
107 return nullptr;
108 }
109
110 return NapiGetInt32(env, 0);
111 }
112
CreateCertExtsJSInstance(napi_env env)113 static napi_value CreateCertExtsJSInstance(napi_env env)
114 {
115 napi_value constructor = nullptr;
116 napi_value instance = nullptr;
117 napi_get_reference_value(env, NapiCertExtension::classRef_, &constructor);
118 napi_new_instance(env, constructor, 0, nullptr, &instance);
119 return instance;
120 }
121
CreateCertExtsExecute(napi_env env,void * data)122 static void CreateCertExtsExecute(napi_env env, void *data)
123 {
124 ExtsAsyncContext context = static_cast<ExtsAsyncContext>(data);
125 context->async->errCode = CfCreate(CF_OBJ_TYPE_EXTENSION, context->encodingBlob, &context->extsObj);
126 if (context->async->errCode != CF_SUCCESS) {
127 context->async->errMsg = "create extension failed";
128 }
129 }
130
CreateCertExtsComplete(napi_env env,napi_status status,void * data)131 static void CreateCertExtsComplete(napi_env env, napi_status status, void *data)
132 {
133 ExtsAsyncContext context = static_cast<ExtsAsyncContext>(data);
134 if (context->async->errCode != CF_SUCCESS) {
135 ReturnJSResult(env, context->async, nullptr);
136 DeleteExtsAsyncContext(env, context);
137 return;
138 }
139
140 napi_value jsObject = CreateCertExtsJSInstance(env);
141 NapiCertExtension *napiObject = new (std::nothrow) NapiCertExtension(context->extsObj);
142 if (napiObject == nullptr) {
143 context->async->errCode = CF_ERR_MALLOC;
144 context->async->errMsg = "Failed to create napi extension class";
145 CF_LOG_E("Failed to create napi extension class");
146 if (context->extsObj != nullptr) {
147 context->extsObj->destroy(&(context->extsObj));
148 }
149 ReturnJSResult(env, context->async, nullptr);
150 DeleteExtsAsyncContext(env, context);
151 return;
152 }
153 status = napi_wrap(
154 env, jsObject, napiObject,
155 [](napi_env env, void *data, void *hint) {
156 NapiCertExtension *certExts = static_cast<NapiCertExtension *>(data);
157 delete certExts;
158 return;
159 },
160 nullptr, nullptr);
161 if (status != napi_ok) {
162 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_NAPI, "failed to wrap obj!"));
163 LOGE("failed to wrap obj!");
164 delete napiObject;
165 return;
166 }
167 ReturnJSResult(env, context->async, jsObject);
168 DeleteExtsAsyncContext(env, context);
169 }
170
CreateCertExtsAsyncWork(napi_env env,ExtsAsyncContext context)171 static napi_value CreateCertExtsAsyncWork(napi_env env, ExtsAsyncContext context)
172 {
173 napi_create_async_work(
174 env,
175 nullptr,
176 GetResourceName(env, "CreateCertExtsAsyncWork"),
177 CreateCertExtsExecute,
178 CreateCertExtsComplete,
179 static_cast<void *>(context),
180 &context->async->asyncWork);
181
182 napi_queue_async_work(env, context->async->asyncWork);
183 if (context->async->asyncType == ASYNC_TYPE_PROMISE) {
184 return context->async->promise;
185 } else {
186 return NapiGetNull(env);
187 }
188 return nullptr;
189 }
190
NapiCreateCertExtension(napi_env env,napi_callback_info info)191 napi_value NapiCreateCertExtension(napi_env env, napi_callback_info info)
192 {
193 ExtsAsyncContext context = NewExtsAsyncContext();
194 if (context == nullptr) {
195 CF_LOG_E("Failed to new create exts async context");
196 return nullptr;
197 }
198
199 napi_value result = ParseCreateExtsJSParams(env, info, context);
200 if (result == nullptr) {
201 CF_LOG_E("Failed to parse JS params for create exts object");
202 DeleteExtsAsyncContext(env, context);
203 return nullptr;
204 }
205
206 result = CreateCertExtsAsyncWork(env, context);
207 if (result == nullptr) {
208 CF_LOG_E("Failed to create exts object in async work");
209 DeleteExtsAsyncContext(env, context);
210 return nullptr;
211 }
212
213 return result;
214 }
215
NapiCommonOperation(napi_env env,napi_callback_info info,int32_t opType,int32_t typeValue)216 static napi_value NapiCommonOperation(napi_env env, napi_callback_info info, int32_t opType, int32_t typeValue)
217 {
218 napi_value jsObject = nullptr;
219 napi_get_cb_info(env, info, nullptr, nullptr, &jsObject, nullptr);
220
221 NapiCertExtension *napiExtsObj = nullptr;
222 napi_unwrap(env, jsObject, reinterpret_cast<void **>(&napiExtsObj));
223 if (napiExtsObj == nullptr) {
224 CF_LOG_E("napi extension objtect is nullptr!");
225 return nullptr;
226 }
227
228 CfObject *extsObj = napiExtsObj->GetObject();
229 if (extsObj == nullptr) {
230 CF_LOG_E("cf objtect is nullptr!");
231 return nullptr;
232 }
233 return CommonOperation(env, info, extsObj, opType, typeValue);
234 }
235
NapiGetExtensionEncoded(napi_env env,napi_callback_info info)236 napi_value NapiGetExtensionEncoded(napi_env env, napi_callback_info info)
237 {
238 return NapiCommonOperation(env, info, OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ITEM);
239 }
240
NapiGetExtensionOidList(napi_env env,napi_callback_info info)241 static napi_value NapiGetExtensionOidList(napi_env env, napi_callback_info info)
242 {
243 return NapiCommonOperation(env, info, OPERATION_TYPE_GET, CF_GET_TYPE_EXT_OIDS);
244 }
245
NapiGetExtensionEntry(napi_env env,napi_callback_info info)246 static napi_value NapiGetExtensionEntry(napi_env env, napi_callback_info info)
247 {
248 return NapiCommonOperation(env, info, OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ENTRY);
249 }
250
NapiExtensionCheckCA(napi_env env,napi_callback_info info)251 static napi_value NapiExtensionCheckCA(napi_env env, napi_callback_info info)
252 {
253 return NapiCommonOperation(env, info, OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_CA);
254 }
255
NapiExtensionHasUnsupportCritical(napi_env env,napi_callback_info info)256 static napi_value NapiExtensionHasUnsupportCritical(napi_env env, napi_callback_info info)
257 {
258 return NapiCommonOperation(env, info, OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_HAS_UN_SUPPORT);
259 }
260
CertExtsConstructor(napi_env env,napi_callback_info info)261 static napi_value CertExtsConstructor(napi_env env, napi_callback_info info)
262 {
263 napi_value thisVar = nullptr;
264 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
265 return thisVar;
266 }
267
DefineCertExtensionJsClass(napi_env env,napi_value exports)268 void NapiCertExtension::DefineCertExtensionJsClass(napi_env env, napi_value exports)
269 {
270 napi_property_descriptor desc[] = {
271 DECLARE_NAPI_FUNCTION("createCertExtension", NapiCreateCertExtension),
272 };
273 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
274
275 napi_property_descriptor CertExtensionDesc[] = {
276 DECLARE_NAPI_FUNCTION("getEncoded", NapiGetExtensionEncoded),
277 DECLARE_NAPI_FUNCTION("getOidList", NapiGetExtensionOidList),
278 DECLARE_NAPI_FUNCTION("getEntry", NapiGetExtensionEntry),
279 DECLARE_NAPI_FUNCTION("checkCA", NapiExtensionCheckCA),
280 DECLARE_NAPI_FUNCTION("hasUnsupportedCriticalExtension", NapiExtensionHasUnsupportCritical),
281 };
282
283 napi_value constructor = nullptr;
284 napi_define_class(
285 env,
286 "CertExtension",
287 NAPI_AUTO_LENGTH,
288 CertExtsConstructor,
289 nullptr,
290 sizeof(CertExtensionDesc) / sizeof(CertExtensionDesc[0]),
291 CertExtensionDesc,
292 &constructor);
293 napi_create_reference(env, constructor, 1, &classRef_);
294 }
295 } // namespace CertFramework
296 } // namespace OHOS
297