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  "auto"
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_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
25     void *conf);
26 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
27     void *conf);
28 
29 
30 static ngx_conf_enum_t  ngx_mail_starttls_state[] = {
31     { ngx_string("off"), NGX_MAIL_STARTTLS_OFF },
32     { ngx_string("on"), NGX_MAIL_STARTTLS_ON },
33     { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY },
34     { ngx_null_string, 0 }
35 };
36 
37 
38 
39 static ngx_conf_bitmask_t  ngx_mail_ssl_protocols[] = {
40     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
41     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
42     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
43     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
44     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
45     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
46     { ngx_null_string, 0 }
47 };
48 
49 
50 static ngx_conf_enum_t  ngx_mail_ssl_verify[] = {
51     { ngx_string("off"), 0 },
52     { ngx_string("on"), 1 },
53     { ngx_string("optional"), 2 },
54     { ngx_string("optional_no_ca"), 3 },
55     { ngx_null_string, 0 }
56 };
57 
58 
59 static ngx_conf_deprecated_t  ngx_mail_ssl_deprecated = {
60     ngx_conf_deprecated, "ssl", "listen ... ssl"
61 };
62 
63 
64 static ngx_command_t  ngx_mail_ssl_commands[] = {
65 
66     { ngx_string("ssl"),
67       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
68       ngx_mail_ssl_enable,
69       NGX_MAIL_SRV_CONF_OFFSET,
70       offsetof(ngx_mail_ssl_conf_t, enable),
71       &ngx_mail_ssl_deprecated },
72 
73     { ngx_string("starttls"),
74       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
75       ngx_mail_ssl_starttls,
76       NGX_MAIL_SRV_CONF_OFFSET,
77       offsetof(ngx_mail_ssl_conf_t, starttls),
78       ngx_mail_starttls_state },
79 
80     { ngx_string("ssl_certificate"),
81       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
82       ngx_conf_set_str_array_slot,
83       NGX_MAIL_SRV_CONF_OFFSET,
84       offsetof(ngx_mail_ssl_conf_t, certificates),
85       NULL },
86 
87     { ngx_string("ssl_certificate_key"),
88       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
89       ngx_conf_set_str_array_slot,
90       NGX_MAIL_SRV_CONF_OFFSET,
91       offsetof(ngx_mail_ssl_conf_t, certificate_keys),
92       NULL },
93 
94     { ngx_string("ssl_password_file"),
95       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
96       ngx_mail_ssl_password_file,
97       NGX_MAIL_SRV_CONF_OFFSET,
98       0,
99       NULL },
100 
101     { ngx_string("ssl_dhparam"),
102       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
103       ngx_conf_set_str_slot,
104       NGX_MAIL_SRV_CONF_OFFSET,
105       offsetof(ngx_mail_ssl_conf_t, dhparam),
106       NULL },
107 
108     { ngx_string("ssl_ecdh_curve"),
109       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
110       ngx_conf_set_str_slot,
111       NGX_MAIL_SRV_CONF_OFFSET,
112       offsetof(ngx_mail_ssl_conf_t, ecdh_curve),
113       NULL },
114 
115     { ngx_string("ssl_protocols"),
116       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
117       ngx_conf_set_bitmask_slot,
118       NGX_MAIL_SRV_CONF_OFFSET,
119       offsetof(ngx_mail_ssl_conf_t, protocols),
120       &ngx_mail_ssl_protocols },
121 
122     { ngx_string("ssl_ciphers"),
123       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
124       ngx_conf_set_str_slot,
125       NGX_MAIL_SRV_CONF_OFFSET,
126       offsetof(ngx_mail_ssl_conf_t, ciphers),
127       NULL },
128 
129     { ngx_string("ssl_prefer_server_ciphers"),
130       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
131       ngx_conf_set_flag_slot,
132       NGX_MAIL_SRV_CONF_OFFSET,
133       offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
134       NULL },
135 
136     { ngx_string("ssl_session_cache"),
137       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
138       ngx_mail_ssl_session_cache,
139       NGX_MAIL_SRV_CONF_OFFSET,
140       0,
141       NULL },
142 
143     { ngx_string("ssl_session_tickets"),
144       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
145       ngx_conf_set_flag_slot,
146       NGX_MAIL_SRV_CONF_OFFSET,
147       offsetof(ngx_mail_ssl_conf_t, session_tickets),
148       NULL },
149 
150     { ngx_string("ssl_session_ticket_key"),
151       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
152       ngx_conf_set_str_array_slot,
153       NGX_MAIL_SRV_CONF_OFFSET,
154       offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
155       NULL },
156 
157     { ngx_string("ssl_session_timeout"),
158       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
159       ngx_conf_set_sec_slot,
160       NGX_MAIL_SRV_CONF_OFFSET,
161       offsetof(ngx_mail_ssl_conf_t, session_timeout),
162       NULL },
163 
164     { ngx_string("ssl_verify_client"),
165       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
166       ngx_conf_set_enum_slot,
167       NGX_MAIL_SRV_CONF_OFFSET,
168       offsetof(ngx_mail_ssl_conf_t, verify),
169       &ngx_mail_ssl_verify },
170 
171     { ngx_string("ssl_verify_depth"),
172       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
173       ngx_conf_set_num_slot,
174       NGX_MAIL_SRV_CONF_OFFSET,
175       offsetof(ngx_mail_ssl_conf_t, verify_depth),
176       NULL },
177 
178     { ngx_string("ssl_client_certificate"),
179       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
180       ngx_conf_set_str_slot,
181       NGX_MAIL_SRV_CONF_OFFSET,
182       offsetof(ngx_mail_ssl_conf_t, client_certificate),
183       NULL },
184 
185     { ngx_string("ssl_trusted_certificate"),
186       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
187       ngx_conf_set_str_slot,
188       NGX_MAIL_SRV_CONF_OFFSET,
189       offsetof(ngx_mail_ssl_conf_t, trusted_certificate),
190       NULL },
191 
192     { ngx_string("ssl_crl"),
193       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
194       ngx_conf_set_str_slot,
195       NGX_MAIL_SRV_CONF_OFFSET,
196       offsetof(ngx_mail_ssl_conf_t, crl),
197       NULL },
198 
199       ngx_null_command
200 };
201 
202 
203 static ngx_mail_module_t  ngx_mail_ssl_module_ctx = {
204     NULL,                                  /* protocol */
205 
206     NULL,                                  /* create main configuration */
207     NULL,                                  /* init main configuration */
208 
209     ngx_mail_ssl_create_conf,              /* create server configuration */
210     ngx_mail_ssl_merge_conf                /* merge server configuration */
211 };
212 
213 
214 ngx_module_t  ngx_mail_ssl_module = {
215     NGX_MODULE_V1,
216     &ngx_mail_ssl_module_ctx,              /* module context */
217     ngx_mail_ssl_commands,                 /* module directives */
218     NGX_MAIL_MODULE,                       /* module type */
219     NULL,                                  /* init master */
220     NULL,                                  /* init module */
221     NULL,                                  /* init process */
222     NULL,                                  /* init thread */
223     NULL,                                  /* exit thread */
224     NULL,                                  /* exit process */
225     NULL,                                  /* exit master */
226     NGX_MODULE_V1_PADDING
227 };
228 
229 
230 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
231 
232 
233 static void *
ngx_mail_ssl_create_conf(ngx_conf_t * cf)234 ngx_mail_ssl_create_conf(ngx_conf_t *cf)
235 {
236     ngx_mail_ssl_conf_t  *scf;
237 
238     scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
239     if (scf == NULL) {
240         return NULL;
241     }
242 
243     /*
244      * set by ngx_pcalloc():
245      *
246      *     scf->listen = 0;
247      *     scf->protocols = 0;
248      *     scf->dhparam = { 0, NULL };
249      *     scf->ecdh_curve = { 0, NULL };
250      *     scf->client_certificate = { 0, NULL };
251      *     scf->trusted_certificate = { 0, NULL };
252      *     scf->crl = { 0, NULL };
253      *     scf->ciphers = { 0, NULL };
254      *     scf->shm_zone = NULL;
255      */
256 
257     scf->enable = NGX_CONF_UNSET;
258     scf->starttls = NGX_CONF_UNSET_UINT;
259     scf->certificates = NGX_CONF_UNSET_PTR;
260     scf->certificate_keys = NGX_CONF_UNSET_PTR;
261     scf->passwords = NGX_CONF_UNSET_PTR;
262     scf->prefer_server_ciphers = NGX_CONF_UNSET;
263     scf->verify = NGX_CONF_UNSET_UINT;
264     scf->verify_depth = NGX_CONF_UNSET_UINT;
265     scf->builtin_session_cache = NGX_CONF_UNSET;
266     scf->session_timeout = NGX_CONF_UNSET;
267     scf->session_tickets = NGX_CONF_UNSET;
268     scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
269 
270     return scf;
271 }
272 
273 
274 static char *
ngx_mail_ssl_merge_conf(ngx_conf_t * cf,void * parent,void * child)275 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
276 {
277     ngx_mail_ssl_conf_t *prev = parent;
278     ngx_mail_ssl_conf_t *conf = child;
279 
280     char                *mode;
281     ngx_pool_cleanup_t  *cln;
282 
283     ngx_conf_merge_value(conf->enable, prev->enable, 0);
284     ngx_conf_merge_uint_value(conf->starttls, prev->starttls,
285                          NGX_MAIL_STARTTLS_OFF);
286 
287     ngx_conf_merge_value(conf->session_timeout,
288                          prev->session_timeout, 300);
289 
290     ngx_conf_merge_value(conf->prefer_server_ciphers,
291                          prev->prefer_server_ciphers, 0);
292 
293     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
294                          (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
295                           |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
296 
297     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
298     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
299 
300     ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
301     ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
302                          NULL);
303 
304     ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
305 
306     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
307 
308     ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
309                          NGX_DEFAULT_ECDH_CURVE);
310 
311     ngx_conf_merge_str_value(conf->client_certificate,
312                          prev->client_certificate, "");
313     ngx_conf_merge_str_value(conf->trusted_certificate,
314                          prev->trusted_certificate, "");
315     ngx_conf_merge_str_value(conf->crl, prev->crl, "");
316 
317     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
318 
319 
320     conf->ssl.log = cf->log;
321 
322     if (conf->listen) {
323         mode = "listen ... ssl";
324 
325     } else if (conf->enable) {
326         mode = "ssl";
327 
328     } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
329         mode = "starttls";
330 
331     } else {
332         return NGX_CONF_OK;
333     }
334 
335     if (conf->file == NULL) {
336         conf->file = prev->file;
337         conf->line = prev->line;
338     }
339 
340     if (conf->certificates == NULL) {
341         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
342                       "no \"ssl_certificate\" is defined for "
343                       "the \"%s\" directive in %s:%ui",
344                       mode, conf->file, conf->line);
345         return NGX_CONF_ERROR;
346     }
347 
348     if (conf->certificate_keys == NULL) {
349         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
350                       "no \"ssl_certificate_key\" is defined for "
351                       "the \"%s\" directive in %s:%ui",
352                       mode, conf->file, conf->line);
353         return NGX_CONF_ERROR;
354     }
355 
356     if (conf->certificate_keys->nelts < conf->certificates->nelts) {
357         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
358                       "no \"ssl_certificate_key\" is defined "
359                       "for certificate \"%V\" and "
360                       "the \"%s\" directive in %s:%ui",
361                       ((ngx_str_t *) conf->certificates->elts)
362                       + conf->certificates->nelts - 1,
363                       mode, conf->file, conf->line);
364         return NGX_CONF_ERROR;
365     }
366 
367     if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
368         return NGX_CONF_ERROR;
369     }
370 
371     cln = ngx_pool_cleanup_add(cf->pool, 0);
372     if (cln == NULL) {
373         ngx_ssl_cleanup_ctx(&conf->ssl);
374         return NGX_CONF_ERROR;
375     }
376 
377     cln->handler = ngx_ssl_cleanup_ctx;
378     cln->data = &conf->ssl;
379 
380     if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
381                              conf->certificate_keys, conf->passwords)
382         != NGX_OK)
383     {
384         return NGX_CONF_ERROR;
385     }
386 
387     if (conf->verify) {
388 
389         if (conf->client_certificate.len == 0 && conf->verify != 3) {
390             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
391                           "no ssl_client_certificate for ssl_client_verify");
392             return NGX_CONF_ERROR;
393         }
394 
395         if (ngx_ssl_client_certificate(cf, &conf->ssl,
396                                        &conf->client_certificate,
397                                        conf->verify_depth)
398             != NGX_OK)
399         {
400             return NGX_CONF_ERROR;
401         }
402 
403         if (ngx_ssl_trusted_certificate(cf, &conf->ssl,
404                                         &conf->trusted_certificate,
405                                         conf->verify_depth)
406             != NGX_OK)
407         {
408             return NGX_CONF_ERROR;
409         }
410 
411         if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
412             return NGX_CONF_ERROR;
413         }
414     }
415 
416     if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
417                         conf->prefer_server_ciphers)
418         != NGX_OK)
419     {
420         return NGX_CONF_ERROR;
421     }
422 
423     if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
424         return NGX_CONF_ERROR;
425     }
426 
427     if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
428         return NGX_CONF_ERROR;
429     }
430 
431     ngx_conf_merge_value(conf->builtin_session_cache,
432                          prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
433 
434     if (conf->shm_zone == NULL) {
435         conf->shm_zone = prev->shm_zone;
436     }
437 
438     if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
439                               conf->certificates, conf->builtin_session_cache,
440                               conf->shm_zone, conf->session_timeout)
441         != NGX_OK)
442     {
443         return NGX_CONF_ERROR;
444     }
445 
446     ngx_conf_merge_value(conf->session_tickets,
447                          prev->session_tickets, 1);
448 
449 #ifdef SSL_OP_NO_TICKET
450     if (!conf->session_tickets) {
451         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
452     }
453 #endif
454 
455     ngx_conf_merge_ptr_value(conf->session_ticket_keys,
456                          prev->session_ticket_keys, NULL);
457 
458     if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
459         != NGX_OK)
460     {
461         return NGX_CONF_ERROR;
462     }
463 
464     return NGX_CONF_OK;
465 }
466 
467 
468 static char *
ngx_mail_ssl_enable(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)469 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
470 {
471     ngx_mail_ssl_conf_t  *scf = conf;
472 
473     char  *rv;
474 
475     rv = ngx_conf_set_flag_slot(cf, cmd, conf);
476 
477     if (rv != NGX_CONF_OK) {
478         return rv;
479     }
480 
481     if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
482         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
483                            "\"starttls\" directive conflicts with \"ssl on\"");
484         return NGX_CONF_ERROR;
485     }
486 
487     if (!scf->listen) {
488         scf->file = cf->conf_file->file.name.data;
489         scf->line = cf->conf_file->line;
490     }
491 
492     return NGX_CONF_OK;
493 }
494 
495 
496 static char *
ngx_mail_ssl_starttls(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)497 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
498 {
499     ngx_mail_ssl_conf_t  *scf = conf;
500 
501     char  *rv;
502 
503     rv = ngx_conf_set_enum_slot(cf, cmd, conf);
504 
505     if (rv != NGX_CONF_OK) {
506         return rv;
507     }
508 
509     if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
510         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
511                            "\"ssl\" directive conflicts with \"starttls\"");
512         return NGX_CONF_ERROR;
513     }
514 
515     if (!scf->listen) {
516         scf->file = cf->conf_file->file.name.data;
517         scf->line = cf->conf_file->line;
518     }
519 
520     return NGX_CONF_OK;
521 }
522 
523 
524 static char *
ngx_mail_ssl_password_file(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)525 ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
526 {
527     ngx_mail_ssl_conf_t  *scf = conf;
528 
529     ngx_str_t  *value;
530 
531     if (scf->passwords != NGX_CONF_UNSET_PTR) {
532         return "is duplicate";
533     }
534 
535     value = cf->args->elts;
536 
537     scf->passwords = ngx_ssl_read_password_file(cf, &value[1]);
538 
539     if (scf->passwords == NULL) {
540         return NGX_CONF_ERROR;
541     }
542 
543     return NGX_CONF_OK;
544 }
545 
546 
547 static char *
ngx_mail_ssl_session_cache(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)548 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
549 {
550     ngx_mail_ssl_conf_t  *scf = conf;
551 
552     size_t       len;
553     ngx_str_t   *value, name, size;
554     ngx_int_t    n;
555     ngx_uint_t   i, j;
556 
557     value = cf->args->elts;
558 
559     for (i = 1; i < cf->args->nelts; i++) {
560 
561         if (ngx_strcmp(value[i].data, "off") == 0) {
562             scf->builtin_session_cache = NGX_SSL_NO_SCACHE;
563             continue;
564         }
565 
566         if (ngx_strcmp(value[i].data, "none") == 0) {
567             scf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
568             continue;
569         }
570 
571         if (ngx_strcmp(value[i].data, "builtin") == 0) {
572             scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
573             continue;
574         }
575 
576         if (value[i].len > sizeof("builtin:") - 1
577             && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
578                == 0)
579         {
580             n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
581                          value[i].len - (sizeof("builtin:") - 1));
582 
583             if (n == NGX_ERROR) {
584                 goto invalid;
585             }
586 
587             scf->builtin_session_cache = n;
588 
589             continue;
590         }
591 
592         if (value[i].len > sizeof("shared:") - 1
593             && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
594                == 0)
595         {
596             len = 0;
597 
598             for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
599                 if (value[i].data[j] == ':') {
600                     break;
601                 }
602 
603                 len++;
604             }
605 
606             if (len == 0) {
607                 goto invalid;
608             }
609 
610             name.len = len;
611             name.data = value[i].data + sizeof("shared:") - 1;
612 
613             size.len = value[i].len - j - 1;
614             size.data = name.data + len + 1;
615 
616             n = ngx_parse_size(&size);
617 
618             if (n == NGX_ERROR) {
619                 goto invalid;
620             }
621 
622             if (n < (ngx_int_t) (8 * ngx_pagesize)) {
623                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
624                                    "session cache \"%V\" is too small",
625                                    &value[i]);
626 
627                 return NGX_CONF_ERROR;
628             }
629 
630             scf->shm_zone = ngx_shared_memory_add(cf, &name, n,
631                                                    &ngx_mail_ssl_module);
632             if (scf->shm_zone == NULL) {
633                 return NGX_CONF_ERROR;
634             }
635 
636             scf->shm_zone->init = ngx_ssl_session_cache_init;
637 
638             continue;
639         }
640 
641         goto invalid;
642     }
643 
644     if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) {
645         scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
646     }
647 
648     return NGX_CONF_OK;
649 
650 invalid:
651 
652     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
653                        "invalid session cache \"%V\"", &value[i]);
654 
655     return NGX_CONF_ERROR;
656 }
657