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,HcfX509TrustAnchorArray * & out)76 static bool GetX509TrustAnchorArray(napi_env env, napi_value arg, 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 false;
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 return false;
110 }
111
112 if (!BuildX509TrustAnchorObj(env, element, out->data[i])) {
113 LOGE("build x509 trust anchor obj failed!");
114 FreeTrustAnchorArray(out);
115 return false;
116 }
117 }
118 out->count = length;
119 return true;
120 }
121
GetCertCRLCollectionArray(napi_env env,napi_value arg,HcfCertCRLCollectionArray * & out)122 static bool GetCertCRLCollectionArray(napi_env env, napi_value arg, HcfCertCRLCollectionArray *&out)
123 {
124 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_CERTCRLS.c_str());
125 if (obj == nullptr) {
126 LOGI("prop certCRLs do not exist!");
127 return true;
128 }
129
130 uint32_t length;
131 if (!GetArrayLength(env, obj, length)) {
132 LOGE("get array length failed!");
133 return false;
134 }
135
136 out = static_cast<HcfCertCRLCollectionArray *>(CfMalloc(sizeof(HcfCertCRLCollectionArray), 0));
137 if (out == nullptr) {
138 LOGE("Failed to allocate out memory!");
139 return false;
140 }
141 out->count = length;
142 out->data = static_cast<HcfCertCrlCollection **>(CfMalloc(length * sizeof(HcfCertCrlCollection *), 0));
143 if (out->data == nullptr) {
144 LOGE("Failed to allocate data memory!");
145 CfFree(out);
146 out = nullptr;
147 return false;
148 }
149 for (uint32_t i = 0; i < length; i++) {
150 napi_value element;
151 napi_status status = napi_get_element(env, obj, i, &element);
152 if (status != napi_ok) {
153 LOGE("get element failed!");
154 CfFree(out->data);
155 CfFree(out);
156 out = nullptr;
157 return false;
158 }
159 NapiCertCRLCollection *napiCertCrlCollectionObj = nullptr;
160 napi_unwrap(env, element, reinterpret_cast<void **>(&napiCertCrlCollectionObj));
161 if (napiCertCrlCollectionObj == nullptr) {
162 LOGE("napi cert crl collection object is nullptr!");
163 CfFree(out->data);
164 CfFree(out);
165 out = nullptr;
166 return false;
167 }
168 out->data[i] = napiCertCrlCollectionObj->GetCertCrlCollection();
169 }
170 return true;
171 }
172
GetRevocationOptions(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)173 static bool GetRevocationOptions(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
174 {
175 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OPTIONS.c_str());
176 if (obj == nullptr) {
177 return true;
178 }
179 bool flag = false;
180 napi_status status = napi_is_array(env, obj, &flag);
181 if (status != napi_ok || !flag) {
182 return false;
183 }
184
185 uint32_t length = 0;
186 status = napi_get_array_length(env, obj, &length);
187 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
188 return false;
189 }
190 out->options = static_cast<HcfRevChkOpArray *>(CfMalloc(sizeof(HcfRevChkOpArray), 0));
191 if (out->options == nullptr) {
192 return false;
193 }
194 out->options->count = length;
195 out->options->data = static_cast<HcfRevChkOption *>(CfMalloc(length * sizeof(HcfRevChkOption), 0));
196 if (out->options->data == nullptr) {
197 CfFree(out->options);
198 out->options = nullptr;
199 return false;
200 }
201 for (uint32_t i = 0; i < length; i++) {
202 napi_value element;
203 if (napi_get_element(env, obj, i, &element) != napi_ok ||
204 napi_get_value_int32(env, element, (int32_t *)&(out->options->data[i])) != napi_ok) {
205 CfFree(out->options->data);
206 CfFree(out->options);
207 return false;
208 }
209 switch (out->options->data[i]) {
210 case REVOCATION_CHECK_OPTION_PREFER_OCSP:
211 case REVOCATION_CHECK_OPTION_ACCESS_NETWORK:
212 case REVOCATION_CHECK_OPTION_FALLBACK_NO_PREFER:
213 case REVOCATION_CHECK_OPTION_FALLBACK_LOCAL:
214 break;
215 default:
216 CfFree(out->options->data);
217 out->options->data = nullptr;
218 CfFree(out->options);
219 out->options = nullptr;
220 return false;
221 }
222 }
223 return true;
224 }
225
GetRevocationocspDigest(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)226 static bool GetRevocationocspDigest(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
227 {
228 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_DIGEST.c_str());
229 if (obj == nullptr) {
230 return true;
231 }
232
233 out->ocspDigest = CertGetBlobFromStringJSParams(env, obj);
234 if (out->ocspDigest == nullptr) {
235 return false;
236 }
237
238 char *mdName = reinterpret_cast<char *>(out->ocspDigest->data);
239 if (strcmp(mdName, "SHA1") == 0) {
240 return true;
241 } else if (strcmp(mdName, "SHA224") == 0) {
242 return true;
243 } else if (strcmp(mdName, "SHA256") == 0) {
244 return true;
245 } else if (strcmp(mdName, "SHA384") == 0) {
246 return true;
247 } else if (strcmp(mdName, "SHA512") == 0) {
248 return true;
249 } else if (strcmp(mdName, "MD5") == 0) {
250 return true;
251 }
252
253 CfFree(out->ocspDigest->data);
254 out->ocspDigest->data = nullptr;
255 CfFree(out->ocspDigest);
256 out->ocspDigest = nullptr;
257 return false;
258 }
259
GetRevocationDetail(napi_env env,napi_value rckObj,HcfRevocationCheckParam * & out)260 static bool GetRevocationDetail(napi_env env, napi_value rckObj, HcfRevocationCheckParam *&out)
261 {
262 napi_value obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_REQ_EXTENSION.c_str());
263 if (obj != nullptr) {
264 out->ocspRequestExtension = CertGetBlobArrFromArrUarrJSParams(env, obj);
265 if (out->ocspRequestExtension == nullptr) {
266 return false;
267 }
268 }
269 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESP_URI.c_str());
270 if (obj != nullptr) {
271 out->ocspResponderURI = CertGetBlobFromStringJSParams(env, obj);
272 if (out->ocspResponderURI == nullptr) {
273 return false;
274 }
275 }
276 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESP_CERT.c_str());
277 if (obj != nullptr) {
278 NapiX509Certificate *napiX509Cert = nullptr;
279 napi_unwrap(env, obj, reinterpret_cast<void **>(&napiX509Cert));
280 if (napiX509Cert != nullptr) {
281 out->ocspResponderCert = napiX509Cert->GetX509Cert();
282 if (out->ocspResponderCert == nullptr) {
283 return false;
284 }
285 } else {
286 return false;
287 }
288 }
289 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_OCSP_RESPS.c_str());
290 if (obj != nullptr) {
291 out->ocspResponses = CertGetBlobFromUint8ArrJSParams(env, obj);
292 if (out->ocspResponses == nullptr) {
293 return false;
294 }
295 }
296 obj = GetProp(env, rckObj, CERT_CHAIN_VALIDATE_TAG_CRL_DOWNLOAD_URI.c_str());
297 if (obj != nullptr) {
298 out->crlDownloadURI = CertGetBlobFromStringJSParams(env, obj);
299 if (out->crlDownloadURI == nullptr) {
300 return false;
301 }
302 }
303 if (!GetRevocationocspDigest(env, rckObj, out)) {
304 return false;
305 }
306 return GetRevocationOptions(env, rckObj, out);
307 }
308
FreeHcfRevocationCheckParam(HcfRevocationCheckParam * param)309 static void FreeHcfRevocationCheckParam(HcfRevocationCheckParam *param)
310 {
311 if (param == nullptr) {
312 return;
313 }
314 if (param->ocspRequestExtension != nullptr) {
315 FreeCfBlobArray(param->ocspRequestExtension->data, param->ocspRequestExtension->count);
316 CfFree(param->ocspRequestExtension);
317 }
318 CfBlobFree(¶m->ocspResponderURI);
319 CfBlobFree(¶m->ocspResponses);
320 CfBlobFree(¶m->crlDownloadURI);
321 if (param->options != nullptr) {
322 if (param->options->data != nullptr) {
323 CfFree(param->options->data);
324 }
325 CfFree(param->options);
326 }
327 CfBlobFree(¶m->ocspDigest);
328 CfFree(param);
329 }
330
GetRevocationCheckParam(napi_env env,napi_value arg,HcfRevocationCheckParam * & out)331 static bool GetRevocationCheckParam(napi_env env, napi_value arg, HcfRevocationCheckParam *&out)
332 {
333 napi_value rckObj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_REVOCATIONCHECKPARAM.c_str());
334 if (rckObj == nullptr) {
335 LOGI("RevocationCheckParam do not exist!");
336 return true;
337 }
338 napi_valuetype valueType;
339 napi_typeof(env, rckObj, &valueType);
340 if (valueType == napi_null || valueType != napi_object) {
341 LOGE("Failed to check input param!");
342 return false;
343 }
344
345 out = static_cast<HcfRevocationCheckParam *>(CfMalloc(sizeof(HcfRevocationCheckParam), 0));
346 if (out == nullptr) {
347 LOGE("Failed to allocate out memory!");
348 return false;
349 }
350 if (!GetRevocationDetail(env, rckObj, out)) {
351 LOGE("Failed to get revocation detail!");
352 FreeHcfRevocationCheckParam(out);
353 out = nullptr;
354 return false;
355 }
356
357 return true;
358 }
359
GetValidationPolicyType(napi_env env,napi_value arg,HcfValPolicyType & out)360 static bool GetValidationPolicyType(napi_env env, napi_value arg, HcfValPolicyType &out)
361 {
362 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_POLICY.c_str());
363 if (obj != nullptr) {
364 napi_status status = napi_get_value_int32(env, obj, (int32_t *)&out);
365 if (status != napi_ok) {
366 return false;
367 }
368 }
369 return true;
370 }
371
GetSSLHostname(napi_env env,napi_value arg,CfBlob * & out)372 static bool GetSSLHostname(napi_env env, napi_value arg, CfBlob *&out)
373 {
374 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_SSLHOSTNAME.c_str());
375 if (obj == nullptr) {
376 LOGI("Param type not SSLHostname!");
377 return true;
378 }
379 out = CertGetBlobFromStringJSParams(env, obj);
380 if (out == nullptr) {
381 LOGE("SSLHostname is nullptr");
382 return false;
383 }
384 return true;
385 }
386
GetKeyUsage(napi_env env,napi_value arg,HcfKuArray * & out)387 static bool GetKeyUsage(napi_env env, napi_value arg, HcfKuArray *&out)
388 {
389 out = nullptr;
390 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_KEYUSAGE.c_str());
391 if (obj == nullptr) {
392 return true;
393 }
394 bool flag = false;
395 napi_status status = napi_is_array(env, obj, &flag);
396 if (status != napi_ok || !flag) {
397 return false;
398 }
399 uint32_t length = 0;
400 status = napi_get_array_length(env, obj, &length);
401 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
402 return false;
403 }
404 out = static_cast<HcfKuArray *>(CfMalloc(sizeof(HcfKuArray), 0));
405 if (out == nullptr) {
406 return false;
407 }
408 out->count = length;
409 out->data = static_cast<HcfKeyUsageType *>(CfMalloc(length * sizeof(HcfKeyUsageType), 0));
410 if (out->data == nullptr) {
411 CfFree(out);
412 out = nullptr;
413 return false;
414 }
415 for (uint32_t i = 0; i < length; i++) {
416 napi_value element;
417 if (napi_get_element(env, obj, i, &element) != napi_ok ||
418 napi_get_value_int32(env, element, (int32_t *)&(out->data[i])) != napi_ok) {
419 CfFree(out->data);
420 CfFree(out);
421 out = nullptr;
422 return false;
423 }
424 }
425 return true;
426 }
427
FreeX509CertChainValidateParams(HcfX509CertChainValidateParams & param)428 void FreeX509CertChainValidateParams(HcfX509CertChainValidateParams ¶m)
429 {
430 CfBlobFree(¶m.date);
431 if (param.trustAnchors != nullptr) {
432 for (uint32_t i = 0; i < param.trustAnchors->count; ++i) {
433 FreeX509TrustAnchorObj(param.trustAnchors->data[i]);
434 }
435 CfFree(param.trustAnchors);
436 param.trustAnchors = nullptr;
437 }
438
439 if (param.certCRLCollections != nullptr) {
440 CfFree(param.certCRLCollections->data);
441 CfFree(param.certCRLCollections);
442 param.certCRLCollections = nullptr;
443 }
444
445 CfBlobFree(&(param.sslHostname));
446 if (param.keyUsage != nullptr) {
447 CfFree(param.keyUsage->data);
448 CfFree(param.keyUsage);
449 param.keyUsage = nullptr;
450 }
451
452 FreeHcfRevocationCheckParam(param.revocationCheckParam);
453 param.revocationCheckParam = nullptr;
454 }
455
FreeTrustAnchorArray(HcfX509TrustAnchorArray * trustAnchorArray,bool freeCertFlag)456 void FreeTrustAnchorArray(HcfX509TrustAnchorArray *trustAnchorArray, bool freeCertFlag)
457 {
458 if (trustAnchorArray == NULL) {
459 return;
460 }
461 for (uint32_t i = 0; i < trustAnchorArray->count; i++) {
462 if (trustAnchorArray->data[i] != NULL) {
463 if (freeCertFlag) {
464 CfObjDestroy(trustAnchorArray->data[i]->CACert);
465 }
466 trustAnchorArray->data[i]->CACert = NULL;
467 CfBlobFree(&trustAnchorArray->data[i]->CAPubKey);
468 CfBlobFree(&trustAnchorArray->data[i]->CASubject);
469 CfBlobFree(&trustAnchorArray->data[i]->nameConstraints);
470 CfFree(trustAnchorArray->data[i]);
471 trustAnchorArray->data[i] = NULL;
472 }
473 }
474
475 CfFree(trustAnchorArray);
476 }
477
BuildX509CertChainValidateParams(napi_env env,napi_value arg,HcfX509CertChainValidateParams & param)478 bool BuildX509CertChainValidateParams(napi_env env, napi_value arg, HcfX509CertChainValidateParams ¶m)
479 {
480 napi_valuetype type;
481 napi_typeof(env, arg, &type);
482 if (type != napi_object) {
483 LOGE("wrong argument type. expect string type. [Type]: %d", type);
484 return false;
485 }
486
487 if (!GetValidDate(env, arg, param.date)) {
488 LOGE("Get valid date failed");
489 return false;
490 }
491 if (!GetX509TrustAnchorArray(env, arg, param.trustAnchors)) {
492 LOGE("Get X509 trust anchor array failed");
493 return false;
494 }
495 if (!GetCertCRLCollectionArray(env, arg, param.certCRLCollections)) {
496 LOGE("Get cert CRL collection array failed");
497 return false;
498 }
499 if (!GetRevocationCheckParam(env, arg, param.revocationCheckParam)) {
500 LOGE("Get revocation check param failed!");
501 return false;
502 }
503 if (!GetValidationPolicyType(env, arg, param.policy)) {
504 LOGE("Get validation policy type failed!");
505 return false;
506 }
507 if (!GetSSLHostname(env, arg, param.sslHostname)) {
508 LOGE("Get SSL hostname failed!");
509 return false;
510 }
511 if (!GetKeyUsage(env, arg, param.keyUsage)) {
512 LOGE("Get key usage failed!");
513 return false;
514 }
515
516 return true;
517 }
518
519 } // namespace CertFramework
520 } // namespace OHOS
521