[PATCH] Proxy remote server SSL certificate verification

Maxim Dounin mdounin at mdounin.ru
Wed Aug 21 14:30:33 UTC 2013


Hello!

On Wed, Aug 21, 2013 at 02:45:55PM +0300, Aviram Cohen wrote:

> Hello!
> 
> Thank you for the useful feedback!
> I think it's better not to use ssl_trusted_certificate (for a more
> extensible solution).
> The following is the fixed patch. I've also attached it in case Gmail
> corrupts it.

[...]

>  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, (char *) cert->data, NULL)
> +        == 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;
> +}

Even if you don't want to reuse ssl_trusted_certificate value, 
reusing ngx_ssl_trusted_certificate() function might be a good 
idea.  In particular, it would have saved you from a bug with 
relative certificate names handling.

> +
> +
> +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;
> +}
> +

Note: the SSL_get_verify_result() is currently called directly by 
ngx_http_request.c code, and introducing a wrapper function for 
proxy code might not be a good idea.

[...]

> +    { ngx_string("proxy_ssl_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_certificate),
> +      NULL },
>  #endif

Still bad name.  Such name will easily cause confusion with a 
client certificate proxy may in theory use as well.  Something 
like "proxy_ssl_trusted_certificate" is probably good enough.

[...]

> @@ -3748,6 +3786,13 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n
>          != NGX_OK)
>      {
>          return NGX_ERROR;
> +    }
> +
> +    if (ngx_ssl_set_verify_options(plcf->upstream.ssl,
> +          &plcf->upstream.ssl_certificate, plcf->upstream.ssl_verify_depth)
> +        != NGX_OK)
> +    {
> +        return NGX_ERROR;
>      }

This is called before options used are correctly set.

(There is also a style problem here, but it doesn't really matter 
as you'll have to rewrite the code anyway.)

[...]

> @@ -1334,6 +1341,11 @@ ngx_http_upstream_ssl_handshake(ngx_conn
> 
>          ngx_http_upstream_send_request(r, u);
> 
> +        c = r->connection;
> +
> +fail:
> +        ngx_http_run_posted_requests(c);
> +
>          return;
>      }
> 

You probably missed my previous comment.  You have a use after 
free problem here.  Try triggering an error in 
ngx_http_upstream_send_request() with NGX_DEBUG_MALLOC defined, it 
should segfault.
 
[...]

-- 
Maxim Dounin
http://nginx.org/en/donation.html



More information about the nginx-devel mailing list