[nginx] SSL: variables support in ssl_certificate and ssl_certificate_key.
Maxim Dounin
mdounin at mdounin.ru
Mon Feb 25 13:49:42 UTC 2019
details: https://hg.nginx.org/nginx/rev/be2af41d3620
branches:
changeset: 7462:be2af41d3620
user: Maxim Dounin <mdounin at mdounin.ru>
date: Mon Feb 25 16:42:05 2019 +0300
description:
SSL: variables support in ssl_certificate and ssl_certificate_key.
To evaluate variables, a request is created in the certificate callback,
and then freed. To do this without side effects on the stub_status
counters and connection state, an additional function was introduced,
ngx_http_alloc_request().
Only works with OpenSSL 1.0.2+, since there is no SSL_CTX_set_cert_cb()
in older versions.
diffstat:
src/http/modules/ngx_http_ssl_module.c | 116 +++++++++++++++++++++++++++++-
src/http/modules/ngx_http_ssl_module.h | 3 +
src/http/ngx_http.h | 4 +
src/http/ngx_http_request.c | 126 +++++++++++++++++++++++++++-----
4 files changed, 225 insertions(+), 24 deletions(-)
diffs (357 lines):
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -41,6 +41,9 @@ static void *ngx_http_ssl_create_srv_con
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child);
+static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_http_ssl_srv_conf_t *conf);
+
static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -550,6 +553,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t
* set by ngx_pcalloc():
*
* sscf->protocols = 0;
+ * sscf->certificate_values = NULL;
* sscf->dhparam = { 0, NULL };
* sscf->ecdh_curve = { 0, NULL };
* sscf->client_certificate = { 0, NULL };
@@ -727,13 +731,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;
- if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
- conf->certificate_keys, conf->passwords)
- != NGX_OK)
- {
+ if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
+ if (conf->certificate_values) {
+
+#ifdef SSL_R_CERT_CB_ERROR
+
+ /* install callback to lookup certificates */
+
+ SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_http_ssl_certificate, NULL);
+
+#else
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "variables in "
+ "\"ssl_certificate\" and \"ssl_certificate_key\" "
+ "directives are not supported on this platform");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+
+ /* configure certificates */
+
+ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
@@ -831,6 +860,85 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
}
+static ngx_int_t
+ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_http_ssl_srv_conf_t *conf)
+{
+ ngx_str_t *cert, *key;
+ ngx_uint_t i, nelts;
+ ngx_http_complex_value_t *cv;
+ ngx_http_compile_complex_value_t ccv;
+
+ cert = conf->certificates->elts;
+ key = conf->certificate_keys->elts;
+ nelts = conf->certificates->nelts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_http_script_variables_count(&cert[i])) {
+ goto found;
+ }
+
+ if (ngx_http_script_variables_count(&key[i])) {
+ goto found;
+ }
+ }
+
+ return NGX_OK;
+
+found:
+
+ conf->certificate_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_http_complex_value_t));
+ if (conf->certificate_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ conf->certificate_key_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_http_complex_value_t));
+ if (conf->certificate_key_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < nelts; i++) {
+
+ cv = ngx_array_push(conf->certificate_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &cert[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ cv = ngx_array_push(conf->certificate_key_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &key[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
static char *
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -36,6 +36,9 @@ typedef struct {
ngx_array_t *certificates;
ngx_array_t *certificate_keys;
+ ngx_array_t *certificate_values;
+ ngx_array_t *certificate_key_values;
+
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
ngx_str_t client_certificate;
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -88,6 +88,10 @@ void ngx_http_close_connection(ngx_conne
#if (NGX_HTTP_SSL && defined SSL_CTRL_SET_TLSEXT_HOSTNAME)
int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
#endif
+#if (NGX_HTTP_SSL && defined SSL_R_CERT_CB_ERROR)
+int ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
+#endif
+
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -11,6 +11,7 @@
static void ngx_http_wait_request_handler(ngx_event_t *ev);
+static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c);
static void ngx_http_process_request_line(ngx_event_t *rev);
static void ngx_http_process_request_headers(ngx_event_t *rev);
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
@@ -503,17 +504,45 @@ ngx_http_wait_request_handler(ngx_event_
ngx_http_request_t *
ngx_http_create_request(ngx_connection_t *c)
{
+ ngx_http_request_t *r;
+ ngx_http_log_ctx_t *ctx;
+ ngx_http_core_loc_conf_t *clcf;
+
+ r = ngx_http_alloc_request(c);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ c->requests++;
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ ngx_set_connection_log(c, clcf->error_log);
+
+ ctx = c->log->data;
+ ctx->request = r;
+ ctx->current_request = r;
+
+#if (NGX_STAT_STUB)
+ (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
+ r->stat_reading = 1;
+ (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
+#endif
+
+ return r;
+}
+
+
+static ngx_http_request_t *
+ngx_http_alloc_request(ngx_connection_t *c)
+{
ngx_pool_t *pool;
ngx_time_t *tp;
ngx_http_request_t *r;
- ngx_http_log_ctx_t *ctx;
ngx_http_connection_t *hc;
ngx_http_core_srv_conf_t *cscf;
- ngx_http_core_loc_conf_t *clcf;
ngx_http_core_main_conf_t *cmcf;
- c->requests++;
-
hc = c->data;
cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
@@ -541,10 +570,6 @@ ngx_http_create_request(ngx_connection_t
r->read_event_handler = ngx_http_block_reading;
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
- ngx_set_connection_log(r->connection, clcf->error_log);
-
r->header_in = hc->busy ? hc->busy->buf : c->buffer;
if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
@@ -604,17 +629,8 @@ ngx_http_create_request(ngx_connection_t
r->http_state = NGX_HTTP_READING_REQUEST_STATE;
- ctx = c->log->data;
- ctx->request = r;
- ctx->current_request = r;
r->log_handler = ngx_http_log_error_handler;
-#if (NGX_STAT_STUB)
- (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
- r->stat_reading = 1;
- (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
-#endif
-
return r;
}
@@ -931,6 +947,74 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
#endif
+
+#ifdef SSL_R_CERT_CB_ERROR
+
+int
+ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
+{
+ ngx_str_t cert, key;
+ ngx_uint_t i, nelts;
+ ngx_connection_t *c;
+ ngx_http_request_t *r;
+ ngx_http_ssl_srv_conf_t *sscf;
+ ngx_http_complex_value_t *certs, *keys;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ if (c->ssl->handshaked) {
+ return 0;
+ }
+
+ r = ngx_http_alloc_request(c);
+ if (r == NULL) {
+ return 0;
+ }
+
+ r->logged = 1;
+
+ sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
+
+ nelts = sscf->certificate_values->nelts;
+ certs = sscf->certificate_values->elts;
+ keys = sscf->certificate_key_values->elts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl cert: \"%s\"", cert.data);
+
+ if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl key: \"%s\"", key.data);
+
+ if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, NULL)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+ }
+
+ ngx_http_free_request(r, 0);
+ c->destroyed = 0;
+ return 1;
+
+failed:
+
+ ngx_http_free_request(r, 0);
+ c->destroyed = 0;
+ return 0;
+}
+
+#endif
+
#endif
@@ -3514,9 +3598,11 @@ ngx_http_free_request(ngx_http_request_t
r->headers_out.status = rc;
}
- log->action = "logging request";
-
- ngx_http_log_request(r);
+ if (!r->logged) {
+ log->action = "logging request";
+
+ ngx_http_log_request(r);
+ }
log->action = "closing request";
More information about the nginx-devel
mailing list