Mercurial > hg > nginx-quic
annotate src/mail/ngx_mail_ssl_module.c @ 4072:cf334deeea66
Bugfix: read event was not blocked after reading body.
Read event should be blocked after reading body, else undefined behaviour
might occur on additional client activity. This fixes segmentation faults
observed with proxy_ignore_client_abort set.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 05 Sep 2011 12:43:31 +0000 |
parents | a1dd9dc754ab |
children | 7de74ed694c8 |
rev | line source |
---|---|
539 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
1136 | 9 #include <ngx_mail.h> |
539 | 10 |
11 | |
3960 | 12 #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" |
13 #define NGX_DEFAULT_ECDH_CURVE "prime256v1" | |
539 | 14 |
15 | |
1136 | 16 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); |
17 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); | |
2224 | 18 |
19 static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, | |
20 void *conf); | |
21 static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, | |
22 void *conf); | |
1136 | 23 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, |
976 | 24 void *conf); |
539 | 25 |
26 | |
583 | 27 static ngx_conf_enum_t ngx_http_starttls_state[] = { |
1136 | 28 { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, |
29 { ngx_string("on"), NGX_MAIL_STARTTLS_ON }, | |
30 { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY }, | |
583 | 31 { ngx_null_string, 0 } |
32 }; | |
33 | |
34 | |
35 | |
1136 | 36 static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = { |
547 | 37 { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, |
38 { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, | |
39 { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, | |
40 { ngx_null_string, 0 } | |
41 }; | |
42 | |
43 | |
1136 | 44 static ngx_command_t ngx_mail_ssl_commands[] = { |
539 | 45 |
46 { ngx_string("ssl"), | |
1136 | 47 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, |
2224 | 48 ngx_mail_ssl_enable, |
1136 | 49 NGX_MAIL_SRV_CONF_OFFSET, |
50 offsetof(ngx_mail_ssl_conf_t, enable), | |
539 | 51 NULL }, |
52 | |
583 | 53 { ngx_string("starttls"), |
1136 | 54 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
2224 | 55 ngx_mail_ssl_starttls, |
1136 | 56 NGX_MAIL_SRV_CONF_OFFSET, |
57 offsetof(ngx_mail_ssl_conf_t, starttls), | |
583 | 58 ngx_http_starttls_state }, |
59 | |
539 | 60 { ngx_string("ssl_certificate"), |
1136 | 61 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 62 ngx_conf_set_str_slot, |
1136 | 63 NGX_MAIL_SRV_CONF_OFFSET, |
64 offsetof(ngx_mail_ssl_conf_t, certificate), | |
539 | 65 NULL }, |
66 | |
67 { ngx_string("ssl_certificate_key"), | |
1136 | 68 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 69 ngx_conf_set_str_slot, |
1136 | 70 NGX_MAIL_SRV_CONF_OFFSET, |
71 offsetof(ngx_mail_ssl_conf_t, certificate_key), | |
539 | 72 NULL }, |
73 | |
2044 | 74 { ngx_string("ssl_dhparam"), |
75 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
76 ngx_conf_set_str_slot, | |
77 NGX_MAIL_SRV_CONF_OFFSET, | |
78 offsetof(ngx_mail_ssl_conf_t, dhparam), | |
79 NULL }, | |
80 | |
3960 | 81 { ngx_string("ssl_ecdh_curve"), |
82 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, | |
83 ngx_conf_set_str_slot, | |
84 NGX_MAIL_SRV_CONF_OFFSET, | |
85 offsetof(ngx_mail_ssl_conf_t, ecdh_curve), | |
86 NULL }, | |
87 | |
547 | 88 { ngx_string("ssl_protocols"), |
1136 | 89 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE, |
547 | 90 ngx_conf_set_bitmask_slot, |
1136 | 91 NGX_MAIL_SRV_CONF_OFFSET, |
92 offsetof(ngx_mail_ssl_conf_t, protocols), | |
93 &ngx_mail_ssl_protocols }, | |
547 | 94 |
539 | 95 { ngx_string("ssl_ciphers"), |
1136 | 96 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
539 | 97 ngx_conf_set_str_slot, |
1136 | 98 NGX_MAIL_SRV_CONF_OFFSET, |
99 offsetof(ngx_mail_ssl_conf_t, ciphers), | |
539 | 100 NULL }, |
101 | |
547 | 102 { ngx_string("ssl_prefer_server_ciphers"), |
1136 | 103 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, |
547 | 104 ngx_conf_set_flag_slot, |
1136 | 105 NGX_MAIL_SRV_CONF_OFFSET, |
106 offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), | |
547 | 107 NULL }, |
563 | 108 |
976 | 109 { ngx_string("ssl_session_cache"), |
1136 | 110 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, |
111 ngx_mail_ssl_session_cache, | |
112 NGX_MAIL_SRV_CONF_OFFSET, | |
976 | 113 0, |
114 NULL }, | |
115 | |
573 | 116 { ngx_string("ssl_session_timeout"), |
1136 | 117 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, |
573 | 118 ngx_conf_set_sec_slot, |
1136 | 119 NGX_MAIL_SRV_CONF_OFFSET, |
120 offsetof(ngx_mail_ssl_conf_t, session_timeout), | |
573 | 121 NULL }, |
547 | 122 |
539 | 123 ngx_null_command |
124 }; | |
125 | |
126 | |
1136 | 127 static ngx_mail_module_t ngx_mail_ssl_module_ctx = { |
1487
f69493e8faab
ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
Igor Sysoev <igor@sysoev.ru>
parents:
1136
diff
changeset
|
128 NULL, /* protocol */ |
f69493e8faab
ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
Igor Sysoev <igor@sysoev.ru>
parents:
1136
diff
changeset
|
129 |
539 | 130 NULL, /* create main configuration */ |
131 NULL, /* init main configuration */ | |
132 | |
1136 | 133 ngx_mail_ssl_create_conf, /* create server configuration */ |
134 ngx_mail_ssl_merge_conf /* merge server configuration */ | |
539 | 135 }; |
136 | |
137 | |
1136 | 138 ngx_module_t ngx_mail_ssl_module = { |
539 | 139 NGX_MODULE_V1, |
1136 | 140 &ngx_mail_ssl_module_ctx, /* module context */ |
141 ngx_mail_ssl_commands, /* module directives */ | |
142 NGX_MAIL_MODULE, /* module type */ | |
541 | 143 NULL, /* init master */ |
539 | 144 NULL, /* init module */ |
541 | 145 NULL, /* init process */ |
146 NULL, /* init thread */ | |
147 NULL, /* exit thread */ | |
148 NULL, /* exit process */ | |
149 NULL, /* exit master */ | |
150 NGX_MODULE_V1_PADDING | |
539 | 151 }; |
152 | |
153 | |
1136 | 154 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); |
543 | 155 |
156 | |
539 | 157 static void * |
1136 | 158 ngx_mail_ssl_create_conf(ngx_conf_t *cf) |
577 | 159 { |
1136 | 160 ngx_mail_ssl_conf_t *scf; |
577 | 161 |
1136 | 162 scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t)); |
539 | 163 if (scf == NULL) { |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2759
diff
changeset
|
164 return NULL; |
539 | 165 } |
166 | |
167 /* | |
577 | 168 * set by ngx_pcalloc(): |
539 | 169 * |
547 | 170 * scf->protocols = 0; |
2044 | 171 * scf->certificate = { 0, NULL }; |
172 * scf->certificate_key = { 0, NULL }; | |
173 * scf->dhparam = { 0, NULL }; | |
3960 | 174 * scf->ecdh_curve = { 0, NULL }; |
3516
dd1570b6f237
ngx_str_set() and ngx_str_null()
Igor Sysoev <igor@sysoev.ru>
parents:
3196
diff
changeset
|
175 * scf->ciphers = { 0, NULL }; |
976 | 176 * scf->shm_zone = NULL; |
539 | 177 */ |
178 | |
179 scf->enable = NGX_CONF_UNSET; | |
2759 | 180 scf->starttls = NGX_CONF_UNSET_UINT; |
976 | 181 scf->prefer_server_ciphers = NGX_CONF_UNSET; |
182 scf->builtin_session_cache = NGX_CONF_UNSET; | |
573 | 183 scf->session_timeout = NGX_CONF_UNSET; |
539 | 184 |
185 return scf; | |
186 } | |
187 | |
188 | |
189 static char * | |
1136 | 190 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
539 | 191 { |
1136 | 192 ngx_mail_ssl_conf_t *prev = parent; |
193 ngx_mail_ssl_conf_t *conf = child; | |
539 | 194 |
2224 | 195 char *mode; |
563 | 196 ngx_pool_cleanup_t *cln; |
197 | |
539 | 198 ngx_conf_merge_value(conf->enable, prev->enable, 0); |
2224 | 199 ngx_conf_merge_uint_value(conf->starttls, prev->starttls, |
200 NGX_MAIL_STARTTLS_OFF); | |
539 | 201 |
573 | 202 ngx_conf_merge_value(conf->session_timeout, |
203 prev->session_timeout, 300); | |
204 | |
547 | 205 ngx_conf_merge_value(conf->prefer_server_ciphers, |
206 prev->prefer_server_ciphers, 0); | |
207 | |
208 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, | |
3190
dd2ae3872634
disable SSLv2 and low ciphers by default
Igor Sysoev <igor@sysoev.ru>
parents:
2996
diff
changeset
|
209 (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); |
547 | 210 |
2224 | 211 ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); |
212 ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); | |
539 | 213 |
2044 | 214 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); |
215 | |
3960 | 216 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, |
217 NGX_DEFAULT_ECDH_CURVE); | |
218 | |
2124 | 219 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); |
539 | 220 |
221 | |
547 | 222 conf->ssl.log = cf->log; |
539 | 223 |
2224 | 224 if (conf->enable) { |
225 mode = "ssl"; | |
226 | |
227 } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { | |
228 mode = "starttls"; | |
229 | |
230 } else { | |
231 mode = ""; | |
232 } | |
233 | |
234 if (*mode) { | |
235 | |
236 if (conf->certificate.len == 0) { | |
237 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
238 "no \"ssl_certificate\" is defined for " | |
239 "the \"%s\" directive in %s:%ui", | |
240 mode, conf->file, conf->line); | |
241 return NGX_CONF_ERROR; | |
242 } | |
243 | |
244 if (conf->certificate_key.len == 0) { | |
245 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
246 "no \"ssl_certificate_key\" is defined for " | |
247 "the \"%s\" directive in %s:%ui", | |
248 mode, conf->file, conf->line); | |
249 return NGX_CONF_ERROR; | |
250 } | |
251 | |
252 } else { | |
253 | |
254 if (conf->certificate.len == 0) { | |
255 return NGX_CONF_OK; | |
256 } | |
257 | |
258 if (conf->certificate_key.len == 0) { | |
259 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
260 "no \"ssl_certificate_key\" is defined " | |
261 "for certificate \"%V\"", | |
262 &conf->certificate); | |
263 return NGX_CONF_ERROR; | |
264 } | |
265 } | |
266 | |
969 | 267 if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { |
539 | 268 return NGX_CONF_ERROR; |
269 } | |
270 | |
563 | 271 cln = ngx_pool_cleanup_add(cf->pool, 0); |
272 if (cln == NULL) { | |
539 | 273 return NGX_CONF_ERROR; |
274 } | |
275 | |
563 | 276 cln->handler = ngx_ssl_cleanup_ctx; |
277 cln->data = &conf->ssl; | |
278 | |
279 if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate, | |
280 &conf->certificate_key) | |
281 != NGX_OK) | |
547 | 282 { |
283 return NGX_CONF_ERROR; | |
284 } | |
539 | 285 |
286 if (conf->ciphers.len) { | |
547 | 287 if (SSL_CTX_set_cipher_list(conf->ssl.ctx, |
563 | 288 (const char *) conf->ciphers.data) |
289 == 0) | |
539 | 290 { |
291 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, | |
292 "SSL_CTX_set_cipher_list(\"%V\") failed", | |
293 &conf->ciphers); | |
294 } | |
295 } | |
296 | |
563 | 297 if (conf->prefer_server_ciphers) { |
298 SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); | |
299 } | |
300 | |
3959
b1f48fa31e6c
MSIE export versions are rare now, so RSA 512 key is generated on demand
Igor Sysoev <igor@sysoev.ru>
parents:
3938
diff
changeset
|
301 SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback); |
539 | 302 |
2044 | 303 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { |
304 return NGX_CONF_ERROR; | |
305 } | |
306 | |
976 | 307 ngx_conf_merge_value(conf->builtin_session_cache, |
2032 | 308 prev->builtin_session_cache, NGX_SSL_NONE_SCACHE); |
976 | 309 |
310 if (conf->shm_zone == NULL) { | |
311 conf->shm_zone = prev->shm_zone; | |
312 } | |
539 | 313 |
1136 | 314 if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx, |
976 | 315 conf->builtin_session_cache, |
316 conf->shm_zone, conf->session_timeout) | |
317 != NGX_OK) | |
318 { | |
319 return NGX_CONF_ERROR; | |
320 } | |
573 | 321 |
539 | 322 return NGX_CONF_OK; |
323 } | |
563 | 324 |
577 | 325 |
976 | 326 static char * |
2224 | 327 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
328 { | |
329 ngx_mail_ssl_conf_t *scf = conf; | |
330 | |
331 char *rv; | |
332 | |
333 rv = ngx_conf_set_flag_slot(cf, cmd, conf); | |
334 | |
335 if (rv != NGX_CONF_OK) { | |
336 return rv; | |
337 } | |
338 | |
339 if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { | |
340 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
341 "\"starttls\" directive conflicts with \"ssl on\""); | |
342 return NGX_CONF_ERROR; | |
343 } | |
344 | |
345 scf->file = cf->conf_file->file.name.data; | |
346 scf->line = cf->conf_file->line; | |
347 | |
348 return NGX_CONF_OK; | |
349 } | |
350 | |
351 | |
352 static char * | |
353 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
354 { | |
355 ngx_mail_ssl_conf_t *scf = conf; | |
356 | |
357 char *rv; | |
358 | |
359 rv = ngx_conf_set_enum_slot(cf, cmd, conf); | |
360 | |
361 if (rv != NGX_CONF_OK) { | |
362 return rv; | |
363 } | |
364 | |
365 if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { | |
366 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
367 "\"ssl\" directive conflicts with \"starttls\""); | |
368 return NGX_CONF_ERROR; | |
369 } | |
370 | |
371 scf->file = cf->conf_file->file.name.data; | |
372 scf->line = cf->conf_file->line; | |
373 | |
374 return NGX_CONF_OK; | |
375 } | |
376 | |
377 | |
378 static char * | |
1136 | 379 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
976 | 380 { |
1136 | 381 ngx_mail_ssl_conf_t *scf = conf; |
976 | 382 |
383 size_t len; | |
384 ngx_str_t *value, name, size; | |
385 ngx_int_t n; | |
386 ngx_uint_t i, j; | |
387 | |
388 value = cf->args->elts; | |
389 | |
390 for (i = 1; i < cf->args->nelts; i++) { | |
391 | |
1778 | 392 if (ngx_strcmp(value[i].data, "off") == 0) { |
393 scf->builtin_session_cache = NGX_SSL_NO_SCACHE; | |
394 continue; | |
395 } | |
396 | |
2032 | 397 if (ngx_strcmp(value[i].data, "none") == 0) { |
398 scf->builtin_session_cache = NGX_SSL_NONE_SCACHE; | |
399 continue; | |
400 } | |
401 | |
976 | 402 if (ngx_strcmp(value[i].data, "builtin") == 0) { |
403 scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; | |
404 continue; | |
405 } | |
406 | |
407 if (value[i].len > sizeof("builtin:") - 1 | |
408 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1) | |
409 == 0) | |
410 { | |
411 n = ngx_atoi(value[i].data + sizeof("builtin:") - 1, | |
412 value[i].len - (sizeof("builtin:") - 1)); | |
413 | |
414 if (n == NGX_ERROR) { | |
415 goto invalid; | |
416 } | |
417 | |
418 scf->builtin_session_cache = n; | |
419 | |
420 continue; | |
421 } | |
422 | |
423 if (value[i].len > sizeof("shared:") - 1 | |
424 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1) | |
425 == 0) | |
426 { | |
427 len = 0; | |
428 | |
429 for (j = sizeof("shared:") - 1; j < value[i].len; j++) { | |
430 if (value[i].data[j] == ':') { | |
431 break; | |
432 } | |
433 | |
434 len++; | |
435 } | |
436 | |
437 if (len == 0) { | |
438 goto invalid; | |
439 } | |
440 | |
441 name.len = len; | |
442 name.data = value[i].data + sizeof("shared:") - 1; | |
443 | |
444 size.len = value[i].len - j - 1; | |
445 size.data = name.data + len + 1; | |
446 | |
447 n = ngx_parse_size(&size); | |
448 | |
449 if (n == NGX_ERROR) { | |
450 goto invalid; | |
451 } | |
452 | |
453 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | |
454 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
455 "session cache \"%V\" is too small", | |
456 &value[i]); | |
457 | |
458 return NGX_CONF_ERROR; | |
459 } | |
460 | |
461 scf->shm_zone = ngx_shared_memory_add(cf, &name, n, | |
1136 | 462 &ngx_mail_ssl_module); |
976 | 463 if (scf->shm_zone == NULL) { |
464 return NGX_CONF_ERROR; | |
465 } | |
466 | |
467 continue; | |
468 } | |
469 | |
470 goto invalid; | |
471 } | |
472 | |
473 if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) { | |
474 scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE; | |
475 } | |
476 | |
3992
a1dd9dc754ab
A new fix for the case when ssl_session_cache defined, but ssl is not
Igor Sysoev <igor@sysoev.ru>
parents:
3960
diff
changeset
|
477 scf->shm_zone->init = ngx_ssl_session_cache_init; |
a1dd9dc754ab
A new fix for the case when ssl_session_cache defined, but ssl is not
Igor Sysoev <igor@sysoev.ru>
parents:
3960
diff
changeset
|
478 |
976 | 479 return NGX_CONF_OK; |
480 | |
481 invalid: | |
482 | |
483 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
484 "invalid session cache \"%V\"", &value[i]); | |
485 | |
486 return NGX_CONF_ERROR; | |
487 } |