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 = %d, error msg:%s.", errCode, pChError);
176             res = ConvertOpensslErrorMsg(errCode);
177             break;
178         }
179     } while (0);
180 
181     if (verifyCtx != NULL) {
182         X509_STORE_CTX_free(verifyCtx);
183     }
184     if (store != NULL) {
185         X509_STORE_free(store);
186     }
187     return res;
188 }
189 
ValidateCertChain(CertsInfo * certs,uint32_t certNum,enum CfEncodingFormat format)190 static CfResult ValidateCertChain(CertsInfo *certs, uint32_t certNum, enum CfEncodingFormat format)
191 {
192     for (uint32_t i = 0; i < certNum; ++i) {
193         X509 *x509 = GetX509Cert(certs[i].data, certs[i].len, format);
194         if (x509 == NULL) {
195             LOGE("Failed to convert cert blob to x509.");
196             return CF_ERR_CRYPTO_OPERATION; /* X509 will be freed by caller func. */
197         }
198         certs[i].x509 = x509;
199     }
200     return ValidateCertChainInner(certs, certNum);
201 }
202 
Validate(HcfCertChainValidatorSpi * self,const CfArray * certsList)203 static CfResult Validate(HcfCertChainValidatorSpi *self, const CfArray *certsList)
204 {
205     if ((self == NULL) || (certsList == NULL) || (certsList->count <= 1)) {
206         LOGE("Invalid input parameter.");
207         return CF_INVALID_PARAMS;
208     }
209     if (!CfIsClassMatch((CfObjectBase *)self, GetX509CertChainValidatorClass())) {
210         LOGE("Class is not match.");
211         return CF_INVALID_PARAMS;
212     }
213     CertsInfo *certs = NULL;
214     CfResult res = InitX509Certs(certsList, &certs);
215     if (res != CF_SUCCESS) {
216         LOGE("Failed to init certs, res = %d.", res);
217         return res;
218     }
219     res = ValidateCertChain(certs, certsList->count, certsList->format);
220     if (res != CF_SUCCESS) {
221         LOGE("Failed to validate cert chain, res = %d.", res);
222     }
223     FreeX509Certs(&certs, certsList->count);
224     return res;
225 }
226 
HcfCertChainValidatorSpiCreate(HcfCertChainValidatorSpi ** spi)227 CfResult HcfCertChainValidatorSpiCreate(HcfCertChainValidatorSpi **spi)
228 {
229     if (spi == NULL) {
230         LOGE("Invalid params, spi is null!");
231         return CF_INVALID_PARAMS;
232     }
233     HcfCertChainValidatorSpi *validator = (HcfCertChainValidatorSpi *)CfMalloc(sizeof(HcfCertChainValidatorSpi), 0);
234     if (validator == NULL) {
235         LOGE("Failed to allocate certChain validator spi object memory!");
236         return CF_ERR_MALLOC;
237     }
238     validator->base.getClass = GetX509CertChainValidatorClass;
239     validator->base.destroy = DestroyX509CertChainValidator;
240     validator->engineValidate = Validate;
241 
242     *spi = validator;
243     return CF_SUCCESS;
244 }