# define HAVE_ECDH
#endif
-/* Check every 30 minutes if parameters file has been updated */
-#define SSL_PARAMFILE_CHECK_INTERVAL (60*30)
-
-#define SSL_PARAMETERS_PATH "ssl-params"
-
#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME /* FIXME: this may be unnecessary.. */
# undef HAVE_SSL_GET_SERVERNAME
#endif
};
struct ssl_parameters {
- const char *path;
- time_t last_refresh;
- int fd;
-
- DH *dh_512, *dh_default;
+ DH *dh_default;
};
struct ssl_server_context {
const char *cert;
const char *key;
const char *ca;
+ const char *dh;
const char *cipher_list;
const char *protocols;
bool verify_client_cert;
return ctx1->verify_client_cert == ctx2->verify_client_cert ? 0 : 1;
}
-static void ssl_params_corrupted(const char *reason)
-{
- i_fatal("Corrupted SSL ssl-parameters.dat in state_dir: %s", reason);
-}
-
-static void read_next(struct ssl_parameters *params, void *data, size_t size)
-{
- int ret;
-
- if ((ret = read_full(params->fd, data, size)) < 0)
- i_fatal("read(%s) failed: %m", params->path);
- if (ret == 0)
- ssl_params_corrupted("Truncated file");
-}
-
-static bool read_dh_parameters_next(struct ssl_parameters *params)
-{
- unsigned char *buf;
- const unsigned char *cbuf;
- unsigned int len;
- int bits;
-
- /* read bit size. 0 ends the DH parameters list. */
- read_next(params, &bits, sizeof(bits));
-
- if (bits == 0)
- return FALSE;
-
- /* read data size. */
- read_next(params, &len, sizeof(len));
- if (len > 1024*100) /* should be enough? */
- ssl_params_corrupted("File too large");
-
- buf = i_malloc(len);
- read_next(params, buf, len);
-
- cbuf = buf;
- switch (bits) {
- case 512:
- if (params->dh_512 != NULL)
- ssl_params_corrupted("Duplicate 512bit parameters");
- params->dh_512 = d2i_DHparams(NULL, &cbuf, len);
- break;
- default:
- if (params->dh_default != NULL)
- ssl_params_corrupted("Duplicate default parameters");
- params->dh_default = d2i_DHparams(NULL, &cbuf, len);
- break;
- }
-
- i_free(buf);
- return TRUE;
-}
-
static void ssl_free_parameters(struct ssl_parameters *params)
{
- if (params->dh_512 != NULL) {
- DH_free(params->dh_512);
- params->dh_512 = NULL;
- }
if (params->dh_default != NULL) {
DH_free(params->dh_default);
params->dh_default = NULL;
}
}
-static void ssl_refresh_parameters(struct ssl_parameters *params)
-{
- char c;
- int ret;
-
- if (params->last_refresh > ioloop_time - SSL_PARAMFILE_CHECK_INTERVAL)
- return;
- params->last_refresh = ioloop_time;
-
- params->fd = net_connect_unix(params->path);
- if (params->fd == -1) {
- i_error("connect(%s) failed: %m", params->path);
- return;
- }
- net_set_nonblock(params->fd, FALSE);
-
- ssl_free_parameters(params);
- while (read_dh_parameters_next(params)) ;
-
- if ((ret = read_full(params->fd, &c, 1)) < 0)
- i_fatal("read(%s) failed: %m", params->path);
- else if (ret != 0) {
- /* more data than expected */
- ssl_params_corrupted("More data than expected");
- }
-
- if (close(params->fd) < 0)
- i_error("close(%s) failed: %m", params->path);
- params->fd = -1;
-}
-
static void ssl_set_io(struct ssl_proxy *proxy, enum ssl_io_action action)
{
switch (action) {
return -1;
}
- ssl_refresh_parameters(&ssl_params);
+
ssl = SSL_new(ssl_ctx);
if (ssl == NULL) {
return RSA_generate_key(keylength, RSA_F4, NULL, NULL);
}
-static DH *ssl_tmp_dh_callback(SSL *ssl ATTR_UNUSED,
- int is_export, int keylength)
-{
- if (is_export != 0 && keylength == 512 && ssl_params.dh_512 != NULL)
- return ssl_params.dh_512;
-
- return ssl_params.dh_default;
-}
-
static void ssl_info_callback(const SSL *ssl, int where, int ret)
{
struct ssl_proxy *proxy;
#endif
if (SSL_CTX_need_tmp_RSA(ssl_ctx) != 0)
SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
- SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
#ifdef HAVE_ECDH
/* In the non-recommended situation where ECDH cipher suites are being
used instead of ECDHE, do not reuse the same ECDH key pair for
return pkey;
}
+static DH *
+ssl_proxy_load_dh(const char *dhparam)
+{
+ DH *dh;
+ BIO *bio;
+
+ bio = BIO_new_mem_buf(t_strdup_noconst(dhparam), strlen(dhparam));
+ if (bio == NULL)
+ i_fatal("BIO_new_mem_buf() failed");
+ dh = NULL;
+ dh = PEM_read_bio_DHparams(bio, &dh, NULL, NULL);
+ if (dh == NULL)
+ i_fatal("Couldn't parse DH parameters: %s",
+ openssl_iostream_key_load_error());
+ BIO_free(bio);
+ return dh;
+}
+
static void
ssl_proxy_ctx_use_key(SSL_CTX *ctx,
const struct master_service_ssl_settings *set)
EVP_PKEY_free(pkey);
}
+static void
+ssl_proxy_ctx_use_dh(SSL_CTX *ctx,
+ const struct master_service_ssl_settings *set)
+{
+ DH *dh;
+
+ dh = ssl_proxy_load_dh(set->ssl_dh);
+ if (SSL_CTX_set_tmp_dh(ctx, dh) != 1)
+ i_fatal("Can't load DH parameters: %s", openssl_iostream_key_load_error());
+ DH_free(dh);
+}
+
#if defined(HAVE_ECDH) && !defined(SSL_CTRL_SET_ECDH_AUTO)
static int
ssl_proxy_ctx_get_pkey_ec_curve_name(const struct master_service_ssl_settings *set)
ctx->cert = p_strdup(pool, ssl_set->ssl_cert);
ctx->key = p_strdup(pool, ssl_set->ssl_key);
ctx->ca = p_strdup(pool, ssl_set->ssl_ca);
+ ctx->dh = p_strdup(pool, ssl_set->ssl_dh);
ctx->cipher_list = p_strdup(pool, ssl_set->ssl_cipher_list);
ctx->protocols = p_strdup(pool, ssl_set->ssl_protocols);
ctx->verify_client_cert = ssl_set->ssl_verify_client_cert ||
#endif
ssl_proxy_ctx_use_key(ctx->ctx, ssl_set);
+ ssl_proxy_ctx_use_dh(ctx->ctx, ssl_set);
if (ctx->verify_client_cert)
ssl_proxy_ctx_verify_client(ctx->ctx, xnames);
(void)RAND_bytes(&buf, 1);
memset(&ssl_params, 0, sizeof(ssl_params));
- ssl_params.path = SSL_PARAMETERS_PATH;
ssl_proxy_count = 0;
ssl_proxies = NULL;