Mercurial > dovecot > core-2.2
changeset 622:235188ee7a05 HEAD
Support for OpenSSL.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 20 Nov 2002 16:05:13 +0200 |
parents | 5690ce7151c9 |
children | 3fa9e363cd3d |
files | acconfig.h configure.in src/login/Makefile.am src/login/ssl-proxy-gnutls.c src/login/ssl-proxy-openssl.c src/login/ssl-proxy.c src/master/Makefile.am src/master/ssl-init-gnutls.c src/master/ssl-init-openssl.c src/master/ssl-init.c src/master/ssl-init.h |
diffstat | 11 files changed, 1057 insertions(+), 618 deletions(-) [+] |
line wrap: on
line diff
--- a/acconfig.h Wed Nov 20 16:04:04 2002 +0200 +++ b/acconfig.h Wed Nov 20 16:05:13 2002 +0200 @@ -9,6 +9,8 @@ /* Build with SSL/TLS support */ #undef HAVE_SSL +#undef HAVE_GNUTLS +#undef HAVE_OPENSSL /* build with IPv6 support */ #undef HAVE_IPV6
--- a/configure.in Wed Nov 20 16:04:04 2002 +0200 +++ b/configure.in Wed Nov 20 16:05:13 2002 +0200 @@ -102,14 +102,24 @@ AC_DEFINE(BUILD_RAWLOG) fi) -AC_ARG_WITH(gnutls, -[ --with-gnutls Build with GNUTLS (default)], +AC_ARG_WITH(ssl, +[ --with-ssl=[gnutls|openssl] Build with GNUTLS (default) or OpenSSL], if test x$withval = xno; then want_gnutls=no + want_openssl=no + elif test x$withval = xgnutls; then + want_gnutls=yes + want_openssl=no + elif test x$withval = xopenssl; then + want_gnutls=no + want_openssl=yes else want_gnutls=yes - fi, - want_gnutls=yes) + want_openssl=yes + fi, [ + want_gnutls=yes + want_openssl=yes + ]) dnl ** dnl ** just some generic stuff... @@ -346,22 +356,42 @@ ]) dnl ** -dnl ** SSL (gnutls) +dnl ** SSL dnl ** if test $want_gnutls = yes; then - AC_CHECK_LIB(gnutls, gnutls_global_init, [ - AC_DEFINE(HAVE_SSL) - SSL_LIBS="-lgnutls -lgcrypt" - AC_SUBST(SSL_LIBS) - have_ssl=yes - ], [ - have_ssl=no - ], -lgcrypt) + AC_CHECK_LIB(gnutls, gnutls_global_init, [ + AC_DEFINE(HAVE_SSL) + AC_DEFINE(HAVE_GNUTLS) + SSL_LIBS="-lgnutls -lgcrypt" + AC_SUBST(SSL_LIBS) + have_ssl="yes (GNUTLS)" + have_gnutls=yes + ], [ + have_ssl=no + ], -lgcrypt) else - have_ssl=no + have_ssl=no fi +if test "$want_openssl" = "yes" -a "$have_ssl" = "no"; then + AC_CHECK_LIB(ssl, SSL_read, [ + AC_CHECK_LIB(crypto, X509_new, [ + AC_CHECK_HEADERS(openssl/ssl.h openssl/err.h, [ + AC_DEFINE(HAVE_SSL) + AC_DEFINE(HAVE_OPENSSL) + SSL_LIBS="-lssl -lcrypto" + AC_SUBST(SSL_LIBS) + have_ssl="yes (OpenSSL)" + have_openssl=yes + ]) + ]) + ]) +fi + +AM_CONDITIONAL(SSL_GNUTLS, test "$have_gnutls" = "yes") +AM_CONDITIONAL(SSL_OPENSSL, test "$have_openssl" = "yes") + dnl ** dnl ** shadow/pam support dnl ** @@ -481,7 +511,7 @@ dnl ** capability="IMAP4rev1" -if test "$have_ssl" = "yes"; then +if test "$have_ssl" != "no"; then capability="$capability STARTTLS" fi AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability")
--- a/src/login/Makefile.am Wed Nov 20 16:04:04 2002 +0200 +++ b/src/login/Makefile.am Wed Nov 20 16:05:13 2002 +0200 @@ -13,7 +13,9 @@ client-authenticate.c \ main.c \ master.c \ - ssl-proxy.c + ssl-proxy.c \ + ssl-proxy-gnutls.c \ + ssl-proxy-openssl.c noinst_HEADERS = \ auth-connection.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/login/ssl-proxy-gnutls.c Wed Nov 20 16:05:13 2002 +0200 @@ -0,0 +1,521 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "ioloop.h" +#include "network.h" +#include "ssl-proxy.h" + +#ifdef HAVE_GNUTLS + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <gcrypt.h> +#include <gnutls/gnutls.h> + +typedef struct { + int refcount; + + gnutls_session session; + int fd_ssl, fd_plain; + IO io_ssl, io_plain; + int io_ssl_dir; + + unsigned char outbuf_plain[1024]; + unsigned int outbuf_pos_plain; + + size_t send_left_ssl, send_left_plain; +} SSLProxy; + +const int protocol_priority[] = + { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; +const int kx_priority[] = + { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 }; +const int cipher_priority[] = + { GNUTLS_CIPHER_RIJNDAEL_CBC, GNUTLS_CIPHER_3DES_CBC, + GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_ARCFOUR_40, 0 }; +const int comp_priority[] = + { GNUTLS_COMP_LZO, GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; +const int mac_priority[] = + { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 }; +const int cert_type_priority[] = + { GNUTLS_CRT_X509, 0 }; + +static gnutls_certificate_credentials x509_cred; +static gnutls_dh_params dh_params; +static gnutls_rsa_params rsa_params; + +static void ssl_input(void *context, int handle, IO io); +static void plain_input(void *context, int handle, IO io); +static int ssl_proxy_destroy(SSLProxy *proxy); + +static const char *get_alert_text(SSLProxy *proxy) +{ + return gnutls_alert_get_name(gnutls_alert_get(proxy->session)); +} + +static int handle_ssl_error(SSLProxy *proxy, int error) +{ + if (!gnutls_error_is_fatal(error)) { + if (error == GNUTLS_E_WARNING_ALERT_RECEIVED) { + i_warning("Received SSL warning alert: %s", + get_alert_text(proxy)); + } + return 0; + } + + /* fatal error occured */ + if (error == GNUTLS_E_FATAL_ALERT_RECEIVED) { + i_warning("Received SSL fatal alert: %s", + get_alert_text(proxy)); + } else { + i_warning("Error reading from SSL client: %s", + gnutls_strerror(error)); + } + + gnutls_alert_send_appropriate(proxy->session, error); + ssl_proxy_destroy(proxy); + return -1; +} + +static int proxy_recv_ssl(SSLProxy *proxy, void *data, size_t size) +{ + int rcvd; + + rcvd = gnutls_record_recv(proxy->session, data, size); + if (rcvd > 0) + return rcvd; + + if (rcvd == 0 || rcvd == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) { + /* disconnected, either by nicely telling us that we'll + close the connection, or by simply killing the + connection which gives us the packet length error. */ + ssl_proxy_destroy(proxy); + return -1; + } + + return handle_ssl_error(proxy, rcvd); +} + +static int proxy_send_ssl(SSLProxy *proxy, const void *data, size_t size) +{ + int sent; + + sent = gnutls_record_send(proxy->session, data, size); + if (sent >= 0) + return sent; + + if (sent == GNUTLS_E_PUSH_ERROR || sent == GNUTLS_E_INVALID_SESSION) { + /* don't warn about errors related to unexpected disconnection */ + ssl_proxy_destroy(proxy); + return -1; + } + + return handle_ssl_error(proxy, sent); +} + +static int ssl_proxy_destroy(SSLProxy *proxy) +{ + if (--proxy->refcount > 0) + return TRUE; + + gnutls_deinit(proxy->session); + + (void)net_disconnect(proxy->fd_ssl); + (void)net_disconnect(proxy->fd_plain); + + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + if (proxy->io_plain != NULL) + io_remove(proxy->io_plain); + + i_free(proxy); + + main_unref(); + return FALSE; +} + +static void ssl_output(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + int sent; + + sent = net_transmit(proxy->fd_plain, + proxy->outbuf_plain + proxy->outbuf_pos_plain, + proxy->send_left_plain); + if (sent < 0) { + /* disconnected */ + ssl_proxy_destroy(proxy); + return; + } + + proxy->send_left_plain -= sent; + proxy->outbuf_pos_plain += sent; + + if (proxy->send_left_plain > 0) + return; + + /* everything is sent, start reading again */ + io_remove(proxy->io_ssl); + proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy); +} + +static void ssl_input(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + int rcvd, sent; + + rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain, + sizeof(proxy->outbuf_plain)); + if (rcvd <= 0) + return; + + sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd); + if (sent == rcvd) + return; + + if (sent < 0) { + /* disconnected */ + ssl_proxy_destroy(proxy); + return; + } + + /* everything wasn't sent - don't read anything until we've + sent it all */ + proxy->outbuf_pos_plain = 0; + proxy->send_left_plain = rcvd - sent; + + io_remove(proxy->io_ssl); + proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy); +} + +static void plain_output(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + int sent; + + sent = proxy_send_ssl(proxy, NULL, proxy->send_left_ssl); + if (sent <= 0) + return; + + proxy->send_left_ssl -= sent; + if (proxy->send_left_ssl > 0) + return; + + /* everything is sent, start reading again */ + io_remove(proxy->io_plain); + proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy); +} + +static void plain_input(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + char buf[1024]; + ssize_t rcvd, sent; + + rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf)); + if (rcvd < 0) { + /* disconnected */ + gnutls_bye(proxy->session, 1); + ssl_proxy_destroy(proxy); + return; + } + + sent = proxy_send_ssl(proxy, buf, (size_t)rcvd); + if (sent < 0 || sent == rcvd) + return; + + /* everything wasn't sent - don't read anything until we've + sent it all */ + proxy->send_left_ssl = rcvd - sent; + + io_remove(proxy->io_plain); + proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy); +} + +static void ssl_handshake(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + int ret, dir; + + ret = gnutls_handshake(proxy->session); + if (ret >= 0) { + /* handshake done, now we can start reading */ + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + + proxy->io_plain = io_add(proxy->fd_plain, IO_READ, + plain_input, proxy); + proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, + ssl_input, proxy); + return; + } + + if (handle_ssl_error(proxy, ret) < 0) + return; + + /* i/o interrupted */ + dir = gnutls_handshake_get_direction(proxy->session) == 0 ? + IO_READ : IO_WRITE; + if (proxy->io_ssl_dir != dir) { + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + proxy->io_ssl = io_add(proxy->fd_ssl, dir, + ssl_handshake, proxy); + proxy->io_ssl_dir = dir; + } +} + +static gnutls_session initialize_state(void) +{ + gnutls_session session; + + gnutls_init(&session, GNUTLS_SERVER); + + gnutls_protocol_set_priority(session, protocol_priority); + gnutls_cipher_set_priority(session, cipher_priority); + gnutls_compression_set_priority(session, comp_priority); + gnutls_kx_set_priority(session, kx_priority); + gnutls_mac_set_priority(session, mac_priority); + gnutls_cert_type_set_priority(session, cert_type_priority); + + gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); + return session; +} + +int ssl_proxy_new(int fd) +{ + SSLProxy *proxy; + gnutls_session session; + int sfd[2]; + + if (!ssl_initialized) + return -1; + + session = initialize_state(); + gnutls_transport_set_ptr(session, fd); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { + i_error("socketpair() failed: %m"); + gnutls_deinit(session); + return -1; + } + + net_set_nonblock(sfd[0], TRUE); + net_set_nonblock(sfd[1], TRUE); + + proxy = i_new(SSLProxy, 1); + proxy->refcount = 1; + proxy->session = session; + proxy->fd_ssl = fd; + proxy->fd_plain = sfd[0]; + + proxy->refcount++; + ssl_handshake(proxy, -1, NULL); + if (!ssl_proxy_destroy(proxy)) + return -1; + + main_ref(); + return sfd[1]; +} + +static void read_next_field(int fd, gnutls_datum *datum, + const char *fname, const char *field_name) +{ + ssize_t ret; + + /* get size */ + ret = read(fd, &datum->size, sizeof(datum->size)); + if (ret < 0) + i_fatal("read() failed for %s: %m", fname); + + if (ret != sizeof(datum->size)) { + (void)unlink(fname); + i_fatal("Corrupted SSL parameter file %s: File too small", + fname); + } + + if (datum->size > 10240) { + (void)unlink(fname); + i_fatal("Corrupted SSL parameter file %s: " + "Field '%s' too large (%u)", + fname, field_name, datum->size); + } + + /* read the actual data */ + datum->data = t_malloc(datum->size); + ret = read(fd, datum->data, datum->size); + if (ret < 0) + i_fatal("read() failed for %s: %m", fname); + + if ((size_t)ret != datum->size) { + (void)unlink(fname); + i_fatal("Corrupted SSL parameter file %s: " + "Field '%s' not fully in file (%u < %u)", + fname, field_name, datum->size - ret, datum->size); + } +} + +static void read_dh_parameters(int fd, const char *fname) +{ + gnutls_datum dbits, prime, generator; + int ret, bits; + + if ((ret = gnutls_dh_params_init(&dh_params)) < 0) { + i_fatal("gnutls_dh_params_init() failed: %s", + gnutls_strerror(ret)); + } + + /* read until bits field is 0 */ + for (;;) { + read_next_field(fd, &dbits, fname, "DH bits"); + + if (dbits.size != sizeof(int)) { + (void)unlink(fname); + i_fatal("Corrupted SSL parameter file %s: " + "Field 'DH bits' has invalid size %u", + fname, dbits.size); + } + + bits = *((int *) dbits.data); + if (bits == 0) + break; + + read_next_field(fd, &prime, fname, "DH prime"); + read_next_field(fd, &generator, fname, "DH generator"); + + ret = gnutls_dh_params_set(dh_params, prime, generator, bits); + if (ret < 0) { + i_fatal("gnutls_dh_params_set() failed: %s", + gnutls_strerror(ret)); + } + } +} + +static void read_rsa_parameters(int fd, const char *fname) +{ + gnutls_datum m, e, d, p, q, u; + int ret; + + read_next_field(fd, &m, fname, "RSA m"); + read_next_field(fd, &e, fname, "RSA e"); + read_next_field(fd, &d, fname, "RSA d"); + read_next_field(fd, &p, fname, "RSA p"); + read_next_field(fd, &q, fname, "RSA q"); + read_next_field(fd, &u, fname, "RSA u"); + + if ((ret = gnutls_rsa_params_init(&rsa_params)) < 0) { + i_fatal("gnutls_rsa_params_init() failed: %s", + gnutls_strerror(ret)); + } + + /* only 512bit is allowed */ + ret = gnutls_rsa_params_set(rsa_params, m, e, d, p, q, u, 512); + if (ret < 0) { + i_fatal("gnutls_rsa_params_set() failed: %s", + gnutls_strerror(ret)); + } +} + +static void read_parameters(const char *fname) +{ + int fd; + + /* we'll wait until parameter file exists */ + for (;;) { + fd = open(fname, O_RDONLY); + if (fd != -1) + break; + + if (errno != ENOENT) + i_fatal("Can't open SSL parameter file %s: %m", fname); + + sleep(1); + } + + read_dh_parameters(fd, fname); + read_rsa_parameters(fd, fname); + + (void)close(fd); +} + +static void gcrypt_log_handler(void *context __attr_unused__, int level, + const char *fmt, va_list args) +{ + char *buf; + + t_push(); + + buf = t_malloc(printf_string_upper_bound(fmt, args)); + vsprintf(buf, fmt, args); + + if (level == GCRY_LOG_FATAL) + i_error("gcrypt fatal: %s", buf); + + t_pop(); +} + +void ssl_proxy_init(void) +{ + const char *certfile, *keyfile, *paramfile; + char buf[4]; + int ret; + + certfile = getenv("SSL_CERT_FILE"); + keyfile = getenv("SSL_KEY_FILE"); + paramfile = getenv("SSL_PARAM_FILE"); + + if (certfile == NULL || keyfile == NULL || paramfile == NULL) { + /* SSL support is disabled */ + return; + } + + if ((ret = gnutls_global_init() < 0)) { + i_fatal("gnu_tls_global_init() failed: %s", + gnutls_strerror(ret)); + } + + /* gcrypt initialization - set log handler and make sure randomizer + opens /dev/urandom now instead of after we've chrooted */ + gcry_set_log_handler(gcrypt_log_handler, NULL); + gcry_randomize(buf, sizeof(buf), GCRY_STRONG_RANDOM); + + read_parameters(paramfile); + + if ((ret = gnutls_certificate_allocate_cred(&x509_cred)) < 0) { + i_fatal("gnutls_certificate_allocate_cred() failed: %s", + gnutls_strerror(ret)); + } + + ret = gnutls_certificate_set_x509_key_file(x509_cred, certfile, keyfile, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + i_fatal("Can't load certificate files %s and %s: %s", + certfile, keyfile, gnutls_strerror(ret)); + } + + ret = gnutls_certificate_set_dh_params(x509_cred, dh_params); + if (ret < 0) + i_fatal("Can't set DH parameters: %s", gnutls_strerror(ret)); + ret = gnutls_certificate_set_rsa_params(x509_cred, rsa_params); + if (ret < 0) + i_fatal("Can't set RSA parameters: %s", gnutls_strerror(ret)); + + ssl_initialized = TRUE; +} + +void ssl_proxy_deinit(void) +{ + if (ssl_initialized) { + gnutls_certificate_free_cred(x509_cred); + gnutls_global_deinit(); + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/login/ssl-proxy-openssl.c Wed Nov 20 16:05:13 2002 +0200 @@ -0,0 +1,376 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "ioloop.h" +#include "network.h" +#include "ssl-proxy.h" + +#ifdef HAVE_OPENSSL + +#include <openssl/crypto.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/err.h> + +typedef enum { + SSL_STATE_HANDSHAKE, + SSL_STATE_READ, + SSL_STATE_WRITE +} SSLState; + +typedef struct { + int refcount; + + SSL *ssl; + SSLState state; + + int fd_ssl, fd_plain; + IO io_ssl, io_plain_read, io_plain_write; + int io_ssl_dir; + + unsigned char plainout_buf[1024]; + unsigned int plainout_pos, plainout_size; + + unsigned char sslout_buf[1024]; + unsigned int sslout_pos, sslout_size; +} SSLProxy; + +static SSL_CTX *ssl_ctx; + +static void plain_read(SSLProxy *proxy); +static void plain_write(SSLProxy *proxy); + +static int ssl_proxy_destroy(SSLProxy *proxy); +static void ssl_set_direction(SSLProxy *proxy, int dir); + +static void plain_block_input(SSLProxy *proxy, int block) +{ + if (block) { + if (proxy->io_plain_read != NULL) { + io_remove(proxy->io_plain_read); + proxy->io_plain_read = NULL; + } + } else { + if (proxy->io_plain_read == NULL) { + proxy->io_plain_read = + io_add(proxy->fd_plain, IO_READ, + (IOFunc) plain_read, proxy); + } + } +} + +static void ssl_block(SSLProxy *proxy, int block) +{ + i_assert(proxy->state == SSL_STATE_READ); + + if (block) { + if (proxy->io_ssl != NULL) { + io_remove(proxy->io_ssl); + proxy->io_ssl = NULL; + } + + proxy->io_ssl_dir = -2; + } else { + proxy->io_ssl_dir = -1; + ssl_set_direction(proxy, IO_READ); + } +} + +static void plain_read(SSLProxy *proxy) +{ + ssize_t ret; + + i_assert(proxy->sslout_size == 0); + + ret = net_receive(proxy->fd_plain, proxy->sslout_buf, + sizeof(proxy->sslout_buf)); + if (ret < 0) + ssl_proxy_destroy(proxy); + else { + proxy->sslout_size = ret; + proxy->sslout_pos = 0; + + proxy->state = SSL_STATE_WRITE; + ssl_set_direction(proxy, IO_WRITE); + + plain_block_input(proxy, TRUE); + } +} + +static void plain_write(SSLProxy *proxy) +{ + ssize_t ret; + + ret = net_transmit(proxy->fd_plain, + proxy->plainout_buf + proxy->plainout_pos, + proxy->plainout_size); + if (ret < 0) + ssl_proxy_destroy(proxy); + else { + proxy->plainout_size -= ret; + proxy->plainout_pos += ret; + + if (proxy->plainout_size > 0) { + ssl_block(proxy, TRUE); + if (proxy->io_plain_write == NULL) { + proxy->io_plain_write = + io_add(proxy->fd_plain, IO_WRITE, + (IOFunc) plain_write, proxy); + } + } else { + proxy->plainout_pos = 0; + ssl_block(proxy, FALSE); + + if (proxy->io_plain_write != NULL) { + io_remove(proxy->io_plain_write); + proxy->io_plain_write = NULL; + } + } + } + +} + +const char *ssl_last_error(void) +{ + unsigned long err; + char *buf; + + err = ERR_get_error(); + if (err == 0) + return strerror(errno); + + buf = t_malloc(256); + buf[255] = '\0'; + ERR_error_string_n(err, buf, 255); + return buf; +} + +static void ssl_handle_error(SSLProxy *proxy, int err, const char *func) +{ + err = SSL_get_error(proxy->ssl, err); + switch (err) { + case SSL_ERROR_WANT_READ: + ssl_set_direction(proxy, IO_READ); + break; + case SSL_ERROR_WANT_WRITE: + ssl_set_direction(proxy, IO_WRITE); + break; + case SSL_ERROR_SYSCALL: + /* eat up the error queue */ + i_error("%s failed: %s", func, ssl_last_error()); + ssl_proxy_destroy(proxy); + break; + case SSL_ERROR_ZERO_RETURN: + /* clean connection closing */ + default: + ssl_proxy_destroy(proxy); + break; + } +} + +static void ssl_handshake_step(SSLProxy *proxy) +{ + int ret; + + ret = SSL_accept(proxy->ssl); + if (ret != 1) { + plain_block_input(proxy, TRUE); + ssl_handle_error(proxy, ret, "SSL_accept()"); + } else { + plain_block_input(proxy, FALSE); + ssl_set_direction(proxy, IO_READ); + proxy->state = SSL_STATE_READ; + } +} + +static void ssl_read_step(SSLProxy *proxy) +{ + int ret; + + i_assert(proxy->plainout_size == 0); + + ret = SSL_read(proxy->ssl, proxy->plainout_buf, + sizeof(proxy->plainout_buf)); + if (ret <= 0) { + plain_block_input(proxy, TRUE); + ssl_handle_error(proxy, ret, "SSL_read()"); + } else { + plain_block_input(proxy, FALSE); + ssl_set_direction(proxy, IO_READ); + + proxy->plainout_pos = 0; + proxy->plainout_size = ret; + plain_write(proxy); + } +} + +static void ssl_write_step(SSLProxy *proxy) +{ + int ret; + + ret = SSL_write(proxy->ssl, proxy->sslout_buf + proxy->sslout_pos, + proxy->sslout_size); + if (ret <= 0) { + plain_block_input(proxy, TRUE); + ssl_handle_error(proxy, ret, "SSL_write()"); + } else { + proxy->sslout_size -= ret; + proxy->sslout_pos += ret; + + if (proxy->sslout_size > 0) { + plain_block_input(proxy, TRUE); + ssl_set_direction(proxy, IO_WRITE); + proxy->state = SSL_STATE_WRITE; + } else { + plain_block_input(proxy, FALSE); + ssl_set_direction(proxy, IO_READ); + proxy->state = SSL_STATE_READ; + proxy->sslout_pos = 0; + } + } +} + +static void ssl_step(void *context, int fd __attr_unused__, + IO io __attr_unused__) +{ + SSLProxy *proxy = context; + + switch (proxy->state) { + case SSL_STATE_HANDSHAKE: + ssl_handshake_step(proxy); + break; + case SSL_STATE_READ: + ssl_read_step(proxy); + break; + case SSL_STATE_WRITE: + ssl_write_step(proxy); + break; + } +} + +static void ssl_set_direction(SSLProxy *proxy, int dir) +{ + i_assert(proxy->io_ssl_dir != -2); + + if (proxy->io_ssl_dir == dir) + return; + + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + proxy->io_ssl = io_add(proxy->fd_ssl, dir, ssl_step, proxy); +} + +int ssl_proxy_new(int fd) +{ + SSLProxy *proxy; + SSL *ssl; + int sfd[2]; + + if (!ssl_initialized) + return -1; + + ssl = SSL_new(ssl_ctx); + if (ssl == NULL) { + i_error("SSL_new() failed: %s", ssl_last_error()); + return -1; + } + + SSL_set_accept_state(ssl); + if (SSL_set_fd(ssl, fd) != 1) { + i_error("SSL_set_fd() failed: %s", ssl_last_error()); + return -1; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { + i_error("socketpair() failed: %m"); + SSL_free(ssl); + return -1; + } + + net_set_nonblock(sfd[0], TRUE); + net_set_nonblock(sfd[1], TRUE); + + proxy = i_new(SSLProxy, 1); + proxy->refcount = 1; + proxy->ssl = ssl; + proxy->fd_ssl = fd; + proxy->fd_plain = sfd[0]; + + proxy->state = SSL_STATE_HANDSHAKE; + ssl_set_direction(proxy, IO_READ); + + proxy->refcount++; + ssl_handshake_step(proxy); + if (!ssl_proxy_destroy(proxy)) + return -1; + + main_ref(); + return sfd[1]; +} + +static int ssl_proxy_destroy(SSLProxy *proxy) +{ + if (--proxy->refcount > 0) + return TRUE; + + SSL_free(proxy->ssl); + + (void)net_disconnect(proxy->fd_ssl); + (void)net_disconnect(proxy->fd_plain); + + if (proxy->io_ssl != NULL) + io_remove(proxy->io_ssl); + if (proxy->io_plain_read != NULL) + io_remove(proxy->io_plain_read); + if (proxy->io_plain_write != NULL) + io_remove(proxy->io_plain_write); + + i_free(proxy); + + main_unref(); + return FALSE; +} + +void ssl_proxy_init(void) +{ + const char *certfile, *keyfile, *paramfile; + int ret; + + certfile = getenv("SSL_CERT_FILE"); + keyfile = getenv("SSL_KEY_FILE"); + paramfile = getenv("SSL_PARAM_FILE"); + + if (certfile == NULL || keyfile == NULL || paramfile == NULL) { + /* SSL support is disabled */ + return; + } + + SSL_library_init(); + SSL_load_error_strings(); + + if ((ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) + i_fatal("SSL_CTX_new() failed"); + + ret = SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile); + if (ret != 1) { + i_fatal("Can't load certificate file %s: %s", + certfile, ssl_last_error()); + } + + ret = SSL_CTX_use_PrivateKey_file(ssl_ctx, keyfile, SSL_FILETYPE_PEM); + if (ret != 1) { + i_fatal("Can't load private key file %s: %s", + keyfile, ssl_last_error()); + } + + ssl_initialized = TRUE; +} + +void ssl_proxy_deinit(void) +{ + if (ssl_initialized) + SSL_CTX_free(ssl_ctx); +} + +#endif
--- a/src/login/ssl-proxy.c Wed Nov 20 16:04:04 2002 +0200 +++ b/src/login/ssl-proxy.c Wed Nov 20 16:05:13 2002 +0200 @@ -1,526 +1,10 @@ /* Copyright (C) 2002 Timo Sirainen */ -#include "common.h" -#include "ioloop.h" -#include "network.h" -#include "ssl-proxy.h" +#include "lib.h" int ssl_initialized = FALSE; -#ifdef HAVE_SSL - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <gcrypt.h> -#include <gnutls/gnutls.h> - -typedef struct { - int refcount; - - gnutls_session session; - int fd_ssl, fd_plain; - IO io_ssl, io_plain; - int io_ssl_dir; - - unsigned char outbuf_plain[1024]; - unsigned int outbuf_pos_plain; - - size_t send_left_ssl, send_left_plain; -} SSLProxy; - -const int protocol_priority[] = - { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; -const int kx_priority[] = - { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 }; -const int cipher_priority[] = - { GNUTLS_CIPHER_RIJNDAEL_CBC, GNUTLS_CIPHER_3DES_CBC, - GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_ARCFOUR_40, 0 }; -const int comp_priority[] = - { GNUTLS_COMP_LZO, GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; -const int mac_priority[] = - { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 }; -const int cert_type_priority[] = - { GNUTLS_CRT_X509, 0 }; - -static gnutls_certificate_credentials x509_cred; -static gnutls_dh_params dh_params; -static gnutls_rsa_params rsa_params; - -static void ssl_input(void *context, int handle, IO io); -static void plain_input(void *context, int handle, IO io); -static int ssl_proxy_destroy(SSLProxy *proxy); - -static const char *get_alert_text(SSLProxy *proxy) -{ - return gnutls_alert_get_name(gnutls_alert_get(proxy->session)); -} - -static int handle_ssl_error(SSLProxy *proxy, int error) -{ - if (!gnutls_error_is_fatal(error)) { - if (error == GNUTLS_E_WARNING_ALERT_RECEIVED) { - i_warning("Received SSL warning alert: %s", - get_alert_text(proxy)); - } - return 0; - } - - /* fatal error occured */ - if (error == GNUTLS_E_FATAL_ALERT_RECEIVED) { - i_warning("Received SSL fatal alert: %s", - get_alert_text(proxy)); - } else { - i_warning("Error reading from SSL client: %s", - gnutls_strerror(error)); - } - - gnutls_alert_send_appropriate(proxy->session, error); - ssl_proxy_destroy(proxy); - return -1; -} - -static int proxy_recv_ssl(SSLProxy *proxy, void *data, size_t size) -{ - int rcvd; - - rcvd = gnutls_record_recv(proxy->session, data, size); - if (rcvd > 0) - return rcvd; - - if (rcvd == 0 || rcvd == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) { - /* disconnected, either by nicely telling us that we'll - close the connection, or by simply killing the - connection which gives us the packet length error. */ - ssl_proxy_destroy(proxy); - return -1; - } - - return handle_ssl_error(proxy, rcvd); -} - -static int proxy_send_ssl(SSLProxy *proxy, const void *data, size_t size) -{ - int sent; - - sent = gnutls_record_send(proxy->session, data, size); - if (sent >= 0) - return sent; - - if (sent == GNUTLS_E_PUSH_ERROR || sent == GNUTLS_E_INVALID_SESSION) { - /* don't warn about errors related to unexpected disconnection */ - ssl_proxy_destroy(proxy); - return -1; - } - - return handle_ssl_error(proxy, sent); -} - -static int ssl_proxy_destroy(SSLProxy *proxy) -{ - if (--proxy->refcount > 0) - return TRUE; - - gnutls_deinit(proxy->session); - - (void)net_disconnect(proxy->fd_ssl); - (void)net_disconnect(proxy->fd_plain); - - if (proxy->io_ssl != NULL) - io_remove(proxy->io_ssl); - if (proxy->io_plain != NULL) - io_remove(proxy->io_plain); - - i_free(proxy); - - main_unref(); - return FALSE; -} - -static void ssl_output(void *context, int fd __attr_unused__, - IO io __attr_unused__) -{ - SSLProxy *proxy = context; - int sent; - - sent = net_transmit(proxy->fd_plain, - proxy->outbuf_plain + proxy->outbuf_pos_plain, - proxy->send_left_plain); - if (sent < 0) { - /* disconnected */ - ssl_proxy_destroy(proxy); - return; - } - - proxy->send_left_plain -= sent; - proxy->outbuf_pos_plain += sent; - - if (proxy->send_left_plain > 0) - return; - - /* everything is sent, start reading again */ - io_remove(proxy->io_ssl); - proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy); -} - -static void ssl_input(void *context, int fd __attr_unused__, - IO io __attr_unused__) -{ - SSLProxy *proxy = context; - int rcvd, sent; - - rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain, - sizeof(proxy->outbuf_plain)); - if (rcvd <= 0) - return; - - sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd); - if (sent == rcvd) - return; - - if (sent < 0) { - /* disconnected */ - ssl_proxy_destroy(proxy); - return; - } - - /* everything wasn't sent - don't read anything until we've - sent it all */ - proxy->outbuf_pos_plain = 0; - proxy->send_left_plain = rcvd - sent; - - io_remove(proxy->io_ssl); - proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy); -} - -static void plain_output(void *context, int fd __attr_unused__, - IO io __attr_unused__) -{ - SSLProxy *proxy = context; - int sent; - - sent = proxy_send_ssl(proxy, NULL, proxy->send_left_ssl); - if (sent <= 0) - return; - - proxy->send_left_ssl -= sent; - if (proxy->send_left_ssl > 0) - return; - - /* everything is sent, start reading again */ - io_remove(proxy->io_plain); - proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy); -} - -static void plain_input(void *context, int fd __attr_unused__, - IO io __attr_unused__) -{ - SSLProxy *proxy = context; - char buf[1024]; - ssize_t rcvd, sent; - - rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf)); - if (rcvd < 0) { - /* disconnected */ - gnutls_bye(proxy->session, 1); - ssl_proxy_destroy(proxy); - return; - } - - sent = proxy_send_ssl(proxy, buf, (size_t)rcvd); - if (sent < 0 || sent == rcvd) - return; - - /* everything wasn't sent - don't read anything until we've - sent it all */ - proxy->send_left_ssl = rcvd - sent; - - io_remove(proxy->io_plain); - proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy); -} - -static void ssl_handshake(void *context, int fd __attr_unused__, - IO io __attr_unused__) -{ - SSLProxy *proxy = context; - int ret, dir; - - ret = gnutls_handshake(proxy->session); - if (ret >= 0) { - /* handshake done, now we can start reading */ - if (proxy->io_ssl != NULL) - io_remove(proxy->io_ssl); - - proxy->io_plain = io_add(proxy->fd_plain, IO_READ, - plain_input, proxy); - proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, - ssl_input, proxy); - return; - } - - if (handle_ssl_error(proxy, ret) < 0) - return; - - /* i/o interrupted */ - dir = gnutls_handshake_get_direction(proxy->session) == 0 ? - IO_READ : IO_WRITE; - if (proxy->io_ssl_dir != dir) { - if (proxy->io_ssl != NULL) - io_remove(proxy->io_ssl); - proxy->io_ssl = io_add(proxy->fd_ssl, dir, - ssl_handshake, proxy); - proxy->io_ssl_dir = dir; - } -} - -static gnutls_session initialize_state(void) -{ - gnutls_session session; - - gnutls_init(&session, GNUTLS_SERVER); - - gnutls_protocol_set_priority(session, protocol_priority); - gnutls_cipher_set_priority(session, cipher_priority); - gnutls_compression_set_priority(session, comp_priority); - gnutls_kx_set_priority(session, kx_priority); - gnutls_mac_set_priority(session, mac_priority); - gnutls_cert_type_set_priority(session, cert_type_priority); - - gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred); - return session; -} - -int ssl_proxy_new(int fd) -{ - SSLProxy *proxy; - gnutls_session session; - int sfd[2]; - - if (!ssl_initialized) - return -1; - - session = initialize_state(); - gnutls_transport_set_ptr(session, fd); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { - i_error("socketpair() failed: %m"); - gnutls_deinit(session); - return -1; - } - - net_set_nonblock(sfd[0], TRUE); - net_set_nonblock(sfd[1], TRUE); - - proxy = i_new(SSLProxy, 1); - proxy->refcount = 1; - proxy->session = session; - proxy->fd_ssl = fd; - proxy->fd_plain = sfd[0]; - - proxy->refcount++; - ssl_handshake(proxy, -1, NULL); - if (!ssl_proxy_destroy(proxy)) - return -1; - - main_ref(); - return sfd[1]; -} - -static void read_next_field(int fd, gnutls_datum *datum, - const char *fname, const char *field_name) -{ - ssize_t ret; - - /* get size */ - ret = read(fd, &datum->size, sizeof(datum->size)); - if (ret < 0) - i_fatal("read() failed for %s: %m", fname); - - if (ret != sizeof(datum->size)) { - (void)unlink(fname); - i_fatal("Corrupted SSL parameter file %s: File too small", - fname); - } - - if (datum->size > 10240) { - (void)unlink(fname); - i_fatal("Corrupted SSL parameter file %s: " - "Field '%s' too large (%u)", - fname, field_name, datum->size); - } - - /* read the actual data */ - datum->data = t_malloc(datum->size); - ret = read(fd, datum->data, datum->size); - if (ret < 0) - i_fatal("read() failed for %s: %m", fname); - - if ((size_t)ret != datum->size) { - (void)unlink(fname); - i_fatal("Corrupted SSL parameter file %s: " - "Field '%s' not fully in file (%u < %u)", - fname, field_name, datum->size - ret, datum->size); - } -} - -static void read_dh_parameters(int fd, const char *fname) -{ - gnutls_datum dbits, prime, generator; - int ret, bits; - - if ((ret = gnutls_dh_params_init(&dh_params)) < 0) { - i_fatal("gnutls_dh_params_init() failed: %s", - gnutls_strerror(ret)); - } - - /* read until bits field is 0 */ - for (;;) { - read_next_field(fd, &dbits, fname, "DH bits"); - - if (dbits.size != sizeof(int)) { - (void)unlink(fname); - i_fatal("Corrupted SSL parameter file %s: " - "Field 'DH bits' has invalid size %u", - fname, dbits.size); - } - - bits = *((int *) dbits.data); - if (bits == 0) - break; - - read_next_field(fd, &prime, fname, "DH prime"); - read_next_field(fd, &generator, fname, "DH generator"); - - ret = gnutls_dh_params_set(dh_params, prime, generator, bits); - if (ret < 0) { - i_fatal("gnutls_dh_params_set() failed: %s", - gnutls_strerror(ret)); - } - } -} - -static void read_rsa_parameters(int fd, const char *fname) -{ - gnutls_datum m, e, d, p, q, u; - int ret; - - read_next_field(fd, &m, fname, "RSA m"); - read_next_field(fd, &e, fname, "RSA e"); - read_next_field(fd, &d, fname, "RSA d"); - read_next_field(fd, &p, fname, "RSA p"); - read_next_field(fd, &q, fname, "RSA q"); - read_next_field(fd, &u, fname, "RSA u"); - - if ((ret = gnutls_rsa_params_init(&rsa_params)) < 0) { - i_fatal("gnutls_rsa_params_init() failed: %s", - gnutls_strerror(ret)); - } - - /* only 512bit is allowed */ - ret = gnutls_rsa_params_set(rsa_params, m, e, d, p, q, u, 512); - if (ret < 0) { - i_fatal("gnutls_rsa_params_set() failed: %s", - gnutls_strerror(ret)); - } -} - -static void read_parameters(const char *fname) -{ - int fd; - - /* we'll wait until parameter file exists */ - for (;;) { - fd = open(fname, O_RDONLY); - if (fd != -1) - break; - - if (errno != ENOENT) - i_fatal("Can't open SSL parameter file %s: %m", fname); - - sleep(1); - } - - read_dh_parameters(fd, fname); - read_rsa_parameters(fd, fname); - - (void)close(fd); -} - -static void gcrypt_log_handler(void *context __attr_unused__, int level, - const char *fmt, va_list args) -{ - char *buf; - - t_push(); - - buf = t_malloc(printf_string_upper_bound(fmt, args)); - vsprintf(buf, fmt, args); - - if (level == GCRY_LOG_FATAL) - i_error("gcrypt fatal: %s", buf); - - t_pop(); -} - -void ssl_proxy_init(void) -{ - const char *certfile, *keyfile, *paramfile; - char buf[4]; - int ret; - - certfile = getenv("SSL_CERT_FILE"); - keyfile = getenv("SSL_KEY_FILE"); - paramfile = getenv("SSL_PARAM_FILE"); - - if (certfile == NULL || keyfile == NULL || paramfile == NULL) { - /* SSL support is disabled */ - return; - } - - if ((ret = gnutls_global_init() < 0)) { - i_fatal("gnu_tls_global_init() failed: %s", - gnutls_strerror(ret)); - } - - /* gcrypt initialization - set log handler and make sure randomizer - opens /dev/urandom now instead of after we've chrooted */ - gcry_set_log_handler(gcrypt_log_handler, NULL); - gcry_randomize(buf, sizeof(buf), GCRY_STRONG_RANDOM); - - read_parameters(paramfile); - - if ((ret = gnutls_certificate_allocate_cred(&x509_cred)) < 0) { - i_fatal("gnutls_certificate_allocate_cred() failed: %s", - gnutls_strerror(ret)); - } - - ret = gnutls_certificate_set_x509_key_file(x509_cred, certfile, keyfile, - GNUTLS_X509_FMT_PEM); - if (ret < 0) { - i_fatal("Can't load certificate files %s and %s: %s", - certfile, keyfile, gnutls_strerror(ret)); - } - - ret = gnutls_certificate_set_dh_params(x509_cred, dh_params); - if (ret < 0) - i_fatal("Can't set DH parameters: %s", gnutls_strerror(ret)); - ret = gnutls_certificate_set_rsa_params(x509_cred, rsa_params); - if (ret < 0) - i_fatal("Can't set RSA parameters: %s", gnutls_strerror(ret)); - - ssl_initialized = TRUE; -} - -void ssl_proxy_deinit(void) -{ - if (ssl_initialized) { - gnutls_certificate_free_cred(x509_cred); - gnutls_global_deinit(); - } -} - -#else +#ifndef HAVE_SSL /* no SSL support */
--- a/src/master/Makefile.am Wed Nov 20 16:04:04 2002 +0200 +++ b/src/master/Makefile.am Wed Nov 20 16:05:13 2002 +0200 @@ -16,7 +16,9 @@ login-process.c \ main.c \ settings.c \ - ssl-init.c + ssl-init.c \ + ssl-init-gnutls.c \ + ssl-init-openssl.c noinst_HEADERS = \ auth-process.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/master/ssl-init-gnutls.c Wed Nov 20 16:05:13 2002 +0200 @@ -0,0 +1,85 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "write-full.h" +#include "ssl-init.h" + +#ifdef HAVE_GNUTLS + +#include <gnutls/gnutls.h> + +static int prime_nums[] = { 768, 1024, 0 }; + +static void write_datum(int fd, const char *fname, gnutls_datum *dbits) +{ + if (write_full(fd, &dbits->size, sizeof(dbits->size)) < 0) + i_fatal("write_full() failed for file %s: %m", fname); + + if (write_full(fd, dbits->data, dbits->size) < 0) + i_fatal("write_full() failed for file %s: %m", fname); +} + +static void generate_dh_parameters(int fd, const char *fname) +{ + gnutls_datum dbits, prime, generator; + int ret, bits, i; + + dbits.size = sizeof(bits); + dbits.data = (unsigned char *) &bits; + + for (i = 0; prime_nums[i] != 0; i++) { + bits = prime_nums[i]; + + ret = gnutls_dh_params_generate(&prime, &generator, bits); + if (ret < 0) { + i_fatal("gnutls_dh_params_generate(%d) failed: %s", + bits, gnutls_strerror(ret)); + } + + write_datum(fd, fname, &dbits); + write_datum(fd, fname, &prime); + write_datum(fd, fname, &generator); + + free(prime.data); + free(generator.data); + } + + bits = 0; + write_datum(fd, fname, &dbits); +} + +static void generate_rsa_parameters(int fd, const char *fname) +{ + gnutls_datum m, e, d, p, q, u; + int ret; + + ret = gnutls_rsa_params_generate(&m, &e, &d, &p, &q, &u, 512); + if (ret < 0) { + i_fatal("gnutls_rsa_params_generate() faile: %s", + strerror(ret)); + } + + write_datum(fd, fname, &m); + write_datum(fd, fname, &e); + write_datum(fd, fname, &d); + write_datum(fd, fname, &p); + write_datum(fd, fname, &q); + write_datum(fd, fname, &u); +} + +void _ssl_generate_parameters(int fd, const char *fname) +{ + int ret; + + if ((ret = gnutls_global_init() < 0)) { + i_fatal("gnu_tls_global_init() failed: %s", + gnutls_strerror(ret)); + } + + generate_dh_parameters(fd, temp_fname); + generate_rsa_parameters(fd, temp_fname); + + gnutls_global_deinit(); +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/master/ssl-init-openssl.c Wed Nov 20 16:05:13 2002 +0200 @@ -0,0 +1,12 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "common.h" +#include "ssl-init.h" + +#ifdef HAVE_OPENSSL + +void _ssl_generate_parameters(int fd, const char *fname) +{ +} + +#endif
--- a/src/master/ssl-init.c Wed Nov 20 16:04:04 2002 +0200 +++ b/src/master/ssl-init.c Wed Nov 20 16:05:13 2002 +0200 @@ -2,88 +2,22 @@ #include "common.h" #include "ioloop.h" -#include "write-full.h" +#include "ssl-init.h" #ifdef HAVE_SSL #include <stdio.h> -#include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> -#include <gnutls/gnutls.h> - -static int prime_nums[] = { 768, 1024, 0 }; static Timeout to; static int generating; -static void write_datum(int fd, const char *fname, gnutls_datum *dbits) -{ - if (write_full(fd, &dbits->size, sizeof(dbits->size)) < 0) - i_fatal("write_full() failed for file %s: %m", fname); - - if (write_full(fd, dbits->data, dbits->size) < 0) - i_fatal("write_full() failed for file %s: %m", fname); -} - -static void generate_dh_parameters(int fd, const char *fname) -{ - gnutls_datum dbits, prime, generator; - int ret, bits, i; - - dbits.size = sizeof(bits); - dbits.data = (unsigned char *) &bits; - - for (i = 0; prime_nums[i] != 0; i++) { - bits = prime_nums[i]; - - ret = gnutls_dh_params_generate(&prime, &generator, bits); - if (ret < 0) { - i_fatal("gnutls_dh_params_generate(%d) failed: %s", - bits, gnutls_strerror(ret)); - } - - write_datum(fd, fname, &dbits); - write_datum(fd, fname, &prime); - write_datum(fd, fname, &generator); - - free(prime.data); - free(generator.data); - } - - bits = 0; - write_datum(fd, fname, &dbits); -} - -static void generate_rsa_parameters(int fd, const char *fname) -{ - gnutls_datum m, e, d, p, q, u; - int ret; - - ret = gnutls_rsa_params_generate(&m, &e, &d, &p, &q, &u, 512); - if (ret < 0) { - i_fatal("gnutls_rsa_params_generate() faile: %s", - strerror(ret)); - } - - write_datum(fd, fname, &m); - write_datum(fd, fname, &e); - write_datum(fd, fname, &d); - write_datum(fd, fname, &p); - write_datum(fd, fname, &q); - write_datum(fd, fname, &u); -} - static void generate_parameters_file(const char *fname) { const char *temp_fname; - int fd, ret; - - if ((ret = gnutls_global_init() < 0)) { - i_fatal("gnu_tls_global_init() failed: %s", - gnutls_strerror(ret)); - } + int fd; temp_fname = t_strconcat(fname, ".tmp", NULL); (void)unlink(temp_fname); @@ -94,16 +28,13 @@ temp_fname); } - generate_dh_parameters(fd, temp_fname); - generate_rsa_parameters(fd, temp_fname); + _ssl_generate_parameters(fd, temp_fname); if (close(fd) < 0) i_fatal("close() failed for %s: %m", temp_fname); if (rename(temp_fname, fname) < 0) i_fatal("rename(%s, %s) failed: %m", temp_fname, fname); - - gnutls_global_deinit(); } static void start_generate_process(void) @@ -171,16 +102,8 @@ #else -void ssl_parameter_process_destroyed(pid_t pid __attr_unused__) -{ -} - -void ssl_init(void) -{ -} - -void ssl_deinit(void) -{ -} +void ssl_parameter_process_destroyed(pid_t pid __attr_unused__) {} +void ssl_init(void) {} +void ssl_deinit(void) {} #endif