view src/lib-ssl-iostream/iostream-openssl-params.c @ 12616:bd23d4e10fa1

Added lib-ssl-iostream for handling SSL connections more easily.
author Timo Sirainen <tss@iki.fi>
date Mon, 31 Jan 2011 18:40:27 +0200
parents
children ba770cba5598
line wrap: on
line source

/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "buffer.h"
#include "iostream-openssl.h"

/* 2 or 5. Haven't seen their difference explained anywhere, but 2 is the
   default.. */
#define DH_GENERATOR 2

static int dh_param_bitsizes[] = { 512, 1024 };

static int generate_dh_parameters(int bitsize, buffer_t *output)
{
        DH *dh;
	unsigned char *p;
	int len, len2;

	dh = DH_generate_parameters(bitsize, DH_GENERATOR, NULL, NULL);
	if (dh == NULL) {
		i_error("DH_generate_parameters(bits=%d, gen=%d) failed: %s",
			bitsize, DH_GENERATOR, ssl_iostream_error());
		return -1;
	}

	len = i2d_DHparams(dh, NULL);
	if (len < 0) {
		i_error("i2d_DHparams() failed: %s", ssl_iostream_error());
		DH_free(dh);
		return -1;
	}

	buffer_append(output, &bitsize, sizeof(bitsize));
	buffer_append(output, &len, sizeof(len));

	p = buffer_append_space_unsafe(output, len);
	len2 = i2d_DHparams(dh, &p);
	i_assert(len == len2);
	DH_free(dh);
	return 0;
}

int ssl_iostream_generate_params(buffer_t *output)
{
	unsigned int i;

	for (i = 0; i < N_ELEMENTS(dh_param_bitsizes); i++) {
		if (generate_dh_parameters(dh_param_bitsizes[i], output) < 0)
			return -1;
	}
	buffer_append_zero(output, sizeof(int));
	return 0;
}

static int read_int(const unsigned char **data, const unsigned char *end)
{
	unsigned int len = end - *data;
	int ret;

	if (len < sizeof(ret))
		return -1;
	memcpy(&ret, *data, sizeof(ret));
	*data += sizeof(ret);
	return ret;
}

static int
read_dh_parameters_next(struct ssl_iostream_context *ctx,
			const unsigned char **data, const unsigned char *end)
{
	const unsigned char *dbuf;
	DH *dh;
	int bits, len, ret = 1;

	/* get bit size. 0 ends the DH parameters list. */
	if ((bits = read_int(data, end)) <= 0)
		return bits;

	/* get data size */
	if ((len = read_int(data, end)) <= 0 || end - *data < len)
		return -1;

	dbuf = *data;
	dh = d2i_DHparams(NULL, &dbuf, len);
	*data += len;

	if (dh == NULL)
		return -1;

	switch (bits) {
	case 512:
		ctx->dh_512 = dh;
		break;
	case 1024:
		ctx->dh_1024 = dh;
		break;
	default:
		ret = -1;
		break;
	}
	return ret;
}

int ssl_iostream_context_import_params(struct ssl_iostream_context *ctx,
				       const buffer_t *input)
{
	const unsigned char *data, *end;
	int ret;

	ssl_iostream_context_free_params(ctx);

	data = input->data;
	end = data + input->used;
	while ((ret = read_dh_parameters_next(ctx, &data, end)) > 0) ;

	return ret < 0 || data != end ? -1 : 0;
}

void ssl_iostream_context_free_params(struct ssl_iostream_context *ctx)
{
	if (ctx->dh_512 != NULL) {
		DH_free(ctx->dh_512);
                ctx->dh_512 = NULL;
	}
	if (ctx->dh_1024 != NULL) {
		DH_free(ctx->dh_1024);
                ctx->dh_1024 = NULL;
	}
}