• 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_object.h"
17 
18 #include "securec.h"
19 
20 #include "cf_log.h"
21 #include "cf_memory.h"
22 #include "cf_param.h"
23 #include "cf_result.h"
24 
25 #include "napi_cert_utils.h"
26 #include "napi_common.h"
27 
28 using namespace std;
29 
30 namespace OHOS {
31 namespace CertFramework {
32 constexpr size_t MAX_ARGS_COUNT = 5;
33 
34 constexpr uint32_t NAPI_OUT_TYPE_BLOB = 1;
35 constexpr uint32_t NAPI_OUT_TYPE_ARRAY = 2;
36 constexpr uint32_t NAPI_OUT_TYPE_NUMBER = 3;
37 constexpr uint32_t NAPI_OUT_TYPE_ENCODING_BLOB = 4;
38 constexpr uint32_t NAPI_OUT_TYPE_BOOL = 5;
39 
40 constexpr size_t PARAM_INDEX_0 = 0;
41 constexpr size_t PARAM_INDEX_1 = 1;
42 constexpr size_t PARAM_INDEX_2 = 2;
43 constexpr size_t PARAM_INDEX_3 = 3;
44 constexpr size_t PARAM_INDEX_4 = 4;
45 
46 constexpr size_t PARAM_COUNT_CERT_GET_ITEM = 1;
47 constexpr size_t PARAM_COUNT_EXT_GET_OIDS = 1;
48 constexpr size_t PARAM_COUNT_EXT_GET_ENTRY = 2;
49 constexpr size_t PARAM_COUNT_EXT_GET_ITEM = 0;
50 constexpr size_t PARAM_COUNT_EXT_CHECK_CA = 0;
51 constexpr size_t PARAM_COUNT_EXT_HAS_UN_SUPPORT = 0;
52 
53 struct CfInputParamsMap {
54     int32_t opType;
55     int32_t type;
56     size_t paramsCnt;
57     napi_valuetype expectedType[MAX_ARGS_COUNT];
58 };
59 
60 struct CfParamTagMap {
61     size_t index;
62     napi_valuetype valueType;
63     CfTag tag;
64 };
65 
66 struct CfResultMap {
67     int32_t opType;
68     int32_t type;
69     CfTag resultType;
70     uint32_t outType;
71 };
72 
73 const struct CfInputParamsMap INPUT_PARAMS_MAP[] = {
74     { OPERATION_TYPE_GET, CF_GET_TYPE_CERT_ITEM, PARAM_COUNT_CERT_GET_ITEM, { napi_number } },
75     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_OIDS, PARAM_COUNT_EXT_GET_OIDS, { napi_number } },
76     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ENTRY, PARAM_COUNT_EXT_GET_ENTRY, { napi_number, napi_object } },
77     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ITEM, PARAM_COUNT_EXT_GET_ITEM, { napi_undefined } },
78     { OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_CA, PARAM_COUNT_EXT_CHECK_CA, { napi_undefined } },
79     { OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_HAS_UN_SUPPORT, PARAM_COUNT_EXT_HAS_UN_SUPPORT, { napi_undefined } },
80 };
81 
82 const struct CfParamTagMap TAG_MAP[] = {
83     { PARAM_INDEX_0, napi_object, CF_TAG_PARAM0_BUFFER },
84     { PARAM_INDEX_1, napi_object, CF_TAG_PARAM1_BUFFER },
85     { PARAM_INDEX_2, napi_object, CF_TAG_PARAM2_BUFFER },
86     { PARAM_INDEX_3, napi_object, CF_TAG_PARAM3_BUFFER },
87     { PARAM_INDEX_4, napi_object, CF_TAG_PARAM4_BUFFER },
88     { PARAM_INDEX_0, napi_number, CF_TAG_PARAM0_INT32 },
89     { PARAM_INDEX_1, napi_number, CF_TAG_PARAM1_INT32 },
90     { PARAM_INDEX_2, napi_number, CF_TAG_PARAM2_INT32 },
91     { PARAM_INDEX_3, napi_number, CF_TAG_PARAM3_INT32 },
92     { PARAM_INDEX_4, napi_number, CF_TAG_PARAM4_INT32 },
93 };
94 
95 const struct CfResultMap RESULT_MAP[] = {
96     { OPERATION_TYPE_GET, CF_GET_TYPE_CERT_ITEM, CF_TAG_RESULT_BYTES, NAPI_OUT_TYPE_BLOB },
97     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_OIDS, CF_TAG_RESULT_BYTES, NAPI_OUT_TYPE_ARRAY },
98     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ENTRY, CF_TAG_RESULT_BYTES, NAPI_OUT_TYPE_BLOB },
99     { OPERATION_TYPE_GET, CF_GET_TYPE_EXT_ITEM, CF_TAG_RESULT_BYTES, NAPI_OUT_TYPE_ENCODING_BLOB },
100     { OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_CA, CF_TAG_RESULT_INT, NAPI_OUT_TYPE_NUMBER },
101     { OPERATION_TYPE_CHECK, CF_CHECK_TYPE_EXT_HAS_UN_SUPPORT, CF_TAG_RESULT_BOOL, NAPI_OUT_TYPE_BOOL },
102 };
103 
FreeParsedParams(vector<CfParam> & params)104 static void FreeParsedParams(vector<CfParam> &params)
105 {
106     CfParam *param = params.data();
107     size_t paramCount = params.size();
108     if (param == nullptr) {
109         return;
110     }
111     while (paramCount > 0) {
112         paramCount--;
113         if ((param->tag & CF_TAG_TYPE_MASK) == CF_TAG_TYPE_BYTES) {
114             CF_FREE_PTR(param->blob.data);
115             param->blob.size = 0;
116         }
117         ++param;
118     }
119 }
120 
GetTagValue(size_t index,napi_valuetype valueType)121 static CfTag GetTagValue(size_t index, napi_valuetype valueType)
122 {
123     uint32_t count = sizeof(TAG_MAP) / sizeof(TAG_MAP[0]);
124     for (uint32_t i = 0; i < count; ++i) {
125         if ((index == TAG_MAP[i].index) && (valueType == TAG_MAP[i].valueType)) {
126             return TAG_MAP[i].tag;
127         }
128     }
129     return CF_TAG_INVALID;
130 }
131 
GetInputObject(napi_env env,napi_value object,size_t index,vector<CfParam> & params)132 static int32_t GetInputObject(napi_env env, napi_value object, size_t index, vector<CfParam> &params)
133 {
134     CfBlob *inBlob = CertGetBlobFromNapiValue(env, object);
135     if (inBlob == nullptr) {
136         CF_LOG_E("get blob failed");
137         return CF_INVALID_PARAMS;
138     }
139 
140     CfParam param;
141     param.tag = GetTagValue(index, napi_object);
142     param.blob.data = inBlob->data;
143     param.blob.size = inBlob->size;
144     params.push_back(param);
145 
146     CfFree(inBlob); /* inBlob's data need freed by caller */
147     return CF_SUCCESS;
148 }
149 
GetInputNumber(napi_env env,napi_value object,size_t index,vector<CfParam> & params)150 static int32_t GetInputNumber(napi_env env, napi_value object, size_t index, vector<CfParam> &params)
151 {
152     CfParam param;
153     napi_status status = napi_get_value_int32(env, object, &param.int32Param);
154     if (status != napi_ok) {
155         CF_LOG_E("can not get int value");
156         return CF_INVALID_PARAMS;
157     }
158 
159     param.tag = GetTagValue(index, napi_number);
160     params.push_back(param);
161     return CF_SUCCESS;
162 }
163 
GetInputParams(napi_env env,napi_value object,size_t index,vector<CfParam> & params)164 static int32_t GetInputParams(napi_env env, napi_value object, size_t index, vector<CfParam> &params)
165 {
166     napi_valuetype valueType = napi_undefined;
167     napi_status status = napi_typeof(env, object, &valueType);
168     if (status != napi_ok) {
169         CF_LOG_E("could not get object type");
170         return CF_INVALID_PARAMS;
171     }
172 
173     if (valueType == napi_object) {
174         return GetInputObject(env, object, index, params);
175     } else if (valueType == napi_number) {
176         return GetInputNumber(env, object, index, params);
177     } else {
178         return CF_INVALID_PARAMS;
179     }
180 }
181 
AddParams(const vector<CfParam> & params,CfParamSet * & paramSet)182 static int32_t AddParams(const vector<CfParam> &params, CfParamSet *&paramSet)
183 {
184     const CfParam *param = params.data();
185     size_t paramCount = params.size();
186     if (param == nullptr) {
187         return CF_SUCCESS;
188     }
189 
190     for (uint32_t i = 0; i < paramCount; ++i) {
191         int32_t ret = CfAddParams(paramSet, param, 1);
192         if (ret != CF_SUCCESS) {
193             CF_LOG_E("add param[%u] failed", i);
194             return ret;
195         }
196         param++;
197     }
198     return CF_SUCCESS;
199 }
200 
ConstructInParamSet(const vector<CfParam> & params,CfParamSet * & inParamSet)201 static int32_t ConstructInParamSet(const vector<CfParam> &params, CfParamSet *&inParamSet)
202 {
203     CfParamSet *tmp = NULL;
204     int32_t ret = CfInitParamSet(&tmp);
205     if (ret != CF_SUCCESS) {
206         CF_LOG_E("init paramSet failed");
207         return ret;
208     }
209 
210     ret = AddParams(params, tmp);
211     if (ret != CF_SUCCESS) {
212         CfFreeParamSet(&tmp);
213         return ret;
214     }
215 
216     ret = CfBuildParamSet(&tmp);
217     if (ret != CF_SUCCESS) {
218         CF_LOG_E("build paramSet failed");
219         CfFreeParamSet(&tmp);
220         return ret;
221     }
222 
223     inParamSet = tmp;
224     return CF_SUCCESS;
225 }
226 
ConstructTypeParams(int32_t opType,int32_t typeValue,vector<CfParam> & params)227 static void ConstructTypeParams(int32_t opType, int32_t typeValue, vector<CfParam> &params)
228 {
229     CfParam param;
230     if (opType == OPERATION_TYPE_GET) {
231         param.tag = CF_TAG_GET_TYPE;
232         param.int32Param = typeValue;
233     } else { /* is check */
234         param.tag = CF_TAG_CHECK_TYPE;
235         param.int32Param = typeValue;
236     }
237     params.push_back(param);
238 }
239 
CheckParamsNapiType(napi_env env,napi_value * argv,size_t argc,napi_valuetype const * expectedType,size_t expectedCnt)240 static int32_t CheckParamsNapiType(napi_env env, napi_value *argv, size_t argc,
241     napi_valuetype const *expectedType, size_t expectedCnt)
242 {
243     if (argc != expectedCnt) {
244         CF_LOG_E("params count invalid");
245         return CF_INVALID_PARAMS;
246     }
247 
248     for (size_t i = 0; i < argc; ++i) {
249         napi_valuetype valueType = napi_undefined;
250         napi_status status = napi_typeof(env, argv[i], &valueType);
251         if (status != napi_ok) {
252             CF_LOG_E("could not get object type");
253             return CF_INVALID_PARAMS;
254         }
255 
256         if (valueType != expectedType[i]) {
257             CF_LOG_E("input object type invalid");
258             return CF_INVALID_PARAMS;
259         }
260     }
261 
262     return CF_SUCCESS;
263 }
264 
CheckInputParams(napi_env env,napi_value * argv,size_t argc,int32_t opType,int32_t typeValue)265 static int32_t CheckInputParams(napi_env env, napi_value *argv, size_t argc, int32_t opType, int32_t typeValue)
266 {
267     for (uint32_t i = 0; i < sizeof(INPUT_PARAMS_MAP) / sizeof(INPUT_PARAMS_MAP[0]); ++i) {
268         if ((opType == INPUT_PARAMS_MAP[i].opType) && (typeValue == INPUT_PARAMS_MAP[i].type)) {
269             if (CheckParamsNapiType(env, argv, argc, INPUT_PARAMS_MAP[i].expectedType,
270                 INPUT_PARAMS_MAP[i].paramsCnt) != CF_SUCCESS) {
271                 return CF_INVALID_PARAMS;
272             }
273             return CF_SUCCESS;
274         }
275     }
276     return CF_INVALID_PARAMS;
277 }
278 
GetInParamSet(napi_env env,napi_callback_info info,int32_t opType,int32_t typeValue,CfParamSet * & inParamSet)279 static int32_t GetInParamSet(napi_env env, napi_callback_info info, int32_t opType, int32_t typeValue,
280     CfParamSet *&inParamSet)
281 {
282     size_t argc = MAX_ARGS_COUNT;
283     napi_value argv[MAX_ARGS_COUNT] = { 0 };
284     napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
285 
286     int32_t ret = CheckInputParams(env, argv, argc, opType, typeValue);
287     if (ret != CF_SUCCESS) {
288         CF_LOG_E("input params invalid");
289         return CF_INVALID_PARAMS;
290     }
291 
292     vector<CfParam> params;
293     ConstructTypeParams(opType, typeValue, params);
294 
295     for (size_t i = 0; i < argc; ++i) {
296         ret = GetInputParams(env, argv[i], i, params);
297         if (ret != CF_SUCCESS) {
298             FreeParsedParams(params);
299             CF_LOG_E("param[%u] invalid", i);
300             return ret;
301         }
302     }
303 
304     /* ext get encoded */
305     if ((typeValue == CF_GET_TYPE_EXT_ITEM) && (argc == 0)) {
306         CfParam paramExtEncoded = { .tag = CF_TAG_PARAM0_INT32, .int32Param = CF_ITEM_ENCODED };
307         params.push_back(paramExtEncoded);
308     }
309 
310     ret = ConstructInParamSet(params, inParamSet);
311     FreeParsedParams(params);
312     if (ret != CF_SUCCESS) {
313         CF_LOG_E("construct In paramSet failed");
314         return ret;
315     }
316 
317     return CF_SUCCESS;
318 }
319 
GetResultType(int32_t opType,int32_t typeValue,CfTag & resultType,uint32_t & outType)320 static int32_t GetResultType(int32_t opType, int32_t typeValue, CfTag &resultType, uint32_t &outType)
321 {
322     for (uint32_t i = 0; i < sizeof(RESULT_MAP) / sizeof(RESULT_MAP[0]); ++i) {
323         if ((typeValue == RESULT_MAP[i].type) && (opType == RESULT_MAP[i].opType)) {
324             resultType = RESULT_MAP[i].resultType;
325             outType = RESULT_MAP[i].outType;
326             return CF_SUCCESS;
327         }
328     }
329     return CF_INVALID_PARAMS;
330 }
331 
CheckResultType(const CfParamSet * paramSet,CfTag resultType)332 static int32_t CheckResultType(const CfParamSet *paramSet, CfTag resultType)
333 {
334     CfParam *resultTypeParam = NULL;
335     int32_t ret = CfGetParam(paramSet, CF_TAG_RESULT_TYPE, &resultTypeParam);
336     if (ret != CF_SUCCESS) {
337         CF_LOG_E("get CF_TAG_RESULT_TYPE failed.");
338         return ret;
339     }
340 
341     if (resultTypeParam->int32Param != (resultType & CF_TAG_TYPE_MASK)) {
342         CF_LOG_E("result type[0x%x] is not [0x%x].", resultTypeParam->int32Param, resultType);
343         return CF_INVALID_PARAMS;
344     }
345 
346     return CF_SUCCESS;
347 }
348 
ConvertToNapiValue(napi_env env,int32_t opType,int32_t typeValue,const CfParamSet * paramSet)349 static napi_value ConvertToNapiValue(napi_env env, int32_t opType, int32_t typeValue, const CfParamSet *paramSet)
350 {
351     CfTag resultType = CF_TAG_INVALID;
352     uint32_t outType = 0;
353     int32_t ret = GetResultType(opType, typeValue, resultType, outType);
354     if (ret != CF_SUCCESS) {
355         CF_LOG_E("get result type failed.");
356         return nullptr;
357     }
358 
359     ret = CheckResultType(paramSet, resultType);
360     if (ret != CF_SUCCESS) {
361         return nullptr;
362     }
363 
364     CfParam *resultParam = NULL;
365     ret = CfGetParam(paramSet, resultType, &resultParam);
366     if (ret != CF_SUCCESS) {
367         CF_LOG_E("get [0x%x] from param failed.", resultType);
368         return nullptr;
369     }
370 
371     if (outType == NAPI_OUT_TYPE_BLOB) {
372         return CertConvertBlobToNapiValue(env, &resultParam->blob);
373     } else if (outType == NAPI_OUT_TYPE_ARRAY) {
374         CF_LOG_I("blob array");
375         return ConvertBlobArrayToNapiValue(env, paramSet);
376     } else if (outType == NAPI_OUT_TYPE_NUMBER) {
377         napi_value result = nullptr;
378         napi_create_int32(env, resultParam->int32Param, &result);
379         return result;
380     } else if (outType == NAPI_OUT_TYPE_ENCODING_BLOB) {
381         CfEncodingBlob encoded = { resultParam->blob.data, resultParam->blob.size, CF_FORMAT_DER };
382         return ConvertEncodingBlobToNapiValue(env, &encoded);
383     } else if (outType == NAPI_OUT_TYPE_BOOL) {
384         napi_value result = nullptr;
385         napi_get_boolean(env, resultParam->boolParam, &result);
386         return result;
387     }
388 
389     return nullptr;
390 }
391 
DoOperation(const CfObject * obj,int32_t opType,const CfParamSet * inParamSet,CfParamSet ** outParamSet)392 static int32_t DoOperation(const CfObject *obj, int32_t opType, const CfParamSet *inParamSet,
393     CfParamSet **outParamSet)
394 {
395     int32_t ret = CF_INVALID_PARAMS;
396     if (opType == OPERATION_TYPE_GET) {
397         ret = obj->get(obj, inParamSet, outParamSet);
398     } else if (opType == OPERATION_TYPE_CHECK) {
399         ret = obj->check(obj, inParamSet, outParamSet);
400     }
401     if (ret != CF_SUCCESS) {
402         CF_LOG_E("do operation[%d] failed", opType);
403     }
404     return ret;
405 }
406 
CommonOperation(napi_env env,napi_callback_info info,const CfObject * obj,int32_t opType,int32_t typeValue)407 napi_value CommonOperation(napi_env env, napi_callback_info info, const CfObject *obj,
408     int32_t opType, int32_t typeValue)
409 {
410     CfParamSet *inParamSet = NULL;
411     int32_t ret = GetInParamSet(env, info, opType, typeValue, inParamSet);
412     if (ret != CF_SUCCESS) {
413         napi_throw(env, CertGenerateBusinessError(env, ret, "get param failed"));
414         return nullptr;
415     }
416 
417     CfParamSet *outParamSet = NULL;
418     ret = DoOperation(obj, opType, inParamSet, &outParamSet);
419     CfFreeParamSet(&inParamSet);
420     if (ret != CF_SUCCESS) {
421         napi_throw(env, CertGenerateBusinessError(env, ret, "do operation failed"));
422         return nullptr;
423     }
424 
425     napi_value returnValue = ConvertToNapiValue(env, opType, typeValue, outParamSet);
426     if (returnValue == nullptr) {
427         napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "construct result failed"));
428     }
429     CfFreeParamSet(&outParamSet);
430     return returnValue;
431 }
432 }  // namespace CertFramework
433 }  // namespace OHOS
434