xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_dh.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: tls_dh.c,v 1.1.1.2 2010/06/17 18:07:09 tron Exp $	*/
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   */
104 static 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   */
117 static 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   */
134 static DH *dh_1024 = 0;
135 static DH *dh_512 = 0;
136 
137 /* tls_set_dh_from_file - set Diffie-Hellman parameters from file */
138 
139 void    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 
170 static 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 
192 DH     *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 
208 int     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 
269 int     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