upstream nginx-0.7.35
[nginx.git] / nginx / src / http / modules / ngx_http_ssl_module.c
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  "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP"
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 #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
35
36 static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
37     void *conf);
38
39 static char  ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher";
40
41 #endif
42
43
44 static ngx_conf_bitmask_t  ngx_http_ssl_protocols[] = {
45     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
46     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
47     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
48     { ngx_null_string, 0 }
49 };
50
51
52 static ngx_conf_enum_t  ngx_http_ssl_verify[] = {
53     { ngx_string("off"), 0 },
54     { ngx_string("on"), 1 },
55     { ngx_string("ask"), 2 },
56     { ngx_null_string, 0 }
57 };
58
59
60 static ngx_command_t  ngx_http_ssl_commands[] = {
61
62     { ngx_string("ssl"),
63       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
64       ngx_http_ssl_enable,
65       NGX_HTTP_SRV_CONF_OFFSET,
66       offsetof(ngx_http_ssl_srv_conf_t, enable),
67       NULL },
68
69     { ngx_string("ssl_certificate"),
70       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
71       ngx_conf_set_str_slot,
72       NGX_HTTP_SRV_CONF_OFFSET,
73       offsetof(ngx_http_ssl_srv_conf_t, certificate),
74       NULL },
75
76     { ngx_string("ssl_certificate_key"),
77       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
78       ngx_conf_set_str_slot,
79       NGX_HTTP_SRV_CONF_OFFSET,
80       offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
81       NULL },
82
83     { ngx_string("ssl_dhparam"),
84       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
85       ngx_conf_set_str_slot,
86       NGX_HTTP_SRV_CONF_OFFSET,
87       offsetof(ngx_http_ssl_srv_conf_t, dhparam),
88       NULL },
89
90     { ngx_string("ssl_protocols"),
91       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
92       ngx_conf_set_bitmask_slot,
93       NGX_HTTP_SRV_CONF_OFFSET,
94       offsetof(ngx_http_ssl_srv_conf_t, protocols),
95       &ngx_http_ssl_protocols },
96
97     { ngx_string("ssl_ciphers"),
98       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
99       ngx_conf_set_str_slot,
100       NGX_HTTP_SRV_CONF_OFFSET,
101       offsetof(ngx_http_ssl_srv_conf_t, ciphers),
102       NULL },
103
104     { ngx_string("ssl_verify_client"),
105       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
106       ngx_conf_set_enum_slot,
107       NGX_HTTP_SRV_CONF_OFFSET,
108       offsetof(ngx_http_ssl_srv_conf_t, verify),
109       &ngx_http_ssl_verify },
110
111     { ngx_string("ssl_verify_depth"),
112       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
113       ngx_conf_set_num_slot,
114       NGX_HTTP_SRV_CONF_OFFSET,
115       offsetof(ngx_http_ssl_srv_conf_t, verify_depth),
116       NULL },
117
118     { ngx_string("ssl_client_certificate"),
119       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
120       ngx_conf_set_str_slot,
121       NGX_HTTP_SRV_CONF_OFFSET,
122       offsetof(ngx_http_ssl_srv_conf_t, client_certificate),
123       NULL },
124
125     { ngx_string("ssl_prefer_server_ciphers"),
126       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
127 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
128       ngx_conf_set_flag_slot,
129       NGX_HTTP_SRV_CONF_OFFSET,
130       offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers),
131       NULL },
132 #else
133       ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 },
134 #endif
135
136     { ngx_string("ssl_session_cache"),
137       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
138       ngx_http_ssl_session_cache,
139       NGX_HTTP_SRV_CONF_OFFSET,
140       0,
141       NULL },
142
143     { ngx_string("ssl_session_timeout"),
144       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
145       ngx_conf_set_sec_slot,
146       NGX_HTTP_SRV_CONF_OFFSET,
147       offsetof(ngx_http_ssl_srv_conf_t, session_timeout),
148       NULL },
149
150       ngx_null_command
151 };
152
153
154 static ngx_http_module_t  ngx_http_ssl_module_ctx = {
155     ngx_http_ssl_add_variables,            /* preconfiguration */
156     NULL,                                  /* postconfiguration */
157
158     NULL,                                  /* create main configuration */
159     NULL,                                  /* init main configuration */
160
161     ngx_http_ssl_create_srv_conf,          /* create server configuration */
162     ngx_http_ssl_merge_srv_conf,           /* merge server configuration */
163
164     NULL,                                  /* create location configuration */
165     NULL                                   /* merge location configuration */
166 };
167
168
169 ngx_module_t  ngx_http_ssl_module = {
170     NGX_MODULE_V1,
171     &ngx_http_ssl_module_ctx,              /* module context */
172     ngx_http_ssl_commands,                 /* module directives */
173     NGX_HTTP_MODULE,                       /* module type */
174     NULL,                                  /* init master */
175     NULL,                                  /* init module */
176     NULL,                                  /* init process */
177     NULL,                                  /* init thread */
178     NULL,                                  /* exit thread */
179     NULL,                                  /* exit process */
180     NULL,                                  /* exit master */
181     NGX_MODULE_V1_PADDING
182 };
183
184
185 static ngx_http_variable_t  ngx_http_ssl_vars[] = {
186
187     { ngx_string("ssl_protocol"), NULL, ngx_http_ssl_static_variable,
188       (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 },
189
190     { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_static_variable,
191       (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGEABLE, 0 },
192
193     { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable,
194       (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 },
195
196     { ngx_string("ssl_client_raw_cert"), NULL, ngx_http_ssl_variable,
197       (uintptr_t) ngx_ssl_get_raw_certificate,
198       NGX_HTTP_VAR_CHANGEABLE, 0 },
199
200     { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable,
201       (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
202
203     { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_variable,
204       (uintptr_t) ngx_ssl_get_issuer_dn, NGX_HTTP_VAR_CHANGEABLE, 0 },
205
206     { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
207       (uintptr_t) ngx_ssl_get_serial_number, 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 NGX_CONF_ERROR;
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->ciphers.len = 0;
317      *     sscf->ciphers.data = NULL;
318      *     sscf->shm_zone = NULL;
319      */
320
321     sscf->enable = NGX_CONF_UNSET;
322     sscf->prefer_server_ciphers = NGX_CONF_UNSET;
323     sscf->verify = NGX_CONF_UNSET;
324     sscf->verify_depth = NGX_CONF_UNSET;
325     sscf->builtin_session_cache = NGX_CONF_UNSET;
326     sscf->session_timeout = NGX_CONF_UNSET;
327
328     return sscf;
329 }
330
331
332 static char *
333 ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
334 {
335     ngx_http_ssl_srv_conf_t *prev = parent;
336     ngx_http_ssl_srv_conf_t *conf = child;
337
338     ngx_pool_cleanup_t  *cln;
339
340     ngx_conf_merge_value(conf->enable, prev->enable, 0);
341
342     ngx_conf_merge_value(conf->session_timeout,
343                          prev->session_timeout, 300);
344
345     ngx_conf_merge_value(conf->prefer_server_ciphers,
346                          prev->prefer_server_ciphers, 0);
347
348     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
349                          (NGX_CONF_BITMASK_SET
350                           |NGX_SSL_SSLv2|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
363     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
364
365
366     conf->ssl.log = cf->log;
367
368     if (conf->enable) {
369
370         if (conf->certificate.len == 0) {
371             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
372                           "no \"ssl_certificate\" is defined for "
373                           "the \"ssl\" directive in %s:%ui",
374                           conf->file, conf->line);
375             return NGX_CONF_ERROR;
376         }
377
378         if (conf->certificate_key.len == 0) {
379             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
380                           "no \"ssl_certificate_key\" is defined for "
381                           "the \"ssl\" directive in %s:%ui",
382                           conf->file, conf->line);
383             return NGX_CONF_ERROR;
384         }
385
386     } else {
387
388         if (conf->certificate.len == 0) {
389             return NGX_CONF_OK;
390         }
391
392         if (conf->certificate_key.len == 0) {
393             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
394                           "no \"ssl_certificate_key\" is defined "
395                           "for certificate \"%V\"", &conf->certificate);
396             return NGX_CONF_ERROR;
397         }
398     }
399
400     if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
401         return NGX_CONF_ERROR;
402     }
403
404 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
405
406     if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,
407                                                ngx_http_ssl_servername)
408         == 0)
409     {
410         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
411                       "SSL_CTX_set_tlsext_servername_callback() failed");
412         return NGX_CONF_ERROR;
413     }
414
415 #endif
416
417     cln = ngx_pool_cleanup_add(cf->pool, 0);
418     if (cln == NULL) {
419         return NGX_CONF_ERROR;
420     }
421
422     cln->handler = ngx_ssl_cleanup_ctx;
423     cln->data = &conf->ssl;
424
425     if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
426                             &conf->certificate_key)
427         != NGX_OK)
428     {
429         return NGX_CONF_ERROR;
430     }
431
432     if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
433                                 (const char *) conf->ciphers.data)
434         == 0)
435     {
436         ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
437                       "SSL_CTX_set_cipher_list(\"%V\") failed",
438                       &conf->ciphers);
439     }
440
441     if (conf->verify) {
442
443         if (conf->client_certificate.len == 0) {
444             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
445                           "no ssl_client_certificate for ssl_client_verify");
446             return NGX_CONF_ERROR;
447         }
448
449         if (ngx_ssl_client_certificate(cf, &conf->ssl,
450                                        &conf->client_certificate,
451                                        conf->verify_depth)
452             != NGX_OK)
453         {
454             return NGX_CONF_ERROR;
455         }
456     }
457
458 #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
459
460     if (conf->prefer_server_ciphers) {
461         SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
462     }
463
464 #endif
465
466     /* a temporary 512-bit RSA key is required for export versions of MSIE */
467     if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) {
468         return NGX_CONF_ERROR;
469     }
470
471     if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
472         return NGX_CONF_ERROR;
473     }
474
475     ngx_conf_merge_value(conf->builtin_session_cache,
476                          prev->builtin_session_cache, NGX_SSL_NONE_SCACHE);
477
478     if (conf->shm_zone == NULL) {
479         conf->shm_zone = prev->shm_zone;
480     }
481
482     if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
483                               conf->builtin_session_cache,
484                               conf->shm_zone, conf->session_timeout)
485         != NGX_OK)
486     {
487         return NGX_CONF_ERROR;
488     }
489
490     return NGX_CONF_OK;
491 }
492
493
494 static char *
495 ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
496 {
497     ngx_http_ssl_srv_conf_t *sscf = conf;
498
499     char  *rv;
500
501     rv = ngx_conf_set_flag_slot(cf, cmd, conf);
502
503     if (rv != NGX_CONF_OK) {
504         return rv;
505     }
506
507     sscf->file = cf->conf_file->file.name.data;
508     sscf->line = cf->conf_file->line;
509
510     return NGX_CONF_OK;
511 }
512
513
514 static char *
515 ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
516 {
517     ngx_http_ssl_srv_conf_t *sscf = conf;
518
519     size_t       len;
520     ngx_str_t   *value, name, size;
521     ngx_int_t    n;
522     ngx_uint_t   i, j;
523
524     value = cf->args->elts;
525
526     for (i = 1; i < cf->args->nelts; i++) {
527
528         if (ngx_strcmp(value[i].data, "off") == 0) {
529             sscf->builtin_session_cache = NGX_SSL_NO_SCACHE;
530             continue;
531         }
532
533         if (ngx_strcmp(value[i].data, "none") == 0) {
534             sscf->builtin_session_cache = NGX_SSL_NONE_SCACHE;
535             continue;
536         }
537
538         if (ngx_strcmp(value[i].data, "builtin") == 0) {
539             sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
540             continue;
541         }
542
543         if (value[i].len > sizeof("builtin:") - 1
544             && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
545                == 0)
546         {
547             n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
548                          value[i].len - (sizeof("builtin:") - 1));
549
550             if (n == NGX_ERROR) {
551                 goto invalid;
552             }
553
554             sscf->builtin_session_cache = n;
555
556             continue;
557         }
558
559         if (value[i].len > sizeof("shared:") - 1
560             && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
561                == 0)
562         {
563             len = 0;
564
565             for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
566                 if (value[i].data[j] == ':') {
567                     break;
568                 }
569
570                 len++;
571             }
572
573             if (len == 0) {
574                 goto invalid;
575             }
576
577             name.len = len;
578             name.data = value[i].data + sizeof("shared:") - 1;
579
580             size.len = value[i].len - j - 1;
581             size.data = name.data + len + 1;
582
583             n = ngx_parse_size(&size);
584
585             if (n == NGX_ERROR) {
586                 goto invalid;
587             }
588
589             if (n < (ngx_int_t) (8 * ngx_pagesize)) {
590                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
591                                    "session cache \"%V\" is too small",
592                                    &value[i]);
593
594                 return NGX_CONF_ERROR;
595             }
596
597             sscf->shm_zone = ngx_shared_memory_add(cf, &name, n,
598                                                    &ngx_http_ssl_module);
599             if (sscf->shm_zone == NULL) {
600                 return NGX_CONF_ERROR;
601             }
602
603             continue;
604         }
605
606         goto invalid;
607     }
608
609     if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) {
610         sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
611     }
612
613     return NGX_CONF_OK;
614
615 invalid:
616
617     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
618                        "invalid session cache \"%V\"", &value[i]);
619
620     return NGX_CONF_ERROR;
621 }
622
623
624 #if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
625
626 static char *
627 ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
628 {
629     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
630                        "\"%V\" directive is available only in %s,",
631                        &cmd->name, cmd->post);
632
633     return NGX_CONF_ERROR;
634 }
635
636 #endif