[PATCH] Multiple certificate support with OpenSSL >= 1.0.2

kyprizel kyprizel at gmail.com
Tue Mar 17 18:38:42 UTC 2015


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 <eldar at 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 <
albertcasademont at 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 <kyprizel at 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 at nginx.org
>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20150317/15511da5/attachment-0001.html>


More information about the nginx-devel mailing list