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