On 17/10/13 16:18, Maxim Dounin wrote:
<snip>
Issues I'm aware of with this patch:

   - It doesn't check that each of the certs has a different key type
(but perhaps it should).  If you specify multiple certs with the
same algorithm, all but the last one will be ignored.

Bad, but we could live with it if there will be no better way to
do things.

We could call EVP_PKEY_type() for each private key, and throw an error if there's >1 key of any particular type (EVP_PKEY_RSA, EVP_PKEY_DSA, EVP_PKEY_EC).

But I think I'd prefer to "live with it". Future OpenSSL versions might add new key types, or might make it possible for a server to offer multiple certs of the same type (e.g. 2 ECC certs with different curves). It would be nice if Nginx could support such enhancements automatically.

   - The certs and keys need to be specified in the correct order.
If you specify "my_rsa.crt my_ecc.crt" and "my_ecc.key my_rsa.key",
Nginx will start but it won't be able to complete any SSL
handshakes.  This could be improved.

This is certainly not something acceptable.  There should be a
better way to specify certs and keys.

Patch v2 (attached) checks that each cert and key are correctly paired. If they're incorrectly paired, Nginx will throw an error and refuse to start.

   - It doesn't add the new feature to mail_ssl_module.  Perhaps it should.

This could wait.

Implemented in patch v2. Untested, but the changes are virtually identical to the http_ssl_module changes.

   - The changes I made to ngx_conf_set_str_array_slot() work for me,
but do they break anything?

It doesn't look like changes we want. The
ngx_conf_set_str_array_slot() function is intended to handle
arrays like this:

     example_array_directive value1;
     example_array_directive value2;

Thanks for that tip.  :-)

I would rather see ssl_certificates to be used this way, something
like:

     ssl_certificate      rsa.crt;
     ssl_certificate_key  rsa.key;

     ssl_certificate      ecc.crt;
     ssl_certificate_key  ecc.key;

I agree.  Fixed in patch v2.

   - An RSA cert and an ECC cert might well be issued by different
CAs.  On Apache httpd, you have to use SSLCACertificatePath to
persuade OpenSSL to send different Intermediate certs for each one.
Nginx doesn't currently have an equivalent directive, and Maxim has
previously said it's unlikely to be added [1].
I haven't researched this properly yet, but I think it might be
possible to do "certificate path" in memory (i.e. without syscalls
and disk access on each certificate check) using the OpenSSL
X509_LOOKUP API.

AFAIR, OpenSSL only able to store one certificate chain per
SSL_CTX, which is the root cause of the problem.

I think you're right.  I've not tried to address this yet.

   - I expect Maxim will have other comments.  :-)

One thing which instantly comes in mind is SSL Stapling related
issues.

Ah yes. The Nginx stapling code seems to assume one cert and therefore one OCSP Response. So, I think it needs updating to handle multiple certs and OCSP Responses and to call SSL_get_certificate(SSL*) to get the cert that the server has selected to send to the client. I've not tried to address this yet.

--
Rob Stradling
Senior Research & Development Scientist
COMODO - Creating Trust Online
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -200,16 +200,20 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
 
 #ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
     /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
     SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
 #endif
 
+#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG
+    SSL_CTX_set_options(ssl->ctx, SSL_OP_SAFARI_ECDHE_ECDSA_BUG);
+#endif
+
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
 
     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
 
@@ -248,19 +252,20 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
     return NGX_OK;
 }
 
 
 ngx_int_t
 ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
     ngx_str_t *key)
 {
-    BIO     *bio;
-    X509    *x509;
-    u_long   n;
+    BIO       *bio;
+    X509      *x509;
+    EVP_PKEY  *pkey = NULL;
+    u_long     n;
 
     if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
         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
@@ -337,30 +342,93 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_
     }
 
     BIO_free(bio);
 
     if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
         return NGX_ERROR;
     }
 
-    if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
-                                    SSL_FILETYPE_PEM)
-        == 0)
-    {
+    bio = BIO_new_file((char *) key->data, "r");
+    if (bio == NULL) {
         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
-                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
+                      "BIO_new_file(\"%s\") failed", key->data);
         return NGX_ERROR;
     }
 
+    pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+    if (pkey == NULL) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "PEM_read_bio_PrivateKey(\"%s\") failed", key->data);
+        BIO_free(bio);
+        return NGX_ERROR;
+    }
+
+    x509 = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
+    if (X509_check_private_key(x509, pkey) != 1) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "X509_check_private_key(\"%s\") for \"%V\" failed",
+                      key->data, cert);
+        EVP_PKEY_free(pkey);
+        BIO_free(bio);
+        return NGX_ERROR;
+    }
+
+    if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) != 1) {
+        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                      "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data);
+        EVP_PKEY_free(pkey);
+        BIO_free(bio);
+        return NGX_ERROR;
+    }
+
+    EVP_PKEY_free(pkey);
+    BIO_free(bio);
+
     return NGX_OK;
 }
 
 
 ngx_int_t
+ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs,
+    ngx_array_t *keys)
+{
+    ngx_uint_t   i;
+    ngx_str_t   *cert;
+    ngx_str_t   *key;
+
+    cert = certs->elts;
+
+    if (keys == NGX_CONF_UNSET_PTR) {
+        i = 0;
+        goto label_failed;
+    }
+    else if (keys->nelts < certs->nelts) {
+        i = keys->nelts;
+        goto label_failed;
+    }
+
+    key = keys->elts;
+
+    for (i = 0; i < certs->nelts; i++)
+        if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i]) != NGX_OK)
+            return NGX_ERROR;
+
+    return NGX_OK;
+
+label_failed:
+    ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+                  "no \"ssl_certificate_key\" is defined for "
+                  "ssl_certificate \"%V\"",
+                  &cert[i]);
+    return NGX_ERROR;
+}
+
+
+ngx_int_t
 ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
     ngx_int_t depth)
 {
     STACK_OF(X509_NAME)  *list;
 
     SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_ssl_verify_callback);
 
     SSL_CTX_set_verify_depth(ssl->ctx, depth);
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -104,18 +104,18 @@ typedef struct {
 #define NGX_SSL_BUFFER   1
 #define NGX_SSL_CLIENT   2
 
 #define NGX_SSL_BUFSIZE  16384
 
 
 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_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
+    ngx_array_t *certs, ngx_array_t *keys);
 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_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -66,26 +66,26 @@ static ngx_command_t  ngx_http_ssl_comma
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
       ngx_http_ssl_enable,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, enable),
       NULL },
 
     { 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_dhparam"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
       NGX_HTTP_SRV_CONF_OFFSET,
       offsetof(ngx_http_ssl_srv_conf_t, dhparam),
       NULL },
@@ -404,18 +404,16 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
     if (sscf == NULL) {
         return NULL;
     }
 
     /*
      * 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 };
      *     sscf->trusted_certificate = { 0, NULL };
      *     sscf->crl = { 0, NULL };
      *     sscf->ciphers = { 0, NULL };
      *     sscf->shm_zone = NULL;
      *     sscf->stapling_file = { 0, NULL };
@@ -423,16 +421,18 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t 
      */
 
     sscf->enable = NGX_CONF_UNSET;
     sscf->prefer_server_ciphers = NGX_CONF_UNSET;
     sscf->verify = NGX_CONF_UNSET_UINT;
     sscf->verify_depth = NGX_CONF_UNSET_UINT;
     sscf->builtin_session_cache = NGX_CONF_UNSET;
     sscf->session_timeout = NGX_CONF_UNSET;
+    sscf->certificates = NGX_CONF_UNSET_PTR;
+    sscf->certificate_keys = NGX_CONF_UNSET_PTR;
     sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
     sscf->stapling = NGX_CONF_UNSET;
     sscf->stapling_verify = NGX_CONF_UNSET;
 
     return sscf;
 }
 
 
@@ -463,18 +463,20 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
                          (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1
                           |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
 
     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,
+                         NGX_CONF_UNSET_PTR);
+    ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
+                         NGX_CONF_UNSET_PTR);
 
     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
 
     ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
                          "");
     ngx_conf_merge_str_value(conf->trusted_certificate,
                          prev->trusted_certificate, "");
     ngx_conf_merge_str_value(conf->crl, prev->crl, "");
@@ -487,46 +489,26 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     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, "");
 
     conf->ssl.log = cf->log;
 
-    if (conf->enable) {
-
-        if (conf->certificate.len == 0) {
+    if ((conf->certificates == NGX_CONF_UNSET_PTR)
+            || (conf->certificates->nelts == 0)) {
+        if (conf->enable) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"ssl_certificate\" is defined for "
                           "the \"ssl\" directive in %s:%ui",
                           conf->file, conf->line);
             return NGX_CONF_ERROR;
         }
-
-        if (conf->certificate_key.len == 0) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined for "
-                          "the \"ssl\" directive in %s:%ui",
-                          conf->file, conf->line);
-            return NGX_CONF_ERROR;
-        }
-
-    } else {
-
-        if (conf->certificate.len == 0) {
-            return NGX_CONF_OK;
-        }
-
-        if (conf->certificate_key.len == 0) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined "
-                          "for certificate \"%V\"", &conf->certificate);
-            return NGX_CONF_ERROR;
-        }
+        return NGX_CONF_OK;
     }
 
     if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
 
@@ -550,18 +532,18 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
         return NGX_CONF_ERROR;
     }
 
     cln->handler = ngx_ssl_cleanup_ctx;
     cln->data = &conf->ssl;
 
-    if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
-                            &conf->certificate_key)
+    if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+                             conf->certificate_keys)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
     }
 
     if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
                                 (const char *) conf->ciphers.data)
         == 0)
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -25,18 +25,18 @@ typedef struct {
 
     ngx_uint_t                      verify;
     ngx_uint_t                      verify_depth;
 
     ssize_t                         builtin_session_cache;
 
     time_t                          session_timeout;
 
-    ngx_str_t                       certificate;
-    ngx_str_t                       certificate_key;
+    ngx_array_t                    *certificates;
+    ngx_array_t                    *certificate_keys;
     ngx_str_t                       dhparam;
     ngx_str_t                       ecdh_curve;
     ngx_str_t                       client_certificate;
     ngx_str_t                       trusted_certificate;
     ngx_str_t                       crl;
 
     ngx_str_t                       ciphers;
 
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -57,26 +57,26 @@ static ngx_command_t  ngx_mail_ssl_comma
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
       ngx_mail_ssl_starttls,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, starttls),
       ngx_mail_starttls_state },
 
     { ngx_string("ssl_certificate"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_conf_set_str_array_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_ssl_conf_t, certificate),
+      offsetof(ngx_mail_ssl_conf_t, certificates),
       NULL },
 
     { ngx_string("ssl_certificate_key"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
+      ngx_conf_set_str_array_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_ssl_conf_t, certificate_key),
+      offsetof(ngx_mail_ssl_conf_t, certificate_keys),
       NULL },
 
     { ngx_string("ssl_dhparam"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
       NGX_MAIL_SRV_CONF_OFFSET,
       offsetof(ngx_mail_ssl_conf_t, dhparam),
       NULL },
@@ -173,29 +173,29 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
     if (scf == NULL) {
         return NULL;
     }
 
     /*
      * set by ngx_pcalloc():
      *
      *     scf->protocols = 0;
-     *     scf->certificate = { 0, NULL };
-     *     scf->certificate_key = { 0, NULL };
      *     scf->dhparam = { 0, NULL };
      *     scf->ecdh_curve = { 0, NULL };
      *     scf->ciphers = { 0, NULL };
      *     scf->shm_zone = NULL;
      */
 
     scf->enable = NGX_CONF_UNSET;
     scf->starttls = NGX_CONF_UNSET_UINT;
     scf->prefer_server_ciphers = NGX_CONF_UNSET;
     scf->builtin_session_cache = NGX_CONF_UNSET;
     scf->session_timeout = NGX_CONF_UNSET;
+    scf->certificates = NGX_CONF_UNSET_PTR;
+    scf->certificate_keys = NGX_CONF_UNSET_PTR;
     scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
 
     return scf;
 }
 
 
 static char *
 ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
@@ -215,18 +215,20 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
 
     ngx_conf_merge_value(conf->prefer_server_ciphers,
                          prev->prefer_server_ciphers, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
                          (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3|NGX_SSL_TLSv1
                           |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
 
-    ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
-    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
+    ngx_conf_merge_ptr_value(conf->certificates, prev->certificates,
+                         NGX_CONF_UNSET_PTR);
+    ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
+                         NGX_CONF_UNSET_PTR);
 
     ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
 
     ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
                          NGX_DEFAULT_ECDH_CURVE);
 
     ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
 
@@ -243,63 +245,42 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
        mode = "";
     }
 
     if (conf->file == NULL) {
         conf->file = prev->file;
         conf->line = prev->line;
     }
 
-    if (*mode) {
-
-        if (conf->certificate.len == 0) {
+    if ((conf->certificates == NGX_CONF_UNSET_PTR)
+            || (conf->certificates->nelts == 0)) {
+        if (*mode) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                           "no \"ssl_certificate\" is defined for "
                           "the \"%s\" directive in %s:%ui",
                           mode, conf->file, conf->line);
             return NGX_CONF_ERROR;
         }
-
-        if (conf->certificate_key.len == 0) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined for "
-                          "the \"%s\" directive in %s:%ui",
-                          mode, conf->file, conf->line);
-            return NGX_CONF_ERROR;
-        }
-
-    } else {
-
-        if (conf->certificate.len == 0) {
-            return NGX_CONF_OK;
-        }
-
-        if (conf->certificate_key.len == 0) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined "
-                          "for certificate \"%V\"",
-                          &conf->certificate);
-            return NGX_CONF_ERROR;
-        }
+        return NGX_CONF_OK;
     }
 
     if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
         return NGX_CONF_ERROR;
     }
 
     cln->handler = ngx_ssl_cleanup_ctx;
     cln->data = &conf->ssl;
 
-    if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
-                            &conf->certificate_key)
+    if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+                             conf->certificate_keys)
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
     }
 
     if (SSL_CTX_set_cipher_list(conf->ssl.ctx,
                                 (const char *) conf->ciphers.data)
         == 0)
diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -27,18 +27,18 @@ typedef struct {
 
     ngx_uint_t       starttls;
     ngx_uint_t       protocols;
 
     ssize_t          builtin_session_cache;
 
     time_t           session_timeout;
 
-    ngx_str_t        certificate;
-    ngx_str_t        certificate_key;
+    ngx_array_t     *certificates;
+    ngx_array_t     *certificate_keys;
     ngx_str_t        dhparam;
     ngx_str_t        ecdh_curve;
 
     ngx_str_t        ciphers;
 
     ngx_shm_zone_t  *shm_zone;
 
     ngx_array_t     *session_ticket_keys;
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel

Reply via email to