• 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 "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 = %{public}lu, error string = %{public}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         certObj = NULL;
101         return ret;
102     }
103 
104     *object = &certObj->base;
105     return CF_SUCCESS;
106 }
107 
CfOpensslDestoryCert(CfBase ** object)108 void CfOpensslDestoryCert(CfBase **object)
109 {
110     if ((object == NULL) || (*object == NULL)) {
111         CF_LOG_E("invalid input params");
112         return;
113     }
114 
115     CfOpensslCertObj *certObj = (CfOpensslCertObj *)*object;
116     if (certObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_CERT)) {
117         CF_LOG_E("the object is invalid , type = %{public}lu", certObj->base.type);
118         return;
119     }
120 
121     if (certObj->x509Cert != NULL) {
122         X509_free(certObj->x509Cert);
123     }
124     CfFree(certObj);
125     *object = NULL;
126     return;
127 }
128 
CfOpensslVerifyCert(const CfBase * certObj,const CfBlob * pubKey)129 int32_t CfOpensslVerifyCert(const CfBase *certObj, const CfBlob *pubKey)
130 {
131     (void)certObj;
132     (void)pubKey;
133     return CF_SUCCESS;
134 }
135 
GetCertTbs(const CfOpensslCertObj * certObj,CfBlob * outBlob)136 static int32_t GetCertTbs(const CfOpensslCertObj *certObj, CfBlob *outBlob)
137 {
138     X509 *tmp = X509_dup(certObj->x509Cert);
139     if (tmp == NULL) {
140         CF_LOG_E("Failed to copy x509Cert!");
141         CfPrintOpensslError();
142         return CF_ERR_CRYPTO_OPERATION;
143     }
144 
145     unsigned char *out = NULL;
146     int len = i2d_re_X509_tbs(tmp, &out);
147     if (len <= 0) {
148         CF_LOG_E("Failed to convert internal tbs to der format, tbs len is : %{public}d", len);
149         X509_free(tmp);
150         return CF_ERR_CRYPTO_OPERATION;
151     }
152 
153     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
154     X509_free(tmp);
155     OPENSSL_free(out);
156     return ret;
157 }
158 
GetCertIssuerUniqueId(const CfOpensslCertObj * certObj,CfBlob * outBlob)159 static int32_t GetCertIssuerUniqueId(const CfOpensslCertObj *certObj, CfBlob *outBlob)
160 {
161     const ASN1_BIT_STRING *issuerUid = NULL;
162     (void)X509_get0_uids(certObj->x509Cert, &issuerUid, NULL);
163     if (issuerUid == NULL) {
164         CF_LOG_E("Failed to get internal issuerUid!");
165         return CF_NOT_EXIST;
166     }
167 
168     unsigned char *out = NULL;
169     int len = i2d_ASN1_BIT_STRING((ASN1_BIT_STRING *)issuerUid, &out);
170     if (len <= 0) {
171         CF_LOG_E("Failed to convert internal issuerUid to der format, issuerUid len is : %{public}d", len);
172         return CF_ERR_CRYPTO_OPERATION;
173     }
174 
175     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
176     OPENSSL_free(out);
177     return ret;
178 }
179 
GetCertSubjectUniqueId(const CfOpensslCertObj * certObj,CfBlob * outBlob)180 static int32_t GetCertSubjectUniqueId(const CfOpensslCertObj *certObj, CfBlob *outBlob)
181 {
182     const ASN1_BIT_STRING *subjectUid = NULL;
183     (void)X509_get0_uids(certObj->x509Cert, NULL, &subjectUid);
184     if (subjectUid == NULL) {
185         CF_LOG_E("Failed to get internal subjectUid!");
186         return CF_NOT_EXIST;
187     }
188 
189     unsigned char *out = NULL;
190     int len = i2d_ASN1_BIT_STRING((ASN1_BIT_STRING *)subjectUid, &out);
191     if (len <= 0) {
192         CF_LOG_E("Failed to convert internal subjectUid to der format, subjectUid len is : %{public}d", len);
193         return CF_ERR_CRYPTO_OPERATION;
194     }
195 
196     int32_t ret = DeepCopyDataToBlob(out, (uint32_t)len, outBlob);
197     OPENSSL_free(out);
198     return ret;
199 }
200 
GetCertPubKey(const CfOpensslCertObj * certObj,CfBlob * outBlob)201 static int32_t GetCertPubKey(const CfOpensslCertObj *certObj, CfBlob *outBlob)
202 {
203     EVP_PKEY *pubKey = (EVP_PKEY *)X509_get_pubkey(certObj->x509Cert);
204     if (pubKey == NULL) {
205         CfPrintOpensslError();
206         CF_LOG_E("the x509 cert data is error!");
207         return CF_ERR_CRYPTO_OPERATION;
208     }
209 
210     unsigned char *pubKeyBytes = NULL;
211     int32_t pubKeyLen = i2d_PUBKEY(pubKey, &pubKeyBytes);
212     if (pubKeyLen <= 0) {
213         EVP_PKEY_free(pubKey);
214         CfPrintOpensslError();
215         CF_LOG_E("Failed to convert internal pubkey to der format!");
216         return CF_ERR_CRYPTO_OPERATION;
217     }
218 
219     int32_t ret = DeepCopyDataToBlob(pubKeyBytes, (uint32_t)pubKeyLen, outBlob);
220     EVP_PKEY_free(pubKey);
221     OPENSSL_free(pubKeyBytes);
222     return ret;
223 }
224 
GetCertExtensions(const CfOpensslCertObj * certObj,CfBlob * outBlob)225 static int32_t GetCertExtensions(const CfOpensslCertObj *certObj, CfBlob *outBlob)
226 {
227     int32_t ret = CF_SUCCESS;
228     unsigned char *extbytes = NULL;
229     do {
230         X509_EXTENSIONS *exts = (X509_EXTENSIONS *)X509_get0_extensions(certObj->x509Cert);
231         if (exts == NULL) {
232             CF_LOG_E("the x509 cert data is error!");
233             ret = CF_ERR_CRYPTO_OPERATION;
234             break;
235         }
236 
237         if (sk_X509_EXTENSION_num(exts) <= 0) { /* check whether extensions is valid */
238             CF_LOG_E("No extension in certificate!");
239             ret = CF_NOT_EXIST;
240             break;
241         }
242 
243         int32_t extLen = i2d_X509_EXTENSIONS(exts, &extbytes);
244         if (extLen <= 0) {
245             CF_LOG_E("get extLen failed!");
246             ret = CF_ERR_CRYPTO_OPERATION;
247             break;
248         }
249 
250         ret = DeepCopyDataToBlob(extbytes, (uint32_t)extLen, outBlob);
251     } while (0);
252 
253     if (extbytes != NULL) {
254         OPENSSL_free(extbytes);
255     }
256     if (ret != CF_SUCCESS) {
257         CfPrintOpensslError();
258     }
259     return ret;
260 }
261 
CfOpensslGetCertItem(const CfBase * object,CfItemId id,CfBlob * outBlob)262 int32_t CfOpensslGetCertItem(const CfBase *object, CfItemId id, CfBlob *outBlob)
263 {
264     if (object == NULL || outBlob == NULL) {
265         CF_LOG_E("invalid input params");
266         return CF_INVALID_PARAMS;
267     }
268 
269     const CfOpensslCertObj *certObj = (const CfOpensslCertObj *)object;
270     if (certObj->base.type != CF_MAGIC(CF_MAGIC_TYPE_ADAPTER_RESOURCE, CF_OBJ_TYPE_CERT) ||
271         certObj->x509Cert == NULL) {
272         CF_LOG_E("the object is invalid , type = %{public}lu", certObj->base.type);
273         return CF_INVALID_PARAMS;
274     }
275 
276     switch (id) {
277         case CF_ITEM_TBS:
278             return GetCertTbs(certObj, outBlob);
279         case CF_ITEM_ISSUER_UNIQUE_ID:
280             return GetCertIssuerUniqueId(certObj, outBlob);
281         case CF_ITEM_SUBJECT_UNIQUE_ID:
282             return GetCertSubjectUniqueId(certObj, outBlob);
283         case CF_ITEM_EXTENSIONS:
284             return GetCertExtensions(certObj, outBlob);
285         case CF_ITEM_PUBLIC_KEY:
286             return GetCertPubKey(certObj, outBlob);
287         default:
288             CF_LOG_E("the value of id is wrong, id = %{public}d", (int32_t)id);
289             return CF_INVALID_PARAMS;
290     }
291 }
292 
293