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