2 * librb: a library used by charybdis 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>
27 #include <commio-int.h>
28 #include <commio-ssl.h>
32 #include <gnutls/gnutls.h>
33 #include <gnutls/x509.h>
34 #include <gnutls/abstract.h>
36 #if (GNUTLS_VERSION_MAJOR < 3)
39 # include <gnutls/crypto.h>
42 static gnutls_certificate_credentials_t x509
;
43 static gnutls_dh_params_t dh_params
;
44 static gnutls_priority_t default_priority
;
46 /* These are all used for getting GnuTLS to supply a client cert. */
48 static unsigned int x509_cert_count
;
49 static gnutls_x509_crt_t x509_cert
[MAX_CERTS
];
50 static gnutls_x509_privkey_t x509_key
;
51 #if GNUTLS_VERSION_MAJOR < 3
52 static int cert_callback(gnutls_session_t session
, const gnutls_datum_t
*req_ca_rdn
, int nreqs
,
53 const gnutls_pk_algorithm_t
*sign_algos
, int sign_algos_len
, gnutls_retr_st
*st
);
55 static int cert_callback(gnutls_session_t session
, const gnutls_datum_t
*req_ca_rdn
, int nreqs
,
56 const gnutls_pk_algorithm_t
*sign_algos
, int sign_algos_len
, gnutls_retr2_st
*st
);
59 #define SSL_P(x) *((gnutls_session_t *)F->ssl)
62 rb_ssl_shutdown(rb_fde_t
*F
)
65 if(F
== NULL
|| F
->ssl
== NULL
)
67 for(i
= 0; i
< 4; i
++)
69 if(gnutls_bye(SSL_P(F
), GNUTLS_SHUT_RDWR
) == GNUTLS_E_SUCCESS
)
72 gnutls_deinit(SSL_P(F
));
77 rb_ssl_handshake_count(rb_fde_t
*F
)
79 return F
->handshake_count
;
83 rb_ssl_clear_handshake_count(rb_fde_t
*F
)
85 F
->handshake_count
= 0;
89 rb_ssl_timeout(rb_fde_t
*F
, void *notused
)
91 lrb_assert(F
->accept
!= NULL
);
92 F
->accept
->callback(F
, RB_ERR_TIMEOUT
, NULL
, 0, F
->accept
->data
);
97 do_ssl_handshake(rb_fde_t
*F
, PF
* callback
, void *data
)
102 ret
= gnutls_handshake(SSL_P(F
));
105 if((ret
== GNUTLS_E_INTERRUPTED
&& rb_ignore_errno(errno
)) || ret
== GNUTLS_E_AGAIN
)
107 if(gnutls_record_get_direction(SSL_P(F
)) == 0)
108 flags
= RB_SELECT_READ
;
110 flags
= RB_SELECT_WRITE
;
111 rb_setselect(F
, flags
, callback
, data
);
117 return 1; /* handshake is finished..go about life */
121 rb_ssl_tryaccept(rb_fde_t
*F
, void *data
)
124 struct acceptdata
*ad
;
126 lrb_assert(F
->accept
!= NULL
);
128 ret
= do_ssl_handshake(F
, rb_ssl_tryaccept
, NULL
);
130 /* do_ssl_handshake does the rb_setselect */
136 rb_settimeout(F
, 0, NULL
, NULL
);
137 rb_setselect(F
, RB_SELECT_READ
| RB_SELECT_WRITE
, NULL
, NULL
);
140 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
142 ad
->callback(F
, RB_ERROR_SSL
, NULL
, 0, ad
->data
);
148 rb_ssl_start_accepted(rb_fde_t
*new_F
, ACCB
* cb
, void *data
, int timeout
)
150 gnutls_session_t
*ssl
;
151 new_F
->type
|= RB_FD_SSL
;
152 ssl
= new_F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
153 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
155 new_F
->accept
->callback
= cb
;
156 new_F
->accept
->data
= data
;
157 rb_settimeout(new_F
, timeout
, rb_ssl_timeout
, NULL
);
159 new_F
->accept
->addrlen
= 0;
161 gnutls_init(ssl
, GNUTLS_SERVER
);
162 gnutls_set_default_priority(*ssl
);
163 gnutls_credentials_set(*ssl
, GNUTLS_CRD_CERTIFICATE
, x509
);
164 gnutls_dh_set_prime_bits(*ssl
, 1024);
165 gnutls_transport_set_ptr(*ssl
, (gnutls_transport_ptr_t
) (long int)new_F
->fd
);
166 gnutls_certificate_server_set_request(*ssl
, GNUTLS_CERT_REQUEST
);
167 gnutls_priority_set(*ssl
, default_priority
);
169 if(do_ssl_handshake(new_F
, rb_ssl_tryaccept
, NULL
))
171 struct acceptdata
*ad
= new_F
->accept
;
172 new_F
->accept
= NULL
;
173 ad
->callback(new_F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
183 rb_ssl_accept_setup(rb_fde_t
*F
, rb_fde_t
*new_F
, struct sockaddr
*st
, int addrlen
)
185 new_F
->type
|= RB_FD_SSL
;
186 new_F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
187 new_F
->accept
= rb_malloc(sizeof(struct acceptdata
));
189 new_F
->accept
->callback
= F
->accept
->callback
;
190 new_F
->accept
->data
= F
->accept
->data
;
191 rb_settimeout(new_F
, 10, rb_ssl_timeout
, NULL
);
192 memcpy(&new_F
->accept
->S
, st
, addrlen
);
193 new_F
->accept
->addrlen
= addrlen
;
195 gnutls_init((gnutls_session_t
*) new_F
->ssl
, GNUTLS_SERVER
);
196 gnutls_set_default_priority(SSL_P(new_F
));
197 gnutls_credentials_set(SSL_P(new_F
), GNUTLS_CRD_CERTIFICATE
, x509
);
198 gnutls_dh_set_prime_bits(SSL_P(new_F
), 1024);
199 gnutls_transport_set_ptr(SSL_P(new_F
), (gnutls_transport_ptr_t
) (long int)rb_get_fd(new_F
));
200 gnutls_certificate_server_set_request(SSL_P(new_F
), GNUTLS_CERT_REQUEST
);
201 gnutls_priority_set(SSL_P(F
), default_priority
);
203 if(do_ssl_handshake(F
, rb_ssl_tryaccept
, NULL
))
205 struct acceptdata
*ad
= F
->accept
;
207 ad
->callback(F
, RB_OK
, (struct sockaddr
*)&ad
->S
, ad
->addrlen
, ad
->data
);
216 rb_ssl_read_or_write(int r_or_w
, rb_fde_t
*F
, void *rbuf
, const void *wbuf
, size_t count
)
219 gnutls_session_t
*ssl
= F
->ssl
;
222 ret
= gnutls_record_recv(*ssl
, rbuf
, count
);
224 ret
= gnutls_record_send(*ssl
, wbuf
, count
);
231 case GNUTLS_E_INTERRUPTED
:
232 if(rb_ignore_errno(errno
))
234 if(gnutls_record_get_direction(*ssl
) == 0)
235 return RB_RW_SSL_NEED_READ
;
237 return RB_RW_SSL_NEED_WRITE
;
243 return RB_RW_IO_ERROR
;
250 rb_ssl_read(rb_fde_t
*F
, void *buf
, size_t count
)
252 return rb_ssl_read_or_write(0, F
, buf
, NULL
, count
);
256 rb_ssl_write(rb_fde_t
*F
, const void *buf
, size_t count
)
258 return rb_ssl_read_or_write(1, F
, NULL
, buf
, count
);
261 #if (GNUTLS_VERSION_MAJOR < 3)
263 rb_gcry_random_seed(void *unused
)
265 gcry_fast_random_poll();
272 gnutls_global_init();
274 if(gnutls_certificate_allocate_credentials(&x509
) != GNUTLS_E_SUCCESS
)
276 rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials");
280 #if GNUTLS_VERSION_MAJOR < 3
281 gnutls_certificate_client_set_retrieve_function(x509
, cert_callback
);
283 gnutls_certificate_set_retrieve_function(x509
, cert_callback
);
286 #if (GNUTLS_VERSION_MAJOR < 3)
287 rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed
, NULL
, 300);
293 /* We only have one certificate to authenticate with, as both client and server. Unfortunately,
294 * GnuTLS tries to be clever, and as client, will attempt to use a certificate that the server
295 * will trust. We usually use self-signed certs, though, so the result of this search is always
296 * nothing. Therefore, it uses no certificate to authenticate as a client. This is undesirable
297 * as it breaks fingerprint auth. Thus, we use this callback to force GnuTLS to always
298 * authenticate with our certificate at all times.
300 #if GNUTLS_VERSION_MAJOR < 3
302 cert_callback(gnutls_session_t session
, const gnutls_datum_t
*req_ca_rdn
, int nreqs
,
303 const gnutls_pk_algorithm_t
*sign_algos
, int sign_algos_len
, gnutls_retr_st
*st
)
306 cert_callback(gnutls_session_t session
, const gnutls_datum_t
*req_ca_rdn
, int nreqs
,
307 const gnutls_pk_algorithm_t
*sign_algos
, int sign_algos_len
, gnutls_retr2_st
*st
)
310 /* XXX - ugly hack. Tell GnuTLS to use the first (only) certificate we have for auth. */
311 #if (GNUTLS_VERSION_MAJOR < 3)
312 st
->type
= GNUTLS_CRT_X509
;
314 st
->cert_type
= GNUTLS_CRT_X509
;
315 st
->key_type
= GNUTLS_PRIVKEY_X509
;
317 st
->ncerts
= x509_cert_count
;
318 st
->cert
.x509
= x509_cert
;
319 st
->key
.x509
= x509_key
;
326 rb_free_datum_t(gnutls_datum_t
* d
)
332 static gnutls_datum_t
*
333 rb_load_file_into_datum_t(const char *file
)
336 gnutls_datum_t
*datum
;
337 struct stat fileinfo
;
339 if((f
= fopen(file
, "r")) == NULL
)
341 if(fstat(fileno(f
), &fileinfo
))
344 datum
= rb_malloc(sizeof(gnutls_datum_t
));
346 if(fileinfo
.st_size
> 131072) /* deal with retards */
347 datum
->size
= 131072;
349 datum
->size
= fileinfo
.st_size
;
351 datum
->data
= rb_malloc(datum
->size
+ 1);
352 count
= fread(datum
->data
, datum
->size
, 1, f
);
357 rb_free_datum_t(datum
);
364 rb_setup_ssl_server(const char *certfile
, const char *keyfile
, const char *dhfile
, const char *cipher_list
)
368 gnutls_datum_t
*d_cert
, *d_key
;
372 rb_lib_log("rb_setup_ssl_server: No certificate file");
379 if((d_cert
= rb_load_file_into_datum_t(certfile
)) == NULL
)
381 rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", strerror(errno
));
385 if((d_key
= rb_load_file_into_datum_t(keyfile
)) == NULL
)
387 rb_lib_log("rb_setup_ssl_server: Error loading key: %s", strerror(errno
));
391 /* In addition to creating the certificate set, we also need to store our cert elsewhere
392 * so we can force GnuTLS to identify with it when acting as a client.
394 gnutls_x509_privkey_init(&x509_key
);
395 if ((ret
= gnutls_x509_privkey_import(x509_key
, d_key
, GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
397 rb_lib_log("rb_setup_ssl_server: Error loading key file: %s", gnutls_strerror(ret
));
401 x509_cert_count
= MAX_CERTS
;
402 if ((ret
= gnutls_x509_crt_list_import(x509_cert
, &x509_cert_count
, d_cert
, GNUTLS_X509_FMT_PEM
,
403 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED
)) < 0)
405 rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", gnutls_strerror(ret
));
408 x509_cert_count
= ret
;
411 gnutls_certificate_set_x509_key_mem(x509
, d_cert
, d_key
,
412 GNUTLS_X509_FMT_PEM
)) != GNUTLS_E_SUCCESS
)
414 rb_lib_log("rb_setup_ssl_server: Error loading certificate or key file: %s",
415 gnutls_strerror(ret
));
419 rb_free_datum_t(d_cert
);
420 rb_free_datum_t(d_key
);
424 if(gnutls_dh_params_init(&dh_params
) == GNUTLS_E_SUCCESS
)
426 gnutls_datum_t
*data
;
428 data
= rb_load_file_into_datum_t(dhfile
);
431 xret
= gnutls_dh_params_import_pkcs3(dh_params
, data
,
432 GNUTLS_X509_FMT_PEM
);
435 ("rb_setup_ssl_server: Error parsing DH file: %s\n",
436 gnutls_strerror(xret
));
437 rb_free_datum_t(data
);
439 gnutls_certificate_set_dh_params(x509
, dh_params
);
442 rb_lib_log("rb_setup_ssl_server: Unable to setup DH parameters");
445 ret
= gnutls_priority_init(&default_priority
, cipher_list
, &err
);
448 rb_lib_log("rb_setup_ssl_server: syntax error (using defaults instead) in ssl cipher list at: %s", err
);
449 gnutls_priority_init(&default_priority
, NULL
, &err
);
457 rb_ssl_listen(rb_fde_t
*F
, int backlog
, int defer_accept
)
461 result
= rb_listen(F
, backlog
, defer_accept
);
462 F
->type
= RB_FD_SOCKET
| RB_FD_LISTEN
| RB_FD_SSL
;
475 rb_ssl_connect_realcb(rb_fde_t
*F
, int status
, struct ssl_connect
*sconn
)
477 F
->connect
->callback
= sconn
->callback
;
478 F
->connect
->data
= sconn
->data
;
480 rb_connect_callback(F
, status
);
484 rb_ssl_tryconn_timeout_cb(rb_fde_t
*F
, void *data
)
486 rb_ssl_connect_realcb(F
, RB_ERR_TIMEOUT
, data
);
490 rb_ssl_tryconn_cb(rb_fde_t
*F
, void *data
)
492 struct ssl_connect
*sconn
= data
;
495 ret
= do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
500 rb_ssl_connect_realcb(F
, RB_ERROR_SSL
, sconn
);
503 /* do_ssl_handshake does the rb_setselect stuff */
510 rb_ssl_connect_realcb(F
, RB_OK
, sconn
);
514 rb_ssl_tryconn(rb_fde_t
*F
, int status
, void *data
)
516 struct ssl_connect
*sconn
= data
;
519 rb_ssl_connect_realcb(F
, status
, sconn
);
523 F
->type
|= RB_FD_SSL
;
526 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
527 F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
528 gnutls_init(F
->ssl
, GNUTLS_CLIENT
);
529 gnutls_set_default_priority(SSL_P(F
));
530 gnutls_credentials_set(SSL_P(F
), GNUTLS_CRD_CERTIFICATE
, x509
);
531 gnutls_dh_set_prime_bits(SSL_P(F
), 1024);
532 gnutls_transport_set_ptr(SSL_P(F
), (gnutls_transport_ptr_t
) (long int)F
->fd
);
533 gnutls_priority_set(SSL_P(F
), default_priority
);
535 do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
539 rb_connect_tcp_ssl(rb_fde_t
*F
, struct sockaddr
*dest
,
540 struct sockaddr
*clocal
, CNCB
* callback
, void *data
, int timeout
)
542 struct ssl_connect
*sconn
;
546 sconn
= rb_malloc(sizeof(struct ssl_connect
));
548 sconn
->callback
= callback
;
549 sconn
->timeout
= timeout
;
550 rb_connect_tcp(F
, dest
, clocal
, rb_ssl_tryconn
, sconn
, timeout
);
555 rb_ssl_start_connected(rb_fde_t
*F
, CNCB
* callback
, void *data
, int timeout
)
557 struct ssl_connect
*sconn
;
561 sconn
= rb_malloc(sizeof(struct ssl_connect
));
563 sconn
->callback
= callback
;
564 sconn
->timeout
= timeout
;
565 F
->connect
= rb_malloc(sizeof(struct conndata
));
566 F
->connect
->callback
= callback
;
567 F
->connect
->data
= data
;
568 F
->type
|= RB_FD_SSL
;
569 F
->ssl
= rb_malloc(sizeof(gnutls_session_t
));
571 gnutls_init(F
->ssl
, GNUTLS_CLIENT
);
572 gnutls_set_default_priority(SSL_P(F
));
573 gnutls_credentials_set(SSL_P(F
), GNUTLS_CRD_CERTIFICATE
, x509
);
574 gnutls_dh_set_prime_bits(SSL_P(F
), 1024);
575 gnutls_transport_set_ptr(SSL_P(F
), (gnutls_transport_ptr_t
) (long int)F
->fd
);
576 gnutls_priority_set(SSL_P(F
), default_priority
);
578 rb_settimeout(F
, sconn
->timeout
, rb_ssl_tryconn_timeout_cb
, sconn
);
580 do_ssl_handshake(F
, rb_ssl_tryconn_cb
, (void *)sconn
);
584 rb_init_prng(const char *path
, prng_seed_t seed_type
)
586 #if GNUTLS_VERSION_MAJOR < 3
587 gcry_fast_random_poll();
593 rb_get_random(void *buf
, size_t length
)
595 #if GNUTLS_VERSION_MAJOR < 3
596 gcry_randomize(buf
, length
, GCRY_STRONG_RANDOM
);
598 gnutls_rnd(GNUTLS_RND_KEY
, buf
, length
);
604 rb_get_ssl_strerror(rb_fde_t
*F
)
606 return gnutls_strerror(F
->ssl_errno
);
610 make_certfp(gnutls_x509_crt_t cert
, uint8_t certfp
[RB_SSL_CERTFP_LEN
], int method
)
612 gnutls_digest_algorithm_t algo
;
619 case RB_SSL_CERTFP_METH_CERT_SHA1
:
620 algo
= GNUTLS_DIG_SHA1
;
621 len
= RB_SSL_CERTFP_LEN_SHA1
;
623 case RB_SSL_CERTFP_METH_SPKI_SHA256
:
625 case RB_SSL_CERTFP_METH_CERT_SHA256
:
626 algo
= GNUTLS_DIG_SHA256
;
627 len
= RB_SSL_CERTFP_LEN_SHA256
;
629 case RB_SSL_CERTFP_METH_SPKI_SHA512
:
631 case RB_SSL_CERTFP_METH_CERT_SHA512
:
632 algo
= GNUTLS_DIG_SHA512
;
633 len
= RB_SSL_CERTFP_LEN_SHA512
;
641 if (gnutls_x509_crt_get_fingerprint(cert
, algo
, certfp
, &digest_size
) != 0)
646 gnutls_pubkey_t pubkey
;
647 unsigned char *der_pubkey
= NULL
;
648 size_t der_pubkey_len
= 0;
650 if (gnutls_pubkey_init(&pubkey
) == GNUTLS_E_SUCCESS
)
652 if (gnutls_pubkey_import_x509(pubkey
, cert
, 0) == GNUTLS_E_SUCCESS
)
654 if (gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, der_pubkey
, &der_pubkey_len
) == GNUTLS_E_SHORT_MEMORY_BUFFER
)
656 der_pubkey
= rb_malloc(der_pubkey_len
);
658 if (gnutls_pubkey_export(pubkey
, GNUTLS_X509_FMT_DER
, der_pubkey
, &der_pubkey_len
) != GNUTLS_E_SUCCESS
)
666 gnutls_pubkey_deinit(pubkey
);
671 if (gnutls_hash_fast(algo
, der_pubkey
, der_pubkey_len
, certfp
) != 0)
686 rb_get_ssl_certfp(rb_fde_t
*F
, uint8_t certfp
[RB_SSL_CERTFP_LEN
], int method
)
688 gnutls_x509_crt_t cert
;
689 unsigned int cert_list_size
;
690 const gnutls_datum_t
*cert_list
;
693 if (gnutls_certificate_type_get(SSL_P(F
)) != GNUTLS_CRT_X509
)
696 if (gnutls_x509_crt_init(&cert
) < 0)
700 cert_list
= gnutls_certificate_get_peers(SSL_P(F
), &cert_list_size
);
701 if (cert_list
== NULL
)
703 gnutls_x509_crt_deinit(cert
);
707 if (gnutls_x509_crt_import(cert
, &cert_list
[0], GNUTLS_X509_FMT_DER
) < 0)
709 gnutls_x509_crt_deinit(cert
);
713 len
= make_certfp(cert
, certfp
, method
);
714 gnutls_x509_crt_deinit(cert
);
719 rb_get_ssl_certfp_file(const char *filename
, uint8_t certfp
[RB_SSL_CERTFP_LEN
], int method
)
721 gnutls_x509_crt_t cert
;
722 gnutls_datum_t
*d_cert
;
725 if ((d_cert
= rb_load_file_into_datum_t(filename
)) == NULL
)
728 if (gnutls_x509_crt_init(&cert
) < 0)
731 if (gnutls_x509_crt_import(cert
, d_cert
, GNUTLS_X509_FMT_PEM
) != 0)
734 len
= make_certfp(cert
, certfp
, method
);
735 gnutls_x509_crt_deinit(cert
);
740 rb_supports_ssl(void)
746 rb_get_ssl_info(char *buf
, size_t len
)
748 snprintf(buf
, len
, "GNUTLS: compiled (%s), library (%s)",
749 LIBGNUTLS_VERSION
, gnutls_check_version(NULL
));
753 rb_ssl_get_cipher(rb_fde_t
*F
)
755 static char buf
[1024];
757 const char* proto_name
=
758 gnutls_protocol_get_name(gnutls_protocol_get_version(SSL_P(F
)));
760 const char* kex_alg_name
=
761 gnutls_kx_get_name(gnutls_kx_get(SSL_P(F
)));
763 const char* cipher_alg_name
=
764 gnutls_cipher_get_name(gnutls_cipher_get(SSL_P(F
)));
766 const char* mac_alg_name
=
767 gnutls_mac_get_name(gnutls_mac_get(SSL_P(F
)));
769 (void) snprintf(buf
, sizeof buf
, "%s%s%s%s%s%s%s",
770 proto_name
? proto_name
: "",
771 proto_name
? ", " : "",
772 kex_alg_name
? kex_alg_name
: "",
773 kex_alg_name
? "-" : "",
774 cipher_alg_name
? cipher_alg_name
: "",
775 cipher_alg_name
? "-" : "",
776 mac_alg_name
? mac_alg_name
: "");
781 #endif /* HAVE_GNUTLS */