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