BBlack has uploaded a new change for review.
https://gerrit.wikimedia.org/r/286506
Change subject: multicert + libssl1.0.2 patches for 1.10.0
......................................................................
multicert + libssl1.0.2 patches for 1.10.0
Note these patchfiles were taken from our previous 1.9.4-1+wmf1
release. They mostly only needed minor offset corrections to
apply cleanly to 1.10.0 (those offset corrections are already
applied in the patchfiles in this commit). In one case there was
a very tiny obvious update to an argument type.
Bug: T96848
Change-Id: Ida2b3deffc97ef40704a32581e824723267df700
---
M debian/control
A debian/patches/1001-openssl102.patch
A debian/patches/1002-stapling-per-cert.patch
A debian/patches/1003-stapling-multi-cert.patch
A debian/patches/1004-cert-list.patch
A debian/patches/1005-multicert-modules.patch
A debian/patches/1006-multicert-stream-modules.patch
M debian/patches/series
8 files changed, 1,686 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/operations/software/nginx
refs/changes/06/286506/1
diff --git a/debian/control b/debian/control
index 52baf37..94185cb 100644
--- a/debian/control
+++ b/debian/control
@@ -20,7 +20,7 @@
libpam0g-dev,
libpcre3-dev,
libperl-dev,
- libssl-dev,
+ libssl-dev (>= 1.0.2),
libxslt1-dev,
po-debconf,
zlib1g-dev
diff --git a/debian/patches/1001-openssl102.patch
b/debian/patches/1001-openssl102.patch
new file mode 100644
index 0000000..7d85c55
--- /dev/null
+++ b/debian/patches/1001-openssl102.patch
@@ -0,0 +1,231 @@
+----------- Original nginx-devel post --------------------------------------
+Hi,
+
+This is my last version of 'Multiple server certificates support ' patches.
+
+I restaged the changes in a more smart way.
+It is more respectful of 'contributing' requirements.
+
+It relies on OpenSSL to maintain a list of server certificates.
+It now stores a stapling context within/for each server certificate.
+
+Reviews and comments are welcome.
+
+Regards,
+Filipe da Silva
+Ingima
+
+---
+# HG changeset patch
+# User Filipe da Silva <fdasilva at ingima.com>
+# Date 1430147821 -7200
+# Mon Apr 27 17:17:01 2015 +0200
+# Node ID 0ac2a8668f852b604d46ff858199650bd3003fdb
+# Parent fc99323a3d790dcc7b87121261b4236d098336de
+SSL: introduce support of last openssl 1.0.2 features.
+
+Rely on openSSL 1.0.2 internals to manage the server certificate list and
+replace the previous SSL_CTX_ex_data(ngx_ssl_certificate_index, ...) storage.
+
+Add two new server certificate accessor methods to encapsulate this change:
+ngx_ssl_get_server_certificate & ngx_ssl_get_next_server_certificate.
+
+Add guards around ngx_ssl_stapling_index init when OCSP stapling is
unsupported.
+
+Compatible with 'stable-1.8'.
+------- End original nginx-devel post --------------------------------------
+
+WMF notes: applied to 1.9.3 with only one trivial manual context fixup, patch
+below is amended to apply cleanly
+
+diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
+index de10296..9ff3545 100644
+--- a/src/event/ngx_event_openssl.c
++++ b/src/event/ngx_event_openssl.c
+@@ -179,6 +179,7 @@ ngx_ssl_init(ngx_log_t *log)
+ return NGX_ERROR;
+ }
+
++#if OPENSSL_VERSION_NUMBER < 0x10002000L
+ ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+ if (ngx_ssl_certificate_index == -1) {
+@@ -186,7 +187,9 @@ ngx_ssl_init(ngx_log_t *log)
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
++#endif
+
++#if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
+ ngx_ssl_stapling_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+ if (ngx_ssl_stapling_index == -1) {
+@@ -194,6 +197,7 @@ ngx_ssl_init(ngx_log_t *log)
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
++#endif
+
+ return NGX_OK;
+ }
+@@ -308,6 +312,33 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void
*data)
+ }
+
+
++X509*
++ngx_ssl_get_server_certificate(ngx_ssl_t *ssl)
++{
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L
++ if (SSL_CTX_set_current_cert(ssl->ctx, SSL_CERT_SET_FIRST)) {
++ return (SSL_CTX_get0_certificate(ssl->ctx));
++ }
++ return NULL;
++#else
++
++ return (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index));
++#endif
++}
++
++
++X509*
++ngx_ssl_get_next_server_certificate(ngx_ssl_t *ssl)
++{
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L
++ if (SSL_CTX_set_current_cert(ssl->ctx, SSL_CERT_SET_NEXT)) {
++ return (SSL_CTX_get0_certificate(ssl->ctx));
++ }
++#endif
++ return NULL;
++}
++
++
+ ngx_int_t
+ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
+ ngx_str_t *key, ngx_array_t *passwords)
+@@ -351,6 +382,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert,
+ return NGX_ERROR;
+ }
+
++#if OPENSSL_VERSION_NUMBER < 0x10002000L
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
+ == 0)
+ {
+@@ -360,6 +392,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert,
+ BIO_free(bio);
+ return NGX_ERROR;
+ }
++#endif
+
+ X509_free(x509);
+
+@@ -387,10 +420,21 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert,
+ return NGX_ERROR;
+ }
+
++#ifdef SSL_CTX_add0_chain_cert
++ /*
++ * OpenSSL >=1.0.2 allows multiple server certificates in a single
++ * SSL_CTX to each have a different chain
++ */
++ if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) {
++ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
++ "SSL_CTX_add0_chain_cert(\"%s\") failed",
++ cert->data);
++#else
+ if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
+ cert->data);
++#endif
+ X509_free(x509);
+ BIO_free(bio);
+ return NGX_ERROR;
+@@ -2184,7 +2228,7 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t
*sess_ctx)
+ goto failed;
+ }
+
+- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
++ cert = ngx_ssl_get_server_certificate(ssl);
+
+ if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
+index 09654db..6d5eae3 100644
+--- a/src/event/ngx_event_openssl.h
++++ b/src/event/ngx_event_openssl.h
+@@ -207,6 +207,8 @@ ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c,
ngx_pool_t *pool,
+ ngx_str_t *s);
+ ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *s);
++X509* ngx_ssl_get_server_certificate(ngx_ssl_t *ssl);
++X509* ngx_ssl_get_next_server_certificate(ngx_ssl_t *ssl);
+
+
+ ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
+@@ -226,7 +228,6 @@ extern int ngx_ssl_connection_index;
+ extern int ngx_ssl_server_conf_index;
+ extern int ngx_ssl_session_cache_index;
+ extern int ngx_ssl_session_ticket_keys_index;
+-extern int ngx_ssl_certificate_index;
+ extern int ngx_ssl_stapling_index;
+
+
+diff --git a/src/event/ngx_event_openssl_stapling.c
b/src/event/ngx_event_openssl_stapling.c
+index 5322b1b..1e21891 100644
+--- a/src/event/ngx_event_openssl_stapling.c
++++ b/src/event/ngx_event_openssl_stapling.c
+@@ -269,9 +269,11 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
+ ngx_ssl_stapling_t *staple;
+
+ staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
++ cert = ngx_ssl_get_server_certificate(ssl->ctx);
+
+-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++#ifdef SSL_CTX_get0_chain_certs
++ SSL_CTX_get0_chain_certs(ssl->ctx, &chain);
++#elif OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
+ #else
+ chain = ssl->ctx->extra_certs;
+@@ -542,6 +544,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
+ u_char *p;
+ int n;
+ size_t len;
++ unsigned long flags;
+ time_t now, valid;
+ ngx_str_t response;
+ X509_STORE *store;
+@@ -597,15 +600,28 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
+ goto error;
+ }
+
+-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++#ifdef SSL_CTX_get0_chain_certs
++ SSL_CTX_get0_chain_certs(staple->ssl_ctx, &chain);
++#elif OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
+ #else
+ chain = staple->ssl_ctx->extra_certs;
+ #endif
+
+- if (OCSP_basic_verify(basic, chain, store,
+- staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
+- != 1)
++ flags = staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY;
++
++#if OPENSSL_VERSION_NUMBER < 0x10000000L
++ /*
++ * ECDSA/SHA-2 signature verification not supported.
++ * Released with OpenSSL 1.0.0 [29 Mar 2010]
++ * *) Add support for dsa-with-SHA224 and dsa-with-SHA256.
++ * See openssl commit 06e2dd037e29f82b92e1d1b9454f1595e602fb94
++ */
++ flags = flags | OCSP_NOSIGS;
++ /* TODO: improve case handling */
++#endif
++
++ if (OCSP_basic_verify(basic, chain, store, flags) != 1)
+ {
+ ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+ "OCSP_basic_verify() failed");
diff --git a/debian/patches/1002-stapling-per-cert.patch
b/debian/patches/1002-stapling-per-cert.patch
new file mode 100644
index 0000000..1828268
--- /dev/null
+++ b/debian/patches/1002-stapling-per-cert.patch
@@ -0,0 +1,379 @@
+----------- Original nginx-devel post --------------------------------------
+# HG changeset patch
+# User Filipe da Silva <fdasilva at ingima.com>
+# Date 1430147821 -7200
+# Mon Apr 27 17:17:01 2015 +0200
+# Node ID caabe5c77b51274237d7c49fffb864a27ca0a25f
+# Parent 0ac2a8668f852b604d46ff858199650bd3003fdb
+OCSP Stapling: attach one stapling_t context per server certificate.
+
+Prepare for multiple server certificate support.
+Split common stapling settings from per-certificate settings.
+Keep common stapling settings attached to initial SSL server
+context, as before.
+
+Know limit: the staple file must contain a response with as much CERTID as
+server certificate. This means that one OCSP request must be made about
+all the certificates at once.
+
+Compatible with 'stable-1.8'
+------- End original nginx-devel post --------------------------------------
+
+WMF notes: This one didn't apply completely cleanly, so the patch below
+differs in non-trivial ways from the original mailing list patch. The issues
+were related to the recent staple->valid changes in 1.9.
+
+In the interest of keeping this diff closer to the original from the mailing
+list it's based on, I removed 1.9.3's setting of staple->valid to
+NGX_MAX_TIME_T_VALUE for the ssl_stapling_file case, and in the _status
+callback I moved the "staple->valid >= ngx_time()" check to only apply to
+the non-ssl_stapling_file case.
+
+diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
+index 9ff3545..81b1848 100644
+--- a/src/event/ngx_event_openssl.c
++++ b/src/event/ngx_event_openssl.c
+@@ -106,6 +106,7 @@ int ngx_ssl_session_cache_index;
+ int ngx_ssl_session_ticket_keys_index;
+ int ngx_ssl_certificate_index;
+ int ngx_ssl_stapling_index;
++int ngx_ssl_cert_stapling_index;
+
+
+ ngx_int_t
+@@ -197,6 +198,14 @@ ngx_ssl_init(ngx_log_t *log)
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
++
++ ngx_ssl_cert_stapling_index = X509_get_ex_new_index(0, NULL, NULL, NULL,
++ NULL);
++ if (ngx_ssl_cert_stapling_index == -1) {
++ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
++ "X509_get_ex_new_index() failed");
++ return NGX_ERROR;
++ }
+ #endif
+
+ return NGX_OK;
+diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
+index 6d5eae3..a4c9adf 100644
+--- a/src/event/ngx_event_openssl.h
++++ b/src/event/ngx_event_openssl.h
+@@ -229,6 +229,7 @@ extern int ngx_ssl_server_conf_index;
+ extern int ngx_ssl_session_cache_index;
+ extern int ngx_ssl_session_ticket_keys_index;
+ extern int ngx_ssl_stapling_index;
++extern int ngx_ssl_cert_stapling_index;
+
+
+ #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
+diff --git a/src/event/ngx_event_openssl_stapling.c
b/src/event/ngx_event_openssl_stapling.c
+index 1e21891..0798462 100644
+--- a/src/event/ngx_event_openssl_stapling.c
++++ b/src/event/ngx_event_openssl_stapling.c
+@@ -14,13 +14,22 @@
+ #if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
+
+
++/* OCSP stapling configuration per server */
+ typedef struct {
+- ngx_str_t staple;
++ ngx_str_t staple_file;
+ ngx_msec_t timeout;
+
+ ngx_resolver_t *resolver;
+ ngx_msec_t resolver_timeout;
+
++ unsigned verify:1;
++} ngx_ssl_staple_conf_t;
++
++
++/* OCSP stapling context per certificate */
++typedef struct {
++ ngx_str_t staple; /* OCSP response from responder */
++
+ ngx_addr_t *addrs;
+ ngx_str_t host;
+ ngx_str_t uri;
+@@ -34,7 +43,6 @@ typedef struct {
+ time_t valid;
+ time_t refresh;
+
+- unsigned verify:1;
+ unsigned loading:1;
+ } ngx_ssl_stapling_t;
+
+@@ -54,6 +62,7 @@ struct ngx_ssl_ocsp_ctx_s {
+
+ ngx_resolver_t *resolver;
+ ngx_msec_t resolver_timeout;
++ unsigned verify:1;
+
+ ngx_msec_t timeout;
+
+@@ -84,14 +93,15 @@ struct ngx_ssl_ocsp_ctx_s {
+
+
+ static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
+- ngx_str_t *file);
++ ngx_str_t *file, ngx_ssl_staple_conf_t *conf);
+ static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
+ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_str_t *responder);
+
+ static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
+ void *data);
+-static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
++static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple,
++ ngx_ssl_staple_conf_t *conf);
+ static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
+
+ static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time);
+@@ -122,23 +132,14 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file,
+ ngx_str_t *responder, ngx_uint_t verify)
+ {
+ ngx_int_t rc;
+- ngx_pool_cleanup_t *cln;
+- ngx_ssl_stapling_t *staple;
++ ngx_ssl_staple_conf_t *conf;
+
+- staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
+- if (staple == NULL) {
++ conf = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_staple_conf_t));
++ if (conf == NULL) {
+ return NGX_ERROR;
+ }
+
+- cln = ngx_pool_cleanup_add(cf->pool, 0);
+- if (cln == NULL) {
+- return NGX_ERROR;
+- }
+-
+- cln->handler = ngx_ssl_stapling_cleanup;
+- cln->data = staple;
+-
+- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)
++ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, conf)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+@@ -146,14 +147,13 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file,
+ return NGX_ERROR;
+ }
+
+- staple->ssl_ctx = ssl->ctx;
+- staple->timeout = 60000;
+- staple->verify = verify;
++ conf->timeout = 60000;
++ conf->verify = verify;
+
+ if (file->len) {
+ /* use OCSP response from the file */
+
+- if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {
++ if (ngx_ssl_stapling_file(cf, ssl, file, conf) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+@@ -183,22 +183,20 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file,
+ done:
+
+ SSL_CTX_set_tlsext_status_cb(ssl->ctx,
ngx_ssl_certificate_status_callback);
+- SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple);
++ SSL_CTX_set_tlsext_status_arg(ssl->ctx, conf);
+
+ return NGX_OK;
+ }
+
+
+ static ngx_int_t
+-ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
++ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
++ ngx_ssl_staple_conf_t *conf)
+ {
+ BIO *bio;
+ int len;
+ u_char *p, *buf;
+ OCSP_RESPONSE *response;
+- ngx_ssl_stapling_t *staple;
+-
+- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+
+ if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
+ return NGX_ERROR;
+@@ -226,7 +224,8 @@ ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file)
+ goto failed;
+ }
+
+- buf = ngx_alloc(len, ssl->log);
++ /* File content buffer allocated from pool to avoid additional cleanup */
++ buf = ngx_palloc(cf->pool, len);
+ if (buf == NULL) {
+ goto failed;
+ }
+@@ -243,9 +242,8 @@ ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file)
+ OCSP_RESPONSE_free(response);
+ BIO_free(bio);
+
+- staple->staple.data = buf;
+- staple->staple.len = len;
+- staple->valid = NGX_MAX_TIME_T_VALUE;
++ conf->staple_file.data = buf;
++ conf->staple_file.len = len;
+
+ return NGX_OK;
+
+@@ -267,10 +265,33 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
+ X509_STORE_CTX *store_ctx;
+ STACK_OF(X509) *chain;
+ ngx_ssl_stapling_t *staple;
++ ngx_pool_cleanup_t *cln;
+
+- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+ cert = ngx_ssl_get_server_certificate(ssl->ctx);
+
++ staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
++ if (staple == NULL) {
++ return NGX_ERROR;
++ }
++
++ cln = ngx_pool_cleanup_add(cf->pool, 0);
++ if (cln == NULL) {
++ return NGX_ERROR;
++ }
++
++ cln->handler = ngx_ssl_stapling_cleanup;
++ cln->data = staple;
++
++ if (X509_set_ex_data(cert, ngx_ssl_cert_stapling_index, staple)
++ == 0)
++ {
++ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
++ "X509_set_ex_data() failed");
++ return NGX_ERROR;
++ }
++
++ staple->ssl_ctx = ssl->ctx;
++
+ #ifdef SSL_CTX_get0_chain_certs
+ SSL_CTX_get0_chain_certs(ssl->ctx, &chain);
+ #elif OPENSSL_VERSION_NUMBER >= 0x10001000L
+@@ -358,9 +379,11 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t
*ssl, ngx_str_t *responder)
+ ngx_url_t u;
+ char *s;
+ ngx_ssl_stapling_t *staple;
++ X509 *cert;
+ STACK_OF(OPENSSL_STRING) *aia;
+
+- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
++ cert = ngx_ssl_get_server_certificate(ssl);
++ staple = X509_get_ex_data(cert, ngx_ssl_cert_stapling_index);
+
+ if (responder->len == 0) {
+
+@@ -445,7 +468,7 @@ ngx_int_t
+ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
+ {
+- ngx_ssl_stapling_t *staple;
++ ngx_ssl_staple_conf_t *staple;
+
+ staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+
+@@ -459,45 +482,58 @@ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ static int
+ ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
+ {
+- int rc;
+- u_char *p;
+- ngx_connection_t *c;
+- ngx_ssl_stapling_t *staple;
++ int rc;
++ u_char *p;
++ ngx_str_t resp;
++ ngx_connection_t *c;
++ ngx_ssl_staple_conf_t *conf;
++ ngx_ssl_stapling_t *staple;
++ X509 *cert;
+
+ c = ngx_ssl_get_connection(ssl_conn);
++ cert = SSL_get_certificate(ssl_conn);
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL certificate status callback");
+
+- staple = data;
++ staple = X509_get_ex_data(cert, ngx_ssl_cert_stapling_index);
++ conf = data;
+ rc = SSL_TLSEXT_ERR_NOACK;
++ resp.len = 0;
+
+- if (staple->staple.len
+- && staple->valid >= ngx_time())
+- {
+- /* we have to copy ocsp response as OpenSSL will free it by itself */
++ if (conf->staple_file.len) {
++ resp = conf->staple_file;
++ }
++ else if (staple && staple->staple.len && staple->valid >= ngx_time()) {
++ resp = staple->staple;
++ }
++
++ if (resp.len) {
++ /* We have to copy ocsp response as OpenSSL will free it by itself */
++ p = OPENSSL_malloc(resp.len);
+
+- p = OPENSSL_malloc(staple->staple.len);
+ if (p == NULL) {
+ ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "OPENSSL_malloc()
failed");
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+- ngx_memcpy(p, staple->staple.data, staple->staple.len);
++ ngx_memcpy(p, resp.data, resp.len);
+
+- SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, staple->staple.len);
++ SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp.len);
+
+ rc = SSL_TLSEXT_ERR_OK;
+ }
+
+- ngx_ssl_stapling_update(staple);
++ if (staple) {
++ ngx_ssl_stapling_update(staple, conf);
++ }
+
+ return rc;
+ }
+
+
+ static void
+-ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
++ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple, ngx_ssl_staple_conf_t
*conf)
+ {
+ ngx_ssl_ocsp_ctx_t *ctx;
+
+@@ -521,10 +557,10 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
+ ctx->host = staple->host;
+ ctx->uri = staple->uri;
+ ctx->port = staple->port;
+- ctx->timeout = staple->timeout;
++ ctx->timeout = conf->timeout;
+
+- ctx->resolver = staple->resolver;
+- ctx->resolver_timeout = staple->resolver_timeout;
++ ctx->resolver = conf->resolver;
++ ctx->resolver_timeout = conf->resolver_timeout;
+
+ ctx->handler = ngx_ssl_stapling_ocsp_handler;
+ ctx->data = staple;
+@@ -608,7 +644,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
+ chain = staple->ssl_ctx->extra_certs;
+ #endif
+
+- flags = staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY;
++ flags = ctx->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY;
+
+ #if OPENSSL_VERSION_NUMBER < 0x10000000L
+ /*
diff --git a/debian/patches/1003-stapling-multi-cert.patch
b/debian/patches/1003-stapling-multi-cert.patch
new file mode 100644
index 0000000..13dfb0c
--- /dev/null
+++ b/debian/patches/1003-stapling-multi-cert.patch
@@ -0,0 +1,134 @@
+----------- Original nginx-devel post --------------------------------------
+# HG changeset patch
+# User Filipe da Silva <fdasilva at ingima.com>
+# Date 1430147821 -7200
+# Mon Apr 27 17:17:01 2015 +0200
+# Node ID 1b79826c93a4822fa3c11bc4139ca76e5189b14c
+# Parent caabe5c77b51274237d7c49fffb864a27ca0a25f
+OCSP Stapling: introduce multiple cert support.
+
+Loop on each certificate to init his respective stapling context.
+
+Compatible with 'stable-1.8'
+------- End original nginx-devel post --------------------------------------
+
+WMF notes: applied to 1.9.3 without failure, this patch just readjusts offsets
+
+diff --git a/src/event/ngx_event_openssl_stapling.c
b/src/event/ngx_event_openssl_stapling.c
+index 0798462..32d3c80 100644
+--- a/src/event/ngx_event_openssl_stapling.c
++++ b/src/event/ngx_event_openssl_stapling.c
+@@ -94,9 +94,10 @@ struct ngx_ssl_ocsp_ctx_s {
+
+ static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
+ ngx_str_t *file, ngx_ssl_staple_conf_t *conf);
+-static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
++static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,
++ X509 *cert);
+ static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
+- ngx_str_t *responder);
++ ngx_str_t *responder, X509 *cert);
+
+ static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
+ void *data);
+@@ -131,8 +132,9 @@ ngx_int_t
+ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
+ ngx_str_t *responder, ngx_uint_t verify)
+ {
+- ngx_int_t rc;
++ ngx_int_t rc, res;
+ ngx_ssl_staple_conf_t *conf;
++ X509 *cert;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_staple_conf_t));
+ if (conf == NULL) {
+@@ -160,24 +162,30 @@ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file,
+ goto done;
+ }
+
+- rc = ngx_ssl_stapling_issuer(cf, ssl);
++ res = NGX_DECLINED;
++ cert = ngx_ssl_get_server_certificate(ssl);
+
+- if (rc == NGX_DECLINED) {
+- return NGX_OK;
+- }
++ while (cert) {
++ rc = ngx_ssl_stapling_issuer(cf, ssl, cert);
+
+- if (rc != NGX_OK) {
+- return NGX_ERROR;
+- }
++ if (rc == NGX_OK) {
++ rc = ngx_ssl_stapling_responder(cf, ssl, responder, cert);
++ }
+
+- rc = ngx_ssl_stapling_responder(cf, ssl, responder);
++ if (rc == NGX_OK) {
++ /* result becomes OK when at least one cert is OK */
++ res = NGX_OK;
++ } else if (rc == NGX_DECLINED) {
++ rc = NGX_OK;
++ } else {
++ return NGX_ERROR;
++ }
+
+- if (rc == NGX_DECLINED) {
+- return NGX_OK;
++ cert = ngx_ssl_get_next_server_certificate(ssl);
+ }
+
+- if (rc != NGX_OK) {
+- return NGX_ERROR;
++ if (res == NGX_DECLINED) {
++ return NGX_OK;
+ }
+
+ done:
+@@ -257,18 +265,16 @@ failed:
+
+
+ static ngx_int_t
+-ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
++ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert)
+ {
+ int i, n, rc;
+- X509 *cert, *issuer;
++ X509 *issuer;
+ X509_STORE *store;
+ X509_STORE_CTX *store_ctx;
+ STACK_OF(X509) *chain;
+ ngx_ssl_stapling_t *staple;
+ ngx_pool_cleanup_t *cln;
+
+- cert = ngx_ssl_get_server_certificate(ssl->ctx);
+-
+ staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
+ if (staple == NULL) {
+ return NGX_ERROR;
+@@ -374,22 +380,21 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
+
+
+ static ngx_int_t
+-ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t
*responder)
++ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t
*responder,
++ X509 *cert)
+ {
+ ngx_url_t u;
+ char *s;
+ ngx_ssl_stapling_t *staple;
+- X509 *cert;
+ STACK_OF(OPENSSL_STRING) *aia;
+
+- cert = ngx_ssl_get_server_certificate(ssl);
+ staple = X509_get_ex_data(cert, ngx_ssl_cert_stapling_index);
+
+ if (responder->len == 0) {
+
+ /* extract OCSP responder URL from certificate */
+
+- aia = X509_get1_ocsp(staple->cert);
++ aia = X509_get1_ocsp(cert);
+ if (aia == NULL) {
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+ "\"ssl_stapling\" ignored, "
diff --git a/debian/patches/1004-cert-list.patch
b/debian/patches/1004-cert-list.patch
new file mode 100644
index 0000000..de215bc
--- /dev/null
+++ b/debian/patches/1004-cert-list.patch
@@ -0,0 +1,144 @@
+----------- Original nginx-devel post --------------------------------------
+# HG changeset patch
+# User Filipe da Silva <fdasilva at ingima.com>
+# Date 1430147821 -7200
+# Mon Apr 27 17:17:01 2015 +0200
+# Node ID e465a170ec3889eef1ab2d5d9f59cf8b12e97055
+# Parent 1b79826c93a4822fa3c11bc4139ca76e5189b14c
+SSL: introduce certificate list support.
+
+Arguments are now a list of certificates and list of keys.
+Split ngx_ssl_certificate to loop separately on cert and keys.
+SSL session_id_context value is build with every configured certificate.
+
+Compatible with 'stable-1.8'
+------- End original nginx-devel post --------------------------------------
+
+WMF notes: applied to 1.9.3 completely clean
+
+diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
+index 81b1848..b4423c9 100644
+--- a/src/event/ngx_event_openssl.c
++++ b/src/event/ngx_event_openssl.c
+@@ -33,6 +33,10 @@ static void ngx_ssl_connection_error(ngx_connection_t *c,
int sslerr,
+ ngx_err_t err, char *text);
+ static void ngx_ssl_clear_error(ngx_log_t *log);
+
++static ngx_int_t ngx_ssl_server_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
++ ngx_str_t *cert);
++static ngx_int_t ngx_ssl_private_key(ngx_conf_t *cf, ngx_ssl_t *ssl,
++ ngx_str_t *key, ngx_array_t *passwords);
+ static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
+ ngx_str_t *sess_ctx);
+ ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
+@@ -349,14 +353,39 @@ ngx_ssl_get_next_server_certificate(ngx_ssl_t *ssl)
+
+
+ ngx_int_t
+-ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
+- ngx_str_t *key, ngx_array_t *passwords)
++ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,
++ ngx_array_t *keys, ngx_array_t *passwords)
++{
++ ngx_uint_t i, j;
++ ngx_str_t *cert;
++ ngx_str_t *key;
++
++ /* Load server certificates */
++ cert = certs->elts;
++ for (i = 0; i < certs->nelts; i++, cert++) {
++ if (ngx_ssl_server_certificate(cf, ssl, cert) != NGX_OK) {
++ return NGX_ERROR;
++ }
++ }
++
++ /* Load private keys */
++ key = keys->elts;
++ for (j = 0; j < keys->nelts; j++, key++) {
++ if (ngx_ssl_private_key(cf, ssl, key, passwords) != NGX_OK) {
++ return NGX_ERROR;
++ }
++ }
++
++ return NGX_OK;
++}
++
++
++static ngx_int_t
++ngx_ssl_server_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert)
+ {
+ BIO *bio;
+ X509 *x509;
+ u_long n;
+- ngx_str_t *pwd;
+- ngx_uint_t tries;
+
+ if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
+ return NGX_ERROR;
+@@ -452,6 +481,17 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert,
+
+ BIO_free(bio);
+
++ return NGX_OK;
++}
++
++
++static ngx_int_t
++ngx_ssl_private_key(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *key,
++ ngx_array_t *passwords)
++{
++ ngx_str_t *pwd;
++ ngx_uint_t tries;
++
+ if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
+
+ #ifndef OPENSSL_NO_ENGINE
+@@ -2239,18 +2279,24 @@ ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t
*sess_ctx)
+
+ cert = ngx_ssl_get_server_certificate(ssl);
+
+- if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
+- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+- "X509_digest() failed");
+- goto failed;
+- }
++ while (cert) {
+
+- if (EVP_DigestUpdate(md, buf, len) == 0) {
+- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+- "EVP_DigestUpdate() failed");
+- goto failed;
++ if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
++ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
++ "X509_digest() failed");
++ goto failed;
++ }
++
++ if (EVP_DigestUpdate(md, buf, len) == 0) {
++ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
++ "EVP_DigestUpdate() failed");
++ goto failed;
++ }
++
++ cert = ngx_ssl_get_next_server_certificate(ssl);
+ }
+
++
+ list = SSL_CTX_get_client_CA_list(ssl->ctx);
+
+ if (list != NULL) {
+diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
+index a4c9adf..5fab4fd 100644
+--- a/src/event/ngx_event_openssl.h
++++ b/src/event/ngx_event_openssl.h
+@@ -140,8 +140,8 @@ typedef struct {
+
+ ngx_int_t ngx_ssl_init(ngx_log_t *log);
+ ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
+-ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
+- ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
++ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
++ ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords);
+ 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/debian/patches/1005-multicert-modules.patch
b/debian/patches/1005-multicert-modules.patch
new file mode 100644
index 0000000..cfdaf47
--- /dev/null
+++ b/debian/patches/1005-multicert-modules.patch
@@ -0,0 +1,536 @@
+----------- Original nginx-devel post --------------------------------------
+# HG changeset patch
+# User Filipe da Silva <fdasilva at ingima.com>
+# Date 1430148930 -7200
+# Mon Apr 27 17:35:30 2015 +0200
+# Node ID 64aad233af2e71b17d6ef8c7c021b701c83d578d
+# Parent f4975130e1101c4003a0ce4e5422990b780d50fe
+SSL: add Multiple SSL certificate support to other modules.
+
+Multiple entries are now possible for ssl_certificate and ssl_certificate_key
+settings.
+Fix compilation of previous patch changes.
+
+Compatible with 'stable-1.8'
+------- End original nginx-devel post --------------------------------------
+
+WMF notes: applied to 1.9.3 without failure, this patch just readjusts offsets
+
+diff --git a/src/http/modules/ngx_http_proxy_module.c
b/src/http/modules/ngx_http_proxy_module.c
+index c24ef17..5d425a4 100644
+--- a/src/http/modules/ngx_http_proxy_module.c
++++ b/src/http/modules/ngx_http_proxy_module.c
+@@ -97,8 +97,8 @@ typedef struct {
+ ngx_uint_t ssl_verify_depth;
+ ngx_str_t ssl_trusted_certificate;
+ ngx_str_t ssl_crl;
+- ngx_str_t ssl_certificate;
+- ngx_str_t ssl_certificate_key;
++ ngx_array_t *ssl_certificates;
++ ngx_array_t *ssl_certificate_keys;
+ ngx_array_t *ssl_passwords;
+ #endif
+ } ngx_http_proxy_loc_conf_t;
+@@ -680,16 +680,16 @@ static ngx_command_t ngx_http_proxy_commands[] = {
+
+ { 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_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
++ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificates),
+ NULL },
+
+ { ngx_string("proxy_ssl_certificate_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
++ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_keys),
+ NULL },
+
+ { ngx_string("proxy_ssl_password_file"),
+@@ -2868,6 +2868,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
+ conf->upstream.ssl_verify = NGX_CONF_UNSET;
+ conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
+ conf->ssl_passwords = NGX_CONF_UNSET_PTR;
++ conf->ssl_certificates = NGX_CONF_UNSET_PTR;
++ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
+ #endif
+
+ /* "proxy_cyclic_temp_file" is disabled */
+@@ -3194,10 +3196,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void
*parent, void *child)
+ prev->ssl_trusted_certificate, "");
+ ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
+
+- ngx_conf_merge_str_value(conf->ssl_certificate,
+- prev->ssl_certificate, "");
+- ngx_conf_merge_str_value(conf->ssl_certificate_key,
+- prev->ssl_certificate_key, "");
++ ngx_conf_merge_ptr_value(conf->ssl_certificates,
++ prev->ssl_certificates, NULL);
++ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
++ prev->ssl_certificate_keys, NULL);
++
+ ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
+
+ if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
+@@ -4284,6 +4287,7 @@ static ngx_int_t
+ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
+ {
+ ngx_pool_cleanup_t *cln;
++ ngx_str_t *oddkey;
+
+ plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+ if (plcf->upstream.ssl == NULL) {
+@@ -4306,18 +4310,43 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf,
ngx_http_proxy_loc_conf_t *plcf)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = plcf->upstream.ssl;
+
+- if (plcf->ssl_certificate.len) {
++ if (plcf->ssl_certificates && plcf->ssl_certificates->nelts > 0) {
++
++ if (!plcf->ssl_certificate_keys
++ || plcf->ssl_certificate_keys->nelts
++ < plcf->ssl_certificates->nelts)
++ {
++
++ oddkey = plcf->ssl_certificates->elts;
+
+- if (plcf->ssl_certificate_key.len == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"proxy_ssl_certificate_key\" is defined "
+- "for certificate \"%V\"", &plcf->ssl_certificate);
++ "for ssl certificate \"%V\"",
++ oddkey[(plcf->ssl_certificate_keys)
++ ? plcf->ssl_certificate_keys->nelts
++ : 0]);
++
+ return NGX_ERROR;
+ }
+
+- if (ngx_ssl_certificate(cf, plcf->upstream.ssl,
&plcf->ssl_certificate,
+- &plcf->ssl_certificate_key,
plcf->ssl_passwords)
+- != NGX_OK)
++#ifndef SSL_CTX_add0_chain_cert
++ if (plcf->ssl_certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificate configured "
++ "in \"proxy_ssl_certificate\", "
++ "but OpenSSL version < 1.0.2 used");
++ return NGX_ERROR;
++ }
++#endif
++
++ if (ngx_ssl_certificates(cf, plcf->upstream.ssl,
plcf->ssl_certificates,
++ plcf->ssl_certificate_keys,
++ plcf->ssl_passwords)
++ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+diff --git a/src/http/modules/ngx_http_ssl_module.c
b/src/http/modules/ngx_http_ssl_module.c
+index 6a4108c..6b7d34a 100644
+--- a/src/http/modules/ngx_http_ssl_module.c
++++ b/src/http/modules/ngx_http_ssl_module.c
+@@ -81,16 +81,16 @@ static ngx_command_t ngx_http_ssl_commands[] = {
+
+ { ngx_string("ssl_certificate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+- offsetof(ngx_http_ssl_srv_conf_t, certificate),
++ offsetof(ngx_http_ssl_srv_conf_t, certificates),
+ NULL },
+
+ { ngx_string("ssl_certificate_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+- offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
++ offsetof(ngx_http_ssl_srv_conf_t, certificate_keys),
+ NULL },
+
+ { ngx_string("ssl_password_file"),
+@@ -508,8 +508,6 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
+ * set by ngx_pcalloc():
+ *
+ * sscf->protocols = 0;
+- * sscf->certificate = { 0, NULL };
+- * sscf->certificate_key = { 0, NULL };
+ * sscf->dhparam = { 0, NULL };
+ * sscf->ecdh_curve = { 0, NULL };
+ * sscf->client_certificate = { 0, NULL };
+@@ -526,6 +524,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
+ sscf->buffer_size = NGX_CONF_UNSET_SIZE;
+ sscf->verify = NGX_CONF_UNSET_UINT;
+ sscf->verify_depth = NGX_CONF_UNSET_UINT;
++ sscf->certificates = NGX_CONF_UNSET_PTR;
++ sscf->certificate_keys = NGX_CONF_UNSET_PTR;
+ sscf->passwords = NGX_CONF_UNSET_PTR;
+ sscf->builtin_session_cache = NGX_CONF_UNSET;
+ sscf->session_timeout = NGX_CONF_UNSET;
+@@ -573,8 +573,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child)
+ ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
+
+- ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
+- ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
"");
++ ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
++ ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
++ NULL);
+
+ ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
+
+@@ -601,7 +602,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child)
+
+ if (conf->enable) {
+
+- if (conf->certificate.len == 0) {
++ if (!conf->certificates || conf->certificates->nelts == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate\" is defined for "
+ "the \"ssl\" directive in %s:%ui",
+@@ -609,7 +610,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child)
+ return NGX_CONF_ERROR;
+ }
+
+- if (conf->certificate_key.len == 0) {
++ if (!conf->certificate_keys || conf->certificate_keys->nelts == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined for "
+ "the \"ssl\" directive in %s:%ui",
+@@ -619,18 +620,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void
*parent, void *child)
+
+ } else {
+
+- if (conf->certificate.len == 0) {
++ if (!conf->certificates || conf->certificates->nelts == 0) {
+ return NGX_CONF_OK;
+ }
+
+- if (conf->certificate_key.len == 0) {
++ if (!conf->certificate_keys || conf->certificate_keys->nelts == 0) {
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "no \"ssl_certificate_key\" is defined "
++ "for certificate \"%V\"", &conf->certificates[0]);
++ return NGX_CONF_ERROR;
++ }
++ if (conf->certificate_keys->nelts < conf->certificates->nelts) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined "
+- "for certificate \"%V\"", &conf->certificate);
++ "for certificate \"%V\"",
++ &conf->certificates[conf->certificate_keys->nelts]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
++#ifndef SSL_CTX_add0_chain_cert
++ if (conf->certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificate configured in "
++ "\"ssl_certificate\", but OpenSSL < 1.0.2 used");
++ return NGX_CONF_ERROR;
++ }
++#endif
++
+ if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+@@ -666,8 +687,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = &conf->ssl;
+
+- if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
+- &conf->certificate_key, conf->passwords)
++ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
++ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+diff --git a/src/http/modules/ngx_http_ssl_module.h
b/src/http/modules/ngx_http_ssl_module.h
+index 8e69e9e..d4d1397 100644
+--- a/src/http/modules/ngx_http_ssl_module.h
++++ b/src/http/modules/ngx_http_ssl_module.h
+@@ -32,8 +32,8 @@ typedef struct {
+
+ time_t session_timeout;
+
+- ngx_str_t certificate;
+- ngx_str_t certificate_key;
++ ngx_array_t *certificates;
++ ngx_array_t *certificate_keys;
+ ngx_str_t dhparam;
+ ngx_str_t ecdh_curve;
+ ngx_str_t client_certificate;
+diff --git a/src/http/modules/ngx_http_uwsgi_module.c
b/src/http/modules/ngx_http_uwsgi_module.c
+index fef2c46..baf0a74 100644
+--- a/src/http/modules/ngx_http_uwsgi_module.c
++++ b/src/http/modules/ngx_http_uwsgi_module.c
+@@ -54,8 +54,8 @@ typedef struct {
+ ngx_uint_t ssl_verify_depth;
+ ngx_str_t ssl_trusted_certificate;
+ ngx_str_t ssl_crl;
+- ngx_str_t ssl_certificate;
+- ngx_str_t ssl_certificate_key;
++ ngx_array_t *ssl_certificates;
++ ngx_array_t *ssl_certificate_keys;
+ ngx_array_t *ssl_passwords;
+ #endif
+ } ngx_http_uwsgi_loc_conf_t;
+@@ -518,16 +518,16 @@ static ngx_command_t ngx_http_uwsgi_commands[] = {
+
+ { ngx_string("uwsgi_ssl_certificate"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate),
++ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificates),
+ NULL },
+
+ { ngx_string("uwsgi_ssl_certificate_key"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key),
++ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_keys),
+ NULL },
+
+ { ngx_string("uwsgi_ssl_password_file"),
+@@ -1432,6 +1432,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
+ conf->upstream.ssl_verify = NGX_CONF_UNSET;
+ conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
+ conf->ssl_passwords = NGX_CONF_UNSET_PTR;
++ conf->ssl_certificates = NGX_CONF_UNSET_PTR;
++ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
+ #endif
+
+ /* "uwsgi_cyclic_temp_file" is disabled */
+@@ -1745,11 +1747,10 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void
*parent, void *child)
+ ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
+ prev->ssl_trusted_certificate, "");
+ ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
+-
+- ngx_conf_merge_str_value(conf->ssl_certificate,
+- prev->ssl_certificate, "");
+- ngx_conf_merge_str_value(conf->ssl_certificate_key,
+- prev->ssl_certificate_key, "");
++ ngx_conf_merge_ptr_value(conf->ssl_certificates,
++ prev->ssl_certificates, NULL);
++ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
++ prev->ssl_certificate_keys, NULL);
+ ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
+
+ if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {
+@@ -2286,6 +2287,7 @@ static ngx_int_t
+ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
+ {
+ ngx_pool_cleanup_t *cln;
++ ngx_str_t *oddkey;
+
+ uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+ if (uwcf->upstream.ssl == NULL) {
+@@ -2308,17 +2310,42 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf,
ngx_http_uwsgi_loc_conf_t *uwcf)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = uwcf->upstream.ssl;
+
+- if (uwcf->ssl_certificate.len) {
++ if (uwcf->ssl_certificates && uwcf->ssl_certificates->nelts > 0) {
++
++ if (!uwcf->ssl_certificate_keys
++ || uwcf->ssl_certificate_keys->nelts
++ < uwcf->ssl_certificates->nelts)
++ {
++
++ oddkey = uwcf->ssl_certificates->elts;
+
+- if (uwcf->ssl_certificate_key.len == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"uwsgi_ssl_certificate_key\" is defined "
+- "for certificate \"%V\"", &uwcf->ssl_certificate);
++ "for ssl certificate \"%V\"",
++ oddkey[(uwcf->ssl_certificate_keys)
++ ? uwcf->ssl_certificate_keys->nelts
++ : 0]);
++
+ return NGX_ERROR;
+ }
+
+- if (ngx_ssl_certificate(cf, uwcf->upstream.ssl,
&uwcf->ssl_certificate,
+- &uwcf->ssl_certificate_key,
uwcf->ssl_passwords)
++#ifndef SSL_CTX_add0_chain_cert
++ if (uwcf->ssl_certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificate configured "
++ "in \"uwsgi_ssl_certificate\", but "
++ "OpenSSL < 1.0.2 used");
++ return NGX_ERROR;
++ }
++#endif
++
++ if (ngx_ssl_certificates(cf, uwcf->upstream.ssl,
uwcf->ssl_certificates,
++ uwcf->ssl_certificate_keys,
++ uwcf->ssl_passwords)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
+index ff5c141..137dd10 100644
+--- a/src/mail/ngx_mail_ssl_module.c
++++ b/src/mail/ngx_mail_ssl_module.c
+@@ -73,16 +73,16 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
+
+ { ngx_string("ssl_certificate"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+- offsetof(ngx_mail_ssl_conf_t, certificate),
++ offsetof(ngx_mail_ssl_conf_t, certificates),
+ NULL },
+
+ { ngx_string("ssl_certificate_key"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_MAIL_SRV_CONF_OFFSET,
+- offsetof(ngx_mail_ssl_conf_t, certificate_key),
++ offsetof(ngx_mail_ssl_conf_t, certificate_keys),
+ NULL },
+
+ { ngx_string("ssl_password_file"),
+@@ -238,8 +238,6 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
+ * set by ngx_pcalloc():
+ *
+ * scf->protocols = 0;
+- * scf->certificate = { 0, NULL };
+- * scf->certificate_key = { 0, NULL };
+ * scf->dhparam = { 0, NULL };
+ * scf->ecdh_curve = { 0, NULL };
+ * scf->client_certificate = { 0, NULL };
+@@ -250,6 +248,8 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
+ */
+
+ scf->enable = NGX_CONF_UNSET;
++ scf->certificates = NGX_CONF_UNSET_PTR;
++ scf->certificate_keys = NGX_CONF_UNSET_PTR;
+ scf->starttls = NGX_CONF_UNSET_UINT;
+ scf->passwords = NGX_CONF_UNSET_PTR;
+ scf->prefer_server_ciphers = NGX_CONF_UNSET;
+@@ -290,8 +290,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void
*child)
+ ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
+
+- ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
+- ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
"");
++ ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
++ ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
++ NULL);
+
+ ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
+
+@@ -328,7 +329,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void
*child)
+
+ if (*mode) {
+
+- if (conf->certificate.len == 0) {
++ if (!conf->certificates || conf->certificates->nelts == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate\" is defined for "
+ "the \"%s\" directive in %s:%ui",
+@@ -336,7 +337,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void
*child)
+ return NGX_CONF_ERROR;
+ }
+
+- if (conf->certificate_key.len == 0) {
++ if (!conf->certificate_keys || conf->certificate_keys->nelts == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined for "
+ "the \"%s\" directive in %s:%ui",
+@@ -344,17 +345,24 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child)
+ return NGX_CONF_ERROR;
+ }
+
++ if (conf->certificate_keys->nelts < conf->certificates->nelts) {
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "no \"ssl_certificate_key\" is defined "
++ "for certificate \"%V\"",
++ &conf->certificates[conf->certificate_keys->nelts]);
++ return NGX_CONF_ERROR;
++ }
++
+ } else {
+
+- if (conf->certificate.len == 0) {
++ if (!conf->certificates || conf->certificates->nelts == 0) {
+ return NGX_CONF_OK;
+ }
+
+- if (conf->certificate_key.len == 0) {
++ if (!conf->certificate_keys || conf->certificate_keys->nelts == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined "
+- "for certificate \"%V\"",
+- &conf->certificate);
++ "for certificate \"%V\"", &conf->certificates[0]);
+ return NGX_CONF_ERROR;
+ }
+ }
+@@ -371,8 +379,21 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = &conf->ssl;
+
+- if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
+- &conf->certificate_key, conf->passwords)
++#ifndef SSL_CTX_add0_chain_cert
++ if (conf->certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificate configured in "
++ "\"ssl_certificate\", but OpenSSL < 1.0.2 used");
++ return NGX_CONF_ERROR;
++ }
++#endif
++
++ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
++ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h
+index 296a6a2..0753e26 100644
+--- a/src/mail/ngx_mail_ssl_module.h
++++ b/src/mail/ngx_mail_ssl_module.h
+@@ -35,8 +35,8 @@ typedef struct {
+
+ time_t session_timeout;
+
+- ngx_str_t certificate;
+- ngx_str_t certificate_key;
++ ngx_array_t *certificates;
++ ngx_array_t *certificate_keys;
+ ngx_str_t dhparam;
+ ngx_str_t ecdh_curve;
+ ngx_str_t client_certificate;
diff --git a/debian/patches/1006-multicert-stream-modules.patch
b/debian/patches/1006-multicert-stream-modules.patch
new file mode 100644
index 0000000..d489c99
--- /dev/null
+++ b/debian/patches/1006-multicert-stream-modules.patch
@@ -0,0 +1,251 @@
+This is basically a cargo-culting of the changes in
+1005-multicert-modules.patch that makes very very similar changes to the
+stream_proxy and stream_ssl modules, which are newer than the nginx 1.8
+originally targeted by Filipe's patch set. --bblack
+
+diff --git a/src/stream/ngx_stream_proxy_module.c
b/src/stream/ngx_stream_proxy_module.c
+index 6c535fd..c2b7452 100644
+--- a/src/stream/ngx_stream_proxy_module.c
++++ b/src/stream/ngx_stream_proxy_module.c
+@@ -35,8 +35,8 @@ typedef struct {
+ ngx_uint_t ssl_verify_depth;
+ ngx_str_t ssl_trusted_certificate;
+ ngx_str_t ssl_crl;
+- ngx_str_t ssl_certificate;
+- ngx_str_t ssl_certificate_key;
++ ngx_array_t *ssl_certificates;
++ ngx_array_t *ssl_certificate_keys;
+ ngx_array_t *ssl_passwords;
+
+ ngx_ssl_t *ssl;
+@@ -277,16 +277,16 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
+
+ { ngx_string("proxy_ssl_certificate"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+- offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate),
++ offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificates),
+ NULL },
+
+ { ngx_string("proxy_ssl_certificate_key"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+- offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key),
++ offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_keys),
+ NULL },
+
+ { ngx_string("proxy_ssl_password_file"),
+@@ -1405,8 +1405,6 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
+ * conf->ssl_name = { 0, NULL };
+ * conf->ssl_trusted_certificate = { 0, NULL };
+ * conf->ssl_crl = { 0, NULL };
+- * conf->ssl_certificate = { 0, NULL };
+- * conf->ssl_certificate_key = { 0, NULL };
+ *
+ * conf->ssl = NULL;
+ * conf->upstream = NULL;
+@@ -1430,6 +1428,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
+ conf->ssl_server_name = NGX_CONF_UNSET;
+ conf->ssl_verify = NGX_CONF_UNSET;
+ conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
++ conf->ssl_certificates = NGX_CONF_UNSET_PTR;
++ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
+ conf->ssl_passwords = NGX_CONF_UNSET_PTR;
+ #endif
+
+@@ -1500,11 +1500,11 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void
*parent, void *child)
+
+ ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
+
+- ngx_conf_merge_str_value(conf->ssl_certificate,
+- prev->ssl_certificate, "");
++ ngx_conf_merge_ptr_value(conf->ssl_certificates,
++ prev->ssl_certificates, NULL);
+
+- ngx_conf_merge_str_value(conf->ssl_certificate_key,
+- prev->ssl_certificate_key, "");
++ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
++ prev->ssl_certificate_keys, NULL);
+
+ ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
+
+@@ -1524,6 +1524,7 @@ static ngx_int_t
+ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf)
+ {
+ ngx_pool_cleanup_t *cln;
++ ngx_str_t *oddkey;
+
+ pscf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
+ if (pscf->ssl == NULL) {
+@@ -1544,17 +1545,41 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf,
ngx_stream_proxy_srv_conf_t *pscf)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = pscf->ssl;
+
+- if (pscf->ssl_certificate.len) {
++ if (pscf->ssl_certificates && pscf->ssl_certificates->nelts > 0) {
++
++ if (!pscf->ssl_certificate_keys
++ || pscf->ssl_certificate_keys->nelts
++ < pscf->ssl_certificates->nelts)
++ {
++
++ oddkey = pscf->ssl_certificates->elts;
+
+- if (pscf->ssl_certificate_key.len == 0) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"proxy_ssl_certificate_key\" is defined "
+- "for certificate \"%V\"", &pscf->ssl_certificate);
++ "for ssl certificate \"%V\"",
++ oddkey[(pscf->ssl_certificate_keys)
++ ? pscf->ssl_certificate_keys->nelts
++ : 0]);
+ return NGX_ERROR;
+ }
+
+- if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate,
+- &pscf->ssl_certificate_key,
pscf->ssl_passwords)
++#ifndef SSL_CTX_add0_chain_cert
++ if (pscf->ssl_certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificates configured "
++ "in \"proxy_ssl_certificates\", "
++ "but OpenSSL version < 1.0.2 used");
++ return NGX_ERROR;
++ }
++#endif
++
++ if (ngx_ssl_certificates(cf, pscf->ssl, pscf->ssl_certificates,
++ pscf->ssl_certificate_keys,
++ pscf->ssl_passwords)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+diff --git a/src/stream/ngx_stream_ssl_module.c
b/src/stream/ngx_stream_ssl_module.c
+index e12da1b..360db17 100644
+--- a/src/stream/ngx_stream_ssl_module.c
++++ b/src/stream/ngx_stream_ssl_module.c
+@@ -45,16 +45,16 @@ static ngx_command_t ngx_stream_ssl_commands[] = {
+
+ { ngx_string("ssl_certificate"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+- offsetof(ngx_stream_ssl_conf_t, certificate),
++ offsetof(ngx_stream_ssl_conf_t, certificates),
+ NULL },
+
+ { ngx_string("ssl_certificate_key"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+- ngx_conf_set_str_slot,
++ ngx_conf_set_str_array_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+- offsetof(ngx_stream_ssl_conf_t, certificate_key),
++ offsetof(ngx_stream_ssl_conf_t, certificate_keys),
+ NULL },
+
+ { ngx_string("ssl_password_file"),
+@@ -175,8 +175,6 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf)
+ * set by ngx_pcalloc():
+ *
+ * scf->protocols = 0;
+- * scf->certificate = { 0, NULL };
+- * scf->certificate_key = { 0, NULL };
+ * scf->dhparam = { 0, NULL };
+ * scf->ecdh_curve = { 0, NULL };
+ * scf->ciphers = { 0, NULL };
+@@ -184,6 +182,8 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf)
+ */
+
+ scf->handshake_timeout = NGX_CONF_UNSET_MSEC;
++ scf->certificates = NGX_CONF_UNSET_PTR;
++ scf->certificate_keys = NGX_CONF_UNSET_PTR;
+ scf->passwords = NGX_CONF_UNSET_PTR;
+ scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ scf->builtin_session_cache = NGX_CONF_UNSET;
+@@ -216,8 +216,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child)
+ (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
+ |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+
+- ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
+- ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
"");
++ ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
++ ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
++ NULL);
+
+ ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
+
+@@ -231,17 +232,36 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child)
+
+ conf->ssl.log = cf->log;
+
+- if (conf->certificate.len == 0) {
++ if (!conf->certificates || conf->certificates->nelts == 0) {
+ return NGX_CONF_OK;
+ }
+
+- if (conf->certificate_key.len == 0) {
++ if (!conf->certificate_keys || conf->certificate_keys->nelts == 0) {
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "no \"ssl_certificate_key\" is defined "
++ "for certificate \"%V\"", &conf->certificates[0]);
++ return NGX_CONF_ERROR;
++ }
++ if (conf->certificate_keys->nelts < conf->certificates->nelts) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined "
+ "for certificate \"%V\"",
+- &conf->certificate);
++ &conf->certificates[conf->certificate_keys->nelts]);
++ return NGX_CONF_ERROR;
++ }
++
++#ifndef SSL_CTX_add0_chain_cert
++ if (conf->certificates->nelts > 1) {
++ /*
++ * no multiple certificates support for OpenSSL < 1.0.2,
++ * so we need to alarm user
++ */
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "Multiple certificate configured in "
++ "\"ssl_certificate\", but OpenSSL < 1.0.2 used");
+ return NGX_CONF_ERROR;
+ }
++#endif
+
+ if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
+ return NGX_CONF_ERROR;
+@@ -255,8 +275,8 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child)
+ cln->handler = ngx_ssl_cleanup_ctx;
+ cln->data = &conf->ssl;
+
+- if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
+- &conf->certificate_key, conf->passwords)
++ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
++ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+diff --git a/src/stream/ngx_stream_ssl_module.h
b/src/stream/ngx_stream_ssl_module.h
+index 85e8b6e..331341f 100644
+--- a/src/stream/ngx_stream_ssl_module.h
++++ b/src/stream/ngx_stream_ssl_module.h
+@@ -27,8 +27,8 @@ typedef struct {
+
+ time_t session_timeout;
+
+- ngx_str_t certificate;
+- ngx_str_t certificate_key;
++ ngx_array_t *certificates;
++ ngx_array_t *certificate_keys;
+ ngx_str_t dhparam;
+ ngx_str_t ecdh_curve;
+
diff --git a/debian/patches/series b/debian/patches/series
index 04b971f..250ff54 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,12 @@
perl-use-dpkg-buildflags.patch
0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch
+# 1001-1005 is forward ports of multi-cert patches from Filipe da Silva
+# circa 2015-04-27, onto nginx-1.9.14, from the 5 posts starting here:
+# http://mailman.nginx.org/pipermail/nginx-devel/2015-April/006863.html
+1001-openssl102.patch
+1002-stapling-per-cert.patch
+1003-stapling-multi-cert.patch
+1004-cert-list.patch
+1005-multicert-modules.patch
+# 1006 is a local cargo-cult of 1005's changes into the newer stream modules
+1006-multicert-stream-modules.patch
--
To view, visit https://gerrit.wikimedia.org/r/286506
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ida2b3deffc97ef40704a32581e824723267df700
Gerrit-PatchSet: 1
Gerrit-Project: operations/software/nginx
Gerrit-Branch: wmf-1.10.0-1
Gerrit-Owner: BBlack <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits