1/*++
2/* NAME
3/*	tls_dh
4/* SUMMARY
5/*	Diffie-Hellman parameter support
6/* SYNOPSIS
7/*	#define TLS_INTERNAL
8/*	#include <tls.h>
9/*
10/*	void	tls_set_dh_from_file(path, bits)
11/*	const char *path;
12/*	int	bits;
13/*
14/*	int	tls_set_eecdh_curve(server_ctx, grade)
15/*	SSL_CTX	*server_ctx;
16/*	const char *grade;
17/*
18/*	DH	*tls_tmp_dh_cb(ssl, export, keylength)
19/*	SSL	*ssl; /* unused */
20/*	int	export;
21/*	int	keylength;
22/* DESCRIPTION
23/*	This module maintains parameters for Diffie-Hellman key generation.
24/*
25/*	tls_tmp_dh_cb() is a call-back routine for the
26/*	SSL_CTX_set_tmp_dh_callback() function.
27/*
28/*	tls_set_dh_from_file() overrides compiled-in DH parameters
29/*	with those specified in the named files. The file format
30/*	is as expected by the PEM_read_DHparams() routine. The
31/*	"bits" argument must be 512 or 1024.
32/*
33/*	tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH
34/*	key exchange algorithms by instantiating in the server SSL
35/*	context a suitable curve (corresponding to the specified
36/*	EECDH security grade) from the set of named curves in RFC
37/*	4492 Section 5.1.1. Errors generate warnings, but do not
38/*	disable TLS, rather we continue without EECDH. A zero
39/*	result indicates that the grade is invalid or the corresponding
40/*	curve could not be used.
41/* DIAGNOSTICS
42/*	In case of error, tls_set_dh_from_file() logs a warning and
43/*	ignores the request.
44/* LICENSE
45/* .ad
46/* .fi
47/*	This software is free. You can do with it whatever you want.
48/*	The original author kindly requests that you acknowledge
49/*	the use of his software.
50/* AUTHOR(S)
51/*	Originally written by:
52/*	Lutz Jaenicke
53/*	BTU Cottbus
54/*	Allgemeine Elektrotechnik
55/*	Universitaetsplatz 3-4
56/*	D-03044 Cottbus, Germany
57/*
58/*	Updated by:
59/*	Wietse Venema
60/*	IBM T.J. Watson Research
61/*	P.O. Box 704
62/*	Yorktown Heights, NY 10598, USA
63/*--*/
64
65/* System library. */
66
67#include <sys_defs.h>
68
69#ifdef USE_TLS
70#include <stdio.h>
71
72/* Utility library. */
73
74#include <msg.h>
75
76 /*
77  * Global library
78  */
79#include <mail_params.h>
80
81/* TLS library. */
82
83#define TLS_INTERNAL
84#include <tls.h>
85
86/* Application-specific. */
87
88 /*
89  * Compiled-in EDH primes (the compiled-in generator is always 2). These are
90  * used when no parameters are explicitly loaded from a site-specific file.
91  *
92  * 512-bit parameters are used for export ciphers, and 1024-bit parameters are
93  * used for non-export ciphers. An ~80-bit strong EDH key exchange is really
94  * too weak to protect 128+ bit keys, but larger DH primes are
95  * computationally expensive. When greater security is required, use EECDH.
96  */
97
98 /*
99  * Generated via "openssl dhparam -2 -noout -C 512 2>/dev/null" TODO:
100  * generate at compile-time.
101  */
102static unsigned char dh512_p[] = {
103    0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2,
104    0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4,
105    0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E,
106    0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5,
107    0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB,
108    0x4F, 0x70, 0xBA, 0x5B,
109};
110
111 /*
112  * Generated via "openssl dhparam -2 -noout -C 1024 2>/dev/null" TODO:
113  * generate at compile-time.
114  */
115static unsigned char dh1024_p[] = {
116    0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D,
117    0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88,
118    0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51,
119    0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F,
120    0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72,
121    0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76,
122    0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81,
123    0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E,
124    0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6,
125    0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF,
126    0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B,
127};
128
129 /*
130  * Cached results.
131  */
132static DH *dh_1024 = 0;
133static DH *dh_512 = 0;
134
135/* tls_set_dh_from_file - set Diffie-Hellman parameters from file */
136
137void    tls_set_dh_from_file(const char *path, int bits)
138{
139    FILE   *paramfile;
140    DH    **dhPtr;
141
142    switch (bits) {
143    case 512:
144	dhPtr = &dh_512;
145	break;
146    case 1024:
147	dhPtr = &dh_1024;
148	break;
149    default:
150	msg_panic("Invalid DH parameters size %d, file %s", bits, path);
151    }
152
153    if ((paramfile = fopen(path, "r")) != 0) {
154	if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) {
155	    msg_warn("cannot load %d-bit DH parameters from file %s"
156		     " -- using compiled-in defaults", bits, path);
157	    tls_print_errors();
158	}
159	(void) fclose(paramfile);		/* 200411 */
160    } else {
161	msg_warn("cannot load %d-bit DH parameters from file %s: %m"
162		 " -- using compiled-in defaults", bits, path);
163    }
164}
165
166/* tls_get_dh - get compiled-in DH parameters */
167
168static DH *tls_get_dh(const unsigned char *p, int plen)
169{
170    DH     *dh;
171    static unsigned char g[] = {0x02,};
172
173    /* Use the compiled-in parameters. */
174    if ((dh = DH_new()) == 0) {
175	msg_warn("cannot create DH parameter set: %m");	/* 200411 */
176	return (0);
177    }
178    dh->p = BN_bin2bn(p, plen, (BIGNUM *) 0);
179    dh->g = BN_bin2bn(g, 1, (BIGNUM *) 0);
180    if ((dh->p == 0) || (dh->g == 0)) {
181	msg_warn("cannot load compiled-in DH parameters");	/* 200411 */
182	DH_free(dh);				/* 200411 */
183	return (0);
184    }
185    return (dh);
186}
187
188/* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */
189
190DH     *tls_tmp_dh_cb(SSL *unused_ssl, int export, int keylength)
191{
192    DH     *dh_tmp;
193
194    if (export && keylength == 512) {		/* 40-bit export cipher */
195	if (dh_512 == 0)
196	    dh_512 = tls_get_dh(dh512_p, (int) sizeof(dh512_p));
197	dh_tmp = dh_512;
198    } else {					/* ADH, DHE-RSA or DSA */
199	if (dh_1024 == 0)
200	    dh_1024 = tls_get_dh(dh1024_p, (int) sizeof(dh1024_p));
201	dh_tmp = dh_1024;
202    }
203    return (dh_tmp);
204}
205
206int     tls_set_eecdh_curve(SSL_CTX *server_ctx, const char *grade)
207{
208#if OPENSSL_VERSION_NUMBER >= 0x1000000fL && !defined(OPENSSL_NO_ECDH)
209    int     nid;
210    EC_KEY *ecdh;
211    const char *curve;
212    int     g;
213
214#define TLS_EECDH_INVALID	0
215#define TLS_EECDH_NONE		1
216#define TLS_EECDH_STRONG	2
217#define TLS_EECDH_ULTRA		3
218    static NAME_CODE eecdh_table[] = {
219	"none", TLS_EECDH_NONE,
220	"strong", TLS_EECDH_STRONG,
221	"ultra", TLS_EECDH_ULTRA,
222	0, TLS_EECDH_INVALID,
223    };
224
225    switch (g = name_code(eecdh_table, NAME_CODE_FLAG_NONE, grade)) {
226    default:
227	msg_panic("Invalid eecdh grade code: %d", g);
228    case TLS_EECDH_INVALID:
229	msg_warn("Invalid TLS eecdh grade \"%s\": EECDH disabled", grade);
230	return (0);
231    case TLS_EECDH_NONE:
232	return (1);
233    case TLS_EECDH_STRONG:
234	curve = var_tls_eecdh_strong;
235	break;
236    case TLS_EECDH_ULTRA:
237	curve = var_tls_eecdh_ultra;
238	break;
239    }
240
241    /*
242     * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
243     * from RFC 4492 section 5.1.1, or explicitly described curves over
244     * binary fields. OpenSSL only supports the "named curves", which provide
245     * maximum interoperability. The recommended curve for 128-bit
246     * work-factor key exchange is "prime256v1" a.k.a. "secp256r1" from
247     * Section 2.7 of http://www.secg.org/download/aid-386/sec2_final.pdf
248     */
249
250    if ((nid = OBJ_sn2nid(curve)) == NID_undef) {
251	msg_warn("unknown curve \"%s\": disabling EECDH support", curve);
252	return (0);
253    }
254    ERR_clear_error();
255    if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0
256	|| SSL_CTX_set_tmp_ecdh(server_ctx, ecdh) == 0) {
257	msg_warn("unable to use curve \"%s\": disabling EECDH support", curve);
258	tls_print_errors();
259	return (0);
260    }
261#endif
262    return (1);
263}
264
265#ifdef TEST
266
267int     main(int unused_argc, char **unused_argv)
268{
269    tls_tmp_dh_cb(0, 1, 512);
270    tls_tmp_dh_cb(0, 1, 1024);
271    tls_tmp_dh_cb(0, 1, 2048);
272    tls_tmp_dh_cb(0, 0, 512);
273    return (0);
274}
275
276#endif
277
278#endif
279