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> ¶ms)
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> ¶ms)
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 return CF_SUCCESS;
149 }
150
GetInputNumber(napi_env env,napi_value object,size_t index,vector<CfParam> & params)151 static int32_t GetInputNumber(napi_env env, napi_value object, size_t index, vector<CfParam> ¶ms)
152 {
153 CfParam param;
154 napi_status status = napi_get_value_int32(env, object, ¶m.int32Param);
155 if (status != napi_ok) {
156 CF_LOG_E("can not get int value");
157 return CF_INVALID_PARAMS;
158 }
159
160 param.tag = GetTagValue(index, napi_number);
161 params.push_back(param);
162 return CF_SUCCESS;
163 }
164
GetInputParams(napi_env env,napi_value object,size_t index,vector<CfParam> & params)165 static int32_t GetInputParams(napi_env env, napi_value object, size_t index, vector<CfParam> ¶ms)
166 {
167 napi_valuetype valueType = napi_undefined;
168 napi_status status = napi_typeof(env, object, &valueType);
169 if (status != napi_ok) {
170 CF_LOG_E("could not get object type");
171 return CF_INVALID_PARAMS;
172 }
173
174 if (valueType == napi_object) {
175 return GetInputObject(env, object, index, params);
176 } else if (valueType == napi_number) {
177 return GetInputNumber(env, object, index, params);
178 } else {
179 return CF_INVALID_PARAMS;
180 }
181 }
182
AddParams(const vector<CfParam> & params,CfParamSet * & paramSet)183 static int32_t AddParams(const vector<CfParam> ¶ms, CfParamSet *¶mSet)
184 {
185 const CfParam *param = params.data();
186 size_t paramCount = params.size();
187 if (param == nullptr) {
188 return CF_SUCCESS;
189 }
190
191 for (uint32_t i = 0; i < paramCount; ++i) {
192 int32_t ret = CfAddParams(paramSet, param, 1);
193 if (ret != CF_SUCCESS) {
194 CF_LOG_E("add param[%u] failed", i);
195 return ret;
196 }
197 param++;
198 }
199 return CF_SUCCESS;
200 }
201
ConstructInParamSet(const vector<CfParam> & params,CfParamSet * & inParamSet)202 static int32_t ConstructInParamSet(const vector<CfParam> ¶ms, CfParamSet *&inParamSet)
203 {
204 CfParamSet *tmp = NULL;
205 int32_t ret = CfInitParamSet(&tmp);
206 if (ret != CF_SUCCESS) {
207 CF_LOG_E("init paramSet failed");
208 return ret;
209 }
210
211 ret = AddParams(params, tmp);
212 if (ret != CF_SUCCESS) {
213 CfFreeParamSet(&tmp);
214 return ret;
215 }
216
217 ret = CfBuildParamSet(&tmp);
218 if (ret != CF_SUCCESS) {
219 CF_LOG_E("build paramSet failed");
220 CfFreeParamSet(&tmp);
221 return ret;
222 }
223
224 inParamSet = tmp;
225 return CF_SUCCESS;
226 }
227
ConstructTypeParams(int32_t opType,int32_t typeValue,vector<CfParam> & params)228 static void ConstructTypeParams(int32_t opType, int32_t typeValue, vector<CfParam> ¶ms)
229 {
230 CfParam param;
231 if (opType == OPERATION_TYPE_GET) {
232 param.tag = CF_TAG_GET_TYPE;
233 param.int32Param = typeValue;
234 } else { /* is check */
235 param.tag = CF_TAG_CHECK_TYPE;
236 param.int32Param = typeValue;
237 }
238 params.push_back(param);
239 }
240
CheckParamsNapiType(napi_env env,napi_value * argv,size_t argc,napi_valuetype const * expectedType,size_t expectedCnt)241 static int32_t CheckParamsNapiType(napi_env env, napi_value *argv, size_t argc,
242 napi_valuetype const *expectedType, size_t expectedCnt)
243 {
244 if (argc != expectedCnt) {
245 CF_LOG_E("params count invalid");
246 return CF_INVALID_PARAMS;
247 }
248
249 for (size_t i = 0; i < argc; ++i) {
250 napi_valuetype valueType = napi_undefined;
251 napi_status status = napi_typeof(env, argv[i], &valueType);
252 if (status != napi_ok) {
253 CF_LOG_E("could not get object type");
254 return CF_INVALID_PARAMS;
255 }
256
257 if (valueType != expectedType[i]) {
258 CF_LOG_E("input object type invalid");
259 return CF_INVALID_PARAMS;
260 }
261 }
262
263 return CF_SUCCESS;
264 }
265
CheckInputParams(napi_env env,napi_value * argv,size_t argc,int32_t opType,int32_t typeValue)266 static int32_t CheckInputParams(napi_env env, napi_value *argv, size_t argc, int32_t opType, int32_t typeValue)
267 {
268 for (uint32_t i = 0; i < sizeof(INPUT_PARAMS_MAP) / sizeof(INPUT_PARAMS_MAP[0]); ++i) {
269 if ((opType == INPUT_PARAMS_MAP[i].opType) && (typeValue == INPUT_PARAMS_MAP[i].type)) {
270 if (CheckParamsNapiType(env, argv, argc, INPUT_PARAMS_MAP[i].expectedType,
271 INPUT_PARAMS_MAP[i].paramsCnt) != CF_SUCCESS) {
272 return CF_INVALID_PARAMS;
273 }
274 return CF_SUCCESS;
275 }
276 }
277 return CF_INVALID_PARAMS;
278 }
279
GetInParamSet(napi_env env,napi_callback_info info,int32_t opType,int32_t typeValue,CfParamSet * & inParamSet)280 static int32_t GetInParamSet(napi_env env, napi_callback_info info, int32_t opType, int32_t typeValue,
281 CfParamSet *&inParamSet)
282 {
283 size_t argc = MAX_ARGS_COUNT;
284 napi_value argv[MAX_ARGS_COUNT] = { 0 };
285 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
286
287 int32_t ret = CheckInputParams(env, argv, argc, opType, typeValue);
288 if (ret != CF_SUCCESS) {
289 CF_LOG_E("input params invalid");
290 return CF_INVALID_PARAMS;
291 }
292
293 vector<CfParam> params;
294 ConstructTypeParams(opType, typeValue, params);
295
296 for (size_t i = 0; i < argc; ++i) {
297 ret = GetInputParams(env, argv[i], i, params);
298 if (ret != CF_SUCCESS) {
299 FreeParsedParams(params);
300 CF_LOG_E("param[%u] invalid", i);
301 return ret;
302 }
303 }
304
305 /* ext get encoded */
306 if ((typeValue == CF_GET_TYPE_EXT_ITEM) && (argc == 0)) {
307 CfParam paramExtEncoded = { .tag = CF_TAG_PARAM0_INT32, .int32Param = CF_ITEM_ENCODED };
308 params.push_back(paramExtEncoded);
309 }
310
311 ret = ConstructInParamSet(params, inParamSet);
312 FreeParsedParams(params);
313 if (ret != CF_SUCCESS) {
314 CF_LOG_E("construct In paramSet failed");
315 return ret;
316 }
317
318 return CF_SUCCESS;
319 }
320
GetResultType(int32_t opType,int32_t typeValue,CfTag & resultType,uint32_t & outType)321 static int32_t GetResultType(int32_t opType, int32_t typeValue, CfTag &resultType, uint32_t &outType)
322 {
323 for (uint32_t i = 0; i < sizeof(RESULT_MAP) / sizeof(RESULT_MAP[0]); ++i) {
324 if ((typeValue == RESULT_MAP[i].type) && (opType == RESULT_MAP[i].opType)) {
325 resultType = RESULT_MAP[i].resultType;
326 outType = RESULT_MAP[i].outType;
327 return CF_SUCCESS;
328 }
329 }
330 return CF_INVALID_PARAMS;
331 }
332
CheckResultType(const CfParamSet * paramSet,CfTag resultType)333 static int32_t CheckResultType(const CfParamSet *paramSet, CfTag resultType)
334 {
335 CfParam *resultTypeParam = NULL;
336 int32_t ret = CfGetParam(paramSet, CF_TAG_RESULT_TYPE, &resultTypeParam);
337 if (ret != CF_SUCCESS) {
338 CF_LOG_E("get CF_TAG_RESULT_TYPE failed.");
339 return ret;
340 }
341
342 if (resultTypeParam->int32Param != (resultType & CF_TAG_TYPE_MASK)) {
343 CF_LOG_E("result type[0x%x] is not [0x%x].", resultTypeParam->int32Param, resultType);
344 return CF_INVALID_PARAMS;
345 }
346
347 return CF_SUCCESS;
348 }
349
ConvertToNapiValue(napi_env env,int32_t opType,int32_t typeValue,const CfParamSet * paramSet)350 static napi_value ConvertToNapiValue(napi_env env, int32_t opType, int32_t typeValue, const CfParamSet *paramSet)
351 {
352 CfTag resultType = CF_TAG_INVALID;
353 uint32_t outType = 0;
354 int32_t ret = GetResultType(opType, typeValue, resultType, outType);
355 if (ret != CF_SUCCESS) {
356 CF_LOG_E("get result type failed.");
357 return nullptr;
358 }
359
360 ret = CheckResultType(paramSet, resultType);
361 if (ret != CF_SUCCESS) {
362 return nullptr;
363 }
364
365 CfParam *resultParam = NULL;
366 ret = CfGetParam(paramSet, resultType, &resultParam);
367 if (ret != CF_SUCCESS) {
368 CF_LOG_E("get [0x%x] from param failed.", resultType);
369 return nullptr;
370 }
371
372 if (outType == NAPI_OUT_TYPE_BLOB) {
373 return CertConvertBlobToNapiValue(env, &resultParam->blob);
374 } else if (outType == NAPI_OUT_TYPE_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