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