From 0b38190e1f839237d104c1094cd34fb2388c81df Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 12 Jan 2008 00:00:05 +0100 Subject: [PATCH] more support for gnutls Signed-off-by: Pierre Habouzit --- lib-sys/evtloop.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++- lib-sys/evtloop.h | 5 ++-- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/lib-sys/evtloop.c b/lib-sys/evtloop.c index 1991646..4dd3d45 100644 --- a/lib-sys/evtloop.c +++ b/lib-sys/evtloop.c @@ -29,6 +29,7 @@ #endif #include "evtloop.h" #include "mutt.h" +#include "mutt_ssl.li" static int epollfd = -1; @@ -69,6 +70,14 @@ int el_job_setmode(job_t *w, el_mode mode) } } +void job_wipe(job_t *w) +{ + if (w->xcred) + gnutls_certificate_free_credentials(w->xcred); + if (w->session) + gnutls_deinit(w->session); +} + int el_job_release(job_t *w, el_status reason) { w->state = EL_LLP_FINI; @@ -76,12 +85,37 @@ int el_job_release(job_t *w, el_status reason) w->m->finalize(w, reason); } if (w->fd >= 0) { + if (w->session) + gnutls_bye(w->session, GNUTLS_SHUT_RDWR); close(w->fd); } job_delete(&w); return -1; } +static int el_job_connecting_ssl(job_t *w) +{ + int err = gnutls_handshake(w->session); + + if (err < 0 && !gnutls_error_is_fatal(err)) { + int wr = gnutls_record_get_direction(w->session); + return el_job_setemode(w, wr ? EL_WRITING : EL_READING); + } + if (err < 0) + return el_job_release(w, EL_RDHUP); + +#if 0 + if (!tls_check_certificate (conn)) + return -1; + + /* set Security Strength Factor (SSF) for SASL */ + /* NB: gnutls_cipher_get_key_size() returns key length in bytes */ + conn->ssf = gnutls_cipher_get_key_size(gnutls_cipher_get(w->session)) * 8; +#endif + w->state = EL_LLP_READY; + return w->m->on_event(w, EL_EVT_RUNNING); +} + static int el_job_connecting(job_t *w) { int err = 0; @@ -90,12 +124,49 @@ static int el_job_connecting(job_t *w) if (getsockopt(w->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &len) || err) return el_job_release(w, EL_ERROR); + if (w->session) { + w->llp = &el_job_connecting_ssl; + return w->llp(w); + } w->state = EL_LLP_READY; return w->m->on_event(w, EL_EVT_RUNNING); } +static int tls_negociate(job_t *w) +{ + static int protocol_priority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; + + if (gnutls_certificate_allocate_credentials(&w->xcred) < 0) + return -1; + + /* ignore errors, maybe file doesn't exist yet */ + gnutls_certificate_set_x509_trust_file(w->xcred, mod_ssl.cert_file, + GNUTLS_X509_FMT_PEM); + + if (mod_ssl.ca_certificates_file) { + gnutls_certificate_set_x509_trust_file(w->xcred, + mod_ssl.ca_certificates_file, GNUTLS_X509_FMT_PEM); + } + gnutls_init(&w->session, GNUTLS_CLIENT); + + /* set socket */ + gnutls_transport_set_ptr(w->session, (gnutls_transport_ptr)(intptr_t)w->fd); + + /* disable TLS/SSL protocols as needed */ + if (!mod_ssl.use_sslv3) { + protocol_priority[1] = 0; + } + + /* We use default priorities (see gnutls documentation), + except for protocol version */ + gnutls_set_default_priority(w->session); + gnutls_protocol_set_priority(w->session, protocol_priority); + gnutls_credentials_set(w->session, GNUTLS_CRD_CERTIFICATE, w->xcred); + return 0; +} + int el_job_connect(job_t *w, struct sockaddr *addr, socklen_t len, - int type, int proto) + int type, int proto, int ssl) { int res, sock = socket(addr->sa_family, type, proto); @@ -111,6 +182,9 @@ int el_job_connect(job_t *w, struct sockaddr *addr, socklen_t len, goto error; w->fd = sock; + if (ssl && tls_negociate(w) < 0) + goto error; + w->llp = &el_job_connecting; return el_job_setmode(w, EL_WRITING); diff --git a/lib-sys/evtloop.h b/lib-sys/evtloop.h index b64942e..2be7366 100644 --- a/lib-sys/evtloop.h +++ b/lib-sys/evtloop.h @@ -57,6 +57,7 @@ typedef struct job_t { int fd; gnutls_session_t session; + gnutls_certificate_credentials_t xcred; el_state state : 2; el_mode mode : 3; @@ -67,7 +68,7 @@ typedef struct job_t { void *ptr; } job_t; DO_INIT(job_t, job); -DO_WIPE(job_t, job); +void job_wipe(job_t *w); DO_NEW(job_t, job); DO_DELETE(job_t, job); @@ -84,7 +85,7 @@ typedef struct machine_t { __must_check__ int el_job_setmode(job_t *w, el_mode); __must_check__ int el_job_release(job_t *j, el_status); __must_check__ int el_job_connect(job_t *w, struct sockaddr *, socklen_t len, - int type, int proto); + int type, int proto, int ssl); __must_check__ ssize_t el_job_read(job_t *w, buffer_t *buf); __must_check__ ssize_t el_job_write(job_t *w, buffer_t *buf); -- 2.20.1