Proxy: add "proxy_ssl_alpn" directive. ALPN is used here only to indicate what version of the HTTP protocol is going to be used and proxy doesn't verify that upstream agreed to it. Please note that upstream is allowed to reject SSL connection with a fatal "no_application_protocol" alert if it doesn't support it. Change-Id: I02a18dae6aa9517d9fd9fd8da989dabfd8b82787 Signed-off-by: Piotr Sikora <piotrsikora@google.com> Reviewed-on: https://nginx-review.googlesource.com/2833 Reviewed-by: Lizan Zhou <zlizan@google.com>
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 1d43b73..1cc886d 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c
@@ -648,6 +648,29 @@ ngx_int_t +ngx_ssl_alpn_protos(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *protos) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + if (SSL_CTX_set_alpn_protos(ssl->ctx, protos->data, protos->len) != 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_alpn_protos() failed"); + return NGX_ERROR; + } + + return NGX_OK; + +#else + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "nginx was built with OpenSSL that lacks ALPN support"); + return NGX_ERROR; + +#endif +} + + +ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth) {
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index e093e10..87ffb66 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h
@@ -147,6 +147,8 @@ ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_uint_t prefer_server_ciphers); +ngx_int_t ngx_ssl_alpn_protos(ngx_conf_t *cf, ngx_ssl_t *ssl, + ngx_str_t *protos); 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,
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index f81fe73..e1ac1ef 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c
@@ -651,6 +651,13 @@ offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("proxy_ssl_alpn"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_alpn), + NULL }, + { ngx_string("proxy_ssl_name"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_set_complex_value_slot, @@ -2880,6 +2887,7 @@ conf->upstream.intercept_errors = NGX_CONF_UNSET; #if (NGX_HTTP_SSL) + conf->upstream.ssl_alpn = NGX_CONF_UNSET; conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; @@ -3211,6 +3219,8 @@ conf->upstream.ssl_name = prev->upstream.ssl_name; } + ngx_conf_merge_value(conf->upstream.ssl_alpn, + prev->upstream.ssl_alpn, 0); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -4319,6 +4329,7 @@ static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) { + ngx_str_t alpn; ngx_pool_cleanup_t *cln; plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); @@ -4365,6 +4376,24 @@ return NGX_ERROR; } + if (plcf->upstream.ssl_alpn) { + + switch (plcf->http_version) { + + case NGX_HTTP_VERSION_10: + ngx_str_set(&alpn, NGX_HTTP_10_ALPN_ADVERTISE); + break; + + case NGX_HTTP_VERSION_11: + ngx_str_set(&alpn, NGX_HTTP_11_ALPN_ADVERTISE); + break; + } + + if (ngx_ssl_alpn_protos(cf, plcf->upstream.ssl, &alpn) != NGX_OK) { + return NGX_ERROR; + } + } + if (plcf->upstream.ssl_verify) { if (plcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 2771ac1..bf9e022 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c
@@ -17,8 +17,6 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" - #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index b63a8b6..e5306ef 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h
@@ -13,6 +13,11 @@ #include <ngx_core.h> +#define NGX_HTTP_10_ALPN_ADVERTISE "\x08http/1.0" +#define NGX_HTTP_11_ALPN_ADVERTISE "\x08http/1.1" +#define NGX_HTTP_NPN_ADVERTISE NGX_HTTP_11_ALPN_ADVERTISE + + typedef struct ngx_http_request_s ngx_http_request_t; typedef struct ngx_http_upstream_s ngx_http_upstream_t; typedef struct ngx_http_cache_s ngx_http_cache_t;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 148a364..5384247 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h
@@ -226,6 +226,7 @@ #if (NGX_HTTP_SSL || NGX_COMPAT) ngx_ssl_t *ssl; + ngx_flag_t ssl_alpn; ngx_flag_t ssl_session_reuse; ngx_http_complex_value_t *ssl_name;