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