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 if (param->ocspResponderCert != nullptr) {
314 CfObjDestroy(param->ocspResponderCert);
315 }
316 CfBlobFree(¶m->ocspResponses);
317 CfBlobFree(¶m->crlDownloadURI);
318 if (param->options != nullptr) {
319 if (param->options->data != nullptr) {
320 CfFree(param->options->data);
321 }
322 CfFree(param->options);
323 }
324 CfBlobFree(¶m->ocspDigest);
325 CfFree(param);
326 }
327
GetRevocationCheckParam(napi_env env,napi_value arg,HcfRevocationCheckParam * & out)328 static bool GetRevocationCheckParam(napi_env env, napi_value arg, HcfRevocationCheckParam *&out)
329 {
330 napi_value rckObj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_REVOCATIONCHECKPARAM.c_str());
331 if (rckObj == nullptr) {
332 LOGI("RevocationCheckParam do not exist!");
333 return true;
334 }
335 napi_valuetype valueType;
336 napi_typeof(env, rckObj, &valueType);
337 if (valueType == napi_null || valueType != napi_object) {
338 LOGE("Failed to check input param!");
339 return false;
340 }
341
342 out = static_cast<HcfRevocationCheckParam *>(CfMalloc(sizeof(HcfRevocationCheckParam), 0));
343 if (out == nullptr) {
344 LOGE("Failed to allocate out memory!");
345 return false;
346 }
347 if (!GetRevocationDetail(env, rckObj, out)) {
348 LOGE("Failed to get revocation detail!");
349 FreeHcfRevocationCheckParam(out);
350 return false;
351 }
352
353 return true;
354 }
355
GetValidationPolicyType(napi_env env,napi_value arg,HcfValPolicyType & out)356 static bool GetValidationPolicyType(napi_env env, napi_value arg, HcfValPolicyType &out)
357 {
358 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_POLICY.c_str());
359 if (obj != nullptr) {
360 napi_status status = napi_get_value_int32(env, obj, (int32_t *)&out);
361 if (status != napi_ok) {
362 return false;
363 }
364 }
365 return true;
366 }
367
GetSSLHostname(napi_env env,napi_value arg,CfBlob * & out)368 static bool GetSSLHostname(napi_env env, napi_value arg, CfBlob *&out)
369 {
370 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_SSLHOSTNAME.c_str());
371 if (obj == nullptr) {
372 LOGI("Param type not SSLHostname!");
373 return true;
374 }
375 out = CertGetBlobFromStringJSParams(env, obj);
376 if (out == nullptr) {
377 LOGE("SSLHostname is nullptr");
378 return false;
379 }
380 return true;
381 }
382
GetKeyUsage(napi_env env,napi_value arg,HcfKuArray * & out)383 static bool GetKeyUsage(napi_env env, napi_value arg, HcfKuArray *&out)
384 {
385 out = nullptr;
386 napi_value obj = GetProp(env, arg, CERT_CHAIN_VALIDATE_TAG_KEYUSAGE.c_str());
387 if (obj == nullptr) {
388 return true;
389 }
390 bool flag = false;
391 napi_status status = napi_is_array(env, obj, &flag);
392 if (status != napi_ok || !flag) {
393 return false;
394 }
395 uint32_t length = 0;
396 status = napi_get_array_length(env, obj, &length);
397 if (status != napi_ok || length == 0 || length > MAX_NAPI_ARRAY_OF_U8ARR) {
398 return false;
399 }
400 out = static_cast<HcfKuArray *>(CfMalloc(sizeof(HcfKuArray), 0));
401 if (out == nullptr) {
402 return false;
403 }
404 out->count = length;
405 out->data = static_cast<HcfKeyUsageType *>(CfMalloc(length * sizeof(HcfKeyUsageType), 0));
406 if (out->data == nullptr) {
407 CfFree(out);
408 out = nullptr;
409 return false;
410 }
411 for (uint32_t i = 0; i < length; i++) {
412 napi_value element;
413 if (napi_get_element(env, obj, i, &element) != napi_ok ||
414 napi_get_value_int32(env, element, (int32_t *)&(out->data[i])) != napi_ok) {
415 CfFree(out->data);
416 CfFree(out);
417 out = nullptr;
418 return false;
419 }
420 }
421 return true;
422 }
423
FreeX509CertChainValidateParams(HcfX509CertChainValidateParams & param)424 void FreeX509CertChainValidateParams(HcfX509CertChainValidateParams ¶m)
425 {
426 CfBlobFree(¶m.date);
427 if (param.trustAnchors != nullptr) {
428 for (uint32_t i = 0; i < param.trustAnchors->count; ++i) {
429 FreeX509TrustAnchorObj(param.trustAnchors->data[i]);
430 }
431 CfFree(param.trustAnchors);
432 param.trustAnchors = nullptr;
433 }
434
435 if (param.certCRLCollections != nullptr) {
436 CfFree(param.certCRLCollections->data);
437 CfFree(param.certCRLCollections);
438 param.certCRLCollections = nullptr;
439 }
440
441 CfBlobFree(&(param.sslHostname));
442 if (param.keyUsage != nullptr) {
443 CfFree(param.keyUsage->data);
444 CfFree(param.keyUsage);
445 param.keyUsage = nullptr;
446 }
447 }
448
FreeTrustAnchorArray(HcfX509TrustAnchorArray * trustAnchorArray,bool freeCertFlag)449 void FreeTrustAnchorArray(HcfX509TrustAnchorArray *trustAnchorArray, bool freeCertFlag)
450 {
451 if (trustAnchorArray == NULL) {
452 return;
453 }
454 for (uint32_t i = 0; i < trustAnchorArray->count; i++) {
455 if (trustAnchorArray->data[i] != NULL) {
456 if (freeCertFlag) {
457 CfObjDestroy(trustAnchorArray->data[i]->CACert);
458 }
459 trustAnchorArray->data[i]->CACert = NULL;
460 CfBlobFree(&trustAnchorArray->data[i]->CAPubKey);
461 CfBlobFree(&trustAnchorArray->data[i]->CASubject);
462 CfBlobFree(&trustAnchorArray->data[i]->nameConstraints);
463 CfFree(trustAnchorArray->data[i]);
464 trustAnchorArray->data[i] = NULL;
465 }
466 }
467
468 CfFree(trustAnchorArray);
469 }
470
BuildX509CertChainValidateParams(napi_env env,napi_value arg,HcfX509CertChainValidateParams & param)471 bool BuildX509CertChainValidateParams(napi_env env, napi_value arg, HcfX509CertChainValidateParams ¶m)
472 {
473 napi_valuetype type;
474 napi_typeof(env, arg, &type);
475 if (type != napi_object) {
476 LOGE("wrong argument type. expect string type. [Type]: %d", type);
477 return false;
478 }
479
480 if (!GetValidDate(env, arg, param.date)) {
481 LOGE("Get valid date failed");
482 return false;
483 }
484 if (!GetX509TrustAnchorArray(env, arg, param.trustAnchors)) {
485 LOGE("Get X509 trust anchor array failed");
486 return false;
487 }
488 if (!GetCertCRLCollectionArray(env, arg, param.certCRLCollections)) {
489 LOGE("Get cert CRL collection array failed");
490 return false;
491 }
492 if (!GetRevocationCheckParam(env, arg, param.revocationCheckParam)) {
493 LOGE("Get revocation check param failed!");
494 return false;
495 }
496 if (!GetValidationPolicyType(env, arg, param.policy)) {
497 LOGE("Get validation policy type failed!");
498 return false;
499 }
500 if (!GetSSLHostname(env, arg, param.sslHostname)) {
501 LOGE("Get SSL hostname failed!");
502 return false;
503 }
504 if (!GetKeyUsage(env, arg, param.keyUsage)) {
505 LOGE("Get key usage failed!");
506 return false;
507 }
508
509 return true;
510 }
511
512 } // namespace CertFramework
513 } // namespace OHOS
514