[PATCH] Proxy remote server SSL certificate verification
Aviram Cohen
aviram at adallom.com
Tue Sep 3 12:32:58 UTC 2013
Hello!
Thanks for the comments. The new version with all the fixes is
attached (and also pasted in this mail).
Best regards,
Aviram
diff -Npru nginx-1.4.1/src/http/modules/ngx_http_proxy_module.c
nginx-1.4.1-proxy-ssl-verification/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-verification/src/http/modules/ngx_http_proxy_module.c
2013-09-03 15:23:15.607874155 +0300
@@ -74,6 +74,11 @@ typedef struct {
ngx_uint_t http_version;
+#if (NGX_HTTP_SSL)
+ ngx_uint_t ssl_verify_depth;
+ ngx_str_t ssl_trusted_certificate;
+#endif
+
ngx_uint_t headers_hash_max_size;
ngx_uint_t headers_hash_bucket_size;
} ngx_http_proxy_loc_conf_t;
@@ -510,6 +515,27 @@ static ngx_command_t ngx_http_proxy_com
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
NULL },
+
+ { ngx_string("proxy_ssl_verify"),
+ 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),
+ 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, ssl_verify_depth),
+ NULL },
+
+ { ngx_string("proxy_ssl_trusted_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, ssl_trusted_certificate),
+ NULL },
#endif
@@ -2382,6 +2408,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
* conf->body_set = NULL;
* conf->body_source = { 0, NULL };
* conf->redirects = NULL;
+ * conf->ssl_trusted_certificate = NULL;
*/
conf->upstream.store = NGX_CONF_UNSET;
@@ -2419,8 +2446,11 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
conf->upstream.intercept_errors = NGX_CONF_UNSET;
+
#if (NGX_HTTP_SSL)
conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
+ conf->upstream.ssl_verify = NGX_CONF_UNSET;
+ conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
#endif
/* "proxy_cyclic_temp_file" is disabled */
@@ -2695,8 +2725,36 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
prev->upstream.intercept_errors, 0);
#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,
+ prev->upstream.ssl_verify, 0);
+ ngx_conf_merge_uint_value(conf->ssl_verify_depth,
+ prev->ssl_verify_depth, 1);
+ ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
+ prev->ssl_trusted_certificate, "");
+
+ if (conf->upstream.ssl && conf->upstream.ssl_verify) {
+ if (conf->ssl_trusted_certificate.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no \"proxy_ssl_trusted_certificate\" is "
+ " defined for the \"proxy_ssl_verify\" "
+ "directive");
+
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ if (conf->upstream.ssl
+ && ngx_ssl_trusted_certificate(cf, conf->upstream.ssl,
+ &conf->ssl_trusted_certificate,
+ conf->ssl_verify_depth)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
#endif
ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
diff -Npru nginx-1.4.1/src/http/ngx_http_upstream.c
nginx-1.4.1-proxy-ssl-verification/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-verification/src/http/ngx_http_upstream.c
2013-09-03 15:23:15.611874377 +0300
@@ -1319,12 +1319,30 @@ ngx_http_upstream_ssl_handshake(ngx_conn
{
ngx_http_request_t *r;
ngx_http_upstream_t *u;
-
+ X509 *cert;
+
r = c->data;
u = r->upstream;
if (c->ssl->handshaked) {
-
+ if (u->conf->ssl_verify) {
+ if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "upstream ssl certificate validation failed");
+ goto fail;
+ }
+
+ cert = SSL_get_peer_certificate(c->ssl->connection);
+
+ if (cert == NULL) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "upstream sent no required SSL certificate");
+ goto fail;
+ }
+
+ X509_free(cert);
+ }
+
if (u->conf->ssl_session_reuse) {
u->peer.save_session(&u->peer, u->peer.data);
}
@@ -1332,13 +1350,21 @@ ngx_http_upstream_ssl_handshake(ngx_conn
c->write->handler = ngx_http_upstream_handler;
c->read->handler = ngx_http_upstream_handler;
+ c = r->connection;
+
ngx_http_upstream_send_request(r, u);
+ ngx_http_run_posted_requests(c);
+
return;
}
+fail:
+ c = r->connection;
+
ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+ ngx_http_run_posted_requests(c);
}
#endif
diff -Npru nginx-1.4.1/src/http/ngx_http_upstream.h
nginx-1.4.1-proxy-ssl-verification/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-verification/src/http/ngx_http_upstream.h
2013-09-03 15:23:15.611874377 +0300
@@ -191,6 +191,7 @@ typedef struct {
#if (NGX_HTTP_SSL)
ngx_ssl_t *ssl;
ngx_flag_t ssl_session_reuse;
+ ngx_flag_t ssl_verify;
#endif
ngx_str_t module;
On Mon, Sep 2, 2013 at 3:09 PM, Maxim Dounin <mdounin at mdounin.ru> wrote:
> Hello!
>
> On Sun, Sep 01, 2013 at 11:19:06AM +0300, Aviram Cohen wrote:
>
>> Hello!
>>
>> On Wed, Aug 28, 2013 at 3:41 AM, Maxim Dounin <mdounin at mdounin.ru> wrote:
>> > Hello!
>> >
>> [...]
>> >
>> > if (conf->upstream.ssl
>> > && ngx_ssl_trusted_certificate(cf, conf->upstream.ssl,
>> > &conf->upstream.ssl_certificate
>> > conf->upstream.ssl_verify_depth)
>> > != NGX_OK)
>> > {
>> > ...
>> > }
>> >
>> > Additional question is what happens in a configuration like
>> >
>> > location / {
>> > proxy_pass https://example.com;
>> > proxy_ssl_verify on;
>> > proxy_ssl_trusted_ceritifcate example.crt;
>> >
>> > if ($foo) {
>> > # do nothing
>> > }
>> > }
>> >
>> > or the same with a nested location instead of "if". Quick look
>> > suggest it will result in trusted certs loaded twice (and stale
>> > alerts later due to how OpenSSL handles this).
>> >
>>
>> I have tried this configuration (and also a nested location), and didn't
>> see that Nginx loaded the same certificate twice (I've actually put
>> a breakpoint on the if clause in which ngx_ssl_trusted_certificate
>> is called, and it was called only once for the location.
>>
>> Can you specify exactly how to reproduce this case?
>
> I was probably wrong here, as the code you added is before the
> conf->upstream.ssl is inherited.
>
> --
> Maxim Dounin
> http://nginx.org/en/donation.html
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
--
Aviram Cohen, R&D
Adallom, 1 Ha'Barzel st., Tel-Aviv, Israel
Mobile: +972 (54) 5833508
aviram at adallom.com, www.adallom.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nginx-1.4.1-proxy-ssl-verification.patch
Type: application/octet-stream
Size: 6235 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130903/d255af92/attachment.obj>
More information about the nginx-devel
mailing list