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