1 /*
2 * Copyright (c) 2023-2024 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_cert_utils.h"
17 #include <string>
18 #include "cf_log.h"
19 #include "cf_memory.h"
20 #include "cipher.h"
21 #include "config.h"
22 #include "detailed_ccm_params.h"
23 #include "detailed_gcm_params.h"
24 #include "detailed_iv_params.h"
25 #include "napi_cert_defines.h"
26 #include "securec.h"
27 #include "utils.h"
28
29 namespace OHOS {
30 namespace CertFramework {
31 using namespace std;
32
33 struct CfResultCodeMap {
34 CfResult retValue;
35 ResultCode retCode;
36 };
37
38 const struct CfResultCodeMap CODE_MAP[] = {
39 { CF_SUCCESS, JS_SUCCESS },
40 { CF_INVALID_PARAMS, JS_ERR_CERT_INVALID_PARAMS },
41 { CF_NOT_SUPPORT, JS_ERR_CERT_NOT_SUPPORT },
42 { CF_ERR_MALLOC, JS_ERR_CERT_OUT_OF_MEMORY },
43 { CF_ERR_CRYPTO_OPERATION, JS_ERR_CERT_CRYPTO_OPERATION },
44 { CF_ERR_CERT_SIGNATURE_FAILURE, JS_ERR_CERT_SIGNATURE_FAILURE },
45 { CF_ERR_CERT_NOT_YET_VALID, JS_ERR_CERT_NOT_YET_VALID },
46 { CF_ERR_CERT_HAS_EXPIRED, JS_ERR_CERT_HAS_EXPIRED },
47 { CF_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, JS_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY },
48 { CF_ERR_KEYUSAGE_NO_CERTSIGN, JS_ERR_KEYUSAGE_NO_CERTSIGN },
49 { CF_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, JS_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE },
50 };
51
CertNapiGetNull(napi_env env)52 napi_value CertNapiGetNull(napi_env env)
53 {
54 napi_value result = nullptr;
55 napi_get_null(env, &result);
56 return result;
57 }
58
ConvertArrayToNapiValue(napi_env env,CfArray * array)59 napi_value ConvertArrayToNapiValue(napi_env env, CfArray *array)
60 {
61 if (array == nullptr) {
62 LOGE("array is null!");
63 return nullptr;
64 }
65 if (array->count == 0) {
66 LOGE("array count is 0!");
67 return nullptr;
68 }
69 napi_value returnArray = nullptr;
70 napi_create_array(env, &returnArray);
71 if (returnArray == nullptr) {
72 LOGE("create return array failed!");
73 return nullptr;
74 }
75 for (uint32_t i = 0; i < array->count; i++) {
76 CfBlob *blob = reinterpret_cast<CfBlob *>(array->data + i);
77 napi_value outBuffer = GenerateArrayBuffer(env, blob->data, blob->size);
78 if (outBuffer == nullptr) {
79 LOGE("generate array buffer failed!");
80 return nullptr;
81 }
82 napi_value element = nullptr;
83 napi_create_typedarray(env, napi_uint8_array, blob->size, outBuffer, 0, &element);
84 napi_set_element(env, returnArray, i, element);
85 }
86 napi_value returnValue = nullptr;
87 napi_create_object(env, &returnValue);
88 napi_set_named_property(env, returnValue, CERT_TAG_DATA.c_str(), returnArray);
89 return returnValue;
90 }
91
GenerateArrayBuffer(napi_env env,uint8_t * data,uint32_t size)92 napi_value GenerateArrayBuffer(napi_env env, uint8_t *data, uint32_t size)
93 {
94 uint8_t *buffer = static_cast<uint8_t *>(CfMalloc(size, 0));
95 if (buffer == nullptr) {
96 LOGE("malloc uint8 array buffer failed!");
97 return nullptr;
98 }
99
100 if (memcpy_s(buffer, size, data, size) != EOK) {
101 LOGE("memcpy_s data to buffer failed!");
102 CfFree(buffer);
103 return nullptr;
104 }
105
106 napi_value outBuffer = nullptr;
107 napi_status status = napi_create_external_arraybuffer(
108 env, buffer, size, [](napi_env env, void *data, void *hint) { CfFree(data); }, nullptr, &outBuffer);
109 if (status != napi_ok) {
110 LOGE("create uint8 array buffer failed!");
111 CfFree(buffer);
112 return nullptr;
113 }
114 buffer = nullptr;
115 return outBuffer;
116 }
117
GetDataOfEncodingBlob(napi_env env,napi_value data,CfEncodingBlob * encodingBlob)118 static bool GetDataOfEncodingBlob(napi_env env, napi_value data, CfEncodingBlob *encodingBlob)
119 {
120 napi_typedarray_type arrayType;
121 napi_value arrayBuffer = nullptr;
122 size_t length = 0;
123 size_t offset = 0;
124 void *rawData = nullptr;
125
126 napi_status status = napi_get_typedarray_info(env, data, &arrayType, &length,
127 reinterpret_cast<void **>(&rawData), &arrayBuffer, &offset);
128 if (status != napi_ok) {
129 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get array data failed"));
130 LOGE("failed to get array data!");
131 return false;
132 }
133 if (arrayType != napi_uint8_array) {
134 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "array type is not uint8 array"));
135 LOGE("array is not uint8 array!");
136 return false;
137 }
138
139 if (length == 0) {
140 LOGE("input data length is 0");
141 return false;
142 }
143 encodingBlob->data = static_cast<uint8_t *>(CfMalloc(length, 0));
144 if (encodingBlob->data == nullptr) {
145 LOGE("malloc encoding blob data failed!");
146 return false;
147 }
148 if (memcpy_s(encodingBlob->data, length, rawData, length) != EOK) {
149 LOGE("memcpy_s encoding blob data failed!");
150 CfFree(encodingBlob->data);
151 encodingBlob->data = nullptr;
152 return false;
153 }
154 encodingBlob->len = length;
155 return true;
156 }
157
GetEncodingBlobFromValue(napi_env env,napi_value obj,CfEncodingBlob ** encodingBlob)158 bool GetEncodingBlobFromValue(napi_env env, napi_value obj, CfEncodingBlob **encodingBlob)
159 {
160 *encodingBlob = static_cast<CfEncodingBlob *>(CfMalloc(sizeof(CfEncodingBlob), 0));
161 if (*encodingBlob == nullptr) {
162 LOGE("malloc encoding blob failed!");
163 return false;
164 }
165 napi_value data = nullptr;
166 napi_status status = napi_get_named_property(env, obj, CERT_TAG_DATA.c_str(), &data);
167 if (status != napi_ok) {
168 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get encoding blob data failed"));
169 LOGE("failed to get encoding blob data!");
170 CfFree(*encodingBlob);
171 *encodingBlob = nullptr;
172 return false;
173 }
174 if (!GetDataOfEncodingBlob(env, data, *encodingBlob)) {
175 CfFree(*encodingBlob);
176 *encodingBlob = nullptr;
177 return false;
178 }
179 napi_value format = nullptr;
180 status = napi_get_named_property(env, obj, CERT_TAG_ENCODING_FORMAT.c_str(), &format);
181 if (status != napi_ok) {
182 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get encoding blob format failed"));
183 LOGE("failed to get encoding blob format!");
184 CfFree((*encodingBlob)->data);
185 (*encodingBlob)->data = nullptr;
186 CfFree(*encodingBlob);
187 *encodingBlob = nullptr;
188 return false;
189 }
190 napi_get_value_uint32(env, format, reinterpret_cast<uint32_t *>(&(*encodingBlob)->encodingFormat));
191 return true;
192 }
193
ConvertEncodingBlobToNapiValue(napi_env env,CfEncodingBlob * encodingBlob)194 napi_value ConvertEncodingBlobToNapiValue(napi_env env, CfEncodingBlob *encodingBlob)
195 {
196 napi_value outBuffer = GenerateArrayBuffer(env, encodingBlob->data, encodingBlob->len);
197 if (outBuffer == nullptr) {
198 LOGE("generate array buffer failed!");
199 return nullptr;
200 }
201 napi_value outData = nullptr;
202 napi_create_typedarray(env, napi_uint8_array, encodingBlob->len, outBuffer, 0, &outData);
203 napi_value encoding = nullptr;
204 napi_create_uint32(env, encodingBlob->encodingFormat, &encoding);
205 napi_value returnEncodingBlob = nullptr;
206 napi_create_object(env, &returnEncodingBlob);
207 napi_set_named_property(env, returnEncodingBlob, CERT_TAG_DATA.c_str(), outData);
208 napi_set_named_property(env, returnEncodingBlob, CERT_TAG_ENCODING_FORMAT.c_str(), encoding);
209 return returnEncodingBlob;
210 }
211
CertGetBlobFromNapiValue(napi_env env,napi_value arg)212 CfBlob *CertGetBlobFromNapiValue(napi_env env, napi_value arg)
213 {
214 if ((env == nullptr) || (arg == nullptr)) {
215 LOGE("Invalid parmas!");
216 return nullptr;
217 }
218 napi_value data = nullptr;
219 napi_status status = napi_get_named_property(env, arg, CERT_TAG_DATA.c_str(), &data);
220 if ((status != napi_ok) || (data == nullptr)) {
221 LOGE("failed to get valid data property!");
222 return nullptr;
223 }
224 return CertGetBlobFromUint8ArrJSParams(env, data);
225 }
226
CertConvertBlobToNapiValue(napi_env env,CfBlob * blob)227 napi_value CertConvertBlobToNapiValue(napi_env env, CfBlob *blob)
228 {
229 napi_value outData = ConvertBlobToUint8ArrNapiValue(env, blob);
230 if (outData == nullptr) {
231 LOGE("convert to uint8 arr failed");
232 return nullptr;
233 }
234 napi_value dataBlob = nullptr;
235 napi_create_object(env, &dataBlob);
236 napi_set_named_property(env, dataBlob, CERT_TAG_DATA.c_str(), outData);
237
238 return dataBlob;
239 }
240
ConvertBlobToUint8ArrNapiValue(napi_env env,CfBlob * blob)241 napi_value ConvertBlobToUint8ArrNapiValue(napi_env env, CfBlob *blob)
242 {
243 if (blob == nullptr || blob->data == nullptr || blob->size == 0) {
244 LOGE("Invalid blob!");
245 return nullptr;
246 }
247 /* free in napi_create_external_arraybuffer, not in this scope. */
248 uint8_t *buffer = static_cast<uint8_t *>(CfMalloc(blob->size, 0));
249 if (buffer == nullptr) {
250 LOGE("malloc uint8 array buffer failed!");
251 return nullptr;
252 }
253
254 if (memcpy_s(buffer, blob->size, blob->data, blob->size) != EOK) {
255 LOGE("memcpy_s data to buffer failed!");
256 CfFree(buffer);
257 return nullptr;
258 }
259
260 napi_value outBuffer = nullptr;
261 napi_status status = napi_create_external_arraybuffer(
262 env, buffer, blob->size, [](napi_env env, void *data, void *hint) { CfFree(data); }, nullptr, &outBuffer);
263 if (status != napi_ok) {
264 LOGE("create uint8 array buffer failed!");
265 CfFree(buffer);
266 return nullptr;
267 }
268 buffer = nullptr;
269
270 napi_value outData = nullptr;
271 napi_create_typedarray(env, napi_uint8_array, blob->size, outBuffer, 0, &outData);
272
273 return outData;
274 }
275
GetDataOfCertChain(napi_env env,napi_value data,HcfCertChainData * certChain)276 static bool GetDataOfCertChain(napi_env env, napi_value data, HcfCertChainData *certChain)
277 {
278 napi_typedarray_type arrayType;
279 napi_value arrayBuffer = nullptr;
280 size_t length = 0;
281 size_t offset = 0;
282 void *rawData = nullptr;
283
284 napi_status status = napi_get_typedarray_info(env, data, &arrayType, &length,
285 reinterpret_cast<void **>(&rawData), &arrayBuffer, &offset);
286 if (status != napi_ok) {
287 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get array data failed"));
288 LOGE("failed to get array data!");
289 return false;
290 }
291 if (arrayType != napi_uint8_array) {
292 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "array type is not uint8 array"));
293 LOGE("array is not uint8 array!");
294 return false;
295 }
296
297 if (length == 0) {
298 LOGE("input data length is 0");
299 return false;
300 }
301 certChain->data = static_cast<uint8_t *>(CfMalloc(length, 0));
302 if (certChain->data == nullptr) {
303 LOGE("malloc cert chain data failed!");
304 return false;
305 }
306 if (memcpy_s(certChain->data, length, rawData, length) != EOK) {
307 LOGE("memcpy_s cert chain data failed!");
308 CfFree(certChain->data);
309 certChain->data = nullptr;
310 return false;
311 }
312 certChain->dataLen = length;
313 return true;
314 }
315
GetCertChainFromValue(napi_env env,napi_value obj,HcfCertChainData ** certChainData)316 bool GetCertChainFromValue(napi_env env, napi_value obj, HcfCertChainData **certChainData)
317 {
318 *certChainData = static_cast<HcfCertChainData *>(CfMalloc(sizeof(HcfCertChainData), 0));
319 if (*certChainData == nullptr) {
320 LOGE("malloc certChainData failed!");
321 return false;
322 }
323 napi_value data = nullptr;
324 napi_status status = napi_get_named_property(env, obj, CERT_TAG_DATA.c_str(), &data);
325 if (status != napi_ok) {
326 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert chain data failed"));
327 LOGE("failed to get cert chain data!");
328 CfFree(*certChainData);
329 *certChainData = nullptr;
330 return false;
331 }
332 if (!GetDataOfCertChain(env, data, *certChainData)) {
333 CfFree(*certChainData);
334 *certChainData = nullptr;
335 return false;
336 }
337
338 napi_value certCount = nullptr;
339 status = napi_get_named_property(env, obj, CERT_TAG_COUNT.c_str(), &certCount);
340 if (status != napi_ok) {
341 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert chain count failed"));
342 LOGE("failed to get cert count!");
343 CfFree((*certChainData)->data);
344 (*certChainData)->data = nullptr;
345 CfFree(*certChainData);
346 *certChainData = nullptr;
347 return false;
348 }
349 napi_get_value_uint32(env, certCount, reinterpret_cast<uint32_t *>(&(*certChainData)->count));
350
351 napi_value format = nullptr;
352 status = napi_get_named_property(env, obj, CERT_TAG_ENCODING_FORMAT.c_str(), &format);
353 if (status != napi_ok) {
354 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get cert chain format failed"));
355 LOGE("failed to get cert chain format!");
356 CfFree((*certChainData)->data);
357 (*certChainData)->data = nullptr;
358 CfFree(*certChainData);
359 *certChainData = nullptr;
360 return false;
361 }
362 napi_get_value_uint32(env, format, reinterpret_cast<uint32_t *>(&(*certChainData)->format));
363 return true;
364 }
365
CertGetBlobFromUint8ArrJSParams(napi_env env,napi_value arg)366 CfBlob *CertGetBlobFromUint8ArrJSParams(napi_env env, napi_value arg)
367 {
368 size_t length = 0;
369 size_t offset = 0;
370 void *rawData = nullptr;
371 napi_value arrayBuffer = nullptr;
372 napi_typedarray_type arrayType;
373 // Warning: Do not release the rawData returned by this interface because the rawData is managed by VM.
374 napi_status status = napi_get_typedarray_info(
375 env, arg, &arrayType, &length, reinterpret_cast<void **>(&rawData), &arrayBuffer, &offset);
376 if (status != napi_ok) {
377 LOGE("failed to get valid rawData.");
378 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "failed to get valid rawData!"));
379 return nullptr;
380 }
381 if (arrayType != napi_uint8_array) {
382 LOGE("input data is not uint8 array.");
383 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "input data is not uint8 array!"));
384 return nullptr;
385 }
386
387 if (length == 0 || rawData == nullptr) {
388 LOGE("array length is 0!");
389 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "array length is 0!"));
390 return nullptr;
391 }
392
393 CfBlob *newBlob = static_cast<CfBlob *>(CfMalloc(sizeof(CfBlob), 0));
394 if (newBlob == nullptr) {
395 LOGE("Failed to allocate newBlob memory!");
396 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed!"));
397 return nullptr;
398 }
399
400 newBlob->size = length;
401 newBlob->data = static_cast<uint8_t *>(CfMalloc(length, 0));
402 if (newBlob->data == nullptr) {
403 LOGE("malloc blob data failed!");
404 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed!"));
405 CfFree(newBlob);
406 return nullptr;
407 }
408 if (memcpy_s(newBlob->data, length, rawData, length) != EOK) {
409 LOGE("memcpy_s blob data failed!");
410 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_COPY, "copy memory failed!"));
411 CfFree(newBlob->data);
412 CfFree(newBlob);
413 return nullptr;
414 }
415
416 return newBlob;
417 }
418
CertGetBlobFromStringJSParams(napi_env env,napi_value arg)419 CfBlob *CertGetBlobFromStringJSParams(napi_env env, napi_value arg)
420 {
421 napi_valuetype valueType;
422 napi_typeof(env, arg, &valueType);
423 if (valueType != napi_string) {
424 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type is not string"));
425 LOGE("wrong argument type. expect string type. [Type]: %d", valueType);
426 return nullptr;
427 }
428
429 size_t length = 0;
430 if (napi_get_value_string_utf8(env, arg, nullptr, 0, &length) != napi_ok) {
431 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "can not get string length!"));
432 LOGE("can not get string length");
433 return nullptr;
434 }
435
436 if (length == 0) {
437 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "string length is 0!"));
438 LOGE("string length is 0");
439 return nullptr;
440 }
441
442 CfBlob *newBlob = static_cast<CfBlob *>(CfMalloc(sizeof(CfBlob), 0));
443 if (newBlob == nullptr) {
444 LOGE("Failed to allocate newBlob memory!");
445 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed!"));
446 return nullptr;
447 }
448
449 newBlob->size = length + 1;
450 newBlob->data = static_cast<uint8_t *>(CfMalloc(newBlob->size, 0));
451 if (newBlob->data == nullptr) {
452 LOGE("malloc blob data failed!");
453 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
454 CfFree(newBlob);
455 return nullptr;
456 }
457
458 if (napi_get_value_string_utf8(env, arg, reinterpret_cast<char *>(newBlob->data), newBlob->size, &length) !=
459 napi_ok) {
460 LOGE("can not get string value");
461 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get string failed"));
462 CfFree(newBlob->data);
463 CfFree(newBlob);
464 return nullptr;
465 }
466
467 return newBlob;
468 }
469
GetProp(napi_env env,napi_value arg,const char * name)470 napi_value GetProp(napi_env env, napi_value arg, const char *name)
471 {
472 bool result = false;
473 napi_has_named_property(env, arg, name, &result);
474 if (!result) {
475 LOGI("%s do not exist!", name);
476 return nullptr;
477 }
478 napi_value obj = nullptr;
479 napi_status status = napi_get_named_property(env, arg, name, &obj);
480 if (status != napi_ok || obj == nullptr) {
481 LOGI("get property %s failed!", name);
482 return nullptr;
483 }
484 napi_valuetype valueType;
485 napi_typeof(env, obj, &valueType);
486 if (valueType == napi_undefined) {
487 LOGI("%s valueType is null or undefined.", name);
488 return nullptr;
489 }
490
491 LOGI("%s is not null!", name);
492 return obj;
493 }
494
CertGetBlobArrFromArrUarrJSParams(napi_env env,napi_value arg)495 CfBlobArray *CertGetBlobArrFromArrUarrJSParams(napi_env env, napi_value arg)
496 {
497 bool flag = false;
498 napi_status status = napi_is_array(env, arg, &flag);
499 if (status != napi_ok || !flag) {
500 LOGE("not array!");
501 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "not array!"));
502 return nullptr;
503 }
504 uint32_t length = 0;
505 status = napi_get_array_length(env, arg, &length);
506 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
507 LOGE("length is invalid!");
508 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "length is invalid!"));
509 return nullptr;
510 }
511
512 CfBlobArray *newBlobArr = static_cast<CfBlobArray *>(CfMalloc(sizeof(CfBlobArray), 0));
513 if (newBlobArr == nullptr) {
514 LOGE("Failed to allocate newBlobArr memory!");
515 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
516 return nullptr;
517 }
518
519 newBlobArr->count = length;
520 newBlobArr->data = static_cast<CfBlob *>(CfMalloc(length * sizeof(CfBlob), 0));
521 if (newBlobArr->data == nullptr) {
522 LOGE("Failed to allocate data memory!");
523 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
524 CfFree(newBlobArr);
525 return nullptr;
526 }
527 for (uint32_t i = 0; i < length; i++) {
528 napi_value element;
529 if (napi_get_element(env, arg, i, &element) == napi_ok) {
530 CfBlob *blob = CertGetBlobFromUint8ArrJSParams(env, element);
531 if (blob != nullptr) {
532 newBlobArr->data[i] = *blob;
533 CfFree(blob); // release blob object, not release blob data
534 continue;
535 }
536 }
537 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "input arr is invalid"));
538 FreeCfBlobArray(newBlobArr->data, newBlobArr->count);
539 CfFree(newBlobArr);
540 LOGE("Failed to allocate data memory!");
541 return nullptr;
542 }
543 return newBlobArr;
544 }
545
GetArrayLen(napi_env env,napi_value arg,uint32_t & length)546 static bool GetArrayLen(napi_env env, napi_value arg, uint32_t &length)
547 {
548 bool flag = false;
549 napi_status status = napi_is_array(env, arg, &flag);
550 if (status != napi_ok || !flag) {
551 LOGE("not array!");
552 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "not array!"));
553 return false;
554 }
555
556 status = napi_get_array_length(env, arg, &length);
557 if (status != napi_ok || length == 0) {
558 LOGE("array length = 0!");
559 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "array length = 0!"));
560 return false;
561 }
562 return true;
563 }
564
CertGetBlobFromArrBoolJSParams(napi_env env,napi_value arg)565 CfBlob *CertGetBlobFromArrBoolJSParams(napi_env env, napi_value arg)
566 {
567 uint32_t length = 0;
568 if (!GetArrayLen(env, arg, length)) {
569 LOGE("get array length failed!");
570 return nullptr;
571 }
572
573 CfBlob *newBlob = static_cast<CfBlob *>(CfMalloc(sizeof(CfBlob), 0));
574 if (newBlob == nullptr) {
575 LOGE("Failed to allocate newBlob memory!");
576 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
577 return nullptr;
578 }
579
580 newBlob->size = length;
581 newBlob->data = static_cast<uint8_t *>(CfMalloc(length, 0));
582 if (newBlob->data == nullptr) {
583 LOGE("Failed to allocate data memory!");
584 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
585 CfFree(newBlob);
586 return nullptr;
587 }
588 napi_status status = napi_ok;
589 for (uint32_t i = 0; i < length; i++) {
590 napi_value element;
591 status = napi_get_element(env, arg, i, &element);
592 if (status != napi_ok) {
593 LOGE("Failed to get element!");
594 break;
595 }
596 bool elemResult = false;
597 status = napi_get_value_bool(env, element, &elemResult);
598 if (status != napi_ok) {
599 LOGE("Failed to get value bool!");
600 break;
601 }
602 newBlob->data[i] = (elemResult ? 1 : 0);
603 }
604
605 if (status != napi_ok) {
606 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "invalid params!"));
607 CfFree(newBlob->data);
608 CfFree(newBlob);
609 return nullptr;
610 }
611
612 return newBlob;
613 }
614
ParserArray(napi_env env,napi_value arg,uint32_t & arrayLen)615 bool ParserArray(napi_env env, napi_value arg, uint32_t &arrayLen)
616 {
617 bool flag = false;
618 napi_status status = napi_is_array(env, arg, &flag);
619 if (status != napi_ok || !flag) {
620 return false;
621 }
622 uint32_t length = 0;
623 status = napi_get_array_length(env, arg, &length);
624 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
625 return false;
626 }
627 arrayLen = length;
628 return true;
629 }
630
SubAltNameArrayDataClearAndFree(SubAltNameArray * array)631 void SubAltNameArrayDataClearAndFree(SubAltNameArray *array)
632 {
633 if (array == NULL) {
634 LOGD("The input array is null, no need to free.");
635 return;
636 }
637 if (array->data != NULL) {
638 for (uint32_t i = 0; i < array->count; ++i) {
639 CF_FREE_BLOB(array->data[i].name);
640 }
641 CfFree(array->data);
642 array->data = NULL;
643 array->count = 0;
644 }
645 }
646
CertGetSANArrFromArrUarrJSParams(napi_env env,napi_value arg)647 SubAltNameArray *CertGetSANArrFromArrUarrJSParams(napi_env env, napi_value arg)
648 {
649 uint32_t length = 0;
650 if (!ParserArray(env, arg, length)) {
651 LOGE("Length is invalid!");
652 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "length is invalid!"));
653 return nullptr;
654 }
655
656 SubAltNameArray *newSANArr = static_cast<SubAltNameArray *>(CfMalloc(sizeof(SubAltNameArray), 0));
657 if (newSANArr == nullptr) {
658 LOGE("Failed to allocate newSANArr memory!");
659 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
660 return nullptr;
661 }
662
663 newSANArr->count = length;
664 newSANArr->data =
665 static_cast<SubjectAlternaiveNameData *>(CfMalloc(length * sizeof(SubjectAlternaiveNameData), 0));
666 if (newSANArr->data == nullptr) {
667 LOGE("Failed to allocate data memory!");
668 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
669 SubAltNameArrayDataClearAndFree(newSANArr);
670 CfFree(newSANArr);
671 return nullptr;
672 }
673 for (uint32_t i = 0; i < length; i++) {
674 napi_value element;
675 if (napi_get_element(env, arg, i, &element) == napi_ok) {
676 napi_value obj = GetProp(env, element, CERT_MATCH_TAG_SUBJECT_ALT_NAMES_TYPE.c_str());
677 if (obj == nullptr || napi_get_value_int32(env, obj, (int32_t *)&(newSANArr->data[i].type)) != napi_ok) {
678 LOGE("Failed to get type!");
679 SubAltNameArrayDataClearAndFree(newSANArr);
680 CfFree(newSANArr);
681 return nullptr;
682 }
683 obj = GetProp(env, element, CERT_MATCH_TAG_SUBJECT_ALT_NAMES_DATA.c_str());
684 CfBlob *blob = CertGetBlobFromUint8ArrJSParams(env, obj);
685 if (blob != nullptr) {
686 newSANArr->data[i].name = *blob;
687 CfFree(blob);
688 continue;
689 }
690 }
691 LOGE("Failed to allocate data memory!");
692 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "input arr is invalid"));
693 SubAltNameArrayDataClearAndFree(newSANArr);
694 CfFree(newSANArr);
695 return nullptr;
696 }
697 return newSANArr;
698 }
699
CertGetArrFromArrUarrJSParams(napi_env env,napi_value arg)700 CfArray *CertGetArrFromArrUarrJSParams(napi_env env, napi_value arg)
701 {
702 bool flag = false;
703 napi_status status = napi_is_array(env, arg, &flag);
704 if (status != napi_ok || !flag) {
705 LOGE("Not array!");
706 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "not array!"));
707 return nullptr;
708 }
709 uint32_t length = 0;
710 status = napi_get_array_length(env, arg, &length);
711 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
712 LOGE("Length is invalid!");
713 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "length is invalid!"));
714 return nullptr;
715 }
716 CfArray *newBlobArr = static_cast<CfArray *>(CfMalloc(sizeof(CfArray), 0));
717 if (newBlobArr == nullptr) {
718 LOGE("Failed to allocate newBlobArr memory!");
719 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
720 return nullptr;
721 }
722 newBlobArr->count = length;
723 newBlobArr->format = CF_FORMAT_DER;
724 newBlobArr->data = static_cast<CfBlob *>(CfMalloc(length * sizeof(CfBlob), 0));
725 if (newBlobArr->data == nullptr) {
726 LOGE("Failed to allocate data memory!");
727 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc failed"));
728 CfFree(newBlobArr);
729 return nullptr;
730 }
731 for (uint32_t i = 0; i < length; i++) {
732 napi_value element;
733 if (napi_get_element(env, arg, i, &element) == napi_ok) {
734 CfBlob *blob = CertGetBlobFromStringJSParams(env, element);
735 if (blob != nullptr) {
736 newBlobArr->data[i] = *blob;
737 CfFree(blob);
738 continue;
739 }
740 }
741 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "input arr is invalid"));
742 FreeCfBlobArray(newBlobArr->data, newBlobArr->count);
743 CfFree(newBlobArr);
744 LOGE("Failed to allocate data memory!");
745 return nullptr;
746 }
747 return newBlobArr;
748 }
749
CertGetBlobFromBigIntJSParams(napi_env env,napi_value arg,CfBlob & outBlob)750 bool CertGetBlobFromBigIntJSParams(napi_env env, napi_value arg, CfBlob &outBlob)
751 {
752 napi_valuetype valueType;
753 napi_typeof(env, arg, &valueType);
754 if (valueType != napi_bigint) {
755 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type error"));
756 LOGE("Wrong argument type. expect int type. [Type]: %d", valueType);
757 return false;
758 }
759
760 int signBit;
761 size_t wordCount;
762
763 napi_get_value_bigint_words(env, arg, nullptr, &wordCount, nullptr);
764 if ((wordCount == 0) || (wordCount > (MAX_SN_BYTE_CNT / sizeof(uint64_t)))) {
765 LOGE("Get big int failed.");
766 return false;
767 }
768 int length = wordCount * sizeof(uint64_t);
769 uint8_t *retArr = reinterpret_cast<uint8_t *>(CfMalloc(length, 0));
770 if (retArr == nullptr) {
771 LOGE("Malloc blob data failed!");
772 return false;
773 }
774 if (napi_get_value_bigint_words(env, arg, &signBit, &wordCount, reinterpret_cast<uint64_t *>(retArr)) != napi_ok) {
775 CfFree(retArr);
776 LOGE("Failed to get valid rawData.");
777 return false;
778 }
779 if (signBit != 0) {
780 CfFree(retArr);
781 LOGE("Failed to get gegative rawData.");
782 return false;
783 }
784 outBlob.data = retArr;
785 outBlob.size = (uint32_t)length;
786 return true;
787 }
788
CertGetSerialNumberFromBigIntJSParams(napi_env env,napi_value arg,CfBlob & outBlob)789 bool CertGetSerialNumberFromBigIntJSParams(napi_env env, napi_value arg, CfBlob &outBlob)
790 {
791 napi_valuetype valueType;
792 napi_typeof(env, arg, &valueType);
793 if (valueType != napi_bigint) {
794 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type error"));
795 LOGE("wrong argument type. expect int type. [Type]: %d", valueType);
796 return false;
797 }
798
799 size_t wordCount = 0;
800 if (napi_get_value_bigint_words(env, arg, nullptr, &wordCount, nullptr) != napi_ok) {
801 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get serialNum failed"));
802 LOGE("can not get word count");
803 return false;
804 }
805 if (wordCount == 0 || wordCount > (MAX_SN_BYTE_CNT / sizeof(int64_t))) {
806 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get serialNum len failed"));
807 LOGE("can not get wordCount, wordCount = %u", wordCount);
808 return false;
809 }
810
811 uint8_t serialBuf[MAX_SN_BYTE_CNT] = { 0 };
812 uint32_t serialLen = sizeof(int64_t) * wordCount;
813
814 int sign = 0;
815 if (napi_get_value_bigint_words(env, arg, &sign, &wordCount, reinterpret_cast<uint64_t *>(serialBuf)) != napi_ok ||
816 sign > 0) {
817 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "get serialNum len failed"));
818 LOGE("can not get bigint value, sign = %d", sign); // sign 0 : positive, sign 1 : negative
819 return false;
820 }
821 outBlob.data = static_cast<uint8_t *>(CfMalloc(serialLen, 0));
822 if (outBlob.data == nullptr) {
823 napi_throw(env, CertGenerateBusinessError(env, CF_ERR_MALLOC, "malloc serialNum failed"));
824 LOGE("malloc blob data failed!");
825 return false;
826 }
827 outBlob.size = serialLen;
828 // reverse data: because BN_bin2bn() converts the positive integer in big-endian form of length len into a BIGNUM
829 for (uint32_t i = 0; i < serialLen; ++i) {
830 outBlob.data[i] = serialBuf[outBlob.size - 1 - i];
831 }
832
833 return true;
834 }
835
CertGetStringFromJSParams(napi_env env,napi_value arg,string & returnStr)836 bool CertGetStringFromJSParams(napi_env env, napi_value arg, string &returnStr)
837 {
838 napi_valuetype valueType;
839 napi_typeof(env, arg, &valueType);
840 if (valueType != napi_string) {
841 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type is not string"));
842 LOGE("wrong argument type. expect string type. [Type]: %d", valueType);
843 return false;
844 }
845
846 size_t length = 0;
847 if (napi_get_value_string_utf8(env, arg, nullptr, 0, &length) != napi_ok) {
848 LOGE("can not get string length");
849 return false;
850 }
851 returnStr.reserve(length + 1);
852 returnStr.resize(length);
853 if (napi_get_value_string_utf8(env, arg, returnStr.data(), (length + 1), &length) != napi_ok) {
854 LOGE("can not get string value");
855 return false;
856 }
857 return true;
858 }
859
CertGetInt32FromJSParams(napi_env env,napi_value arg,int32_t & returnInt)860 bool CertGetInt32FromJSParams(napi_env env, napi_value arg, int32_t &returnInt)
861 {
862 napi_valuetype valueType;
863 napi_typeof(env, arg, &valueType);
864 if (valueType != napi_number) {
865 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type is not number"));
866 LOGE("wrong argument type. expect int type. [Type]: %d", valueType);
867 return false;
868 }
869
870 if (napi_get_value_int32(env, arg, &returnInt) != napi_ok) {
871 LOGE("can not get int value");
872 return false;
873 }
874 return true;
875 }
876
CertGetCallbackFromJSParams(napi_env env,napi_value arg,napi_ref * returnCb)877 bool CertGetCallbackFromJSParams(napi_env env, napi_value arg, napi_ref *returnCb)
878 {
879 napi_valuetype valueType = napi_undefined;
880 napi_typeof(env, arg, &valueType);
881 if (valueType != napi_function) {
882 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "param type is not function"));
883 LOGE("wrong argument type. expect callback type. [Type]: %d", valueType);
884 return false;
885 }
886
887 napi_create_reference(env, arg, 1, returnCb);
888 return true;
889 }
890
GetCertErrValueByErrCode(int32_t errCode)891 static uint32_t GetCertErrValueByErrCode(int32_t errCode)
892 {
893 uint32_t count = sizeof(CODE_MAP) / sizeof(CODE_MAP[0]);
894 for (uint32_t i = 0; i < count; i++) {
895 if (errCode == CODE_MAP[i].retValue) {
896 return CODE_MAP[i].retCode;
897 }
898 }
899 return JS_ERR_CERT_RUNTIME_ERROR;
900 }
901
CertGenerateBusinessError(napi_env env,int32_t errCode,const char * errMsg)902 napi_value CertGenerateBusinessError(napi_env env, int32_t errCode, const char *errMsg)
903 {
904 napi_value businessError = nullptr;
905
906 napi_value code = nullptr;
907 napi_create_uint32(env, GetCertErrValueByErrCode(errCode), &code);
908
909 napi_value msg = nullptr;
910 napi_create_string_utf8(env, errMsg, NAPI_AUTO_LENGTH, &msg);
911
912 napi_create_error(env, nullptr, msg, &businessError);
913 napi_set_named_property(env, businessError, CERT_TAG_ERR_CODE.c_str(), code);
914
915 return businessError;
916 }
917
CertCheckArgsCount(napi_env env,size_t argc,size_t expectedCount,bool isSync)918 bool CertCheckArgsCount(napi_env env, size_t argc, size_t expectedCount, bool isSync)
919 {
920 if (isSync) {
921 if (argc != expectedCount) {
922 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "invalid params count"));
923 LOGE("invalid params count!");
924 return false;
925 }
926 } else {
927 if ((argc != expectedCount) && (argc != (expectedCount - ARGS_SIZE_ONE))) {
928 napi_throw(env, CertGenerateBusinessError(env, CF_INVALID_PARAMS, "invalid params count"));
929 LOGE("invalid params count!");
930 return false;
931 }
932 }
933 return true;
934 }
935
GetAsyncType(napi_env env,size_t argc,size_t maxCount,napi_value arg)936 AsyncType GetAsyncType(napi_env env, size_t argc, size_t maxCount, napi_value arg)
937 {
938 if (argc == (maxCount - 1)) { /* inner caller func: maxCount is bigger than 1 */
939 return ASYNC_TYPE_PROMISE;
940 }
941
942 napi_valuetype valueType = napi_undefined;
943 napi_typeof(env, arg, &valueType);
944 /* If the input is undefined or null, the value is processed as promise type. */
945 if ((valueType == napi_undefined) || (valueType == napi_null)) {
946 CF_LOG_I("input value is undefined or null");
947 return ASYNC_TYPE_PROMISE;
948 }
949
950 return ASYNC_TYPE_CALLBACK;
951 }
952
CertGetResourceName(napi_env env,const char * name)953 napi_value CertGetResourceName(napi_env env, const char *name)
954 {
955 napi_value resourceName = nullptr;
956 napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resourceName);
957 return resourceName;
958 }
959
ConvertBlobToNapiValue(napi_env env,const CfBlob * blob)960 napi_value ConvertBlobToNapiValue(napi_env env, const CfBlob *blob)
961 {
962 if (blob == nullptr || blob->data == nullptr || blob->size == 0) {
963 LOGE("Invalid blob!");
964 return nullptr;
965 }
966 uint8_t *buffer = static_cast<uint8_t *>(CfMalloc(blob->size, 0));
967 if (buffer == nullptr) {
968 LOGE("malloc uint8 array buffer failed!");
969 return nullptr;
970 }
971
972 (void)memcpy_s(buffer, blob->size, blob->data, blob->size);
973 napi_value outBuffer = nullptr;
974 napi_status status = napi_create_external_arraybuffer(
975 env, buffer, blob->size, [](napi_env env, void *data, void *hint) { CfFree(data); }, nullptr, &outBuffer);
976 if (status != napi_ok) {
977 LOGE("create uint8 array buffer failed!");
978 CfFree(buffer);
979 return nullptr;
980 }
981 buffer = nullptr;
982
983 napi_value outData = nullptr;
984 napi_create_typedarray(env, napi_uint8_array, blob->size, outBuffer, 0, &outData);
985 napi_value dataBlob = nullptr;
986 napi_create_object(env, &dataBlob);
987 napi_set_named_property(env, dataBlob, CERT_TAG_DATA.c_str(), outData);
988
989 return dataBlob;
990 }
991
ConvertBlobToWords(const CfBlob & blob,uint64_t * & words,uint32_t & wordsCount)992 static CfResult ConvertBlobToWords(const CfBlob &blob, uint64_t *&words, uint32_t &wordsCount)
993 {
994 uint32_t blockSize = sizeof(uint64_t);
995 uint32_t convertDataSize = ((blob.size + (blockSize - 1)) >> QUAD_WORD_ALIGN_UP) << QUAD_WORD_ALIGN_UP;
996 uint8_t *convertData = static_cast<uint8_t *>(CfMalloc(convertDataSize, 0));
997 if (convertData == nullptr) {
998 LOGE("malloc convert data failed");
999 return CF_ERR_MALLOC;
1000 }
1001
1002 /* convertData has been initialized 0, reverse blob data */
1003 for (uint32_t i = 0; i < blob.size; ++i) {
1004 convertData[i] = blob.data[blob.size - 1 - i];
1005 }
1006
1007 words = reinterpret_cast<uint64_t *>(convertData);
1008 wordsCount = convertDataSize / blockSize;
1009 return CF_SUCCESS;
1010 }
1011
ConvertBlobToBigIntWords(napi_env env,const CfBlob & blob)1012 napi_value ConvertBlobToBigIntWords(napi_env env, const CfBlob &blob)
1013 {
1014 if (blob.data == nullptr || blob.size == 0 || blob.size > MAX_SN_BYTE_CNT) {
1015 LOGE("Invalid blob!");
1016 return nullptr;
1017 }
1018
1019 uint64_t *words = nullptr;
1020 uint32_t wordsCount = 0;
1021 CfResult ret = ConvertBlobToWords(blob, words, wordsCount);
1022 if (ret != CF_SUCCESS) {
1023 napi_throw(env, CertGenerateBusinessError(env, ret, "convert data to words failed"));
1024 LOGE("convert data to words failed");
1025 return nullptr;
1026 }
1027
1028 napi_value result = nullptr;
1029 napi_create_bigint_words(env, 0, wordsCount, words, &result);
1030 CfFree(words);
1031 return result;
1032 }
1033
ConvertBlobToInt64(napi_env env,const CfBlob & blob)1034 napi_value ConvertBlobToInt64(napi_env env, const CfBlob &blob)
1035 {
1036 if (blob.data == nullptr || blob.size == 0 || blob.size > sizeof(int64_t)) {
1037 LOGE("Invalid blob!");
1038 return nullptr;
1039 }
1040
1041 uint64_t serialNumber = 0;
1042 for (uint32_t i = 0; i < blob.size; ++i) {
1043 serialNumber = ((serialNumber << (BYTE_TO_BIT_CNT * i)) | static_cast<uint64_t>(blob.data[i]));
1044 }
1045
1046 napi_value result = nullptr;
1047 napi_create_int64(env, static_cast<long>(serialNumber), &result);
1048 return result;
1049 }
1050
ConvertArrayStringToNapiValue(napi_env env,CfArray * array)1051 napi_value ConvertArrayStringToNapiValue(napi_env env, CfArray *array)
1052 {
1053 if (array == nullptr) {
1054 LOGE("array is null!");
1055 return nullptr;
1056 }
1057 if (array->count == 0) {
1058 LOGE("array count is 0!");
1059 return nullptr;
1060 }
1061 napi_value returnArray = nullptr;
1062 napi_create_array(env, &returnArray);
1063 if (returnArray == nullptr) {
1064 LOGE("create return array failed!");
1065 return nullptr;
1066 }
1067 for (uint32_t i = 0; i < array->count; i++) {
1068 CfBlob *blob = reinterpret_cast<CfBlob *>(array->data + i);
1069 napi_value element = nullptr;
1070 napi_create_string_utf8(env, reinterpret_cast<char *>(blob->data), blob->size, &element);
1071 napi_set_element(env, returnArray, i, element);
1072 }
1073 return returnArray;
1074 }
1075
ConvertBlobToEncodingBlob(const CfBlob & blob,CfEncodingBlob * encodingBlob)1076 bool ConvertBlobToEncodingBlob(const CfBlob &blob, CfEncodingBlob *encodingBlob)
1077 {
1078 if (blob.data == nullptr || blob.size == 0) {
1079 LOGE("Invalid blob!");
1080 return false;
1081 }
1082
1083 encodingBlob->data = static_cast<uint8_t *>(CfMalloc(blob.size, 0));
1084 if (encodingBlob->data == nullptr) {
1085 LOGE("malloc encoding blob data failed!");
1086 return false;
1087 }
1088 if (memcpy_s(encodingBlob->data, blob.size, blob.data, blob.size) != EOK) {
1089 LOGE("memcpy_s encoding blob data failed!");
1090 CfFree(encodingBlob->data);
1091 encodingBlob->data = nullptr;
1092 return false;
1093 }
1094 encodingBlob->len = blob.size;
1095 encodingBlob->encodingFormat = CF_FORMAT_DER;
1096 return true;
1097 }
1098 } // namespace CertFramework
1099 } // namespace OHOS
1100