]> jfr.im git - solanum.git/blame - libratbox/src/openssl.c
libratbox/openssl: Set explicit cipher list for the client context aswell
[solanum.git] / libratbox / src / openssl.c
CommitLineData
db137867
AC
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.
55abcbb2 17 *
db137867
AC
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>
d3806d05 36#include <openssl/evp.h>
db137867
AC
37#include <openssl/rand.h>
38
39static SSL_CTX *ssl_server_ctx;
40static SSL_CTX *ssl_client_ctx;
c2ac22cc 41static int libratbox_index = -1;
db137867 42
3202e249
VY
43static unsigned long
44get_last_err(void)
db137867
AC
45{
46 unsigned long t_err, err = 0;
47 err = ERR_get_error();
48 if(err == 0)
49 return 0;
3202e249 50
db137867
AC
51 while((t_err = ERR_get_error()) > 0)
52 err = t_err;
53
54 return err;
55}
56
57void
3202e249 58rb_ssl_shutdown(rb_fde_t *F)
db137867
AC
59{
60 int i;
61 if(F == NULL || F->ssl == NULL)
62 return;
63 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
64
3202e249 65 for(i = 0; i < 4; i++)
db137867
AC
66 {
67 if(SSL_shutdown((SSL *) F->ssl))
68 break;
69 }
70 get_last_err();
71 SSL_free((SSL *) F->ssl);
72}
73
c2ac22cc
VY
74unsigned int
75rb_ssl_handshake_count(rb_fde_t *F)
76{
77 return F->handshake_count;
78}
79
80void
81rb_ssl_clear_handshake_count(rb_fde_t *F)
82{
83 F->handshake_count = 0;
84}
85
db137867 86static void
3202e249 87rb_ssl_timeout(rb_fde_t *F, void *notused)
db137867 88{
73d6283c
VY
89 lrb_assert(F->accept != NULL);
90 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
db137867
AC
91}
92
93
3202e249
VY
94static void
95rb_ssl_info_callback(SSL * ssl, int where, int ret)
c2ac22cc
VY
96{
97 if(where & SSL_CB_HANDSHAKE_START)
98 {
99 rb_fde_t *F = SSL_get_ex_data(ssl, libratbox_index);
100 if(F == NULL)
101 return;
102 F->handshake_count++;
3202e249 103 }
c2ac22cc
VY
104}
105
106static void
107rb_setup_ssl_cb(rb_fde_t *F)
108{
109 SSL_set_ex_data(F->ssl, libratbox_index, (char *)F);
3202e249 110 SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *,int,int))rb_ssl_info_callback);
c2ac22cc
VY
111}
112
db137867 113static void
3202e249 114rb_ssl_tryaccept(rb_fde_t *F, void *data)
db137867
AC
115{
116 int ssl_err;
117 lrb_assert(F->accept != NULL);
73d6283c 118 int flags;
2142f691 119 struct acceptdata *ad;
db137867
AC
120
121 if(!SSL_is_init_finished((SSL *) F->ssl))
122 {
123 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
124 {
125 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
126 {
db137867
AC
127 case SSL_ERROR_WANT_READ:
128 case SSL_ERROR_WANT_WRITE:
73d6283c
VY
129 if(ssl_err == SSL_ERROR_WANT_WRITE)
130 flags = RB_SELECT_WRITE;
131 else
132 flags = RB_SELECT_READ;
133 F->ssl_errno = get_last_err();
134 rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
135 break;
136 case SSL_ERROR_SYSCALL:
137 F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
138 break;
db137867
AC
139 default:
140 F->ssl_errno = get_last_err();
141 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
142 break;
143 }
144 return;
145 }
146 }
147 rb_settimeout(F, 0, NULL, NULL);
148 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
3202e249 149
2142f691 150 ad = F->accept;
db137867 151 F->accept = NULL;
3202e249 152 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
2142f691 153 rb_free(ad);
db137867
AC
154
155}
156
c2ac22cc
VY
157
158static void
159rb_ssl_accept_common(rb_fde_t *new_F)
db137867
AC
160{
161 int ssl_err;
db137867
AC
162 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
163 {
164 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
165 {
166 case SSL_ERROR_SYSCALL:
167 if(rb_ignore_errno(errno))
168 case SSL_ERROR_WANT_READ:
169 case SSL_ERROR_WANT_WRITE:
170 {
171 new_F->ssl_errno = get_last_err();
172 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
173 rb_ssl_tryaccept, NULL);
174 return;
175 }
176 default:
177 new_F->ssl_errno = get_last_err();
178 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
179 return;
180 }
181 }
182 else
183 {
184 rb_ssl_tryaccept(new_F, NULL);
185 }
186}
187
c2ac22cc 188void
3202e249 189rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
c2ac22cc
VY
190{
191 new_F->type |= RB_FD_SSL;
192 new_F->ssl = SSL_new(ssl_server_ctx);
193 new_F->accept = rb_malloc(sizeof(struct acceptdata));
194
195 new_F->accept->callback = cb;
196 new_F->accept->data = data;
197 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
198
199 new_F->accept->addrlen = 0;
200 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
201 rb_setup_ssl_cb(new_F);
202 rb_ssl_accept_common(new_F);
203}
204
db137867
AC
205
206
207
208void
3202e249 209rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
db137867 210{
db137867
AC
211 new_F->type |= RB_FD_SSL;
212 new_F->ssl = SSL_new(ssl_server_ctx);
213 new_F->accept = rb_malloc(sizeof(struct acceptdata));
214
215 new_F->accept->callback = F->accept->callback;
216 new_F->accept->data = F->accept->data;
217 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
218 memcpy(&new_F->accept->S, st, addrlen);
219 new_F->accept->addrlen = addrlen;
220
a9fb3ed0 221 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
c2ac22cc
VY
222 rb_setup_ssl_cb(new_F);
223 rb_ssl_accept_common(new_F);
db137867
AC
224}
225
226static ssize_t
3202e249 227rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
db137867
AC
228{
229 ssize_t ret;
230 unsigned long err;
231 SSL *ssl = F->ssl;
232
233 if(r_or_w == 0)
3202e249 234 ret = (ssize_t) SSL_read(ssl, rbuf, (int)count);
db137867 235 else
3202e249 236 ret = (ssize_t) SSL_write(ssl, wbuf, (int)count);
db137867
AC
237
238 if(ret < 0)
239 {
240 switch (SSL_get_error(ssl, ret))
241 {
242 case SSL_ERROR_WANT_READ:
243 errno = EAGAIN;
244 return RB_RW_SSL_NEED_READ;
245 case SSL_ERROR_WANT_WRITE:
246 errno = EAGAIN;
247 return RB_RW_SSL_NEED_WRITE;
248 case SSL_ERROR_ZERO_RETURN:
249 return 0;
250 case SSL_ERROR_SYSCALL:
251 err = get_last_err();
252 if(err == 0)
253 {
254 F->ssl_errno = 0;
255 return RB_RW_IO_ERROR;
256 }
257 break;
258 default:
259 err = get_last_err();
260 break;
261 }
262 F->ssl_errno = err;
263 if(err > 0)
264 {
265 errno = EIO; /* not great but... */
266 return RB_RW_SSL_ERROR;
267 }
268 return RB_RW_IO_ERROR;
269 }
270 return ret;
271}
272
273ssize_t
3202e249 274rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
db137867
AC
275{
276 return rb_ssl_read_or_write(0, F, buf, NULL, count);
277}
278
279ssize_t
3202e249 280rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
db137867
AC
281{
282 return rb_ssl_read_or_write(1, F, NULL, buf, count);
283}
284
7247337a
JT
285static int
286verify_accept_all_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
287{
288 return 1;
289}
290
918d73d5
JT
291static const char *
292get_ssl_error(unsigned long err)
293{
294 static char buf[512];
295
296 ERR_error_string_n(err, buf, sizeof buf);
297 return buf;
298}
299
db137867
AC
300int
301rb_init_ssl(void)
302{
303 int ret = 1;
c2ac22cc 304 char libratbox_data[] = "libratbox data";
cb266283 305 const char libratbox_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL";
db137867
AC
306 SSL_load_error_strings();
307 SSL_library_init();
c2ac22cc 308 libratbox_index = SSL_get_ex_new_index(0, libratbox_data, NULL, NULL, NULL);
a4c8c827
AJ
309
310#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
db137867 311 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
a4c8c827
AJ
312#else
313 ssl_server_ctx = SSL_CTX_new(TLS_server_method());
314#endif
315
db137867
AC
316 if(ssl_server_ctx == NULL)
317 {
318 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
918d73d5 319 get_ssl_error(ERR_get_error()));
db137867
AC
320 ret = 0;
321 }
a4c8c827
AJ
322
323 long server_options = SSL_CTX_get_options(ssl_server_ctx);
324
325#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
326 server_options |= SSL_OP_NO_SSLv2;
327 server_options |= SSL_OP_NO_SSLv3;
328#endif
329
362ef2d9 330#ifdef SSL_OP_SINGLE_DH_USE
a4c8c827
AJ
331 server_options |= SSL_OP_SINGLE_DH_USE;
332#endif
333
334#ifdef SSL_OP_SINGLE_ECDH_USE
335 server_options |= SSL_OP_SINGLE_ECDH_USE;
6b6a5799 336#endif
a4c8c827 337
6b6a5799 338#ifdef SSL_OP_NO_TICKET
a4c8c827 339 server_options |= SSL_OP_NO_TICKET;
362ef2d9 340#endif
a4c8c827
AJ
341
342 server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
343
344 SSL_CTX_set_options(ssl_server_ctx, server_options);
7247337a 345 SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
989652e7 346 SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF);
cb266283 347 SSL_CTX_set_cipher_list(ssl_server_ctx, libratbox_ciphers);
b6e799f5
AC
348
349 /* Set ECDHE on OpenSSL 1.00+, but make sure it's actually available because redhat are dicks
350 and bastardise their OpenSSL for stupid reasons... */
a4c8c827 351 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && defined(NID_secp384r1)
9e26f000
KB
352 EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
353 if (key) {
354 SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key);
355 EC_KEY_free(key);
356 }
31d22015 357 #endif
3202e249 358
a4c8c827 359#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
db137867 360 ssl_client_ctx = SSL_CTX_new(TLSv1_client_method());
a4c8c827 361#else
c86f11da 362 ssl_client_ctx = SSL_CTX_new(TLS_client_method());
a4c8c827 363#endif
db137867
AC
364
365 if(ssl_client_ctx == NULL)
366 {
367 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
918d73d5 368 get_ssl_error(ERR_get_error()));
db137867
AC
369 ret = 0;
370 }
6b6a5799
AM
371
372#ifdef SSL_OP_NO_TICKET
373 SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET);
374#endif
375
cb266283
AJ
376 SSL_CTX_set_cipher_list(ssl_client_ctx, libratbox_ciphers);
377
db137867
AC
378 return ret;
379}
380
381
382int
383rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
384{
db137867
AC
385 DH *dh;
386 unsigned long err;
387 if(cert == NULL)
388 {
389 rb_lib_log("rb_setup_ssl_server: No certificate file");
390 return 0;
391 }
07e14084 392 if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert))
db137867
AC
393 {
394 err = ERR_get_error();
395 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
918d73d5 396 get_ssl_error(err));
db137867
AC
397 return 0;
398 }
399
400 if(keyfile == NULL)
401 {
402 rb_lib_log("rb_setup_ssl_server: No key file");
403 return 0;
404 }
405
406
07e14084 407 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))
db137867
AC
408 {
409 err = ERR_get_error();
410 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
918d73d5 411 get_ssl_error(err));
db137867
AC
412 return 0;
413 }
414
415 if(dhfile != NULL)
416 {
417 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
3202e249
VY
418 BIO *bio = BIO_new_file(dhfile, "r");
419 if(bio != NULL)
db137867 420 {
3202e249 421 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
db137867
AC
422 if(dh == NULL)
423 {
424 err = ERR_get_error();
425 rb_lib_log
426 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
918d73d5 427 dhfile, get_ssl_error(err));
3202e249 428 BIO_free(bio);
db137867
AC
429 return 0;
430 }
3202e249 431 BIO_free(bio);
db137867 432 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
3202e249
VY
433 }
434 else
435 {
436 err = ERR_get_error();
437 rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
918d73d5 438 dhfile, get_ssl_error(err));
db137867
AC
439 }
440 }
441 return 1;
442}
443
444int
aa4737a0 445rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept)
db137867 446{
aa4737a0
AC
447 int result;
448
449 result = rb_listen(F, backlog, defer_accept);
db137867 450 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
aa4737a0
AC
451
452 return result;
db137867
AC
453}
454
455struct ssl_connect
456{
457 CNCB *callback;
458 void *data;
459 int timeout;
460};
461
462static void
3202e249 463rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
db137867
AC
464{
465 F->connect->callback = sconn->callback;
466 F->connect->data = sconn->data;
467 rb_free(sconn);
468 rb_connect_callback(F, status);
469}
470
471static void
3202e249 472rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
db137867
AC
473{
474 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
475}
476
477static void
3202e249 478rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
db137867
AC
479{
480 struct ssl_connect *sconn = data;
481 int ssl_err;
482 if(!SSL_is_init_finished((SSL *) F->ssl))
483 {
484 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
485 {
486 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
487 {
488 case SSL_ERROR_SYSCALL:
489 if(rb_ignore_errno(errno))
490 case SSL_ERROR_WANT_READ:
491 case SSL_ERROR_WANT_WRITE:
492 {
493 F->ssl_errno = get_last_err();
494 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
495 rb_ssl_tryconn_cb, sconn);
496 return;
497 }
498 default:
499 F->ssl_errno = get_last_err();
500 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
501 return;
502 }
503 }
504 else
505 {
506 rb_ssl_connect_realcb(F, RB_OK, sconn);
507 }
508 }
509}
510
511static void
3202e249 512rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
db137867
AC
513{
514 struct ssl_connect *sconn = data;
515 int ssl_err;
516 if(status != RB_OK)
517 {
518 rb_ssl_connect_realcb(F, status, sconn);
519 return;
520 }
521
522 F->type |= RB_FD_SSL;
523 F->ssl = SSL_new(ssl_client_ctx);
524 SSL_set_fd((SSL *) F->ssl, F->fd);
c2ac22cc 525 rb_setup_ssl_cb(F);
db137867
AC
526 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
527 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
528 {
529 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
530 {
531 case SSL_ERROR_SYSCALL:
532 if(rb_ignore_errno(errno))
533 case SSL_ERROR_WANT_READ:
534 case SSL_ERROR_WANT_WRITE:
535 {
536 F->ssl_errno = get_last_err();
537 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
538 rb_ssl_tryconn_cb, sconn);
539 return;
540 }
541 default:
542 F->ssl_errno = get_last_err();
543 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
544 return;
545 }
546 }
547 else
548 {
549 rb_ssl_connect_realcb(F, RB_OK, sconn);
550 }
551}
552
553void
3202e249 554rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
db137867
AC
555 struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
556{
557 struct ssl_connect *sconn;
558 if(F == NULL)
559 return;
560
561 sconn = rb_malloc(sizeof(struct ssl_connect));
562 sconn->data = data;
563 sconn->callback = callback;
564 sconn->timeout = timeout;
565 rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
566
567}
568
569void
3202e249 570rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
db137867
AC
571{
572 struct ssl_connect *sconn;
573 int ssl_err;
574 if(F == NULL)
575 return;
576
577 sconn = rb_malloc(sizeof(struct ssl_connect));
578 sconn->data = data;
579 sconn->callback = callback;
580 sconn->timeout = timeout;
581 F->connect = rb_malloc(sizeof(struct conndata));
582 F->connect->callback = callback;
583 F->connect->data = data;
584 F->type |= RB_FD_SSL;
585 F->ssl = SSL_new(ssl_client_ctx);
3202e249 586
db137867 587 SSL_set_fd((SSL *) F->ssl, F->fd);
c2ac22cc 588 rb_setup_ssl_cb(F);
db137867
AC
589 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
590 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
591 {
592 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
593 {
594 case SSL_ERROR_SYSCALL:
595 if(rb_ignore_errno(errno))
596 case SSL_ERROR_WANT_READ:
597 case SSL_ERROR_WANT_WRITE:
598 {
599 F->ssl_errno = get_last_err();
600 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
601 rb_ssl_tryconn_cb, sconn);
602 return;
603 }
604 default:
605 F->ssl_errno = get_last_err();
606 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
607 return;
608 }
609 }
610 else
611 {
612 rb_ssl_connect_realcb(F, RB_OK, sconn);
613 }
614}
615
616int
617rb_init_prng(const char *path, prng_seed_t seed_type)
618{
619 if(seed_type == RB_PRNG_DEFAULT)
620 {
3202e249 621#ifdef _WIN32
db137867
AC
622 RAND_screen();
623#endif
624 return RAND_status();
625 }
626 if(path == NULL)
627 return RAND_status();
628
629 switch (seed_type)
630 {
db137867
AC
631 case RB_PRNG_FILE:
632 if(RAND_load_file(path, -1) == -1)
633 return -1;
634 break;
3202e249 635#ifdef _WIN32
db137867
AC
636 case RB_PRNGWIN32:
637 RAND_screen();
638 break;
639#endif
640 default:
641 return -1;
642 }
643
644 return RAND_status();
645}
646
647int
648rb_get_random(void *buf, size_t length)
649{
a9fb3ed0 650 int ret;
3202e249 651
a9fb3ed0 652 if((ret = RAND_bytes(buf, length)) == 0)
db137867 653 {
a9fb3ed0 654 /* remove the error from the queue */
3202e249 655 ERR_get_error();
db137867 656 }
a9fb3ed0 657 return ret;
db137867
AC
658}
659
a9fb3ed0
VY
660int
661rb_get_pseudo_random(void *buf, size_t length)
662{
663 int ret;
664 ret = RAND_pseudo_bytes(buf, length);
665 if(ret < 0)
666 return 0;
667 return 1;
668}
db137867
AC
669
670const char *
3202e249 671rb_get_ssl_strerror(rb_fde_t *F)
db137867 672{
918d73d5 673 return get_ssl_error(F->ssl_errno);
db137867
AC
674}
675
7247337a
JT
676int
677rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
678{
679 X509 *cert;
680 int res;
681
682 if (F->ssl == NULL)
683 return 0;
684
685 cert = SSL_get_peer_certificate((SSL *) F->ssl);
686 if(cert != NULL)
687 {
688 res = SSL_get_verify_result((SSL *) F->ssl);
614502a6
AJ
689 if(
690 res == X509_V_OK ||
691 res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
692 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
693 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
694 res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
7247337a 695 {
d3806d05
AJ
696 unsigned int certfp_length = RB_SSL_CERTFP_LEN;
697 X509_digest(cert, EVP_sha1(), certfp, &certfp_length);
97b0e99e 698 X509_free(cert);
7247337a
JT
699 return 1;
700 }
b2d64e51 701 X509_free(cert);
7247337a
JT
702 }
703
704 return 0;
705}
706
db137867
AC
707int
708rb_supports_ssl(void)
709{
710 return 1;
711}
712
030272f3
VY
713void
714rb_get_ssl_info(char *buf, size_t len)
715{
55abcbb2 716 rb_snprintf(buf, len, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
e732a57b
JT
717 SSLeay_version(SSLEAY_VERSION),
718 (long)OPENSSL_VERSION_NUMBER, SSLeay());
030272f3
VY
719}
720
721
db137867 722#endif /* HAVE_OPESSL */