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_x509_cert_chain_validate_params.h"
17
18 #include "cf_log.h"
19 #include "cf_memory.h"
20 #include "cf_type.h"
21 #include "napi/native_api.h"
22 #include "napi/native_common.h"
23 #include "napi_cert_crl_collection.h"
24 #include "napi_cert_defines.h"
25 #include "napi_cert_utils.h"
26 #include "napi_object.h"
27 #include "napi_x509_trust_anchor.h"
28 #include "napi_x509_certificate.h"
29 #include "utils.h"
30 #include "x509_cert_chain_validate_params.h"
31
32 namespace OHOS {
33 namespace CertFramework {
34
GetValidDate(napi_env env,napi_value arg,CfBlob * & out)35 static bool GetValidDate(napi_env env, napi_value arg, CfBlob *&out)
36 {
37 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_DATE.c_str());
38 if (obj == nullptr) {
39 LOGI("prop date do not exist!");
40 return true;
41 }
42 out = CertGetBlobFromStringJSParams(env, obj);
43 if (out == nullptr) {
44 LOGE("get blob failed!");
45 return false;
46 }
47 return true;
48 }
49
GetArrayLength(napi_env env,napi_value arg,uint32_t & length)50 static bool GetArrayLength(napi_env env, napi_value arg, uint32_t &length)
51 {
52 length = 0;
53 bool flag = false;
54 napi_status status = napi_is_array(env, arg, &flag);
55 if (status != napi_ok || !flag) {
56 LOGE("param type not array!");
57 return false;
58 }
59 status = napi_get_array_length(env, arg, &length);
60 if (status != napi_ok || length == 0 || length > MAX_LEN_OF_ARRAY) {
61 LOGE("array length is invalid!");
62 return false;
63 }
64 return true;
65 }
66
FreeTrustAnchorArray(HcfX509TrustAnchorArray * & trustAnchors)67 static void FreeTrustAnchorArray(HcfX509TrustAnchorArray *&trustAnchors)
68 {
69 for (uint32_t i = 0; i < trustAnchors->count; ++i) {
70 FreeX509TrustAnchorObj(trustAnchors->data[i]);
71 }
72 CfFree(trustAnchors);
73 trustAnchors = nullptr;
74 }
75
GetX509TrustAnchorArray(napi_env env,napi_value arg,bool isTrustSystemCa,HcfX509TrustAnchorArray * & out)76 static bool GetX509TrustAnchorArray(napi_env env, napi_value arg, bool isTrustSystemCa, HcfX509TrustAnchorArray *&out)
77 {
78 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_TRUSTANCHORS.c_str());
79 if (obj == nullptr) {
80 LOGE("param type not array!");
81 return false;
82 }
83
84 uint32_t length;
85 if (!GetArrayLength(env, obj, length)) {
86 LOGE("get array length failed!");
87 return isTrustSystemCa;
88 }
89
90 out = static_cast<HcfX509TrustAnchorArray *>(CfMalloc(sizeof(HcfX509TrustAnchorArray), 0));
91 if (out == nullptr) {
92 LOGE("Failed to allocate out memory!");
93 return false;
94 }
95
96 out->count = length;
97 out->data = static_cast<HcfX509TrustAnchor **>(CfMalloc(length * sizeof(HcfX509TrustAnchor *), 0));
98 if (out->data == nullptr) {
99 LOGE("Failed to allocate data memory!");
100 CfFree(out);
101 out = nullptr;
102 return false;
103 }
104 for (uint32_t i = 0; i < length; ++i) {
105 napi_value element;
106 if (napi_get_element(env, obj, i, &element) != napi_ok) {
107 LOGE("get element failed!");
108 FreeTrustAnchorArray(out);
109 out = nullptr;
110 return false;
111 }
112
113 if (!BuildX509TrustAnchorObj(env, element, out->data[i])) {
114 LOGE("build x509 trust anchor obj failed!");
115 FreeTrustAnchorArray(out);
116 out = nullptr;
117 return false;
118 }
119 }
120 out->count = length;
121 return true;
122 }
123
GetCertCRLCollectionArray(napi_env env,napi_value arg,HcfCertCRLCollectionArray * & out)124 static bool GetCertCRLCollectionArray(napi_env env, napi_value arg, HcfCertCRLCollectionArray *&out)
125 {
126 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_CERTCRLS.c_str());
127 if (obj == nullptr) {
128 LOGI("prop certCRLs do not exist!");
129 return true;
130 }
131
132 uint32_t length;
133 if (!GetArrayLength(env, obj, length)) {
134 LOGE("get array length failed!");
135 return false;
136 }
137
138 out = static_cast<HcfCertCRLCollectionArray *>(CfMalloc(sizeof(HcfCertCRLCollectionArray), 0));
139 if (out == nullptr) {
140 LOGE("Failed to allocate out memory!");
141 return false;
142 }
143 out->count = length;
144 out->data = static_cast<HcfCertCrlCollection **>(CfMalloc(length * sizeof(HcfCertCrlCollection *), 0));
145 if (out->data == nullptr) {
146 LOGE("Failed to allocate data memory!");
147 CfFree(out);
148 out = nullptr;
149 return false;
150 }
151 for (uint32_t i = 0; i < length; i++) {
152 napi_value element;
153 napi_status status = napi_get_element(env, obj, i, &element);
154 if (status != napi_ok) {
155 LOGE("get element failed!");
156 CfFree(out->data);
157 out->data = nullptr;
158 CfFree(out);
159 out = nullptr;
160 return false;
161 }
162 NapiCertCRLCollection *napiCertCrlCollectionObj = nullptr;
163 napi_unwrap(env, element, reinterpret_cast<void **>(&napiCertCrlCollectionObj));
164 if (napiCertCrlCollectionObj == nullptr) {
165 LOGE("napi cert crl collection object is nullptr!");
166 CfFree(out->data);
167 out->data = nullptr;
168 CfFree(out);
169 out = nullptr;
170 return false;
171 }
172 out->data[i] = napiCertCrlCollectionObj->GetCertCrlCollection();
173 }
174 return true;
175 }
176
GetRevocationOptions(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)177 static bool GetRevocationOptions(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
178 {
179 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OPTIONS.c_str());
180 if (obj == nullptr) {
181 return true;
182 }
183 bool flag = false;
184 napi_status status = napi_is_array(env, obj, &flag);
185 if (status != napi_ok || !flag) {
186 return false;
187 }
188
189 uint32_t length = 0;
190 status = napi_get_array_length(env, obj, &length);
191 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
192 return false;
193 }
194 out->options = static_cast<HcfRevChkOpArray *>(CfMalloc(sizeof(HcfRevChkOpArray), 0));
195 if (out->options == nullptr) {
196 return false;
197 }
198 out->options->count = length;
199 out->options->data = static_cast<HcfRevChkOption *>(CfMalloc(length * sizeof(HcfRevChkOption), 0));
200 if (out->options->data == nullptr) {
201 CF_FREE_PTR(out->options);
202 return false;
203 }
204 for (uint32_t i = 0; i < length; i++) {
205 napi_value element;
206 if (napi_get_element(env, obj, i, &element) != napi_ok ||
207 napi_get_value_int32(env, element, (int32_t *)&(out->options->data[i])) != napi_ok) {
208 CF_FREE_PTR(out->options->data);
209 CF_FREE_PTR(out->options);
210 return false;
211 }
212 switch (out->options->data[i]) {
213 case REVOCATION_CHECK_OPTION_PREFER_OCSP:
214 case REVOCATION_CHECK_OPTION_ACCESS_NETWORK:
215 case REVOCATION_CHECK_OPTION_FALLBACK_NO_PREFER:
216 case REVOCATION_CHECK_OPTION_FALLBACK_LOCAL:
217 break;
218 default:
219 CF_FREE_PTR(out->options->data);
220 CF_FREE_PTR(out->options);
221 return false;
222 }
223 }
224 return true;
225 }
226
GetRevocationocspDigest(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)227 static bool GetRevocationocspDigest(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
228 {
229 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_DIGEST.c_str());
230 if (obj == nullptr) {
231 return true;
232 }
233
234 out->ocspDigest = CertGetBlobFromStringJSParams(env, obj);
235 if (out->ocspDigest == nullptr) {
236 return false;
237 }
238
239 char *mdName = reinterpret_cast<char *>(out->ocspDigest->data);
240 if (strcmp(mdName, "SHA1") == 0) {
241 return true;
242 } else if (strcmp(mdName, "SHA224") == 0) {
243 return true;
244 } else if (strcmp(mdName, "SHA256") == 0) {
245 return true;
246 } else if (strcmp(mdName, "SHA384") == 0) {
247 return true;
248 } else if (strcmp(mdName, "SHA512") == 0) {
249 return true;
250 } else if (strcmp(mdName, "MD5") == 0) {
251 return true;
252 }
253
254 CfFree(out->ocspDigest->data);
255 out->ocspDigest->data = nullptr;
256 CfFree(out->ocspDigest);
257 out->ocspDigest = nullptr;
258 return false;
259 }
260
GetRevocationDetail(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)261 static bool GetRevocationDetail(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
262 {
263 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_REQ_EXTENSION.c_str());
264 if (obj != nullptr) {
265 out->ocspRequestExtension = CertGetBlobArrFromArrUarrJSParams(env, obj);
266 if (out->ocspRequestExtension == nullptr) {
267 return false;
268 }
269 }
270 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESP_URI.c_str());
271 if (obj != nullptr) {
272 out->ocspResponderURI = CertGetBlobFromStringJSParams(env, obj);
273 if (out->ocspResponderURI == nullptr) {
274 return false;
275 }
276 }
277 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESP_CERT.c_str());
278 if (obj != nullptr) {
279 NapiX509Certificate *napiX509Cert = nullptr;
280 napi_unwrap(env, obj, reinterpret_cast<void **>(&napiX509Cert));
281 if (napiX509Cert != nullptr) {
282 out->ocspResponderCert = napiX509Cert->GetX509Cert();
283 if (out->ocspResponderCert == nullptr) {
284 return false;
285 }
286 } else {
287 return false;
288 }
289 }
290 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESPS.c_str());
291 if (obj != nullptr) {
292 out->ocspResponses = CertGetBlobFromUint8ArrJSParams(env, obj);
293 if (out->ocspResponses == nullptr) {
294 return false;
295 }
296 }
297 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_CRL_DOWNLOAD_URI.c_str());
298 if (obj != nullptr) {
299 out->crlDownloadURI = CertGetBlobFromStringJSParams(env, obj);
300 if (out->crlDownloadURI == nullptr) {
301 return false;
302 }
303 }
304 if (!GetRevocationocspDigest(env, rckObj, out)) {
305 return false;
306 }
307 return GetRevocationOptions(env, rckObj, out);
308 }
309
FreeHcfRevocationCheckParam(HcfRevocationCheckParam * param)310 static void FreeHcfRevocationCheckParam(HcfRevocationCheckParam *param)
311 {
312 if (param == nullptr) {
313 return;
314 }
315 if (param->ocspRequestExtension != nullptr) {
316 FreeCfBlobArray(param->ocspRequestExtension->data, param->ocspRequestExtension->count);
317 param->ocspRequestExtension->data = nullptr;
318 param->ocspRequestExtension->count = 0;
319 CfFree(param->ocspRequestExtension);
320 param->ocspRequestExtension = nullptr;
321 }
322 CfBlobFree(¶m->ocspResponderURI);
323 CfBlobFree(¶m->ocspResponses);
324 CfBlobFree(¶m->crlDownloadURI);
325 if (param->options != nullptr) {
326 if (param->options->data != nullptr) {
327 CfFree(param->options->data);
328 param->options->data = nullptr;
329 }
330 CfFree(param->options);
331 param->options = nullptr;
332 }
333 CfBlobFree(¶m->ocspDigest);
334 CfFree(param);
335 }
336
GetRevocationCheckParam(napi_env env,napi_value arg,HcfRevocationCheckParam * & out)337 static bool GetRevocationCheckParam(napi_env env, napi_value arg, HcfRevocationCheckParam *&out)
338 {
339 napi_value rckObj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_REVOCATIONCHECKPARAM.c_str());
340 if (rckObj == nullptr) {
341 LOGI("RevocationCheckParam do not exist!");
342 return true;
343 }
344 napi_valuetype valueType;
345 napi_typeof(env, rckObj, &valueType);
346 if (valueType == napi_null || valueType != napi_object) {
347 LOGE("Failed to check input param!");
348 return false;
349 }
350
351 out = static_cast<HcfRevocationCheckParam *>(CfMalloc(sizeof(HcfRevocationCheckParam), 0));
352 if (out == nullptr) {
353 LOGE("Failed to allocate out memory!");
354 return false;
355 }
356 if (!GetRevocationDetail(env, rckObj, out)) {
357 LOGE("Failed to get revocation detail!");
358 FreeHcfRevocationCheckParam(out);
359 out = nullptr;
360 return false;
361 }
362
363 return true;
364 }
365
GetValidationPolicyType(napi_env env,napi_value arg,HcfValPolicyType & out)366 static bool GetValidationPolicyType(napi_env env, napi_value arg, HcfValPolicyType &out)
367 {
368 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_POLICY.c_str());
369 if (obj != nullptr) {
370 napi_status status = napi_get_value_int32(env, obj, (int32_t *)&out);
371 if (status != napi_ok) {
372 return false;
373 }
374 }
375 return true;
376 }
377
GetSSLHostname(napi_env env,napi_value arg,CfBlob * & out)378 static bool GetSSLHostname(napi_env env, napi_value arg, CfBlob *&out)
379 {
380 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_SSLHOSTNAME.c_str());
381 if (obj == nullptr) {
382 LOGI("Param type not SSLHostname!");
383 return true;
384 }
385 out = CertGetBlobFromStringJSParams(env, obj);
386 if (out == nullptr) {
387 LOGE("SSLHostname is nullptr");
388 return false;
389 }
390 return true;
391 }
392
GetKeyUsage(napi_env env,napi_value arg,HcfKuArray * & out)393 static bool GetKeyUsage(napi_env env, napi_value arg, HcfKuArray *&out)
394 {
395 out = nullptr;
396 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_KEYUSAGE.c_str());
397 if (obj == nullptr) {
398 return true;
399 }
400 bool flag = false;
401 napi_status status = napi_is_array(env, obj, &flag);
402 if (status != napi_ok || !flag) {
403 return false;
404 }
405 uint32_t length = 0;
406 status = napi_get_array_length(env, obj, &length);
407 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
408 return false;
409 }
410 out = static_cast<HcfKuArray *>(CfMalloc(sizeof(HcfKuArray), 0));
411 if (out == nullptr) {
412 return false;
413 }
414 out->count = length;
415 out->data = static_cast<HcfKeyUsageType *>(CfMalloc(length * sizeof(HcfKeyUsageType), 0));
416 if (out->data == nullptr) {
417 CfFree(out);
418 out = nullptr;
419 return false;
420 }
421 for (uint32_t i = 0; i < length; i++) {
422 napi_value element;
423 if (napi_get_element(env, obj, i, &element) != napi_ok ||
424 napi_get_value_int32(env, element, (int32_t *)&(out->data[i])) != napi_ok) {
425 CfFree(out->data);
426 out->data = nullptr;
427 CfFree(out);
428 out = nullptr;
429 return false;
430 }
431 }
432 return true;
433 }
434
GetUseSystemCa(napi_env env,napi_value arg,bool * trustSystemCa)435 static bool GetUseSystemCa(napi_env env, napi_value arg, bool *trustSystemCa)
436 {
437 bool result = false;
438 napi_has_named_property(env, arg, CERT_CHAIN_VALIDATE_TAG_TRUST_SYSTEM_CA.c_str(), &result);
439 if (!result) {
440 LOGI("%{public}s do not exist!", CERT_CHAIN_VALIDATE_TAG_TRUST_SYSTEM_CA.c_str());
441 *trustSystemCa = false;
442 return true;
443 }
444 napi_value obj = nullptr;
445 napi_status status = napi_get_named_property(env, arg, CERT_CHAIN_VALIDATE_TAG_TRUST_SYSTEM_CA.c_str(), &obj);
446 if (status != napi_ok || obj == nullptr) {
447 LOGE("get property %{public}s failed!", CERT_CHAIN_VALIDATE_TAG_TRUST_SYSTEM_CA.c_str());
448 return false;
449 }
450 napi_valuetype valueType;
451 napi_typeof(env, obj, &valueType);
452 if (valueType == napi_undefined) {
453 LOGE("%{public}s valueType is null or undefined.", CERT_CHAIN_VALIDATE_TAG_TRUST_SYSTEM_CA.c_str());
454 return false;
455 }
456 napi_get_value_bool(env, obj, trustSystemCa);
457 return true;
458 }
459
FreeX509CertChainValidateParams(HcfX509CertChainValidateParams & param)460 void FreeX509CertChainValidateParams(HcfX509CertChainValidateParams ¶m)
461 {
462 CfBlobFree(¶m.date);
463 if (param.trustAnchors != nullptr) {
464 for (uint32_t i = 0; i < param.trustAnchors->count; ++i) {
465 FreeX509TrustAnchorObj(param.trustAnchors->data[i]);
466 }
467 CfFree(param.trustAnchors);
468 param.trustAnchors = nullptr;
469 }
470
471 if (param.certCRLCollections != nullptr) {
472 CfFree(param.certCRLCollections->data);
473 param.certCRLCollections->data = nullptr;
474 CfFree(param.certCRLCollections);
475 param.certCRLCollections = nullptr;
476 }
477
478 CfBlobFree(&(param.sslHostname));
479 if (param.keyUsage != nullptr) {
480 CfFree(param.keyUsage->data);
481 param.keyUsage->data = nullptr;
482 CfFree(param.keyUsage);
483 param.keyUsage = nullptr;
484 }
485
486 FreeHcfRevocationCheckParam(param.revocationCheckParam);
487 param.revocationCheckParam = nullptr;
488 }
489
FreeTrustAnchorArray(HcfX509TrustAnchorArray * trustAnchorArray,bool freeCertFlag)490 void FreeTrustAnchorArray(HcfX509TrustAnchorArray *trustAnchorArray, bool freeCertFlag)
491 {
492 if (trustAnchorArray == NULL) {
493 return;
494 }
495 for (uint32_t i = 0; i < trustAnchorArray->count; i++) {
496 if (trustAnchorArray->data[i] != NULL) {
497 if (freeCertFlag) {
498 CfObjDestroy(trustAnchorArray->data[i]->CACert);
499 }
500 trustAnchorArray->data[i]->CACert = NULL;
501 CfBlobFree(&trustAnchorArray->data[i]->CAPubKey);
502 CfBlobFree(&trustAnchorArray->data[i]->CASubject);
503 CfBlobFree(&trustAnchorArray->data[i]->nameConstraints);
504 CfFree(trustAnchorArray->data[i]);
505 trustAnchorArray->data[i] = NULL;
506 }
507 }
508
509 CfFree(trustAnchorArray);
510 }
511
BuildX509CertChainValidateParams(napi_env env,napi_value arg,HcfX509CertChainValidateParams & param)512 bool BuildX509CertChainValidateParams(napi_env env, napi_value arg, HcfX509CertChainValidateParams ¶m)
513 {
514 napi_valuetype type;
515 napi_typeof(env, arg, &type);
516 if (type != napi_object) {
517 LOGE("wrong argument type. expect string type. [Type]: %{public}d", type);
518 return false;
519 }
520
521 if (!GetValidDate(env, arg, param.date)) {
522 LOGE("Get valid date failed");
523 return false;
524 }
525 if (!GetUseSystemCa(env, arg, &(param.trustSystemCa))) {
526 LOGE("Get use system ca failed!");
527 return false;
528 }
529 if (!GetX509TrustAnchorArray(env, arg, param.trustSystemCa, param.trustAnchors)) {
530 LOGE("Get X509 trust anchor array failed");
531 return false;
532 }
533 if (!GetCertCRLCollectionArray(env, arg, param.certCRLCollections)) {
534 LOGE("Get cert CRL collection array failed");
535 return false;
536 }
537 if (!GetRevocationCheckParam(env, arg, param.revocationCheckParam)) {
538 LOGE("Get revocation check param failed!");
539 return false;
540 }
541 if (!GetValidationPolicyType(env, arg, param.policy)) {
542 LOGE("Get validation policy type failed!");
543 return false;
544 }
545 if (!GetSSLHostname(env, arg, param.sslHostname)) {
546 LOGE("Get SSL hostname failed!");
547 return false;
548 }
549 if (!GetKeyUsage(env, arg, param.keyUsage)) {
550 LOGE("Get key usage failed!");
551 return false;
552 }
553 return true;
554 }
555
556 } // namespace CertFramework
557 } // namespace OHOS
558