aboutsummaryrefslogtreecommitdiff
path: root/src/http
diff options
context:
space:
mode:
Diffstat (limited to 'src/http')
-rw-r--r--src/http/modules/ngx_http_ssl_module.c109
-rw-r--r--src/http/modules/ngx_http_ssl_module.h4
-rw-r--r--src/http/ngx_http_request.c36
-rw-r--r--src/http/ngx_http_request.h5
-rw-r--r--src/http/ngx_http_special_response.c28
-rw-r--r--src/http/ngx_http_variables.c13
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;