Postfix3.3.1
tls_dh.c
[詳解]
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 /* void tls_auto_eecdh_curves(SSL_CTX *ctx)
15 /* SSL_CTX *ctx;
16 /*
17 /* void tls_set_eecdh_curve(server_ctx, grade)
18 /* SSL_CTX *server_ctx;
19 /* const char *grade;
20 /*
21 /* DH *tls_tmp_dh_cb(ssl, export, keylength)
22 /* SSL *ssl; /* unused */
23 /* int export;
24 /* int keylength;
25 /* DESCRIPTION
26 /* This module maintains parameters for Diffie-Hellman key generation.
27 /*
28 /* tls_tmp_dh_cb() is a call-back routine for the
29 /* SSL_CTX_set_tmp_dh_callback() function.
30 /*
31 /* tls_set_dh_from_file() overrides compiled-in DH parameters
32 /* with those specified in the named files. The file format
33 /* is as expected by the PEM_read_DHparams() routine. The
34 /* "bits" argument must be 512 or 1024.
35 /*
36 /* tls_auto_eecdh_curves() enables negotiation of the most preferred curve
37 /* among the curves specified by the tls_eecdh_auto_curves configuration
38 /* parameter.
39 /*
40 /* tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH
41 /* key exchange algorithms by instantiating in the server SSL
42 /* context a suitable curve (corresponding to the specified
43 /* EECDH security grade) from the set of named curves in RFC
44 /* 4492 Section 5.1.1. Errors generate warnings, but do not
45 /* disable TLS, rather we continue without EECDH. A zero
46 /* result indicates that the grade is invalid or the corresponding
47 /* curve could not be used. The "auto" grade enables multiple
48 /* curves, with the actual curve chosen as the most preferred
49 /* among those supported by both the server and the client.
50 /* DIAGNOSTICS
51 /* In case of error, tls_set_dh_from_file() logs a warning and
52 /* ignores the request.
53 /* LICENSE
54 /* .ad
55 /* .fi
56 /* This software is free. You can do with it whatever you want.
57 /* The original author kindly requests that you acknowledge
58 /* the use of his software.
59 /* AUTHOR(S)
60 /* Originally written by:
61 /* Lutz Jaenicke
62 /* BTU Cottbus
63 /* Allgemeine Elektrotechnik
64 /* Universitaetsplatz 3-4
65 /* D-03044 Cottbus, Germany
66 /*
67 /* Updated by:
68 /* Wietse Venema
69 /* IBM T.J. Watson Research
70 /* P.O. Box 704
71 /* Yorktown Heights, NY 10598, USA
72 /*--*/
73 
74 /* System library. */
75 
76 #include <sys_defs.h>
77 
78 #ifdef USE_TLS
79 #include <stdio.h>
80 
81 /* Utility library. */
82 
83 #include <msg.h>
84 #include <mymalloc.h>
85 #include <stringops.h>
86 
87  /*
88  * Global library
89  */
90 #include <mail_params.h>
91 
92 /* TLS library. */
93 
94 #define TLS_INTERNAL
95 #include <tls.h>
96 #include <openssl/dh.h>
97 #if OPENSSL_VERSION_NUMBER >= 0x1000200fUL && !defined(OPENSSL_NO_ECDH)
98 #include <openssl/ec.h>
99 #endif
100 
101 /* Application-specific. */
102 
103  /*
104  * Compiled-in DH parameters. Used when no parameters are explicitly loaded
105  * from a site-specific file. Using an ASN.1 DER encoding avoids the need
106  * to explicitly manipulate the internal representation of DH parameter
107  * objects.
108  *
109  * 512-bit parameters are used for export ciphers, and 2048-bit parameters are
110  * used for non-export ciphers. The non-export group is now 2048-bit, as
111  * 1024 bits is increasingly considered to weak by clients. When greater
112  * security is required, use EECDH.
113  */
114 
115  /*-
116  * Generated via:
117  * $ openssl dhparam -2 -outform DER 512 2>/dev/null |
118  * hexdump -ve '/1 "0x%02x, "' | fmt
119  * TODO: generate at compile-time. But that is no good for the majority of
120  * sites that install pre-compiled binaries, and breaks reproducible builds.
121  * Instead, generate at installation time and use main.cf configuration.
122  */
123 static unsigned char dh512_der[] = {
124  0x30, 0x46, 0x02, 0x41, 0x00, 0xd8, 0xbf, 0x11, 0xd6, 0x41, 0x2a, 0x7a,
125  0x9c, 0x78, 0xb2, 0xaa, 0x41, 0x23, 0x0a, 0xdc, 0xcf, 0xb7, 0x19, 0xc5,
126  0x16, 0x4c, 0xcb, 0x4a, 0xd0, 0xd2, 0x1f, 0x1f, 0x70, 0x24, 0x86, 0x6f,
127  0x51, 0x52, 0xc6, 0x5b, 0x28, 0xbb, 0x82, 0xe1, 0x24, 0x91, 0x3d, 0x4d,
128  0x95, 0x56, 0xf8, 0x0b, 0x2c, 0xe0, 0x36, 0x67, 0x88, 0x64, 0x15, 0x1f,
129  0x45, 0xd5, 0xb8, 0x0a, 0x00, 0x03, 0x76, 0x32, 0x0b, 0x02, 0x01, 0x02,
130 };
131 
132  /*-
133  * Generated via:
134  * $ openssl dhparam -2 -outform DER 2048 2>/dev/null |
135  * hexdump -ve '/1 "0x%02x, "' | fmt
136  * TODO: generate at compile-time. But that is no good for the majority of
137  * sites that install pre-compiled binaries, and breaks reproducible builds.
138  * Instead, generate at installation time and use main.cf configuration.
139  */
140 static unsigned char dh2048_der[] = {
141  0x30, 0x82, 0x01, 0x08, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf, 0x28, 0x1b,
142  0x68, 0x69, 0x90, 0x2f, 0x37, 0x9f, 0x5a, 0x50, 0x23, 0x73, 0x2c, 0x11,
143  0xf2, 0xac, 0x7c, 0x3e, 0x58, 0xb9, 0x23, 0x3e, 0x02, 0x07, 0x4d, 0xba,
144  0xd9, 0x2c, 0xc1, 0x9e, 0xf9, 0xc4, 0x2f, 0xbc, 0x8d, 0x86, 0x4b, 0x2a,
145  0x87, 0x86, 0x93, 0x32, 0x0f, 0x72, 0x40, 0xfe, 0x7e, 0xa2, 0xc1, 0x32,
146  0xf0, 0x65, 0x9c, 0xc3, 0x19, 0x25, 0x2d, 0xeb, 0x6a, 0x49, 0x94, 0x79,
147  0x2d, 0xa1, 0xbe, 0x05, 0x26, 0xac, 0x8d, 0x69, 0xdc, 0x2e, 0x7e, 0xb5,
148  0xfd, 0x3c, 0x2b, 0x7d, 0x43, 0x22, 0x53, 0xf6, 0x1e, 0x04, 0x45, 0xd7,
149  0x53, 0x84, 0xfd, 0x6b, 0x12, 0x72, 0x47, 0x04, 0xaf, 0xa4, 0xac, 0x4b,
150  0x55, 0xb6, 0x79, 0x42, 0x40, 0x88, 0x54, 0x48, 0xd5, 0x4d, 0x3a, 0xb2,
151  0xbf, 0x6c, 0x26, 0x95, 0x29, 0xdd, 0x8b, 0x9e, 0xed, 0xb8, 0x60, 0x8e,
152  0xb5, 0x35, 0xb6, 0x22, 0x44, 0x1f, 0xfb, 0x56, 0x74, 0xfe, 0xf0, 0x2c,
153  0xe6, 0x0c, 0x22, 0xc9, 0x35, 0xb3, 0x1b, 0x96, 0xbb, 0x0a, 0x5a, 0xc3,
154  0x09, 0xa0, 0xcc, 0xa5, 0x40, 0x90, 0x0f, 0x59, 0xa2, 0x89, 0x69, 0x2a,
155  0x69, 0x79, 0xe4, 0xd3, 0x24, 0xc6, 0x8c, 0xda, 0xbc, 0x98, 0x3a, 0x5b,
156  0x16, 0xae, 0x63, 0x6c, 0x0b, 0x43, 0x4f, 0xf3, 0x2e, 0xc8, 0xa9, 0x6b,
157  0x58, 0x6a, 0xa9, 0x8e, 0x64, 0x09, 0x3d, 0x88, 0x44, 0x4f, 0x97, 0x2c,
158  0x1d, 0x98, 0xb0, 0xa9, 0xc0, 0xb6, 0x8d, 0x19, 0x37, 0x1f, 0xb7, 0xc9,
159  0x86, 0xa8, 0xdc, 0x37, 0x4d, 0x64, 0x27, 0xf3, 0xf5, 0x2b, 0x7b, 0x6b,
160  0x76, 0x84, 0x3f, 0xc1, 0x23, 0x97, 0x2d, 0x71, 0xf7, 0xb6, 0xc2, 0x35,
161  0x28, 0x10, 0x96, 0xd6, 0x69, 0x0c, 0x2e, 0x1f, 0x9f, 0xdf, 0x82, 0x81,
162  0x57, 0x57, 0x39, 0xa5, 0xf2, 0x81, 0x29, 0x57, 0xf9, 0x2f, 0xd0, 0x03,
163  0xab, 0x02, 0x01, 0x02,
164 };
165 
166  /*
167  * Cached results.
168  */
169 static DH *dh_1024 = 0;
170 static DH *dh_512 = 0;
171 
172 /* tls_set_dh_from_file - set Diffie-Hellman parameters from file */
173 
174 void tls_set_dh_from_file(const char *path, int bits)
175 {
176  FILE *paramfile;
177  DH **dhPtr;
178 
179  switch (bits) {
180  case 512:
181  dhPtr = &dh_512;
182  break;
183  case 1024:
184  dhPtr = &dh_1024;
185  break;
186  default:
187  msg_panic("Invalid DH parameters size %d, file %s", bits, path);
188  }
189 
190  /*
191  * This function is the first to set the DH parameters, but free any
192  * prior value just in case the call sequence changes some day.
193  */
194  if (*dhPtr) {
195  DH_free(*dhPtr);
196  *dhPtr = 0;
197  }
198  if ((paramfile = fopen(path, "r")) != 0) {
199  if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) {
200  msg_warn("cannot load %d-bit DH parameters from file %s"
201  " -- using compiled-in defaults", bits, path);
202  tls_print_errors();
203  }
204  (void) fclose(paramfile); /* 200411 */
205  } else {
206  msg_warn("cannot load %d-bit DH parameters from file %s: %m"
207  " -- using compiled-in defaults", bits, path);
208  }
209 }
210 
211 /* tls_get_dh - get compiled-in DH parameters */
212 
213 static DH *tls_get_dh(const unsigned char *p, size_t plen)
214 {
215  const unsigned char *endp = p;
216  DH *dh = 0;
217 
218  if (d2i_DHparams(&dh, &endp, plen) && plen == endp - p)
219  return (dh);
220 
221  msg_warn("cannot load compiled-in DH parameters");
222  if (dh)
223  DH_free(dh);
224  return (0);
225 }
226 
227 /* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */
228 
229 DH *tls_tmp_dh_cb(SSL *unused_ssl, int export, int keylength)
230 {
231  DH *dh_tmp;
232 
233  if (export && keylength == 512) { /* 40-bit export cipher */
234  if (dh_512 == 0)
235  dh_512 = tls_get_dh(dh512_der, sizeof(dh512_der));
236  dh_tmp = dh_512;
237  } else { /* ADH, DHE-RSA or DSA */
238  if (dh_1024 == 0)
239  dh_1024 = tls_get_dh(dh2048_der, sizeof(dh2048_der));
240  dh_tmp = dh_1024;
241  }
242  return (dh_tmp);
243 }
244 
245 void tls_auto_eecdh_curves(SSL_CTX *ctx)
246 {
247 #if OPENSSL_VERSION_NUMBER >= 0x1000200fUL && !defined(OPENSSL_NO_ECDH)
248  SSL_CTX *tmpctx;
249  int *nids;
250  int space = 5;
251  int n = 0;
252  int unknown = 0;
253  char *save;
254  char *curves;
255  char *curve;
256 
257  if ((tmpctx = SSL_CTX_new(TLS_method())) == 0) {
258  msg_warn("cannot allocate temp SSL_CTX, using default ECDHE curves");
259  tls_print_errors();
260  return;
261  }
262  nids = mymalloc(space * sizeof(int));
263  curves = save = mystrdup(var_tls_eecdh_auto);
264 #define RETURN do { \
265  myfree(save); \
266  myfree(nids); \
267  SSL_CTX_free(tmpctx); \
268  return; \
269  } while (0)
270 
271  while ((curve = mystrtok(&curves, CHARS_COMMA_SP)) != 0) {
272  int nid = EC_curve_nist2nid(curve);
273 
274  if (nid == NID_undef)
275  nid = OBJ_sn2nid(curve);
276  if (nid == NID_undef)
277  nid = OBJ_ln2nid(curve);
278  if (nid == NID_undef) {
279  msg_warn("ignoring unknown \"auto\" ECDHE curve \"%s\"",
280  curve);
281  continue;
282  }
283 
284  /*
285  * Validate the NID by trying it as the sole EC curve for a
286  * throw-away SSL context. Silently skip unsupported code points.
287  * This way, we can list X25519 and X448 as soon as the nids are
288  * assigned, and before the supporting code is implemented. They'll
289  * be silently skipped when not yet supported.
290  */
291  if (SSL_CTX_set1_curves(tmpctx, &nid, 1) <= 0) {
292  ++unknown;
293  continue;
294  }
295  if (++n > space) {
296  space *= 2;
297  nids = myrealloc(nids, space * sizeof(int));
298  }
299  nids[n - 1] = nid;
300  }
301 
302  if (n == 0) {
303  if (unknown > 0)
304  msg_warn("none of the \"auto\" ECDHE curves are supported");
305  RETURN;
306  }
307  if (SSL_CTX_set1_curves(ctx, nids, n) <= 0) {
308  msg_warn("failed to configure \"auto\" ECDHE curves");
309  tls_print_errors();
310  RETURN;
311  }
312 
313  /*
314  * This is a NOP in OpenSSL 1.1.0 and later, where curves are always
315  * auto-negotiated.
316  */
317 #if OPENSSL_VERSION_NUMBER < 0x10100000UL
318  if (SSL_CTX_set_ecdh_auto(ctx, 1) <= 0) {
319  msg_warn("failed to enable automatic ECDHE curve selection");
320  tls_print_errors();
321  RETURN;
322  }
323 #endif
324  RETURN;
325 #endif
326 }
327 
328 void tls_set_eecdh_curve(SSL_CTX *server_ctx, const char *grade)
329 {
330 #if OPENSSL_VERSION_NUMBER >= 0x1000000fUL && !defined(OPENSSL_NO_ECDH)
331  int nid;
332  EC_KEY *ecdh;
333  const char *curve;
334  int g;
335 
336 #define TLS_EECDH_INVALID 0
337 #define TLS_EECDH_NONE 1
338 #define TLS_EECDH_STRONG 2
339 #define TLS_EECDH_ULTRA 3
340 #if OPENSSL_VERSION_NUMBER >= 0x1000200fUL
341 #define TLS_EECDH_AUTO 4
342 #endif
343  static NAME_CODE eecdh_table[] = {
344  "none", TLS_EECDH_NONE,
345  "strong", TLS_EECDH_STRONG,
346  "ultra", TLS_EECDH_ULTRA,
347 #if OPENSSL_VERSION_NUMBER >= 0x1000200fUL
348  "auto", TLS_EECDH_AUTO,
349 #endif
350  0, TLS_EECDH_INVALID,
351  };
352 
353  switch (g = name_code(eecdh_table, NAME_CODE_FLAG_NONE, grade)) {
354  default:
355  msg_panic("Invalid eecdh grade code: %d", g);
356  case TLS_EECDH_INVALID:
357  msg_warn("Invalid TLS eecdh grade \"%s\": EECDH disabled", grade);
358  return;
359  case TLS_EECDH_NONE:
360  return;
361  case TLS_EECDH_STRONG:
362  curve = var_tls_eecdh_strong;
363  break;
364  case TLS_EECDH_ULTRA:
365  curve = var_tls_eecdh_ultra;
366  break;
367 #if OPENSSL_VERSION_NUMBER >= 0x1000200fUL
368  case TLS_EECDH_AUTO:
369  tls_auto_eecdh_curves(server_ctx);
370  return;
371 #endif
372  }
373 
374  /*
375  * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
376  * from RFC 4492 section 5.1.1, or explicitly described curves over
377  * binary fields. OpenSSL only supports the "named curves", which provide
378  * maximum interoperability. The recommended curve for 128-bit
379  * work-factor key exchange is "prime256v1" a.k.a. "secp256r1" from
380  * Section 2.7 of http://www.secg.org/download/aid-386/sec2_final.pdf
381  */
382 
383  if ((nid = OBJ_sn2nid(curve)) == NID_undef) {
384  msg_warn("unknown curve \"%s\": disabling EECDH support", curve);
385  return;
386  }
387  ERR_clear_error();
388  if ((ecdh = EC_KEY_new_by_curve_name(nid)) == 0
389  || SSL_CTX_set_tmp_ecdh(server_ctx, ecdh) == 0) {
390  EC_KEY_free(ecdh); /* OK if NULL */
391  msg_warn("unable to use curve \"%s\": disabling EECDH support", curve);
392  tls_print_errors();
393  return;
394  }
395  EC_KEY_free(ecdh);
396 #endif
397  return;
398 }
399 
400 #ifdef TEST
401 
402 int main(int unused_argc, char **unused_argv)
403 {
404  tls_tmp_dh_cb(0, 1, 512);
405  tls_tmp_dh_cb(0, 1, 1024);
406  tls_tmp_dh_cb(0, 1, 2048);
407  tls_tmp_dh_cb(0, 0, 512);
408  return (0);
409 }
410 
411 #endif
412 
413 #endif
char * var_tls_eecdh_auto
char * var_tls_eecdh_ultra
char * mystrdup(const char *str)
Definition: mymalloc.c:225
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
void * myrealloc(void *ptr, ssize_t len)
Definition: mymalloc.c:175
int main(int argc, char **argv)
Definition: anvil.c:1010
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define NAME_CODE_FLAG_NONE
Definition: name_code.h:22
int name_code(const NAME_CODE *table, int flags, const char *name)
Definition: name_code.c:65
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
char * var_tls_eecdh_strong
#define RETURN(x)
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150