<div dir="ltr"><div><div>Sure it should be tested (there are can be some memory leaks).<br></div>Need to know if it's idologically acceptable.<br><br></div>Nginx with dual cert support can be tested at <a href="https://ctftime.org">https://ctftime.org</a>.<br><div><div><div><div><br>Patch in body inline:<br># HG changeset patch<br># User Eldar Zaitov <<a href="mailto:eldar@kyprizel.net">eldar@kyprizel.net</a>><br># Date 1426616118 -10800<br># Node ID 83b0f57fbcb514ffd74bb89070580473bacd286e<br># Parent e370c5fdf4c8edc2e8d33d7170c1b1cc74a2ecb6<br>Multiple SSL certificate support with OpenSSL >= 1.0.2<br><br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.c<br>--- a/src/event/ngx_event_openssl.c Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/event/ngx_event_openssl.c Tue Mar 17 21:15:18 2015 +0300<br>@@ -286,198 +286,282 @@<br> <br> <br> ngx_int_t<br>-ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,<br>- ngx_str_t *key, ngx_array_t *passwords)<br>+ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,<br>+ ngx_array_t *keys, ngx_array_t *passwords)<br> {<br>- BIO *bio;<br>- X509 *x509;<br>- u_long n;<br>- ngx_str_t *pwd;<br>- ngx_uint_t tries;<br>-<br>- if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {<br>+ ngx_str_t *pwd;<br>+ ngx_uint_t tries;<br>+ ngx_str_t *cert;<br>+ ngx_str_t *key;<br>+ ngx_uint_t i, j;<br>+ u_long n;<br>+ BIO *bio;<br>+ EVP_PKEY *pkey;<br>+ X509 *x509;<br>+ X509 *x509_ca;<br>+ STACK_OF(X509) *chain;<br>+ ngx_array_t *certificates;<br>+ ngx_ssl_certificate_t *cert_info;<br>+<br>+ bio = NULL;<br>+ pkey = NULL;<br>+ x509 = NULL;<br>+ x509_ca = NULL;<br>+<br>+ cert = certs->elts;<br>+ key = keys->elts;<br>+<br>+ certificates = ngx_array_create(cf->pool, certs->nelts,<br>+ sizeof(ngx_ssl_certificate_t));<br>+ if (certificates == NULL) {<br> return NGX_ERROR;<br> }<br> <br>- /*<br>- * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't<br>- * allow to access certificate later from SSL_CTX, so we reimplement<br>- * it here<br>- */<br>-<br>- bio = BIO_new_file((char *) cert->data, "r");<br>- if (bio == NULL) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "BIO_new_file(\"%s\") failed", cert->data);<br>- return NGX_ERROR;<br>- }<br>-<br>- x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);<br>- if (x509 == NULL) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);<br>- BIO_free(bio);<br>- return NGX_ERROR;<br>- }<br>-<br>- if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "SSL_CTX_use_certificate(\"%s\") failed", cert->data);<br>- X509_free(x509);<br>- BIO_free(bio);<br>- return NGX_ERROR;<br>- }<br>-<br>- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)<br>- == 0)<br>- {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "SSL_CTX_set_ex_data() failed");<br>- X509_free(x509);<br>- BIO_free(bio);<br>- return NGX_ERROR;<br>- }<br>-<br>- X509_free(x509);<br>-<br>- /* read rest of the chain */<br>-<br>- for ( ;; ) {<br>-<br>- x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);<br>+ for (i = 0; i < certs->nelts; i++) {<br>+<br>+ /* load server certificate */<br>+<br>+ if (ngx_conf_full_name(cf->cycle, &cert[i], 1) != NGX_OK) {<br>+ goto failed;<br>+ }<br>+<br>+ /*<br>+ * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't<br>+ * allow to access certificate later from SSL_CTX, so we reimplement<br>+ * it here<br>+ */<br>+<br>+ bio = BIO_new_file((char *) cert[i].data, "r");<br>+ if (bio == NULL) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "BIO_new_file(\"%V\") failed", &cert[i]);<br>+ goto failed;<br>+ }<br>+<br>+ x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);<br> if (x509 == NULL) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "PEM_read_bio_X509_AUX(\"%V\") failed", &cert[i]);<br>+ goto failed;<br>+ }<br>+<br>+ if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "SSL_CTX_use_certificate(\"%V\") failed", &cert[i]);<br>+ goto failed;<br>+ }<br>+<br>+<br>+ /* read rest of the chain */<br>+<br>+ for (j = 0; ; j++) {<br>+<br>+ x509_ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);<br> n = ERR_peek_last_error();<br> <br>- if (ERR_GET_LIB(n) == ERR_LIB_PEM<br>- && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)<br>- {<br>- /* end of file */<br>- ERR_clear_error();<br>+ if (x509_ca == NULL) {<br>+<br>+ if (ERR_GET_LIB(n) == ERR_LIB_PEM<br>+ && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)<br>+ {<br>+ /* end of file */<br>+ ERR_clear_error();<br>+ break;<br>+ }<br>+<br>+ /* some real error */<br>+<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "PEM_read_bio_X509(\"%V\") failed", &cert[i]);<br>+ goto failed;<br>+ }<br>+<br>+#ifdef SSL_CTX_add0_chain_cert<br>+ /* OpenSSL >=1.0.2 allows multiple server certificates in a single<br>+ * SSL_CTX to each have a different chain<br>+ */<br>+ if (SSL_CTX_add0_chain_cert(ssl->ctx, x509_ca) == 0) {<br>+<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "SSL_CTX_add0_chain_cert(\"%V\") failed",<br>+ &cert[i]);<br>+ goto failed;<br>+ }<br>+#else<br>+ if (i == 0) {<br>+ if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509_ca) == 0) {<br>+<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "SSL_CTX_add_extra_chain_cert() failed");<br>+ goto failed;<br>+ }<br> break;<br> }<br>-<br>- /* some real error */<br>+#endif<br>+<br>+ }<br>+<br>+ BIO_free(bio);<br>+ bio = NULL;<br>+<br>+<br>+ /* load private key */<br>+<br>+ if (ngx_strncmp(key[i].data, "engine:", sizeof("engine:") - 1) == 0) {<br>+#ifndef OPENSSL_NO_ENGINE<br>+<br>+ u_char *p, *last;<br>+ ENGINE *engine;<br>+<br>+ p = key[i].data + sizeof("engine:") - 1;<br>+ last = (u_char *) ngx_strchr(p, ':');<br>+<br>+ if (last == NULL) {<br>+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>+ "invalid syntax in \"%V\"", &(key[i]));<br>+ goto failed;<br>+ }<br>+<br>+<br>+ *last = '\0';<br>+<br>+ engine = ENGINE_by_id((char *) p);<br>+<br>+ if (engine == NULL) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "ENGINE_by_id(\"%s\") failed", p);<br>+ goto failed;<br>+ }<br>+<br>+ *last++ = ':';<br>+<br>+ pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);<br>+<br>+ if (pkey == NULL) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "ENGINE_load_private_key(\"%s\") failed", last);<br>+ ENGINE_free(engine);<br>+ goto failed;<br>+ }<br>+<br>+ ENGINE_free(engine);<br>+<br>+ if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "SSL_CTX_use_PrivateKey(\"%s\") failed", last);<br>+ goto failed;<br>+ }<br>+<br>+ EVP_PKEY_free(pkey);<br>+ pkey = NULL;<br>+<br>+ continue;<br>+#else<br>+<br>+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>+ "loading \"engine:...\" certificate keys "<br>+ "is not supported");<br>+ goto failed;<br>+<br>+#endif<br>+ }<br>+<br>+ if (ngx_conf_full_name(cf->cycle, &key[i], 1) != NGX_OK) {<br>+ goto failed;<br>+ }<br>+<br>+ if (passwords) {<br>+ tries = passwords->nelts;<br>+ pwd = passwords->elts;<br>+<br>+ SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);<br>+ SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);<br>+ } else {<br>+ tries = 1;<br>+#if (NGX_SUPPRESS_WARN)<br>+ pwd = NULL;<br>+#endif<br>+ }<br>+<br>+<br>+ for ( ;; ) {<br>+ if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key[i].data,<br>+ SSL_FILETYPE_PEM)<br>+ != 0)<br>+ {<br>+ break;<br>+ }<br>+<br>+ if (--tries) {<br>+ ERR_clear_error();<br>+ SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);<br>+ continue;<br>+ }<br> <br> ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "PEM_read_bio_X509(\"%s\") failed", cert->data);<br>- BIO_free(bio);<br>- return NGX_ERROR;<br>+ "SSL_CTX_use_PrivateKey_file(\"%s\") failed",<br>+ key[i].data);<br>+ goto failed;<br> }<br> <br>- if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {<br>+ if (SSL_CTX_check_private_key(ssl->ctx) < 1) {<br> ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "SSL_CTX_add_extra_chain_cert(\"%s\") failed",<br>- cert->data);<br>- X509_free(x509);<br>- BIO_free(bio);<br>- return NGX_ERROR;<br>+ "PrivateKey \"%V\" does not match \"%V\" failed",<br>+ &key[i], &cert[i]);<br>+ goto failed;<br> }<br>- }<br>-<br>- BIO_free(bio);<br>-<br>- if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {<br>-<br>-#ifndef OPENSSL_NO_ENGINE<br>-<br>- u_char *p, *last;<br>- ENGINE *engine;<br>- EVP_PKEY *pkey;<br>-<br>- p = key->data + sizeof("engine:") - 1;<br>- last = (u_char *) ngx_strchr(p, ':');<br>-<br>- if (last == NULL) {<br>- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>- "invalid syntax in \"%V\"", key);<br>- return NGX_ERROR;<br>+<br>+ SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);<br>+<br>+<br>+#ifdef SSL_CTX_get0_chain_certs<br>+ SSL_CTX_get0_chain_certs(ssl->ctx, &chain);<br>+#else<br>+#if OPENSSL_VERSION_NUMBER >= 0x10001000L<br>+ SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);<br>+#else<br>+ chain = ssl->ctx->extra_certs;<br>+#endif<br>+#endif<br>+<br>+ cert_info = ngx_array_push(certificates);<br>+ if (cert_info == NULL) {<br>+ goto failed;<br> }<br> <br>- *last = '\0';<br>-<br>- engine = ENGINE_by_id((char *) p);<br>-<br>- if (engine == NULL) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "ENGINE_by_id(\"%s\") failed", p);<br>- return NGX_ERROR;<br>- }<br>-<br>- *last++ = ':';<br>-<br>- pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);<br>-<br>- if (pkey == NULL) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "ENGINE_load_private_key(\"%s\") failed", last);<br>- ENGINE_free(engine);<br>- return NGX_ERROR;<br>- }<br>-<br>- ENGINE_free(engine);<br>-<br>- if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "SSL_CTX_use_PrivateKey(\"%s\") failed", last);<br>- EVP_PKEY_free(pkey);<br>- return NGX_ERROR;<br>- }<br>-<br>+ cert_info->issuer = NULL;<br>+ cert_info->cert = x509;<br>+ CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);<br>+<br>+ cert_info->chain = chain;<br>+<br>+<br>+ }<br>+<br>+ /* store cert info for future use in stapling and sessions */<br>+<br>+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, certificates)<br>+ == 0)<br>+ {<br>+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>+ "SSL_CTX_set_ex_data() failed");<br>+ goto failed;<br>+ }<br>+<br>+ return NGX_OK;<br>+<br>+failed:<br>+<br>+ if (bio)<br>+ BIO_free(bio);<br>+ if (pkey)<br> EVP_PKEY_free(pkey);<br>-<br>- return NGX_OK;<br>-<br>-#else<br>-<br>- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<br>- "loading \"engine:...\" certificate keys "<br>- "is not supported");<br>- return NGX_ERROR;<br>-<br>-#endif<br>- }<br>-<br>- if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {<br>- return NGX_ERROR;<br>- }<br>-<br>- if (passwords) {<br>- tries = passwords->nelts;<br>- pwd = passwords->elts;<br>-<br>- SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);<br>- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);<br>-<br>- } else {<br>- tries = 1;<br>-#if (NGX_SUPPRESS_WARN)<br>- pwd = NULL;<br>-#endif<br>- }<br>-<br>- for ( ;; ) {<br>-<br>- if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,<br>- SSL_FILETYPE_PEM)<br>- != 0)<br>- {<br>- break;<br>- }<br>-<br>- if (--tries) {<br>- ERR_clear_error();<br>- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);<br>- continue;<br>- }<br>-<br>- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>- "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);<br>- return NGX_ERROR;<br>- }<br>-<br>- SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);<br>-<br>- return NGX_OK;<br>+ if (x509)<br>+ X509_free(x509);<br>+ if (x509_ca)<br>+ X509_free(x509_ca);<br>+<br>+ return NGX_ERROR;<br> }<br> <br> <br>@@ -2111,13 +2195,14 @@<br> static ngx_int_t<br> ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)<br> {<br>- int n, i;<br>- X509 *cert;<br>- X509_NAME *name;<br>- EVP_MD_CTX md;<br>- unsigned int len;<br>- STACK_OF(X509_NAME) *list;<br>- u_char buf[EVP_MAX_MD_SIZE];<br>+ int n, i;<br>+ X509_NAME *name;<br>+ EVP_MD_CTX md;<br>+ unsigned int len;<br>+ STACK_OF(X509_NAME) *list;<br>+ u_char buf[EVP_MAX_MD_SIZE];<br>+ ngx_array_t *certs;<br>+ ngx_ssl_certificate_t *cert_info;<br> <br> /*<br> * Session ID context is set based on the string provided,<br>@@ -2138,9 +2223,14 @@<br> goto failed;<br> }<br> <br>- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);<br>-<br>- if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {<br>+ certs = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);<br>+ if (!certs || certs->nelts == 0) {<br>+ goto failed;<br>+ }<br>+<br>+ cert_info = certs->elts;<br>+<br>+ if (X509_digest((&cert_info[0])->cert, EVP_sha1(), buf, &len) == 0) {<br> ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br> "X509_digest() failed");<br> goto failed;<br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.h<br>--- a/src/event/ngx_event_openssl.h Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/event/ngx_event_openssl.h Tue Mar 17 21:15:18 2015 +0300<br>@@ -45,6 +45,13 @@<br> <br> <br> typedef struct {<br>+ X509 *cert;<br>+ X509 *issuer;<br>+ STACK_OF(X509) *chain;<br>+} ngx_ssl_certificate_t;<br>+<br>+<br>+typedef struct {<br> ngx_ssl_conn_t *connection;<br> <br> ngx_int_t last;<br>@@ -122,15 +129,15 @@<br> <br> ngx_int_t ngx_ssl_init(ngx_log_t *log);<br> ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);<br>-ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>- ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);<br>+ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>+ ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords);<br> ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,<br> ngx_str_t *cert, ngx_int_t depth);<br> ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,<br> ngx_str_t *cert, ngx_int_t depth);<br> ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);<br> ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>- ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);<br>+ ngx_array_t *files, ngx_array_t *responders, ngx_uint_t verify);<br> ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,<br> ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);<br> RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,<br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl_stapling.c<br>--- a/src/event/ngx_event_openssl_stapling.c Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/event/ngx_event_openssl_stapling.c Tue Mar 17 21:15:18 2015 +0300<br>@@ -28,8 +28,7 @@<br> <br> SSL_CTX *ssl_ctx;<br> <br>- X509 *cert;<br>- X509 *issuer;<br>+ ngx_ssl_certificate_t *cert_info;<br> <br> time_t valid;<br> <br>@@ -83,10 +82,11 @@<br> <br> <br> static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>- ngx_str_t *file);<br>-static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);<br>+ ngx_ssl_stapling_t *staple, ngx_str_t *file);<br>+static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>+ ngx_ssl_stapling_t *staple);<br> static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>- ngx_str_t *responder);<br>+ ngx_ssl_stapling_t *staple, ngx_str_t *responder);<br> <br> static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,<br> void *data);<br>@@ -115,15 +115,29 @@<br> <br> <br> ngx_int_t<br>-ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,<br>- ngx_str_t *responder, ngx_uint_t verify)<br>+ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,<br>+ ngx_array_t *responders, ngx_uint_t verify)<br> {<br>- ngx_int_t rc;<br>- ngx_pool_cleanup_t *cln;<br>- ngx_ssl_stapling_t *staple;<br>+ ngx_uint_t i;<br>+ ngx_array_t *staples;<br>+ ngx_array_t *certificates;<br>+ ngx_pool_cleanup_t *cln;<br>+ ngx_str_t *responder, *file;<br>+ ngx_str_t empty_responder = ngx_null_string;<br>+ ngx_ssl_stapling_t *staple;<br>+ ngx_ssl_certificate_t *cert_info;<br> <br>- staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));<br>- if (staple == NULL) {<br>+ responder = NULL;<br>+ file = NULL;<br>+<br>+ certificates = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);<br>+ if (certificates == NULL || (certificates->nelts == 0)) {<br>+ return NGX_ERROR;<br>+ }<br>+<br>+ staples = ngx_array_create(cf->pool, certificates->nelts,<br>+ sizeof(ngx_ssl_stapling_t));<br>+ if (staples == NULL) {<br> return NGX_ERROR;<br> }<br> <br>@@ -133,9 +147,66 @@<br> }<br> <br> cln->handler = ngx_ssl_stapling_cleanup;<br>- cln->data = staple;<br>+ cln->data = staples;<br> <br>- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)<br>+<br>+ cert_info = certificates->elts;<br>+ staple = staples->elts;<br>+<br>+ if (responders)<br>+ responder = responders->elts;<br>+<br>+ if (files)<br>+ file = files->elts;<br>+<br>+ for (i = 0; i < certificates->nelts; i++) {<br>+<br>+ staple = ngx_array_push(staples);<br>+ staple->timeout = 60000;<br>+ staple->ssl_ctx = ssl->ctx;<br>+ CRYPTO_add(&ssl->ctx->references, 1, CRYPTO_LOCK_X509);<br>+<br>+ staple->cert_info = &cert_info[i];<br>+ if (ngx_ssl_stapling_issuer(cf, ssl, staple) == NGX_ERROR) {<br>+ return NGX_ERROR;<br>+ }<br>+ staple->verify = verify;<br>+<br>+ if (responder && responders->nelts > i) {<br>+<br>+ if (ngx_ssl_stapling_responder(cf, ssl, staple, &responder[i])<br>+ != NGX_OK)<br>+ {<br>+ return NGX_ERROR;<br>+ }<br>+<br>+ } else {<br>+<br>+ if (ngx_ssl_stapling_responder(cf, ssl, staple, &empty_responder)<br>+ == NGX_ERROR)<br>+ {<br>+ return NGX_ERROR;<br>+ }<br>+ empty_responder.len = 0;<br>+ empty_responder.data = NULL;<br>+<br>+ }<br>+<br>+ if (!file || files->nelts <= i)<br>+ continue;<br>+<br>+ if (file[i].len) {<br>+<br>+ /* use OCSP response from the file */<br>+<br>+ if (ngx_ssl_stapling_file(cf, ssl, staple, &file[i]) != NGX_OK) {<br>+ return NGX_ERROR;<br>+ }<br>+ }<br>+ }<br>+<br>+<br>+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staples)<br> == 0)<br> {<br> ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,<br>@@ -143,59 +214,21 @@<br> return NGX_ERROR;<br> }<br> <br>- staple->ssl_ctx = ssl->ctx;<br>- staple->timeout = 60000;<br>- staple->verify = verify;<br>-<br>- if (file->len) {<br>- /* use OCSP response from the file */<br>-<br>- if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {<br>- return NGX_ERROR;<br>- }<br>-<br>- goto done;<br>- }<br>-<br>- rc = ngx_ssl_stapling_issuer(cf, ssl);<br>-<br>- if (rc == NGX_DECLINED) {<br>- return NGX_OK;<br>- }<br>-<br>- if (rc != NGX_OK) {<br>- return NGX_ERROR;<br>- }<br>-<br>- rc = ngx_ssl_stapling_responder(cf, ssl, responder);<br>-<br>- if (rc == NGX_DECLINED) {<br>- return NGX_OK;<br>- }<br>-<br>- if (rc != NGX_OK) {<br>- return NGX_ERROR;<br>- }<br>-<br>-done:<br>-<br> SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback);<br>- SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple);<br>+ SSL_CTX_set_tlsext_status_arg(ssl->ctx, staples);<br> <br> return NGX_OK;<br> }<br> <br> <br> static ngx_int_t<br>-ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)<br>+ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>+ ngx_ssl_stapling_t *staple, ngx_str_t *file)<br> {<br> BIO *bio;<br> int len;<br> u_char *p, *buf;<br> OCSP_RESPONSE *response;<br>- ngx_ssl_stapling_t *staple;<br>-<br>- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);<br> <br> if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {<br> return NGX_ERROR;<br>@@ -255,23 +288,32 @@<br> <br> <br> static ngx_int_t<br>-ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)<br>+ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>+ ngx_ssl_stapling_t *staple)<br> {<br>- int i, n, rc;<br>- X509 *cert, *issuer;<br>- X509_STORE *store;<br>- X509_STORE_CTX *store_ctx;<br>- STACK_OF(X509) *chain;<br>- ngx_ssl_stapling_t *staple;<br>+ int i, n, rc;<br>+ X509 *issuer;<br>+ X509_STORE *store;<br>+ X509_STORE_CTX *store_ctx;<br>+ ngx_ssl_certificate_t *cert_info = staple->cert_info;<br>+ X509 *cert;<br>+ STACK_OF(X509) *chain;<br> <br>- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);<br>- cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);<br> <br>-#if OPENSSL_VERSION_NUMBER >= 0x10001000L<br>- SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);<br>-#else<br>- chain = ssl->ctx->extra_certs;<br>-#endif<br>+ if (!cert_info || !cert_info->cert) {<br>+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,<br>+ "\"ssl_stapling\" ignored, no certificate info found");<br>+ return NGX_ERROR;<br>+ }<br>+<br>+ if (!cert_info->chain) {<br>+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,<br>+ "\"ssl_stapling\" ignored, no certificate chain found");<br>+ return NGX_ERROR;<br>+ }<br>+<br>+ cert = cert_info->cert;<br>+ chain = cert_info->chain;<br> <br> n = sk_X509_num(chain);<br> <br>@@ -286,8 +328,7 @@<br> ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,<br> "SSL get issuer: found %p in extra certs", issuer);<br> <br>- staple->cert = cert;<br>- staple->issuer = issuer;<br>+ cert_info->issuer = issuer;<br> <br> return NGX_OK;<br> }<br>@@ -334,28 +375,25 @@<br> ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,<br> "SSL get issuer: found %p in cert store", issuer);<br> <br>- staple->cert = cert;<br>- staple->issuer = issuer;<br>+ cert_info->issuer = issuer;<br> <br> return NGX_OK;<br> }<br> <br> <br> static ngx_int_t<br>-ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder)<br>+ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,<br>+ ngx_ssl_stapling_t *staple, ngx_str_t *responder)<br> {<br> ngx_url_t u;<br> char *s;<br>- ngx_ssl_stapling_t *staple;<br> STACK_OF(OPENSSL_STRING) *aia;<br> <br>- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);<br>-<br> if (responder->len == 0) {<br> <br> /* extract OCSP responder URL from certificate */<br> <br>- aia = X509_get1_ocsp(staple->cert);<br>+ aia = X509_get1_ocsp(staple->cert_info->cert);<br> if (aia == NULL) {<br> ngx_log_error(NGX_LOG_WARN, ssl->log, 0,<br> "\"ssl_stapling\" ignored, "<br>@@ -434,12 +472,21 @@<br> ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,<br> ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)<br> {<br>+<br>+ ngx_uint_t i;<br>+ ngx_array_t *staples;<br> ngx_ssl_stapling_t *staple;<br> <br>- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);<br>+ staples = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);<br>+ if (staples == NULL) {<br>+ return NGX_ERROR;<br>+ }<br> <br>- staple->resolver = resolver;<br>- staple->resolver_timeout = resolver_timeout;<br>+ staple = staples->elts;<br>+ for (i = 0; i < staples->nelts; i++) {<br>+ staple[i].resolver = resolver;<br>+ staple[i].resolver_timeout = resolver_timeout;<br>+ }<br> <br> return NGX_OK;<br> }<br>@@ -448,19 +495,46 @@<br> static int<br> ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)<br> {<br>- int rc;<br>- u_char *p;<br>- ngx_connection_t *c;<br>- ngx_ssl_stapling_t *staple;<br>+ int rc;<br>+ ngx_uint_t i;<br>+ u_char *p;<br>+ ngx_connection_t *c;<br>+ X509 *cert;<br>+ ngx_array_t *staples = data;<br>+ ngx_ssl_stapling_t *staple, *staples_elm;<br>+ ngx_ssl_certificate_t *cert_info;<br>+<br>+ staple = NULL;<br> <br> c = ngx_ssl_get_connection(ssl_conn);<br> <br> ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,<br> "SSL certificate status callback");<br> <br>- staple = data;<br>+<br>+ cert = SSL_get_certificate(ssl_conn);<br>+<br> rc = SSL_TLSEXT_ERR_NOACK;<br> <br>+ /* find a staple for current certificate */<br>+<br>+ staples_elm = staples->elts;<br>+ for (i = 0; i < staples->nelts; i++) {<br>+<br>+ cert_info = staples_elm[i].cert_info;<br>+ if (!cert_info)<br>+ continue;<br>+<br>+ if (cert == cert_info->cert) {<br>+ staple = &staples_elm[i];<br>+ break;<br>+ }<br>+ }<br>+<br>+ if (staple == NULL) {<br>+ return rc;<br>+ }<br>+<br> if (staple->staple.len) {<br> /* we have to copy ocsp response as OpenSSL will free it by itself */<br> <br>@@ -486,7 +560,8 @@<br> static void<br> ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)<br> {<br>- ngx_ssl_ocsp_ctx_t *ctx;<br>+ ngx_ssl_ocsp_ctx_t *ctx;<br>+ ngx_ssl_certificate_t *cert_info;<br> <br> if (staple->host.len == 0<br> || staple->loading || staple->valid >= ngx_time())<br>@@ -494,6 +569,11 @@<br> return;<br> }<br> <br>+ cert_info = staple->cert_info;<br>+ if (!cert_info) {<br>+ return;<br>+ }<br>+<br> staple->loading = 1;<br> <br> ctx = ngx_ssl_ocsp_start();<br>@@ -501,8 +581,8 @@<br> return;<br> }<br> <br>- ctx->cert = staple->cert;<br>- ctx->issuer = staple->issuer;<br>+ ctx->cert = cert_info->cert;<br>+ ctx->issuer = cert_info->issuer;<br> <br> ctx->addrs = staple->addrs;<br> ctx->host = staple->host;<br>@@ -528,17 +608,17 @@<br> #if OPENSSL_VERSION_NUMBER >= 0x0090707fL<br> const<br> #endif<br>- u_char *p;<br>- int n;<br>- size_t len;<br>- ngx_str_t response;<br>- X509_STORE *store;<br>- STACK_OF(X509) *chain;<br>- OCSP_CERTID *id;<br>- OCSP_RESPONSE *ocsp;<br>- OCSP_BASICRESP *basic;<br>- ngx_ssl_stapling_t *staple;<br>- ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;<br>+ u_char *p;<br>+ int n;<br>+ size_t len;<br>+ ngx_str_t response;<br>+ X509_STORE *store;<br>+ OCSP_CERTID *id;<br>+ OCSP_RESPONSE *ocsp;<br>+ OCSP_BASICRESP *basic;<br>+ ngx_ssl_stapling_t *staple;<br>+ ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;<br>+ ngx_ssl_certificate_t *cert_info;<br> <br> staple = ctx->data;<br> ocsp = NULL;<br>@@ -584,22 +664,28 @@<br> goto error;<br> }<br> <br>-#if OPENSSL_VERSION_NUMBER >= 0x10001000L<br>- SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);<br>-#else<br>- chain = staple->ssl_ctx->extra_certs;<br>+ cert_info = staple->cert_info;<br>+ if (!cert_info) {<br>+ ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,<br>+ "No certificate information found");<br>+ goto error;<br>+ }<br>+<br>+ if (OCSP_basic_verify(basic, cert_info->chain, store, (staple->verify)<br>+ ? OCSP_TRUSTOTHER<br>+ : OCSP_NOVERIFY<br>+#if OPENSSL_VERSION_NUMBER < 0x10000000L<br>+ /* ECDSA/SHA-2 signature verification not supported */<br>+ | OCSP_NOSIGS<br> #endif<br>-<br>- if (OCSP_basic_verify(basic, chain, store,<br>- staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)<br>- != 1)<br>+ ) != 1)<br> {<br> ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,<br> "OCSP_basic_verify() failed");<br> goto error;<br> }<br> <br>- id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);<br>+ id = OCSP_cert_to_id(NULL, cert_info->cert, ctx->issuer);<br> if (id == NULL) {<br> ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,<br> "OCSP_cert_to_id() failed");<br>@@ -685,14 +771,28 @@<br> static void<br> ngx_ssl_stapling_cleanup(void *data)<br> {<br>- ngx_ssl_stapling_t *staple = data;<br>+ ngx_uint_t i;<br>+ ngx_ssl_stapling_t *staple;<br>+ ngx_ssl_certificate_t *cert_info;<br>+ ngx_array_t *staples = data;<br> <br>- if (staple->issuer) {<br>- X509_free(staple->issuer);<br>- }<br>+ staple = staples->elts;<br>+ for (i = 0; i < staples->nelts; i++) {<br>+ if (staple[i].staple.data) {<br>+ ngx_free(staple[i].staple.data);<br>+ }<br> <br>- if (staple->staple.data) {<br>- ngx_free(staple->staple.data);<br>+ cert_info = staple[i].cert_info;<br>+ if (!cert_info)<br>+ continue;<br>+<br>+ if (cert_info->issuer) {<br>+ X509_free(cert_info->issuer);<br>+ }<br>+<br>+ if (cert_info->chain) {<br>+ sk_X509_free(cert_info->chain);<br>+ }<br> }<br> }<br> <br>@@ -1742,8 +1842,8 @@<br> <br> <br> ngx_int_t<br>-ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,<br>- ngx_str_t *responder, ngx_uint_t verify)<br>+ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,<br>+ ngx_array_t *responders, ngx_uint_t verify)<br> {<br> ngx_log_error(NGX_LOG_WARN, ssl->log, 0,<br> "\"ssl_stapling\" ignored, not supported");<br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/http/modules/ngx_http_proxy_module.c<br>--- a/src/http/modules/ngx_http_proxy_module.c Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/http/modules/ngx_http_proxy_module.c Tue Mar 17 21:15:18 2015 +0300<br>@@ -97,8 +97,8 @@<br> ngx_uint_t ssl_verify_depth;<br> ngx_str_t ssl_trusted_certificate;<br> ngx_str_t ssl_crl;<br>- ngx_str_t ssl_certificate;<br>- ngx_str_t ssl_certificate_key;<br>+ ngx_array_t *ssl_certificates;<br>+ ngx_array_t *ssl_certificate_keys;<br> ngx_array_t *ssl_passwords;<br> #endif<br> } ngx_http_proxy_loc_conf_t;<br>@@ -657,16 +657,16 @@<br> <br> { ngx_string("proxy_ssl_certificate"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_LOC_CONF_OFFSET,<br>- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),<br>+ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificates),<br> NULL },<br> <br> { ngx_string("proxy_ssl_certificate_key"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_LOC_CONF_OFFSET,<br>- offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),<br>+ offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_keys),<br> NULL },<br> <br> { ngx_string("proxy_ssl_password_file"),<br>@@ -2625,6 +2625,8 @@<br> conf->upstream.ssl_verify = NGX_CONF_UNSET;<br> conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;<br> conf->ssl_passwords = NGX_CONF_UNSET_PTR;<br>+ conf->ssl_certificates = NGX_CONF_UNSET_PTR;<br>+ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;<br> #endif<br> <br> /* "proxy_cyclic_temp_file" is disabled */<br>@@ -2953,10 +2955,11 @@<br> prev->ssl_trusted_certificate, "");<br> ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");<br> <br>- ngx_conf_merge_str_value(conf->ssl_certificate,<br>- prev->ssl_certificate, "");<br>- ngx_conf_merge_str_value(conf->ssl_certificate_key,<br>- prev->ssl_certificate_key, "");<br>+ ngx_conf_merge_ptr_value(conf->ssl_certificates,<br>+ prev->ssl_certificates, NULL);<br>+ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,<br>+ prev->ssl_certificate_keys, NULL);<br>+<br> ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);<br> <br> if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {<br>@@ -4043,6 +4046,7 @@<br> ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)<br> {<br> ngx_pool_cleanup_t *cln;<br>+ ngx_str_t *oddkey;<br> <br> plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));<br> if (plcf->upstream.ssl == NULL) {<br>@@ -4065,18 +4069,43 @@<br> cln->handler = ngx_ssl_cleanup_ctx;<br> cln->data = plcf->upstream.ssl;<br> <br>- if (plcf->ssl_certificate.len) {<br>-<br>- if (plcf->ssl_certificate_key.len == 0) {<br>+ if (plcf->ssl_certificates && (plcf->ssl_certificates->nelts > 0)) {<br>+<br>+ if ((!plcf->ssl_certificate_keys)<br>+ || (plcf->ssl_certificate_keys->nelts<br>+ < plcf->ssl_certificates->nelts))<br>+ {<br>+<br>+ oddkey = plcf->ssl_certificates->elts;<br>+<br> ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>- "no \"proxy_ssl_certificate_key\" is defined "<br>- "for certificate \"%V\"", &plcf->ssl_certificate);<br>+ "no \"proxy_ssl_certificate_key\" is defined for "<br>+ "ssl certificate \"%V\"",<br>+ oddkey[(plcf->ssl_certificate_keys)<br>+ ? plcf->ssl_certificate_keys->nelts<br>+ : 0]);<br>+<br> return NGX_ERROR;<br> }<br> <br>- if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate,<br>- &plcf->ssl_certificate_key, plcf->ssl_passwords)<br>- != NGX_OK)<br>+#ifndef SSL_CTX_add0_chain_cert<br>+ if (plcf->ssl_certificates->nelts > 1) {<br>+ /*<br>+ * no multiple certificates support for OpenSSL < 1.0.2,<br>+ * so we need to alarm user<br>+ */<br>+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>+ "Multiple certificate configured "<br>+ "in \"proxy_ssl_certificate\", "<br>+ "but OpenSSL version < 1.0.2 used");<br>+ return NGX_ERROR;<br>+ }<br>+#endif<br>+<br>+ if (ngx_ssl_certificates(cf, plcf->upstream.ssl, plcf->ssl_certificates,<br>+ plcf->ssl_certificate_keys,<br>+ plcf->ssl_passwords)<br>+ != NGX_OK)<br> {<br> return NGX_ERROR;<br> }<br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/http/modules/ngx_http_ssl_module.c<br>--- a/src/http/modules/ngx_http_ssl_module.c Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/http/modules/ngx_http_ssl_module.c Tue Mar 17 21:15:18 2015 +0300<br>@@ -81,16 +81,16 @@<br> <br> { ngx_string("ssl_certificate"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_SRV_CONF_OFFSET,<br>- offsetof(ngx_http_ssl_srv_conf_t, certificate),<br>+ offsetof(ngx_http_ssl_srv_conf_t, certificates),<br> NULL },<br> <br> { ngx_string("ssl_certificate_key"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_SRV_CONF_OFFSET,<br>- offsetof(ngx_http_ssl_srv_conf_t, certificate_key),<br>+ offsetof(ngx_http_ssl_srv_conf_t, certificate_keys),<br> NULL },<br> <br> { ngx_string("ssl_password_file"),<br>@@ -214,16 +214,16 @@<br> <br> { ngx_string("ssl_stapling_file"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_SRV_CONF_OFFSET,<br>- offsetof(ngx_http_ssl_srv_conf_t, stapling_file),<br>+ offsetof(ngx_http_ssl_srv_conf_t, stapling_files),<br> NULL },<br> <br> { ngx_string("ssl_stapling_responder"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_SRV_CONF_OFFSET,<br>- offsetof(ngx_http_ssl_srv_conf_t, stapling_responder),<br>+ offsetof(ngx_http_ssl_srv_conf_t, stapling_responders),<br> NULL },<br> <br> { ngx_string("ssl_stapling_verify"),<br>@@ -505,8 +505,6 @@<br> * set by ngx_pcalloc():<br> *<br> * sscf->protocols = 0;<br>- * sscf->certificate = { 0, NULL };<br>- * sscf->certificate_key = { 0, NULL };<br> * sscf->dhparam = { 0, NULL };<br> * sscf->ecdh_curve = { 0, NULL };<br> * sscf->client_certificate = { 0, NULL };<br>@@ -514,12 +512,12 @@<br> * sscf->crl = { 0, NULL };<br> * sscf->ciphers = { 0, NULL };<br> * sscf->shm_zone = NULL;<br>- * sscf->stapling_file = { 0, NULL };<br>- * sscf->stapling_responder = { 0, NULL };<br> */<br> <br> sscf->enable = NGX_CONF_UNSET;<br> sscf->prefer_server_ciphers = NGX_CONF_UNSET;<br>+ sscf->certificates = NGX_CONF_UNSET_PTR;<br>+ sscf->certificate_keys = NGX_CONF_UNSET_PTR;<br> sscf->buffer_size = NGX_CONF_UNSET_SIZE;<br> sscf->verify = NGX_CONF_UNSET_UINT;<br> sscf->verify_depth = NGX_CONF_UNSET_UINT;<br>@@ -530,6 +528,8 @@<br> sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;<br> sscf->stapling = NGX_CONF_UNSET;<br> sscf->stapling_verify = NGX_CONF_UNSET;<br>+ sscf->stapling_files = NGX_CONF_UNSET_PTR;<br>+ sscf->stapling_responders = NGX_CONF_UNSET_PTR;<br> <br> return sscf;<br> }<br>@@ -570,8 +570,10 @@<br> ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);<br> ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);<br> <br>- ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");<br>- ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");<br>+ ngx_conf_merge_ptr_value(conf->certificates, prev->certificates,<br>+ NULL);<br>+ ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,<br>+ NULL);<br> <br> ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);<br> <br>@@ -590,15 +592,18 @@<br> <br> ngx_conf_merge_value(conf->stapling, prev->stapling, 0);<br> ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0);<br>- ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, "");<br>- ngx_conf_merge_str_value(conf->stapling_responder,<br>- prev->stapling_responder, "");<br>+ ngx_conf_merge_ptr_value(conf->stapling_files, prev->stapling_files,<br>+ NULL);<br>+ ngx_conf_merge_ptr_value(conf->stapling_responders,<br>+ prev->stapling_responders, NULL);<br> <br> conf->ssl.log = cf->log;<br> <br> if (conf->enable) {<br> <br>- if (conf->certificate.len == 0) {<br>+ if ((!conf->certificates)<br>+ || (conf->certificates->nelts == 0)) {<br>+<br> ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br> "no \"ssl_certificate\" is defined for "<br> "the \"ssl\" directive in %s:%ui",<br>@@ -606,7 +611,9 @@<br> return NGX_CONF_ERROR;<br> }<br> <br>- if (conf->certificate_key.len == 0) {<br>+ if ((!conf->certificate_keys)<br>+ || (conf->certificate_keys->nelts == 0)) {<br>+<br> ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br> "no \"ssl_certificate_key\" is defined for "<br> "the \"ssl\" directive in %s:%ui",<br>@@ -616,18 +623,39 @@<br> <br> } else {<br> <br>- if (conf->certificate.len == 0) {<br>+ if ((!conf->certificates)<br>+ || (conf->certificates->nelts == 0)) {<br>+<br> return NGX_CONF_OK;<br> }<br> <br>- if (conf->certificate_key.len == 0) {<br>+ if ((!conf->certificate_keys)<br>+ || (conf->certificate_keys->nelts < conf->certificates->nelts))<br>+ {<br>+<br> ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>- "no \"ssl_certificate_key\" is defined "<br>- "for certificate \"%V\"", &conf->certificate);<br>+ "no \"ssl_certificate_key\" is defined for "<br>+ "ssl_certificate \"%V\"",<br>+ &conf->certificates[(conf->certificate_keys)<br>+ ? conf->certificate_keys->nelts<br>+ : 0]);<br> return NGX_CONF_ERROR;<br> }<br> }<br> <br>+#ifndef SSL_CTX_add0_chain_cert<br>+ if (conf->certificates->nelts > 1) {<br>+ /*<br>+ * no multiple certificates support for OpenSSL < 1.0.2,<br>+ * so we need to alarm user<br>+ */<br>+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>+ "Multiple certificate configured in "<br>+ "\"ssl_certificate\", but OpenSSL < 1.0.2 used");<br>+ return NGX_CONF_ERROR;<br>+ }<br>+#endif<br>+<br> if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {<br> return NGX_CONF_ERROR;<br> }<br>@@ -663,8 +691,8 @@<br> cln->handler = ngx_ssl_cleanup_ctx;<br> cln->data = &conf->ssl;<br> <br>- if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,<br>- &conf->certificate_key, conf->passwords)<br>+ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,<br>+ conf->certificate_keys, conf->passwords)<br> != NGX_OK)<br> {<br> return NGX_CONF_ERROR;<br>@@ -760,8 +788,8 @@<br> <br> if (conf->stapling) {<br> <br>- if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,<br>- &conf->stapling_responder, conf->stapling_verify)<br>+ if (ngx_ssl_stapling(cf, &conf->ssl, conf->stapling_files,<br>+ conf->stapling_responders, conf->stapling_verify)<br> != NGX_OK)<br> {<br> return NGX_CONF_ERROR;<br>diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/http/modules/ngx_http_uwsgi_module.c<br>--- a/src/http/modules/ngx_http_uwsgi_module.c Tue Mar 17 00:26:27 2015 +0300<br>+++ b/src/http/modules/ngx_http_uwsgi_module.c Tue Mar 17 21:15:18 2015 +0300<br>@@ -54,8 +54,8 @@<br> ngx_uint_t ssl_verify_depth;<br> ngx_str_t ssl_trusted_certificate;<br> ngx_str_t ssl_crl;<br>- ngx_str_t ssl_certificate;<br>- ngx_str_t ssl_certificate_key;<br>+ ngx_array_t *ssl_certificates;<br>+ ngx_array_t *ssl_certificate_keys;<br> ngx_array_t *ssl_passwords;<br> #endif<br> } ngx_http_uwsgi_loc_conf_t;<br>@@ -510,16 +510,16 @@<br> <br> { ngx_string("uwsgi_ssl_certificate"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_LOC_CONF_OFFSET,<br>- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate),<br>+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificates),<br> NULL },<br> <br> { ngx_string("uwsgi_ssl_certificate_key"),<br> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,<br>- ngx_conf_set_str_slot,<br>+ ngx_conf_set_str_array_slot,<br> NGX_HTTP_LOC_CONF_OFFSET,<br>- offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key),<br>+ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_keys),<br> NULL },<br> <br> { ngx_string("uwsgi_ssl_password_file"),<br>@@ -1412,6 +1412,8 @@<br> conf->upstream.ssl_verify = NGX_CONF_UNSET;<br> conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;<br> conf->ssl_passwords = NGX_CONF_UNSET_PTR;<br>+ conf->ssl_certificates = NGX_CONF_UNSET_PTR;<br>+ conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;<br> #endif<br> <br> /* "uwsgi_cyclic_temp_file" is disabled */<br>@@ -1723,11 +1725,10 @@<br> ngx_conf_merge_str_value(conf->ssl_trusted_certificate,<br> prev->ssl_trusted_certificate, "");<br> ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");<br>-<br>- ngx_conf_merge_str_value(conf->ssl_certificate,<br>- prev->ssl_certificate, "");<br>- ngx_conf_merge_str_value(conf->ssl_certificate_key,<br>- prev->ssl_certificate_key, "");<br>+ ngx_conf_merge_ptr_value(conf->ssl_certificates,<br>+ prev->ssl_certificates, NULL);<br>+ ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,<br>+ prev->ssl_certificate_keys, NULL);<br> ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);<br> <br> if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {<br>@@ -2264,6 +2265,7 @@<br> ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)<br> {<br> ngx_pool_cleanup_t *cln;<br>+ ngx_str_t *oddkey;<br> <br> uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));<br> if (uwcf->upstream.ssl == NULL) {<br>@@ -2286,17 +2288,42 @@<br> cln->handler = ngx_ssl_cleanup_ctx;<br> cln->data = uwcf->upstream.ssl;<br> <br>- if (uwcf->ssl_certificate.len) {<br>-<br>- if (uwcf->ssl_certificate_key.len == 0) {<br>+ if (uwcf->ssl_certificates && (uwcf->ssl_certificates->nelts > 0)) {<br>+<br>+ if ((!uwcf->ssl_certificate_keys)<br>+ || (uwcf->ssl_certificate_keys->nelts<br>+ < uwcf->ssl_certificates->nelts))<br>+ {<br>+<br>+ oddkey = &uwcf->ssl_certificates->elts;<br>+<br> ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>- "no \"uwsgi_ssl_certificate_key\" is defined "<br>- "for certificate \"%V\"", &uwcf->ssl_certificate);<br>+ "no \"uwsgi_ssl_certificate_key\" is defined for "<br>+ "ssl certificate \"%V\"",<br>+ oddkey[(uwcf->ssl_certificate_keys)<br>+ ? uwcf->ssl_certificate_keys->nelts<br>+ : 0]);<br>+<br> return NGX_ERROR;<br> }<br> <br>- if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate,<br>- &uwcf->ssl_certificate_key, uwcf->ssl_passwords)<br>+#ifndef SSL_CTX_add0_chain_cert<br>+ if (uwcf->ssl_certificates->nelts > 1) {<br>+ /*<br>+ * no multiple certificates support for OpenSSL < 1.0.2,<br>+ * so we need to alarm user<br>+ */<br>+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,<br>+ "Multiple certificate configured "<br>+ "in "\"uwsgi_ssl_certificate\", but "<br>+ "OpenSSL < 1.0.2 used");<br>+ return NGX_ERROR;<br>+ }<br>+#endif<br>+<br>+ if (ngx_ssl_certificates(cf, uwcf->upstream.ssl, uwcf->ssl_certificates,<br>+ uwcf->ssl_certificate_keys,<br>+ uwcf->ssl_passwords)<br> != NGX_OK)<br> {<br> return NGX_ERROR;<br><br></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 17, 2015 at 9:27 PM, Albert Casademont Filella <span dir="ltr"><<a href="mailto:albertcasademont@gmail.com" target="_blank">albertcasademont@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>This would be a very nice addition indeed, thanks!! I guess it needs quite a lot of testing though, ECC certs are still not really common these days.<br><br></div>BTW and before some of the core devs says it patches should be sent in the email body, not as an attachment. It is much more convenient for reviewing it ;)<br></div><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Tue, Mar 17, 2015 at 7:22 PM, kyprizel <span dir="ltr"><<a href="mailto:kyprizel@gmail.com" target="_blank">kyprizel@gmail.com</a>></span> wrote:<br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><div dir="ltr">Hi,<br>Sorry for spamming - previous message was sent to wrong mailing list and possibly included broken patch.<br><br>This patch is mostly finishing of Rob Stradlings patch discussed in thread<br><a href="http://mailman.nginx.org/pipermail/nginx-devel/2013-November/004475.html" target="_blank">http://mailman.nginx.org/pipermail/nginx-devel/2013-November/004475.html</a><br><br>Multi certificate support works only for OpenSSL >= 1.0.2.<br>Only certificates with different crypto algorithms (ECC/RSA/DSA) can be used b/c of OpenSSL limitations, otherwise (RSA+SHA-256 / RSA-SHA-1 for example) only last specified in the config will be used.<br>Can you please review it.<br><br>Thank you.<br><br></div>
<br></div></div>_______________________________________________<br>
nginx-devel mailing list<br>
<a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
<a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><br></blockquote></div><br></div>
<br>_______________________________________________<br>
nginx-devel mailing list<br>
<a href="mailto:nginx-devel@nginx.org">nginx-devel@nginx.org</a><br>
<a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><br></blockquote></div><br></div>