• 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,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(&param->ocspResponderURI);
319     CfBlobFree(&param->ocspResponses);
320     CfBlobFree(&param->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(&param->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 &param)
429 {
430     CfBlobFree(&param.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 &param)
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