• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&param->ocspResponderURI);
323     CfBlobFree(&param->ocspResponses);
324     CfBlobFree(&param->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(&param->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 &param)
461 {
462     CfBlobFree(&param.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 &param)
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