On Sat, Aug 13, 2016 at 02:57:14AM +1000, Joel Sing wrote:
> The following diff makes httpd stricter with respect to TLS configuration:
> 
> - Do not allow TLS and non-TLS to be configured on the same port.
> - Do not allow TLS options to be specified without a TLS listener.
> - Ensure that TLS options are the same when a server is specified on the
>   same address/port.
> 
> Currently, these configurations are permitted but do not work as intended.
> 
> This also factors out (and reuses) the server matching code that was already
> duplicated.
> 
> ok?
> 

- I think server_match() and server_tls_cmp() can both live in
server.c (server_match() somewhere close to server_foreach() - this
match function can be used for at least one other case outside of
parse.y).

- As discussed before, for consistency with the config, please use
"tls" instead of "TLS" in the log messages. 

FYI, The SNI diff doesn't like the tls_cert_file and tls_key_file
checks in server_tls_cmp(), as they now become valid, but they can be
removed/changed later.

Otherwise OK reyk@

> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
> retrieving revision 1.78
> diff -u -p -r1.78 parse.y
> --- parse.y   21 Jun 2016 21:35:24 -0000      1.78
> +++ parse.y   12 Aug 2016 16:48:28 -0000
> @@ -107,8 +107,10 @@ int               host_if(const char *, struct addre
>  int           host(const char *, struct addresslist *,
>                   int, struct portrange *, const char *, int);
>  void          host_free(struct addresslist *);
> +struct server        *server_match(struct server *, int);
>  struct server        *server_inherit(struct server *, struct server_config *,
>                   struct server_config *);
> +int           server_tls_cmp(struct server *, struct server *);
>  int           getservice(char *);
>  int           is_if_in_group(const char *, const char *);
>  
> @@ -283,24 +285,13 @@ server          : SERVER optmatch STRING        {
>  
>                       TAILQ_INSERT_TAIL(&srv->srv_hosts, srv_conf, entry);
>               } '{' optnl serveropts_l '}'    {
> -                     struct server           *s = NULL, *sn;
> +                     struct server           *s, *sn;
>                       struct server_config    *a, *b;
>  
>                       srv_conf = &srv->srv_conf;
>  
> -                     TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
> -                             if ((s->srv_conf.flags &
> -                                 SRVFLAG_LOCATION) == 0 &&
> -                                 strcmp(s->srv_conf.name,
> -                                 srv->srv_conf.name) == 0 &&
> -                                 s->srv_conf.port == srv->srv_conf.port &&
> -                                 sockaddr_cmp(
> -                                 (struct sockaddr *)&s->srv_conf.ss,
> -                                 (struct sockaddr *)&srv->srv_conf.ss,
> -                                 s->srv_conf.prefixlen) == 0)
> -                                     break;
> -                     }
> -                     if (s != NULL) {
> +                     /* Check if the new server already exists. */
> +                     if (server_match(srv, 1) != NULL) {
>                               yyerror("server \"%s\" defined twice",
>                                   srv->srv_conf.name);
>                               serverconfig_free(srv_conf);
> @@ -315,16 +306,39 @@ server          : SERVER optmatch STRING        {
>                               YYERROR;
>                       }
>  
> +                     if ((s = server_match(srv, 0)) != NULL) {
> +                             if ((s->srv_conf.flags & SRVFLAG_TLS) != 
> +                                 (srv->srv_conf.flags & SRVFLAG_TLS)) {
> +                                     yyerror("server \"%s\": TLS and "
> +                                         "non-TLS on same address/port",
> +                                         srv->srv_conf.name);
> +                                     serverconfig_free(srv_conf);
> +                                     free(srv);
> +                                     YYERROR;
> +                             }
> +                             if (server_tls_cmp(s, srv) != 0) {
> +                                     yyerror("server \"%s\": TLS "
> +                                         "configuration mismatch on same "
> +                                         "address/port",
> +                                         srv->srv_conf.name);
> +                                     serverconfig_free(srv_conf);
> +                                     free(srv);
> +                                     YYERROR;
> +                             }
> +                     }
> +
>                       if ((srv->srv_conf.flags & SRVFLAG_TLS) &&
>                           srv->srv_conf.tls_protocols == 0) {
> -                             yyerror("no TLS protocols");
> +                             yyerror("server \"%s\": no TLS protocols",
> +                                 srv->srv_conf.name);
> +                             serverconfig_free(srv_conf);
>                               free(srv);
>                               YYERROR;
>                       }
>  
>                       if (server_tls_load_keypair(srv) == -1) {
> -                             yyerror("failed to load public/private keys "
> -                                 "for server %s", srv->srv_conf.name);
> +                             yyerror("server \"%s\": failed to load "
> +                                 "public/private keys", srv->srv_conf.name);
>                               serverconfig_free(srv_conf);
>                               free(srv);
>                               YYERROR;
> @@ -398,7 +412,7 @@ serveroptsl       : LISTEN ON STRING opttls po
>                                   sizeof(*alias))) == NULL)
>                                       fatal("out of memory");
>  
> -                             /* Add as an alias */
> +                             /* Add as an IP-based alias. */
>                               s_conf = alias;
>                       } else
>                               s_conf = &srv->srv_conf;
> @@ -416,9 +430,8 @@ serveroptsl       : LISTEN ON STRING opttls po
>                       s_conf->prefixlen = h->prefixlen;
>                       host_free(&al);
>  
> -                     if ($4) {
> +                     if ($4)
>                               s_conf->flags |= SRVFLAG_TLS;
> -                     }
>  
>                       if (alias != NULL) {
>                               /* IP-based; use name match flags from parent */
> @@ -468,10 +481,22 @@ serveroptsl     : LISTEN ON STRING opttls po
>                       }
>               }
>               | tls                   {
> +                     struct server_config    *sc;
> +                     int                      tls_flag = 0;
> +
>                       if (parentsrv != NULL) {
>                               yyerror("tls configuration inside location");
>                               YYERROR;
>                       }
> +
> +                     /* Ensure that at least one server has TLS enabled. */
> +                     TAILQ_FOREACH(sc, &srv->srv_hosts, entry) {
> +                             tls_flag |= (sc->flags & SRVFLAG_TLS);
> +                     }
> +                     if (tls_flag == 0) {
> +                             yyerror("tls options without tls listener");
> +                             YYERROR;
> +                     }
>               }
>               | root
>               | directory
> @@ -1968,6 +1993,33 @@ host_free(struct addresslist *al)
>  }
>  
>  struct server *
> +server_match(struct server *s2, int match_name)
> +{
> +     struct server   *s1;
> +
> +     /* Attempt to find matching server. */
> +     TAILQ_FOREACH(s1, conf->sc_servers, srv_entry) {
> +             if ((s1->srv_conf.flags & SRVFLAG_LOCATION) != 0)
> +                     continue;
> +             if (match_name) {
> +                     if (strcmp(s1->srv_conf.name, s2->srv_conf.name) != 0)
> +                             continue;
> +             }
> +             if (s1->srv_conf.port != s2->srv_conf.port)
> +                     continue;
> +             if (sockaddr_cmp(
> +                 (struct sockaddr *)&s1->srv_conf.ss,
> +                 (struct sockaddr *)&s2->srv_conf.ss,
> +                 s1->srv_conf.prefixlen) != 0)
> +                     continue;
> +
> +             return (s1);
> +     }
> +
> +     return (NULL);
> +}
> +
> +struct server *
>  server_inherit(struct server *src, struct server_config *alias,
>      struct server_config *addr)
>  {
> @@ -2028,19 +2080,7 @@ server_inherit(struct server *src, struc
>       }
>  
>       /* Check if the new server already exists */
> -     TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
> -             if ((s->srv_conf.flags &
> -                 SRVFLAG_LOCATION) == 0 &&
> -                 strcmp(s->srv_conf.name,
> -                 dst->srv_conf.name) == 0 &&
> -                 s->srv_conf.port == dst->srv_conf.port &&
> -                 sockaddr_cmp(
> -                 (struct sockaddr *)&s->srv_conf.ss,
> -                 (struct sockaddr *)&dst->srv_conf.ss,
> -                 s->srv_conf.prefixlen) == 0)
> -                     break;
> -     }
> -     if (s != NULL) {
> +     if (server_match(dst, 1) != NULL) {
>               yyerror("server \"%s\" defined twice",
>                   dst->srv_conf.name);
>               serverconfig_free(&dst->srv_conf);
> @@ -2078,6 +2118,30 @@ server_inherit(struct server *src, struc
>       }
>  
>       return (dst);
> +}
> +
> +int
> +server_tls_cmp(struct server *s1, struct server *s2)
> +{
> +     struct server_config    *sc1, *sc2;
> +
> +     sc1 = &s1->srv_conf;
> +     sc2 = &s2->srv_conf;
> +
> +     if (sc1->tls_protocols != sc2->tls_protocols)
> +             return (-1);
> +     if (strcmp(sc1->tls_cert_file, sc2->tls_cert_file) != 0)
> +             return (-1);
> +     if (strcmp(sc1->tls_key_file, sc2->tls_key_file) != 0)
> +             return (-1);
> +     if (strcmp(sc1->tls_ciphers, sc2->tls_ciphers) != 0)
> +             return (-1);
> +     if (strcmp(sc1->tls_dhe_params, sc2->tls_dhe_params) != 0)
> +             return (-1);
> +     if (strcmp(sc1->tls_ecdhe_curve, sc2->tls_ecdhe_curve) != 0)
> +             return (-1);
> +
> +     return (0);
>  }
>  
>  int
> 

-- 

Reply via email to