ssl-proxy-gnutls.c revision 2e37d45867d081db150ab78dad303b9077aea24f
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "login-common.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "network.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "hash.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "ssl-proxy.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#ifdef HAVE_GNUTLS
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#error broken currently
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdio.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <stdlib.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <unistd.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <fcntl.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <gcrypt.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#include <gnutls/gnutls.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstruct ssl_proxy {
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen int refcount;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen gnutls_session session;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen struct ip_addr ip;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen int fd_ssl, fd_plain;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct io *io_ssl, *io_plain;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen int io_ssl_dir;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen unsigned char outbuf_plain[1024];
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen unsigned int outbuf_pos_plain;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen size_t send_left_ssl, send_left_plain;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen};
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenconst int protocol_priority[] =
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainenconst int kx_priority[] =
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, 0 };
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenconst int cipher_priority[] =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen { GNUTLS_CIPHER_RIJNDAEL_CBC, GNUTLS_CIPHER_3DES_CBC,
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_CIPHER_ARCFOUR_40, 0 };
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenconst int comp_priority[] =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen { GNUTLS_COMP_LZO, GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenconst int mac_priority[] =
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenconst int cert_type_priority[] =
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen { GNUTLS_CRT_X509, 0 };
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic struct hash_table *ssl_proxies;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic gnutls_certificate_credentials x509_cred;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenstatic gnutls_dh_params dh_params;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainenstatic gnutls_rsa_params rsa_params;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void ssl_input(struct ssl_proxy *proxy);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void plain_input(struct ssl_proxy *proxy);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic bool ssl_proxy_destroy(struct ssl_proxy *proxy);
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainenstatic const char *get_alert_text(struct ssl_proxy *proxy)
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen{
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen return gnutls_alert_get_name(gnutls_alert_get(proxy->session));
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic int handle_ssl_error(struct ssl_proxy *proxy, int error)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (!gnutls_error_is_fatal(error)) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (!verbose_ssl)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return 0;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen if (error == GNUTLS_E_WARNING_ALERT_RECEIVED) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_warning("Received SSL warning alert: %s [%s]",
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen get_alert_text(proxy),
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen net_ip2addr(&proxy->ip));
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen } else {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_warning("Non-fatal SSL error: %s: %s",
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen get_alert_text(proxy),
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen net_ip2addr(&proxy->ip));
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen }
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return 0;
df831edaa3b3aa22e03bc5fd416a0553c5600a69Phil Carmody }
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (verbose_ssl) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen /* fatal error occurred */
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (error == GNUTLS_E_FATAL_ALERT_RECEIVED) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_warning("Received SSL fatal alert: %s [%s]",
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen get_alert_text(proxy),
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen net_ip2addr(&proxy->ip));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_warning("Error reading from SSL client: %s [%s]",
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen gnutls_strerror(error),
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen net_ip2addr(&proxy->ip));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen gnutls_alert_send_appropriate(proxy->session, error);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen ssl_proxy_destroy(proxy);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return -1;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic int proxy_recv_ssl(struct ssl_proxy *proxy, void *data, size_t size)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen int rcvd;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen rcvd = gnutls_record_recv(proxy->session, data, size);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (rcvd > 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen return rcvd;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (rcvd == 0 || rcvd == GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen /* disconnected, either by nicely telling us that we'll
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen close the connection, or by simply killing the
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen connection which gives us the packet length error. */
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen ssl_proxy_destroy(proxy);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return -1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return handle_ssl_error(proxy, rcvd);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenstatic int proxy_send_ssl(struct ssl_proxy *proxy,
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen const void *data, size_t size)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen int sent;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sent = gnutls_record_send(proxy->session, data, size);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (sent >= 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return sent;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen if (sent == GNUTLS_E_PUSH_ERROR || sent == GNUTLS_E_INVALID_SESSION) {
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen /* don't warn about errors related to unexpected
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen disconnection */
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen ssl_proxy_destroy(proxy);
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen return -1;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen return handle_ssl_error(proxy, sent);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic int ssl_proxy_destroy(struct ssl_proxy *proxy)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (--proxy->refcount > 0)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return TRUE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen hash_table_remove(ssl_proxies, proxy);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen gnutls_deinit(proxy->session);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (proxy->io_ssl != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen io_remove(proxy->io_ssl);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (proxy->io_plain != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_remove(proxy->io_plain);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen (void)net_disconnect(proxy->fd_ssl);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen (void)net_disconnect(proxy->fd_plain);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen i_free(proxy);
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen main_unref();
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen return FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenstatic void ssl_output(struct ssl_proxy *proxy)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int sent;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen sent = net_transmit(proxy->fd_plain,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen proxy->outbuf_plain + proxy->outbuf_pos_plain,
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen proxy->send_left_plain);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (sent < 0) {
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* disconnected */
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen ssl_proxy_destroy(proxy);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen return;
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen proxy->send_left_plain -= sent;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen proxy->outbuf_pos_plain += sent;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen if (proxy->send_left_plain > 0)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen /* everything is sent, start reading again */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen io_remove(proxy->io_ssl);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ, ssl_input, proxy);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen}
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenstatic void ssl_input(struct ssl_proxy *proxy)
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen{
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen int rcvd, sent;
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen rcvd = proxy_recv_ssl(proxy, proxy->outbuf_plain,
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen sizeof(proxy->outbuf_plain));
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (rcvd <= 0)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen sent = net_transmit(proxy->fd_plain, proxy->outbuf_plain, (size_t)rcvd);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (sent == rcvd)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (sent < 0) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* disconnected */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen ssl_proxy_destroy(proxy);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* everything wasn't sent - don't read anything until we've
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen sent it all */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen proxy->outbuf_pos_plain = 0;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen proxy->send_left_plain = rcvd - sent;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen io_remove(proxy->io_ssl);
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_WRITE, ssl_output, proxy);
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainenstatic void plain_output(struct ssl_proxy *proxy)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen int sent;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen sent = proxy_send_ssl(proxy, NULL, proxy->send_left_ssl);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (sent <= 0)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen proxy->send_left_ssl -= sent;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (proxy->send_left_ssl > 0)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen return;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen /* everything is sent, start reading again */
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen io_remove(proxy->io_plain);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen proxy->io_plain = io_add(proxy->fd_plain, IO_READ, plain_input, proxy);
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic void plain_input(struct ssl_proxy *proxy)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen char buf[1024];
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssize_t rcvd, sent;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen rcvd = net_receive(proxy->fd_plain, buf, sizeof(buf));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (rcvd < 0) {
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen /* disconnected */
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen gnutls_bye(proxy->session, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ssl_proxy_destroy(proxy);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sent = proxy_send_ssl(proxy, buf, (size_t)rcvd);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (sent < 0 || sent == rcvd)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen /* everything wasn't sent - don't read anything until we've
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen sent it all */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen proxy->send_left_ssl = rcvd - sent;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen io_remove(proxy->io_plain);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen proxy->io_plain = io_add(proxy->fd_ssl, IO_WRITE, plain_output, proxy);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void ssl_handshake(struct ssl_proxy *proxy)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int ret, dir;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen ret = gnutls_handshake(proxy->session);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen if (ret >= 0) {
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen /* handshake done, now we can start reading */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (proxy->io_ssl != NULL)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen io_remove(proxy->io_ssl);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen proxy->io_plain = io_add(proxy->fd_plain, IO_READ,
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen plain_input, proxy);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, IO_READ,
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen ssl_input, proxy);
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (handle_ssl_error(proxy, ret) < 0)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* i/o interrupted */
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen dir = gnutls_record_get_direction(proxy->session) == 0 ?
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen IO_READ : IO_WRITE;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (proxy->io_ssl_dir != dir) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen if (proxy->io_ssl != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_remove(proxy->io_ssl);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen proxy->io_ssl = io_add(proxy->fd_ssl, dir,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen ssl_handshake, proxy);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen proxy->io_ssl_dir = dir;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenstatic gnutls_session initialize_state(void)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen gnutls_session session;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen gnutls_init(&session, GNUTLS_SERVER);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen gnutls_protocol_set_priority(session, protocol_priority);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen gnutls_cipher_set_priority(session, cipher_priority);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen gnutls_compression_set_priority(session, comp_priority);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen gnutls_kx_set_priority(session, kx_priority);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen gnutls_mac_set_priority(session, mac_priority);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen gnutls_certificate_type_set_priority(session, cert_type_priority);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen gnutls_cred_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return session;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainenint ssl_proxy_new(int fd, struct ip_addr *ip)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct ssl_proxy *proxy;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen gnutls_session session;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen int sfd[2];
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (!ssl_initialized) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_error("SSL support not enabled in configuration");
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen session = initialize_state();
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen gnutls_transport_set_ptr(session, fd);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen i_error("socketpair() failed: %m");
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen gnutls_deinit(session);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen return -1;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen net_set_nonblock(sfd[0], TRUE);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen net_set_nonblock(sfd[1], TRUE);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen net_set_nonblock(fd, TRUE);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy = i_new(struct ssl_proxy, 1);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy->refcount = 1;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy->session = session;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy->fd_ssl = fd;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy->fd_plain = sfd[0];
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen proxy->ip = *ip;
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen hash_table_insert(ssl_proxies, proxy, proxy);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen proxy->refcount++;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen ssl_handshake(proxy);
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen if (!ssl_proxy_destroy(proxy)) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen /* handshake failed. return the disconnected socket anyway
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen so the caller doesn't try to use the old closed fd */
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen return sfd[1];
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen }
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen main_ref();
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen return sfd[1];
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen}
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainenstatic void read_next_field(int fd, gnutls_datum *datum,
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen const char *fname, const char *field_name)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen{
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen ssize_t ret;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* get size */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = read(fd, &datum->size, sizeof(datum->size));
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (ret < 0)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen i_fatal("read() failed for %s: %m", fname);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen if (ret != sizeof(datum->size)) {
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen (void)unlink(fname);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_fatal("Corrupted SSL parameter file %s: File too small",
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen fname);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (datum->size > 10240) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen (void)unlink(fname);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_fatal("Corrupted SSL parameter file %s: "
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen "Field '%s' too large (%u)",
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen fname, field_name, datum->size);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen /* read the actual data */
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen datum->data = t_malloc(datum->size);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen ret = read(fd, datum->data, datum->size);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (ret < 0)
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_fatal("read() failed for %s: %m", fname);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if ((size_t)ret != datum->size) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen (void)unlink(fname);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_fatal("Corrupted SSL parameter file %s: "
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen "Field '%s' not fully in file (%u < %u)",
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen fname, field_name, datum->size - ret, datum->size);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenstatic void read_dh_parameters(int fd, const char *fname)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen gnutls_datum dbits, prime, generator;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen int ret, bits;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if ((ret = gnutls_dh_params_init(&dh_params)) < 0) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_fatal("gnutls_dh_params_init() failed: %s",
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen gnutls_strerror(ret));
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen }
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* read until bits field is 0 */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (;;) {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen read_next_field(fd, &dbits, fname, "DH bits");
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (dbits.size != sizeof(int)) {
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen (void)unlink(fname);
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen i_fatal("Corrupted SSL parameter file %s: "
df16c7e87511fed827e6890a2a47d13ca48716deTimo Sirainen "Field 'DH bits' has invalid size %u",
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fname, dbits.size);
0611067f385a37773800225256dcd5cf6aa34212Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen bits = *((int *) dbits.data);
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen if (bits == 0)
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen break;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen read_next_field(fd, &prime, fname, "DH prime");
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen read_next_field(fd, &generator, fname, "DH generator");
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen ret = gnutls_dh_params_set(dh_params, prime, generator, bits);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_fatal("gnutls_dh_params_set() failed: %s",
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen gnutls_strerror(ret));
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen }
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenstatic void read_rsa_parameters(int fd, const char *fname)
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen{
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen gnutls_datum m, e, d, p, q, u;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen int ret;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen read_next_field(fd, &m, fname, "RSA m");
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen read_next_field(fd, &e, fname, "RSA e");
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen read_next_field(fd, &d, fname, "RSA d");
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen read_next_field(fd, &p, fname, "RSA p");
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen read_next_field(fd, &q, fname, "RSA q");
f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69Timo Sirainen read_next_field(fd, &u, fname, "RSA u");
c0b1543512bc3e0a3a9f526056a3678a07ce32f5Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen if ((ret = gnutls_rsa_params_init(&rsa_params)) < 0) {
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen i_fatal("gnutls_rsa_params_init() failed: %s",
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen gnutls_strerror(ret));
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen }
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen /* only 512bit is allowed */
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen ret = gnutls_rsa_params_set(rsa_params, m, e, d, p, q, u, 512);
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen if (ret < 0) {
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen i_fatal("gnutls_rsa_params_set() failed: %s",
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen gnutls_strerror(ret));
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen}
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainenstatic void read_parameters(const char *fname)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen int fd;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* we'll wait until parameter file exists */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen for (;;) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen fd = open(fname, O_RDONLY);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (fd != -1)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen break;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (errno != ENOENT)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_fatal("Can't open SSL parameter file %s: %m", fname);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen sleep(1);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen read_dh_parameters(fd, fname);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen read_rsa_parameters(fd, fname);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen (void)close(fd);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenstatic void gcrypt_log_handler(void *context ATTR_UNUSED, int level,
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen const char *fmt, va_list args)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen if (level != GCRY_LOG_FATAL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen T_BEGIN {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_error("gcrypt fatal: %s", t_strdup_vprintf(fmt, args));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } T_END;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid ssl_proxy_init(void)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen const char *certfile, *keyfile, *paramfile;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen unsigned char buf[4];
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen int ret;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen certfile = getenv("SSL_CERT_FILE");
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen keyfile = getenv("SSL_KEY_FILE");
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen paramfile = getenv("SSL_PARAM_FILE");
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (certfile == NULL || keyfile == NULL || paramfile == NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen /* SSL support is disabled */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen return;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen if ((ret = gnutls_global_init() < 0)) {
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen i_fatal("gnu_tls_global_init() failed: %s",
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen gnutls_strerror(ret));
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen }
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* gcrypt initialization - set log handler and make sure randomizer
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen opens /dev/urandom now instead of after we've chrooted */
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen gcry_set_log_handler(gcrypt_log_handler, NULL);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen gcry_randomize(buf, sizeof(buf), GCRY_STRONG_RANDOM);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen read_parameters(paramfile);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen i_fatal("gnutls_certificate_allocate_credentials() failed: %s",
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen gnutls_strerror(ret));
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen ret = gnutls_certificate_set_x509_key_file(x509_cred, certfile, keyfile,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen GNUTLS_X509_FMT_PEM);
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen if (ret < 0) {
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen i_fatal("Can't load certificate files %s and %s: %s",
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen certfile, keyfile, gnutls_strerror(ret));
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen gnutls_certificate_set_dh_params(x509_cred, dh_params);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen gnutls_certificate_set_rsa_export_params(x509_cred, rsa_params);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen ssl_proxies = hash_table_create(system_pool, system_pool, 0,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen NULL, NULL);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ssl_initialized = TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid ssl_proxy_deinit(void)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct hash_iterate_context *iter;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen void *key, *value;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (!ssl_initialized)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen iter = hash_table_iterate_init(ssl_proxies);
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen while (hash_table_iterate(iter, &key, &value))
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen ssl_proxy_destroy(value);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen hash_table_iterate_deinit(iter);
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen hash_table_destroy(ssl_proxies);
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen gnutls_certificate_free_credentials(x509_cred);
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen gnutls_global_deinit();
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen}
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainen#endif
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen