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>
35 #include <gnutls/abstract.h>
36 #include <gnutls/x509.h>
38 #if (GNUTLS_VERSION_MAJOR < 3)
41 # include <gnutls/crypto.h>
46 RB_FD_TLS_DIRECTION_IN
= 0,
47 RB_FD_TLS_DIRECTION_OUT
= 1
48 } rb_fd_tls_direction
;
50 #define SSL_P(x) *((gnutls_session_t *) ((x)->ssl))
54 // Server side variables
55 static gnutls_certificate_credentials_t server_cert_key
;
56 static gnutls_dh_params_t server_dhp
;
58 // Client side variables
60 static gnutls_x509_crt_t client_cert
[MAX_CERTS
];
61 static gnutls_x509_privkey_t client_key
;
62 static unsigned int client_cert_count
;
65 static gnutls_priority_t default_priority
;
76 static const char *rb_ssl_strerror(int);
77 static void rb_ssl_connect_realcb(rb_fde_t
*, int, struct ssl_connect
*);
79 static ssize_t
rb_sock_net_recv(gnutls_transport_ptr_t
, void *, size_t);
80 static ssize_t
rb_sock_net_xmit(gnutls_transport_ptr_t
, const void *, size_t);
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_ssl_init_fd(rb_fde_t
*const F
, const rb_fd_tls_direction dir
)
126 F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
130 rb_lib_log("%s: rb_malloc: allocation failure", __func__
);
135 unsigned int init_flags
= 0;
139 case RB_FD_TLS_DIRECTION_IN
:
140 init_flags
|= GNUTLS_SERVER
;
142 case RB_FD_TLS_DIRECTION_OUT
:
143 init_flags
|= GNUTLS_CLIENT
;
147 gnutls_init((gnutls_session_t
*) F
->ssl
, init_flags
);
148 gnutls_set_default_priority(SSL_P(F
));
149 gnutls_credentials_set(SSL_P(F
), GNUTLS_CRD_CERTIFICATE
, server_cert_key
);
150 gnutls_dh_set_prime_bits(SSL_P(F
), 2048);
151 gnutls_priority_set(SSL_P(F
), default_priority
);
153 gnutls_transport_set_ptr(SSL_P(F
), (gnutls_transport_ptr_t
) F
);
154 gnutls_transport_set_pull_function(SSL_P(F
), rb_sock_net_recv
);
155 gnutls_transport_set_push_function(SSL_P(F
), rb_sock_net_xmit
);
157 if(dir
== RB_FD_TLS_DIRECTION_IN
)
158 gnutls_certificate_server_set_request(SSL_P(F
), GNUTLS_CERT_REQUEST
);
162 rb_ssl_accept_common(rb_fde_t
*const F
, void *const data
)
164 lrb_assert(F
!= NULL
);
165 lrb_assert(F
->accept
!= NULL
);
166 lrb_assert(F
->accept
->callback
!= NULL
);
167 lrb_assert(F
->ssl
!= NULL
);
171 const int ret
= gnutls_handshake(SSL_P(F
));
172 const int err
= errno
;
174 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (err
== 0 || rb_ignore_errno(err
))))
176 unsigned int flags
= (gnutls_record_get_direction(SSL_P(F
)) == 0) ? RB_SELECT_READ
: RB_SELECT_WRITE
;
177 rb_setselect(F
, flags
, rb_ssl_accept_common
, data
);
181 // These 2 calls may affect errno, which is why we save it above and restore it below
182 rb_settimeout(F
, 0, NULL
, NULL
);
183 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
185 struct acceptdata
*const ad
= F
->accept
;
188 if(ret
== GNUTLS_E_SUCCESS
)
190 F
->handshake_count
++;
191 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
193 else if(ret
== GNUTLS_E_INTERRUPTED
&& err
!= 0)
196 ad
->callback(F
, RB_ERROR
, NULL
, 0, ad
->data
);
201 F
->ssl_errno
= (unsigned long) -ret
;
202 ad
->callback(F
, RB_ERROR_SSL
, NULL
, 0, ad
->data
);
209 rb_ssl_connect_common(rb_fde_t
*const F
, void *const data
)
211 lrb_assert(F
!= NULL
);
212 lrb_assert(F
->ssl
!= NULL
);
216 const int ret
= gnutls_handshake(SSL_P(F
));
217 const int err
= errno
;
219 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (err
== 0 || rb_ignore_errno(err
))))
221 unsigned int flags
= (gnutls_record_get_direction(SSL_P(F
)) == 0) ? RB_SELECT_READ
: RB_SELECT_WRITE
;
222 rb_setselect(F
, flags
, rb_ssl_connect_common
, data
);
226 // These 2 calls may affect errno, which is why we save it above and restore it below
227 rb_settimeout(F
, 0, NULL
, NULL
);
228 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
230 struct ssl_connect
*const sconn
= data
;
232 if(ret
== GNUTLS_E_SUCCESS
)
234 F
->handshake_count
++;
235 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
237 else if(ret
== GNUTLS_E_INTERRUPTED
&& err
!= 0)
240 rb_ssl_connect_realcb(F
, RB_ERROR
, sconn
);
245 F
->ssl_errno
= (unsigned long) -ret
;
246 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
251 rb_ssl_strerror(const int err
)
253 return gnutls_strerror(err
);
257 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
)
264 ret
= gnutls_record_recv(SSL_P(F
), rbuf
, count
);
266 ret
= gnutls_record_send(SSL_P(F
), wbuf
, count
);
271 if(ret
== GNUTLS_E_AGAIN
|| (ret
== GNUTLS_E_INTERRUPTED
&& (errno
== 0 || rb_ignore_errno(errno
))))
273 if(gnutls_record_get_direction(SSL_P(F
)) == 0)
274 return RB_RW_SSL_NEED_READ
;
276 return RB_RW_SSL_NEED_WRITE
;
279 if(ret
== GNUTLS_E_INTERRUPTED
&& errno
!= 0)
280 return RB_RW_IO_ERROR
;
283 F
->ssl_errno
= (unsigned long) -ret
;
284 return RB_RW_SSL_ERROR
;
287 #if (GNUTLS_VERSION_MAJOR < 3)
289 rb_gcry_random_seed(void *const unused
)
291 gcry_fast_random_poll();
296 rb_free_datum_t(gnutls_datum_t
*const datum
)
301 rb_free(datum
->data
);
305 static gnutls_datum_t
*
306 rb_load_file_into_datum_t(const char *const file
)
308 const int datum_fd
= open(file
, O_RDONLY
);
312 struct stat fileinfo
;
313 if(fstat(datum_fd
, &fileinfo
) != 0)
315 (void) close(datum_fd
);
319 const size_t datum_size
= (fileinfo
.st_size
< 131072) ? (size_t) fileinfo
.st_size
: 131072;
322 (void) close(datum_fd
);
326 gnutls_datum_t
*datum
;
327 if((datum
= rb_malloc(sizeof *datum
)) == NULL
)
329 (void) close(datum_fd
);
332 if((datum
->data
= rb_malloc(datum_size
+ 1)) == NULL
)
335 (void) close(datum_fd
);
339 for(size_t data_read
= 0; data_read
< datum_size
; )
341 ssize_t ret
= read(datum_fd
, ((unsigned char *)datum
->data
) + data_read
, datum_size
- data_read
);
345 rb_free_datum_t(datum
);
346 (void) close(datum_fd
);
350 data_read
+= (size_t) ret
;
352 (void) close(datum_fd
);
354 datum
->data
[datum_size
] = '\0';
355 datum
->size
= (unsigned int) datum_size
;
360 make_certfp(gnutls_x509_crt_t cert
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
363 gnutls_digest_algorithm_t md_type
;
369 case RB_SSL_CERTFP_METH_CERT_SHA1
:
370 hashlen
= RB_SSL_CERTFP_LEN_SHA1
;
371 md_type
= GNUTLS_DIG_SHA1
;
373 case RB_SSL_CERTFP_METH_SPKI_SHA256
:
375 case RB_SSL_CERTFP_METH_CERT_SHA256
:
376 hashlen
= RB_SSL_CERTFP_LEN_SHA256
;
377 md_type
= GNUTLS_DIG_SHA256
;
379 case RB_SSL_CERTFP_METH_SPKI_SHA512
:
381 case RB_SSL_CERTFP_METH_CERT_SHA512
:
382 hashlen
= RB_SSL_CERTFP_LEN_SHA512
;
383 md_type
= GNUTLS_DIG_SHA512
;
391 size_t digest_size
= (size_t) hashlen
;
393 if(gnutls_x509_crt_get_fingerprint(cert
, md_type
, certfp
, &digest_size
) != 0)
399 gnutls_pubkey_t pubkey
;
401 if(gnutls_pubkey_init(&pubkey
) != 0)
404 if(gnutls_pubkey_import_x509(pubkey
, cert
, 0) != 0)
406 gnutls_pubkey_deinit(pubkey
);
410 unsigned char derkey
[262144]; // Should be big enough to hold any SubjectPublicKeyInfo structure
411 size_t derkey_len
= sizeof derkey
;
413 if(gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, derkey
, &derkey_len
) != 0)
415 gnutls_pubkey_deinit(pubkey
);
419 gnutls_pubkey_deinit(pubkey
);
421 if(gnutls_hash_fast(md_type
, derkey
, derkey_len
, certfp
) != 0)
430 * External GNUTLS-specific code
434 rb_ssl_shutdown(rb_fde_t
*const F
)
436 if(F
== NULL
|| F
->ssl
== NULL
)
439 for(int i
= 0; i
< 4; i
++)
441 int ret
= gnutls_bye(SSL_P(F
), GNUTLS_SHUT_RDWR
);
443 if(ret
!= GNUTLS_E_INTERRUPTED
&& ret
!= GNUTLS_E_AGAIN
)
447 gnutls_deinit(SSL_P(F
));
458 if((ret
= gnutls_global_init()) != GNUTLS_E_SUCCESS
)
460 rb_lib_log("%s: gnutls_global_init: %s", __func__
, rb_ssl_strerror(ret
));
464 #if (GNUTLS_VERSION_MAJOR < 3)
465 rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed
, NULL
, 300);
472 rb_setup_ssl_server(const char *const certfile
, const char *keyfile
,
473 const char *const dhfile
, const char *const cipherlist
)
477 rb_lib_log("%s: no certificate file specified", __func__
);
485 gnutls_datum_t
*const d_cert
= rb_load_file_into_datum_t(certfile
);
488 rb_lib_log("%s: Error loading certificate: %s", __func__
, strerror(errno
));
492 gnutls_datum_t
*const d_key
= rb_load_file_into_datum_t(keyfile
);
495 rb_lib_log("%s: Error loading key: %s", __func__
, strerror(errno
));
496 rb_free_datum_t(d_cert
);
502 if((ret
= gnutls_certificate_allocate_credentials(&server_cert_key
)) != GNUTLS_E_SUCCESS
)
504 rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__
, rb_ssl_strerror(ret
));
505 rb_free_datum_t(d_cert
);
506 rb_free_datum_t(d_key
);
510 #if (GNUTLS_VERSION_MAJOR < 3)
511 gnutls_certificate_client_set_retrieve_function(server_cert_key
, rb_ssl_cert_auth_cb
);
513 gnutls_certificate_set_retrieve_function(server_cert_key
, rb_ssl_cert_auth_cb
);
516 if((ret
= gnutls_certificate_set_x509_key_mem(server_cert_key
, d_cert
, d_key
,
517 GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
519 rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__
, rb_ssl_strerror(ret
));
520 gnutls_certificate_free_credentials(server_cert_key
);
521 rb_free_datum_t(d_cert
);
522 rb_free_datum_t(d_key
);
525 if((ret
= gnutls_x509_crt_list_import(client_cert
, &client_cert_count
, d_cert
, GNUTLS_X509_FMT_PEM
,
526 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED
)) < 1)
528 rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__
, rb_ssl_strerror(ret
));
529 gnutls_certificate_free_credentials(server_cert_key
);
530 rb_free_datum_t(d_cert
);
531 rb_free_datum_t(d_key
);
534 client_cert_count
= (unsigned int) ret
;
536 if((ret
= gnutls_x509_privkey_init(&client_key
)) != GNUTLS_E_SUCCESS
)
538 rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__
, rb_ssl_strerror(ret
));
539 gnutls_certificate_free_credentials(server_cert_key
);
540 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
541 gnutls_x509_crt_deinit(client_cert
[i
]);
542 rb_free_datum_t(d_cert
);
543 rb_free_datum_t(d_key
);
546 if((ret
= gnutls_x509_privkey_import(client_key
, d_key
, GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
548 rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__
, rb_ssl_strerror(ret
));
549 gnutls_certificate_free_credentials(server_cert_key
);
550 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
551 gnutls_x509_crt_deinit(client_cert
[i
]);
552 gnutls_x509_privkey_deinit(client_key
);
553 rb_free_datum_t(d_cert
);
554 rb_free_datum_t(d_key
);
558 rb_free_datum_t(d_cert
);
559 rb_free_datum_t(d_key
);
563 gnutls_datum_t
*const d_dhp
= rb_load_file_into_datum_t(dhfile
);
567 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, strerror(errno
));
568 gnutls_certificate_free_credentials(server_cert_key
);
569 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
570 gnutls_x509_crt_deinit(client_cert
[i
]);
571 gnutls_x509_privkey_deinit(client_key
);
574 if((ret
= gnutls_dh_params_init(&server_dhp
)) != GNUTLS_E_SUCCESS
)
576 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, rb_ssl_strerror(ret
));
577 gnutls_certificate_free_credentials(server_cert_key
);
578 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
579 gnutls_x509_crt_deinit(client_cert
[i
]);
580 gnutls_x509_privkey_deinit(client_key
);
581 rb_free_datum_t(d_dhp
);
584 if((ret
= gnutls_dh_params_import_pkcs3(server_dhp
, d_dhp
, GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
586 rb_lib_log("%s: Error parsing DH parameters: %s", __func__
, rb_ssl_strerror(ret
));
587 gnutls_certificate_free_credentials(server_cert_key
);
588 for(unsigned int i
= 0; i
< client_cert_count
; i
++)
589 gnutls_x509_crt_deinit(client_cert
[i
]);
590 gnutls_x509_privkey_deinit(client_key
);
591 gnutls_dh_params_deinit(server_dhp
);
592 rb_free_datum_t(d_dhp
);
596 gnutls_certificate_set_dh_params(server_cert_key
, server_dhp
);
597 rb_free_datum_t(d_dhp
);
600 const char *err
= NULL
;
601 if((ret
= gnutls_priority_init(&default_priority
, cipherlist
, &err
)) != GNUTLS_E_SUCCESS
)
603 rb_lib_log("%s: gnutls_priority_init: %s, error begins at '%s'? -- using defaults instead",
604 __func__
, rb_ssl_strerror(ret
), err
? err
: "<unknown>");
606 (void) gnutls_priority_init(&default_priority
, NULL
, &err
);
609 rb_lib_log("%s: TLS configuration successful", __func__
);
614 rb_init_prng(const char *const path
, prng_seed_t seed_type
)
616 #if (GNUTLS_VERSION_MAJOR < 3)
617 gcry_fast_random_poll();
618 rb_lib_log("%s: PRNG initialised", __func__
);
620 rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__
);
626 rb_get_random(void *const buf
, const size_t length
)
628 #if (GNUTLS_VERSION_MAJOR < 3)
629 gcry_randomize(buf
, length
, GCRY_STRONG_RANDOM
);
631 gnutls_rnd(GNUTLS_RND_KEY
, buf
, length
);
637 rb_get_ssl_strerror(rb_fde_t
*const F
)
639 const int err
= (int) F
->ssl_errno
;
640 return rb_ssl_strerror(-err
);
644 rb_get_ssl_certfp(rb_fde_t
*const F
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
646 if(gnutls_certificate_type_get(SSL_P(F
)) != GNUTLS_CRT_X509
)
649 unsigned int cert_list_size
= 0;
650 const gnutls_datum_t
*const cert_list
= gnutls_certificate_get_peers(SSL_P(F
), &cert_list_size
);
651 if(cert_list
== NULL
|| cert_list_size
< 1)
654 gnutls_x509_crt_t peer_cert
;
655 if(gnutls_x509_crt_init(&peer_cert
) != 0)
658 if(gnutls_x509_crt_import(peer_cert
, &cert_list
[0], GNUTLS_X509_FMT_DER
) < 0)
660 gnutls_x509_crt_deinit(peer_cert
);
664 const int len
= make_certfp(peer_cert
, certfp
, method
);
666 gnutls_x509_crt_deinit(peer_cert
);
672 rb_get_ssl_certfp_file(const char *const filename
, uint8_t certfp
[const RB_SSL_CERTFP_LEN
], const int method
)
674 gnutls_datum_t
*const datum_cert
= rb_load_file_into_datum_t(filename
);
675 if(datum_cert
== NULL
)
678 gnutls_x509_crt_t cert
;
679 if(gnutls_x509_crt_init(&cert
) != 0)
681 rb_free_datum_t(datum_cert
);
684 if(gnutls_x509_crt_import(cert
, datum_cert
, GNUTLS_X509_FMT_PEM
) < 0)
686 gnutls_x509_crt_deinit(cert
);
687 rb_free_datum_t(datum_cert
);
691 const int len
= make_certfp(cert
, certfp
, method
);
693 gnutls_x509_crt_deinit(cert
);
694 rb_free_datum_t(datum_cert
);
700 rb_get_ssl_info(char *const buf
, const size_t len
)
702 (void) snprintf(buf
, len
, "GNUTLS: compiled (v%s), library (v%s)",
703 LIBGNUTLS_VERSION
, gnutls_check_version(NULL
));
707 rb_ssl_get_cipher(rb_fde_t
*const F
)
709 if(F
== NULL
|| F
->ssl
== NULL
)
712 static char buf
[512];
714 gnutls_protocol_t version_ptr
= gnutls_protocol_get_version(SSL_P(F
));
715 gnutls_cipher_algorithm_t cipher_ptr
= gnutls_cipher_get(SSL_P(F
));
717 const char *const version
= gnutls_protocol_get_name(version_ptr
);
718 const char *const cipher
= gnutls_cipher_get_name(cipher_ptr
);
720 (void) snprintf(buf
, sizeof buf
, "%s, %s", version
, cipher
);
726 rb_ssl_read(rb_fde_t
*const F
, void *const buf
, const size_t count
)
728 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
732 rb_ssl_write(rb_fde_t
*const F
, const void *const buf
, const size_t count
)
734 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
740 * Internal library-agnostic code
744 rb_ssl_connect_realcb(rb_fde_t
*const F
, const int status
, struct ssl_connect
*const sconn
)
746 lrb_assert(F
!= NULL
);
747 lrb_assert(F
->connect
!= NULL
);
749 F
->connect
->callback
= sconn
->callback
;
750 F
->connect
->data
= sconn
->data
;
752 rb_connect_callback(F
, status
);
757 rb_ssl_timeout_cb(rb_fde_t
*const F
, void *const data
)
759 lrb_assert(F
->accept
!= NULL
);
760 lrb_assert(F
->accept
->callback
!= NULL
);
762 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
766 rb_ssl_tryconn_timeout_cb(rb_fde_t
*const F
, void *const data
)
768 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
772 rb_ssl_tryconn(rb_fde_t
*const F
, const int status
, void *const data
)
774 lrb_assert(F
!= NULL
);
776 struct ssl_connect
*const sconn
= data
;
780 rb_ssl_connect_realcb(F
, status
, sconn
);
784 F
->type
|= RB_FD_SSL
;
786 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
787 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_OUT
);
788 rb_ssl_connect_common(F
, sconn
);
792 rb_sock_net_recv(gnutls_transport_ptr_t context_ptr
, void *const buf
, const size_t count
)
794 const int fd
= rb_get_fd((rb_fde_t
*)context_ptr
);
796 return recv(fd
, buf
, count
, 0);
800 rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr
, const void *const buf
, const size_t count
)
802 const int fd
= rb_get_fd((rb_fde_t
*)context_ptr
);
804 return send(fd
, buf
, count
, 0);
810 * External library-agnostic code
814 rb_supports_ssl(void)
820 rb_ssl_handshake_count(rb_fde_t
*const F
)
822 return F
->handshake_count
;
826 rb_ssl_clear_handshake_count(rb_fde_t
*const F
)
828 F
->handshake_count
= 0;
832 rb_ssl_start_accepted(rb_fde_t
*const F
, ACCB
*const cb
, void *const data
, const int timeout
)
834 F
->type
|= RB_FD_SSL
;
836 F
->accept
= rb_malloc(sizeof(struct acceptdata
));
837 F
->accept
->callback
= cb
;
838 F
->accept
->data
= data
;
839 F
->accept
->addrlen
= 0;
840 (void) memset(&F
->accept
->S
, 0x00, sizeof F
->accept
->S
);
842 rb_settimeout(F
, timeout
, rb_ssl_timeout_cb
, NULL
);
843 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_IN
);
844 rb_ssl_accept_common(F
, NULL
);
848 rb_ssl_accept_setup(rb_fde_t
*const srv_F
, rb_fde_t
*const cli_F
, struct sockaddr
*const st
, const int addrlen
)
850 cli_F
->type
|= RB_FD_SSL
;
852 cli_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
853 cli_F
->accept
->callback
= srv_F
->accept
->callback
;
854 cli_F
->accept
->data
= srv_F
->accept
->data
;
855 cli_F
->accept
->addrlen
= (rb_socklen_t
) addrlen
;
856 (void) memset(&cli_F
->accept
->S
, 0x00, sizeof cli_F
->accept
->S
);
857 (void) memcpy(&cli_F
->accept
->S
, st
, (size_t) addrlen
);
859 rb_settimeout(cli_F
, 10, rb_ssl_timeout_cb
, NULL
);
860 rb_ssl_init_fd(cli_F
, RB_FD_TLS_DIRECTION_IN
);
861 rb_ssl_accept_common(cli_F
, NULL
);
865 rb_ssl_listen(rb_fde_t
*const F
, const int backlog
, const int defer_accept
)
867 int result
= rb_listen(F
, backlog
, defer_accept
);
869 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
875 rb_connect_tcp_ssl(rb_fde_t
*const F
, struct sockaddr
*const dest
, struct sockaddr
*const clocal
,
876 CNCB
*const callback
, void *const data
, const int timeout
)
881 struct ssl_connect
*const sconn
= rb_malloc(sizeof *sconn
);
883 sconn
->callback
= callback
;
884 sconn
->timeout
= timeout
;
886 rb_connect_tcp(F
, dest
, clocal
, rb_ssl_tryconn
, sconn
, timeout
);
890 rb_ssl_start_connected(rb_fde_t
*const F
, CNCB
*const callback
, void *const data
, const int timeout
)
895 struct ssl_connect
*const sconn
= rb_malloc(sizeof *sconn
);
897 sconn
->callback
= callback
;
898 sconn
->timeout
= timeout
;
900 F
->connect
= rb_malloc(sizeof(struct conndata
));
901 F
->connect
->callback
= callback
;
902 F
->connect
->data
= data
;
904 F
->type
|= RB_FD_SSL
;
906 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
907 rb_ssl_init_fd(F
, RB_FD_TLS_DIRECTION_OUT
);
908 rb_ssl_connect_common(F
, sconn
);
911 #endif /* HAVE_GNUTLS */