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 "cf_adapter_cert_openssl.h"
17 
18 #include "securec.h"
19 
20 #include <openssl/asn1.h>
21 #include <openssl/bio.h>
22 #include <openssl/err.h>
23 #include <openssl/evp.h>
24 #include <openssl/pem.h>
25 #include <openssl/x509v3.h>
26 
27 #include "cf_check.h"
28 #include "cf_log.h"
29 #include "cf_magic.h"
30 #include "cf_memory.h"
31 #include "cf_result.h"
32 
33 #define CF_OPENSSL_ERROR_LEN 128
34 
CfPrintOpensslError(void)35 static void CfPrintOpensslError(void)
36 {
37     char szErr[CF_OPENSSL_ERROR_LEN] = {0};
38     unsigned long errCode = ERR_get_error();
39     ERR_error_string_n(errCode, szErr, CF_OPENSSL_ERROR_LEN);
40 
41     CF_LOG_E("[Openssl]: engine fail, error code = %lu, error string = %s", errCode, szErr);
42 }
43 
DeepCopyDataToBlob(const unsigned char * data,uint32_t len,CfBlob * outBlob)44 static int32_t DeepCopyDataToBlob(const unsigned char *data, uint32_t len, CfBlob *outBlob)
45 {
46     uint8_t *tmp = (uint8_t *)CfMalloc(len, 0);
47     if (tmp == NULL) {
48         CF_LOG_E("Failed to malloc");
49         return CF_ERR_MALLOC;
50     }
51     (void)memcpy_s(tmp, len, data, len);
52 
53     outBlob->data = tmp;
54     outBlob->size = len;
55     return CF_SUCCESS;
56 }
57 
CreateX509Cert(const CfEncodingBlob * inData,CfOpensslCertObj * certObj)58 static int32_t CreateX509Cert(const CfEncodingBlob *inData, CfOpensslCertObj *certObj)
59 {
60     BIO *bio = BIO_new_mem_buf(inData->data, inData->len);
61     if (bio == NULL) {
62         CF_LOG_E("malloc failed");
63         CfPrintOpensslError();
64         return CF_ERR_MALLOC;
65     }
66 
67     /* format has checked in external. value is CF_FORMAT_PEM or CF_FORMAT_DER */
68     if (inData->encodingFormat == CF_FORMAT_PEM) {
69         certObj->x509Cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
70     } else { /* CF_FORMAT_DER */
71         certObj->x509Cert = d2i_X509_bio(bio, NULL);
72     }
73     BIO_free(bio);
74 
75     if (certObj->x509Cert == NULL) {
76         CF_LOG_E("Failed to create cert object");
77         CfPrintOpensslError();
78         return CF_ERR_CRYPTO_OPERATION;
79     }
80     return CF_SUCCESS;
81 }
82 
CfOpensslCreateCert(const CfEncodingBlob * inData,CfBase ** object)83 int32_t CfOpensslCreateCert(const CfEncodingBlob *inData, CfBase **object)
84 {
85     if ((CfCheckEncodingBlob(inData, MAX_LEN_CERTIFICATE) != CF_SUCCESS) || (object == NULL)) {
86         CF_LOG_E("invalid input params");
87         return CF_INVALID_PARAMS;
88     }
89 
90     CfOpensslCertObj *certObj = CfMalloc(sizeof(CfOpensslCertObj), 0);
91     if (certObj == NULL) {
92         CF_LOG_E("malloc failed");
93         return CF_ERR_MALLOC;
94     }
95     certObj->base.type = CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_CERT);
96 
97     int32_t ret = CreateX509Cert(inData, certObj);
98     if (ret != CF_SUCCESS) {
99         CfFree(certObj);
100         return ret;
101     }
102 
103     *object = &certObj->base;
104     return CF_SUCCESS;
105 }
106 
CfOpensslDestoryCert(CfBase ** object)107 void CfOpensslDestoryCert(CfBase **object)
108 {
109     if ((object == NULL) || (*object == NULL)) {
110         CF_LOG_E("invalid input params");
111         return;
112     }
113 
114     CfOpensslCertObj *certObj = (CfOpensslCertObj *)*object;
115     if (certObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_CERT)) {
116         CF_LOG_E("the object is invalid , type = %lu", certObj->base.type);
117         return;
118     }
119 
120     if (certObj->x509Cert != NULL) {
121         X509_free(certObj->x509Cert);
122     }
123     CfFree(certObj);
124     *object = NULL;
125     return;
126 }
127 
CfOpensslVerifyCert(const CfBase * certObj,const CfBlob * pubKey)128 int32_t CfOpensslVerifyCert(const CfBase *certObj, const CfBlob *pubKey)
129 {
130     (void)certObj;
131     (void)pubKey;
132     return CF_SUCCESS;
133 }
134 
GetCertTbs(const CfOpensslCertObj * certObj,CfBlob * outBlob)135 static int32_t GetCertTbs(const CfOpensslCertObj *certObj, CfBlob *outBlob)
136 {
137     X509 *tmp = X509_dup(certObj->x509Cert);
138     if (tmp == NULL) {
139         CF_LOG_E("Failed to copy x509Cert!");
140         CfPrintOpensslError();
141         return CF_ERR_CRYPTO_OPERATION;
142     }
143 
144     unsigned char *out = NULL;
145     int len = i2d_re_X509_tbs(tmp, &out);
146     if (len <= 0) {
147         CF_LOG_E("Failed to convert internal tbs to der format, tbs len is : %d", len);
148         X509_free(tmp);
149         return CF_ERR_CRYPTO_OPERATION;
150     }
151 
152     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
153     X509_free(tmp);
154     OPENSSL_free(out);
155     return ret;
156 }
157 
GetCertIssuerUniqueId(const CfOpensslCertObj * certObj,CfBlob * outBlob)158 static int32_t GetCertIssuerUniqueId(const CfOpensslCertObj *certObj, CfBlob *outBlob)
159 {
160     const ASN1_BIT_STRING *issuerUid = NULL;
161     (void)X509_get0_uids(certObj->x509Cert, &issuerUid, NULL);
162     if (issuerUid == NULL) {
163         CF_LOG_E("Failed to get internal issuerUid!");
164         return CF_NOT_EXIST;
165     }
166 
167     unsigned char *out = NULL;
168     int len = i2d_ASN1_BIT_STRING((ASN1_BIT_STRING *)issuerUid, &out);
169     if (len <= 0) {
170         CF_LOG_E("Failed to convert internal issuerUid to der format, issuerUid len is : %d", len);
171         return CF_ERR_CRYPTO_OPERATION;
172     }
173 
174     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
175     OPENSSL_free(out);
176     return ret;
177 }
178 
GetCertSubjectUniqueId(const CfOpensslCertObj * certObj,CfBlob * outBlob)179 static int32_t GetCertSubjectUniqueId(const CfOpensslCertObj *certObj, CfBlob *outBlob)
180 {
181     const ASN1_BIT_STRING *subjectUid = NULL;
182     (void)X509_get0_uids(certObj->x509Cert, NULL, &subjectUid);
183     if (subjectUid == NULL) {
184         CF_LOG_E("Failed to get internal subjectUid!");
185         return CF_NOT_EXIST;
186     }
187 
188     unsigned char *out = NULL;
189     int len = i2d_ASN1_BIT_STRING((ASN1_BIT_STRING *)subjectUid, &out);
190     if (len <= 0) {
191         CF_LOG_E("Failed to convert internal subjectUid to der format, subjectUid len is : %d", len);
192         return CF_ERR_CRYPTO_OPERATION;
193     }
194 
195     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
196     OPENSSL_free(out);
197     return ret;
198 }
199 
GetCertPubKey(const CfOpensslCertObj * certObj,CfBlob * outBlob)200 static int32_t GetCertPubKey(const CfOpensslCertObj *certObj, CfBlob *outBlob)
201 {
202     EVP_PKEY *pubKey = (EVP_PKEY *)X509_get_pubkey(certObj->x509Cert);
203     if (pubKey == NULL) {
204         CfPrintOpensslError();
205         CF_LOG_E("the x509 cert data is error!");
206         return CF_ERR_CRYPTO_OPERATION;
207     }
208 
209     unsigned char *pubKeyBytes = NULL;
210     int32_t pubKeyLen = i2d_PUBKEY(pubKey, &pubKeyBytes);
211     if (pubKeyLen <= 0) {
212         EVP_PKEY_free(pubKey);
213         CfPrintOpensslError();
214         CF_LOG_E("Failed to convert internal pubkey to der format!");
215         return CF_ERR_CRYPTO_OPERATION;
216     }
217 
218     int32_t ret = DeepCopyDataToBlob(pubKeyBytes, (uint32_t)pubKeyLen, outBlob);
219     EVP_PKEY_free(pubKey);
220     OPENSSL_free(pubKeyBytes);
221     return ret;
222 }
223 
GetCertExtensions(const CfOpensslCertObj * certObj,CfBlob * outBlob)224 static int32_t GetCertExtensions(const CfOpensslCertObj *certObj, CfBlob *outBlob)
225 {
226     int32_t ret = CF_SUCCESS;
227     unsigned char *extbytes = NULL;
228     do {
229         X509_EXTENSIONS *exts = (X509_EXTENSIONS *)X509_get0_extensions(certObj->x509Cert);
230         if (exts == NULL) {
231             CF_LOG_E("the x509 cert data is error!");
232             ret = CF_ERR_CRYPTO_OPERATION;
233             break;
234         }
235 
236         if (sk_X509_EXTENSION_num(exts) <= 0) { /* check whether extensions is valid */
237             CF_LOG_E("No extension in certificate!");
238             ret = CF_NOT_EXIST;
239             break;
240         }
241 
242         int32_t extLen = i2d_X509_EXTENSIONS(exts, &extbytes);
243         if (extLen <= 0) {
244             CF_LOG_E("get extLen failed!");
245             ret = CF_ERR_CRYPTO_OPERATION;
246             break;
247         }
248 
249         ret = DeepCopyDataToBlob(extbytes, (uint32_t)extLen, outBlob);
250     } while (0);
251 
252     if (extbytes != NULL) {
253         OPENSSL_free(extbytes);
254     }
255     if (ret != CF_SUCCESS) {
256         CfPrintOpensslError();
257     }
258     return ret;
259 }
260 
CfOpensslGetCertItem(const CfBase * object,CfItemId id,CfBlob * outBlob)261 int32_t CfOpensslGetCertItem(const CfBase *object, CfItemId id, CfBlob *outBlob)
262 {
263     if (object == NULL || outBlob == NULL) {
264         CF_LOG_E("invalid input params");
265         return CF_INVALID_PARAMS;
266     }
267 
268     const CfOpensslCertObj *certObj = (const CfOpensslCertObj *)object;
269     if (certObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_CERT) ||
270         certObj->x509Cert == NULL) {
271         CF_LOG_E("the object is invalid , type = %lu", certObj->base.type);
272         return CF_INVALID_PARAMS;
273     }
274 
275     switch (id) {
276         case CF_ITEM_TBS:
277             return GetCertTbs(certObj, outBlob);
278         case CF_ITEM_ISSUER_UNIQUE_ID:
279             return GetCertIssuerUniqueId(certObj, outBlob);
280         case CF_ITEM_SUBJECT_UNIQUE_ID:
281             return GetCertSubjectUniqueId(certObj, outBlob);
282         case CF_ITEM_EXTENSIONS:
283             return GetCertExtensions(certObj, outBlob);
284         case CF_ITEM_PUBLIC_KEY:
285             return GetCertPubKey(certObj, outBlob);
286         default:
287             CF_LOG_E("the value of id is wrong, id = %d", (int32_t)id);
288             return CF_INVALID_PARAMS;
289     }
290 }
291 
292