BBlack has uploaded a new change for review. https://gerrit.wikimedia.org/r/235739
Change subject: multicert + libssl1.0.2 diffs rebased onto 1.9.4-1 ...................................................................... multicert + libssl1.0.2 diffs rebased onto 1.9.4-1 Change-Id: I67b67af2280c94c15cd1d74696672d674a2d3e6c --- 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/39/235739/1 diff --git a/debian/control b/debian/control index b3bfcc3..1548aef 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..e78e7d3 --- /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 1b789e6..982ef24 100644 +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -168,6 +168,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) { +@@ -175,7 +176,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) { +@@ -183,6 +186,7 @@ ngx_ssl_init(ngx_log_t *log) + "SSL_CTX_get_ex_new_index() failed"); + return NGX_ERROR; + } ++#endif + + return NGX_OK; + } +@@ -297,6 +301,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) +@@ -340,6 +371,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) + { +@@ -349,6 +381,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); + +@@ -376,10 +409,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; +@@ -2150,7 +2194,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 08eff64..d7d0381 100644 +--- a/src/event/ngx_event_openssl.h ++++ b/src/event/ngx_event_openssl.h +@@ -189,6 +189,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); +@@ -208,7 +210,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 fa77678..a4f5679 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; +@@ -538,6 +540,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; +@@ -593,15 +596,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..f993b18 --- /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 982ef24..0dbb203 100644 +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -103,6 +103,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 +@@ -186,6 +187,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 d7d0381..21e40ec 100644 +--- a/src/event/ngx_event_openssl.h ++++ b/src/event/ngx_event_openssl.h +@@ -211,6 +211,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 a4f5679..16ddf18 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 +@@ -354,9 +375,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) { + +@@ -441,7 +464,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); + +@@ -455,45 +478,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; + +@@ -517,10 +553,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; +@@ -604,7 +640,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..cccd037 --- /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 16ddf18..91573aa 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; +@@ -370,22 +376,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..f302ca6 --- /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 0dbb203..867bd4f 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); +@@ -338,14 +342,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; +@@ -441,6 +470,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 +@@ -2205,18 +2245,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 21e40ec..96517af 100644 +--- a/src/event/ngx_event_openssl.h ++++ b/src/event/ngx_event_openssl.h +@@ -122,8 +122,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..869e285 --- /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 514c23b..305ad41 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; +@@ -672,16 +672,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"), +@@ -2858,6 +2858,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 */ +@@ -3188,10 +3190,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) { +@@ -4278,6 +4281,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) { +@@ -4300,18 +4304,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 d6a1794..35b6de7 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"), +@@ -505,8 +505,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 }; +@@ -523,6 +521,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; +@@ -570,8 +570,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); + +@@ -598,7 +599,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", +@@ -606,7 +607,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", +@@ -616,18 +617,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; + } +@@ -663,8 +684,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 a50c553..e37f5f2 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; +@@ -517,16 +517,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"), +@@ -1430,6 +1430,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 */ +@@ -1743,11 +1745,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) { +@@ -2284,6 +2285,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) { +@@ -2306,17 +2308,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 1075410..ebe4ac8 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..1d16a41 --- /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 68af5a8..93106b5 100644 +--- a/src/stream/ngx_stream_proxy_module.c ++++ b/src/stream/ngx_stream_proxy_module.c +@@ -37,8 +37,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; +@@ -272,16 +272,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"), +@@ -1319,8 +1319,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; +@@ -1343,6 +1341,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 + +@@ -1410,11 +1410,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); + +@@ -1434,6 +1434,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) { +@@ -1454,17 +1455,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 7abd9e1..216cb40 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 73f535e..c447936 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,11 @@ perl-use-dpkg-buildflags.patch +# 1001-1005 is forward ports of multi-cert patches from Filipe da Silva +# circa 2015-04-27, onto nginx-1.9.4, 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/235739 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I67b67af2280c94c15cd1d74696672d674a2d3e6c Gerrit-PatchSet: 1 Gerrit-Project: operations/software/nginx Gerrit-Branch: wmf-1.9.4-1 Gerrit-Owner: BBlack <bbl...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits