From 4d89c83c324605ba9945db238d82e0c1d33334a2 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 11:54:04 +0000 Subject: [PATCH 01/33] GNUTLS: Shut down sessions properly If gnutls_bye() fails with a fatal error, we would reattempt it again and again, even though this may then go on to e.g. cause a segmentation fault. Now we just keep retrying if it was interrupted, in line with the other backends, up to a maximum of 3 retries. --- libratbox/src/gnutls.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 05fe8128..cb983eb6 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -58,18 +58,23 @@ static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_ #define SSL_P(x) *((gnutls_session_t *)F->ssl) void -rb_ssl_shutdown(rb_fde_t *F) +rb_ssl_shutdown(rb_fde_t *const F) { - int i; if(F == NULL || F->ssl == NULL) return; - for(i = 0; i < 4; i++) + + for(int i = 0; i < 4; i++) { - if(gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR) == GNUTLS_E_SUCCESS) + int ret = gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR); + + if(ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_AGAIN) break; } + gnutls_deinit(SSL_P(F)); + rb_free(F->ssl); + F->ssl = NULL; } unsigned int From d9e6ff734935c50c28610f18c4ff9a5f46678214 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Sat, 17 Sep 2016 00:56:11 +0000 Subject: [PATCH 02/33] GNUTLS: Tidy up unit-scope variables and give them clearer names --- libratbox/src/gnutls.c | 64 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index cb983eb6..5f806b5d 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -38,15 +38,6 @@ # include #endif -static gnutls_certificate_credentials_t x509; -static gnutls_dh_params_t dh_params; -static gnutls_priority_t default_priority; - -/* These are all used for getting GnuTLS to supply a client cert. */ -#define MAX_CERTS 6 -static unsigned int x509_cert_count; -static gnutls_x509_crt_t x509_cert[MAX_CERTS]; -static gnutls_x509_privkey_t x509_key; #if GNUTLS_VERSION_MAJOR < 3 static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs, const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr_st *st); @@ -57,6 +48,23 @@ static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_ #define SSL_P(x) *((gnutls_session_t *)F->ssl) + + +// Server side variables +static gnutls_certificate_credentials_t server_cert_key; +static gnutls_dh_params_t server_dhp; + +// Client side variables +#define MAX_CERTS 6 +static gnutls_x509_crt_t client_cert[MAX_CERTS]; +static gnutls_x509_privkey_t client_key; +static unsigned int client_cert_count; + +// Shared variables +static gnutls_priority_t default_priority; + + + void rb_ssl_shutdown(rb_fde_t *const F) { @@ -164,7 +172,7 @@ rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) gnutls_init(ssl, GNUTLS_SERVER); gnutls_set_default_priority(*ssl); - gnutls_credentials_set(*ssl, GNUTLS_CRD_CERTIFICATE, x509); + gnutls_credentials_set(*ssl, GNUTLS_CRD_CERTIFICATE, server_cert_key); gnutls_dh_set_prime_bits(*ssl, 1024); gnutls_transport_set_ptr(*ssl, (gnutls_transport_ptr_t) (long int)new_F->fd); gnutls_certificate_server_set_request(*ssl, GNUTLS_CERT_REQUEST); @@ -198,7 +206,7 @@ rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrl gnutls_init((gnutls_session_t *) new_F->ssl, GNUTLS_SERVER); gnutls_set_default_priority(SSL_P(new_F)); - gnutls_credentials_set(SSL_P(new_F), GNUTLS_CRD_CERTIFICATE, x509); + gnutls_credentials_set(SSL_P(new_F), GNUTLS_CRD_CERTIFICATE, server_cert_key); gnutls_dh_set_prime_bits(SSL_P(new_F), 1024); gnutls_transport_set_ptr(SSL_P(new_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(new_F)); gnutls_certificate_server_set_request(SSL_P(new_F), GNUTLS_CERT_REQUEST); @@ -275,16 +283,16 @@ rb_init_ssl(void) { gnutls_global_init(); - if(gnutls_certificate_allocate_credentials(&x509) != GNUTLS_E_SUCCESS) + if(gnutls_certificate_allocate_credentials(&server_cert_key) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials"); return 0; } #if GNUTLS_VERSION_MAJOR < 3 - gnutls_certificate_client_set_retrieve_function(x509, cert_callback); + gnutls_certificate_client_set_retrieve_function(server_cert_key, cert_callback); #else - gnutls_certificate_set_retrieve_function(x509, cert_callback); + gnutls_certificate_set_retrieve_function(server_cert_key, cert_callback); #endif #if (GNUTLS_VERSION_MAJOR < 3) @@ -318,9 +326,9 @@ cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nr st->cert_type = GNUTLS_CRT_X509; st->key_type = GNUTLS_PRIVKEY_X509; #endif - st->ncerts = x509_cert_count; - st->cert.x509 = x509_cert; - st->key.x509 = x509_key; + st->ncerts = client_cert_count; + st->cert.x509 = client_cert; + st->key.x509 = client_key; st->deinit_all = 0; return 0; @@ -384,24 +392,24 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c /* In addition to creating the certificate set, we also need to store our cert elsewhere * so we can force GnuTLS to identify with it when acting as a client. */ - gnutls_x509_privkey_init(&x509_key); - if ((ret = gnutls_x509_privkey_import(x509_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) + gnutls_x509_privkey_init(&client_key); + if ((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_setup_ssl_server: Error loading key file: %s", gnutls_strerror(ret)); return 0; } - x509_cert_count = MAX_CERTS; - if ((ret = gnutls_x509_crt_list_import(x509_cert, &x509_cert_count, d_cert, GNUTLS_X509_FMT_PEM, + client_cert_count = MAX_CERTS; + if ((ret = gnutls_x509_crt_list_import(client_cert, &client_cert_count, d_cert, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) < 0) { rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", gnutls_strerror(ret)); return 0; } - x509_cert_count = ret; + client_cert_count = ret; if((ret = - gnutls_certificate_set_x509_key_mem(x509, d_cert, d_key, + gnutls_certificate_set_x509_key_mem(server_cert_key, d_cert, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { rb_lib_log("rb_setup_ssl_server: Error loading certificate or key file: %s", @@ -414,14 +422,14 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c if(dhfile != NULL) { - if(gnutls_dh_params_init(&dh_params) == GNUTLS_E_SUCCESS) + if(gnutls_dh_params_init(&server_dhp) == GNUTLS_E_SUCCESS) { gnutls_datum_t *data; int xret; data = rb_load_file_into_datum_t(dhfile); if(data != NULL) { - xret = gnutls_dh_params_import_pkcs3(dh_params, data, + xret = gnutls_dh_params_import_pkcs3(server_dhp, data, GNUTLS_X509_FMT_PEM); if(xret < 0) rb_lib_log @@ -429,7 +437,7 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c gnutls_strerror(xret)); rb_free_datum_t(data); } - gnutls_certificate_set_dh_params(x509, dh_params); + gnutls_certificate_set_dh_params(server_cert_key, server_dhp); } else rb_lib_log("rb_setup_ssl_server: Unable to setup DH parameters"); @@ -520,7 +528,7 @@ rb_ssl_tryconn(rb_fde_t *F, int status, void *data) F->ssl = rb_malloc(sizeof(gnutls_session_t)); gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); - gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, x509); + gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); gnutls_dh_set_prime_bits(SSL_P(F), 1024); gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); gnutls_priority_set(SSL_P(F), default_priority); @@ -563,7 +571,7 @@ rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); - gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, x509); + gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); gnutls_dh_set_prime_bits(SSL_P(F), 1024); gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); gnutls_priority_set(SSL_P(F), default_priority); From 75d7d47a7ec3e8e3f5868c927217570aabd35ac6 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:01:38 +0000 Subject: [PATCH 03/33] GNUTLS: Tidy up headers --- libratbox/src/gnutls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 5f806b5d..e84adc4e 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -20,14 +20,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * - * $Id: gnutls.c 26296 2008-12-13 03:36:00Z androsyn $ */ #include #include + +#ifdef HAVE_GNUTLS + #include #include -#ifdef HAVE_GNUTLS #include #include From fde101b9b2cb4dd147acb1e67f24e0e4ba63f4f1 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:09:56 +0000 Subject: [PATCH 04/33] GNUTLS: Tidy up the cert authentication callback --- libratbox/src/gnutls.c | 82 ++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index e84adc4e..90654069 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -39,14 +39,6 @@ # include #endif -#if GNUTLS_VERSION_MAJOR < 3 -static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs, - const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr_st *st); -#else -static int cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs, - const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr2_st *st); -#endif - #define SSL_P(x) *((gnutls_session_t *)F->ssl) @@ -66,6 +58,42 @@ static gnutls_priority_t default_priority; +/* + * We only have one certificate to authenticate with, as both a client and server. + * + * Unfortunately, GNUTLS tries to be clever, and as client, will attempt to use a certificate that the server will + * trust. We usually use self-signed certs, though, so the result of this search is always nothing. Therefore, it + * uses no certificate to authenticate as a client. This is undesirable, as it breaks fingerprint authentication; + * e.g. the connect::fingerprint on the remote ircd will not match. + * + * Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client. + */ + +static int +rb_ssl_cert_auth_cb(gnutls_session_t session, + const gnutls_datum_t *const req_ca_rdn, const int req_ca_rdn_len, + const gnutls_pk_algorithm_t *const sign_algos, const int sign_algos_len, +#if (GNUTLS_VERSION_MAJOR < 3) + gnutls_retr_st *const st) +#else + gnutls_retr2_st *const st) +#endif +{ +#if (GNUTLS_VERSION_MAJOR < 3) + st->type = GNUTLS_CRT_X509; +#else + st->cert_type = GNUTLS_CRT_X509; + st->key_type = GNUTLS_PRIVKEY_X509; +#endif + + st->ncerts = client_cert_count; + st->cert.x509 = client_cert; + st->key.x509 = client_key; + st->deinit_all = 0; + + return 0; +} + void rb_ssl_shutdown(rb_fde_t *const F) { @@ -291,9 +319,9 @@ rb_init_ssl(void) } #if GNUTLS_VERSION_MAJOR < 3 - gnutls_certificate_client_set_retrieve_function(server_cert_key, cert_callback); + gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); #else - gnutls_certificate_set_retrieve_function(server_cert_key, cert_callback); + gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); #endif #if (GNUTLS_VERSION_MAJOR < 3) @@ -303,38 +331,6 @@ rb_init_ssl(void) return 1; } -/* We only have one certificate to authenticate with, as both client and server. Unfortunately, - * GnuTLS tries to be clever, and as client, will attempt to use a certificate that the server - * will trust. We usually use self-signed certs, though, so the result of this search is always - * nothing. Therefore, it uses no certificate to authenticate as a client. This is undesirable - * as it breaks fingerprint auth. Thus, we use this callback to force GnuTLS to always - * authenticate with our certificate at all times. - */ -#if GNUTLS_VERSION_MAJOR < 3 -static int -cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs, - const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr_st *st) -#else -static int -cert_callback(gnutls_session_t session, const gnutls_datum_t *req_ca_rdn, int nreqs, - const gnutls_pk_algorithm_t *sign_algos, int sign_algos_len, gnutls_retr2_st *st) -#endif -{ - /* XXX - ugly hack. Tell GnuTLS to use the first (only) certificate we have for auth. */ -#if (GNUTLS_VERSION_MAJOR < 3) - st->type = GNUTLS_CRT_X509; -#else - st->cert_type = GNUTLS_CRT_X509; - st->key_type = GNUTLS_PRIVKEY_X509; -#endif - st->ncerts = client_cert_count; - st->cert.x509 = client_cert; - st->key.x509 = client_key; - st->deinit_all = 0; - - return 0; -} - static void rb_free_datum_t(gnutls_datum_t * d) { @@ -391,7 +387,7 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c } /* In addition to creating the certificate set, we also need to store our cert elsewhere - * so we can force GnuTLS to identify with it when acting as a client. + * so we can force GNUTLS to identify with it when acting as a client. */ gnutls_x509_privkey_init(&client_key); if ((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) From 6cc08ecf90f3374fd280ca22c585abf0a571933f Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:11:26 +0000 Subject: [PATCH 05/33] GNUTLS: Move `struct ssl_connect' definition to the top of the file --- libratbox/src/gnutls.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 90654069..9cde957b 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -58,6 +58,17 @@ static gnutls_priority_t default_priority; +struct ssl_connect +{ + CNCB *callback; + void *data; + int timeout; +}; + +static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *); + + + /* * We only have one certificate to authenticate with, as both a client and server. * @@ -462,13 +473,6 @@ rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) return result; } -struct ssl_connect -{ - CNCB *callback; - void *data; - int timeout; -}; - static void rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn) { From 992aa93b803ef09a405316c25e6c4ea59196cb45 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:15:38 +0000 Subject: [PATCH 06/33] GNUTLS: Tidy up rb_init_ssl() and improve its error logging --- libratbox/src/gnutls.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 9cde957b..7a306483 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -321,24 +321,26 @@ rb_gcry_random_seed(void *unused) int rb_init_ssl(void) { - gnutls_global_init(); + int ret; - if(gnutls_certificate_allocate_credentials(&server_cert_key) != GNUTLS_E_SUCCESS) + if ((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials"); + rb_lib_log("%s: gnutls_global_init: %s", __func__, gnutls_strerror(ret)); + return 0; + } + if((ret = gnutls_certificate_allocate_credentials(&server_cert_key)) != GNUTLS_E_SUCCESS) + { + rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, gnutls_strerror(ret)); return 0; } -#if GNUTLS_VERSION_MAJOR < 3 +#if (GNUTLS_VERSION_MAJOR < 3) + rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); #else gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); #endif -#if (GNUTLS_VERSION_MAJOR < 3) - rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); -#endif - return 1; } From 5103d939d0eebfb752dadfe9ad49cd3074893015 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:20:01 +0000 Subject: [PATCH 07/33] GNUTLS: Rename the timeout callback in line with the other backends --- libratbox/src/gnutls.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 7a306483..4202c3ec 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -138,9 +138,11 @@ rb_ssl_clear_handshake_count(rb_fde_t *F) } static void -rb_ssl_timeout(rb_fde_t *F, void *notused) +rb_ssl_timeout_cb(rb_fde_t *F, void *notused) { lrb_assert(F->accept != NULL); + lrb_assert(F->accept->callback != NULL); + F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); } @@ -206,7 +208,7 @@ rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) new_F->accept->callback = cb; new_F->accept->data = data; - rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); + rb_settimeout(new_F, timeout, rb_ssl_timeout_cb, NULL); new_F->accept->addrlen = 0; @@ -240,7 +242,7 @@ rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrl new_F->accept->callback = F->accept->callback; new_F->accept->data = F->accept->data; - rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); + rb_settimeout(new_F, 10, rb_ssl_timeout_cb, NULL); memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; From a41a1d20db008ddf58a3dc2eeec305f6253c4653 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:34:31 +0000 Subject: [PATCH 08/33] GNUTLS: Fix the SSL_P(x) macro It previously assumed there was an "F" variable in the scope it was used in. It now uses its input "x" variable. --- libratbox/src/gnutls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 4202c3ec..912330c1 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -39,7 +39,7 @@ # include #endif -#define SSL_P(x) *((gnutls_session_t *)F->ssl) +#define SSL_P(x) *((gnutls_session_t *) ((x)->ssl)) From 77119a50316a563f8ba791f160813aa9a6f61d10 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:35:09 +0000 Subject: [PATCH 09/33] GNUTLS: Improve the accept callback logic --- libratbox/src/gnutls.c | 108 +++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 64 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 912330c1..c25345da 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -172,20 +172,16 @@ do_ssl_handshake(rb_fde_t *F, PF * callback, void *data) } static void -rb_ssl_tryaccept(rb_fde_t *F, void *data) +rb_ssl_accept_common(rb_fde_t *F, void *data) { - int ret; - struct acceptdata *ad; - lrb_assert(F->accept != NULL); - ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL); + int ret = do_ssl_handshake(F, rb_ssl_accept_common, data); - /* do_ssl_handshake does the rb_setselect */ if(ret == 0) return; - ad = F->accept; + struct acceptdata *const ad = F->accept; F->accept = NULL; rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); @@ -199,68 +195,52 @@ rb_ssl_tryaccept(rb_fde_t *F, void *data) } void -rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) +rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout) { - gnutls_session_t *ssl; - new_F->type |= RB_FD_SSL; - ssl = new_F->ssl = rb_malloc(sizeof(gnutls_session_t)); - new_F->accept = rb_malloc(sizeof(struct acceptdata)); + F->type |= RB_FD_SSL; - new_F->accept->callback = cb; - new_F->accept->data = data; - rb_settimeout(new_F, timeout, rb_ssl_timeout_cb, NULL); + F->accept = rb_malloc(sizeof(struct acceptdata)); + F->accept->callback = cb; + F->accept->data = data; + F->accept->addrlen = 0; + (void) memset(&F->accept->S, 0x00, sizeof F->accept->S); - new_F->accept->addrlen = 0; - - gnutls_init(ssl, GNUTLS_SERVER); - gnutls_set_default_priority(*ssl); - gnutls_credentials_set(*ssl, GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(*ssl, 1024); - gnutls_transport_set_ptr(*ssl, (gnutls_transport_ptr_t) (long int)new_F->fd); - gnutls_certificate_server_set_request(*ssl, GNUTLS_CERT_REQUEST); - gnutls_priority_set(*ssl, default_priority); - - if(do_ssl_handshake(new_F, rb_ssl_tryaccept, NULL)) - { - struct acceptdata *ad = new_F->accept; - new_F->accept = NULL; - ad->callback(new_F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); - rb_free(ad); - } - -} - - - - -void -rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen) -{ - new_F->type |= RB_FD_SSL; - new_F->ssl = rb_malloc(sizeof(gnutls_session_t)); - new_F->accept = rb_malloc(sizeof(struct acceptdata)); - - new_F->accept->callback = F->accept->callback; - new_F->accept->data = F->accept->data; - rb_settimeout(new_F, 10, rb_ssl_timeout_cb, NULL); - memcpy(&new_F->accept->S, st, addrlen); - new_F->accept->addrlen = addrlen; - - gnutls_init((gnutls_session_t *) new_F->ssl, GNUTLS_SERVER); - gnutls_set_default_priority(SSL_P(new_F)); - gnutls_credentials_set(SSL_P(new_F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(new_F), 1024); - gnutls_transport_set_ptr(SSL_P(new_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(new_F)); - gnutls_certificate_server_set_request(SSL_P(new_F), GNUTLS_CERT_REQUEST); + F->ssl = rb_malloc(sizeof(gnutls_session_t)); + gnutls_init((gnutls_session_t *) F->ssl, GNUTLS_SERVER); + gnutls_set_default_priority(SSL_P(F)); + gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); + gnutls_dh_set_prime_bits(SSL_P(F), 1024); + gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)rb_get_fd(F)); + gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST); gnutls_priority_set(SSL_P(F), default_priority); - if(do_ssl_handshake(F, rb_ssl_tryaccept, NULL)) - { - struct acceptdata *ad = F->accept; - F->accept = NULL; - ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); - rb_free(ad); - } + rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL); + rb_ssl_accept_common(F, NULL); +} + +void +rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen) +{ + cli_F->type |= RB_FD_SSL; + + cli_F->accept = rb_malloc(sizeof(struct acceptdata)); + cli_F->accept->callback = srv_F->accept->callback; + cli_F->accept->data = srv_F->accept->data; + cli_F->accept->addrlen = (rb_socklen_t) addrlen; + (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S); + (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen); + + cli_F->ssl = rb_malloc(sizeof(gnutls_session_t)); + gnutls_init((gnutls_session_t *) cli_F->ssl, GNUTLS_SERVER); + gnutls_set_default_priority(SSL_P(cli_F)); + gnutls_credentials_set(SSL_P(cli_F), GNUTLS_CRD_CERTIFICATE, server_cert_key); + gnutls_dh_set_prime_bits(SSL_P(cli_F), 1024); + gnutls_transport_set_ptr(SSL_P(cli_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(cli_F)); + gnutls_certificate_server_set_request(SSL_P(cli_F), GNUTLS_CERT_REQUEST); + gnutls_priority_set(SSL_P(cli_F), default_priority); + + rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL); + rb_ssl_accept_common(cli_F, NULL); } From 4618ec248e56e943e127351d4e0308db6adb3c9b Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 12:54:52 +0000 Subject: [PATCH 10/33] GNUTLS: Improve the connect callback logic --- libratbox/src/gnutls.c | 65 +++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index c25345da..254b0b8d 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -458,48 +458,45 @@ rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) } static void -rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn) +rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *const sconn) { + lrb_assert(F != NULL); + lrb_assert(F->connect != NULL); + F->connect->callback = sconn->callback; F->connect->data = sconn->data; - rb_free(sconn); + rb_connect_callback(F, status); + rb_free(sconn); } static void -rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data) +rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) { rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); } static void -rb_ssl_tryconn_cb(rb_fde_t *F, void *data) +rb_ssl_connect_common(rb_fde_t *const F, void *const data) { - struct ssl_connect *sconn = data; - int ret; + int ret = do_ssl_handshake(F, rb_ssl_connect_common, data); - ret = do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); - - switch (ret) - { - case -1: - rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); - break; - case 0: - /* do_ssl_handshake does the rb_setselect stuff */ + if(ret == 0) return; - default: - break; + struct ssl_connect *const sconn = data; - } - rb_ssl_connect_realcb(F, RB_OK, sconn); + if(ret > 0) + rb_ssl_connect_realcb(F, RB_OK, sconn); + else + rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); } static void rb_ssl_tryconn(rb_fde_t *F, int status, void *data) { - struct ssl_connect *sconn = data; + struct ssl_connect *const sconn = data; + if(status != RB_OK) { rb_ssl_connect_realcb(F, status, sconn); @@ -508,8 +505,6 @@ rb_ssl_tryconn(rb_fde_t *F, int status, void *data) F->type |= RB_FD_SSL; - - rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); F->ssl = rb_malloc(sizeof(gnutls_session_t)); gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); @@ -518,42 +513,43 @@ rb_ssl_tryconn(rb_fde_t *F, int status, void *data) gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); gnutls_priority_set(SSL_P(F), default_priority); - do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); + rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); + rb_ssl_connect_common(F, sconn); } void -rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest, - struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout) +rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockaddr *const clocal, + const int socklen, CNCB *const callback, void *const data, const int timeout) { - struct ssl_connect *sconn; if(F == NULL) return; - sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *const sconn = rb_malloc(sizeof(struct ssl_connect)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; + rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout); - } void -rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) +rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data, const int timeout) { - struct ssl_connect *sconn; if(F == NULL) return; - sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *const sconn = rb_malloc(sizeof(struct ssl_connect)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; + F->connect = rb_malloc(sizeof(struct conndata)); F->connect->callback = callback; F->connect->data = data; - F->type |= RB_FD_SSL; - F->ssl = rb_malloc(sizeof(gnutls_session_t)); + F->type |= RB_FD_SSL; + + F->ssl = rb_malloc(sizeof(gnutls_session_t)); gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); @@ -562,8 +558,7 @@ rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) gnutls_priority_set(SSL_P(F), default_priority); rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); - - do_ssl_handshake(F, rb_ssl_tryconn_cb, (void *)sconn); + rb_ssl_connect_common(F, sconn); } int From 3f32d48dab630f900f54f18c3b9024ddeddce388 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 13:27:40 +0000 Subject: [PATCH 11/33] GNUTLS: Break off TLS setup from callbacks to a dedicated function This is in line with the other backends; eventually those callbacks will be moved to a library-agnostic section. --- libratbox/src/gnutls.c | 83 ++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 254b0b8d..55211b8b 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -41,6 +41,12 @@ #define SSL_P(x) *((gnutls_session_t *) ((x)->ssl)) +typedef enum +{ + RB_FD_TLS_DIRECTION_IN = 0, + RB_FD_TLS_DIRECTION_OUT = 1 +} rb_fd_tls_direction; + // Server side variables @@ -105,6 +111,40 @@ rb_ssl_cert_auth_cb(gnutls_session_t session, return 0; } +static void +rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) +{ + F->ssl = rb_malloc(sizeof(gnutls_session_t)); + + if(F->ssl == NULL) + { + rb_lib_log("%s: rb_malloc: allocation failure", __func__); + rb_close(F); + return; + } + + unsigned int init_flags = 0; + + switch(dir) + { + case RB_FD_TLS_DIRECTION_IN: + init_flags |= GNUTLS_SERVER; + break; + case RB_FD_TLS_DIRECTION_OUT: + init_flags |= GNUTLS_CLIENT; + break; + } + + gnutls_init((gnutls_session_t *) F->ssl, init_flags); + gnutls_set_default_priority(SSL_P(F)); + gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); + gnutls_dh_set_prime_bits(SSL_P(F), 1024); + gnutls_priority_set(SSL_P(F), default_priority); + + if(dir == RB_FD_TLS_DIRECTION_IN) + gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST); +} + void rb_ssl_shutdown(rb_fde_t *const F) { @@ -181,11 +221,12 @@ rb_ssl_accept_common(rb_fde_t *F, void *data) if(ret == 0) return; - struct acceptdata *const ad = F->accept; - F->accept = NULL; rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); + struct acceptdata *const ad = F->accept; + F->accept = NULL; + if(ret > 0) ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); else @@ -205,16 +246,8 @@ rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const F->accept->addrlen = 0; (void) memset(&F->accept->S, 0x00, sizeof F->accept->S); - F->ssl = rb_malloc(sizeof(gnutls_session_t)); - gnutls_init((gnutls_session_t *) F->ssl, GNUTLS_SERVER); - gnutls_set_default_priority(SSL_P(F)); - gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(F), 1024); - gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)rb_get_fd(F)); - gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST); - gnutls_priority_set(SSL_P(F), default_priority); - rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL); + rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN); rb_ssl_accept_common(F, NULL); } @@ -230,16 +263,8 @@ rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockadd (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S); (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen); - cli_F->ssl = rb_malloc(sizeof(gnutls_session_t)); - gnutls_init((gnutls_session_t *) cli_F->ssl, GNUTLS_SERVER); - gnutls_set_default_priority(SSL_P(cli_F)); - gnutls_credentials_set(SSL_P(cli_F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(cli_F), 1024); - gnutls_transport_set_ptr(SSL_P(cli_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(cli_F)); - gnutls_certificate_server_set_request(SSL_P(cli_F), GNUTLS_CERT_REQUEST); - gnutls_priority_set(SSL_P(cli_F), default_priority); - rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL); + rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN); rb_ssl_accept_common(cli_F, NULL); } @@ -505,15 +530,8 @@ rb_ssl_tryconn(rb_fde_t *F, int status, void *data) F->type |= RB_FD_SSL; - F->ssl = rb_malloc(sizeof(gnutls_session_t)); - gnutls_init(F->ssl, GNUTLS_CLIENT); - gnutls_set_default_priority(SSL_P(F)); - gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(F), 1024); - gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); - gnutls_priority_set(SSL_P(F), default_priority); - rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); + rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT); rb_ssl_connect_common(F, sconn); } @@ -549,15 +567,8 @@ rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data F->type |= RB_FD_SSL; - F->ssl = rb_malloc(sizeof(gnutls_session_t)); - gnutls_init(F->ssl, GNUTLS_CLIENT); - gnutls_set_default_priority(SSL_P(F)); - gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(F), 1024); - gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); - gnutls_priority_set(SSL_P(F), default_priority); - rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); + rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_OUT); rb_ssl_connect_common(F, sconn); } From 5797027e9f1610376eddd0f221fb20e11b89148a Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 13:32:30 +0000 Subject: [PATCH 12/33] GNUTLS: Add dedicated socket send/recv functions This avoids a compiler warning regarding casting a file descriptor to a pointer (as input to gnutls_transport_set_ptr()), and also ensures that the pointer is valid for the lifetime of the session. --- libratbox/src/gnutls.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 55211b8b..a2416f9f 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -73,6 +73,9 @@ struct ssl_connect static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *); +static ssize_t rb_sock_net_recv(gnutls_transport_ptr_t, void *, size_t); +static ssize_t rb_sock_net_xmit(gnutls_transport_ptr_t, const void *, size_t); + /* @@ -111,6 +114,22 @@ rb_ssl_cert_auth_cb(gnutls_session_t session, return 0; } +static ssize_t +rb_sock_net_recv(gnutls_transport_ptr_t context_ptr, void *const buf, const size_t count) +{ + const int fd = rb_get_fd((rb_fde_t *)context_ptr); + + return recv(fd, buf, count, 0); +} + +static ssize_t +rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr, const void *const buf, const size_t count) +{ + const int fd = rb_get_fd((rb_fde_t *)context_ptr); + + return send(fd, buf, count, 0); +} + static void rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) { @@ -141,6 +160,10 @@ rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) gnutls_dh_set_prime_bits(SSL_P(F), 1024); gnutls_priority_set(SSL_P(F), default_priority); + gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) F); + gnutls_transport_set_pull_function(SSL_P(F), rb_sock_net_recv); + gnutls_transport_set_push_function(SSL_P(F), rb_sock_net_xmit); + if(dir == RB_FD_TLS_DIRECTION_IN) gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST); } From 25ecd3cc86ff1638a6633bbbec8c910e59d1d79b Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 13:38:12 +0000 Subject: [PATCH 13/33] GNUTLS: Raise minimum group size for Diffie-Hellman-Merkle key exchange A 2048-bit long P should really be the minimum these days. --- libratbox/src/gnutls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index a2416f9f..c9250df7 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -157,7 +157,7 @@ rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) gnutls_init((gnutls_session_t *) F->ssl, init_flags); gnutls_set_default_priority(SSL_P(F)); gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, server_cert_key); - gnutls_dh_set_prime_bits(SSL_P(F), 1024); + gnutls_dh_set_prime_bits(SSL_P(F), 2048); gnutls_priority_set(SSL_P(F), default_priority); gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) F); From 4fc76590b9a398ab458e867ca2dd25f24cd76cae Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 17:52:50 +0000 Subject: [PATCH 14/33] GNUTLS: Rework datum loading code --- libratbox/src/gnutls.c | 65 +++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index c9250df7..35117937 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -375,33 +375,66 @@ rb_init_ssl(void) } static void -rb_free_datum_t(gnutls_datum_t * d) +rb_free_datum_t(gnutls_datum_t *const datum) { - rb_free(d->data); - rb_free(d); + if(datum == NULL) + return; + + rb_free(datum->data); + rb_free(datum); } static gnutls_datum_t * -rb_load_file_into_datum_t(const char *file) +rb_load_file_into_datum_t(const char *const file) { - FILE *f; - gnutls_datum_t *datum; + const int datum_fd = open(file, O_RDONLY); + if(datum_fd < 0) + return NULL; + struct stat fileinfo; - if((f = fopen(file, "r")) == NULL) + if(fstat(datum_fd, &fileinfo) != 0) + { + (void) close(datum_fd); return NULL; - if(fstat(fileno(f), &fileinfo)) + } + + const size_t datum_size = (fileinfo.st_size < 131072) ? (size_t) fileinfo.st_size : 131072; + if(datum_size == 0) + { + (void) close(datum_fd); return NULL; + } - datum = rb_malloc(sizeof(gnutls_datum_t)); + gnutls_datum_t *datum; + if((datum = rb_malloc(sizeof *datum)) == NULL) + { + (void) close(datum_fd); + return NULL; + } + if((datum->data = rb_malloc(datum_size + 1)) == NULL) + { + rb_free(datum); + (void) close(datum_fd); + return NULL; + } - if(fileinfo.st_size > 131072) /* deal with retards */ - datum->size = 131072; - else - datum->size = fileinfo.st_size; + for(size_t data_read = 0; data_read < datum_size; ) + { + ssize_t ret = read(datum_fd, ((unsigned char *)datum->data) + data_read, datum_size - data_read); - datum->data = rb_malloc(datum->size + 1); - fread(datum->data, datum->size, 1, f); - fclose(f); + if(ret <= 0) + { + rb_free_datum_t(datum); + (void) close(datum_fd); + return NULL; + } + + data_read += (size_t) ret; + } + (void) close(datum_fd); + + datum->data[datum_size] = '\0'; + datum->size = (unsigned int) datum_size; return datum; } From 2d01971d0514e93203941072d3f3b0b873f0db9d Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 17:59:44 +0000 Subject: [PATCH 15/33] GNUTLS: Send do_ssl_handshake() to the depths from whence it came --- libratbox/src/gnutls.c | 57 ++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 35117937..f7d34c65 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -209,48 +209,29 @@ rb_ssl_timeout_cb(rb_fde_t *F, void *notused) F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); } - -static int -do_ssl_handshake(rb_fde_t *F, PF * callback, void *data) -{ - int ret; - int flags; - - ret = gnutls_handshake(SSL_P(F)); - if(ret < 0) - { - if((ret == GNUTLS_E_INTERRUPTED && rb_ignore_errno(errno)) || ret == GNUTLS_E_AGAIN) - { - if(gnutls_record_get_direction(SSL_P(F)) == 0) - flags = RB_SELECT_READ; - else - flags = RB_SELECT_WRITE; - rb_setselect(F, flags, callback, data); - return 0; - } - F->ssl_errno = ret; - return -1; - } - return 1; /* handshake is finished..go about life */ -} - static void rb_ssl_accept_common(rb_fde_t *F, void *data) { lrb_assert(F->accept != NULL); + lrb_assert(F->accept->callback != NULL); - int ret = do_ssl_handshake(F, rb_ssl_accept_common, data); + errno = 0; - if(ret == 0) + int ret = gnutls_handshake(SSL_P(F)); + + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno)))) + { + unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; + rb_setselect(F, flags, rb_ssl_accept_common, data); return; - - rb_settimeout(F, 0, NULL, NULL); - rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); + } struct acceptdata *const ad = F->accept; - F->accept = NULL; - if(ret > 0) + F->accept = NULL; + F->ssl_errno = (unsigned long) -ret; + + if(ret == GNUTLS_E_SUCCESS) ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); else ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data); @@ -560,14 +541,20 @@ rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) static void rb_ssl_connect_common(rb_fde_t *const F, void *const data) { - int ret = do_ssl_handshake(F, rb_ssl_connect_common, data); + errno = 0; - if(ret == 0) + int ret = gnutls_handshake(SSL_P(F)); + + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno)))) + { + unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; + rb_setselect(F, flags, rb_ssl_connect_common, data); return; + } struct ssl_connect *const sconn = data; - if(ret > 0) + if(ret == GNUTLS_E_SUCCESS) rb_ssl_connect_realcb(F, RB_OK, sconn); else rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); From d70129a0d65fcbe767fa7633b37e022adbd86e95 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 20:28:16 +0000 Subject: [PATCH 16/33] GNUTLS: Rework rb_init_ssl() and rb_setup_ssl_server() I did my best to remove all possible memory leaks in the latter. It's ugly. --- libratbox/src/gnutls.c | 167 ++++++++++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 61 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index f7d34c65..bb0f8b02 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -339,17 +339,9 @@ rb_init_ssl(void) rb_lib_log("%s: gnutls_global_init: %s", __func__, gnutls_strerror(ret)); return 0; } - if((ret = gnutls_certificate_allocate_credentials(&server_cert_key)) != GNUTLS_E_SUCCESS) - { - rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, gnutls_strerror(ret)); - return 0; - } #if (GNUTLS_VERSION_MAJOR < 3) rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); - gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); -#else - gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); #endif return 1; @@ -420,54 +412,89 @@ rb_load_file_into_datum_t(const char *const file) } int -rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list) +rb_setup_ssl_server(const char *const certfile, const char *keyfile, + const char *const dhfile, const char *const cipherlist) { + if(certfile == NULL) + { + rb_lib_log("%s: no certificate file specified", __func__); + return 0; + } + + if(keyfile == NULL) + keyfile = certfile; + + + gnutls_datum_t *const d_cert = rb_load_file_into_datum_t(certfile); + if(d_cert == NULL) + { + rb_lib_log("%s: Error loading certificate: %s", __func__, strerror(errno)); + return 0; + } + + gnutls_datum_t *const d_key = rb_load_file_into_datum_t(keyfile); + if(d_key == NULL) + { + rb_lib_log("%s: Error loading key: %s", __func__, strerror(errno)); + rb_free_datum_t(d_cert); + return 0; + } + int ret; - const char *err; - gnutls_datum_t *d_cert, *d_key; - if(cert == NULL) + + if((ret = gnutls_certificate_allocate_credentials(&server_cert_key)) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_setup_ssl_server: No certificate file"); + rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, gnutls_strerror(ret)); + rb_free_datum_t(d_cert); + rb_free_datum_t(d_key); return 0; } - if((d_cert = rb_load_file_into_datum_t(cert)) == NULL) +#if (GNUTLS_VERSION_MAJOR < 3) + gnutls_certificate_client_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); +#else + gnutls_certificate_set_retrieve_function(server_cert_key, rb_ssl_cert_auth_cb); +#endif + + if((ret = gnutls_certificate_set_x509_key_mem(server_cert_key, d_cert, d_key, + GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", strerror(errno)); + rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + rb_free_datum_t(d_cert); + rb_free_datum_t(d_key); return 0; } - - if((d_key = rb_load_file_into_datum_t(keyfile)) == NULL) + if((ret = gnutls_x509_crt_list_import(client_cert, &client_cert_count, d_cert, GNUTLS_X509_FMT_PEM, + GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) < 1) { - rb_lib_log("rb_setup_ssl_server: Error loading key: %s", strerror(errno)); + rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + rb_free_datum_t(d_cert); + rb_free_datum_t(d_key); return 0; } + client_cert_count = (unsigned int) ret; - /* In addition to creating the certificate set, we also need to store our cert elsewhere - * so we can force GNUTLS to identify with it when acting as a client. - */ - gnutls_x509_privkey_init(&client_key); - if ((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) + if((ret = gnutls_x509_privkey_init(&client_key)) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_setup_ssl_server: Error loading key file: %s", gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + for(unsigned int i = 0; i < client_cert_count; i++) + gnutls_x509_crt_deinit(client_cert[i]); + rb_free_datum_t(d_cert); + rb_free_datum_t(d_key); return 0; } - - client_cert_count = MAX_CERTS; - if ((ret = gnutls_x509_crt_list_import(client_cert, &client_cert_count, d_cert, GNUTLS_X509_FMT_PEM, - GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) < 0) + if((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", gnutls_strerror(ret)); - return 0; - } - client_cert_count = ret; - - if((ret = - gnutls_certificate_set_x509_key_mem(server_cert_key, d_cert, d_key, - GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) - { - rb_lib_log("rb_setup_ssl_server: Error loading certificate or key file: %s", - gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + for(unsigned int i = 0; i < client_cert_count; i++) + gnutls_x509_crt_deinit(client_cert[i]); + gnutls_x509_privkey_deinit(client_key); + rb_free_datum_t(d_cert); + rb_free_datum_t(d_key); return 0; } @@ -476,35 +503,53 @@ rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, c if(dhfile != NULL) { - if(gnutls_dh_params_init(&server_dhp) == GNUTLS_E_SUCCESS) + gnutls_datum_t *const d_dhp = rb_load_file_into_datum_t(dhfile); + + if(d_dhp == NULL) { - gnutls_datum_t *data; - int xret; - data = rb_load_file_into_datum_t(dhfile); - if(data != NULL) - { - xret = gnutls_dh_params_import_pkcs3(server_dhp, data, - GNUTLS_X509_FMT_PEM); - if(xret < 0) - rb_lib_log - ("rb_setup_ssl_server: Error parsing DH file: %s\n", - gnutls_strerror(xret)); - rb_free_datum_t(data); - } - gnutls_certificate_set_dh_params(server_cert_key, server_dhp); + rb_lib_log("%s: Error parsing DH parameters: %s", __func__, strerror(errno)); + gnutls_certificate_free_credentials(server_cert_key); + for(unsigned int i = 0; i < client_cert_count; i++) + gnutls_x509_crt_deinit(client_cert[i]); + gnutls_x509_privkey_deinit(client_key); + return 0; } - else - rb_lib_log("rb_setup_ssl_server: Unable to setup DH parameters"); + if((ret = gnutls_dh_params_init(&server_dhp)) != GNUTLS_E_SUCCESS) + { + rb_lib_log("%s: Error parsing DH parameters: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + for(unsigned int i = 0; i < client_cert_count; i++) + gnutls_x509_crt_deinit(client_cert[i]); + gnutls_x509_privkey_deinit(client_key); + rb_free_datum_t(d_dhp); + return 0; + } + if((ret = gnutls_dh_params_import_pkcs3(server_dhp, d_dhp, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) + { + rb_lib_log("%s: Error parsing DH parameters: %s", __func__, gnutls_strerror(ret)); + gnutls_certificate_free_credentials(server_cert_key); + for(unsigned int i = 0; i < client_cert_count; i++) + gnutls_x509_crt_deinit(client_cert[i]); + gnutls_x509_privkey_deinit(client_key); + gnutls_dh_params_deinit(server_dhp); + rb_free_datum_t(d_dhp); + return 0; + } + + gnutls_certificate_set_dh_params(server_cert_key, server_dhp); + rb_free_datum_t(d_dhp); } - ret = gnutls_priority_init(&default_priority, cipher_list, &err); - if (ret < 0) + const char *err = NULL; + if((ret = gnutls_priority_init(&default_priority, cipherlist, &err)) != GNUTLS_E_SUCCESS) { - rb_lib_log("rb_setup_ssl_server: syntax error (using defaults instead) in ssl cipher list at: %s", err); - gnutls_priority_init(&default_priority, NULL, &err); - return 1; + rb_lib_log("%s: gnutls_priority_init: %s, error begins at '%s'? -- using defaults instead", + __func__, gnutls_strerror(ret), err ? err : ""); + + (void) gnutls_priority_init(&default_priority, NULL, &err); } + rb_lib_log("%s: TLS configuration successful", __func__); return 1; } From c6600fe29060d6f5d73357aec6757c81e4732558 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 20:38:41 +0000 Subject: [PATCH 17/33] GNUTLS: Add rb_ssl_strerror() function in line with other backends --- libratbox/src/gnutls.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index bb0f8b02..c15f7bf3 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -71,6 +71,7 @@ struct ssl_connect int timeout; }; +static const char *rb_ssl_strerror(int); static void rb_ssl_connect_realcb(rb_fde_t *, int, struct ssl_connect *); static ssize_t rb_sock_net_recv(gnutls_transport_ptr_t, void *, size_t); @@ -114,6 +115,12 @@ rb_ssl_cert_auth_cb(gnutls_session_t session, return 0; } +static const char * +rb_ssl_strerror(int err) +{ + return gnutls_strerror(err); +} + static ssize_t rb_sock_net_recv(gnutls_transport_ptr_t context_ptr, void *const buf, const size_t count) { @@ -336,7 +343,7 @@ rb_init_ssl(void) if ((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: gnutls_global_init: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_global_init: %s", __func__, rb_ssl_strerror(ret)); return 0; } @@ -444,7 +451,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, if((ret = gnutls_certificate_allocate_credentials(&server_cert_key)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_certificate_allocate_credentials: %s", __func__, rb_ssl_strerror(ret)); rb_free_datum_t(d_cert); rb_free_datum_t(d_key); return 0; @@ -459,7 +466,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, if((ret = gnutls_certificate_set_x509_key_mem(server_cert_key, d_cert, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_certificate_set_x509_key_mem: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); rb_free_datum_t(d_cert); rb_free_datum_t(d_key); @@ -468,7 +475,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, if((ret = gnutls_x509_crt_list_import(client_cert, &client_cert_count, d_cert, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED)) < 1) { - rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_x509_crt_list_import: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); rb_free_datum_t(d_cert); rb_free_datum_t(d_key); @@ -478,7 +485,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, if((ret = gnutls_x509_privkey_init(&client_key)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_x509_privkey_init: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); for(unsigned int i = 0; i < client_cert_count; i++) gnutls_x509_crt_deinit(client_cert[i]); @@ -488,7 +495,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, } if((ret = gnutls_x509_privkey_import(client_key, d_key, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: gnutls_x509_privkey_import: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); for(unsigned int i = 0; i < client_cert_count; i++) gnutls_x509_crt_deinit(client_cert[i]); @@ -516,7 +523,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, } if((ret = gnutls_dh_params_init(&server_dhp)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: Error parsing DH parameters: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: Error parsing DH parameters: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); for(unsigned int i = 0; i < client_cert_count; i++) gnutls_x509_crt_deinit(client_cert[i]); @@ -526,7 +533,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, } if((ret = gnutls_dh_params_import_pkcs3(server_dhp, d_dhp, GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS) { - rb_lib_log("%s: Error parsing DH parameters: %s", __func__, gnutls_strerror(ret)); + rb_lib_log("%s: Error parsing DH parameters: %s", __func__, rb_ssl_strerror(ret)); gnutls_certificate_free_credentials(server_cert_key); for(unsigned int i = 0; i < client_cert_count; i++) gnutls_x509_crt_deinit(client_cert[i]); @@ -544,7 +551,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, if((ret = gnutls_priority_init(&default_priority, cipherlist, &err)) != GNUTLS_E_SUCCESS) { rb_lib_log("%s: gnutls_priority_init: %s, error begins at '%s'? -- using defaults instead", - __func__, gnutls_strerror(ret), err ? err : ""); + __func__, rb_ssl_strerror(ret), err ? err : ""); (void) gnutls_priority_init(&default_priority, NULL, &err); } @@ -683,7 +690,7 @@ rb_get_random(void *buf, size_t length) const char * rb_get_ssl_strerror(rb_fde_t *F) { - return gnutls_strerror(F->ssl_errno); + return rb_ssl_strerror(F->ssl_errno); } int From 8099d352c9004e137f0949184b2fc53587915717 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 20:40:23 +0000 Subject: [PATCH 18/33] GNUTLS: Store error codes properly This is similar to commit db12df5c16758487e0c88d43cd77926b784fe400 for the MbedTLS backend. The difference is, GNUTLS will not accept positive values as input to gnutls_strerror(), so we invert the sign bit after retrieving the value too, not just when storing it. Also add a forgotten ssl_errno assignment to rb_ssl_connect_common(). --- libratbox/src/gnutls.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index c15f7bf3..365c9b72 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -308,7 +308,7 @@ rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size break; } default: - F->ssl_errno = ret; + F->ssl_errno = (unsigned long) -ret; errno = EIO; return RB_RW_IO_ERROR; } @@ -606,6 +606,8 @@ rb_ssl_connect_common(rb_fde_t *const F, void *const data) struct ssl_connect *const sconn = data; + F->ssl_errno = (unsigned long) -ret; + if(ret == GNUTLS_E_SUCCESS) rb_ssl_connect_realcb(F, RB_OK, sconn); else @@ -690,7 +692,8 @@ rb_get_random(void *buf, size_t length) const char * rb_get_ssl_strerror(rb_fde_t *F) { - return rb_ssl_strerror(F->ssl_errno); + int err = (int) F->ssl_errno; + return rb_ssl_strerror(-err); } int From 8ebebff4b47a2d4fb08d94a51aefff85d7b94973 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 21:45:19 +0000 Subject: [PATCH 19/33] GNUTLS: Improve rb_ssl_accept_common() * Add more debugging assertions * Cancel timeouts and callbacks when handshake succeeds or hard fails * Differentiate between kernel and library errors * Increase F->handshake_count on handshake success I'm still not exactly sure what this is even used for. It may be removed from all backends at a later time if I find it's not being used for anything important, as right now it can only have the values 0 or 1. --- libratbox/src/gnutls.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 365c9b72..f197e206 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -219,29 +219,46 @@ rb_ssl_timeout_cb(rb_fde_t *F, void *notused) static void rb_ssl_accept_common(rb_fde_t *F, void *data) { + lrb_assert(F != NULL); lrb_assert(F->accept != NULL); lrb_assert(F->accept->callback != NULL); + lrb_assert(F->ssl != NULL); errno = 0; int ret = gnutls_handshake(SSL_P(F)); + int err = errno; - if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno)))) + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) { unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; rb_setselect(F, flags, rb_ssl_accept_common, data); return; } - struct acceptdata *const ad = F->accept; + // These 2 calls may affect errno, which is why we save it above and restore it below + rb_settimeout(F, 0, NULL, NULL); + rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); + struct acceptdata *const ad = F->accept; F->accept = NULL; - F->ssl_errno = (unsigned long) -ret; if(ret == GNUTLS_E_SUCCESS) + { + F->handshake_count++; ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); + } + else if(err != 0) + { + errno = err; + ad->callback(F, RB_ERROR, NULL, 0, ad->data); + } else + { + errno = EIO; + F->ssl_errno = (unsigned long) -ret; ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data); + } rb_free(ad); } From 4369f1fa55517d676baa2cede28b96561fe6911d Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 21:52:06 +0000 Subject: [PATCH 20/33] GNUTLS: Improve rb_ssl_connect_common() This is the same as the previous commit for rb_ssl_accept_common(). --- libratbox/src/gnutls.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index f197e206..95f3a7bb 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -610,25 +610,43 @@ rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) static void rb_ssl_connect_common(rb_fde_t *const F, void *const data) { + lrb_assert(F != NULL); + lrb_assert(F->ssl != NULL); + errno = 0; int ret = gnutls_handshake(SSL_P(F)); + int err = errno; - if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno)))) + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) { unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; rb_setselect(F, flags, rb_ssl_connect_common, data); return; } + // These 2 calls may affect errno, which is why we save it above and restore it below + rb_settimeout(F, 0, NULL, NULL); + rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); + struct ssl_connect *const sconn = data; - F->ssl_errno = (unsigned long) -ret; - if(ret == GNUTLS_E_SUCCESS) + { + F->handshake_count++; rb_ssl_connect_realcb(F, RB_OK, sconn); + } + else if(err != 0) + { + errno = err; + rb_ssl_connect_realcb(F, RB_ERROR, sconn); + } else + { + errno = EIO; + F->ssl_errno = (unsigned long) -ret; rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); + } } static void From f4726edf7aaef857b937d2e7be80dcbaf225affb Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 21:53:35 +0000 Subject: [PATCH 21/33] GNUTLS: Fix up rb_ssl_listen() Declare and assign variables at the same time; give function parameters const correctness. --- libratbox/src/gnutls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 95f3a7bb..eb4cdaac 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -578,11 +578,10 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, } int -rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) +rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept) { - int result; + int result = rb_listen(F, backlog, defer_accept); - result = rb_listen(F, backlog, defer_accept); F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; return result; From 2b5bf0bada1b51fa4c05248bc69eff12ace0aa09 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 21:54:53 +0000 Subject: [PATCH 22/33] GNUTLS: Improve rb_connect_tcp_ssl() and rb_ssl_start_connected() Use the variable name instead of its type as an argument to a sizeof allocation. This will prevent possible future errors being introduced when the type of the variable is changed, but the sizeof argument is not updated. --- libratbox/src/gnutls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index eb4cdaac..74bce812 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -673,7 +673,7 @@ rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockad if(F == NULL) return; - struct ssl_connect *const sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *const sconn = rb_malloc(sizeof *sconn); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; @@ -687,7 +687,7 @@ rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data if(F == NULL) return; - struct ssl_connect *const sconn = rb_malloc(sizeof(struct ssl_connect)); + struct ssl_connect *const sconn = rb_malloc(sizeof *sconn); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; From 9986455edcaff2663e60ef5471331dfd3f5d25c0 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 21:57:06 +0000 Subject: [PATCH 23/33] GNUTLS: Log PRNG initialisation --- libratbox/src/gnutls.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 74bce812..7753dc1d 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -708,6 +708,9 @@ rb_init_prng(const char *path, prng_seed_t seed_type) { #if GNUTLS_VERSION_MAJOR < 3 gcry_fast_random_poll(); + rb_lib_log("%s: PRNG initialised", __func__); +#else + rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__); #endif return 1; } From 67d31a2755c2aa8587d96a082aab52e5bcd88d81 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:04:12 +0000 Subject: [PATCH 24/33] GNUTLS: Improve rb_get_ssl_certfp() * Give function parameters const correctness. * Use similar variable names as the other backends -- this will reduce the diff between them. * Check for more kinds of errors in retrieving the peer's certificate. * Log failure to generate fingerprints, like the MbedTLS backend does. --- libratbox/src/gnutls.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 7753dc1d..c635c906 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -734,24 +734,20 @@ rb_get_ssl_strerror(rb_fde_t *F) } int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) +rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) { - gnutls_x509_crt_t cert; - gnutls_digest_algorithm_t algo; - unsigned int cert_list_size = 0; - const gnutls_datum_t *cert_list; - size_t digest_size; + gnutls_digest_algorithm_t md_type; switch(method) { case RB_SSL_CERTFP_METH_SHA1: - algo = GNUTLS_DIG_SHA1; + md_type = GNUTLS_DIG_SHA1; break; case RB_SSL_CERTFP_METH_SHA256: - algo = GNUTLS_DIG_SHA256; + md_type = GNUTLS_DIG_SHA256; break; case RB_SSL_CERTFP_METH_SHA512: - algo = GNUTLS_DIG_SHA512; + md_type = GNUTLS_DIG_SHA512; break; default: return 0; @@ -760,29 +756,33 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) return 0; - cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); - - if (cert_list_size <= 0) + unsigned int cert_list_size = 0; + const gnutls_datum_t *const cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); + if (cert_list == NULL || cert_list_size <= 0) return 0; - if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) + gnutls_x509_crt_t peer_cert; + if (gnutls_x509_crt_init(&peer_cert) != GNUTLS_E_SUCCESS) return 0; - if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) + if (gnutls_x509_crt_import(peer_cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) { - gnutls_x509_crt_deinit(cert); + gnutls_x509_crt_deinit(peer_cert); return 0; } - if (gnutls_x509_crt_get_fingerprint(cert, algo, certfp, &digest_size) != 0) + int ret; + size_t hashlen; + if ((ret = gnutls_x509_crt_get_fingerprint(peer_cert, md_type, certfp, &hashlen)) != 0) { - gnutls_x509_crt_deinit(cert); + rb_lib_log("%s: gnutls_x509_crt_get_fingerprint: %s", __func__, rb_ssl_strerror(ret)); + gnutls_x509_crt_deinit(peer_cert); return 0; } - gnutls_x509_crt_deinit(cert); + gnutls_x509_crt_deinit(peer_cert); - return (int) digest_size; + return (int) hashlen; } int From dd59642de18ab588720d9b6e9dfc5db4626efe55 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:08:10 +0000 Subject: [PATCH 25/33] GNUTLS: Improve rb_get_ssl_info() Explicitly ignore the snprintf return value and properly indent the following line. Also add a 'v' before the version strings so it reads as e.g.: library (v3.3.8), compiled (v3.3.8) --- libratbox/src/gnutls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index c635c906..8065b998 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -794,8 +794,8 @@ rb_supports_ssl(void) void rb_get_ssl_info(char *buf, size_t len) { - rb_snprintf(buf, len, "GNUTLS: compiled (%s), library (%s)", - LIBGNUTLS_VERSION, gnutls_check_version(NULL)); + (void) rb_snprintf(buf, len, "GNUTLS: compiled (v%s), library (v%s)", + LIBGNUTLS_VERSION, gnutls_check_version(NULL)); } const char * From 9c7dda22e8d8b05020c3ed04fa55d9e4aeaa6853 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:09:49 +0000 Subject: [PATCH 26/33] GNUTLS: Improve rb_ssl_get_cipher() * Add debugging assertions. * Reduce the buffer size in line with the other backends. * Ask for the cipher name directly instead of constructing it ourselves from the key exchange / authentication algorithm, symmetric encryption algorithm, and message authentication code algorithm. --- libratbox/src/gnutls.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 8065b998..3a695aea 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -799,30 +799,20 @@ rb_get_ssl_info(char *buf, size_t len) } const char * -rb_ssl_get_cipher(rb_fde_t *F) +rb_ssl_get_cipher(rb_fde_t *const F) { - static char buf[1024]; + if(F == NULL || F->ssl == NULL) + return NULL; - const char* proto_name = - gnutls_protocol_get_name(gnutls_protocol_get_version(SSL_P(F))); + static char buf[512]; - const char* kex_alg_name = - gnutls_kx_get_name(gnutls_kx_get(SSL_P(F))); + gnutls_protocol_t version_ptr = gnutls_protocol_get_version(SSL_P(F)); + gnutls_cipher_algorithm_t cipher_ptr = gnutls_cipher_get(SSL_P(F)); - const char* cipher_alg_name = - gnutls_cipher_get_name(gnutls_cipher_get(SSL_P(F))); + const char *const version = gnutls_protocol_get_name(version_ptr); + const char *const cipher = gnutls_cipher_get_name(cipher_ptr); - const char* mac_alg_name = - gnutls_mac_get_name(gnutls_mac_get(SSL_P(F))); - - (void) rb_snprintf(buf, sizeof buf, "%s%s%s%s%s%s%s", - proto_name ? proto_name : "", - proto_name ? ", " : "", - kex_alg_name ? kex_alg_name : "", - kex_alg_name ? "-" : "", - cipher_alg_name ? cipher_alg_name : "", - cipher_alg_name ? "-" : "", - mac_alg_name ? mac_alg_name : ""); + (void) rb_snprintf(buf, sizeof buf, "%s, %s", version, cipher); return buf; } From 939d7ec7fe985ac85646d9fe080596dfa6511e0b Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:17:13 +0000 Subject: [PATCH 27/33] GNUTLS: Apply whole-file const correctness --- libratbox/src/gnutls.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 3a695aea..b9c54b21 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -116,7 +116,7 @@ rb_ssl_cert_auth_cb(gnutls_session_t session, } static const char * -rb_ssl_strerror(int err) +rb_ssl_strerror(const int err) { return gnutls_strerror(err); } @@ -196,19 +196,19 @@ rb_ssl_shutdown(rb_fde_t *const F) } unsigned int -rb_ssl_handshake_count(rb_fde_t *F) +rb_ssl_handshake_count(rb_fde_t *const F) { return F->handshake_count; } void -rb_ssl_clear_handshake_count(rb_fde_t *F) +rb_ssl_clear_handshake_count(rb_fde_t *const F) { F->handshake_count = 0; } static void -rb_ssl_timeout_cb(rb_fde_t *F, void *notused) +rb_ssl_timeout_cb(rb_fde_t *const F, void *const notused) { lrb_assert(F->accept != NULL); lrb_assert(F->accept->callback != NULL); @@ -217,7 +217,7 @@ rb_ssl_timeout_cb(rb_fde_t *F, void *notused) } static void -rb_ssl_accept_common(rb_fde_t *F, void *data) +rb_ssl_accept_common(rb_fde_t *const F, void *const data) { lrb_assert(F != NULL); lrb_assert(F->accept != NULL); @@ -226,8 +226,8 @@ rb_ssl_accept_common(rb_fde_t *F, void *data) errno = 0; - int ret = gnutls_handshake(SSL_P(F)); - int err = errno; + const int ret = gnutls_handshake(SSL_P(F)); + const int err = errno; if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) { @@ -300,10 +300,10 @@ rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockadd static ssize_t -rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) +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) { ssize_t ret; - gnutls_session_t *ssl = F->ssl; + gnutls_session_t *const ssl = F->ssl; if(r_or_w == 0) ret = gnutls_record_recv(*ssl, rbuf, count); @@ -334,20 +334,20 @@ rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size } ssize_t -rb_ssl_read(rb_fde_t *F, void *buf, size_t count) +rb_ssl_read(rb_fde_t *const F, void *const buf, const size_t count) { return rb_ssl_read_or_write(0, F, buf, NULL, count); } ssize_t -rb_ssl_write(rb_fde_t *F, const void *buf, size_t count) +rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count) { return rb_ssl_read_or_write(1, F, NULL, buf, count); } #if (GNUTLS_VERSION_MAJOR < 3) static void -rb_gcry_random_seed(void *unused) +rb_gcry_random_seed(void *const unused) { gcry_fast_random_poll(); } @@ -614,8 +614,8 @@ rb_ssl_connect_common(rb_fde_t *const F, void *const data) errno = 0; - int ret = gnutls_handshake(SSL_P(F)); - int err = errno; + const int ret = gnutls_handshake(SSL_P(F)); + const int err = errno; if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) { @@ -649,7 +649,7 @@ rb_ssl_connect_common(rb_fde_t *const F, void *const data) } static void -rb_ssl_tryconn(rb_fde_t *F, int status, void *data) +rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data) { struct ssl_connect *const sconn = data; @@ -704,7 +704,7 @@ rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data } int -rb_init_prng(const char *path, prng_seed_t seed_type) +rb_init_prng(const char *const path, prng_seed_t seed_type) { #if GNUTLS_VERSION_MAJOR < 3 gcry_fast_random_poll(); @@ -716,7 +716,7 @@ rb_init_prng(const char *path, prng_seed_t seed_type) } int -rb_get_random(void *buf, size_t length) +rb_get_random(void *const buf, const size_t length) { #if GNUTLS_VERSION_MAJOR < 3 gcry_randomize(buf, length, GCRY_STRONG_RANDOM); @@ -727,9 +727,9 @@ rb_get_random(void *buf, size_t length) } const char * -rb_get_ssl_strerror(rb_fde_t *F) +rb_get_ssl_strerror(rb_fde_t *const F) { - int err = (int) F->ssl_errno; + const int err = (int) F->ssl_errno; return rb_ssl_strerror(-err); } @@ -792,7 +792,7 @@ rb_supports_ssl(void) } void -rb_get_ssl_info(char *buf, size_t len) +rb_get_ssl_info(char *const buf, const size_t len) { (void) rb_snprintf(buf, len, "GNUTLS: compiled (v%s), library (v%s)", LIBGNUTLS_VERSION, gnutls_check_version(NULL)); From d4e71871c085c93349bdfc2cca7459c580bc2341 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:17:56 +0000 Subject: [PATCH 28/33] GNUTLS: rb_ssl_read_or_write(): Use macro to refer to session context --- libratbox/src/gnutls.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index b9c54b21..3a60860c 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -303,12 +303,11 @@ static ssize_t 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) { ssize_t ret; - gnutls_session_t *const ssl = F->ssl; if(r_or_w == 0) - ret = gnutls_record_recv(*ssl, rbuf, count); + ret = gnutls_record_recv(SSL_P(F), rbuf, count); else - ret = gnutls_record_send(*ssl, wbuf, count); + ret = gnutls_record_send(SSL_P(F), wbuf, count); if(ret < 0) { From 0071c423d557de7a97f76044c3570877d4793720 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:26:52 +0000 Subject: [PATCH 29/33] GNUTLS: Improve rb_ssl_read_or_write() * Set errno to 0 before attempting any read/write operations as it may affect our tests otherwise. * Properly check whether the gnutls_record_recv()/gnutls_record_send() call failed and distinguish between kernel and library errors. --- libratbox/src/gnutls.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 3a60860c..ebe11f31 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -304,32 +304,30 @@ rb_ssl_read_or_write(const int r_or_w, rb_fde_t *const F, void *const rbuf, cons { ssize_t ret; + errno = 0; + if(r_or_w == 0) ret = gnutls_record_recv(SSL_P(F), rbuf, count); else ret = gnutls_record_send(SSL_P(F), wbuf, count); - if(ret < 0) + if(ret >= 0) + return ret; + + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (errno == 0 || rb_ignore_errno(errno)))) { - switch (ret) - { - case GNUTLS_E_AGAIN: - case GNUTLS_E_INTERRUPTED: - if(rb_ignore_errno(errno)) - { - if(gnutls_record_get_direction(*ssl) == 0) - return RB_RW_SSL_NEED_READ; - else - return RB_RW_SSL_NEED_WRITE; - break; - } - default: - F->ssl_errno = (unsigned long) -ret; - errno = EIO; - return RB_RW_IO_ERROR; - } + if(gnutls_record_get_direction(SSL_P(F)) == 0) + return RB_RW_SSL_NEED_READ; + else + return RB_RW_SSL_NEED_WRITE; } - return ret; + + if(ret == GNUTLS_E_INTERRUPTED && errno != 0) + return RB_RW_IO_ERROR; + + errno = EIO; + F->ssl_errno = (unsigned long) -ret; + return RB_RW_SSL_ERROR; } ssize_t From 1a75461594342da80252ef0ad3aea5d0966ea460 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:27:45 +0000 Subject: [PATCH 30/33] GNUTLS: Minor fix to rb_ssl_accept_common()/rb_ssl_connect_common() Properly check whether the library was interrupted by the kernel before assuming that a nonzero errno was caused by the kernel. Otherwise, a memory allocation failure in the library for example would incorrectly be interpreted as a syscall error instead of a library error. --- libratbox/src/gnutls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index ebe11f31..7b98128d 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -248,7 +248,7 @@ rb_ssl_accept_common(rb_fde_t *const F, void *const data) F->handshake_count++; ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); } - else if(err != 0) + else if(ret == GNUTLS_E_INTERRUPTED && err != 0) { errno = err; ad->callback(F, RB_ERROR, NULL, 0, ad->data); @@ -632,7 +632,7 @@ rb_ssl_connect_common(rb_fde_t *const F, void *const data) F->handshake_count++; rb_ssl_connect_realcb(F, RB_OK, sconn); } - else if(err != 0) + else if(ret == GNUTLS_E_INTERRUPTED && err != 0) { errno = err; rb_ssl_connect_realcb(F, RB_ERROR, sconn); From 70bb2e24e0a455c226ea1a56c8ae87a011d4c2df Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 22:42:45 +0000 Subject: [PATCH 31/33] GNUTLS: Cosmetic preprocessor cleanliness --- libratbox/src/gnutls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 7b98128d..973de697 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -703,7 +703,7 @@ rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data int rb_init_prng(const char *const path, prng_seed_t seed_type) { -#if GNUTLS_VERSION_MAJOR < 3 +#if (GNUTLS_VERSION_MAJOR < 3) gcry_fast_random_poll(); rb_lib_log("%s: PRNG initialised", __func__); #else @@ -715,7 +715,7 @@ rb_init_prng(const char *const path, prng_seed_t seed_type) int rb_get_random(void *const buf, const size_t length) { -#if GNUTLS_VERSION_MAJOR < 3 +#if (GNUTLS_VERSION_MAJOR < 3) gcry_randomize(buf, length, GCRY_STRONG_RANDOM); #else gnutls_rnd(GNUTLS_RND_KEY, buf, length); From fe9fba46cf5edc94d9e9cf7c6c968d82d396425f Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Fri, 16 Sep 2016 23:58:57 +0000 Subject: [PATCH 32/33] GNUTLS: Add some more misc checks to the start of functions --- libratbox/src/gnutls.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 973de697..58502b1f 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -208,7 +208,7 @@ rb_ssl_clear_handshake_count(rb_fde_t *const F) } static void -rb_ssl_timeout_cb(rb_fde_t *const F, void *const notused) +rb_ssl_timeout_cb(rb_fde_t *const F, void *const data) { lrb_assert(F->accept != NULL); lrb_assert(F->accept->callback != NULL); @@ -648,6 +648,8 @@ rb_ssl_connect_common(rb_fde_t *const F, void *const data) static void rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data) { + lrb_assert(F != NULL); + struct ssl_connect *const sconn = data; if(status != RB_OK) @@ -733,6 +735,9 @@ rb_get_ssl_strerror(rb_fde_t *const F) int rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) { + if (F == NULL || F->ssl == NULL) + return 0; + gnutls_digest_algorithm_t md_type; switch(method) From ecfdcb08e8c2bddcaee4768f63660a9a3a212718 Mon Sep 17 00:00:00 2001 From: Aaron Jones Date: Sat, 17 Sep 2016 00:50:23 +0000 Subject: [PATCH 33/33] GNUTLS: Reorder all functions to match the other backends No code was changed in this commit; just entire lines moved up or down. Ofcourse, most git diff tools won't see it that way. The diff between the MbedTLS backend and this one is now fairly minimal. Note to auditors importing this series of patches for review and integration: This means you can skip this patch if you don't trust me. --- libratbox/src/gnutls.c | 592 +++++++++++++++++++++-------------------- 1 file changed, 305 insertions(+), 287 deletions(-) diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index 58502b1f..7f643a7a 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -39,14 +39,14 @@ # include #endif -#define SSL_P(x) *((gnutls_session_t *) ((x)->ssl)) - typedef enum { RB_FD_TLS_DIRECTION_IN = 0, RB_FD_TLS_DIRECTION_OUT = 1 } rb_fd_tls_direction; +#define SSL_P(x) *((gnutls_session_t *) ((x)->ssl)) + // Server side variables @@ -79,6 +79,10 @@ static ssize_t rb_sock_net_xmit(gnutls_transport_ptr_t, const void *, size_t); +/* + * Internal GNUTLS-specific code + */ + /* * We only have one certificate to authenticate with, as both a client and server. * @@ -89,7 +93,6 @@ static ssize_t rb_sock_net_xmit(gnutls_transport_ptr_t, const void *, size_t); * * Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client. */ - static int rb_ssl_cert_auth_cb(gnutls_session_t session, const gnutls_datum_t *const req_ca_rdn, const int req_ca_rdn_len, @@ -115,28 +118,6 @@ rb_ssl_cert_auth_cb(gnutls_session_t session, return 0; } -static const char * -rb_ssl_strerror(const int err) -{ - return gnutls_strerror(err); -} - -static ssize_t -rb_sock_net_recv(gnutls_transport_ptr_t context_ptr, void *const buf, const size_t count) -{ - const int fd = rb_get_fd((rb_fde_t *)context_ptr); - - return recv(fd, buf, count, 0); -} - -static ssize_t -rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr, const void *const buf, const size_t count) -{ - const int fd = rb_get_fd((rb_fde_t *)context_ptr); - - return send(fd, buf, count, 0); -} - static void rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) { @@ -175,47 +156,6 @@ rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir) gnutls_certificate_server_set_request(SSL_P(F), GNUTLS_CERT_REQUEST); } -void -rb_ssl_shutdown(rb_fde_t *const F) -{ - if(F == NULL || F->ssl == NULL) - return; - - for(int i = 0; i < 4; i++) - { - int ret = gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR); - - if(ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_AGAIN) - break; - } - - gnutls_deinit(SSL_P(F)); - - rb_free(F->ssl); - F->ssl = NULL; -} - -unsigned int -rb_ssl_handshake_count(rb_fde_t *const F) -{ - return F->handshake_count; -} - -void -rb_ssl_clear_handshake_count(rb_fde_t *const F) -{ - F->handshake_count = 0; -} - -static void -rb_ssl_timeout_cb(rb_fde_t *const F, void *const data) -{ - lrb_assert(F->accept != NULL); - lrb_assert(F->accept->callback != NULL); - - F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); -} - static void rb_ssl_accept_common(rb_fde_t *const F, void *const data) { @@ -263,42 +203,54 @@ rb_ssl_accept_common(rb_fde_t *const F, void *const data) rb_free(ad); } -void -rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout) +static void +rb_ssl_connect_common(rb_fde_t *const F, void *const data) { - F->type |= RB_FD_SSL; + lrb_assert(F != NULL); + lrb_assert(F->ssl != NULL); - F->accept = rb_malloc(sizeof(struct acceptdata)); - F->accept->callback = cb; - F->accept->data = data; - F->accept->addrlen = 0; - (void) memset(&F->accept->S, 0x00, sizeof F->accept->S); + errno = 0; - rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL); - rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN); - rb_ssl_accept_common(F, NULL); + const int ret = gnutls_handshake(SSL_P(F)); + const int err = errno; + + if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) + { + unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; + rb_setselect(F, flags, rb_ssl_connect_common, data); + return; + } + + // These 2 calls may affect errno, which is why we save it above and restore it below + rb_settimeout(F, 0, NULL, NULL); + rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); + + struct ssl_connect *const sconn = data; + + if(ret == GNUTLS_E_SUCCESS) + { + F->handshake_count++; + rb_ssl_connect_realcb(F, RB_OK, sconn); + } + else if(ret == GNUTLS_E_INTERRUPTED && err != 0) + { + errno = err; + rb_ssl_connect_realcb(F, RB_ERROR, sconn); + } + else + { + errno = EIO; + F->ssl_errno = (unsigned long) -ret; + rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); + } } -void -rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen) +static const char * +rb_ssl_strerror(const int err) { - cli_F->type |= RB_FD_SSL; - - cli_F->accept = rb_malloc(sizeof(struct acceptdata)); - cli_F->accept->callback = srv_F->accept->callback; - cli_F->accept->data = srv_F->accept->data; - cli_F->accept->addrlen = (rb_socklen_t) addrlen; - (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S); - (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen); - - rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL); - rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN); - rb_ssl_accept_common(cli_F, NULL); + return gnutls_strerror(err); } - - - static ssize_t 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) { @@ -330,18 +282,6 @@ rb_ssl_read_or_write(const int r_or_w, rb_fde_t *const F, void *const rbuf, cons return RB_RW_SSL_ERROR; } -ssize_t -rb_ssl_read(rb_fde_t *const F, void *const buf, const size_t count) -{ - return rb_ssl_read_or_write(0, F, buf, NULL, count); -} - -ssize_t -rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count) -{ - return rb_ssl_read_or_write(1, F, NULL, buf, count); -} - #if (GNUTLS_VERSION_MAJOR < 3) static void rb_gcry_random_seed(void *const unused) @@ -350,24 +290,6 @@ rb_gcry_random_seed(void *const unused) } #endif -int -rb_init_ssl(void) -{ - int ret; - - if ((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) - { - rb_lib_log("%s: gnutls_global_init: %s", __func__, rb_ssl_strerror(ret)); - return 0; - } - -#if (GNUTLS_VERSION_MAJOR < 3) - rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); -#endif - - return 1; -} - static void rb_free_datum_t(gnutls_datum_t *const datum) { @@ -432,6 +354,50 @@ rb_load_file_into_datum_t(const char *const file) return datum; } + + +/* + * External GNUTLS-specific code + */ + +void +rb_ssl_shutdown(rb_fde_t *const F) +{ + if(F == NULL || F->ssl == NULL) + return; + + for(int i = 0; i < 4; i++) + { + int ret = gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR); + + if(ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_AGAIN) + break; + } + + gnutls_deinit(SSL_P(F)); + + rb_free(F->ssl); + F->ssl = NULL; +} + +int +rb_init_ssl(void) +{ + int ret; + + if((ret = gnutls_global_init()) != GNUTLS_E_SUCCESS) + { + rb_lib_log("%s: gnutls_global_init: %s", __func__, rb_ssl_strerror(ret)); + return 0; + } + +#if (GNUTLS_VERSION_MAJOR < 3) + rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300); +#endif + + return 1; +} + int rb_setup_ssl_server(const char *const certfile, const char *keyfile, const char *const dhfile, const char *const cipherlist) @@ -575,15 +541,134 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, } int -rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept) +rb_init_prng(const char *const path, prng_seed_t seed_type) { - int result = rb_listen(F, backlog, defer_accept); - - F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; - - return result; +#if (GNUTLS_VERSION_MAJOR < 3) + gcry_fast_random_poll(); + rb_lib_log("%s: PRNG initialised", __func__); +#else + rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__); +#endif + return 1; } +int +rb_get_random(void *const buf, const size_t length) +{ +#if (GNUTLS_VERSION_MAJOR < 3) + gcry_randomize(buf, length, GCRY_STRONG_RANDOM); +#else + gnutls_rnd(GNUTLS_RND_KEY, buf, length); +#endif + return 1; +} + +const char * +rb_get_ssl_strerror(rb_fde_t *const F) +{ + const int err = (int) F->ssl_errno; + return rb_ssl_strerror(-err); +} + +int +rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) +{ + if(F == NULL || F->ssl == NULL) + return 0; + + gnutls_digest_algorithm_t md_type; + + switch(method) + { + case RB_SSL_CERTFP_METH_SHA1: + md_type = GNUTLS_DIG_SHA1; + break; + case RB_SSL_CERTFP_METH_SHA256: + md_type = GNUTLS_DIG_SHA256; + break; + case RB_SSL_CERTFP_METH_SHA512: + md_type = GNUTLS_DIG_SHA512; + break; + default: + return 0; + } + + if(gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) + return 0; + + unsigned int cert_list_size = 0; + const gnutls_datum_t *const cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); + if(cert_list == NULL || cert_list_size <= 0) + return 0; + + gnutls_x509_crt_t peer_cert; + if(gnutls_x509_crt_init(&peer_cert) != GNUTLS_E_SUCCESS) + return 0; + + if(gnutls_x509_crt_import(peer_cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) + { + gnutls_x509_crt_deinit(peer_cert); + return 0; + } + + int ret; + size_t hashlen; + if((ret = gnutls_x509_crt_get_fingerprint(peer_cert, md_type, certfp, &hashlen)) != 0) + { + rb_lib_log("%s: gnutls_x509_crt_get_fingerprint: %s", __func__, rb_ssl_strerror(ret)); + gnutls_x509_crt_deinit(peer_cert); + return 0; + } + + gnutls_x509_crt_deinit(peer_cert); + + return (int) hashlen; +} + +void +rb_get_ssl_info(char *const buf, const size_t len) +{ + (void) rb_snprintf(buf, len, "GNUTLS: compiled (v%s), library (v%s)", + LIBGNUTLS_VERSION, gnutls_check_version(NULL)); +} + +const char * +rb_ssl_get_cipher(rb_fde_t *const F) +{ + if(F == NULL || F->ssl == NULL) + return NULL; + + static char buf[512]; + + gnutls_protocol_t version_ptr = gnutls_protocol_get_version(SSL_P(F)); + gnutls_cipher_algorithm_t cipher_ptr = gnutls_cipher_get(SSL_P(F)); + + const char *const version = gnutls_protocol_get_name(version_ptr); + const char *const cipher = gnutls_cipher_get_name(cipher_ptr); + + (void) rb_snprintf(buf, sizeof buf, "%s, %s", version, cipher); + + return buf; +} + +ssize_t +rb_ssl_read(rb_fde_t *const F, void *const buf, const size_t count) +{ + return rb_ssl_read_or_write(0, F, buf, NULL, count); +} + +ssize_t +rb_ssl_write(rb_fde_t *const F, const void *const buf, const size_t count) +{ + return rb_ssl_read_or_write(1, F, NULL, buf, count); +} + + + +/* + * Internal library-agnostic code + */ + static void rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *const sconn) { @@ -598,51 +683,18 @@ rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *c } static void -rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) +rb_ssl_timeout_cb(rb_fde_t *const F, void *const data) { - rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); + lrb_assert(F->accept != NULL); + lrb_assert(F->accept->callback != NULL); + + F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data); } static void -rb_ssl_connect_common(rb_fde_t *const F, void *const data) +rb_ssl_tryconn_timeout_cb(rb_fde_t *const F, void *const data) { - lrb_assert(F != NULL); - lrb_assert(F->ssl != NULL); - - errno = 0; - - const int ret = gnutls_handshake(SSL_P(F)); - const int err = errno; - - if(ret == GNUTLS_E_AGAIN || (ret == GNUTLS_E_INTERRUPTED && (err == 0 || rb_ignore_errno(err)))) - { - unsigned int flags = (gnutls_record_get_direction(SSL_P(F)) == 0) ? RB_SELECT_READ : RB_SELECT_WRITE; - rb_setselect(F, flags, rb_ssl_connect_common, data); - return; - } - - // These 2 calls may affect errno, which is why we save it above and restore it below - rb_settimeout(F, 0, NULL, NULL); - rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); - - struct ssl_connect *const sconn = data; - - if(ret == GNUTLS_E_SUCCESS) - { - F->handshake_count++; - rb_ssl_connect_realcb(F, RB_OK, sconn); - } - else if(ret == GNUTLS_E_INTERRUPTED && err != 0) - { - errno = err; - rb_ssl_connect_realcb(F, RB_ERROR, sconn); - } - else - { - errno = EIO; - F->ssl_errno = (unsigned long) -ret; - rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn); - } + rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data); } static void @@ -665,6 +717,89 @@ rb_ssl_tryconn(rb_fde_t *const F, const int status, void *const data) rb_ssl_connect_common(F, sconn); } +static ssize_t +rb_sock_net_recv(gnutls_transport_ptr_t context_ptr, void *const buf, const size_t count) +{ + const int fd = rb_get_fd((rb_fde_t *)context_ptr); + + return recv(fd, buf, count, 0); +} + +static ssize_t +rb_sock_net_xmit(gnutls_transport_ptr_t context_ptr, const void *const buf, const size_t count) +{ + const int fd = rb_get_fd((rb_fde_t *)context_ptr); + + return send(fd, buf, count, 0); +} + + + +/* + * External library-agnostic code + */ + +int +rb_supports_ssl(void) +{ + return 1; +} + +unsigned int +rb_ssl_handshake_count(rb_fde_t *const F) +{ + return F->handshake_count; +} + +void +rb_ssl_clear_handshake_count(rb_fde_t *const F) +{ + F->handshake_count = 0; +} + +void +rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout) +{ + F->type |= RB_FD_SSL; + + F->accept = rb_malloc(sizeof(struct acceptdata)); + F->accept->callback = cb; + F->accept->data = data; + F->accept->addrlen = 0; + (void) memset(&F->accept->S, 0x00, sizeof F->accept->S); + + rb_settimeout(F, timeout, rb_ssl_timeout_cb, NULL); + rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN); + rb_ssl_accept_common(F, NULL); +} + +void +rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen) +{ + cli_F->type |= RB_FD_SSL; + + cli_F->accept = rb_malloc(sizeof(struct acceptdata)); + cli_F->accept->callback = srv_F->accept->callback; + cli_F->accept->data = srv_F->accept->data; + cli_F->accept->addrlen = (rb_socklen_t) addrlen; + (void) memset(&cli_F->accept->S, 0x00, sizeof cli_F->accept->S); + (void) memcpy(&cli_F->accept->S, st, (size_t) addrlen); + + rb_settimeout(cli_F, 10, rb_ssl_timeout_cb, NULL); + rb_ssl_init_fd(cli_F, RB_FD_TLS_DIRECTION_IN); + rb_ssl_accept_common(cli_F, NULL); +} + +int +rb_ssl_listen(rb_fde_t *const F, const int backlog, const int defer_accept) +{ + int result = rb_listen(F, backlog, defer_accept); + + F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL; + + return result; +} + void rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockaddr *const clocal, const int socklen, CNCB *const callback, void *const data, const int timeout) @@ -702,121 +837,4 @@ rb_ssl_start_connected(rb_fde_t *const F, CNCB *const callback, void *const data rb_ssl_connect_common(F, sconn); } -int -rb_init_prng(const char *const path, prng_seed_t seed_type) -{ -#if (GNUTLS_VERSION_MAJOR < 3) - gcry_fast_random_poll(); - rb_lib_log("%s: PRNG initialised", __func__); -#else - rb_lib_log("%s: Skipping PRNG initialisation; not required by GNUTLS v3+ backend", __func__); -#endif - return 1; -} - -int -rb_get_random(void *const buf, const size_t length) -{ -#if (GNUTLS_VERSION_MAJOR < 3) - gcry_randomize(buf, length, GCRY_STRONG_RANDOM); -#else - gnutls_rnd(GNUTLS_RND_KEY, buf, length); -#endif - return 1; -} - -const char * -rb_get_ssl_strerror(rb_fde_t *const F) -{ - const int err = (int) F->ssl_errno; - return rb_ssl_strerror(-err); -} - -int -rb_get_ssl_certfp(rb_fde_t *const F, uint8_t certfp[const RB_SSL_CERTFP_LEN], const int method) -{ - if (F == NULL || F->ssl == NULL) - return 0; - - gnutls_digest_algorithm_t md_type; - - switch(method) - { - case RB_SSL_CERTFP_METH_SHA1: - md_type = GNUTLS_DIG_SHA1; - break; - case RB_SSL_CERTFP_METH_SHA256: - md_type = GNUTLS_DIG_SHA256; - break; - case RB_SSL_CERTFP_METH_SHA512: - md_type = GNUTLS_DIG_SHA512; - break; - default: - return 0; - } - - if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) - return 0; - - unsigned int cert_list_size = 0; - const gnutls_datum_t *const cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); - if (cert_list == NULL || cert_list_size <= 0) - return 0; - - gnutls_x509_crt_t peer_cert; - if (gnutls_x509_crt_init(&peer_cert) != GNUTLS_E_SUCCESS) - return 0; - - if (gnutls_x509_crt_import(peer_cert, &cert_list[0], GNUTLS_X509_FMT_DER) != GNUTLS_E_SUCCESS) - { - gnutls_x509_crt_deinit(peer_cert); - return 0; - } - - int ret; - size_t hashlen; - if ((ret = gnutls_x509_crt_get_fingerprint(peer_cert, md_type, certfp, &hashlen)) != 0) - { - rb_lib_log("%s: gnutls_x509_crt_get_fingerprint: %s", __func__, rb_ssl_strerror(ret)); - gnutls_x509_crt_deinit(peer_cert); - return 0; - } - - gnutls_x509_crt_deinit(peer_cert); - - return (int) hashlen; -} - -int -rb_supports_ssl(void) -{ - return 1; -} - -void -rb_get_ssl_info(char *const buf, const size_t len) -{ - (void) rb_snprintf(buf, len, "GNUTLS: compiled (v%s), library (v%s)", - LIBGNUTLS_VERSION, gnutls_check_version(NULL)); -} - -const char * -rb_ssl_get_cipher(rb_fde_t *const F) -{ - if(F == NULL || F->ssl == NULL) - return NULL; - - static char buf[512]; - - gnutls_protocol_t version_ptr = gnutls_protocol_get_version(SSL_P(F)); - gnutls_cipher_algorithm_t cipher_ptr = gnutls_cipher_get(SSL_P(F)); - - const char *const version = gnutls_protocol_get_name(version_ptr); - const char *const cipher = gnutls_cipher_get_name(cipher_ptr); - - (void) rb_snprintf(buf, sizeof buf, "%s, %s", version, cipher); - - return buf; -} - #endif /* HAVE_GNUTLS */