]> jfr.im git - solanum.git/blob - libratbox/src/openssl.c
libratbox: Fix undefined behaviour advancing pointer beyond end of array.
[solanum.git] / libratbox / src / openssl.c
1 /*
2 * libratbox: a library used by ircd-ratbox and other things
3 * openssl.c: openssl related code
4 *
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 *
23 * $Id: commio.c 24808 2008-01-02 08:17:05Z androsyn $
24 */
25
26 #include <libratbox_config.h>
27 #include <ratbox_lib.h>
28
29 #ifdef HAVE_OPENSSL
30
31 #include <commio-int.h>
32 #include <commio-ssl.h>
33 #include <openssl/ssl.h>
34 #include <openssl/dh.h>
35 #include <openssl/err.h>
36 #include <openssl/rand.h>
37
38 static SSL_CTX *ssl_server_ctx;
39 static SSL_CTX *ssl_client_ctx;
40 static int libratbox_index = -1;
41
42 static unsigned long
43 get_last_err(void)
44 {
45 unsigned long t_err, err = 0;
46 err = ERR_get_error();
47 if(err == 0)
48 return 0;
49
50 while((t_err = ERR_get_error()) > 0)
51 err = t_err;
52
53 return err;
54 }
55
56 void
57 rb_ssl_shutdown(rb_fde_t *F)
58 {
59 int i;
60 if(F == NULL || F->ssl == NULL)
61 return;
62 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
63
64 for(i = 0; i < 4; i++)
65 {
66 if(SSL_shutdown((SSL *) F->ssl))
67 break;
68 }
69 get_last_err();
70 SSL_free((SSL *) F->ssl);
71 }
72
73 unsigned int
74 rb_ssl_handshake_count(rb_fde_t *F)
75 {
76 return F->handshake_count;
77 }
78
79 void
80 rb_ssl_clear_handshake_count(rb_fde_t *F)
81 {
82 F->handshake_count = 0;
83 }
84
85 static void
86 rb_ssl_timeout(rb_fde_t *F, void *notused)
87 {
88 lrb_assert(F->accept != NULL);
89 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
90 }
91
92
93 static void
94 rb_ssl_info_callback(SSL * ssl, int where, int ret)
95 {
96 if(where & SSL_CB_HANDSHAKE_START)
97 {
98 rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index);
99 if(F == NULL)
100 return;
101 F->handshake_count++;
102 }
103 }
104
105 static void
106 rb_setup_ssl_cb(rb_fde_t *F)
107 {
108 SSL_set_ex_data(F->ssl, libratbox_index, (char *)F);
109 SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *,int,int))rb_ssl_info_callback);
110 }
111
112 static void
113 rb_ssl_tryaccept(rb_fde_t *F, void *data)
114 {
115 int ssl_err;
116 lrb_assert(F->accept != NULL);
117 int flags;
118 struct acceptdata *ad;
119
120 if(!SSL_is_init_finished((SSL *) F->ssl))
121 {
122 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
123 {
124 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
125 {
126 case SSL_ERROR_WANT_READ:
127 case SSL_ERROR_WANT_WRITE:
128 if(ssl_err == SSL_ERROR_WANT_WRITE)
129 flags = RB_SELECT_WRITE;
130 else
131 flags = RB_SELECT_READ;
132 F->ssl_errno = get_last_err();
133 rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
134 break;
135 case SSL_ERROR_SYSCALL:
136 F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
137 break;
138 default:
139 F->ssl_errno = get_last_err();
140 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
141 break;
142 }
143 return;
144 }
145 }
146 rb_settimeout(F, 0, NULL, NULL);
147 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
148
149 ad = F->accept;
150 F->accept = NULL;
151 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
152 rb_free(ad);
153
154 }
155
156
157 static void
158 rb_ssl_accept_common(rb_fde_t *new_F)
159 {
160 int ssl_err;
161 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
162 {
163 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
164 {
165 case SSL_ERROR_SYSCALL:
166 if(rb_ignore_errno(errno))
167 case SSL_ERROR_WANT_READ:
168 case SSL_ERROR_WANT_WRITE:
169 {
170 new_F->ssl_errno = get_last_err();
171 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
172 rb_ssl_tryaccept, NULL);
173 return;
174 }
175 default:
176 new_F->ssl_errno = get_last_err();
177 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
178 return;
179 }
180 }
181 else
182 {
183 rb_ssl_tryaccept(new_F, NULL);
184 }
185 }
186
187 void
188 rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
189 {
190 new_F->type |= RB_FD_SSL;
191 new_F->ssl = SSL_new(ssl_server_ctx);
192 new_F->accept = rb_malloc(sizeof(struct acceptdata));
193
194 new_F->accept->callback = cb;
195 new_F->accept->data = data;
196 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
197
198 new_F->accept->addrlen = 0;
199 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
200 rb_setup_ssl_cb(new_F);
201 rb_ssl_accept_common(new_F);
202 }
203
204
205
206
207 void
208 rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
209 {
210 new_F->type |= RB_FD_SSL;
211 new_F->ssl = SSL_new(ssl_server_ctx);
212 new_F->accept = rb_malloc(sizeof(struct acceptdata));
213
214 new_F->accept->callback = F->accept->callback;
215 new_F->accept->data = F->accept->data;
216 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
217 memcpy(&new_F->accept->S, st, addrlen);
218 new_F->accept->addrlen = addrlen;
219
220 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
221 rb_setup_ssl_cb(new_F);
222 rb_ssl_accept_common(new_F);
223 }
224
225 static ssize_t
226 rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
227 {
228 ssize_t ret;
229 unsigned long err;
230 SSL *ssl = F->ssl;
231
232 if(r_or_w == 0)
233 ret = (ssize_t) SSL_read(ssl, rbuf, (int)count);
234 else
235 ret = (ssize_t) SSL_write(ssl, wbuf, (int)count);
236
237 if(ret < 0)
238 {
239 switch (SSL_get_error(ssl, ret))
240 {
241 case SSL_ERROR_WANT_READ:
242 errno = EAGAIN;
243 return RB_RW_SSL_NEED_READ;
244 case SSL_ERROR_WANT_WRITE:
245 errno = EAGAIN;
246 return RB_RW_SSL_NEED_WRITE;
247 case SSL_ERROR_ZERO_RETURN:
248 return 0;
249 case SSL_ERROR_SYSCALL:
250 err = get_last_err();
251 if(err == 0)
252 {
253 F->ssl_errno = 0;
254 return RB_RW_IO_ERROR;
255 }
256 break;
257 default:
258 err = get_last_err();
259 break;
260 }
261 F->ssl_errno = err;
262 if(err > 0)
263 {
264 errno = EIO; /* not great but... */
265 return RB_RW_SSL_ERROR;
266 }
267 return RB_RW_IO_ERROR;
268 }
269 return ret;
270 }
271
272 ssize_t
273 rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
274 {
275 return rb_ssl_read_or_write(0, F, buf, NULL, count);
276 }
277
278 ssize_t
279 rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
280 {
281 return rb_ssl_read_or_write(1, F, NULL, buf, count);
282 }
283
284 static int
285 verify_accept_all_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
286 {
287 return 1;
288 }
289
290 static const char *
291 get_ssl_error(unsigned long err)
292 {
293 static char buf[512];
294
295 ERR_error_string_n(err, buf, sizeof buf);
296 return buf;
297 }
298
299 int
300 rb_init_ssl(void)
301 {
302 int ret = 1;
303 char libratbox_data[] = "libratbox data";
304 SSL_load_error_strings();
305 SSL_library_init();
306 libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL);
307 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
308 if(ssl_server_ctx == NULL)
309 {
310 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
311 get_ssl_error(ERR_get_error()));
312 ret = 0;
313 }
314 /* Disable SSLv2, make the client use our settings */
315 SSL_CTX_set_options(ssl_server_ctx, SSL_OP_NO_SSLv2 | SSL_OP_CIPHER_SERVER_PREFERENCE
316 #ifdef SSL_OP_NO_COMPRESSION
317 | SSL_OP_NO_COMPRESSION
318 #endif
319 #ifdef SSL_OP_SINGLE_DH_USE
320 | SSL_OP_SINGLE_DH_USE
321 #endif
322 );
323 SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
324 SSL_CTX_set_session_id_context(ssl_server_ctx,
325 (const unsigned char *)"libratbox", 9);
326 SSL_CTX_set_cipher_list(ssl_server_ctx, "EECDH+HIGH:EDH+HIGH:HIGH:!aNULL");
327
328 /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks
329 and bastardise their OpenSSL for stupid reasons... */
330 #if (OPENSSL_VERSION_NUMBER >= 0x10000000) && defined(NID_secp384r1)
331 SSL_CTX_set_tmp_ecdh(ssl_server_ctx, EC_KEY_new_by_curve_name(NID_secp384r1));
332 #ifdef SSL_OP_SINGLE_ECDH_USE
333 SSL_CTX_set_options(ssl_server_ctx, SSL_OP_SINGLE_ECDH_USE);
334 #endif
335 #endif
336
337 ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
338
339 if(ssl_client_ctx == NULL)
340 {
341 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
342 get_ssl_error(ERR_get_error()));
343 ret = 0;
344 }
345 return ret;
346 }
347
348
349 int
350 rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
351 {
352 DH *dh;
353 unsigned long err;
354 if(cert == NULL)
355 {
356 rb_lib_log("rb_setup_ssl_server: No certificate file");
357 return 0;
358 }
359 if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert))
360 {
361 err = ERR_get_error();
362 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
363 get_ssl_error(err));
364 return 0;
365 }
366
367 if(keyfile == NULL)
368 {
369 rb_lib_log("rb_setup_ssl_server: No key file");
370 return 0;
371 }
372
373
374 if(!SSL_CTX_use_PrivateKey_file(ssl_server_ctx, keyfile, SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(ssl_client_ctx, keyfile, SSL_FILETYPE_PEM))
375 {
376 err = ERR_get_error();
377 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
378 get_ssl_error(err));
379 return 0;
380 }
381
382 if(dhfile != NULL)
383 {
384 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
385 BIO *bio = BIO_new_file(dhfile, "r");
386 if(bio != NULL)
387 {
388 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
389 if(dh == NULL)
390 {
391 err = ERR_get_error();
392 rb_lib_log
393 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
394 dhfile, get_ssl_error(err));
395 BIO_free(bio);
396 return 0;
397 }
398 BIO_free(bio);
399 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
400 }
401 else
402 {
403 err = ERR_get_error();
404 rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
405 dhfile, get_ssl_error(err));
406 }
407 }
408 return 1;
409 }
410
411 int
412 rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept)
413 {
414 int result;
415
416 result = rb_listen(F, backlog, defer_accept);
417 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
418
419 return result;
420 }
421
422 struct ssl_connect
423 {
424 CNCB *callback;
425 void *data;
426 int timeout;
427 };
428
429 static void
430 rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
431 {
432 F->connect->callback = sconn->callback;
433 F->connect->data = sconn->data;
434 rb_free(sconn);
435 rb_connect_callback(F, status);
436 }
437
438 static void
439 rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
440 {
441 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
442 }
443
444 static void
445 rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
446 {
447 struct ssl_connect *sconn = data;
448 int ssl_err;
449 if(!SSL_is_init_finished((SSL *) F->ssl))
450 {
451 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
452 {
453 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
454 {
455 case SSL_ERROR_SYSCALL:
456 if(rb_ignore_errno(errno))
457 case SSL_ERROR_WANT_READ:
458 case SSL_ERROR_WANT_WRITE:
459 {
460 F->ssl_errno = get_last_err();
461 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
462 rb_ssl_tryconn_cb, sconn);
463 return;
464 }
465 default:
466 F->ssl_errno = get_last_err();
467 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
468 return;
469 }
470 }
471 else
472 {
473 rb_ssl_connect_realcb(F, RB_OK, sconn);
474 }
475 }
476 }
477
478 static void
479 rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
480 {
481 struct ssl_connect *sconn = data;
482 int ssl_err;
483 if(status != RB_OK)
484 {
485 rb_ssl_connect_realcb(F, status, sconn);
486 return;
487 }
488
489 F->type |= RB_FD_SSL;
490 F->ssl = SSL_new(ssl_client_ctx);
491 SSL_set_fd((SSL *) F->ssl, F->fd);
492 rb_setup_ssl_cb(F);
493 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
494 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
495 {
496 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
497 {
498 case SSL_ERROR_SYSCALL:
499 if(rb_ignore_errno(errno))
500 case SSL_ERROR_WANT_READ:
501 case SSL_ERROR_WANT_WRITE:
502 {
503 F->ssl_errno = get_last_err();
504 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
505 rb_ssl_tryconn_cb, sconn);
506 return;
507 }
508 default:
509 F->ssl_errno = get_last_err();
510 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
511 return;
512 }
513 }
514 else
515 {
516 rb_ssl_connect_realcb(F, RB_OK, sconn);
517 }
518 }
519
520 void
521 rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
522 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
523 {
524 struct ssl_connect *sconn;
525 if(F == NULL)
526 return;
527
528 sconn = rb_malloc(sizeof(struct ssl_connect));
529 sconn->data = data;
530 sconn->callback = callback;
531 sconn->timeout = timeout;
532 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
533
534 }
535
536 void
537 rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
538 {
539 struct ssl_connect *sconn;
540 int ssl_err;
541 if(F == NULL)
542 return;
543
544 sconn = rb_malloc(sizeof(struct ssl_connect));
545 sconn->data = data;
546 sconn->callback = callback;
547 sconn->timeout = timeout;
548 F->connect = rb_malloc(sizeof(struct conndata));
549 F->connect->callback = callback;
550 F->connect->data = data;
551 F->type |= RB_FD_SSL;
552 F->ssl = SSL_new(ssl_client_ctx);
553
554 SSL_set_fd((SSL *) F->ssl, F->fd);
555 rb_setup_ssl_cb(F);
556 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
557 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
558 {
559 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
560 {
561 case SSL_ERROR_SYSCALL:
562 if(rb_ignore_errno(errno))
563 case SSL_ERROR_WANT_READ:
564 case SSL_ERROR_WANT_WRITE:
565 {
566 F->ssl_errno = get_last_err();
567 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
568 rb_ssl_tryconn_cb, sconn);
569 return;
570 }
571 default:
572 F->ssl_errno = get_last_err();
573 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
574 return;
575 }
576 }
577 else
578 {
579 rb_ssl_connect_realcb(F, RB_OK, sconn);
580 }
581 }
582
583 int
584 rb_init_prng(const char *path, prng_seed_t seed_type)
585 {
586 if(seed_type == RB_PRNG_DEFAULT)
587 {
588 #ifdef _WIN32
589 RAND_screen();
590 #endif
591 return RAND_status();
592 }
593 if(path == NULL)
594 return RAND_status();
595
596 switch (seed_type)
597 {
598 case RB_PRNG_EGD:
599 if(RAND_egd(path) == -1)
600 return -1;
601 break;
602 case RB_PRNG_FILE:
603 if(RAND_load_file(path, -1) == -1)
604 return -1;
605 break;
606 #ifdef _WIN32
607 case RB_PRNGWIN32:
608 RAND_screen();
609 break;
610 #endif
611 default:
612 return -1;
613 }
614
615 return RAND_status();
616 }
617
618 int
619 rb_get_random(void *buf, size_t length)
620 {
621 int ret;
622
623 if((ret = RAND_bytes(buf, length)) == 0)
624 {
625 /* remove the error from the queue */
626 ERR_get_error();
627 }
628 return ret;
629 }
630
631 int
632 rb_get_pseudo_random(void *buf, size_t length)
633 {
634 int ret;
635 ret = RAND_pseudo_bytes(buf, length);
636 if(ret < 0)
637 return 0;
638 return 1;
639 }
640
641 const char *
642 rb_get_ssl_strerror(rb_fde_t *F)
643 {
644 return get_ssl_error(F->ssl_errno);
645 }
646
647 int
648 rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
649 {
650 X509 *cert;
651 int res;
652
653 if (F->ssl == NULL)
654 return 0;
655
656 cert = SSL_get_peer_certificate((SSL *) F->ssl);
657 if(cert != NULL)
658 {
659 res = SSL_get_verify_result((SSL *) F->ssl);
660 if(res == X509_V_OK ||
661 res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
662 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
663 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
664 {
665 memcpy(certfp, cert->sha1_hash, RB_SSL_CERTFP_LEN);
666 X509_free(cert);
667 return 1;
668 }
669 X509_free(cert);
670 }
671
672 return 0;
673 }
674
675 int
676 rb_supports_ssl(void)
677 {
678 return 1;
679 }
680
681 void
682 rb_get_ssl_info(char *buf, size_t len)
683 {
684 rb_snprintf(buf, len, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
685 SSLeay_version(SSLEAY_VERSION),
686 (long)OPENSSL_VERSION_NUMBER, SSLeay());
687 }
688
689
690 #endif /* HAVE_OPESSL */