ssl-proxy-gnutls.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen { GNUTLS_CIPHER_RIJNDAEL_CBC, GNUTLS_CIPHER_3DES_CBC,
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_ARCFOUR_40, 0 };
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen { GNUTLS_COMP_LZO, GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic gnutls_certificate_credentials x509_cred;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void ssl_input(struct ssl_proxy *proxy);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic void plain_input(struct ssl_proxy *proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic bool ssl_proxy_destroy(struct ssl_proxy *proxy);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic const char *get_alert_text(struct ssl_proxy *proxy)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return gnutls_alert_get_name(gnutls_alert_get(proxy->session));
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainenstatic int handle_ssl_error(struct ssl_proxy *proxy, int error)
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen if (error == GNUTLS_E_WARNING_ALERT_RECEIVED) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen i_warning("Received SSL warning alert: %s [%s]",
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* fatal error occurred */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_warning("Received SSL fatal alert: %s [%s]",
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_warning("Error reading from SSL client: %s [%s]",
b04e691711fd026fc82ba3e0b411420e7da4ec7eTimo Sirainen gnutls_alert_send_appropriate(proxy->session, error);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int proxy_recv_ssl(struct ssl_proxy *proxy, void *data, size_t size)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen rcvd = gnutls_record_recv(proxy->session, data, size);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (rcvd == 0 || rcvd == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* disconnected, either by nicely telling us that we'll
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen close the connection, or by simply killing the
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen connection which gives us the packet length error. */
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainenstatic int proxy_send_ssl(struct ssl_proxy *proxy,
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen sent = gnutls_record_send(proxy->session, data, size);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (sent == GNUTLS_E_PUSH_ERROR || sent == GNUTLS_E_INVALID_SESSION) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen /* don't warn about errors related to unexpected
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen disconnection */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic int ssl_proxy_destroy(struct ssl_proxy *proxy)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void ssl_output(struct ssl_proxy *proxy)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen proxy->outbuf_plain + proxy->outbuf_pos_plain,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* disconnected */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* everything is sent, start reading again */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd);
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen /* disconnected */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* everything wasn't sent - don't read anything until we've
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen sent it all */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void plain_output(struct ssl_proxy *proxy)
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen sent = proxy_send_ssl(proxy, NULL, proxy->send_left_ssl);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* everything is sent, start reading again */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void plain_input(struct ssl_proxy *proxy)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* disconnected */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen sent = proxy_send_ssl(proxy, buf, (size_t)rcvd);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* everything wasn't sent - don't read anything until we've
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen sent it all */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy);
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainenstatic void ssl_handshake(struct ssl_proxy *proxy)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* handshake done, now we can start reading */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen proxy->io_plain = io_add(proxy->fd_plain, IO_READ,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ,
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* i/o interrupted */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen dir = gnutls_record_get_direction(proxy->session) == 0 ?
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_protocol_set_priority(session, protocol_priority);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_cipher_set_priority(session, cipher_priority);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_compression_set_priority(session, comp_priority);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_mac_set_priority(session, mac_priority);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_certificate_type_set_priority(session, cert_type_priority);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
if (!ssl_initialized) {
main_ref();
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)