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