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