<div dir="ltr">Hello!<div><br></div><div>Nginx's reverse proxy doesn't verify the SSL certificate of the remote server (see <a href="http://trac.nginx.org/nginx/ticket/13">http://trac.nginx.org/nginx/ticket/13</a>).</div>
<div><br></div><div>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).</div>
<div><br></div><div>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.</div><div><br></div><div>
Feedback would be welcome.</div><div><br></div><div>Best regards,</div><div>Aviram</div><div><br></div><div><br></div><div><div>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</div>
<div>--- nginx-1.4.1/src/event/ngx_event_openssl.c<span class="" style="white-space:pre"> </span>2013-05-06 13:26:50.000000000 +0300</div><div>+++ nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.c<span class="" style="white-space:pre"> </span>2013-08-20 14:53:31.465251759 +0300</div>
<div>@@ -337,6 +337,31 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_</div><div> </div><div> </div><div> ngx_int_t</div><div>+ngx_ssl_set_verify_options(ngx_ssl_t *ssl, ngx_str_t *cert,</div><div>+ ngx_int_t depth)</div><div>
+{</div><div>+ if (cert->len == 0) {</div><div>+ return NGX_OK;</div><div>+ }</div><div>+</div><div>+ SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);</div><div>+</div><div>
+ SSL_CTX_set_verify_depth(ssl->ctx, depth);</div><div>+</div><div>+ if (SSL_CTX_load_verify_locations(ssl->ctx, NULL, (char *) cert->data)</div><div>+ == 0)</div><div>+ {</div><div>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,</div>
<div>+ "SSL_CTX_load_verify_locations(\"%s\") failed",</div><div>+ cert->data);</div><div>+ return NGX_ERROR;</div><div>+ }</div><div>+</div><div>
+ return NGX_OK;</div><div>+}</div><div>+</div><div>+</div><div>+ngx_int_t</div><div> ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,</div><div> ngx_int_t depth)</div><div> {</div><div>@@ -710,6 +735,17 @@ ngx_ssl_set_session(ngx_connection_t *c,</div>
<div> return NGX_OK;</div><div> }</div><div> </div><div>+</div><div>+ngx_int_t</div><div>+ngx_ssl_verify_result(ngx_connection_t *c)</div><div>+{</div><div>+ if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {</div>
<div>+ ngx_ssl_error(NGX_LOG_EMERG, c->log, 0, "SSL_get_verify_result failed");</div><div>+ return NGX_ERROR;</div><div>+ }</div><div>+ return NGX_OK;</div><div>+}</div><div>+</div><div> </div>
<div> ngx_int_t</div><div> ngx_ssl_handshake(ngx_connection_t *c)</div><div>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</div><div>--- nginx-1.4.1/src/event/ngx_event_openssl.h<span class="" style="white-space:pre"> </span>2013-05-06 13:26:50.000000000 +0300</div>
<div>+++ nginx-1.4.1-proxy-ssl-verify/src/event/ngx_event_openssl.h<span class="" style="white-space:pre"> </span>2013-08-20 14:54:37.933252402 +0300</div><div>@@ -100,6 +100,8 @@ ngx_int_t ngx_ssl_init(ngx_log_t *log);</div>
<div> ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);</div><div> ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,</div><div> ngx_str_t *cert, ngx_str_t *key);</div><div>+ngx_int_t ngx_ssl_set_verify_options(ngx_ssl_t *ssl, ngx_str_t *cert,</div>
<div>+ ngx_int_t depth);</div><div> ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,</div><div> ngx_str_t *cert, ngx_int_t depth);</div><div> ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,</div>
<div>@@ -155,6 +157,7 @@ ngx_int_t ngx_ssl_get_client_verify(ngx_</div><div> ngx_str_t *s);</div><div> </div><div> </div><div>+ngx_int_t ngx_ssl_verify_result(ngx_connection_t *c);</div><div> ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);</div>
<div> ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);</div><div> ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);</div><div>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</div>
<div>--- nginx-1.4.1/src/http/modules/ngx_http_proxy_module.c<span class="" style="white-space:pre"> </span>2013-05-06 13:26:50.000000000 +0300</div><div>+++ nginx-1.4.1-proxy-ssl-verify/src/http/modules/ngx_http_proxy_module.c<span class="" style="white-space:pre"> </span>2013-08-20 14:56:24.001251235 +0300</div>
<div>@@ -511,6 +511,26 @@ static ngx_command_t ngx_http_proxy_com</div><div> offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),</div><div> NULL },</div><div> </div><div>+ { ngx_string("proxy_ssl_verify_peer"),</div>
<div>+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,</div><div>+ ngx_conf_set_flag_slot,</div><div>+ NGX_HTTP_LOC_CONF_OFFSET,</div><div>+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify_peer),</div>
<div>+ NULL },</div><div>+</div><div>+ { ngx_string("proxy_ssl_verify_depth"),</div><div>+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,</div><div>+ ngx_conf_set_num_slot,</div>
<div>+ NGX_HTTP_LOC_CONF_OFFSET,</div><div>+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify_depth),</div><div>+ NULL },</div><div>+ </div><div>+ { ngx_string("proxy_ssl_ca_certificate"),</div>
<div>+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,</div><div>+ ngx_conf_set_str_slot,</div><div>+ NGX_HTTP_LOC_CONF_OFFSET,</div><div>+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_ca_certificate),</div>
<div>+ NULL },</div><div> #endif</div><div> </div><div> ngx_null_command</div><div>@@ -2421,6 +2441,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_</div><div> conf->upstream.intercept_errors = NGX_CONF_UNSET;</div>
<div> #if (NGX_HTTP_SSL)</div><div> conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;</div><div>+ conf->upstream.ssl_verify_peer = NGX_CONF_UNSET;</div><div>+ conf->upstream.ssl_verify_depth = NGX_CONF_UNSET_UINT;</div>
<div> #endif</div><div> </div><div> /* "proxy_cyclic_temp_file" is disabled */</div><div>@@ -2697,6 +2719,22 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t</div><div> #if (NGX_HTTP_SSL)</div><div> ngx_conf_merge_value(conf->upstream.ssl_session_reuse,</div>
<div> prev->upstream.ssl_session_reuse, 1);</div><div>+ ngx_conf_merge_value(conf->upstream.ssl_verify_peer,</div><div>+ prev->upstream.ssl_verify_peer, 0);</div>
<div>+ ngx_conf_merge_uint_value(conf->upstream.ssl_verify_depth,</div><div>+ prev->upstream.ssl_verify_depth, 1);</div><div>+ ngx_conf_merge_str_value(conf->upstream.ssl_ca_certificate,</div>
<div>+ prev->upstream.ssl_ca_certificate, "");</div><div>+</div><div>+ if (conf->upstream.ssl_verify_peer) {</div><div>+ if (conf->upstream.ssl_ca_certificate.len == 0) {</div>
<div>+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,</div><div>+ "no \"proxy_ssl_ca_certificate\" is defined for "</div><div>+ "the \"proxy_ssl_verify_peer\" directive");</div>
<div>+ </div><div>+ return NGX_CONF_ERROR;</div><div>+ }</div><div>+ }</div><div> #endif</div><div> </div><div> ngx_conf_merge_value(conf->redirect, prev->redirect, 1);</div><div>
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</div><div>--- nginx-1.4.1/src/http/ngx_http_upstream.c<span class="" style="white-space:pre"> </span>2013-05-06 13:26:50.000000000 +0300</div>
<div>+++ nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.c<span class="" style="white-space:pre"> </span>2013-08-20 14:59:29.437251122 +0300</div><div>@@ -1281,6 +1281,15 @@ ngx_http_upstream_ssl_init_connection(ng</div>
<div> {</div><div> ngx_int_t rc;</div><div> </div><div>+ if (ngx_ssl_set_verify_options(u->conf->ssl,</div><div>+ &u->conf->ssl_ca_certificate, u->conf->ssl_verify_depth)</div><div>
+ != NGX_OK)</div><div>+ {</div><div>+ ngx_http_upstream_finalize_request(r, u,</div><div>+ NGX_HTTP_INTERNAL_SERVER_ERROR);</div><div>+ return;</div><div>
+ }</div><div>+</div><div> if (ngx_ssl_create_connection(u->conf->ssl, c,</div><div> NGX_SSL_BUFFER|NGX_SSL_CLIENT)</div><div> != NGX_OK)</div><div>@@ -1324,6 +1333,12 @@ ngx_http_upstream_ssl_handshake(ngx_conn</div>
<div> u = r->upstream;</div><div> </div><div> if (c->ssl->handshaked) {</div><div>+ if (u->conf->ssl_verify_peer && ngx_ssl_verify_result(c) != NGX_OK) {</div><div>+ ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream ssl certificate validation failed");</div>
<div>+ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);</div><div>+ goto fail;</div><div>+ }</div><div>+ </div><div> </div><div> if (u->conf->ssl_session_reuse) {</div>
<div> u->peer.save_session(&u->peer, u->peer.data);</div><div>@@ -1334,6 +1349,11 @@ ngx_http_upstream_ssl_handshake(ngx_conn</div><div> </div><div> ngx_http_upstream_send_request(r, u);</div>
<div> </div><div>+fail:</div><div>+ c = r->connection;</div><div>+ </div><div>+ ngx_http_run_posted_requests(c);</div><div>+ </div><div> return;</div><div> }</div><div> </div><div>
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</div><div>--- nginx-1.4.1/src/http/ngx_http_upstream.h<span class="" style="white-space:pre"> </span>2013-05-06 13:26:50.000000000 +0300</div>
<div>+++ nginx-1.4.1-proxy-ssl-verify/src/http/ngx_http_upstream.h<span class="" style="white-space:pre"> </span>2013-08-20 15:00:10.281251422 +0300</div><div>@@ -191,6 +191,9 @@ typedef struct {</div><div> #if (NGX_HTTP_SSL)</div>
<div> ngx_ssl_t *ssl;</div><div> ngx_flag_t ssl_session_reuse;</div><div>+ ngx_flag_t ssl_verify_peer;</div><div>+ ngx_uint_t ssl_verify_depth;</div>
<div>+ ngx_str_t ssl_ca_certificate;</div><div> #endif</div><div> </div><div> ngx_str_t module;</div></div><div><br></div></div>