1 /*
2  * Copyright (c) 2022 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 "cm_napi_user_trusted_cert.h"
17 
18 #include "securec.h"
19 
20 #include "cert_manager_api.h"
21 #include "cm_log.h"
22 #include "cm_mem.h"
23 #include "cm_type.h"
24 #include "cm_napi_common.h"
25 
26 namespace CMNapi {
27 namespace {
28 constexpr int CM_NAPI_USER_INSTALL_ARGS_CNT = 2;
29 constexpr int CM_NAPI_USER_UNINSTALL_ARGS_CNT = 2;
30 constexpr int CM_NAPI_USER_UNINSTALL_ALL_ARGS_CNT = 1;
31 constexpr int CM_NAPI_CALLBACK_ARG_CNT = 1;
32 constexpr uint32_t OUT_AUTH_URI_SIZE = 1000;
33 } // namespace
34 
35 struct UserCertAsyncContextT {
36     napi_async_work asyncWork = nullptr;
37     napi_deferred deferred = nullptr;
38     napi_ref callback = nullptr;
39 
40     int32_t errCode = 0;
41 
42     struct CmBlob *userCert = nullptr;
43     struct CmBlob *certAlias = nullptr;
44     struct CmBlob *certUri = nullptr;
45 };
46 using UserCertAsyncContext = UserCertAsyncContextT *;
47 
InitUserCertAsyncContext(void)48 static UserCertAsyncContext InitUserCertAsyncContext(void)
49 {
50     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(CmMalloc(sizeof(UserCertAsyncContextT)));
51     if (context != nullptr) {
52         (void)memset_s(context, sizeof(UserCertAsyncContextT), 0, sizeof(UserCertAsyncContextT));
53     }
54     return context;
55 }
56 
FreeUserCertAsyncContext(napi_env env,UserCertAsyncContext & context)57 static void FreeUserCertAsyncContext(napi_env env, UserCertAsyncContext &context)
58 {
59     if (context == nullptr) {
60         return;
61     }
62 
63     DeleteNapiContext(env, context->asyncWork, context->callback);
64     FreeCmBlob(context->userCert);
65     FreeCmBlob(context->certAlias);
66     FreeCmBlob(context->certUri);
67     CM_FREE_PTR(context);
68 }
69 
GetUserCertData(napi_env env,napi_value object,UserCertAsyncContext context)70 static int32_t GetUserCertData(napi_env env, napi_value object, UserCertAsyncContext context)
71 {
72     context->userCert = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
73     if (context->userCert == nullptr) {
74         CM_LOG_E("could not alloc userCert blob memory");
75         return CMR_ERROR_MALLOC_FAIL;
76     }
77     (void)memset_s(context->userCert, sizeof(CmBlob), 0, sizeof(CmBlob));
78 
79     napi_value result = GetUint8Array(env, object, *(context->userCert));
80     if (result == nullptr) {
81         CM_LOG_E("could not get userCert data");
82         return CMR_ERROR_INVALID_OPERATION;
83     }
84 
85     return CM_SUCCESS;
86 }
87 
GetCertAliasData(napi_env env,napi_value object,UserCertAsyncContext context)88 static int32_t GetCertAliasData(napi_env env, napi_value object, UserCertAsyncContext context)
89 {
90     napi_value result = ParseCertAlias(env, object, context->certAlias);
91     if (result == nullptr) {
92         CM_LOG_E("could not get certAlias data");
93         return CMR_ERROR_INVALID_OPERATION;
94     }
95 
96     return CM_SUCCESS;
97 }
98 
ParseCertInfo(napi_env env,napi_value object,UserCertAsyncContext context)99 static napi_value ParseCertInfo(napi_env env, napi_value object, UserCertAsyncContext context)
100 {
101     napi_valuetype type = napi_undefined;
102     NAPI_CALL(env, napi_typeof(env, object, &type));
103     if (type != napi_object) {
104         CM_LOG_E("type of param CertBlob is not object");
105         return nullptr;
106     }
107 
108     napi_value userCertValue = nullptr;
109     napi_status status = napi_get_named_property(env, object, "inData", &userCertValue);
110     if (status != napi_ok || userCertValue == nullptr) {
111         CM_LOG_E("get inData failed");
112         return nullptr;
113     }
114 
115     napi_value certAliasValue = nullptr;
116     status = napi_get_named_property(env, object, "alias", &certAliasValue);
117     if (status != napi_ok || certAliasValue == nullptr) {
118         CM_LOG_E("get cert alias failed");
119         return nullptr;
120     }
121 
122     int32_t ret = GetUserCertData(env, userCertValue, context);
123     if (ret != CM_SUCCESS) {
124         return nullptr;
125     }
126 
127     ret = GetCertAliasData(env, certAliasValue, context);
128     if (ret != CM_SUCCESS) {
129         return nullptr;
130     }
131 
132     return GetInt32(env, 0);
133 }
134 
ParseInstallUserCertParams(napi_env env,napi_callback_info info,UserCertAsyncContext context)135 static napi_value ParseInstallUserCertParams(napi_env env, napi_callback_info info, UserCertAsyncContext context)
136 {
137     size_t argc = CM_NAPI_USER_INSTALL_ARGS_CNT;
138     napi_value argv[CM_NAPI_USER_INSTALL_ARGS_CNT] = { nullptr };
139     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
140 
141     if ((argc != CM_NAPI_USER_INSTALL_ARGS_CNT) &&
142         (argc != (CM_NAPI_USER_INSTALL_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
143         ThrowError(env, PARAM_ERROR, "arguments count invalid when installing user cert");
144         CM_LOG_E("arguments count is not expected when installing user cert");
145         return nullptr;
146     }
147 
148     size_t index = 0;
149     napi_value result = ParseCertInfo(env, argv[index], context);
150     if (result == nullptr) {
151         ThrowError(env, PARAM_ERROR, "get context type error");
152         CM_LOG_E("get CertBlob failed when installing user cert");
153         return nullptr;
154     }
155 
156     index++;
157     if (index < argc) {
158         int32_t ret = GetCallback(env, argv[index], context->callback);
159         if (ret != CM_SUCCESS) {
160             ThrowError(env, PARAM_ERROR, "Get callback type failed.");
161             CM_LOG_E("get callback function failed when install user cert");
162             return nullptr;
163         }
164     }
165 
166     return GetInt32(env, 0);
167 }
168 
ParseUninstallUserCertParams(napi_env env,napi_callback_info info,UserCertAsyncContext context)169 static napi_value ParseUninstallUserCertParams(napi_env env, napi_callback_info info, UserCertAsyncContext context)
170 {
171     size_t argc = CM_NAPI_USER_UNINSTALL_ARGS_CNT;
172     napi_value argv[CM_NAPI_USER_UNINSTALL_ARGS_CNT] = { nullptr };
173     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
174 
175     if ((argc != CM_NAPI_USER_UNINSTALL_ARGS_CNT) &&
176         (argc != (CM_NAPI_USER_UNINSTALL_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
177         ThrowError(env, PARAM_ERROR, "arguments count invalid when uninstalling user cert");
178         CM_LOG_E("arguments count is not expected when uninstalling user cert");
179         return nullptr;
180     }
181 
182     size_t index = 0;
183     napi_value result = ParseString(env, argv[index], context->certUri);
184     if (result == nullptr) {
185         ThrowError(env, PARAM_ERROR, "get certUri type error");
186         CM_LOG_E("get CertBlob failed when uninstalling user cert");
187         return nullptr;
188     }
189 
190     index++;
191     if (index < argc) {
192         int32_t ret = GetCallback(env, argv[index], context->callback);
193         if (ret != CM_SUCCESS) {
194             ThrowError(env, PARAM_ERROR, "Get callback type failed.");
195             CM_LOG_E("get callback function failed when uninstalling user cert");
196             return nullptr;
197         }
198     }
199 
200     return GetInt32(env, 0);
201 }
202 
ParseUninstallAllUserCertParams(napi_env env,napi_callback_info info,UserCertAsyncContext context)203 static napi_value ParseUninstallAllUserCertParams(napi_env env, napi_callback_info info, UserCertAsyncContext context)
204 {
205     size_t argc = CM_NAPI_USER_UNINSTALL_ALL_ARGS_CNT;
206     napi_value argv[CM_NAPI_USER_UNINSTALL_ALL_ARGS_CNT] = { nullptr };
207     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
208 
209     if ((argc != CM_NAPI_USER_UNINSTALL_ALL_ARGS_CNT) &&
210         (argc != (CM_NAPI_USER_UNINSTALL_ALL_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
211         ThrowError(env, PARAM_ERROR, "arguments count invalid when uninstalling all user cert");
212         CM_LOG_E("arguments count is not expected when uninstalling all user cert");
213         return nullptr;
214     }
215 
216     size_t index = 0;
217     if (index < argc) {
218         int32_t ret = GetCallback(env, argv[index], context->callback);
219         if (ret != CM_SUCCESS) {
220             ThrowError(env, PARAM_ERROR, "Get callback type failed.");
221             CM_LOG_E("get callback function failed when uninstalling all user cert");
222             return nullptr;
223         }
224     }
225 
226     return GetInt32(env, 0);
227 }
228 
InstallUserCertExecute(napi_env env,void * data)229 static void InstallUserCertExecute(napi_env env, void *data)
230 {
231     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(data);
232     context->certUri = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
233     if (context->certUri == nullptr) {
234         CM_LOG_E("malloc certUri failed");
235         context->errCode = CMR_ERROR_MALLOC_FAIL;
236         return;
237     }
238     (void)memset_s(context->certUri, sizeof(CmBlob), 0, sizeof(CmBlob));
239 
240     context->certUri->data = static_cast<uint8_t *>(CmMalloc(OUT_AUTH_URI_SIZE));
241     if (context->certUri->data == nullptr) {
242         CM_LOG_E("malloc certUri.data failed");
243         context->errCode = CMR_ERROR_MALLOC_FAIL;
244         return;
245     }
246     (void)memset_s(context->certUri->data, OUT_AUTH_URI_SIZE, 0, OUT_AUTH_URI_SIZE);
247     context->certUri->size = OUT_AUTH_URI_SIZE;
248 
249     context->errCode = CmInstallUserTrustedCert(context->userCert, context->certAlias, context->certUri);
250 }
251 
ConvertResultCertUri(napi_env env,const CmBlob * certUri)252 static napi_value ConvertResultCertUri(napi_env env, const CmBlob *certUri)
253 {
254     napi_value result = nullptr;
255     NAPI_CALL(env, napi_create_object(env, &result));
256 
257     napi_value certUriNapi = nullptr;
258     NAPI_CALL(env, napi_create_string_latin1(env, reinterpret_cast<const char *>(certUri->data),
259         NAPI_AUTO_LENGTH, &certUriNapi));
260     NAPI_CALL(env, napi_set_named_property(env, result, "uri", certUriNapi));
261 
262     return result;
263 }
264 
InstallUserCertComplete(napi_env env,napi_status status,void * data)265 static void InstallUserCertComplete(napi_env env, napi_status status, void *data)
266 {
267     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(data);
268     napi_value result[RESULT_NUMBER] = { nullptr };
269     if (context->errCode == CM_SUCCESS) {
270         napi_create_uint32(env, 0, &result[0]);
271         result[1] = ConvertResultCertUri(env, context->certUri);
272     } else {
273         result[0] = GenerateBusinessError(env, context->errCode);
274         napi_get_undefined(env, &result[1]);
275     }
276 
277     if (context->deferred != nullptr) {
278         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
279     } else {
280         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
281     }
282     FreeUserCertAsyncContext(env, context);
283 }
284 
InstallUserCertAsyncWork(napi_env env,UserCertAsyncContext context)285 static napi_value InstallUserCertAsyncWork(napi_env env, UserCertAsyncContext context)
286 {
287     napi_value promise = nullptr;
288     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
289 
290     napi_value resourceName = nullptr;
291     NAPI_CALL(env, napi_create_string_latin1(env, "installUserCertAsyncWork", NAPI_AUTO_LENGTH, &resourceName));
292 
293     NAPI_CALL(env, napi_create_async_work(
294         env, nullptr, resourceName,
295         InstallUserCertExecute,
296         InstallUserCertComplete,
297         static_cast<void *>(context),
298         &context->asyncWork));
299 
300     napi_status status = napi_queue_async_work(env, context->asyncWork);
301     if (status != napi_ok) {
302         ThrowError(env, PARAM_ERROR, "queue async work error");
303         CM_LOG_E("queue async work failed when installing user cert");
304         return nullptr;
305     }
306     return promise;
307 }
308 
UninstallUserCertExecute(napi_env env,void * data)309 static void UninstallUserCertExecute(napi_env env, void *data)
310 {
311     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(data);
312     context->errCode = CmUninstallUserTrustedCert(context->certUri);
313 }
314 
UninstallComplete(napi_env env,napi_status status,void * data)315 static void UninstallComplete(napi_env env, napi_status status, void *data)
316 {
317     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(data);
318     napi_value result[RESULT_NUMBER] = { nullptr };
319     if (context->errCode == CM_SUCCESS) {
320         napi_create_uint32(env, 0, &result[0]);
321         napi_get_boolean(env, true, &result[1]);
322     } else {
323         result[0] = GenerateBusinessError(env, context->errCode);
324         napi_get_undefined(env, &result[1]);
325     }
326 
327     if (context->deferred != nullptr) {
328         GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
329     } else {
330         GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
331     }
332     FreeUserCertAsyncContext(env, context);
333 }
334 
UninstallUserCertAsyncWork(napi_env env,UserCertAsyncContext context)335 static napi_value UninstallUserCertAsyncWork(napi_env env, UserCertAsyncContext context)
336 {
337     napi_value promise = nullptr;
338     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
339 
340     napi_value resourceName = nullptr;
341     NAPI_CALL(env, napi_create_string_latin1(env, "uninstallUserCertAsyncWork", NAPI_AUTO_LENGTH, &resourceName));
342 
343     NAPI_CALL(env, napi_create_async_work(
344         env, nullptr, resourceName,
345         UninstallUserCertExecute,
346         UninstallComplete,
347         static_cast<void *>(context),
348         &context->asyncWork));
349 
350     napi_status status = napi_queue_async_work(env, context->asyncWork);
351     if (status != napi_ok) {
352         ThrowError(env, PARAM_ERROR, "queue async work error");
353         CM_LOG_E("queue async work failed when uninstalling user cert");
354         return nullptr;
355     }
356     return promise;
357 }
358 
UninstallAllUserCertExecute(napi_env env,void * data)359 static void UninstallAllUserCertExecute(napi_env env, void *data)
360 {
361     UserCertAsyncContext context = static_cast<UserCertAsyncContext>(data);
362     context->errCode = CmUninstallAllUserTrustedCert();
363 }
364 
UninstallAllUserCertAsyncWork(napi_env env,UserCertAsyncContext context)365 static napi_value UninstallAllUserCertAsyncWork(napi_env env, UserCertAsyncContext context)
366 {
367     napi_value promise = nullptr;
368     GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
369 
370     napi_value resourceName = nullptr;
371     NAPI_CALL(env, napi_create_string_latin1(env, "uninstallAllUserCertAsyncWork", NAPI_AUTO_LENGTH, &resourceName));
372 
373     NAPI_CALL(env, napi_create_async_work(
374         env, nullptr, resourceName,
375         UninstallAllUserCertExecute,
376         UninstallComplete,
377         static_cast<void *>(context),
378         &context->asyncWork));
379 
380     napi_status status = napi_queue_async_work(env, context->asyncWork);
381     if (status != napi_ok) {
382         ThrowError(env, PARAM_ERROR, "queue async work error");
383         CM_LOG_E("queue async work failed uninstall all user cert");
384         return nullptr;
385     }
386     return promise;
387 }
388 
CMNapiInstallUserTrustedCert(napi_env env,napi_callback_info info)389 napi_value CMNapiInstallUserTrustedCert(napi_env env, napi_callback_info info)
390 {
391     UserCertAsyncContext context = InitUserCertAsyncContext();
392     if (context == nullptr) {
393         CM_LOG_E("init install user cert context failed");
394         return nullptr;
395     }
396 
397     napi_value result = ParseInstallUserCertParams(env, info, context);
398     if (result == nullptr) {
399         CM_LOG_E("parse install user cert params failed");
400         FreeUserCertAsyncContext(env, context);
401         return nullptr;
402     }
403 
404     result = InstallUserCertAsyncWork(env, context);
405     if (result == nullptr) {
406         CM_LOG_E("start install user cert async work failed");
407         FreeUserCertAsyncContext(env, context);
408         return nullptr;
409     }
410 
411     return result;
412 }
413 
CMNapiUninstallUserTrustedCert(napi_env env,napi_callback_info info)414 napi_value CMNapiUninstallUserTrustedCert(napi_env env, napi_callback_info info)
415 {
416     UserCertAsyncContext context = InitUserCertAsyncContext();
417     if (context == nullptr) {
418         CM_LOG_E("init uninstall user cert context failed");
419         return nullptr;
420     }
421 
422     napi_value result = ParseUninstallUserCertParams(env, info, context);
423     if (result == nullptr) {
424         CM_LOG_E("parse uninstall user cert params failed");
425         FreeUserCertAsyncContext(env, context);
426         return nullptr;
427     }
428 
429     result = UninstallUserCertAsyncWork(env, context);
430     if (result == nullptr) {
431         CM_LOG_E("start uninstall user cert async work failed");
432         FreeUserCertAsyncContext(env, context);
433         return nullptr;
434     }
435 
436     return result;
437 }
438 
CMNapiUninstallAllUserTrustedCert(napi_env env,napi_callback_info info)439 napi_value CMNapiUninstallAllUserTrustedCert(napi_env env, napi_callback_info info)
440 {
441     UserCertAsyncContext context = InitUserCertAsyncContext();
442     if (context == nullptr) {
443         CM_LOG_E("init uninstall all user cert context failed");
444         return nullptr;
445     }
446 
447     napi_value result = ParseUninstallAllUserCertParams(env, info, context);
448     if (result == nullptr) {
449         CM_LOG_E("parse uninstall all user cert params failed");
450         FreeUserCertAsyncContext(env, context);
451         return nullptr;
452     }
453 
454     result = UninstallAllUserCertAsyncWork(env, context);
455     if (result == nullptr) {
456         CM_LOG_E("start uninstall all user cert async work failed");
457         FreeUserCertAsyncContext(env, context);
458         return nullptr;
459     }
460 
461     return result;
462 }
463 }  // namespace CMNapi
464 
465