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 "prime256v1"
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_session_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
28 static ngx_conf_enum_t ngx_http_starttls_state
[] = {
29 { ngx_string("off"), NGX_MAIL_STARTTLS_OFF
},
30 { ngx_string("on"), NGX_MAIL_STARTTLS_ON
},
31 { ngx_string("only"), NGX_MAIL_STARTTLS_ONLY
},
32 { ngx_null_string
, 0 }
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 }
47 static ngx_command_t ngx_mail_ssl_commands
[] = {
50 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_FLAG
,
52 NGX_MAIL_SRV_CONF_OFFSET
,
53 offsetof(ngx_mail_ssl_conf_t
, enable
),
56 { ngx_string("starttls"),
57 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
58 ngx_mail_ssl_starttls
,
59 NGX_MAIL_SRV_CONF_OFFSET
,
60 offsetof(ngx_mail_ssl_conf_t
, starttls
),
61 ngx_http_starttls_state
},
63 { ngx_string("ssl_certificate"),
64 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
65 ngx_conf_set_str_slot
,
66 NGX_MAIL_SRV_CONF_OFFSET
,
67 offsetof(ngx_mail_ssl_conf_t
, certificate
),
70 { ngx_string("ssl_certificate_key"),
71 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
72 ngx_conf_set_str_slot
,
73 NGX_MAIL_SRV_CONF_OFFSET
,
74 offsetof(ngx_mail_ssl_conf_t
, certificate_key
),
77 { ngx_string("ssl_dhparam"),
78 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
79 ngx_conf_set_str_slot
,
80 NGX_MAIL_SRV_CONF_OFFSET
,
81 offsetof(ngx_mail_ssl_conf_t
, dhparam
),
84 { ngx_string("ssl_ecdh_curve"),
85 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
86 ngx_conf_set_str_slot
,
87 NGX_MAIL_SRV_CONF_OFFSET
,
88 offsetof(ngx_mail_ssl_conf_t
, ecdh_curve
),
91 { ngx_string("ssl_protocols"),
92 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_1MORE
,
93 ngx_conf_set_bitmask_slot
,
94 NGX_MAIL_SRV_CONF_OFFSET
,
95 offsetof(ngx_mail_ssl_conf_t
, protocols
),
96 &ngx_mail_ssl_protocols
},
98 { ngx_string("ssl_ciphers"),
99 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
100 ngx_conf_set_str_slot
,
101 NGX_MAIL_SRV_CONF_OFFSET
,
102 offsetof(ngx_mail_ssl_conf_t
, ciphers
),
105 { ngx_string("ssl_prefer_server_ciphers"),
106 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_FLAG
,
107 ngx_conf_set_flag_slot
,
108 NGX_MAIL_SRV_CONF_OFFSET
,
109 offsetof(ngx_mail_ssl_conf_t
, prefer_server_ciphers
),
112 { ngx_string("ssl_session_cache"),
113 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE12
,
114 ngx_mail_ssl_session_cache
,
115 NGX_MAIL_SRV_CONF_OFFSET
,
119 { ngx_string("ssl_session_timeout"),
120 NGX_MAIL_MAIN_CONF
|NGX_MAIL_SRV_CONF
|NGX_CONF_TAKE1
,
121 ngx_conf_set_sec_slot
,
122 NGX_MAIL_SRV_CONF_OFFSET
,
123 offsetof(ngx_mail_ssl_conf_t
, session_timeout
),
130 static ngx_mail_module_t ngx_mail_ssl_module_ctx
= {
133 NULL
, /* create main configuration */
134 NULL
, /* init main configuration */
136 ngx_mail_ssl_create_conf
, /* create server configuration */
137 ngx_mail_ssl_merge_conf
/* merge server configuration */
141 ngx_module_t ngx_mail_ssl_module
= {
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 */
153 NGX_MODULE_V1_PADDING
157 static ngx_str_t ngx_mail_ssl_sess_id_ctx
= ngx_string("MAIL");
161 ngx_mail_ssl_create_conf(ngx_conf_t
*cf
)
163 ngx_mail_ssl_conf_t
*scf
;
165 scf
= ngx_pcalloc(cf
->pool
, sizeof(ngx_mail_ssl_conf_t
));
171 * set by ngx_pcalloc():
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;
182 scf
->enable
= NGX_CONF_UNSET
;
183 scf
->starttls
= NGX_CONF_UNSET_UINT
;
184 scf
->prefer_server_ciphers
= NGX_CONF_UNSET
;
185 scf
->builtin_session_cache
= NGX_CONF_UNSET
;
186 scf
->session_timeout
= NGX_CONF_UNSET
;
193 ngx_mail_ssl_merge_conf(ngx_conf_t
*cf
, void *parent
, void *child
)
195 ngx_mail_ssl_conf_t
*prev
= parent
;
196 ngx_mail_ssl_conf_t
*conf
= child
;
199 ngx_pool_cleanup_t
*cln
;
201 ngx_conf_merge_value(conf
->enable
, prev
->enable
, 0);
202 ngx_conf_merge_uint_value(conf
->starttls
, prev
->starttls
,
203 NGX_MAIL_STARTTLS_OFF
);
205 ngx_conf_merge_value(conf
->session_timeout
,
206 prev
->session_timeout
, 300);
208 ngx_conf_merge_value(conf
->prefer_server_ciphers
,
209 prev
->prefer_server_ciphers
, 0);
211 ngx_conf_merge_bitmask_value(conf
->protocols
, prev
->protocols
,
212 (NGX_CONF_BITMASK_SET
|NGX_SSL_SSLv3
|NGX_SSL_TLSv1
213 |NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2
));
215 ngx_conf_merge_str_value(conf
->certificate
, prev
->certificate
, "");
216 ngx_conf_merge_str_value(conf
->certificate_key
, prev
->certificate_key
, "");
218 ngx_conf_merge_str_value(conf
->dhparam
, prev
->dhparam
, "");
220 ngx_conf_merge_str_value(conf
->ecdh_curve
, prev
->ecdh_curve
,
221 NGX_DEFAULT_ECDH_CURVE
);
223 ngx_conf_merge_str_value(conf
->ciphers
, prev
->ciphers
, NGX_DEFAULT_CIPHERS
);
226 conf
->ssl
.log
= cf
->log
;
231 } else if (conf
->starttls
!= NGX_MAIL_STARTTLS_OFF
) {
238 if (conf
->file
== NULL
) {
239 conf
->file
= prev
->file
;
240 conf
->line
= prev
->line
;
245 if (conf
->certificate
.len
== 0) {
246 ngx_log_error(NGX_LOG_EMERG
, cf
->log
, 0,
247 "no \"ssl_certificate\" is defined for "
248 "the \"%s\" directive in %s:%ui",
249 mode
, conf
->file
, conf
->line
);
250 return NGX_CONF_ERROR
;
253 if (conf
->certificate_key
.len
== 0) {
254 ngx_log_error(NGX_LOG_EMERG
, cf
->log
, 0,
255 "no \"ssl_certificate_key\" is defined for "
256 "the \"%s\" directive in %s:%ui",
257 mode
, conf
->file
, conf
->line
);
258 return NGX_CONF_ERROR
;
263 if (conf
->certificate
.len
== 0) {
267 if (conf
->certificate_key
.len
== 0) {
268 ngx_log_error(NGX_LOG_EMERG
, cf
->log
, 0,
269 "no \"ssl_certificate_key\" is defined "
270 "for certificate \"%V\"",
272 return NGX_CONF_ERROR
;
276 if (ngx_ssl_create(&conf
->ssl
, conf
->protocols
, NULL
) != NGX_OK
) {
277 return NGX_CONF_ERROR
;
280 cln
= ngx_pool_cleanup_add(cf
->pool
, 0);
282 return NGX_CONF_ERROR
;
285 cln
->handler
= ngx_ssl_cleanup_ctx
;
286 cln
->data
= &conf
->ssl
;
288 if (ngx_ssl_certificate(cf
, &conf
->ssl
, &conf
->certificate
,
289 &conf
->certificate_key
)
292 return NGX_CONF_ERROR
;
295 if (conf
->ciphers
.len
) {
296 if (SSL_CTX_set_cipher_list(conf
->ssl
.ctx
,
297 (const char *) conf
->ciphers
.data
)
300 ngx_ssl_error(NGX_LOG_EMERG
, cf
->log
, 0,
301 "SSL_CTX_set_cipher_list(\"%V\") failed",
306 if (conf
->prefer_server_ciphers
) {
307 SSL_CTX_set_options(conf
->ssl
.ctx
, SSL_OP_CIPHER_SERVER_PREFERENCE
);
310 SSL_CTX_set_tmp_rsa_callback(conf
->ssl
.ctx
, ngx_ssl_rsa512_key_callback
);
312 if (ngx_ssl_dhparam(cf
, &conf
->ssl
, &conf
->dhparam
) != NGX_OK
) {
313 return NGX_CONF_ERROR
;
316 ngx_conf_merge_value(conf
->builtin_session_cache
,
317 prev
->builtin_session_cache
, NGX_SSL_NONE_SCACHE
);
319 if (conf
->shm_zone
== NULL
) {
320 conf
->shm_zone
= prev
->shm_zone
;
323 if (ngx_ssl_session_cache(&conf
->ssl
, &ngx_mail_ssl_sess_id_ctx
,
324 conf
->builtin_session_cache
,
325 conf
->shm_zone
, conf
->session_timeout
)
328 return NGX_CONF_ERROR
;
336 ngx_mail_ssl_enable(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
338 ngx_mail_ssl_conf_t
*scf
= conf
;
342 rv
= ngx_conf_set_flag_slot(cf
, cmd
, conf
);
344 if (rv
!= NGX_CONF_OK
) {
348 if (scf
->enable
&& (ngx_int_t
) scf
->starttls
> NGX_MAIL_STARTTLS_OFF
) {
349 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
350 "\"starttls\" directive conflicts with \"ssl on\"");
351 return NGX_CONF_ERROR
;
354 scf
->file
= cf
->conf_file
->file
.name
.data
;
355 scf
->line
= cf
->conf_file
->line
;
362 ngx_mail_ssl_starttls(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
364 ngx_mail_ssl_conf_t
*scf
= conf
;
368 rv
= ngx_conf_set_enum_slot(cf
, cmd
, conf
);
370 if (rv
!= NGX_CONF_OK
) {
374 if (scf
->enable
== 1 && (ngx_int_t
) scf
->starttls
> NGX_MAIL_STARTTLS_OFF
) {
375 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
376 "\"ssl\" directive conflicts with \"starttls\"");
377 return NGX_CONF_ERROR
;
380 scf
->file
= cf
->conf_file
->file
.name
.data
;
381 scf
->line
= cf
->conf_file
->line
;
388 ngx_mail_ssl_session_cache(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
390 ngx_mail_ssl_conf_t
*scf
= conf
;
393 ngx_str_t
*value
, name
, size
;
397 value
= cf
->args
->elts
;
399 for (i
= 1; i
< cf
->args
->nelts
; i
++) {
401 if (ngx_strcmp(value
[i
].data
, "off") == 0) {
402 scf
->builtin_session_cache
= NGX_SSL_NO_SCACHE
;
406 if (ngx_strcmp(value
[i
].data
, "none") == 0) {
407 scf
->builtin_session_cache
= NGX_SSL_NONE_SCACHE
;
411 if (ngx_strcmp(value
[i
].data
, "builtin") == 0) {
412 scf
->builtin_session_cache
= NGX_SSL_DFLT_BUILTIN_SCACHE
;
416 if (value
[i
].len
> sizeof("builtin:") - 1
417 && ngx_strncmp(value
[i
].data
, "builtin:", sizeof("builtin:") - 1)
420 n
= ngx_atoi(value
[i
].data
+ sizeof("builtin:") - 1,
421 value
[i
].len
- (sizeof("builtin:") - 1));
423 if (n
== NGX_ERROR
) {
427 scf
->builtin_session_cache
= n
;
432 if (value
[i
].len
> sizeof("shared:") - 1
433 && ngx_strncmp(value
[i
].data
, "shared:", sizeof("shared:") - 1)
438 for (j
= sizeof("shared:") - 1; j
< value
[i
].len
; j
++) {
439 if (value
[i
].data
[j
] == ':') {
451 name
.data
= value
[i
].data
+ sizeof("shared:") - 1;
453 size
.len
= value
[i
].len
- j
- 1;
454 size
.data
= name
.data
+ len
+ 1;
456 n
= ngx_parse_size(&size
);
458 if (n
== NGX_ERROR
) {
462 if (n
< (ngx_int_t
) (8 * ngx_pagesize
)) {
463 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
464 "session cache \"%V\" is too small",
467 return NGX_CONF_ERROR
;
470 scf
->shm_zone
= ngx_shared_memory_add(cf
, &name
, n
,
471 &ngx_mail_ssl_module
);
472 if (scf
->shm_zone
== NULL
) {
473 return NGX_CONF_ERROR
;
476 scf
->shm_zone
->init
= ngx_ssl_session_cache_init
;
484 if (scf
->shm_zone
&& scf
->builtin_session_cache
== NGX_CONF_UNSET
) {
485 scf
->builtin_session_cache
= NGX_SSL_NO_BUILTIN_SCACHE
;
492 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
493 "invalid session cache \"%V\"", &value
[i
]);
495 return NGX_CONF_ERROR
;