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