Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_mail_ssl_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_mail.h>
11 
12 
13 #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5"
14 #define NGX_DEFAULT_ECDH_CURVE "prime256v1"
15 
16 
17 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
18 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
19 
20 static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
21  void *conf);
22 static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd,
23  void *conf);
24 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
25  void *conf);
26 
27 
28 static ngx_conf_enum_t ngx_http_starttls_state[] = {
32  { ngx_null_string, 0 }
33 };
34 
35 
36 
37 static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = {
38  { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
39  { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
40  { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
41  { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
42  { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
43  { ngx_null_string, 0 }
44 };
45 
46 
47 static ngx_command_t ngx_mail_ssl_commands[] = {
48 
49  { ngx_string("ssl"),
51  ngx_mail_ssl_enable,
53  offsetof(ngx_mail_ssl_conf_t, enable),
54  NULL },
55 
56  { ngx_string("starttls"),
58  ngx_mail_ssl_starttls,
60  offsetof(ngx_mail_ssl_conf_t, starttls),
61  ngx_http_starttls_state },
62 
63  { ngx_string("ssl_certificate"),
67  offsetof(ngx_mail_ssl_conf_t, certificate),
68  NULL },
69 
70  { ngx_string("ssl_certificate_key"),
74  offsetof(ngx_mail_ssl_conf_t, certificate_key),
75  NULL },
76 
77  { ngx_string("ssl_dhparam"),
81  offsetof(ngx_mail_ssl_conf_t, dhparam),
82  NULL },
83 
84  { ngx_string("ssl_ecdh_curve"),
88  offsetof(ngx_mail_ssl_conf_t, ecdh_curve),
89  NULL },
90 
91  { ngx_string("ssl_protocols"),
95  offsetof(ngx_mail_ssl_conf_t, protocols),
96  &ngx_mail_ssl_protocols },
97 
98  { ngx_string("ssl_ciphers"),
102  offsetof(ngx_mail_ssl_conf_t, ciphers),
103  NULL },
104 
105  { ngx_string("ssl_prefer_server_ciphers"),
109  offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
110  NULL },
111 
112  { ngx_string("ssl_session_cache"),
114  ngx_mail_ssl_session_cache,
116  0,
117  NULL },
118 
119  { ngx_string("ssl_session_timeout"),
123  offsetof(ngx_mail_ssl_conf_t, session_timeout),
124  NULL },
125 
127 };
128 
129 
130 static ngx_mail_module_t ngx_mail_ssl_module_ctx = {
131  NULL, /* protocol */
132 
133  NULL, /* create main configuration */
134  NULL, /* init main configuration */
135 
136  ngx_mail_ssl_create_conf, /* create server configuration */
137  ngx_mail_ssl_merge_conf /* merge server configuration */
138 };
139 
140 
143  &ngx_mail_ssl_module_ctx, /* module context */
144  ngx_mail_ssl_commands, /* module directives */
145  NGX_MAIL_MODULE, /* module type */
146  NULL, /* init master */
147  NULL, /* init module */
148  NULL, /* init process */
149  NULL, /* init thread */
150  NULL, /* exit thread */
151  NULL, /* exit process */
152  NULL, /* exit master */
154 };
155 
156 
157 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
158 
159 
160 static void *
161 ngx_mail_ssl_create_conf(ngx_conf_t *cf)
162 {
163  ngx_mail_ssl_conf_t *scf;
164 
165  scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
166  if (scf == NULL) {
167  return NULL;
168  }
169 
170  /*
171  * set by ngx_pcalloc():
172  *
173  * scf->protocols = 0;
174  * scf->certificate = { 0, NULL };
175  * scf->certificate_key = { 0, NULL };
176  * scf->dhparam = { 0, NULL };
177  * scf->ecdh_curve = { 0, NULL };
178  * scf->ciphers = { 0, NULL };
179  * scf->shm_zone = NULL;
180  */
181 
182  scf->enable = NGX_CONF_UNSET;
187 
188  return scf;
189 }
190 
191 
192 static char *
193 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
194 {
195  ngx_mail_ssl_conf_t *prev = parent;
196  ngx_mail_ssl_conf_t *conf = child;
197 
198  char *mode;
199  ngx_pool_cleanup_t *cln;
200 
201  ngx_conf_merge_value(conf->enable, prev->enable, 0);
204 
206  prev->session_timeout, 300);
207 
209  prev->prefer_server_ciphers, 0);
210 
214 
217 
218  ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
219 
222 
224 
225 
226  conf->ssl.log = cf->log;
227 
228  if (conf->enable) {
229  mode = "ssl";
230 
231  } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
232  mode = "starttls";
233 
234  } else {
235  mode = "";
236  }
237 
238  if (*mode) {
239 
240  if (conf->certificate.len == 0) {
242  "no \"ssl_certificate\" is defined for "
243  "the \"%s\" directive in %s:%ui",
244  mode, conf->file, conf->line);
245  return NGX_CONF_ERROR;
246  }
247 
248  if (conf->certificate_key.len == 0) {
250  "no \"ssl_certificate_key\" is defined for "
251  "the \"%s\" directive in %s:%ui",
252  mode, conf->file, conf->line);
253  return NGX_CONF_ERROR;
254  }
255 
256  } else {
257 
258  if (conf->certificate.len == 0) {
259  return NGX_CONF_OK;
260  }
261 
262  if (conf->certificate_key.len == 0) {
264  "no \"ssl_certificate_key\" is defined "
265  "for certificate \"%V\"",
266  &conf->certificate);
267  return NGX_CONF_ERROR;
268  }
269  }
270 
271  if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
272  return NGX_CONF_ERROR;
273  }
274 
275  cln = ngx_pool_cleanup_add(cf->pool, 0);
276  if (cln == NULL) {
277  return NGX_CONF_ERROR;
278  }
279 
281  cln->data = &conf->ssl;
282 
283  if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
284  &conf->certificate_key)
285  != NGX_OK)
286  {
287  return NGX_CONF_ERROR;
288  }
289 
290  if (conf->ciphers.len) {
291  if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
292  (const char *) conf->ciphers.data)
293  == 0)
294  {
296  "SSL_CTX_set_cipher_list(\"%V\") failed",
297  &conf->ciphers);
298  }
299  }
300 
301  if (conf->prefer_server_ciphers) {
302  SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
303  }
304 
305  SSL_CTX_set_tmp_rsa_callback(conf->ssl.ctx, ngx_ssl_rsa512_key_callback);
306 
307  if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
308  return NGX_CONF_ERROR;
309  }
310 
313 
314  if (conf->shm_zone == NULL) {
315  conf->shm_zone = prev->shm_zone;
316  }
317 
318  if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
319  conf->builtin_session_cache,
320  conf->shm_zone, conf->session_timeout)
321  != NGX_OK)
322  {
323  return NGX_CONF_ERROR;
324  }
325 
326  return NGX_CONF_OK;
327 }
328 
329 
330 static char *
331 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
332 {
333  ngx_mail_ssl_conf_t *scf = conf;
334 
335  char *rv;
336 
337  rv = ngx_conf_set_flag_slot(cf, cmd, conf);
338 
339  if (rv != NGX_CONF_OK) {
340  return rv;
341  }
342 
343  if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
345  "\"starttls\" directive conflicts with \"ssl on\"");
346  return NGX_CONF_ERROR;
347  }
348 
349  scf->file = cf->conf_file->file.name.data;
350  scf->line = cf->conf_file->line;
351 
352  return NGX_CONF_OK;
353 }
354 
355 
356 static char *
357 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
358 {
359  ngx_mail_ssl_conf_t *scf = conf;
360 
361  char *rv;
362 
363  rv = ngx_conf_set_enum_slot(cf, cmd, conf);
364 
365  if (rv != NGX_CONF_OK) {
366  return rv;
367  }
368 
369  if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
371  "\"ssl\" directive conflicts with \"starttls\"");
372  return NGX_CONF_ERROR;
373  }
374 
375  scf->file = cf->conf_file->file.name.data;
376  scf->line = cf->conf_file->line;
377 
378  return NGX_CONF_OK;
379 }
380 
381 
382 static char *
383 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
384 {
385  ngx_mail_ssl_conf_t *scf = conf;
386 
387  size_t len;
388  ngx_str_t *value, name, size;
389  ngx_int_t n;
390  ngx_uint_t i, j;
391 
392  value = cf->args->elts;
393 
394  for (i = 1; i < cf->args->nelts; i++) {
395 
396  if (ngx_strcmp(value[i].data, "off") == 0) {
398  continue;
399  }
400 
401  if (ngx_strcmp(value[i].data, "none") == 0) {
403  continue;
404  }
405 
406  if (ngx_strcmp(value[i].data, "builtin") == 0) {
408  continue;
409  }
410 
411  if (value[i].len > sizeof("builtin:") - 1
412  && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
413  == 0)
414  {
415  n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
416  value[i].len - (sizeof("builtin:") - 1));
417 
418  if (n == NGX_ERROR) {
419  goto invalid;
420  }
421 
422  scf->builtin_session_cache = n;
423 
424  continue;
425  }
426 
427  if (value[i].len > sizeof("shared:") - 1
428  && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
429  == 0)
430  {
431  len = 0;
432 
433  for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
434  if (value[i].data[j] == ':') {
435  break;
436  }
437 
438  len++;
439  }
440 
441  if (len == 0) {
442  goto invalid;
443  }
444 
445  name.len = len;
446  name.data = value[i].data + sizeof("shared:") - 1;
447 
448  size.len = value[i].len - j - 1;
449  size.data = name.data + len + 1;
450 
451  n = ngx_parse_size(&size);
452 
453  if (n == NGX_ERROR) {
454  goto invalid;
455  }
456 
457  if (n < (ngx_int_t) (8 * ngx_pagesize)) {
459  "session cache \"%V\" is too small",
460  &value[i]);
461 
462  return NGX_CONF_ERROR;
463  }
464 
465  scf->shm_zone = ngx_shared_memory_add(cf, &name, n,
466  &ngx_mail_ssl_module);
467  if (scf->shm_zone == NULL) {
468  return NGX_CONF_ERROR;
469  }
470 
472 
473  continue;
474  }
475 
476  goto invalid;
477  }
478 
479  if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) {
481  }
482 
483  return NGX_CONF_OK;
484 
485 invalid:
486 
488  "invalid session cache \"%V\"", &value[i]);
489 
490  return NGX_CONF_ERROR;
491 }