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 }