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.
This commit is contained in:
parent
fe9fba46cf
commit
ecfdcb08e8
1 changed files with 305 additions and 287 deletions
|
@ -39,14 +39,14 @@
|
||||||
# include <gnutls/crypto.h>
|
# include <gnutls/crypto.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SSL_P(x) *((gnutls_session_t *) ((x)->ssl))
|
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
RB_FD_TLS_DIRECTION_IN = 0,
|
RB_FD_TLS_DIRECTION_IN = 0,
|
||||||
RB_FD_TLS_DIRECTION_OUT = 1
|
RB_FD_TLS_DIRECTION_OUT = 1
|
||||||
} rb_fd_tls_direction;
|
} rb_fd_tls_direction;
|
||||||
|
|
||||||
|
#define SSL_P(x) *((gnutls_session_t *) ((x)->ssl))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Server side variables
|
// 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.
|
* 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.
|
* Thus, we use this callback to force GNUTLS to authenticate with our (server) certificate as a client.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rb_ssl_cert_auth_cb(gnutls_session_t session,
|
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_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;
|
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
|
static void
|
||||||
rb_ssl_init_fd(rb_fde_t *const F, const rb_fd_tls_direction dir)
|
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);
|
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
|
static void
|
||||||
rb_ssl_accept_common(rb_fde_t *const F, void *const data)
|
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);
|
rb_free(ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rb_ssl_start_accepted(rb_fde_t *const F, ACCB *const cb, void *const data, const int timeout)
|
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));
|
errno = 0;
|
||||||
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);
|
const int ret = gnutls_handshake(SSL_P(F));
|
||||||
rb_ssl_init_fd(F, RB_FD_TLS_DIRECTION_IN);
|
const int err = errno;
|
||||||
rb_ssl_accept_common(F, NULL);
|
|
||||||
|
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
|
static const char *
|
||||||
rb_ssl_accept_setup(rb_fde_t *const srv_F, rb_fde_t *const cli_F, struct sockaddr *const st, const int addrlen)
|
rb_ssl_strerror(const int err)
|
||||||
{
|
{
|
||||||
cli_F->type |= RB_FD_SSL;
|
return gnutls_strerror(err);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static ssize_t
|
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)
|
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;
|
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)
|
#if (GNUTLS_VERSION_MAJOR < 3)
|
||||||
static void
|
static void
|
||||||
rb_gcry_random_seed(void *const unused)
|
rb_gcry_random_seed(void *const unused)
|
||||||
|
@ -350,24 +290,6 @@ rb_gcry_random_seed(void *const unused)
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
static void
|
||||||
rb_free_datum_t(gnutls_datum_t *const datum)
|
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;
|
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
|
int
|
||||||
rb_setup_ssl_server(const char *const certfile, const char *keyfile,
|
rb_setup_ssl_server(const char *const certfile, const char *keyfile,
|
||||||
const char *const dhfile, const char *const cipherlist)
|
const char *const dhfile, const char *const cipherlist)
|
||||||
|
@ -575,15 +541,134 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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);
|
#if (GNUTLS_VERSION_MAJOR < 3)
|
||||||
|
gcry_fast_random_poll();
|
||||||
F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
|
rb_lib_log("%s: PRNG initialised", __func__);
|
||||||
|
#else
|
||||||
return result;
|
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
|
static void
|
||||||
rb_ssl_connect_realcb(rb_fde_t *const F, const int status, struct ssl_connect *const sconn)
|
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
|
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
|
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);
|
rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
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
|
void
|
||||||
rb_connect_tcp_ssl(rb_fde_t *const F, struct sockaddr *const dest, struct sockaddr *const clocal,
|
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)
|
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);
|
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 */
|
#endif /* HAVE_GNUTLS */
|
||||||
|
|
Loading…
Reference in a new issue