Mercurial > hg > nginx
comparison src/stream/ngx_stream_ssl_module.c @ 6850:41cb1b64561d
Stream: client SSL certificates verification support.
New directives: "ssl_verify_client", "ssl_verify_depth",
"ssl_client_certificate", "ssl_trusted_certificate", and
"ssl_crl".
New variables: $ssl_client_cert, $ssl_client_raw_cert,
$ssl_client_s_dn, $ssl_client_i_dn, $ssl_client_serial,
$ssl_client_fingerprint, $ssl_client_verify, $ssl_client_v_start,
$ssl_client_v_end, and $ssl_client_v_remain.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Tue, 20 Dec 2016 12:05:14 +0300 |
parents | e75e854657ba |
children | 0a08a8babf53 |
comparison
equal
deleted
inserted
replaced
6849:01adb18a5d23 | 6850:41cb1b64561d |
---|---|
47 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, | 47 { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, |
48 { ngx_null_string, 0 } | 48 { ngx_null_string, 0 } |
49 }; | 49 }; |
50 | 50 |
51 | 51 |
52 static ngx_conf_enum_t ngx_stream_ssl_verify[] = { | |
53 { ngx_string("off"), 0 }, | |
54 { ngx_string("on"), 1 }, | |
55 { ngx_string("optional"), 2 }, | |
56 { ngx_string("optional_no_ca"), 3 }, | |
57 { ngx_null_string, 0 } | |
58 }; | |
59 | |
60 | |
52 static ngx_command_t ngx_stream_ssl_commands[] = { | 61 static ngx_command_t ngx_stream_ssl_commands[] = { |
53 | 62 |
54 { ngx_string("ssl_handshake_timeout"), | 63 { ngx_string("ssl_handshake_timeout"), |
55 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | 64 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, |
56 ngx_conf_set_msec_slot, | 65 ngx_conf_set_msec_slot, |
105 ngx_conf_set_str_slot, | 114 ngx_conf_set_str_slot, |
106 NGX_STREAM_SRV_CONF_OFFSET, | 115 NGX_STREAM_SRV_CONF_OFFSET, |
107 offsetof(ngx_stream_ssl_conf_t, ciphers), | 116 offsetof(ngx_stream_ssl_conf_t, ciphers), |
108 NULL }, | 117 NULL }, |
109 | 118 |
119 { ngx_string("ssl_verify_client"), | |
120 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
121 ngx_conf_set_enum_slot, | |
122 NGX_STREAM_SRV_CONF_OFFSET, | |
123 offsetof(ngx_stream_ssl_conf_t, verify), | |
124 &ngx_stream_ssl_verify }, | |
125 | |
126 { ngx_string("ssl_verify_depth"), | |
127 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
128 ngx_conf_set_num_slot, | |
129 NGX_STREAM_SRV_CONF_OFFSET, | |
130 offsetof(ngx_stream_ssl_conf_t, verify_depth), | |
131 NULL }, | |
132 | |
133 { ngx_string("ssl_client_certificate"), | |
134 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
135 ngx_conf_set_str_slot, | |
136 NGX_STREAM_SRV_CONF_OFFSET, | |
137 offsetof(ngx_stream_ssl_conf_t, client_certificate), | |
138 NULL }, | |
139 | |
140 { ngx_string("ssl_trusted_certificate"), | |
141 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
142 ngx_conf_set_str_slot, | |
143 NGX_STREAM_SRV_CONF_OFFSET, | |
144 offsetof(ngx_stream_ssl_conf_t, trusted_certificate), | |
145 NULL }, | |
146 | |
110 { ngx_string("ssl_prefer_server_ciphers"), | 147 { ngx_string("ssl_prefer_server_ciphers"), |
111 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, | 148 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, |
112 ngx_conf_set_flag_slot, | 149 ngx_conf_set_flag_slot, |
113 NGX_STREAM_SRV_CONF_OFFSET, | 150 NGX_STREAM_SRV_CONF_OFFSET, |
114 offsetof(ngx_stream_ssl_conf_t, prefer_server_ciphers), | 151 offsetof(ngx_stream_ssl_conf_t, prefer_server_ciphers), |
138 { ngx_string("ssl_session_timeout"), | 175 { ngx_string("ssl_session_timeout"), |
139 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | 176 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, |
140 ngx_conf_set_sec_slot, | 177 ngx_conf_set_sec_slot, |
141 NGX_STREAM_SRV_CONF_OFFSET, | 178 NGX_STREAM_SRV_CONF_OFFSET, |
142 offsetof(ngx_stream_ssl_conf_t, session_timeout), | 179 offsetof(ngx_stream_ssl_conf_t, session_timeout), |
180 NULL }, | |
181 | |
182 { ngx_string("ssl_crl"), | |
183 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
184 ngx_conf_set_str_slot, | |
185 NGX_STREAM_SRV_CONF_OFFSET, | |
186 offsetof(ngx_stream_ssl_conf_t, crl), | |
143 NULL }, | 187 NULL }, |
144 | 188 |
145 ngx_null_command | 189 ngx_null_command |
146 }; | 190 }; |
147 | 191 |
195 (uintptr_t) ngx_ssl_get_session_reused, NGX_STREAM_VAR_CHANGEABLE, 0 }, | 239 (uintptr_t) ngx_ssl_get_session_reused, NGX_STREAM_VAR_CHANGEABLE, 0 }, |
196 | 240 |
197 { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, | 241 { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, |
198 (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, | 242 (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, |
199 | 243 |
244 { ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable, | |
245 (uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
246 | |
247 { ngx_string("ssl_client_raw_cert"), NULL, ngx_stream_ssl_variable, | |
248 (uintptr_t) ngx_ssl_get_raw_certificate, | |
249 NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
250 | |
251 { ngx_string("ssl_client_s_dn"), NULL, ngx_stream_ssl_variable, | |
252 (uintptr_t) ngx_ssl_get_subject_dn, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
253 | |
254 { ngx_string("ssl_client_i_dn"), NULL, ngx_stream_ssl_variable, | |
255 (uintptr_t) ngx_ssl_get_issuer_dn, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
256 | |
257 { ngx_string("ssl_client_serial"), NULL, ngx_stream_ssl_variable, | |
258 (uintptr_t) ngx_ssl_get_serial_number, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
259 | |
260 { ngx_string("ssl_client_fingerprint"), NULL, ngx_stream_ssl_variable, | |
261 (uintptr_t) ngx_ssl_get_fingerprint, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
262 | |
263 { ngx_string("ssl_client_verify"), NULL, ngx_stream_ssl_variable, | |
264 (uintptr_t) ngx_ssl_get_client_verify, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
265 | |
266 { ngx_string("ssl_client_v_start"), NULL, ngx_stream_ssl_variable, | |
267 (uintptr_t) ngx_ssl_get_client_v_start, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
268 | |
269 { ngx_string("ssl_client_v_end"), NULL, ngx_stream_ssl_variable, | |
270 (uintptr_t) ngx_ssl_get_client_v_end, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
271 | |
272 { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable, | |
273 (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 }, | |
274 | |
200 { ngx_null_string, NULL, NULL, 0, 0, 0 } | 275 { ngx_null_string, NULL, NULL, 0, 0, 0 } |
201 }; | 276 }; |
202 | 277 |
203 | 278 |
204 static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); | 279 static ngx_str_t ngx_stream_ssl_sess_id_ctx = ngx_string("STREAM"); |
205 | 280 |
206 | 281 |
207 static ngx_int_t | 282 static ngx_int_t |
208 ngx_stream_ssl_handler(ngx_stream_session_t *s) | 283 ngx_stream_ssl_handler(ngx_stream_session_t *s) |
209 { | 284 { |
285 long rc; | |
286 X509 *cert; | |
210 ngx_connection_t *c; | 287 ngx_connection_t *c; |
211 ngx_stream_ssl_conf_t *sslcf; | 288 ngx_stream_ssl_conf_t *sslcf; |
212 | 289 |
213 c = s->connection; | 290 c = s->connection; |
214 | 291 |
223 "in server listening on SSL port"); | 300 "in server listening on SSL port"); |
224 return NGX_ERROR; | 301 return NGX_ERROR; |
225 } | 302 } |
226 | 303 |
227 return ngx_stream_ssl_init_connection(&sslcf->ssl, c); | 304 return ngx_stream_ssl_init_connection(&sslcf->ssl, c); |
305 } | |
306 | |
307 if (sslcf->verify) { | |
308 rc = SSL_get_verify_result(c->ssl->connection); | |
309 | |
310 if (rc != X509_V_OK | |
311 && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) | |
312 { | |
313 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
314 "client SSL certificate verify error: (%l:%s)", | |
315 rc, X509_verify_cert_error_string(rc)); | |
316 | |
317 ngx_ssl_remove_cached_session(sslcf->ssl.ctx, | |
318 (SSL_get0_session(c->ssl->connection))); | |
319 return NGX_ERROR; | |
320 } | |
321 | |
322 if (sslcf->verify == 1) { | |
323 cert = SSL_get_peer_certificate(c->ssl->connection); | |
324 | |
325 if (cert == NULL) { | |
326 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
327 "client sent no required SSL certificate"); | |
328 | |
329 ngx_ssl_remove_cached_session(sslcf->ssl.ctx, | |
330 (SSL_get0_session(c->ssl->connection))); | |
331 return NGX_ERROR; | |
332 } | |
333 | |
334 X509_free(cert); | |
335 } | |
228 } | 336 } |
229 | 337 |
230 return NGX_OK; | 338 return NGX_OK; |
231 } | 339 } |
232 | 340 |
382 * set by ngx_pcalloc(): | 490 * set by ngx_pcalloc(): |
383 * | 491 * |
384 * scf->protocols = 0; | 492 * scf->protocols = 0; |
385 * scf->dhparam = { 0, NULL }; | 493 * scf->dhparam = { 0, NULL }; |
386 * scf->ecdh_curve = { 0, NULL }; | 494 * scf->ecdh_curve = { 0, NULL }; |
495 * scf->client_certificate = { 0, NULL }; | |
496 * scf->trusted_certificate = { 0, NULL }; | |
497 * scf->crl = { 0, NULL }; | |
387 * scf->ciphers = { 0, NULL }; | 498 * scf->ciphers = { 0, NULL }; |
388 * scf->shm_zone = NULL; | 499 * scf->shm_zone = NULL; |
389 */ | 500 */ |
390 | 501 |
391 scf->handshake_timeout = NGX_CONF_UNSET_MSEC; | 502 scf->handshake_timeout = NGX_CONF_UNSET_MSEC; |
392 scf->certificates = NGX_CONF_UNSET_PTR; | 503 scf->certificates = NGX_CONF_UNSET_PTR; |
393 scf->certificate_keys = NGX_CONF_UNSET_PTR; | 504 scf->certificate_keys = NGX_CONF_UNSET_PTR; |
394 scf->passwords = NGX_CONF_UNSET_PTR; | 505 scf->passwords = NGX_CONF_UNSET_PTR; |
395 scf->prefer_server_ciphers = NGX_CONF_UNSET; | 506 scf->prefer_server_ciphers = NGX_CONF_UNSET; |
507 scf->verify = NGX_CONF_UNSET_UINT; | |
508 scf->verify_depth = NGX_CONF_UNSET_UINT; | |
396 scf->builtin_session_cache = NGX_CONF_UNSET; | 509 scf->builtin_session_cache = NGX_CONF_UNSET; |
397 scf->session_timeout = NGX_CONF_UNSET; | 510 scf->session_timeout = NGX_CONF_UNSET; |
398 scf->session_tickets = NGX_CONF_UNSET; | 511 scf->session_tickets = NGX_CONF_UNSET; |
399 scf->session_ticket_keys = NGX_CONF_UNSET_PTR; | 512 scf->session_ticket_keys = NGX_CONF_UNSET_PTR; |
400 | 513 |
421 | 534 |
422 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, | 535 ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, |
423 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 | 536 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |
424 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); | 537 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); |
425 | 538 |
539 ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); | |
540 ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); | |
541 | |
426 ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); | 542 ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); |
427 ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, | 543 ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, |
428 NULL); | 544 NULL); |
429 | 545 |
430 ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); | 546 ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); |
431 | 547 |
432 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); | 548 ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); |
549 | |
550 ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, | |
551 ""); | |
552 ngx_conf_merge_str_value(conf->trusted_certificate, | |
553 prev->trusted_certificate, ""); | |
554 ngx_conf_merge_str_value(conf->crl, prev->crl, ""); | |
433 | 555 |
434 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, | 556 ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, |
435 NGX_DEFAULT_ECDH_CURVE); | 557 NGX_DEFAULT_ECDH_CURVE); |
436 | 558 |
437 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); | 559 ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); |
478 != NGX_OK) | 600 != NGX_OK) |
479 { | 601 { |
480 return NGX_CONF_ERROR; | 602 return NGX_CONF_ERROR; |
481 } | 603 } |
482 | 604 |
605 if (conf->verify) { | |
606 | |
607 if (conf->client_certificate.len == 0 && conf->verify != 3) { | |
608 ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
609 "no ssl_client_certificate for ssl_client_verify"); | |
610 return NGX_CONF_ERROR; | |
611 } | |
612 | |
613 if (ngx_ssl_client_certificate(cf, &conf->ssl, | |
614 &conf->client_certificate, | |
615 conf->verify_depth) | |
616 != NGX_OK) | |
617 { | |
618 return NGX_CONF_ERROR; | |
619 } | |
620 | |
621 if (ngx_ssl_trusted_certificate(cf, &conf->ssl, | |
622 &conf->trusted_certificate, | |
623 conf->verify_depth) | |
624 != NGX_OK) | |
625 { | |
626 return NGX_CONF_ERROR; | |
627 } | |
628 | |
629 if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) { | |
630 return NGX_CONF_ERROR; | |
631 } | |
632 } | |
633 | |
483 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { | 634 if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { |
484 return NGX_CONF_ERROR; | 635 return NGX_CONF_ERROR; |
485 } | 636 } |
486 | 637 |
487 if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) { | 638 if (ngx_ssl_ecdh_curve(cf, &conf->ssl, &conf->ecdh_curve) != NGX_OK) { |