ssl-proxy-gnutls.c revision 7cb128dc4cae2a03a742f63ba7afee23c78e3af0
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen { GNUTLS_CIPHER_RIJNDAEL_CBC, GNUTLS_CIPHER_3DES_CBC,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_ARCFOUR_40, 0 };
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen { GNUTLS_COMP_LZO, GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic gnutls_certificate_credentials x509_cred;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic void ssl_input(struct ssl_proxy *proxy);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic void plain_input(struct ssl_proxy *proxy);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic bool ssl_proxy_destroy(struct ssl_proxy *proxy);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic const char *get_alert_text(struct ssl_proxy *proxy)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return gnutls_alert_get_name(gnutls_alert_get(proxy->session));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic int handle_ssl_error(struct ssl_proxy *proxy, int error)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (error == GNUTLS_E_WARNING_ALERT_RECEIVED) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_warning("Received SSL warning alert: %s [%s]",
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen /* fatal error occurred */
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen i_warning("Received SSL fatal alert: %s [%s]",
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_warning("Error reading from SSL client: %s [%s]",
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_alert_send_appropriate(proxy->session, error);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic int proxy_recv_ssl(struct ssl_proxy *proxy, void *data, size_t size)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen rcvd = gnutls_record_recv(proxy->session, data, size);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (rcvd == 0 || rcvd == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* disconnected, either by nicely telling us that we'll
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen close the connection, or by simply killing the
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen connection which gives us the packet length error. */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic int proxy_send_ssl(struct ssl_proxy *proxy,
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody sent = gnutls_record_send(proxy->session, data, size);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (sent == GNUTLS_E_PUSH_ERROR || sent == GNUTLS_E_INVALID_SESSION) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* don't warn about errors related to unexpected
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen disconnection */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic int ssl_proxy_destroy(struct ssl_proxy *proxy)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic void ssl_output(struct ssl_proxy *proxy)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen proxy->outbuf_plain + proxy->outbuf_pos_plain,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* disconnected */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* everything is sent, start reading again */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* disconnected */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* everything wasn't sent - don't read anything until we've
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen sent it all */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic void plain_output(struct ssl_proxy *proxy)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen sent = proxy_send_ssl(proxy, NULL, proxy->send_left_ssl);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* everything is sent, start reading again */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic void plain_input(struct ssl_proxy *proxy)
8855b8b57050fe3b6dc3f19283488512fae98648Timo Sirainen rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* disconnected */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch sent = proxy_send_ssl(proxy, buf, (size_t)rcvd);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch /* everything wasn't sent - don't read anything until we've
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch sent it all */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic void ssl_handshake(struct ssl_proxy *proxy)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* handshake done, now we can start reading */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch proxy->io_plain = io_add(proxy->fd_plain, IO_READ,
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ,
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch /* i/o interrupted */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch dir = gnutls_record_get_direction(proxy->session) == 0 ?
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_protocol_set_priority(session, protocol_priority);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_cipher_set_priority(session, cipher_priority);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_compression_set_priority(session, comp_priority);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_mac_set_priority(session, mac_priority);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_certificate_type_set_priority(session, cert_type_priority);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch i_error("SSL support not enabled in configuration");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* handshake failed. return the disconnected socket anyway
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen so the caller doesn't try to use the old closed fd */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic void read_next_field(int fd, gnutls_datum *datum,
if (ret < 0)
fname);
if (ret < 0)
if (bits == 0)
if (ret < 0) {
gnutls_datum m, e, d, p, q, u;
int ret;
if (ret < 0) {
int fd;
T_BEGIN {
} T_END;
void ssl_proxy_init(void)
int ret;
if (ret < 0) {
void ssl_proxy_deinit(void)
if (!ssl_initialized)