]> jfr.im git - solanum.git/blame_incremental - librb/src/openssl.c
openssl: don't allow certificates outside the validity period
[solanum.git] / librb / src / openssl.c
... / ...
CommitLineData
1/*
2 * librb: 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 */
24
25#include <librb_config.h>
26#include <rb_lib.h>
27
28#ifdef HAVE_OPENSSL
29
30#include <commio-int.h>
31#include <commio-ssl.h>
32#include <openssl/ssl.h>
33#include <openssl/dh.h>
34#include <openssl/err.h>
35#include <openssl/evp.h>
36#include <openssl/rand.h>
37#include <openssl/opensslv.h>
38
39/*
40 * This is a mess but what can you do when the library authors
41 * refuse to play ball with established conventions?
42 */
43#if defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x20020002L)
44# define LRB_HAVE_TLS_METHOD_API 1
45#else
46# if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10100000L)
47# define LRB_HAVE_TLS_METHOD_API 1
48# endif
49#endif
50
51/*
52 * Use SSL_CTX_set_ecdh_auto() in OpenSSL 1.0.2 only
53 * Use SSL_CTX_set1_curves_list() in OpenSSL 1.0.2 and above
54 * TODO: Merge this into the block above if LibreSSL implements them
55 */
56#if !defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER >= 0x10002000L)
57# define LRB_HAVE_TLS_SET_CURVES 1
58# if (OPENSSL_VERSION_NUMBER < 0x10100000L)
59# define LRB_HAVE_TLS_ECDH_AUTO 1
60# endif
61#endif
62
63static SSL_CTX *ssl_server_ctx;
64static SSL_CTX *ssl_client_ctx;
65static int librb_index = -1;
66
67static unsigned long
68get_last_err(void)
69{
70 unsigned long t_err, err = 0;
71 err = ERR_get_error();
72 if(err == 0)
73 return 0;
74
75 while((t_err = ERR_get_error()) > 0)
76 err = t_err;
77
78 return err;
79}
80
81void
82rb_ssl_shutdown(rb_fde_t *F)
83{
84 int i;
85 if(F == NULL || F->ssl == NULL)
86 return;
87 SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN);
88
89 for(i = 0; i < 4; i++)
90 {
91 if(SSL_shutdown((SSL *) F->ssl))
92 break;
93 }
94 get_last_err();
95 SSL_free((SSL *) F->ssl);
96}
97
98unsigned int
99rb_ssl_handshake_count(rb_fde_t *F)
100{
101 return F->handshake_count;
102}
103
104void
105rb_ssl_clear_handshake_count(rb_fde_t *F)
106{
107 F->handshake_count = 0;
108}
109
110static void
111rb_ssl_timeout(rb_fde_t *F, void *notused)
112{
113 lrb_assert(F->accept != NULL);
114 F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
115}
116
117
118static void
119rb_ssl_info_callback(SSL * ssl, int where, int ret)
120{
121 if(where & SSL_CB_HANDSHAKE_START)
122 {
123 rb_fde_t *F = SSL_get_ex_data(ssl, librb_index);
124 if(F == NULL)
125 return;
126 F->handshake_count++;
127 }
128}
129
130static void
131rb_setup_ssl_cb(rb_fde_t *F)
132{
133 SSL_set_ex_data(F->ssl, librb_index, (char *)F);
134 SSL_set_info_callback((SSL *) F->ssl, (void (*)(const SSL *,int,int))rb_ssl_info_callback);
135}
136
137static void
138rb_ssl_tryaccept(rb_fde_t *F, void *data)
139{
140 int ssl_err;
141 lrb_assert(F->accept != NULL);
142 int flags;
143 struct acceptdata *ad;
144
145 if(!SSL_is_init_finished((SSL *) F->ssl))
146 {
147 if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0)
148 {
149 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
150 {
151 case SSL_ERROR_WANT_READ:
152 case SSL_ERROR_WANT_WRITE:
153 if(ssl_err == SSL_ERROR_WANT_WRITE)
154 flags = RB_SELECT_WRITE;
155 else
156 flags = RB_SELECT_READ;
157 F->ssl_errno = get_last_err();
158 rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
159 break;
160 case SSL_ERROR_SYSCALL:
161 F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data);
162 break;
163 default:
164 F->ssl_errno = get_last_err();
165 F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
166 break;
167 }
168 return;
169 }
170 }
171 rb_settimeout(F, 0, NULL, NULL);
172 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
173
174 ad = F->accept;
175 F->accept = NULL;
176 ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
177 rb_free(ad);
178
179}
180
181
182static void
183rb_ssl_accept_common(rb_fde_t *new_F)
184{
185 int ssl_err;
186 if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
187 {
188 switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
189 {
190 case SSL_ERROR_SYSCALL:
191 if(rb_ignore_errno(errno))
192 case SSL_ERROR_WANT_READ:
193 case SSL_ERROR_WANT_WRITE:
194 {
195 new_F->ssl_errno = get_last_err();
196 rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
197 rb_ssl_tryaccept, NULL);
198 return;
199 }
200 default:
201 new_F->ssl_errno = get_last_err();
202 new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
203 return;
204 }
205 }
206 else
207 {
208 rb_ssl_tryaccept(new_F, NULL);
209 }
210}
211
212void
213rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
214{
215 new_F->type |= RB_FD_SSL;
216 new_F->ssl = SSL_new(ssl_server_ctx);
217 new_F->accept = rb_malloc(sizeof(struct acceptdata));
218
219 new_F->accept->callback = cb;
220 new_F->accept->data = data;
221 rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL);
222
223 new_F->accept->addrlen = 0;
224 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
225 rb_setup_ssl_cb(new_F);
226 rb_ssl_accept_common(new_F);
227}
228
229
230
231
232void
233rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
234{
235 new_F->type |= RB_FD_SSL;
236 new_F->ssl = SSL_new(ssl_server_ctx);
237 new_F->accept = rb_malloc(sizeof(struct acceptdata));
238
239 new_F->accept->callback = F->accept->callback;
240 new_F->accept->data = F->accept->data;
241 rb_settimeout(new_F, 10, rb_ssl_timeout, NULL);
242 memcpy(&new_F->accept->S, st, addrlen);
243 new_F->accept->addrlen = addrlen;
244
245 SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F));
246 rb_setup_ssl_cb(new_F);
247 rb_ssl_accept_common(new_F);
248}
249
250static ssize_t
251rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
252{
253 ssize_t ret;
254 unsigned long err;
255 SSL *ssl = F->ssl;
256
257 if(r_or_w == 0)
258 ret = (ssize_t) SSL_read(ssl, rbuf, (int)count);
259 else
260 ret = (ssize_t) SSL_write(ssl, wbuf, (int)count);
261
262 if(ret < 0)
263 {
264 switch (SSL_get_error(ssl, ret))
265 {
266 case SSL_ERROR_WANT_READ:
267 errno = EAGAIN;
268 return RB_RW_SSL_NEED_READ;
269 case SSL_ERROR_WANT_WRITE:
270 errno = EAGAIN;
271 return RB_RW_SSL_NEED_WRITE;
272 case SSL_ERROR_ZERO_RETURN:
273 return 0;
274 case SSL_ERROR_SYSCALL:
275 err = get_last_err();
276 if(err == 0)
277 {
278 F->ssl_errno = 0;
279 return RB_RW_IO_ERROR;
280 }
281 break;
282 default:
283 err = get_last_err();
284 break;
285 }
286 F->ssl_errno = err;
287 if(err > 0)
288 {
289 errno = EIO; /* not great but... */
290 return RB_RW_SSL_ERROR;
291 }
292 return RB_RW_IO_ERROR;
293 }
294 return ret;
295}
296
297ssize_t
298rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
299{
300 return rb_ssl_read_or_write(0, F, buf, NULL, count);
301}
302
303ssize_t
304rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
305{
306 return rb_ssl_read_or_write(1, F, NULL, buf, count);
307}
308
309static int
310verify_accept_all_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
311{
312 return 1;
313}
314
315static const char *
316get_ssl_error(unsigned long err)
317{
318 static char buf[512];
319
320 ERR_error_string_n(err, buf, sizeof buf);
321 return buf;
322}
323
324int
325rb_init_ssl(void)
326{
327 int ret = 1;
328 char librb_data[] = "librb data";
329 const char librb_ciphers[] = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL";
330#ifdef LRB_HAVE_TLS_SET_CURVES
331 const char librb_curves[] = "P-521:P-384:P-256";
332#endif
333 SSL_load_error_strings();
334 SSL_library_init();
335 librb_index = SSL_get_ex_new_index(0, librb_data, NULL, NULL, NULL);
336
337#ifndef LRB_HAVE_TLS_METHOD_API
338 ssl_server_ctx = SSL_CTX_new(SSLv23_server_method());
339#else
340 ssl_server_ctx = SSL_CTX_new(TLS_server_method());
341#endif
342
343 if(ssl_server_ctx == NULL)
344 {
345 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL server context: %s",
346 get_ssl_error(ERR_get_error()));
347 ret = 0;
348 }
349
350 long server_options = SSL_CTX_get_options(ssl_server_ctx);
351
352#ifndef LRB_HAVE_TLS_METHOD_API
353 server_options |= SSL_OP_NO_SSLv2;
354 server_options |= SSL_OP_NO_SSLv3;
355#endif
356
357#ifdef SSL_OP_SINGLE_DH_USE
358 server_options |= SSL_OP_SINGLE_DH_USE;
359#endif
360
361#ifdef SSL_OP_SINGLE_ECDH_USE
362 server_options |= SSL_OP_SINGLE_ECDH_USE;
363#endif
364
365#ifdef SSL_OP_NO_TICKET
366 server_options |= SSL_OP_NO_TICKET;
367#endif
368
369 server_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
370
371 SSL_CTX_set_options(ssl_server_ctx, server_options);
372 SSL_CTX_set_verify(ssl_server_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb);
373 SSL_CTX_set_session_cache_mode(ssl_server_ctx, SSL_SESS_CACHE_OFF);
374 SSL_CTX_set_cipher_list(ssl_server_ctx, librb_ciphers);
375
376#ifdef LRB_HAVE_TLS_SET_CURVES
377 SSL_CTX_set1_curves_list(ssl_server_ctx, librb_curves);
378#endif
379
380#ifdef LRB_HAVE_TLS_ECDH_AUTO
381 SSL_CTX_set_ecdh_auto(ssl_server_ctx, 1);
382#endif
383
384#if !defined(LRB_HAVE_TLS_SET_CURVES) && !defined(LRB_HAVE_TLS_ECDH_AUTO)
385 /* Set ECDHE on OpenSSL 1.0.0 & 1.0.1, but make sure it's actually available
386 * (it's not by default on Solaris or Red Hat... fuck Red Hat and Oracle)
387 */
388 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && !defined(OPENSSL_NO_ECDH)
389 EC_KEY *key = EC_KEY_new_by_curve_name(NID_secp384r1);
390 if (key) {
391 SSL_CTX_set_tmp_ecdh(ssl_server_ctx, key);
392 EC_KEY_free(key);
393 }
394 #endif
395#endif
396
397#ifndef LRB_HAVE_TLS_METHOD_API
398 ssl_client_ctx = SSL_CTX_new(SSLv23_client_method());
399#else
400 ssl_client_ctx = SSL_CTX_new(TLS_client_method());
401#endif
402
403 if(ssl_client_ctx == NULL)
404 {
405 rb_lib_log("rb_init_openssl: Unable to initialize OpenSSL client context: %s",
406 get_ssl_error(ERR_get_error()));
407 ret = 0;
408 }
409
410#ifndef LRB_HAVE_TLS_METHOD_API
411 SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
412#endif
413
414#ifdef SSL_OP_NO_TICKET
415 SSL_CTX_set_options(ssl_client_ctx, SSL_OP_NO_TICKET);
416#endif
417
418 SSL_CTX_set_cipher_list(ssl_client_ctx, librb_ciphers);
419
420 return ret;
421}
422
423
424int
425rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list)
426{
427 DH *dh;
428 unsigned long err;
429 if(cert == NULL)
430 {
431 rb_lib_log("rb_setup_ssl_server: No certificate file");
432 return 0;
433 }
434 if(!SSL_CTX_use_certificate_chain_file(ssl_server_ctx, cert) || !SSL_CTX_use_certificate_chain_file(ssl_client_ctx, cert))
435 {
436 err = ERR_get_error();
437 rb_lib_log("rb_setup_ssl_server: Error loading certificate file [%s]: %s", cert,
438 get_ssl_error(err));
439 return 0;
440 }
441
442 if(keyfile == NULL)
443 {
444 rb_lib_log("rb_setup_ssl_server: No key file");
445 return 0;
446 }
447
448
449 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))
450 {
451 err = ERR_get_error();
452 rb_lib_log("rb_setup_ssl_server: Error loading keyfile [%s]: %s", keyfile,
453 get_ssl_error(err));
454 return 0;
455 }
456
457 if(dhfile != NULL)
458 {
459 /* DH parameters aren't necessary, but they are nice..if they didn't pass one..that is their problem */
460 BIO *bio = BIO_new_file(dhfile, "r");
461 if(bio != NULL)
462 {
463 dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
464 if(dh == NULL)
465 {
466 err = ERR_get_error();
467 rb_lib_log
468 ("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
469 dhfile, get_ssl_error(err));
470 BIO_free(bio);
471 return 0;
472 }
473 BIO_free(bio);
474 SSL_CTX_set_tmp_dh(ssl_server_ctx, dh);
475 }
476 else
477 {
478 err = ERR_get_error();
479 rb_lib_log("rb_setup_ssl_server: Error loading DH params file [%s]: %s",
480 dhfile, get_ssl_error(err));
481 }
482 }
483
484 if (cipher_list != NULL)
485 {
486 SSL_CTX_set_cipher_list(ssl_server_ctx, cipher_list);
487 }
488
489 return 1;
490}
491
492int
493rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept)
494{
495 int result;
496
497 result = rb_listen(F, backlog, defer_accept);
498 F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
499
500 return result;
501}
502
503struct ssl_connect
504{
505 CNCB *callback;
506 void *data;
507 int timeout;
508};
509
510static void
511rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
512{
513 F->connect->callback = sconn->callback;
514 F->connect->data = sconn->data;
515 rb_free(sconn);
516 rb_connect_callback(F, status);
517}
518
519static void
520rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
521{
522 rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
523}
524
525static void
526rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
527{
528 struct ssl_connect *sconn = data;
529 int ssl_err;
530 if(!SSL_is_init_finished((SSL *) F->ssl))
531 {
532 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
533 {
534 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
535 {
536 case SSL_ERROR_SYSCALL:
537 if(rb_ignore_errno(errno))
538 case SSL_ERROR_WANT_READ:
539 case SSL_ERROR_WANT_WRITE:
540 {
541 F->ssl_errno = get_last_err();
542 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
543 rb_ssl_tryconn_cb, sconn);
544 return;
545 }
546 default:
547 F->ssl_errno = get_last_err();
548 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
549 return;
550 }
551 }
552 else
553 {
554 rb_ssl_connect_realcb(F, RB_OK, sconn);
555 }
556 }
557}
558
559static void
560rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
561{
562 struct ssl_connect *sconn = data;
563 int ssl_err;
564 if(status != RB_OK)
565 {
566 rb_ssl_connect_realcb(F, status, sconn);
567 return;
568 }
569
570 F->type |= RB_FD_SSL;
571 F->ssl = SSL_new(ssl_client_ctx);
572 SSL_set_fd((SSL *) F->ssl, F->fd);
573 rb_setup_ssl_cb(F);
574 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
575 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
576 {
577 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
578 {
579 case SSL_ERROR_SYSCALL:
580 if(rb_ignore_errno(errno))
581 case SSL_ERROR_WANT_READ:
582 case SSL_ERROR_WANT_WRITE:
583 {
584 F->ssl_errno = get_last_err();
585 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
586 rb_ssl_tryconn_cb, sconn);
587 return;
588 }
589 default:
590 F->ssl_errno = get_last_err();
591 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
592 return;
593 }
594 }
595 else
596 {
597 rb_ssl_connect_realcb(F, RB_OK, sconn);
598 }
599}
600
601void
602rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
603 struct sockaddr *clocal, CNCB * callback, void *data, int timeout)
604{
605 struct ssl_connect *sconn;
606 if(F == NULL)
607 return;
608
609 sconn = rb_malloc(sizeof(struct ssl_connect));
610 sconn->data = data;
611 sconn->callback = callback;
612 sconn->timeout = timeout;
613 rb_connect_tcp(F, dest, clocal, rb_ssl_tryconn, sconn, timeout);
614}
615
616void
617rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
618{
619 struct ssl_connect *sconn;
620 int ssl_err;
621 if(F == NULL)
622 return;
623
624 sconn = rb_malloc(sizeof(struct ssl_connect));
625 sconn->data = data;
626 sconn->callback = callback;
627 sconn->timeout = timeout;
628 F->connect = rb_malloc(sizeof(struct conndata));
629 F->connect->callback = callback;
630 F->connect->data = data;
631 F->type |= RB_FD_SSL;
632 F->ssl = SSL_new(ssl_client_ctx);
633
634 SSL_set_fd((SSL *) F->ssl, F->fd);
635 rb_setup_ssl_cb(F);
636 rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
637 if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
638 {
639 switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
640 {
641 case SSL_ERROR_SYSCALL:
642 if(rb_ignore_errno(errno))
643 case SSL_ERROR_WANT_READ:
644 case SSL_ERROR_WANT_WRITE:
645 {
646 F->ssl_errno = get_last_err();
647 rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
648 rb_ssl_tryconn_cb, sconn);
649 return;
650 }
651 default:
652 F->ssl_errno = get_last_err();
653 rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
654 return;
655 }
656 }
657 else
658 {
659 rb_ssl_connect_realcb(F, RB_OK, sconn);
660 }
661}
662
663int
664rb_init_prng(const char *path, prng_seed_t seed_type)
665{
666 if(seed_type == RB_PRNG_DEFAULT)
667 {
668#ifdef _WIN32
669 RAND_screen();
670#endif
671 return RAND_status();
672 }
673 if(path == NULL)
674 return RAND_status();
675
676 switch (seed_type)
677 {
678 case RB_PRNG_FILE:
679 if(RAND_load_file(path, -1) == -1)
680 return -1;
681 break;
682#ifdef _WIN32
683 case RB_PRNGWIN32:
684 RAND_screen();
685 break;
686#endif
687 default:
688 return -1;
689 }
690
691 return RAND_status();
692}
693
694int
695rb_get_random(void *buf, size_t length)
696{
697 int ret;
698
699 if((ret = RAND_bytes(buf, length)) == 0)
700 {
701 /* remove the error from the queue */
702 ERR_get_error();
703 }
704 return ret;
705}
706
707const char *
708rb_get_ssl_strerror(rb_fde_t *F)
709{
710 return get_ssl_error(F->ssl_errno);
711}
712
713static unsigned int
714make_certfp(X509 *cert, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
715{
716 const ASN1_ITEM *it;
717 const EVP_MD *evp;
718 void *data;
719 unsigned int len;
720
721 switch(method)
722 {
723 case RB_SSL_CERTFP_METH_CERT_SHA1:
724 it = ASN1_ITEM_rptr(X509);
725 evp = EVP_sha1();
726 data = cert;
727 len = RB_SSL_CERTFP_LEN_SHA1;
728 break;
729 case RB_SSL_CERTFP_METH_CERT_SHA256:
730 it = ASN1_ITEM_rptr(X509);
731 evp = EVP_sha256();
732 data = cert;
733 len = RB_SSL_CERTFP_LEN_SHA256;
734 break;
735 case RB_SSL_CERTFP_METH_CERT_SHA512:
736 it = ASN1_ITEM_rptr(X509);
737 evp = EVP_sha512();
738 data = cert;
739 len = RB_SSL_CERTFP_LEN_SHA512;
740 break;
741 case RB_SSL_CERTFP_METH_SPKI_SHA256:
742 it = ASN1_ITEM_rptr(X509_PUBKEY);
743 evp = EVP_sha256();
744 data = X509_get_X509_PUBKEY(cert);
745 len = RB_SSL_CERTFP_LEN_SHA256;
746 break;
747 case RB_SSL_CERTFP_METH_SPKI_SHA512:
748 it = ASN1_ITEM_rptr(X509_PUBKEY);
749 evp = EVP_sha512();
750 data = X509_get_X509_PUBKEY(cert);
751 len = RB_SSL_CERTFP_LEN_SHA512;
752 break;
753 default:
754 return 0;
755 }
756
757 if (ASN1_item_digest(it, evp, data, certfp, &len) != 1)
758 len = 0;
759 return len;
760}
761
762int
763rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
764{
765 X509 *cert;
766 int res;
767
768 if (F->ssl == NULL)
769 return 0;
770
771 cert = SSL_get_peer_certificate((SSL *) F->ssl);
772 if(cert != NULL)
773 {
774 res = SSL_get_verify_result((SSL *) F->ssl);
775 if(
776 res == X509_V_OK ||
777 res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
778 res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
779 res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
780 res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
781 res == X509_V_ERR_CERT_UNTRUSTED)
782 {
783 unsigned int len = make_certfp(cert, certfp, method);
784 X509_free(cert);
785 return len;
786 }
787 X509_free(cert);
788 }
789
790 return 0;
791}
792
793int
794rb_get_ssl_certfp_file(const char *filename, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
795{
796 X509 *cert;
797 FILE *f = fopen(filename, "r");
798
799 if (!f)
800 return -1;
801
802 cert = PEM_read_X509(f, NULL, NULL, NULL);
803 fclose(f);
804
805 if (cert) {
806 unsigned int len = make_certfp(cert, certfp, method);
807 X509_free(cert);
808 return len;
809 }
810 return 0;
811}
812
813int
814rb_supports_ssl(void)
815{
816 return 1;
817}
818
819void
820rb_get_ssl_info(char *buf, size_t len)
821{
822 snprintf(buf, len, "Using SSL: %s compiled: 0x%lx, library 0x%lx",
823 SSLeay_version(SSLEAY_VERSION),
824 (long)OPENSSL_VERSION_NUMBER, SSLeay());
825}
826
827const char *
828rb_ssl_get_cipher(rb_fde_t *F)
829{
830 const SSL_CIPHER *sslciph;
831
832 if(F == NULL || F->ssl == NULL)
833 return NULL;
834
835 if((sslciph = SSL_get_current_cipher(F->ssl)) == NULL)
836 return NULL;
837
838 return SSL_CIPHER_get_name(sslciph);
839}
840
841#endif /* HAVE_OPENSSL */