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