[PATCH] Proxy remote server SSL certificate verification
Aviram Cohen
aviram at adallom.com
Tue Aug 20 12:33:43 UTC 2013
Hello!
Nginx's reverse proxy doesn't verify the SSL certificate of the remote
server (see http://trac.nginx.org/nginx/ticket/13).
The following is a suggested patch for v1.4.1 that adds this feature. It is
partially inspired by the patch for v1.1.3 that has been suggested in this
list and in the ticket above, with some improvements (i.e. no need to add
the "verification_failed" field to ngx_ssl_connection_t).
Note that a directory of CA's should be provided as a configuration
parameter ("CApath"), and that this patch is missing a Certificate
Revocation List file feature.
Feedback would be welcome.
Best regards,
Aviram
diff -Nrpu nginx-1.4.1/src/event/ngx_event_openssl.c
nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.c
--- nginx-1.4.1/src/event/ngx_event_openssl.c 2013-05-06 13:26:50.000000000
+0300
+++ nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.c 2013-08-20
14:53:31.465251759 +0300
@@ -337,6 +337,31 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
ngx_int_t
+ngx_ssl_set_verify_options(ngx_ssl_t *ssl, ngx_str_t *cert,
+ ngx_int_t depth)
+{
+ if (cert->len == 0) {
+ return NGX_OK;
+ }
+
+ SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER,
ngx_http_ssl_verify_callback);
+
+ SSL_CTX_set_verify_depth(ssl->ctx, depth);
+
+ if (SSL_CTX_load_verify_locations(ssl->ctx, NULL, (char *) cert->data)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_load_verify_locations(\"%s\") failed",
+ cert->data);
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth)
{
@@ -710,6 +735,17 @@ ngx_ssl_set_session(ngx_connection_t *c,
return NGX_OK;
}
+
+ngx_int_t
+ngx_ssl_verify_result(ngx_connection_t *c)
+{
+ if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
+ ngx_ssl_error(NGX_LOG_EMERG, c->log, 0, "SSL_get_verify_result
failed");
+ return NGX_ERROR;
+ }
+ return NGX_OK;
+}
+
ngx_int_t
ngx_ssl_handshake(ngx_connection_t *c)
diff -Nrpu nginx-1.4.1/src/event/ngx_event_openssl.h
nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.h
--- nginx-1.4.1/src/event/ngx_event_openssl.h 2013-05-06 13:26:50.000000000
+0300
+++ nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.h 2013-08-20
14:54:37.933252402 +0300
@@ -100,6 +100,8 @@ ngx_int_t ngx_ssl_init(ngx_log_t *log);
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_str_t *key);
+ngx_int_t ngx_ssl_set_verify_options(ngx_ssl_t *ssl, ngx_str_t *cert,
+ ngx_int_t depth);
ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_int_t depth);
ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
@@ -155,6 +157,7 @@ ngx_int_t ngx_ssl_get_client_verify(ngx_
ngx_str_t *s);
+ngx_int_t ngx_ssl_verify_result(ngx_connection_t *c);
ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
diff -Nrpu nginx-1.4.1/src/http/modules/ngx_http_proxy_module.c
nginx-1.4.1-proxy-ssl-verify/src/http/modules/ngx_http_proxy_module.c
--- nginx-1.4.1/src/http/modules/ngx_http_proxy_module.c 2013-05-06
13:26:50.000000000 +0300
+++ nginx-1.4.1-proxy-ssl-verify/src/http/modules/ngx_http_proxy_module.c
2013-08-20
14:56:24.001251235 +0300
@@ -511,6 +511,26 @@ static ngx_command_t ngx_http_proxy_com
offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
NULL },
+ { ngx_string("proxy_ssl_verify_peer"),
+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify_peer),
+ NULL },
+
+ { ngx_string("proxy_ssl_verify_depth"),
+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify_depth),
+ NULL },
+
+ { ngx_string("proxy_ssl_ca_certificate"),
+
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_ca_certificate),
+ NULL },
#endif
ngx_null_command
@@ -2421,6 +2441,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
conf->upstream.intercept_errors = NGX_CONF_UNSET;
#if (NGX_HTTP_SSL)
conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
+ conf->upstream.ssl_verify_peer = NGX_CONF_UNSET;
+ conf->upstream.ssl_verify_depth = NGX_CONF_UNSET_UINT;
#endif
/* "proxy_cyclic_temp_file" is disabled */
@@ -2697,6 +2719,22 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
#if (NGX_HTTP_SSL)
ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
prev->upstream.ssl_session_reuse, 1);
+ ngx_conf_merge_value(conf->upstream.ssl_verify_peer,
+ prev->upstream.ssl_verify_peer, 0);
+ ngx_conf_merge_uint_value(conf->upstream.ssl_verify_depth,
+ prev->upstream.ssl_verify_depth, 1);
+ ngx_conf_merge_str_value(conf->upstream.ssl_ca_certificate,
+ prev->upstream.ssl_ca_certificate, "");
+
+ if (conf->upstream.ssl_verify_peer) {
+ if (conf->upstream.ssl_ca_certificate.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no \"proxy_ssl_ca_certificate\" is defined
for "
+ "the \"proxy_ssl_verify_peer\" directive");
+
+ return NGX_CONF_ERROR;
+ }
+ }
#endif
ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
diff -Nrpu nginx-1.4.1/src/http/ngx_http_upstream.c
nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.c
--- nginx-1.4.1/src/http/ngx_http_upstream.c 2013-05-06 13:26:50.000000000
+0300
+++ nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.c 2013-08-20
14:59:29.437251122 +0300
@@ -1281,6 +1281,15 @@ ngx_http_upstream_ssl_init_connection(ng
{
ngx_int_t rc;
+ if (ngx_ssl_set_verify_options(u->conf->ssl,
+ &u->conf->ssl_ca_certificate, u->conf->ssl_verify_depth)
+ != NGX_OK)
+ {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
if (ngx_ssl_create_connection(u->conf->ssl, c,
NGX_SSL_BUFFER|NGX_SSL_CLIENT)
!= NGX_OK)
@@ -1324,6 +1333,12 @@ ngx_http_upstream_ssl_handshake(ngx_conn
u = r->upstream;
if (c->ssl->handshaked) {
+ if (u->conf->ssl_verify_peer && ngx_ssl_verify_result(c) !=
NGX_OK) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream ssl
certificate validation failed");
+ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+ goto fail;
+ }
+
if (u->conf->ssl_session_reuse) {
u->peer.save_session(&u->peer, u->peer.data);
@@ -1334,6 +1349,11 @@ ngx_http_upstream_ssl_handshake(ngx_conn
ngx_http_upstream_send_request(r, u);
+fail:
+ c = r->connection;
+
+ ngx_http_run_posted_requests(c);
+
return;
}
diff -Nrpu nginx-1.4.1/src/http/ngx_http_upstream.h
nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.h
--- nginx-1.4.1/src/http/ngx_http_upstream.h 2013-05-06 13:26:50.000000000
+0300
+++ nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.h 2013-08-20
15:00:10.281251422 +0300
@@ -191,6 +191,9 @@ typedef struct {
#if (NGX_HTTP_SSL)
ngx_ssl_t *ssl;
ngx_flag_t ssl_session_reuse;
+ ngx_flag_t ssl_verify_peer;
+ ngx_uint_t ssl_verify_depth;
+ ngx_str_t ssl_ca_certificate;
#endif
ngx_str_t module;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130820/01a027e6/attachment.html>
More information about the nginx-devel
mailing list