changeset 7269:7f955d3b9a0d

SSL: detect "listen ... ssl" without certificates (ticket #178). In mail and stream modules, no certificate provided is a fatal condition, much like with the "ssl" and "starttls" directives. In http, "listen ... ssl" can be used in a non-default server without certificates as long as there is a certificate in the default one, so missing certificate is only fatal for default servers.
author Maxim Dounin <mdounin@mdounin.ru>
date Tue, 24 Apr 2018 15:29:01 +0300
parents 0d8c72ff62dd
children 46c0c7ef4913
files src/http/modules/ngx_http_ssl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/mail/ngx_mail_core_module.c src/mail/ngx_mail_handler.c src/mail/ngx_mail_ssl_module.c src/mail/ngx_mail_ssl_module.h src/stream/ngx_stream_core_module.c src/stream/ngx_stream_ssl_module.c src/stream/ngx_stream_ssl_module.h
diffstat 11 files changed, 123 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -966,10 +966,12 @@ invalid:
 static ngx_int_t
 ngx_http_ssl_init(ngx_conf_t *cf)
 {
-    ngx_uint_t                   s;
+    ngx_uint_t                   a, p, s;
+    ngx_http_conf_addr_t        *addr;
+    ngx_http_conf_port_t        *port;
     ngx_http_ssl_srv_conf_t     *sscf;
     ngx_http_core_loc_conf_t    *clcf;
-    ngx_http_core_srv_conf_t   **cscfp;
+    ngx_http_core_srv_conf_t   **cscfp, *cscf;
     ngx_http_core_main_conf_t   *cmcf;
 
     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
@@ -993,5 +995,32 @@ ngx_http_ssl_init(ngx_conf_t *cf)
         }
     }
 
+    if (cmcf->ports == NULL) {
+        return NGX_OK;
+    }
+
+    port = cmcf->ports->elts;
+    for (p = 0; p < cmcf->ports->nelts; p++) {
+
+        addr = port[p].addrs.elts;
+        for (a = 0; a < port[p].addrs.nelts; a++) {
+
+            if (!addr[a].opt.ssl) {
+                continue;
+            }
+
+            cscf = addr[a].default_server;
+            sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index];
+
+            if (sscf->certificates == NULL) {
+                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                              "no \"ssl_certificate\" is defined for "
+                              "the \"listen ... ssl\" directive in %s:%ui",
+                              cscf->file_name, cscf->line);
+                return NGX_ERROR;
+            }
+        }
+    }
+
     return NGX_OK;
 }
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3256,6 +3256,9 @@ ngx_http_core_create_srv_conf(ngx_conf_t
     cscf->merge_slashes = NGX_CONF_UNSET;
     cscf->underscores_in_headers = NGX_CONF_UNSET;
 
+    cscf->file_name = cf->conf_file->file.name.data;
+    cscf->line = cf->conf_file->line;
+
     return cscf;
 }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -184,6 +184,9 @@ typedef struct {
     /* server ctx */
     ngx_http_conf_ctx_t        *ctx;
 
+    u_char                     *file_name;
+    ngx_uint_t                  line;
+
     ngx_str_t                   server_name;
 
     size_t                      connection_pool_size;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -336,19 +336,8 @@ ngx_http_init_connection(ngx_connection_
     sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
 
     if (sscf->enable || hc->addr_conf->ssl) {
-
+        hc->ssl = 1;
         c->log->action = "SSL handshaking";
-
-        if (hc->addr_conf->ssl && sscf->ssl.ctx == NULL) {
-            ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                          "no \"ssl_certificate\" is defined "
-                          "in server listening on SSL port");
-            ngx_http_close_connection(c);
-            return;
-        }
-
-        hc->ssl = 1;
-
         rev->handler = ngx_http_ssl_handshake;
     }
     }
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -474,7 +474,16 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
 
         if (ngx_strcmp(value[i].data, "ssl") == 0) {
 #if (NGX_MAIL_SSL)
+            ngx_mail_ssl_conf_t  *sslcf;
+
+            sslcf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_ssl_module);
+
+            sslcf->listen = 1;
+            sslcf->file = cf->conf_file->file.name.data;
+            sslcf->line = cf->conf_file->line;
+
             ls->ssl = 1;
+
             continue;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -165,29 +165,13 @@ ngx_mail_init_connection(ngx_connection_
 
     sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
 
-    if (sslcf->enable) {
+    if (sslcf->enable || addr_conf->ssl) {
         c->log->action = "SSL handshaking";
 
         ngx_mail_ssl_init_connection(&sslcf->ssl, c);
         return;
     }
 
-    if (addr_conf->ssl) {
-
-        c->log->action = "SSL handshaking";
-
-        if (sslcf->ssl.ctx == NULL) {
-            ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                          "no \"ssl_certificate\" is defined "
-                          "in server listening on SSL port");
-            ngx_mail_close_connection(c);
-            return;
-        }
-
-        ngx_mail_ssl_init_connection(&sslcf->ssl, c);
-        return;
-    }
-
     }
 #endif
 
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -238,6 +238,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
     /*
      * set by ngx_pcalloc():
      *
+     *     scf->listen = 0;
      *     scf->protocols = 0;
      *     scf->dhparam = { 0, NULL };
      *     scf->ecdh_curve = { 0, NULL };
@@ -313,14 +314,17 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
 
     conf->ssl.log = cf->log;
 
-    if (conf->enable) {
+    if (conf->listen) {
+        mode = "listen ... ssl";
+
+    } else if (conf->enable) {
         mode = "ssl";
 
     } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) {
         mode = "starttls";
 
     } else {
-        mode = "";
+        return NGX_CONF_OK;
     }
 
     if (conf->file == NULL) {
@@ -328,51 +332,31 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
         conf->line = prev->line;
     }
 
-    if (*mode) {
-
-        if (conf->certificates == NULL) {
-            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_keys == NULL) {
-            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;
-        }
+    if (conf->certificates == NULL) {
+        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_keys->nelts < conf->certificates->nelts) {
-            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "no \"ssl_certificate_key\" is defined "
-                          "for certificate \"%V\" and "
-                          "the \"%s\" directive in %s:%ui",
-                          ((ngx_str_t *) conf->certificates->elts)
-                          + conf->certificates->nelts - 1,
-                          mode, conf->file, conf->line);
-            return NGX_CONF_ERROR;
-        }
-
-    } else {
+    if (conf->certificate_keys == NULL) {
+        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;
+    }
 
-        if (conf->certificates == NULL) {
-            return NGX_CONF_OK;
-        }
-
-        if (conf->certificate_keys == NULL
-            || 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\"",
-                          ((ngx_str_t *) conf->certificates->elts)
-                          + conf->certificates->nelts - 1);
-            return NGX_CONF_ERROR;
-        }
+    if (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\" and "
+                      "the \"%s\" directive in %s:%ui",
+                      ((ngx_str_t *) conf->certificates->elts)
+                      + conf->certificates->nelts - 1,
+                      mode, conf->file, conf->line);
+        return NGX_CONF_ERROR;
     }
 
     if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
@@ -494,8 +478,10 @@ ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
-    scf->file = cf->conf_file->file.name.data;
-    scf->line = cf->conf_file->line;
+    if (!scf->listen) {
+        scf->file = cf->conf_file->file.name.data;
+        scf->line = cf->conf_file->line;
+    }
 
     return NGX_CONF_OK;
 }
@@ -520,8 +506,10 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ng
         return NGX_CONF_ERROR;
     }
 
-    scf->file = cf->conf_file->file.name.data;
-    scf->line = cf->conf_file->line;
+    if (!scf->listen) {
+        scf->file = cf->conf_file->file.name.data;
+        scf->line = cf->conf_file->line;
+    }
 
     return NGX_CONF_OK;
 }
--- a/src/mail/ngx_mail_ssl_module.h
+++ b/src/mail/ngx_mail_ssl_module.h
@@ -26,6 +26,7 @@ typedef struct {
     ngx_ssl_t        ssl;
 
     ngx_uint_t       starttls;
+    ngx_uint_t       listen;
     ngx_uint_t       protocols;
 
     ngx_uint_t       verify;
--- a/src/stream/ngx_stream_core_module.c
+++ b/src/stream/ngx_stream_core_module.c
@@ -734,7 +734,17 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
 
         if (ngx_strcmp(value[i].data, "ssl") == 0) {
 #if (NGX_STREAM_SSL)
+            ngx_stream_ssl_conf_t  *sslcf;
+
+            sslcf = ngx_stream_conf_get_module_srv_conf(cf,
+                                                        ngx_stream_ssl_module);
+
+            sslcf->listen = 1;
+            sslcf->file = cf->conf_file->file.name.data;
+            sslcf->line = cf->conf_file->line;
+
             ls->ssl = 1;
+
             continue;
 #else
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -304,13 +304,6 @@ ngx_stream_ssl_handler(ngx_stream_sessio
     if (c->ssl == NULL) {
         c->log->action = "SSL handshaking";
 
-        if (sslcf->ssl.ctx == NULL) {
-            ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                          "no \"ssl_certificate\" is defined "
-                          "in server listening on SSL port");
-            return NGX_ERROR;
-        }
-
         rv = ngx_stream_ssl_init_connection(&sslcf->ssl, c);
 
         if (rv != NGX_OK) {
@@ -510,6 +503,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *c
     /*
      * set by ngx_pcalloc():
      *
+     *     scf->listen = 0;
      *     scf->protocols = 0;
      *     scf->dhparam = { 0, NULL };
      *     scf->ecdh_curve = { 0, NULL };
@@ -582,18 +576,34 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
 
     conf->ssl.log = cf->log;
 
-    if (conf->certificates == NULL) {
+    if (!conf->listen) {
         return NGX_CONF_OK;
     }
 
-    if (conf->certificate_keys == NULL
-        || conf->certificate_keys->nelts < conf->certificates->nelts)
-    {
+    if (conf->certificates == NULL) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "no \"ssl_certificate\" is defined for "
+                      "the \"listen ... ssl\" directive in %s:%ui",
+                      conf->file, conf->line);
+        return NGX_CONF_ERROR;
+    }
+
+    if (conf->certificate_keys == NULL) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "no \"ssl_certificate_key\" is defined for "
+                      "the \"listen ... ssl\" directive in %s:%ui",
+                      conf->file, conf->line);
+        return NGX_CONF_ERROR;
+    }
+
+    if (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\"",
+                      "for certificate \"%V\" and "
+                      "the \"listen ... ssl\" directive in %s:%ui",
                       ((ngx_str_t *) conf->certificates->elts)
-                      + conf->certificates->nelts - 1);
+                      + conf->certificates->nelts - 1,
+                      conf->file, conf->line);
         return NGX_CONF_ERROR;
     }
 
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -21,6 +21,7 @@ typedef struct {
 
     ngx_ssl_t        ssl;
 
+    ngx_uint_t       listen;
     ngx_uint_t       protocols;
 
     ngx_uint_t       verify;
@@ -47,6 +48,9 @@ typedef struct {
 
     ngx_flag_t       session_tickets;
     ngx_array_t     *session_ticket_keys;
+
+    u_char          *file;
+    ngx_uint_t       line;
 } ngx_stream_ssl_conf_t;