• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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