1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c,
13 ngx_pool_t *pool, ngx_str_t *s);
14
15
16 #define NGX_DEFAULT_CIPHERS "HIGH:!ADH:!MD5"
17
18
19 static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r,
20 ngx_http_variable_value_t *v, uintptr_t data);
21 static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r,
22 ngx_http_variable_value_t *v, uintptr_t data);
23
24 static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf);
25 static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
26 static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
27 void *parent, void *child);
28
29 static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
30 void *conf);
31 static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
32 void *conf);
33
34
35 static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = {
36 { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
37 { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
38 { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
39 { ngx_null_string, 0 }
40 };
41
42
43 static ngx_conf_enum_t ngx_http_ssl_verify[] = {
44 { ngx_string("off"), 0 },
45 { ngx_string("on"), 1 },
46 { ngx_string("optional"), 2 },
47 { ngx_null_string, 0 }
48 };
49
50
51 static ngx_command_t ngx_http_ssl_commands[] = {
52
53 { ngx_string("ssl"),
54 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
55 ngx_http_ssl_enable,
56 NGX_HTTP_SRV_CONF_OFFSET,
57 offsetof(ngx_http_ssl_srv_conf_t, enable),
58 NULL },
59
60 { ngx_string("ssl_certificate"),
61 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
62 ngx_conf_set_str_slot,
63 NGX_HTTP_SRV_CONF_OFFSET,
64 offsetof(ngx_http_ssl_srv_conf_t, certificate),
65 NULL },
66
67 { ngx_string("ssl_certificate_key"),
68 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
69 ngx_conf_set_str_slot,
70 NGX_HTTP_SRV_CONF_OFFSET,
71 offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
72 NULL },
73
74 { ngx_string("ssl_dhparam"),
75 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
76 ngx_conf_set_str_slot,
77 NGX_HTTP_SRV_CONF_OFFSET,
78 offsetof(ngx_http_ssl_srv_conf_t, dhparam),
79 NULL },
80
81 { ngx_string("ssl_protocols"),
82 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
83 ngx_conf_set_bitmask_slot,
84 NGX_HTTP_SRV_CONF_OFFSET,
85 offsetof(ngx_http_ssl_srv_conf_t, protocols),
86 &ngx_http_ssl_protocols },
87
88 { ngx_string("ssl_ciphers"),
89 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
90 ngx_conf_set_str_slot,
91 NGX_HTTP_SRV_CONF_OFFSET,
92 offsetof(ngx_http_ssl_srv_conf_t, ciphers),
93 NULL },
94
95 { ngx_string("ssl_verify_client"),
96 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
97 ngx_conf_set_enum_slot,
98 NGX_HTTP_SRV_CONF_OFFSET,
99 offsetof(ngx_http_ssl_srv_conf_t, verify),
100 &ngx_http_ssl_verify },
101
102 { ngx_string("ssl_verify_depth"),
103 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
104 ngx_conf_set_num_slot,
105 NGX_HTTP_SRV_CONF_OFFSET,
106 offsetof(ngx_http_ssl_srv_conf_t, verify_depth),
107 NULL },
108
109 { ngx_string("ssl_client_certificate"),
110 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
111 ngx_conf_set_str_slot,
112 NGX_HTTP_SRV_CONF_OFFSET,
113 offsetof(ngx_http_ssl_srv_conf_t, client_certificate),
114 NULL },
115
116 { ngx_string("ssl_prefer_server_ciphers"),
117 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
118 ngx_conf_set_flag_slot,
119 NGX_HTTP_SRV_CONF_OFFSET,
120 offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
121 NULL },
122
123 { ngx_string("ssl_session_cache"),
124 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
125 ngx_http_ssl_session_cache,
126 NGX_HTTP_SRV_CONF_OFFSET,
127 0,
128 NULL },
129
130 { ngx_string("ssl_session_timeout"),
131 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
132 ngx_conf_set_sec_slot,
133 NGX_HTTP_SRV_CONF_OFFSET,
134 offsetof(ngx_http_ssl_srv_conf_t, session_timeout),
135 NULL },
136
137 { ngx_string("ssl_crl"),
138 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
139 ngx_conf_set_str_slot,
140 NGX_HTTP_SRV_CONF_OFFSET,
141 offsetof(ngx_http_ssl_srv_conf_t, crl),
142 NULL },
143
144 ngx_null_command
145 };
146
147
148 static ngx_http_module_t ngx_http_ssl_module_ctx = {
149 ngx_http_ssl_add_variables, /* preconfiguration */
150 NULL, /* postconfiguration */
151
152 NULL, /* create main configuration */
153 NULL, /* init main configuration */
154
155 ngx_http_ssl_create_srv_conf, /* create server configuration */
156 ngx_http_ssl_merge_srv_conf, /* merge server configuration */
157
158 NULL, /* create location configuration */
159 NULL /* merge location configuration */
160 };
161
162
163 ngx_module_t ngx_http_ssl_module = {
164 NGX_MODULE_V1,
165 &ngx_http_ssl_module_ctx, /* module context */
166 ngx_http_ssl_commands, /* module directives */
167 NGX_HTTP_MODULE, /* module type */
168 NULL, /* init master */
169 NULL, /* init module */
170 NULL, /* init process */
171 NULL, /* init thread */
172 NULL, /* exit thread */
173 NULL, /* exit process */
174 NULL, /* exit master */
175 NGX_MODULE_V1_PADDING
176 };
177
178
179 static ngx_http_variable_t ngx_http_ssl_vars[] = {
180
181 { ngx_string("ssl_protocol"), NULL, ngx_http_ssl_static_variable,
182 (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
183
184 { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable,
185 (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
186
187 { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable,
188 (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 },
189
190 { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
191 (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
192
193 { ngx_string("ssl_client_raw_cert"), NULL, ngx_http_ssl_variable,
194 (uintptr_t) ngx_ssl_get_raw_certificate,
195 NGX_HTTP_VAR_CHANGEABLE, 0 },
196
197 { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable,
198 (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
199
200 { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable,
201 (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
202
203 { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
204 (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
205
206 { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable,
207 (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 },
208
209 { ngx_null_string, NULL, NULL, 0, 0, 0 }
210 };
211
212
213 static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP");
214
215
216 static ngx_int_t
217 ngx_http_ssl_static_variable(ngx_http_request_t *r,
218 ngx_http_variable_value_t *v, uintptr_t data)
219 {
220 ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
221
222 size_t len;
223 ngx_str_t s;
224
225 if (r->connection->ssl) {
226
227 (void) handler(r->connection, NULL, &s);
228
229 v->data = s.data;
230
231 for (len = 0; v->data[len]; len++) { /* void */ }
232
233 v->len = len;
234 v->valid = 1;
235 v->no_cacheable = 0;
236 v->not_found = 0;
237
238 return NGX_OK;
239 }
240
241 v->not_found = 1;
242
243 return NGX_OK;
244 }
245
246
247 static ngx_int_t
248 ngx_http_ssl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
249 uintptr_t data)
250 {
251 ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data;
252
253 ngx_str_t s;
254
255 if (r->connection->ssl) {
256
257 if (handler(r->connection, r->pool, &s) != NGX_OK) {
258 return NGX_ERROR;
259 }
260
261 v->len = s.len;
262 v->data = s.data;
263
264 if (v->len) {
265 v->valid = 1;
266 v->no_cacheable = 0;
267 v->not_found = 0;
268
269 return NGX_OK;
270 }
271 }
272
273 v->not_found = 1;
274
275 return NGX_OK;
276 }
277
278
279 static ngx_int_t
280 ngx_http_ssl_add_variables(ngx_conf_t *cf)
281 {
282 ngx_http_variable_t *var, *v;
283
284 for (v = ngx_http_ssl_vars; v->name.len; v++) {
285 var = ngx_http_add_variable(cf, &v->name, v->flags);
286 if (var == NULL) {
287 return NGX_ERROR;
288 }
289
290 var->get_handler = v->get_handler;
291 var->data = v->data;
292 }
293
294 return NGX_OK;
295 }
296
297
298 static void *
299 ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
300 {
301 ngx_http_ssl_srv_conf_t *sscf;
302
303 sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
304 if (sscf == NULL) {
305 return NULL;
306 }
307
308 /*
309 * set by ngx_pcalloc():
310 *
311 * sscf->protocols = 0;
312 * sscf->certificate = { 0, NULL };
313 * sscf->certificate_key = { 0, NULL };
314 * sscf->dhparam = { 0, NULL };
315 * sscf->client_certificate = { 0, NULL };
316 * sscf->crl = { 0, NULL };
317 * sscf->ciphers.len = 0;
318 * sscf->ciphers.data = NULL;
319 * sscf->shm_zone = NULL;
320 */
321
322 sscf->enable = NGX_CONF_UNSET;
323 sscf->prefer_server_ciphers = NGX_CONF_UNSET;
324 sscf->verify = NGX_CONF_UNSET_UINT;
325 sscf->verify_depth = NGX_CONF_UNSET_UINT;
326 sscf->builtin_session_cache = NGX_CONF_UNSET;
327 sscf->session_timeout = NGX_CONF_UNSET;
328
329 return sscf;
330 }
331
332
333 static char *
334 ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
335 {
336 ngx_http_ssl_srv_conf_t *prev = parent;
337 ngx_http_ssl_srv_conf_t *conf = child;
338
339 ngx_pool_cleanup_t *cln;
340
341 ngx_conf_merge_value(conf->enable, prev->enable, 0);
342
343 ngx_conf_merge_value(conf->session_timeout,
344 prev->session_timeout, 300);
345
346 ngx_conf_merge_value(conf->prefer_server_ciphers,
347 prev->prefer_server_ciphers, 0);
348
349 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
350 (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1));
351
352 ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
353 ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
354
355 ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
356 ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
357
358 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
359
360 ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
361 "");
362 ngx_conf_merge_str_value(conf->crl, prev->crl, "");
363
364 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
365
366
367 conf->ssl.log = cf->log;
368
369 if (conf->enable) {
370
371 if (conf->certificate.len == 0) {
372 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
373 "no \"ssl_certificate\" is defined for "
374 "the \"ssl\" directive in %s:%ui",
375 conf->file, conf->line);
376 return NGX_CONF_ERROR;
377 }
378
379 if (conf->certificate_key.len == 0) {
380 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
381 "no \"ssl_certificate_key\" is defined for "
382 "the \"ssl\" directive in %s:%ui",
383 conf->file, conf->line);
384 return NGX_CONF_ERROR;
385 }
386
387 } else {
388
389 if (conf->certificate.len == 0) {
390 return NGX_CONF_OK;
391 }
392
393 if (conf->certificate_key.len == 0) {
394 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
395 "no \"ssl_certificate_key\" is defined "
396 "for certificate \"%V\"", &conf->certificate);
397 return NGX_CONF_ERROR;
398 }
399 }
400
401 if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
402 return NGX_CONF_ERROR;
403 }
404
405 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
406
407 if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,
408 ngx_http_ssl_servername)
409 == 0)
410 {
411 ngx_log_error(NGX_LOG_WARN, cf->log, 0,
412 "nginx was build with SNI support, however, now it is linked "
413 "dynamically to an OpenSSL library which has no tlsext support, "
414 "therefore SNI is not available");
415 }
416
417 #endif
418
419 cln = ngx_pool_cleanup_add(cf->pool, 0);
420 if (cln == NULL) {
421 return NGX_CONF_ERROR;
422 }
423
424 cln->handler = ngx_ssl_cleanup_ctx;
425 cln->data = &conf->ssl;
426
427 if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
428 &conf->certificate_key)
429 != NGX_OK)
430 {
431 return NGX_CONF_ERROR;
432 }
433
434 if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
435 (const char *) conf->ciphers.data)
436 == 0)
437 {
438 ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
439 "SSL_CTX_set_cipher_list(\"%V\") failed",
440 &conf->ciphers);
441 }
442
443 if (conf->verify) {
444
445 if (conf->client_certificate.len == 0) {
446 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
447 "no ssl_client_certificate for ssl_client_verify");
448 return NGX_CONF_ERROR;
449 }
450
451 if (ngx_ssl_client_certificate(cf, &conf->ssl,
452 &conf->client_certificate,
453 conf->verify_depth)
454 != NGX_OK)
455 {
456 return NGX_CONF_ERROR;
457 }
458
459 if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
460 return NGX_CONF_ERROR;
461 }
462 }
463
464 if (conf->prefer_server_ciphers) {
465 SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
466 }
467
468 /* a temporary 512-bit RSA key is required for export versions of MSIE */
469 if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
470 return NGX_CONF_ERROR;
471 }
472
473 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
474 return NGX_CONF_ERROR;
475 }
476
477 ngx_conf_merge_value(conf->builtin_session_cache,
478 prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
479
480 if (conf->shm_zone == NULL) {
481 conf->shm_zone = prev->shm_zone;
482 }
483
484 if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
485 conf->builtin_session_cache,
486 conf->shm_zone, conf->session_timeout)
487 != NGX_OK)
488 {
489 return NGX_CONF_ERROR;
490 }
491
492 return NGX_CONF_OK;
493 }
494
495
496 static char *
497 ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
498 {
499 ngx_http_ssl_srv_conf_t *sscf = conf;
500
501 char *rv;
502
503 rv = ngx_conf_set_flag_slot(cf, cmd, conf);
504
505 if (rv != NGX_CONF_OK) {
506 return rv;
507 }
508
509 sscf->file = cf->conf_file->file.name.data;
510 sscf->line = cf->conf_file->line;
511
512 return NGX_CONF_OK;
513 }
514
515
516 static char *
517 ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
518 {
519 ngx_http_ssl_srv_conf_t *sscf = conf;
520
521 size_t len;
522 ngx_str_t *value, name, size;
523 ngx_int_t n;
524 ngx_uint_t i, j;
525
526 value = cf->args->elts;
527
528 for (i = 1; i < cf->args->nelts; i++) {
529
530 if (ngx_strcmp(value[i].data, "off") == 0) {
531 sscf->builtin_session_cache = NGX_SSL_NO_SCACHE;
532 continue;
533 }
534
535 if (ngx_strcmp(value[i].data, "none") == 0) {
536 sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
537 continue;
538 }
539
540 if (ngx_strcmp(value[i].data, "builtin") == 0) {
541 sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
542 continue;
543 }
544
545 if (value[i].len > sizeof("builtin:") - 1
546 && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
547 == 0)
548 {
549 n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
550 value[i].len - (sizeof("builtin:") - 1));
551
552 if (n == NGX_ERROR) {
553 goto invalid;
554 }
555
556 sscf->builtin_session_cache = n;
557
558 continue;
559 }
560
561 if (value[i].len > sizeof("shared:") - 1
562 && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
563 == 0)
564 {
565 len = 0;
566
567 for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
568 if (value[i].data[j] == ':') {
569 value[i].data[j] = '\0';
570 break;
571 }
572
573 len++;
574 }
575
576 if (len == 0) {
577 goto invalid;
578 }
579
580 name.len = len;
581 name.data = value[i].data + sizeof("shared:") - 1;
582
583 size.len = value[i].len - j - 1;
584 size.data = name.data + len + 1;
585
586 n = ngx_parse_size(&size);
587
588 if (n == NGX_ERROR) {
589 goto invalid;
590 }
591
592 if (n < (ngx_int_t) (8 * ngx_pagesize)) {
593 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
594 "session cache \"%V\" is too small",
595 &value[i]);
596
597 return NGX_CONF_ERROR;
598 }
599
600 sscf->shm_zone = ngx_shared_memory_add(cf, &name, n,
601 &ngx_http_ssl_module);
602 if (sscf->shm_zone == NULL) {
603 return NGX_CONF_ERROR;
604 }
605
606 continue;
607 }
608
609 goto invalid;
610 }
611
612 if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) {
613 sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
614 }
615
616 return NGX_CONF_OK;
617
618 invalid:
619
620 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
621 "invalid session cache \"%V\"", &value[i]);
622
623 return NGX_CONF_ERROR;
624 }
625
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.