• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "x509_cert_chain_validator_openssl.h"
17 
18 #include <openssl/asn1.h>
19 #include <openssl/bio.h>
20 #include <openssl/crypto.h>
21 #include <openssl/evp.h>
22 #include <openssl/obj_mac.h>
23 #include <openssl/ossl_typ.h>
24 #include <openssl/pem.h>
25 #include <openssl/x509.h>
26 #include <openssl/x509_vfy.h>
27 
28 #include "cf_blob.h"
29 #include "config.h"
30 #include "cf_log.h"
31 #include "cf_memory.h"
32 #include "utils.h"
33 #include "cf_result.h"
34 #include "certificate_openssl_common.h"
35 
36 #define X509_CERT_CHAIN_VALIDATOR_OPENSSL_CLASS "X509CertChainValidatorOpensslClass"
37 
38 typedef struct {
39     uint8_t *data;
40     size_t len;
41     X509 *x509;
42 } CertsInfo;
43 
44 typedef struct {
45     int32_t errCode;
46     CfResult result;
47 } OpensslErrorToResult;
48 
49 static const OpensslErrorToResult ERROR_TO_RESULT_MAP[] = {
50     { X509_V_OK, CF_SUCCESS },
51     { X509_V_ERR_CERT_SIGNATURE_FAILURE, CF_ERR_CERT_SIGNATURE_FAILURE },
52     { X509_V_ERR_CERT_NOT_YET_VALID, CF_ERR_CERT_NOT_YET_VALID },
53     { X509_V_ERR_CERT_HAS_EXPIRED, CF_ERR_CERT_HAS_EXPIRED },
54     { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, CF_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY },
55     { X509_V_ERR_KEYUSAGE_NO_CERTSIGN, CF_ERR_KEYUSAGE_NO_CERTSIGN },
56     { X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, CF_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE },
57 };
58 
ConvertOpensslErrorMsg(int32_t errCode)59 static CfResult ConvertOpensslErrorMsg(int32_t errCode)
60 {
61     for (uint32_t i = 0; i < sizeof(ERROR_TO_RESULT_MAP) / sizeof(OpensslErrorToResult); i++) {
62         if (ERROR_TO_RESULT_MAP[i].errCode == errCode) {
63             return ERROR_TO_RESULT_MAP[i].result;
64         }
65     }
66     return CF_ERR_CRYPTO_OPERATION;
67 }
68 
GetX509CertChainValidatorClass(void)69 static const char *GetX509CertChainValidatorClass(void)
70 {
71     return X509_CERT_CHAIN_VALIDATOR_OPENSSL_CLASS;
72 }
73 
DestroyX509CertChainValidator(CfObjectBase * self)74 static void DestroyX509CertChainValidator(CfObjectBase *self)
75 {
76     if (self == NULL) {
77         LOGE("Invalid params!");
78         return;
79     }
80     if (!CfIsClassMatch(self, GetX509CertChainValidatorClass())) {
81         LOGE("Class is not match.");
82         return;
83     }
84     CfFree((HcfCertChainValidatorSpi *)self);
85 }
86 
InitX509Certs(const CfArray * certsList,CertsInfo ** certs)87 static CfResult InitX509Certs(const CfArray *certsList, CertsInfo **certs)
88 {
89     uint32_t certsInfoLen = sizeof(CertsInfo) * certsList->count;
90     CertsInfo *certsInfo = (CertsInfo *)CfMalloc(certsInfoLen, 0);
91     if (certsInfo == NULL) {
92         LOGE("Failed to new memory for cert info.");
93         return CF_ERR_MALLOC;
94     }
95     for (uint32_t i = 0; i < certsList->count; ++i) {
96         CertsInfo *info = &(certsInfo[i]);
97         info->data = certsList->data[i].data;
98         info->len = certsList->data[i].size;
99     }
100     *certs = certsInfo;
101     return CF_SUCCESS;
102 }
103 
FreeX509Certs(CertsInfo ** certs,uint32_t certNum)104 static void FreeX509Certs(CertsInfo **certs, uint32_t certNum)
105 {
106     if (certs == NULL) {
107         LOGD("Input NULL certs, no need to free.");
108         return;
109     }
110     for (uint32_t i = 0; i < certNum; ++i) {
111         if ((*certs)[i].x509 != NULL) {
112             X509_free((*certs)[i].x509);
113             (*certs)[i].x509 = NULL;
114         }
115     }
116     CfFree(*certs);
117     *certs = NULL;
118 }
119 
GetX509Cert(const uint8_t * data,size_t len,enum CfEncodingFormat format)120 static X509 *GetX509Cert(const uint8_t *data, size_t len, enum CfEncodingFormat format)
121 {
122     X509 *x509 = NULL;
123     BIO *bio = BIO_new_mem_buf(data, len);
124     if (bio == NULL) {
125         LOGE("Failed to new memory for bio.");
126         return NULL;
127     }
128 
129     if (format == CF_FORMAT_DER) {
130         x509 = d2i_X509_bio(bio, NULL);
131     } else if (format == CF_FORMAT_PEM) {
132         x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
133     }
134 
135     BIO_free(bio);
136     return x509;
137 }
138 
ValidateCertChainInner(CertsInfo * certs,uint32_t certNum)139 static CfResult ValidateCertChainInner(CertsInfo *certs, uint32_t certNum)
140 {
141     CfResult res = CF_SUCCESS;
142     X509_STORE *store = X509_STORE_new();
143     X509_STORE_CTX *verifyCtx = X509_STORE_CTX_new();
144     do {
145         if ((store == NULL) || (verifyCtx == NULL)) {
146             LOGE("Failed to verify cert chain init.");
147             res = CF_ERR_MALLOC;
148             break;
149         }
150 
151         for (uint32_t i = certNum - 1; i > 0; i--) { // certs[certNum - 1] represents the 0th cert.
152             if (X509_STORE_add_cert(store, certs[i].x509) != CF_OPENSSL_SUCCESS) {
153                 LOGE("Failed to add cert to store.");
154                 CfPrintOpensslError();
155                 res = CF_ERR_MALLOC;
156                 break;
157             }
158         }
159         if (res != CF_SUCCESS) {
160             break;
161         }
162         /* Do not check cert validity against current time. */
163         X509_STORE_set_flags(store, X509_V_FLAG_NO_CHECK_TIME);
164         int32_t resOpenssl = X509_STORE_CTX_init(verifyCtx, store, certs[0].x509, NULL);
165         if (resOpenssl != CF_OPENSSL_SUCCESS) {
166             LOGE("Failed to init verify ctx.");
167             res = CF_ERR_CRYPTO_OPERATION;
168             CfPrintOpensslError();
169             break;
170         }
171         resOpenssl = X509_verify_cert(verifyCtx);
172         if (resOpenssl != CF_OPENSSL_SUCCESS) {
173             int32_t errCode = X509_STORE_CTX_get_error(verifyCtx);
174             const char *pChError = X509_verify_cert_error_string(errCode);
175             LOGE("Failed to verify cert, openssl openssl error code = %{public}d, error msg:%{public}s.",
176                 errCode, pChError);
177             res = ConvertOpensslErrorMsg(errCode);
178             break;
179         }
180     } while (0);
181 
182     if (verifyCtx != NULL) {
183         X509_STORE_CTX_free(verifyCtx);
184     }
185     if (store != NULL) {
186         X509_STORE_free(store);
187     }
188     return res;
189 }
190 
ValidateCertChain(CertsInfo * certs,uint32_t certNum,enum CfEncodingFormat format)191 static CfResult ValidateCertChain(CertsInfo *certs, uint32_t certNum, enum CfEncodingFormat format)
192 {
193     for (uint32_t i = 0; i < certNum; ++i) {
194         X509 *x509 = GetX509Cert(certs[i].data, certs[i].len, format);
195         if (x509 == NULL) {
196             LOGE("Failed to convert cert blob to x509.");
197             return CF_ERR_CRYPTO_OPERATION; /* X509 will be freed by caller func. */
198         }
199         certs[i].x509 = x509;
200     }
201     return ValidateCertChainInner(certs, certNum);
202 }
203 
Validate(HcfCertChainValidatorSpi * self,const CfArray * certsList)204 static CfResult Validate(HcfCertChainValidatorSpi *self, const CfArray *certsList)
205 {
206     if ((self == NULL) || (certsList == NULL) || (certsList->count <= 1)) {
207         LOGE("Invalid input parameter.");
208         return CF_INVALID_PARAMS;
209     }
210     if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertChainValidatorClass())) {
211         LOGE("Class is not match.");
212         return CF_INVALID_PARAMS;
213     }
214     CertsInfo *certs = NULL;
215     CfResult res = InitX509Certs(certsList, &certs);
216     if (res != CF_SUCCESS) {
217         LOGE("Failed to init certs, res = %{public}d.", res);
218         return res;
219     }
220     res = ValidateCertChain(certs, certsList->count, certsList->format);
221     if (res != CF_SUCCESS) {
222         LOGE("Failed to validate cert chain, res = %{public}d.", res);
223     }
224     FreeX509Certs(&certs, certsList->count);
225     return res;
226 }
227 
HcfCertChainValidatorSpiCreate(HcfCertChainValidatorSpi ** spi)228 CfResult HcfCertChainValidatorSpiCreate(HcfCertChainValidatorSpi **spi)
229 {
230     if (spi == NULL) {
231         LOGE("Invalid params, spi is null!");
232         return CF_INVALID_PARAMS;
233     }
234     HcfCertChainValidatorSpi *validator = (HcfCertChainValidatorSpi *)CfMalloc(sizeof(HcfCertChainValidatorSpi), 0);
235     if (validator == NULL) {
236         LOGE("Failed to allocate certChain validator spi object memory!");
237         return CF_ERR_MALLOC;
238     }
239     validator->base.getClass = GetX509CertChainValidatorClass;
240     validator->base.destroy = DestroyX509CertChainValidator;
241     validator->engineValidate = Validate;
242 
243     *spi = validator;
244     return CF_SUCCESS;
245 }