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> ¶ms)
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> ¶ms)
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> ¶ms)
147 {
148 CfParam param;
149 napi_status status = napi_get_value_int32(env, object, ¶m.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> ¶ms)
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> ¶ms, CfParamSet *¶mSet)
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> ¶ms, 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> ¶ms)
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