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