Sure it should be tested (there are can be some memory leaks).
Need to know if it's idologically acceptable.

Nginx with dual cert support can be tested at https://ctftime.org.

Patch in body inline:
# HG changeset patch
# User Eldar Zaitov <el...@kyprizel.net>
# Date 1426616118 -10800
# Node ID 83b0f57fbcb514ffd74bb89070580473bacd286e
# Parent  e370c5fdf4c8edc2e8d33d7170c1b1cc74a2ecb6
Multiple SSL certificate support with OpenSSL >= 1.0.2

diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c Tue Mar 17 00:26:27 2015 +0300
+++ b/src/event/ngx_event_openssl.c Tue Mar 17 21:15:18 2015 +0300
@@ -286,198 +286,282 @@


 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)
 {
-    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) {
+    ngx_str_t              *pwd;
+    ngx_uint_t              tries;
+    ngx_str_t              *cert;
+    ngx_str_t              *key;
+    ngx_uint_t              i, j;
+    u_long                  n;
+    BIO                    *bio;
+    EVP_PKEY               *pkey;
+    X509                   *x509;
+    X509                   *x509_ca;
+    STACK_OF(X509)         *chain;
+    ngx_array_t            *certificates;
+    ngx_ssl_certificate_t  *cert_info;
+
+    bio = NULL;
+    pkey = NULL;
+    x509 = NULL;
+    x509_ca = NULL;
+
+    cert = certs->elts;
+    key = keys->elts;
+
+    certificates = ngx_array_create(cf->pool, certs->nelts,
+                                    sizeof(ngx_ssl_certificate_t));
+    if (certificates == NULL) {
         return NGX_ERROR;
     }

-    /*
-     * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
-     * allow to access certificate later from SSL_CTX, so we reimplement
-     * it here
-     */
-
-    bio = BIO_new_file((char *) cert->data, "r");
-    if (bio == NULL) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "BIO_new_file(\"%s\") failed", cert->data);
-        return NGX_ERROR;
-    }
-
-    x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
-    if (x509 == NULL) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
-        BIO_free(bio);
-        return NGX_ERROR;
-    }
-
-    if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "SSL_CTX_use_certificate(\"%s\") failed",
cert->data);
-        X509_free(x509);
-        BIO_free(bio);
-        return NGX_ERROR;
-    }
-
-    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
-        == 0)
-    {
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "SSL_CTX_set_ex_data() failed");
-        X509_free(x509);
-        BIO_free(bio);
-        return NGX_ERROR;
-    }
-
-    X509_free(x509);
-
-    /* read rest of the chain */
-
-    for ( ;; ) {
-
-        x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+    for (i = 0; i < certs->nelts; i++) {
+
+        /* load server certificate */
+
+        if (ngx_conf_full_name(cf->cycle, &cert[i], 1) != NGX_OK) {
+            goto failed;
+        }
+
+        /*
+         * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
+         * allow to access certificate later from SSL_CTX, so we
reimplement
+         * it here
+         */
+
+        bio = BIO_new_file((char *) cert[i].data, "r");
+        if (bio == NULL) {
+            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                          "BIO_new_file(\"%V\") failed", &cert[i]);
+            goto failed;
+        }
+
+        x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
         if (x509 == NULL) {
+            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                          "PEM_read_bio_X509_AUX(\"%V\") failed",
&cert[i]);
+            goto failed;
+        }
+
+        if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
+            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                          "SSL_CTX_use_certificate(\"%V\") failed",
&cert[i]);
+            goto failed;
+        }
+
+
+        /* read rest of the chain */
+
+        for (j = 0; ; j++) {
+
+            x509_ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
             n = ERR_peek_last_error();

-            if (ERR_GET_LIB(n) == ERR_LIB_PEM
-                && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
-            {
-                /* end of file */
-                ERR_clear_error();
+            if (x509_ca == NULL) {
+
+                if (ERR_GET_LIB(n) == ERR_LIB_PEM
+                    && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
+                {
+                    /* end of file */
+                    ERR_clear_error();
+                    break;
+                }
+
+                /* some real error */
+
+                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                              "PEM_read_bio_X509(\"%V\") failed",
&cert[i]);
+                goto failed;
+            }
+
+#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_ca) == 0) {
+
+                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                              "SSL_CTX_add0_chain_cert(\"%V\") failed",
+                              &cert[i]);
+                goto failed;
+            }
+#else
+            if (i == 0) {
+                if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509_ca) == 0) {
+
+                    ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                                  "SSL_CTX_add_extra_chain_cert() failed");
+                    goto failed;
+                }
                 break;
             }
-
-            /* some real error */
+#endif
+
+        }
+
+        BIO_free(bio);
+        bio = NULL;
+
+
+        /* load private key */
+
+        if (ngx_strncmp(key[i].data, "engine:", sizeof("engine:") - 1) ==
0) {
+#ifndef OPENSSL_NO_ENGINE
+
+            u_char      *p, *last;
+            ENGINE      *engine;
+
+            p = key[i].data + sizeof("engine:") - 1;
+            last = (u_char *) ngx_strchr(p, ':');
+
+            if (last == NULL) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid syntax in \"%V\"", &(key[i]));
+                goto failed;
+            }
+
+
+            *last = '\0';
+
+            engine = ENGINE_by_id((char *) p);
+
+            if (engine == NULL) {
+                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                              "ENGINE_by_id(\"%s\") failed", p);
+                goto failed;
+            }
+
+            *last++ = ':';
+
+            pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
+
+            if (pkey == NULL) {
+                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                              "ENGINE_load_private_key(\"%s\") failed",
last);
+                ENGINE_free(engine);
+                goto failed;
+            }
+
+            ENGINE_free(engine);
+
+            if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
+                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                              "SSL_CTX_use_PrivateKey(\"%s\") failed",
last);
+                goto failed;
+            }
+
+            EVP_PKEY_free(pkey);
+            pkey = NULL;
+
+            continue;
+#else
+
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "loading \"engine:...\" certificate keys "
+                               "is not supported");
+            goto failed;
+
+#endif
+        }
+
+        if (ngx_conf_full_name(cf->cycle, &key[i], 1) != NGX_OK) {
+            goto failed;
+        }
+
+        if (passwords) {
+            tries = passwords->nelts;
+            pwd = passwords->elts;
+
+            SSL_CTX_set_default_passwd_cb(ssl->ctx,
ngx_ssl_password_callback);
+            SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
+        } else {
+            tries = 1;
+#if (NGX_SUPPRESS_WARN)
+            pwd = NULL;
+#endif
+        }
+
+
+        for ( ;; ) {
+            if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key[i].data,
+                                            SSL_FILETYPE_PEM)
+                != 0)
+            {
+                break;
+            }
+
+            if (--tries) {
+                ERR_clear_error();
+                SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
+                continue;
+            }

             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                          "PEM_read_bio_X509(\"%s\") failed", cert->data);
-            BIO_free(bio);
-            return NGX_ERROR;
+                          "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
+                          key[i].data);
+            goto failed;
         }

-        if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
+        if (SSL_CTX_check_private_key(ssl->ctx) < 1) {
             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                          "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
-                          cert->data);
-            X509_free(x509);
-            BIO_free(bio);
-            return NGX_ERROR;
+                          "PrivateKey \"%V\" does not match \"%V\" failed",
+                          &key[i], &cert[i]);
+            goto failed;
         }
-    }
-
-    BIO_free(bio);
-
-    if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
-
-#ifndef OPENSSL_NO_ENGINE
-
-        u_char      *p, *last;
-        ENGINE      *engine;
-        EVP_PKEY    *pkey;
-
-        p = key->data + sizeof("engine:") - 1;
-        last = (u_char *) ngx_strchr(p, ':');
-
-        if (last == NULL) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid syntax in \"%V\"", key);
-            return NGX_ERROR;
+
+        SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
+
+
+#ifdef SSL_CTX_get0_chain_certs
+        SSL_CTX_get0_chain_certs(ssl->ctx, &chain);
+#else
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+        SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
+#else
+        chain = ssl->ctx->extra_certs;
+#endif
+#endif
+
+        cert_info = ngx_array_push(certificates);
+        if (cert_info == NULL) {
+            goto failed;
         }

-        *last = '\0';
-
-        engine = ENGINE_by_id((char *) p);
-
-        if (engine == NULL) {
-            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                          "ENGINE_by_id(\"%s\") failed", p);
-            return NGX_ERROR;
-        }
-
-        *last++ = ':';
-
-        pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
-
-        if (pkey == NULL) {
-            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                          "ENGINE_load_private_key(\"%s\") failed", last);
-            ENGINE_free(engine);
-            return NGX_ERROR;
-        }
-
-        ENGINE_free(engine);
-
-        if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
-            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                          "SSL_CTX_use_PrivateKey(\"%s\") failed", last);
-            EVP_PKEY_free(pkey);
-            return NGX_ERROR;
-        }
-
+        cert_info->issuer = NULL;
+        cert_info->cert = x509;
+        CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
+
+        cert_info->chain = chain;
+
+
+     }
+
+     /* store cert info for future use in stapling and sessions */
+
+     if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index,
certificates)
+         == 0)
+     {
+         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                         "SSL_CTX_set_ex_data() failed");
+         goto failed;
+     }
+
+     return NGX_OK;
+
+failed:
+
+    if (bio)
+        BIO_free(bio);
+    if (pkey)
         EVP_PKEY_free(pkey);
-
-        return NGX_OK;
-
-#else
-
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "loading \"engine:...\" certificate keys "
-                           "is not supported");
-        return NGX_ERROR;
-
-#endif
-    }
-
-    if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    if (passwords) {
-        tries = passwords->nelts;
-        pwd = passwords->elts;
-
-        SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);
-        SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
-
-    } else {
-        tries = 1;
-#if (NGX_SUPPRESS_WARN)
-        pwd = NULL;
-#endif
-    }
-
-    for ( ;; ) {
-
-        if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
-                                        SSL_FILETYPE_PEM)
-            != 0)
-        {
-            break;
-        }
-
-        if (--tries) {
-            ERR_clear_error();
-            SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
-            continue;
-        }
-
-        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
key->data);
-        return NGX_ERROR;
-    }
-
-    SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
-
-    return NGX_OK;
+    if (x509)
+        X509_free(x509);
+    if (x509_ca)
+        X509_free(x509_ca);
+
+    return NGX_ERROR;
 }


@@ -2111,13 +2195,14 @@
 static ngx_int_t
 ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
 {
-    int                   n, i;
-    X509                 *cert;
-    X509_NAME            *name;
-    EVP_MD_CTX            md;
-    unsigned int          len;
-    STACK_OF(X509_NAME)  *list;
-    u_char                buf[EVP_MAX_MD_SIZE];
+    int                     n, i;
+    X509_NAME              *name;
+    EVP_MD_CTX              md;
+    unsigned int            len;
+    STACK_OF(X509_NAME)    *list;
+    u_char                  buf[EVP_MAX_MD_SIZE];
+    ngx_array_t            *certs;
+    ngx_ssl_certificate_t  *cert_info;

     /*
      * Session ID context is set based on the string provided,
@@ -2138,9 +2223,14 @@
         goto failed;
     }

-    cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
-
-    if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
+    certs = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
+    if (!certs || certs->nelts == 0) {
+        goto failed;
+    }
+
+    cert_info = certs->elts;
+
+    if (X509_digest((&cert_info[0])->cert, EVP_sha1(), buf, &len) == 0) {
         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                       "X509_digest() failed");
         goto failed;
diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h Tue Mar 17 00:26:27 2015 +0300
+++ b/src/event/ngx_event_openssl.h Tue Mar 17 21:15:18 2015 +0300
@@ -45,6 +45,13 @@


 typedef struct {
+    X509                       *cert;
+    X509                       *issuer;
+    STACK_OF(X509)             *chain;
+} ngx_ssl_certificate_t;
+
+
+typedef struct {
     ngx_ssl_conn_t             *connection;

     ngx_int_t                   last;
@@ -122,15 +129,15 @@

 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,
     ngx_str_t *cert, ngx_int_t depth);
 ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
 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_array_t *files, ngx_array_t *responders, ngx_uint_t verify);
 ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
 RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
diff -r e370c5fdf4c8 -r 83b0f57fbcb5 src/event/ngx_event_openssl_stapling.c
--- a/src/event/ngx_event_openssl_stapling.c    Tue Mar 17 00:26:27 2015
+0300
+++ b/src/event/ngx_event_openssl_stapling.c    Tue Mar 17 21:15:18 2015
+0300
@@ -28,8 +28,7 @@

     SSL_CTX                     *ssl_ctx;

-    X509                        *cert;
-    X509                        *issuer;
+    ngx_ssl_certificate_t       *cert_info;

     time_t                       valid;

@@ -83,10 +82,11 @@


 static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
-    ngx_str_t *file);
-static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
+    ngx_ssl_stapling_t *staple, ngx_str_t *file);
+static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,
+    ngx_ssl_stapling_t *staple);
 static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
-    ngx_str_t *responder);
+    ngx_ssl_stapling_t *staple, ngx_str_t *responder);

 static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
     void *data);
@@ -115,15 +115,29 @@


 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_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,
+    ngx_array_t *responders, ngx_uint_t verify)
 {
-    ngx_int_t                  rc;
-    ngx_pool_cleanup_t        *cln;
-    ngx_ssl_stapling_t        *staple;
+    ngx_uint_t               i;
+    ngx_array_t             *staples;
+    ngx_array_t             *certificates;
+    ngx_pool_cleanup_t      *cln;
+    ngx_str_t               *responder, *file;
+    ngx_str_t                empty_responder = ngx_null_string;
+    ngx_ssl_stapling_t      *staple;
+    ngx_ssl_certificate_t   *cert_info;

-    staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
-    if (staple == NULL) {
+    responder = NULL;
+    file = NULL;
+
+    certificates = SSL_CTX_get_ex_data(ssl->ctx,
ngx_ssl_certificate_index);
+    if (certificates == NULL || (certificates->nelts == 0)) {
+        return NGX_ERROR;
+    }
+
+    staples = ngx_array_create(cf->pool, certificates->nelts,
+                               sizeof(ngx_ssl_stapling_t));
+    if (staples == NULL) {
         return NGX_ERROR;
     }

@@ -133,9 +147,66 @@
     }

     cln->handler = ngx_ssl_stapling_cleanup;
-    cln->data = staple;
+    cln->data = staples;

-    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)
+
+    cert_info = certificates->elts;
+    staple = staples->elts;
+
+    if (responders)
+        responder = responders->elts;
+
+    if (files)
+        file = files->elts;
+
+    for (i = 0; i < certificates->nelts; i++) {
+
+        staple = ngx_array_push(staples);
+        staple->timeout = 60000;
+        staple->ssl_ctx = ssl->ctx;
+        CRYPTO_add(&ssl->ctx->references, 1, CRYPTO_LOCK_X509);
+
+        staple->cert_info = &cert_info[i];
+        if (ngx_ssl_stapling_issuer(cf, ssl, staple) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+        staple->verify = verify;
+
+        if (responder && responders->nelts > i) {
+
+            if (ngx_ssl_stapling_responder(cf, ssl, staple, &responder[i])
+                != NGX_OK)
+            {
+                return NGX_ERROR;
+            }
+
+        } else {
+
+            if (ngx_ssl_stapling_responder(cf, ssl, staple,
&empty_responder)
+                == NGX_ERROR)
+            {
+                return NGX_ERROR;
+            }
+            empty_responder.len = 0;
+            empty_responder.data = NULL;
+
+        }
+
+        if (!file || files->nelts <= i)
+            continue;
+
+        if (file[i].len) {
+
+            /* use OCSP response from the file */
+
+            if (ngx_ssl_stapling_file(cf, ssl, staple, &file[i]) !=
NGX_OK) {
+                return NGX_ERROR;
+            }
+        }
+    }
+
+
+    if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staples)
         == 0)
     {
         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
@@ -143,59 +214,21 @@
         return NGX_ERROR;
     }

-    staple->ssl_ctx = ssl->ctx;
-    staple->timeout = 60000;
-    staple->verify = verify;
-
-    if (file->len) {
-        /* use OCSP response from the file */
-
-        if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {
-            return NGX_ERROR;
-        }
-
-        goto done;
-    }
-
-    rc = ngx_ssl_stapling_issuer(cf, ssl);
-
-    if (rc == NGX_DECLINED) {
-        return NGX_OK;
-    }
-
-    if (rc != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-    rc = ngx_ssl_stapling_responder(cf, ssl, responder);
-
-    if (rc == NGX_DECLINED) {
-        return NGX_OK;
-    }
-
-    if (rc != NGX_OK) {
-        return NGX_ERROR;
-    }
-
-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, staples);

     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_ssl_stapling_t *staple, ngx_str_t *file)
 {
     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;
@@ -255,23 +288,32 @@


 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,
+                        ngx_ssl_stapling_t *staple)
 {
-    int                  i, n, rc;
-    X509                *cert, *issuer;
-    X509_STORE          *store;
-    X509_STORE_CTX      *store_ctx;
-    STACK_OF(X509)      *chain;
-    ngx_ssl_stapling_t  *staple;
+    int                     i, n, rc;
+    X509                   *issuer;
+    X509_STORE             *store;
+    X509_STORE_CTX         *store_ctx;
+    ngx_ssl_certificate_t  *cert_info = staple->cert_info;
+    X509                   *cert;
+    STACK_OF(X509)         *chain;

-    staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
-    cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);

-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-    SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
-#else
-    chain = ssl->ctx->extra_certs;
-#endif
+    if (!cert_info || !cert_info->cert) {
+        ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+                      "\"ssl_stapling\" ignored, no certificate info
found");
+        return NGX_ERROR;
+    }
+
+    if (!cert_info->chain) {
+        ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
+                      "\"ssl_stapling\" ignored, no certificate chain
found");
+        return NGX_ERROR;
+    }
+
+    cert = cert_info->cert;
+    chain = cert_info->chain;

     n = sk_X509_num(chain);

@@ -286,8 +328,7 @@
             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                            "SSL get issuer: found %p in extra certs",
issuer);

-            staple->cert = cert;
-            staple->issuer = issuer;
+            cert_info->issuer = issuer;

             return NGX_OK;
         }
@@ -334,28 +375,25 @@
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                    "SSL get issuer: found %p in cert store", issuer);

-    staple->cert = cert;
-    staple->issuer = issuer;
+    cert_info->issuer = issuer;

     return NGX_OK;
 }


 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_ssl_stapling_t *staple, ngx_str_t
*responder)
 {
     ngx_url_t                  u;
     char                      *s;
-    ngx_ssl_stapling_t        *staple;
     STACK_OF(OPENSSL_STRING)  *aia;

-    staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
-
     if (responder->len == 0) {

         /* extract OCSP responder URL from certificate */

-        aia = X509_get1_ocsp(staple->cert);
+        aia = X509_get1_ocsp(staple->cert_info->cert);
         if (aia == NULL) {
             ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                           "\"ssl_stapling\" ignored, "
@@ -434,12 +472,21 @@
 ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
     ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
 {
+
+    ngx_uint_t           i;
+    ngx_array_t         *staples;
     ngx_ssl_stapling_t  *staple;

-    staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+    staples = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
+    if (staples == NULL) {
+        return NGX_ERROR;
+    }

-    staple->resolver = resolver;
-    staple->resolver_timeout = resolver_timeout;
+    staple = staples->elts;
+    for (i = 0; i < staples->nelts; i++) {
+        staple[i].resolver = resolver;
+        staple[i].resolver_timeout = resolver_timeout;
+    }

     return NGX_OK;
 }
@@ -448,19 +495,46 @@
 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;
+    ngx_uint_t              i;
+    u_char                 *p;
+    ngx_connection_t       *c;
+    X509                   *cert;
+    ngx_array_t            *staples = data;
+    ngx_ssl_stapling_t     *staple, *staples_elm;
+    ngx_ssl_certificate_t  *cert_info;
+
+    staple = NULL;

     c = ngx_ssl_get_connection(ssl_conn);

     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                    "SSL certificate status callback");

-    staple = data;
+
+    cert = SSL_get_certificate(ssl_conn);
+
     rc = SSL_TLSEXT_ERR_NOACK;

+    /* find a staple for current certificate */
+
+    staples_elm = staples->elts;
+    for (i = 0; i < staples->nelts; i++) {
+
+        cert_info = staples_elm[i].cert_info;
+        if (!cert_info)
+            continue;
+
+        if (cert == cert_info->cert) {
+            staple = &staples_elm[i];
+            break;
+        }
+    }
+
+    if (staple == NULL) {
+        return rc;
+    }
+
     if (staple->staple.len) {
         /* we have to copy ocsp response as OpenSSL will free it by itself
*/

@@ -486,7 +560,8 @@
 static void
 ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
 {
-    ngx_ssl_ocsp_ctx_t  *ctx;
+    ngx_ssl_ocsp_ctx_t      *ctx;
+    ngx_ssl_certificate_t   *cert_info;

     if (staple->host.len == 0
         || staple->loading || staple->valid >= ngx_time())
@@ -494,6 +569,11 @@
         return;
     }

+    cert_info = staple->cert_info;
+    if (!cert_info) {
+        return;
+    }
+
     staple->loading = 1;

     ctx = ngx_ssl_ocsp_start();
@@ -501,8 +581,8 @@
         return;
     }

-    ctx->cert = staple->cert;
-    ctx->issuer = staple->issuer;
+    ctx->cert = cert_info->cert;
+    ctx->issuer = cert_info->issuer;

     ctx->addrs = staple->addrs;
     ctx->host = staple->host;
@@ -528,17 +608,17 @@
 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
     const
 #endif
-    u_char                *p;
-    int                    n;
-    size_t                 len;
-    ngx_str_t              response;
-    X509_STORE            *store;
-    STACK_OF(X509)        *chain;
-    OCSP_CERTID           *id;
-    OCSP_RESPONSE         *ocsp;
-    OCSP_BASICRESP        *basic;
-    ngx_ssl_stapling_t    *staple;
-    ASN1_GENERALIZEDTIME  *thisupdate, *nextupdate;
+    u_char                 *p;
+    int                     n;
+    size_t                  len;
+    ngx_str_t               response;
+    X509_STORE             *store;
+    OCSP_CERTID            *id;
+    OCSP_RESPONSE          *ocsp;
+    OCSP_BASICRESP         *basic;
+    ngx_ssl_stapling_t     *staple;
+    ASN1_GENERALIZEDTIME   *thisupdate, *nextupdate;
+    ngx_ssl_certificate_t  *cert_info;

     staple = ctx->data;
     ocsp = NULL;
@@ -584,22 +664,28 @@
         goto error;
     }

-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
-    SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
-#else
-    chain = staple->ssl_ctx->extra_certs;
+    cert_info = staple->cert_info;
+    if (!cert_info) {
+        ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
+                      "No certificate information found");
+        goto error;
+    }
+
+    if (OCSP_basic_verify(basic, cert_info->chain, store, (staple->verify)
+                                                            ?
OCSP_TRUSTOTHER
+                                                            : OCSP_NOVERIFY
+#if OPENSSL_VERSION_NUMBER < 0x10000000L
+        /* ECDSA/SHA-2 signature verification not supported */
+                                                              | OCSP_NOSIGS
 #endif
-
-    if (OCSP_basic_verify(basic, chain, store,
-                          staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
-        != 1)
+       ) != 1)
     {
         ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
                       "OCSP_basic_verify() failed");
         goto error;
     }

-    id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
+    id = OCSP_cert_to_id(NULL, cert_info->cert, ctx->issuer);
     if (id == NULL) {
         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                       "OCSP_cert_to_id() failed");
@@ -685,14 +771,28 @@
 static void
 ngx_ssl_stapling_cleanup(void *data)
 {
-    ngx_ssl_stapling_t  *staple = data;
+    ngx_uint_t              i;
+    ngx_ssl_stapling_t     *staple;
+    ngx_ssl_certificate_t  *cert_info;
+    ngx_array_t            *staples = data;

-    if (staple->issuer) {
-        X509_free(staple->issuer);
-    }
+    staple = staples->elts;
+    for (i = 0; i < staples->nelts; i++) {
+        if (staple[i].staple.data) {
+            ngx_free(staple[i].staple.data);
+        }

-    if (staple->staple.data) {
-        ngx_free(staple->staple.data);
+        cert_info = staple[i].cert_info;
+        if (!cert_info)
+            continue;
+
+        if (cert_info->issuer) {
+            X509_free(cert_info->issuer);
+        }
+
+        if (cert_info->chain) {
+            sk_X509_free(cert_info->chain);
+        }
     }
 }

@@ -1742,8 +1842,8 @@


 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_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *files,
+    ngx_array_t *responders, ngx_uint_t verify)
 {
     ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                   "\"ssl_stapling\" ignored, not supported");
diff -r e370c5fdf4c8 -r 83b0f57fbcb5
src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c  Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_proxy_module.c  Tue Mar 17 21:15:18 2015
+0300
@@ -97,8 +97,8 @@
     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;
@@ -657,16 +657,16 @@

     { 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"),
@@ -2625,6 +2625,8 @@
     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 */
@@ -2953,10 +2955,11 @@
                               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) {
@@ -4043,6 +4046,7 @@
 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) {
@@ -4065,18 +4069,43 @@
     cln->handler = ngx_ssl_cleanup_ctx;
     cln->data = plcf->upstream.ssl;

-    if (plcf->ssl_certificate.len) {
-
-        if (plcf->ssl_certificate_key.len == 0) {
+    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;
+
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"proxy_ssl_certificate_key\" is defined "
-                          "for certificate \"%V\"",
&plcf->ssl_certificate);
+                          "no \"proxy_ssl_certificate_key\" is defined 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 -r e370c5fdf4c8 -r 83b0f57fbcb5 src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c    Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_ssl_module.c    Tue Mar 17 21:15:18 2015
+0300
@@ -81,16 +81,16 @@

     { 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"),
@@ -214,16 +214,16 @@

     { ngx_string("ssl_stapling_file"),
       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, stapling_file),
+      offsetof(ngx_http_ssl_srv_conf_t, stapling_files),
       NULL },

     { ngx_string("ssl_stapling_responder"),
       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, stapling_responder),
+      offsetof(ngx_http_ssl_srv_conf_t, stapling_responders),
       NULL },

     { ngx_string("ssl_stapling_verify"),
@@ -505,8 +505,6 @@
      * 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 };
@@ -514,12 +512,12 @@
      *     sscf->crl = { 0, NULL };
      *     sscf->ciphers = { 0, NULL };
      *     sscf->shm_zone = NULL;
-     *     sscf->stapling_file = { 0, NULL };
-     *     sscf->stapling_responder = { 0, NULL };
      */

     sscf->enable = NGX_CONF_UNSET;
     sscf->prefer_server_ciphers = NGX_CONF_UNSET;
+    sscf->certificates = NGX_CONF_UNSET_PTR;
+    sscf->certificate_keys = NGX_CONF_UNSET_PTR;
     sscf->buffer_size = NGX_CONF_UNSET_SIZE;
     sscf->verify = NGX_CONF_UNSET_UINT;
     sscf->verify_depth = NGX_CONF_UNSET_UINT;
@@ -530,6 +528,8 @@
     sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
     sscf->stapling = NGX_CONF_UNSET;
     sscf->stapling_verify = NGX_CONF_UNSET;
+    sscf->stapling_files = NGX_CONF_UNSET_PTR;
+    sscf->stapling_responders = NGX_CONF_UNSET_PTR;

     return sscf;
 }
@@ -570,8 +570,10 @@
     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);

@@ -590,15 +592,18 @@

     ngx_conf_merge_value(conf->stapling, prev->stapling, 0);
     ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0);
-    ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, "");
-    ngx_conf_merge_str_value(conf->stapling_responder,
-                         prev->stapling_responder, "");
+    ngx_conf_merge_ptr_value(conf->stapling_files, prev->stapling_files,
+                        NULL);
+    ngx_conf_merge_ptr_value(conf->stapling_responders,
+                        prev->stapling_responders, NULL);

     conf->ssl.log = cf->log;

     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 +611,9 @@
             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 +623,39 @@

     } 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 < conf->certificates->nelts))
+        {
+
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined "
-                          "for certificate \"%V\"", &conf->certificate);
+                          "no \"ssl_certificate_key\" is defined for "
+                          "ssl_certificate \"%V\"",
+                          &conf->certificates[(conf->certificate_keys)
+                                              ?
conf->certificate_keys->nelts
+                                              : 0]);
             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 +691,8 @@
     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;
@@ -760,8 +788,8 @@

     if (conf->stapling) {

-        if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,
-                             &conf->stapling_responder,
conf->stapling_verify)
+        if (ngx_ssl_stapling(cf, &conf->ssl, conf->stapling_files,
+                             conf->stapling_responders,
conf->stapling_verify)
             != NGX_OK)
         {
             return NGX_CONF_ERROR;
diff -r e370c5fdf4c8 -r 83b0f57fbcb5
src/http/modules/ngx_http_uwsgi_module.c
--- a/src/http/modules/ngx_http_uwsgi_module.c  Tue Mar 17 00:26:27 2015
+0300
+++ b/src/http/modules/ngx_http_uwsgi_module.c  Tue Mar 17 21:15:18 2015
+0300
@@ -54,8 +54,8 @@
     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;
@@ -510,16 +510,16 @@

     { 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"),
@@ -1412,6 +1412,8 @@
     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 */
@@ -1723,11 +1725,10 @@
     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) {
@@ -2264,6 +2265,7 @@
 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) {
@@ -2286,17 +2288,42 @@
     cln->handler = ngx_ssl_cleanup_ctx;
     cln->data = uwcf->upstream.ssl;

-    if (uwcf->ssl_certificate.len) {
-
-        if (uwcf->ssl_certificate_key.len == 0) {
+    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;
+
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"uwsgi_ssl_certificate_key\" is defined "
-                          "for certificate \"%V\"",
&uwcf->ssl_certificate);
+                          "no \"uwsgi_ssl_certificate_key\" is defined 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;


On Tue, Mar 17, 2015 at 9:27 PM, Albert Casademont Filella <
albertcasadem...@gmail.com> wrote:

> 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.
>
> 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 ;)
>
> On Tue, Mar 17, 2015 at 7:22 PM, kyprizel <kypri...@gmail.com> wrote:
>
>> Hi,
>> Sorry for spamming - previous message was sent to wrong mailing list and
>> possibly included broken patch.
>>
>> This patch is mostly finishing of Rob Stradlings patch discussed in thread
>> http://mailman.nginx.org/pipermail/nginx-devel/2013-November/004475.html
>>
>> Multi certificate support works only for OpenSSL >= 1.0.2.
>> 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.
>> Can you please review it.
>>
>> Thank you.
>>
>>
>> _______________________________________________
>> nginx-devel mailing list
>> nginx-devel@nginx.org
>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel@nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel

Reply via email to