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