2 * libratbox: a library used by ircd-ratbox and other things
3 * gnutls.c: gnutls related code
5 * Copyright (C) 2007-2008 ircd-ratbox development team
6 * Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
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.
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.
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
25 #include <librb_config.h>
30 #include <commio-int.h>
31 #include <commio-ssl.h>
34 #include <gnutls/gnutls.h>
36 #include <gnutls/abstract.h>
37 #include <gnutls/x509.h>
39 #if (GNUTLS_VERSION_MAJOR < 3)
42 # include <gnutls/crypto.h>
45 #include "gnutls_ratbox.h"
49 RB_FD_TLS_DIRECTION_IN
= 0,
50 RB_FD_TLS_DIRECTION_OUT
= 1
51 } rb_fd_tls_direction
;
53 #define SSL_P(x) *((gnutls_session_t *) ((x)->ssl))
57 // Server side variables
58 static gnutls_certificate_credentials_t server_cert_key
;
59 static gnutls_dh_params_t server_dhp
;
61 // Client side variables
63 static gnutls_x509_crt_t client_cert
[MAX_CERTS
];
64 static gnutls_x509_privkey_t client_key
;
65 static unsigned int client_cert_count
;
68 static gnutls_priority_t default_priority
;
79 static const char *rb_ssl_strerror(int);
80 static void rb_ssl_connect_realcb(rb_fde_t
*, int, struct ssl_connect
*);
85 * Internal GNUTLS-specific code
89 * We only have one certificate to authenticate with, as both a client and server.
91 * Unfortunately, GNUTLS tries to be clever, and as client, will attempt to use a certificate that the server will
92 * trust. We usually use self-signed certs, though, so the result of this search is always nothing. Therefore, it
93 * uses no certificate to authenticate as a client. This is undesirable, as it breaks fingerprint authentication;
94 * e.g. the connect::fingerprint on the remote ircd will not match.
96 * Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client.
99 rb_ssl_cert_auth_cb(gnutls_session_t session
,
100 const gnutls_datum_t
*const req_ca_rdn
, const int req_ca_rdn_len
,
101 const gnutls_pk_algorithm_t
*const sign_algos
, const int sign_algos_len
,
102 #if (GNUTLS_VERSION_MAJOR < 3)
103 gnutls_retr_st
*const st
)
105 gnutls_retr2_st
*const st
)
108 #if (GNUTLS_VERSION_MAJOR < 3)
109 st
->type
= GNUTLS_CRT_X509
;
111 st
->cert_type
= GNUTLS_CRT_X509
;
112 st
->key_type
= GNUTLS_PRIVKEY_X509
;
115 st
->ncerts
= client_cert_count
;
116 st
->cert
.x509
= client_cert
;
117 st
->key
.x509
= client_key
;
124 rb_sock_net_recv(gnutls_transport_ptr_t context_ptr
, void *const buf
, const size_t count
)
126 const int fd
= rb_get_fd((rb_fde_t
*)context_ptr
);
128 return recv(fd
, buf
, count
, 0);
132 rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr
, const void *const buf
, const size_t count
)
134 const int fd
= rb_get_fd((rb_fde_t
*)context_ptr
);
136 return send(fd
, buf
, count
, 0);
140 rb_ssl_init_fd(rb_fde_t
*const F
, const rb_fd_tls_direction dir
)
142 F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
146 rb_lib_log("%s: rb_malloc: allocation failure", __func__
);
151 unsigned int init_flags
= 0;
155 case RB_FD_TLS_DIRECTION_IN
:
156 init_flags
|= GNUTLS_SERVER
;
158 case RB_FD_TLS_DIRECTION_OUT
:
159 init_flags
|= GNUTLS_CLIENT
;
163 gnutls_init((gnutls_session_t
*) F
->ssl
, init_flags
);
164 gnutls_credentials_set(SSL_P(F
), GNUTLS_CRD_CERTIFICATE
, server_cert_key
);
165 gnutls_dh_set_prime_bits(SSL_P(F
), 2048);
167 gnutls_transport_set_ptr(SSL_P(F
), (gnutls_transport_ptr_t
) F
);
168 gnutls_transport_set_pull_function(SSL_P(F
), rb_sock_net_recv
);
169 gnutls_transport_set_push_function(SSL_P(F
), rb_sock_net_xmit
);
171 if (gnutls_priority_set(SSL_P(F
), default_priority
) != GNUTLS_E_SUCCESS
)
172 gnutls_set_default_priority(SSL_P(F
));
174 if(dir
== RB_FD_TLS_DIRECTION_IN
)
175 gnutls_certificate_server_set_request(SSL_P(F
), GNUTLS_CERT_REQUEST
);
179 rb_ssl_accept_common(rb_fde_t
*const F
, void *const data
)
181 lrb_assert(F
!= NULL
);
182 lrb_assert(F
->accept
!= NULL
);
183 lrb_assert(F
->accept
->callback
!= NULL
);
184 lrb_assert(F
->ssl
!= NULL
);
188 const int ret
= gnutls_handshake(SSL_P(F
));
189 const int err
= errno
;
191 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (err
== 0 || rb_ignore_errno(err
))))
193 unsigned int flags
= (gnutls_record_get_direction(SSL_P(F
)) == 0) ? RB_SELECT_READ
: RB_SELECT_WRITE
;
194 rb_setselect(F
, flags
, rb_ssl_accept_common
, data
);
198 // These 2 calls may affect errno, which is why we save it above and restore it below
199 rb_settimeout(F
, 0, NULL
, NULL
);
200 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
202 struct acceptdata
*const ad
= F
->accept
;
205 if(ret
== GNUTLS_E_SUCCESS
)
207 F
->handshake_count
++;
208 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
210 else if(ret
== GNUTLS_E_INTERRUPTED
&& err
!= 0)
213 ad
->callback(F
, RB_ERROR
, NULL
, 0, ad
->data
);
218 F
->ssl_errno
= (unsigned long) -ret
;
219 ad
->callback(F
, RB_ERROR_SSL
, NULL
, 0, ad
->data
);
226 rb_ssl_connect_common(rb_fde_t
*const F
, void *const data
)
228 lrb_assert(F
!= NULL
);
229 lrb_assert(F
->ssl
!= NULL
);
233 const int ret
= gnutls_handshake(SSL_P(F
));
234 const int err
= errno
;
236 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (err
== 0 || rb_ignore_errno(err
))))
238 unsigned int flags
= (gnutls_record_get_direction(SSL_P(F
)) == 0) ? RB_SELECT_READ
: RB_SELECT_WRITE
;
239 rb_setselect(F
, flags
, rb_ssl_connect_common
, data
);
243 // These 2 calls may affect errno, which is why we save it above and restore it below
244 rb_settimeout(F
, 0, NULL
, NULL
);
245 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
247 struct ssl_connect
*const sconn
= data
;
249 if(ret
== GNUTLS_E_SUCCESS
)
251 F
->handshake_count
++;
252 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
254 else if(ret
== GNUTLS_E_INTERRUPTED
&& err
!= 0)
257 rb_ssl_connect_realcb(F
, RB_ERROR
, sconn
);
262 F
->ssl_errno
= (unsigned long) -ret
;
263 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
268 rb_ssl_strerror(const int err
)
270 return gnutls_strerror(err
);
274 rb_ssl_read_or_write(const int r_or_w
, rb_fde_t
*const F
, void *const rbuf
, const void *const wbuf
, const size_t count
)
281 ret
= gnutls_record_recv(SSL_P(F
), rbuf
, count
);
283 ret
= gnutls_record_send(SSL_P(F
), wbuf
, count
);
288 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (errno
== 0 || rb_ignore_errno(errno
))))
290 if(gnutls_record_get_direction(SSL_P(F
)) == 0)
291 return RB_RW_SSL_NEED_READ
;
293 return RB_RW_SSL_NEED_WRITE
;
296 if(ret
== GNUTLS_E_INTERRUPTED
&& errno
!= 0)
297 return RB_RW_IO_ERROR
;
300 F
->ssl_errno
= (unsigned long) -ret
;
301 return RB_RW_SSL_ERROR
;
304 #if (GNUTLS_VERSION_MAJOR < 3)
306 rb_gcry_random_seed(void *const unused
)
308 gcry_fast_random_poll();
313 rb_free_datum_t(gnutls_datum_t
*const datum
)
318 rb_free(datum
->data
);
322 static gnutls_datum_t
*
323 rb_load_file_into_datum_t(const char *const file
)
325 const int datum_fd
= open(file
, O_RDONLY
);
329 struct stat fileinfo
;
330 if(fstat(datum_fd
, &fileinfo
) != 0)
332 (void) close(datum_fd
);
336 const size_t datum_size
= (fileinfo
.st_size
< 131072) ? (size_t) fileinfo
.st_size
: 131072;
339 (void) close(datum_fd
);
343 gnutls_datum_t
*datum
;
344 if((datum
= rb_malloc(sizeof *datum
)) == NULL
)
346 (void) close(datum_fd
);
349 if((datum
->data
= rb_malloc(datum_size
+ 1)) == NULL
)
352 (void) close(datum_fd
);
356 for(size_t data_read
= 0; data_read
< datum_size
; )
358 ssize_t ret
= read(datum_fd
, ((unsigned char *)datum
->data
) + data_read
, datum_size
- data_read
);
362 rb_free_datum_t(datum
);
363 (void) close(datum_fd
);
367 data_read
+= (size_t) ret
;
369 (void) close(datum_fd
);
371 datum
->data
[datum_size
] = '\0';
372 datum
->size
= (unsigned int) datum_size
;
377 make_certfp(gnutls_x509_crt_t cert
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
380 gnutls_digest_algorithm_t md_type
;
386 case RB_SSL_CERTFP_METH_CERT_SHA1
:
387 hashlen
= RB_SSL_CERTFP_LEN_SHA1
;
388 md_type
= GNUTLS_DIG_SHA1
;
390 case RB_SSL_CERTFP_METH_SPKI_SHA256
:
392 case RB_SSL_CERTFP_METH_CERT_SHA256
:
393 hashlen
= RB_SSL_CERTFP_LEN_SHA256
;
394 md_type
= GNUTLS_DIG_SHA256
;
396 case RB_SSL_CERTFP_METH_SPKI_SHA512
:
398 case RB_SSL_CERTFP_METH_CERT_SHA512
:
399 hashlen
= RB_SSL_CERTFP_LEN_SHA512
;
400 md_type
= GNUTLS_DIG_SHA512
;
408 size_t digest_size
= (size_t) hashlen
;
410 if(gnutls_x509_crt_get_fingerprint(cert
, md_type
, certfp
, &digest_size
) != 0)
416 gnutls_pubkey_t pubkey
;
418 if(gnutls_pubkey_init(&pubkey
) != 0)
421 if(gnutls_pubkey_import_x509(pubkey
, cert
, 0) != 0)
423 gnutls_pubkey_deinit(pubkey
);
427 unsigned char derkey
[262144]; // Should be big enough to hold any SubjectPublicKeyInfo structure
428 size_t derkey_len
= sizeof derkey
;
430 if(gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, derkey
, &derkey_len
) != 0)
432 gnutls_pubkey_deinit(pubkey
);
436 gnutls_pubkey_deinit(pubkey
);
438 if(gnutls_hash_fast(md_type
, derkey
, derkey_len
, certfp
) != 0)
447 * External GNUTLS-specific code
451 rb_ssl_shutdown(rb_fde_t
*const F
)
453 if(F
== NULL
|| F
->ssl
== NULL
)
456 for(int i
= 0; i
< 4; i
++)
458 int ret
= gnutls_bye(SSL_P(F
), GNUTLS_SHUT_RDWR
);
460 if(ret
!= GNUTLS_E_INTERRUPTED
&& ret
!= GNUTLS_E_AGAIN
)
464 gnutls_deinit(SSL_P(F
));
475 if((ret
= gnutls_global_init()) != GNUTLS_E_SUCCESS
)
477 rb_lib_log("%s: gnutls_global_init: %s", __func__
, rb_ssl_strerror(ret
));
481 #if (GNUTLS_VERSION_MAJOR < 3)
482 rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed
, NULL
, 300);
489 rb_setup_ssl_server(const char *const certfile
, const char *keyfile
,
490 const char *const dhfile
, const char *cipherlist
)
494 rb_lib_log("%s: no certificate file specified", __func__
);
501 if(cipherlist
== NULL
)
502 cipherlist
= rb_gnutls_default_priority_str
;
505 gnutls_datum_t
*const d_cert
= rb_load_file_into_datum_t(certfile
);
508 rb_lib_log("%s: Error loading certificate: %s", __func__
, strerror(errno
));
512 gnutls_datum_t
*const d_key
= rb_load_file_into_datum_t(keyfile
);
515 rb_lib_log("%s: Error loading key: %s", __func__
, strerror(errno
));
516 rb_free_datum_t(d_cert
);
522 if((ret
= gnutls_certificate_allocate_credentials(&server_cert_key
)) != GNUTLS_E_SUCCESS
)
524 rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__
, rb_ssl_strerror(ret
));
525 rb_free_datum_t(d_cert
);
526 rb_free_datum_t(d_key
);
530 #if (GNUTLS_VERSION_MAJOR < 3)
531 gnutls_certificate_client_set_retrieve_function(server_cert_key
, rb_ssl_cert_auth_cb
);
533 gnutls_certificate_set_retrieve_function(server_cert_key
, rb_ssl_cert_auth_cb
);
536 if((ret
= gnutls_certificate_set_x509_key_mem(server_cert_key
, d_cert
, d_key
,
537 GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
539 rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__
, rb_ssl_strerror(ret
));
540 gnutls_certificate_free_credentials(server_cert_key
);
541 rb_free_datum_t(d_cert
);
542 rb_free_datum_t(d_key
);
545 if((ret
= gnutls_x509_crt_list_import(client_cert
, &client_cert_count
, d_cert
, GNUTLS_X509_FMT_PEM
,
546 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED
)) < 1)
548 rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__
, rb_ssl_strerror(ret
));
549 gnutls_certificate_free_credentials(server_cert_key
);
550 rb_free_datum_t(d_cert
);
551 rb_free_datum_t(d_key
);
554 client_cert_count
= (unsigned int) ret
;
556 if((ret
= gnutls_x509_privkey_init(&client_key
)) != GNUTLS_E_SUCCESS
)
558 rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__
, rb_ssl_strerror(ret
));
559 gnutls_certificate_free_credentials(server_cert_key
);
560 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
561 gnutls_x509_crt_deinit(client_cert
[i
]);
562 rb_free_datum_t(d_cert
);
563 rb_free_datum_t(d_key
);
566 if((ret
= gnutls_x509_privkey_import(client_key
, d_key
, GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
568 rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__
, rb_ssl_strerror(ret
));
569 gnutls_certificate_free_credentials(server_cert_key
);
570 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
571 gnutls_x509_crt_deinit(client_cert
[i
]);
572 gnutls_x509_privkey_deinit(client_key
);
573 rb_free_datum_t(d_cert
);
574 rb_free_datum_t(d_key
);
578 rb_free_datum_t(d_cert
);
579 rb_free_datum_t(d_key
);
583 gnutls_datum_t
*const d_dhp
= rb_load_file_into_datum_t(dhfile
);
587 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, strerror(errno
));
588 gnutls_certificate_free_credentials(server_cert_key
);
589 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
590 gnutls_x509_crt_deinit(client_cert
[i
]);
591 gnutls_x509_privkey_deinit(client_key
);
594 if((ret
= gnutls_dh_params_init(&server_dhp
)) != GNUTLS_E_SUCCESS
)
596 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, rb_ssl_strerror(ret
));
597 gnutls_certificate_free_credentials(server_cert_key
);
598 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
599 gnutls_x509_crt_deinit(client_cert
[i
]);
600 gnutls_x509_privkey_deinit(client_key
);
601 rb_free_datum_t(d_dhp
);
604 if((ret
= gnutls_dh_params_import_pkcs3(server_dhp
, d_dhp
, GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
606 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, rb_ssl_strerror(ret
));
607 gnutls_certificate_free_credentials(server_cert_key
);
608 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
609 gnutls_x509_crt_deinit(client_cert
[i
]);
610 gnutls_x509_privkey_deinit(client_key
);
611 gnutls_dh_params_deinit(server_dhp
);
612 rb_free_datum_t(d_dhp
);
616 gnutls_certificate_set_dh_params(server_cert_key
, server_dhp
);
617 rb_free_datum_t(d_dhp
);
620 const char *err
= NULL
;
621 if((ret
= gnutls_priority_init(&default_priority
, cipherlist
, &err
)) != GNUTLS_E_SUCCESS
)
623 rb_lib_log("%s: gnutls_priority_init: %s, error begins at '%s'? -- using defaults instead",
624 __func__
, rb_ssl_strerror(ret
), err
? err
: "<unknown>");
626 (void) gnutls_priority_init(&default_priority
, NULL
, &err
);
629 rb_lib_log("%s: TLS configuration successful", __func__
);
634 rb_init_prng(const char *const path
, prng_seed_t seed_type
)
636 #if (GNUTLS_VERSION_MAJOR < 3)
637 gcry_fast_random_poll();
638 rb_lib_log("%s: PRNG initialised", __func__
);
640 rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__
);
646 rb_get_random(void *const buf
, const size_t length
)
648 #if (GNUTLS_VERSION_MAJOR < 3)
649 gcry_randomize(buf
, length
, GCRY_STRONG_RANDOM
);
651 gnutls_rnd(GNUTLS_RND_KEY
, buf
, length
);
657 rb_get_ssl_strerror(rb_fde_t
*const F
)
659 const int err
= (int) F
->ssl_errno
;
660 return rb_ssl_strerror(-err
);
664 rb_get_ssl_certfp(rb_fde_t
*const F
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
666 if(gnutls_certificate_type_get(SSL_P(F
)) != GNUTLS_CRT_X509
)
669 unsigned int cert_list_size
= 0;
670 const gnutls_datum_t
*const cert_list
= gnutls_certificate_get_peers(SSL_P(F
), &cert_list_size
);
671 if(cert_list
== NULL
|| cert_list_size
< 1)
674 gnutls_x509_crt_t peer_cert
;
675 if(gnutls_x509_crt_init(&peer_cert
) != 0)
678 if(gnutls_x509_crt_import(peer_cert
, &cert_list
[0], GNUTLS_X509_FMT_DER
) < 0)
680 gnutls_x509_crt_deinit(peer_cert
);
684 const int len
= make_certfp(peer_cert
, certfp
, method
);
686 gnutls_x509_crt_deinit(peer_cert
);
692 rb_get_ssl_certfp_file(const char *const filename
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
694 gnutls_datum_t
*const datum_cert
= rb_load_file_into_datum_t(filename
);
695 if(datum_cert
== NULL
)
698 gnutls_x509_crt_t cert
;
699 if(gnutls_x509_crt_init(&cert
) != 0)
701 rb_free_datum_t(datum_cert
);
704 if(gnutls_x509_crt_import(cert
, datum_cert
, GNUTLS_X509_FMT_PEM
) < 0)
706 gnutls_x509_crt_deinit(cert
);
707 rb_free_datum_t(datum_cert
);
711 const int len
= make_certfp(cert
, certfp
, method
);
713 gnutls_x509_crt_deinit(cert
);
714 rb_free_datum_t(datum_cert
);
720 rb_get_ssl_info(char *const buf
, const size_t len
)
722 (void) snprintf(buf
, len
, "GNUTLS: compiled (v%s), library (v%s)",
723 LIBGNUTLS_VERSION
, gnutls_check_version(NULL
));
727 rb_ssl_get_cipher(rb_fde_t
*const F
)
729 if(F
== NULL
|| F
->ssl
== NULL
)
732 static char buf
[512];
734 gnutls_protocol_t version_ptr
= gnutls_protocol_get_version(SSL_P(F
));
735 gnutls_cipher_algorithm_t cipher_ptr
= gnutls_cipher_get(SSL_P(F
));
737 const char *const version
= gnutls_protocol_get_name(version_ptr
);
738 const char *const cipher
= gnutls_cipher_get_name(cipher_ptr
);
740 (void) snprintf(buf
, sizeof buf
, "%s, %s", version
, cipher
);
746 rb_ssl_read(rb_fde_t
*const F
, void *const buf
, const size_t count
)
748 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
752 rb_ssl_write(rb_fde_t
*const F
, const void *const buf
, const size_t count
)
754 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
760 * Internal library-agnostic code
764 rb_ssl_connect_realcb(rb_fde_t
*const F
, const int status
, struct ssl_connect
*const sconn
)
766 lrb_assert(F
!= NULL
);
767 lrb_assert(F
->connect
!= NULL
);
769 F
->connect
->callback
= sconn
->callback
;
770 F
->connect
->data
= sconn
->data
;
772 rb_connect_callback(F
, status
);
777 rb_ssl_timeout_cb(rb_fde_t
*const F
, void *const data
)
779 lrb_assert(F
->accept
!= NULL
);
780 lrb_assert(F
->accept
->callback
!= NULL
);
782 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
786 rb_ssl_tryconn_timeout_cb(rb_fde_t
*const F
, void *const data
)
788 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
792 rb_ssl_tryconn(rb_fde_t
*const F
, const int status
, void *const data
)
794 lrb_assert(F
!= NULL
);
796 struct ssl_connect
*const sconn
= data
;
800 rb_ssl_connect_realcb(F
, status
, sconn
);
804 F
->type
|= RB_FD_SSL
;
806 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
807 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_OUT
);
808 rb_ssl_connect_common(F
, sconn
);
814 * External library-agnostic code
818 rb_supports_ssl(void)
824 rb_ssl_handshake_count(rb_fde_t
*const F
)
826 return F
->handshake_count
;
830 rb_ssl_clear_handshake_count(rb_fde_t
*const F
)
832 F
->handshake_count
= 0;
836 rb_ssl_start_accepted(rb_fde_t
*const F
, ACCB
*const cb
, void *const data
, const int timeout
)
838 F
->type
|= RB_FD_SSL
;
840 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
841 F
->accept
->callback
= cb
;
842 F
->accept
->data
= data
;
843 F
->accept
->addrlen
= 0;
844 (void) memset(&F
->accept
->S
, 0x00, sizeof F
->accept
->S
);
846 rb_settimeout(F
, timeout
, rb_ssl_timeout_cb
, NULL
);
847 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_IN
);
848 rb_ssl_accept_common(F
, NULL
);
852 rb_ssl_accept_setup(rb_fde_t
*const srv_F
, rb_fde_t
*const cli_F
, struct sockaddr
*const st
, const int addrlen
)
854 cli_F
->type
|= RB_FD_SSL
;
856 cli_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
857 cli_F
->accept
->callback
= srv_F
->accept
->callback
;
858 cli_F
->accept
->data
= srv_F
->accept
->data
;
859 cli_F
->accept
->addrlen
= (rb_socklen_t
) addrlen
;
860 (void) memset(&cli_F
->accept
->S
, 0x00, sizeof cli_F
->accept
->S
);
861 (void) memcpy(&cli_F
->accept
->S
, st
, (size_t) addrlen
);
863 rb_settimeout(cli_F
, 10, rb_ssl_timeout_cb
, NULL
);
864 rb_ssl_init_fd(cli_F
, RB_FD_TLS_DIRECTION_IN
);
865 rb_ssl_accept_common(cli_F
, NULL
);
869 rb_ssl_listen(rb_fde_t
*const F
, const int backlog
, const int defer_accept
)
871 int result
= rb_listen(F
, backlog
, defer_accept
);
873 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
879 rb_connect_tcp_ssl(rb_fde_t
*const F
, struct sockaddr
*const dest
, struct sockaddr
*const clocal
,
880 CNCB
*const callback
, void *const data
, const int timeout
)
885 struct ssl_connect
*const sconn
= rb_malloc(sizeof *sconn
);
887 sconn
->callback
= callback
;
888 sconn
->timeout
= timeout
;
890 rb_connect_tcp(F
, dest
, clocal
, rb_ssl_tryconn
, sconn
, timeout
);
894 rb_ssl_start_connected(rb_fde_t
*const F
, CNCB
*const callback
, void *const data
, const int timeout
)
899 struct ssl_connect
*const sconn
= rb_malloc(sizeof *sconn
);
901 sconn
->callback
= callback
;
902 sconn
->timeout
= timeout
;
904 F
->connect
= rb_malloc(sizeof(struct conndata
));
905 F
->connect
->callback
= callback
;
906 F
->connect
->data
= data
;
908 F
->type
|= RB_FD_SSL
;
910 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
911 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_OUT
);
912 rb_ssl_connect_common(F
, sconn
);
915 #endif /* HAVE_GNUTLS */