diff options
Diffstat (limited to 'src/http')
-rw-r--r-- | src/http/modules/ngx_http_ssl_module.c | 109 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssl_module.h | 4 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 36 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 5 | ||||
-rw-r--r-- | src/http/ngx_http_special_response.c | 28 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 13 |
6 files changed, 181 insertions, 14 deletions
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index e2191ef47..a57fbfb6f 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -19,6 +19,10 @@ typedef u_char *(*ngx_ssl_variable_handler_pt)(ngx_connection_t *); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_ssl_client_s_dn(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_ssl_client_i_dn(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf); static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); @@ -43,7 +47,6 @@ static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { }; - static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl"), @@ -81,6 +84,27 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, ciphers), NULL }, + { ngx_string("ssl_verify_client"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, verify), + NULL }, + + { ngx_string("ssl_verify_depth"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, verify_depth), + NULL }, + + { ngx_string("ssl_client_certificate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, client_certificate), + NULL }, + { ngx_string("ssl_prefer_server_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE @@ -142,6 +166,12 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGABLE, 0 }, + { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_client_s_dn, + 0, NGX_HTTP_VAR_CHANGABLE, 0 }, + + { ngx_string("ssl_client_i_dn"), NULL, ngx_http_ssl_client_i_dn, + 0, NGX_HTTP_VAR_CHANGABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -180,6 +210,58 @@ ngx_http_ssl_variable(ngx_http_request_t *r, static ngx_int_t +ngx_http_ssl_client_s_dn(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + if (r->connection->ssl) { + if (ngx_ssl_get_subject_dn(r->connection, r->pool, (ngx_str_t *) v) + != NGX_OK) + { + return NGX_ERROR; + } + + if (v->len) { + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + return NGX_OK; + } + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_ssl_client_i_dn(ngx_http_request_t *r, ngx_http_variable_value_t *v, + uintptr_t data) +{ + if (r->connection->ssl) { + if (ngx_ssl_get_issuer_dn(r->connection, r->pool, (ngx_str_t *) v) + != NGX_OK) + { + return NGX_ERROR; + } + + if (v->len) { + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + return NGX_OK; + } + } + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_ssl_add_variables(ngx_conf_t *cf) { ngx_http_variable_t *var, *v; @@ -217,12 +299,16 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * scf->certificate.data = NULL; * scf->certificate_key.len = 0; * scf->certificate_key.data = NULL; + * scf->client_certificate.len = 0; + * scf->client_certificate.data = NULL; * scf->ciphers.len = 0; * scf->ciphers.data = NULL; */ scf->enable = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; + scf->verify = NGX_CONF_UNSET; + scf->verify_depth = NGX_CONF_UNSET; scf->prefer_server_ciphers = NGX_CONF_UNSET; return scf; @@ -253,12 +339,18 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) (NGX_CONF_BITMASK_SET |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); + ngx_conf_merge_value(conf->verify, prev->verify, 0); + ngx_conf_merge_value(conf->verify_depth, prev->verify_depth, 1); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, NGX_DEFLAUT_CERTIFICATE); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, NGX_DEFLAUT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, + ""); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS); @@ -291,6 +383,21 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) &conf->ciphers); } + if (conf->verify) { + SSL_CTX_set_verify(conf->ssl.ctx, NGX_SSL_VERIFY, NULL); + + SSL_CTX_set_verify_depth(conf->ssl.ctx, conf->verify_depth); + + if (conf->client_certificate.len) { + if (ngx_ssl_client_certificate(cf, &conf->ssl, + &conf->client_certificate) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + } + #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE if (conf->prefer_server_ciphers) { diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 4207cdfdb..85803096e 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -22,10 +22,14 @@ typedef struct { ngx_uint_t protocols; + ngx_int_t verify; + ngx_int_t verify_depth; + time_t session_timeout; ngx_str_t certificate; ngx_str_t certificate_key; + ngx_str_t client_certificate; ngx_str_t ciphers; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 680b3bd45..5207fa1cc 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1172,8 +1172,12 @@ ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) { - size_t len; - u_char *ua, *user_agent, ch; + size_t len; + u_char *ua, *user_agent, ch; +#if (NGX_HTTP_SSL) + long rc; + ngx_http_ssl_srv_conf_t *sscf; +#endif if (r->headers_in.host) { for (len = 0; len < r->headers_in.host->value.len; len++) { @@ -1243,6 +1247,34 @@ ngx_http_process_request_header(ngx_http_request_t *r) return NGX_ERROR; } +#if (NGX_HTTP_SSL) + + if (r->connection->ssl) { + sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); + + if (sscf->verify) { + rc = SSL_get_verify_result(r->connection->ssl->connection); + + if (rc != X509_V_OK) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client SSL certificate verify error: %l ", rc); + ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); + return NGX_ERROR; + } + + if (SSL_get_peer_certificate(r->connection->ssl->connection) + == NULL) + { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no required SSL certificate"); + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return NGX_ERROR; + } + } + } + +#endif + if (r->headers_in.connection) { if (r->headers_in.connection->value.len == 5 && ngx_strcasecmp(r->headers_in.connection->value.data, "close") diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index cc40f449a..e467dde17 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -75,7 +75,10 @@ /* The special code to close connection without any response */ #define NGX_HTTP_CLOSE 444 -#define NGX_HTTP_OWN_CODES NGX_HTTP_TO_HTTPS +#define NGX_HTTP_OWN_CODES 495 + +#define NGX_HTTPS_CERT_ERROR 495 +#define NGX_HTTPS_NO_CERT 496 /* * We use the special code for the plain HTTP requests that are sent to diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index d1072a9af..734ad6947 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -163,6 +163,26 @@ static char error_416_page[] = ; +static char error_495_page[] = +"<html>" CRLF +"<head><title>400 The SSL certificate error</title></head>" +CRLF +"<body bgcolor=\"white\">" CRLF +"<center><h1>400 Bad Request</h1></center>" CRLF +"<center>The SSL certificate error</center>" CRLF +; + + +static char error_496_page[] = +"<html>" CRLF +"<head><title>400 No required SSL certificate was sent</title></head>" +CRLF +"<body bgcolor=\"white\">" CRLF +"<center><h1>400 Bad Request</h1></center>" CRLF +"<center>No required SSL certificate was sent</center>" CRLF +; + + static char error_497_page[] = "<html>" CRLF "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>" @@ -254,6 +274,8 @@ static ngx_str_t error_pages[] = { #define NGX_HTTP_LEVEL_400 17 + ngx_string(error_495_page), /* 495, https certificate error */ + ngx_string(error_496_page), /* 496, https no certificate */ ngx_string(error_497_page), /* 497, http to https */ ngx_string(error_404_page), /* 498, invalid host name */ ngx_null_string, /* 499, client had closed connection */ @@ -296,6 +318,8 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE: case NGX_HTTP_REQUEST_URI_TOO_LARGE: case NGX_HTTP_TO_HTTPS: + case NGX_HTTPS_CERT_ERROR: + case NGX_HTTPS_NO_CERT: case NGX_HTTP_INTERNAL_SERVER_ERROR: r->keepalive = 0; } @@ -305,6 +329,8 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) switch (error) { case NGX_HTTP_BAD_REQUEST: case NGX_HTTP_TO_HTTPS: + case NGX_HTTPS_CERT_ERROR: + case NGX_HTTPS_NO_CERT: r->lingering_close = 0; } } @@ -372,6 +398,8 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) + NGX_HTTP_LEVEL_400; switch (error) { case NGX_HTTP_TO_HTTPS: + case NGX_HTTPS_CERT_ERROR: + case NGX_HTTPS_NO_CERT: r->headers_out.status = NGX_HTTP_BAD_REQUEST; error = NGX_HTTP_BAD_REQUEST; break; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 0f162a70e..83f2adc0b 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -810,19 +810,12 @@ static ngx_int_t ngx_http_variable_request_method(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->method_name.data) { - if (r->upstream && r->upstream->method.len) { - v->len = r->upstream->method.len; - v->data = r->upstream->method.data; - - } else { - v->len = r->method_name.len; - v->data = r->method_name.data; - } - + if (r->main->method_name.data) { + v->len = r->main->method_name.len; v->valid = 1; v->no_cachable = 0; v->not_found = 0; + v->data = r->main->method_name.data; } else { v->not_found = 1; |