3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5"
14 #define NGX_DEFAULT_ECDH_CURVE "auto"
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);
20 static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
22 static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd,
24 static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
26 static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
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 }
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_null_string, 0 }
49 static ngx_conf_enum_t ngx_mail_ssl_verify[] = {
50 { ngx_string("off"), 0 },
51 { ngx_string("on"), 1 },
52 { ngx_string("optional"), 2 },
53 { ngx_string("optional_no_ca"), 3 },
54 { ngx_null_string, 0 }
58 static ngx_command_t ngx_mail_ssl_commands[] = {
61 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
63 NGX_MAIL_SRV_CONF_OFFSET,
64 offsetof(ngx_mail_ssl_conf_t, enable),
67 { ngx_string("starttls"),
68 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
69 ngx_mail_ssl_starttls,
70 NGX_MAIL_SRV_CONF_OFFSET,
71 offsetof(ngx_mail_ssl_conf_t, starttls),
72 ngx_mail_starttls_state },
74 { ngx_string("ssl_certificate"),
75 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
76 ngx_conf_set_str_array_slot,
77 NGX_MAIL_SRV_CONF_OFFSET,
78 offsetof(ngx_mail_ssl_conf_t, certificates),
81 { ngx_string("ssl_certificate_key"),
82 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
83 ngx_conf_set_str_array_slot,
84 NGX_MAIL_SRV_CONF_OFFSET,
85 offsetof(ngx_mail_ssl_conf_t, certificate_keys),
88 { ngx_string("ssl_password_file"),
89 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
90 ngx_mail_ssl_password_file,
91 NGX_MAIL_SRV_CONF_OFFSET,
95 { ngx_string("ssl_dhparam"),
96 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
97 ngx_conf_set_str_slot,
98 NGX_MAIL_SRV_CONF_OFFSET,
99 offsetof(ngx_mail_ssl_conf_t, dhparam),
102 { ngx_string("ssl_ecdh_curve"),
103 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
104 ngx_conf_set_str_slot,
105 NGX_MAIL_SRV_CONF_OFFSET,
106 offsetof(ngx_mail_ssl_conf_t, ecdh_curve),
109 { ngx_string("ssl_protocols"),
110 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
111 ngx_conf_set_bitmask_slot,
112 NGX_MAIL_SRV_CONF_OFFSET,
113 offsetof(ngx_mail_ssl_conf_t, protocols),
114 &ngx_mail_ssl_protocols },
116 { ngx_string("ssl_ciphers"),
117 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
118 ngx_conf_set_str_slot,
119 NGX_MAIL_SRV_CONF_OFFSET,
120 offsetof(ngx_mail_ssl_conf_t, ciphers),
123 { ngx_string("ssl_prefer_server_ciphers"),
124 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
125 ngx_conf_set_flag_slot,
126 NGX_MAIL_SRV_CONF_OFFSET,
127 offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers),
130 { ngx_string("ssl_session_cache"),
131 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
132 ngx_mail_ssl_session_cache,
133 NGX_MAIL_SRV_CONF_OFFSET,
137 { ngx_string("ssl_session_tickets"),
138 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
139 ngx_conf_set_flag_slot,
140 NGX_MAIL_SRV_CONF_OFFSET,
141 offsetof(ngx_mail_ssl_conf_t, session_tickets),
144 { ngx_string("ssl_session_ticket_key"),
145 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
146 ngx_conf_set_str_array_slot,
147 NGX_MAIL_SRV_CONF_OFFSET,
148 offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
151 { ngx_string("ssl_session_timeout"),
152 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
153 ngx_conf_set_sec_slot,
154 NGX_MAIL_SRV_CONF_OFFSET,
155 offsetof(ngx_mail_ssl_conf_t, session_timeout),
158 { ngx_string("ssl_verify_client"),
159 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
160 ngx_conf_set_enum_slot,
161 NGX_MAIL_SRV_CONF_OFFSET,
162 offsetof(ngx_mail_ssl_conf_t, verify),
163 &ngx_mail_ssl_verify },
165 { ngx_string("ssl_verify_depth"),
166 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
167 ngx_conf_set_num_slot,
168 NGX_MAIL_SRV_CONF_OFFSET,
169 offsetof(ngx_mail_ssl_conf_t, verify_depth),
172 { ngx_string("ssl_client_certificate"),
173 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
174 ngx_conf_set_str_slot,
175 NGX_MAIL_SRV_CONF_OFFSET,
176 offsetof(ngx_mail_ssl_conf_t, client_certificate),
179 { ngx_string("ssl_trusted_certificate"),
180 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
181 ngx_conf_set_str_slot,
182 NGX_MAIL_SRV_CONF_OFFSET,
183 offsetof(ngx_mail_ssl_conf_t, trusted_certificate),
186 { ngx_string("ssl_crl"),
187 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
188 ngx_conf_set_str_slot,
189 NGX_MAIL_SRV_CONF_OFFSET,
190 offsetof(ngx_mail_ssl_conf_t, crl),
197 static ngx_mail_module_t ngx_mail_ssl_module_ctx = {
200 NULL, /* create main configuration */
201 NULL, /* init main configuration */
203 ngx_mail_ssl_create_conf, /* create server configuration */
204 ngx_mail_ssl_merge_conf /* merge server configuration */
208 ngx_module_t ngx_mail_ssl_module = {
210 &ngx_mail_ssl_module_ctx, /* module context */
211 ngx_mail_ssl_commands, /* module directives */
212 NGX_MAIL_MODULE, /* module type */
213 NULL, /* init master */
214 NULL, /* init module */
215 NULL, /* init process */
216 NULL, /* init thread */
217 NULL, /* exit thread */
218 NULL, /* exit process */
219 NULL, /* exit master */
220 NGX_MODULE_V1_PADDING
224 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
228 ngx_mail_ssl_create_conf(ngx_conf_t *cf)
230 ngx_mail_ssl_conf_t *scf;
232 scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t));
238 * set by ngx_pcalloc():
240 * scf->protocols = 0;
241 * scf->dhparam = { 0, NULL };
242 * scf->ecdh_curve = { 0, NULL };
243 * scf->client_certificate = { 0, NULL };
244 * scf->trusted_certificate = { 0, NULL };
245 * scf->crl = { 0, NULL };
246 * scf->ciphers = { 0, NULL };
247 * scf->shm_zone = NULL;
250 scf->enable = NGX_CONF_UNSET;
251 scf->starttls = NGX_CONF_UNSET_UINT;
252 scf->certificates = NGX_CONF_UNSET_PTR;
253 scf->certificate_keys = NGX_CONF_UNSET_PTR;
254 scf->passwords = NGX_CONF_UNSET_PTR;
255 scf->prefer_server_ciphers = NGX_CONF_UNSET;
256 scf->verify = NGX_CONF_UNSET_UINT;
257 scf->verify_depth = NGX_CONF_UNSET_UINT;
258 scf->builtin_session_cache = NGX_CONF_UNSET;
259 scf->session_timeout = NGX_CONF_UNSET;
260 scf->session_tickets = NGX_CONF_UNSET;
261 scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
268 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
270 ngx_mail_ssl_conf_t *prev = parent;
271 ngx_mail_ssl_conf_t *conf = child;
274 ngx_pool_cleanup_t *cln;
276 ngx_conf_merge_value(conf->enable, prev->enable, 0);
277 ngx_conf_merge_uint_value(conf->starttls, prev->starttls,
278 NGX_MAIL_STARTTLS_OFF);
280 ngx_conf_merge_value(conf->session_timeout,
281 prev->session_timeout, 300);
283 ngx_conf_merge_value(conf->prefer_server_ciphers,
284 prev->prefer_server_ciphers, 0);
286 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
287 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
288 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
290 ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
291 ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
293 ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
294 ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
297 ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
299 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
301 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
302 NGX_DEFAULT_ECDH_CURVE);
304 ngx_conf_merge_str_value(conf->client_certificate,
305 prev->client_certificate, "");
306 ngx_conf_merge_str_value(conf->trusted_certificate,
307 prev->trusted_certificate, "");
308 ngx_conf_merge_str_value(conf->crl, prev->crl, "");
310 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
313 conf->ssl.log = cf->log;
318 } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
325 if (conf->file == NULL) {
326 conf->file = prev->file;
327 conf->line = prev->line;
332 if (conf->certificates == NULL) {
333 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
334 "no \"ssl_certificate\" is defined for "
335 "the \"%s\" directive in %s:%ui",
336 mode, conf->file, conf->line);
337 return NGX_CONF_ERROR;
340 if (conf->certificate_keys == NULL) {
341 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
342 "no \"ssl_certificate_key\" is defined for "
343 "the \"%s\" directive in %s:%ui",
344 mode, conf->file, conf->line);
345 return NGX_CONF_ERROR;
348 if (conf->certificate_keys->nelts < conf->certificates->nelts) {
349 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
350 "no \"ssl_certificate_key\" is defined "
351 "for certificate \"%V\" and "
352 "the \"ssl\" directive in %s:%ui",
353 ((ngx_str_t *) conf->certificates->elts)
354 + conf->certificates->nelts - 1,
355 conf->file, conf->line);
356 return NGX_CONF_ERROR;
361 if (conf->certificates == NULL) {
365 if (conf->certificate_keys == NULL
366 || conf->certificate_keys->nelts < conf->certificates->nelts)
368 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
369 "no \"ssl_certificate_key\" is defined "
370 "for certificate \"%V\"",
371 ((ngx_str_t *) conf->certificates->elts)
372 + conf->certificates->nelts - 1);
373 return NGX_CONF_ERROR;
377 if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
378 return NGX_CONF_ERROR;
381 cln = ngx_pool_cleanup_add(cf->pool, 0);
383 return NGX_CONF_ERROR;
386 cln->handler = ngx_ssl_cleanup_ctx;
387 cln->data = &conf->ssl;
389 if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
390 conf->certificate_keys, conf->passwords)
393 return NGX_CONF_ERROR;
398 if (conf->client_certificate.len == 0 && conf->verify != 3) {
399 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
400 "no ssl_client_certificate for ssl_client_verify");
401 return NGX_CONF_ERROR;
404 if (ngx_ssl_client_certificate(cf, &conf->ssl,
405 &conf->client_certificate,
409 return NGX_CONF_ERROR;
412 if (ngx_ssl_trusted_certificate(cf, &conf->ssl,
413 &conf->trusted_certificate,
417 return NGX_CONF_ERROR;
420 if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
421 return NGX_CONF_ERROR;
425 if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
426 conf->prefer_server_ciphers)
429 return NGX_CONF_ERROR;
432 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
433 return NGX_CONF_ERROR;
436 if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) {
437 return NGX_CONF_ERROR;
440 ngx_conf_merge_value(conf->builtin_session_cache,
441 prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
443 if (conf->shm_zone == NULL) {
444 conf->shm_zone = prev->shm_zone;
447 if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
448 conf->builtin_session_cache,
449 conf->shm_zone, conf->session_timeout)
452 return NGX_CONF_ERROR;
455 ngx_conf_merge_value(conf->session_tickets,
456 prev->session_tickets, 1);
458 #ifdef SSL_OP_NO_TICKET
459 if (!conf->session_tickets) {
460 SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_NO_TICKET);
464 ngx_conf_merge_ptr_value(conf->session_ticket_keys,
465 prev->session_ticket_keys, NULL);
467 if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
470 return NGX_CONF_ERROR;
478 ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
480 ngx_mail_ssl_conf_t *scf = conf;
484 rv = ngx_conf_set_flag_slot(cf, cmd, conf);
486 if (rv != NGX_CONF_OK) {
490 if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
491 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
492 "\"starttls\" directive conflicts with \"ssl on\"");
493 return NGX_CONF_ERROR;
496 scf->file = cf->conf_file->file.name.data;
497 scf->line = cf->conf_file->line;
504 ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
506 ngx_mail_ssl_conf_t *scf = conf;
510 rv = ngx_conf_set_enum_slot(cf, cmd, conf);
512 if (rv != NGX_CONF_OK) {
516 if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) {
517 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
518 "\"ssl\" directive conflicts with \"starttls\"");
519 return NGX_CONF_ERROR;
522 scf->file = cf->conf_file->file.name.data;
523 scf->line = cf->conf_file->line;
530 ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
532 ngx_mail_ssl_conf_t *scf = conf;
536 if (scf->passwords != NGX_CONF_UNSET_PTR) {
537 return "is duplicate";
540 value = cf->args->elts;
542 scf->passwords = ngx_ssl_read_password_file(cf, &value[1]);
544 if (scf->passwords == NULL) {
545 return NGX_CONF_ERROR;
553 ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
555 ngx_mail_ssl_conf_t *scf = conf;
558 ngx_str_t *value, name, size;
562 value = cf->args->elts;
564 for (i = 1; i < cf->args->nelts; i++) {
566 if (ngx_strcmp(value[i].data, "off") == 0) {
567 scf->builtin_session_cache = NGX_SSL_NO_SCACHE;
571 if (ngx_strcmp(value[i].data, "none") == 0) {
572 scf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
576 if (ngx_strcmp(value[i].data, "builtin") == 0) {
577 scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
581 if (value[i].len > sizeof("builtin:") - 1
582 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
585 n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
586 value[i].len - (sizeof("builtin:") - 1));
588 if (n == NGX_ERROR) {
592 scf->builtin_session_cache = n;
597 if (value[i].len > sizeof("shared:") - 1
598 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
603 for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
604 if (value[i].data[j] == ':') {
616 name.data = value[i].data + sizeof("shared:") - 1;
618 size.len = value[i].len - j - 1;
619 size.data = name.data + len + 1;
621 n = ngx_parse_size(&size);
623 if (n == NGX_ERROR) {
627 if (n < (ngx_int_t) (8 * ngx_pagesize)) {
628 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
629 "session cache \"%V\" is too small",
632 return NGX_CONF_ERROR;
635 scf->shm_zone = ngx_shared_memory_add(cf, &name, n,
636 &ngx_mail_ssl_module);
637 if (scf->shm_zone == NULL) {
638 return NGX_CONF_ERROR;
641 scf->shm_zone->init = ngx_ssl_session_cache_init;
649 if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) {
650 scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
657 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
658 "invalid session cache \"%V\"", &value[i]);
660 return NGX_CONF_ERROR;