1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "ssl_x509.h"
8 #include "ssl_methods.h"
9 #include "ssl_dbg.h"
10 #include "ssl_port.h"
11 #include "bio.h"
12
13 /**
14 * @brief show X509 certification information
15 */
__X509_show_info(X509 * x)16 int __X509_show_info(X509 *x)
17 {
18 return X509_METHOD_CALL(show_info, x);
19 }
20
21 /**
22 * @brief create a X509 certification object according to input X509 certification
23 */
__X509_new(X509 * ix)24 X509* __X509_new(X509 *ix)
25 {
26 int ret;
27 X509 *x;
28
29 x = ssl_mem_zalloc(sizeof(X509));
30 if (!x) {
31 SSL_DEBUG(SSL_X509_ERROR_LEVEL, "no enough memory > (x)");
32 goto no_mem;
33 }
34
35 x->ref_counter = 1;
36
37 if (ix && ix->method)
38 x->method = ix->method;
39 else
40 x->method = X509_method();
41
42 ret = X509_METHOD_CALL(new, x, ix);
43 if (ret) {
44 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(new) return %d", ret);
45 goto failed;
46 }
47
48 return x;
49
50 failed:
51 ssl_mem_free(x);
52 no_mem:
53 return NULL;
54 }
55
56 /**
57 * @brief create a X509 certification object
58 */
X509_new(void)59 X509* X509_new(void)
60 {
61 return __X509_new(NULL);
62 }
63
64 /**
65 * @brief free a X509 certification object
66 */
X509_free(X509 * x)67 void X509_free(X509 *x)
68 {
69 SSL_ASSERT3(x);
70
71 if (--x->ref_counter > 0) {
72 return;
73 }
74
75 X509_METHOD_CALL(free, x);
76
77 ssl_mem_free(x);
78 };
79
80 /**
81 * @brief load a character certification context into system context. If '*cert' is pointed to the
82 * certification, then load certification into it. Or create a new X509 certification object
83 */
d2i_X509(X509 ** cert,const unsigned char * buffer,long len)84 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len)
85 {
86 int m = 0;
87 int ret;
88 X509 *x;
89
90 SSL_ASSERT2(buffer);
91 SSL_ASSERT2(len);
92
93 if (cert && *cert) {
94 x = *cert;
95 } else {
96 x = X509_new();
97 if (!x) {
98 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL");
99 goto failed1;
100 }
101 m = 1;
102 }
103
104 ret = X509_METHOD_CALL(load, x, buffer, len);
105 if (ret) {
106 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
107 goto failed2;
108 }
109
110 return x;
111
112 failed2:
113 if (m)
114 X509_free(x);
115 failed1:
116 return NULL;
117 }
118
119 /**
120 * @brief return SSL X509 verify parameters
121 */
122
SSL_get0_param(SSL * ssl)123 X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl)
124 {
125 return &ssl->param;
126 }
127
128 /**
129 * @brief set X509 host verification flags
130 */
131
X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM * param,unsigned long flags)132 int X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
133 unsigned long flags)
134 {
135 /* flags not supported yet */
136 return 0;
137 }
138
139 /**
140 * @brief clear X509 host verification flags
141 */
142
X509_VERIFY_PARAM_clear_hostflags(X509_VERIFY_PARAM * param,unsigned long flags)143 int X509_VERIFY_PARAM_clear_hostflags(X509_VERIFY_PARAM *param,
144 unsigned long flags)
145 {
146 /* flags not supported yet */
147 return 0;
148 }
149
150 /**
151 * @brief set SSL context client CA certification
152 */
SSL_CTX_add_client_CA(SSL_CTX * ctx,X509 * x)153 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x)
154 {
155 SSL_ASSERT1(ctx);
156 SSL_ASSERT1(x);
157
158 if (ctx->client_CA == x)
159 return 1;
160
161 X509_free(ctx->client_CA);
162
163 ctx->client_CA = x;
164
165 return 1;
166 }
167
168 /**
169 * @brief add CA client certification into the SSL
170 */
SSL_add_client_CA(SSL * ssl,X509 * x)171 int SSL_add_client_CA(SSL *ssl, X509 *x)
172 {
173 SSL_ASSERT1(ssl);
174 SSL_ASSERT1(x);
175
176 if (ssl->client_CA == x)
177 return 1;
178
179 X509_free(ssl->client_CA);
180
181 ssl->client_CA = x;
182
183 return 1;
184 }
185
186 /**
187 * @brief set the SSL context certification
188 */
SSL_CTX_use_certificate(SSL_CTX * ctx,X509 * x)189 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
190 {
191 SSL_ASSERT1(ctx);
192 SSL_ASSERT1(x);
193
194 if (ctx->cert->x509 == x)
195 return 1;
196
197 X509_free(ctx->cert->x509);
198
199 ctx->cert->x509 = x;
200 x->ref_counter++;
201
202 return 1;
203 }
204
205 /**
206 * @brief set the SSL certification
207 */
SSL_use_certificate(SSL * ssl,X509 * x)208 int SSL_use_certificate(SSL *ssl, X509 *x)
209 {
210 SSL_ASSERT1(ssl);
211 SSL_ASSERT1(x);
212
213 if (ssl->cert->x509 == x)
214 return 1;
215
216 X509_free(ssl->cert->x509);
217
218 ssl->cert->x509 = x;
219
220 return 1;
221 }
222
SSL_CTX_add_extra_chain_cert(SSL_CTX * ctx,X509 * x)223 long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x)
224 {
225 return SSL_CTX_use_certificate(ctx, x);
226 }
227
228 /**
229 * @brief get the SSL certification point
230 */
SSL_get_certificate(const SSL * ssl)231 X509 *SSL_get_certificate(const SSL *ssl)
232 {
233 SSL_ASSERT2(ssl);
234
235 return ssl->cert->x509;
236 }
237
238 /**
239 * @brief load certification into the SSL context
240 */
SSL_CTX_use_certificate_ASN1(SSL_CTX * ctx,int len,const unsigned char * d)241 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len,
242 const unsigned char *d)
243 {
244 int ret;
245 X509 *x;
246
247 x = d2i_X509(NULL, d, len);
248 if (!x) {
249 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
250 goto failed1;
251 }
252
253 ret = SSL_CTX_use_certificate(ctx, x); // This uses the "x" so increments ref_count
254 if (!ret) {
255 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret);
256 goto failed2;
257 }
258
259 X509_free(x); // decrements ref_count, so in case of happy flow doesn't free the "x"
260 return 1;
261
262 failed2:
263 X509_free(x);
264 failed1:
265 return 0;
266 }
267
268 /**
269 * @brief load certification into the SSL
270 */
SSL_use_certificate_ASN1(SSL * ssl,int len,const unsigned char * d)271 int SSL_use_certificate_ASN1(SSL *ssl, int len,
272 const unsigned char *d)
273 {
274 int ret;
275 X509 *x;
276
277 x = d2i_X509(NULL, d, len);
278 if (!x) {
279 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL");
280 goto failed1;
281 }
282
283 ret = SSL_use_certificate(ssl, x);
284 if (!ret) {
285 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_use_certificate() return %d", ret);
286 goto failed2;
287 }
288
289 return 1;
290
291 failed2:
292 X509_free(x);
293 failed1:
294 return 0;
295 }
296
297 /**
298 * @brief load the certification file into SSL context
299 */
SSL_CTX_use_certificate_file(SSL_CTX * ctx,const char * file,int type)300 int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
301 {
302 return 0;
303 }
304
305 /**
306 * @brief load the certification file into SSL
307 */
SSL_use_certificate_file(SSL * ssl,const char * file,int type)308 int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
309 {
310 return 0;
311 }
312
313 /**
314 * @brief get peer certification
315 */
SSL_get_peer_certificate(const SSL * ssl)316 X509 *SSL_get_peer_certificate(const SSL *ssl)
317 {
318 SSL_ASSERT2(ssl);
319
320 return ssl->session->peer;
321 }
322
323 /**
324 * @brief set SSL context client CA certification
325 */
X509_STORE_add_cert(X509_STORE * store,X509 * x)326 int X509_STORE_add_cert(X509_STORE *store, X509 *x) {
327
328 x->ref_counter++;
329
330 SSL_CTX *ctx = (SSL_CTX *)store;
331 SSL_ASSERT1(ctx);
332 SSL_ASSERT1(x);
333
334 if (ctx->client_CA == x) {
335 return 1;
336 }
337
338 if (ctx->client_CA!=NULL) {
339 X509_free(ctx->client_CA);
340 }
341
342 ctx->client_CA = x;
343 return 1;
344 }
345
346 /**
347 * @brief load a character certification context into system context.
348 *
349 * If '*cert' is pointed to the certification, then load certification
350 * into it, or create a new X509 certification object.
351 */
PEM_read_bio_X509(BIO * bp,X509 ** cert,pem_password_cb cb,void * u)352 X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, pem_password_cb cb, void *u) {
353 int m = 0;
354 int ret;
355 X509 *x;
356
357 SSL_ASSERT2(BIO_method_type(bp) & BIO_TYPE_MEM);
358 if (bp->data == NULL || bp->dlen == 0) {
359 return NULL;
360 }
361 if (cert && *cert) {
362 x = *cert;
363 } else {
364 x = X509_new();
365 if (!x) {
366 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL");
367 goto failed;
368 }
369 m = 1;
370 }
371
372 ret = X509_METHOD_CALL(load, x, bp->data, bp->dlen);
373 if (ret) {
374 SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret);
375 goto failed;
376 }
377
378 // If buffer successfully created a X509 from the bio, mark the buffer as consumed
379 bp->data = NULL;
380 bp->dlen = 0;
381 return x;
382
383 failed:
384 if (m) {
385 X509_free(x);
386 }
387
388 return NULL;
389 }
390
PEM_read_bio_X509_AUX(BIO * bp,X509 ** cert,pem_password_cb * cb,void * u)391 X509 *PEM_read_bio_X509_AUX(BIO *bp, X509 **cert, pem_password_cb *cb, void *u)
392 {
393 return PEM_read_bio_X509(bp, cert, cb, u);
394 }
395
396 /**
397 * @brief get the SSL context object X509 certification storage
398 */
SSL_CTX_get_cert_store(const SSL_CTX * ctx)399 X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
400 return (X509_STORE *)ctx;
401 }
402