It will! The diff is nice and OK.
> Am 16.05.2018 um 22:33 schrieb Jan Klemkow <j.klem...@wemelug.de>:
>
> Hi Jack,
>
>> On Wed, May 16, 2018 at 05:32:56PM +0930, Jack Burton wrote:
>> I figured that if we can agree on this much, so httpd can be used for
>> the authentication-only case (which is all non-fastcgi sites would want)
>> straight away, that's be a good first step -- then we can come back and
>> argue the toss over how much client cert data is necessary/sufficient
>> to pass through for authorisation/accounting purposes.
>
> I agree with you. Lets commit this first step.
>
> I tested your diff on current amd64 and sparc64 with an own PKI [1] and
> the firefox browser. Every thing works for me. I also looked down your
> source code which also seams fine to me.
>
> I tested the optional and non-optional "client ca" configuration, as
> well as the revocation and the fastcgi environment feature on both
> architectures. Everything works so far.
>
> Hopefully, it will committed this time! :-)
>
> Thanks!
> Jan
>
> [1]: https://github.com/younix/ca
>
>> There's also a trivial regression test (unchanged from last year), which
>> I'll post again separately next.
>>
>>
>> Index: config.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/config.c,v
>> retrieving revision 1.53
>> diff -u -p -r1.53 config.c
>> --- config.c 19 Jul 2017 17:36:25 -0000 1.53
>> +++ config.c 16 May 2018 07:59:10 -0000
>> @@ -304,10 +304,18 @@ config_setserver_tls(struct httpd *env,
>>
>> log_debug("%s: configuring tls for %s", __func__, srv_conf->name);
>>
>> + if (config_settls(env, srv, TLS_CFG_CA, "ca", srv_conf->tls_ca,
>> + srv_conf->tls_ca_len) != 0)
>> + return (-1);
>> +
>> if (config_settls(env, srv, TLS_CFG_CERT, "cert", srv_conf->tls_cert,
>> srv_conf->tls_cert_len) != 0)
>> return (-1);
>>
>> + if (config_settls(env, srv, TLS_CFG_CRL, "crl", srv_conf->tls_crl,
>> + srv_conf->tls_crl_len) != 0)
>> + return (-1);
>> +
>> if (config_settls(env, srv, TLS_CFG_KEY, "key", srv_conf->tls_key,
>> srv_conf->tls_key_len) != 0)
>> return (-1);
>> @@ -431,6 +439,7 @@ config_getserver_config(struct httpd *en
>>
>> f = SRVFLAG_TLS;
>> srv_conf->flags |= parent->flags & f;
>> + srv_conf->tls_flags = parent->tls_flags;
>>
>> f = SRVFLAG_ACCESS_LOG;
>> if ((srv_conf->flags & f) == 0) {
>> @@ -655,9 +664,21 @@ config_getserver_tls(struct httpd *env,
>> }
>>
>> switch (tls_conf.tls_type) {
>> + case TLS_CFG_CA:
>> + if (config_gettls(env, srv_conf, &tls_conf, "ca", p, len,
>> + &srv_conf->tls_ca, &srv_conf->tls_ca_len) != 0)
>> + goto fail;
>> + break;
>> +
>> case TLS_CFG_CERT:
>> if (config_gettls(env, srv_conf, &tls_conf, "cert", p, len,
>> &srv_conf->tls_cert, &srv_conf->tls_cert_len) != 0)
>> + goto fail;
>> + break;
>> +
>> + case TLS_CFG_CRL:
>> + if (config_gettls(env, srv_conf, &tls_conf, "crl", p, len,
>> + &srv_conf->tls_crl, &srv_conf->tls_crl_len) != 0)
>> goto fail;
>> break;
>>
>> Index: httpd.conf.5
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v
>> retrieving revision 1.90
>> diff -u -p -r1.90 httpd.conf.5
>> --- httpd.conf.5 11 Apr 2018 15:50:46 -0000 1.90
>> +++ httpd.conf.5 16 May 2018 07:59:10 -0000
>> @@ -342,6 +342,10 @@ The revision of the HTTP specification u
>> .It Ic SERVER_SOFTWARE
>> The server software name of
>> .Xr httpd 8 .
>> +.It Ic TLS_PEER_VERIFY
>> +A variable that is set to a comma separated list of TLS client verification
>> +features in use
>> +.Pq omitted when TLS client verification is not in use .
>> .El
>> .It Ic hsts Oo Ar option Oc
>> Enable HTTP Strict Transport Security.
>> @@ -526,6 +530,23 @@ will be used (strong crypto cipher suite
>> See the CIPHERS section of
>> .Xr openssl 1
>> for information about SSL/TLS cipher suites and preference lists.
>> +.It Ic client ca Ar cafile Oo Ic crl Ar crlfile Oc Op Ic optional
>> +Require
>> +.Po
>> +or, if
>> +.Ic optional
>> +is specified, request but do not require
>> +.Pc
>> +TLS client certificates whose authenticity can be verified
>> +against the CA certificate(s) in
>> +.Ar cafile
>> +in order to proceed beyond the TLS handshake.
>> +With
>> +.Ic crl
>> +specified, additionally require that no certificate in the client chain be
>> +listed as revoked in the CRL(s) in
>> +.Ar crlfile .
>> +CA certificates and CRLs should be PEM encoded.
>> .It Ic dhe Ar params
>> Specify the DHE parameters to use for DHE cipher suites.
>> Valid parameter values are none, legacy and auto.
>> Index: httpd.h
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
>> retrieving revision 1.136
>> diff -u -p -r1.136 httpd.h
>> --- httpd.h 11 Apr 2018 15:50:46 -0000 1.136
>> +++ httpd.h 16 May 2018 07:59:10 -0000
>> @@ -424,6 +424,11 @@ SPLAY_HEAD(client_tree, client);
>> #define HSTSFLAG_PRELOAD 0x02
>> #define HSTSFLAG_BITS "\10\01SUBDOMAINS\02PRELOAD"
>>
>> +#define TLSFLAG_CA 0x01
>> +#define TLSFLAG_CRL 0x02
>> +#define TLSFLAG_OPTIONAL 0x04
>> +#define TLSFLAG_BITS "\10\01CA\02CRL\3OPTIONAL"
>> +
>> enum log_format {
>> LOG_FORMAT_COMMON,
>> LOG_FORMAT_COMBINED,
>> @@ -480,12 +485,19 @@ struct server_config {
>> uint32_t maxrequests;
>> size_t maxrequestbody;
>>
>> + uint8_t *tls_ca;
>> + char *tls_ca_file;
>> + size_t tls_ca_len;
>> uint8_t *tls_cert;
>> size_t tls_cert_len;
>> char *tls_cert_file;
>> char tls_ciphers[HTTPD_TLS_CONFIG_MAX];
>> + uint8_t *tls_crl;
>> + char *tls_crl_file;
>> + size_t tls_crl_len;
>> char tls_dhe_params[HTTPD_TLS_CONFIG_MAX];
>> char tls_ecdhe_curves[HTTPD_TLS_CONFIG_MAX];
>> + uint8_t tls_flags;
>> uint8_t *tls_key;
>> size_t tls_key_len;
>> char *tls_key_file;
>> @@ -524,7 +536,9 @@ struct server_config {
>> TAILQ_HEAD(serverhosts, server_config);
>>
>> enum tls_config_type {
>> + TLS_CFG_CA,
>> TLS_CFG_CERT,
>> + TLS_CFG_CRL,
>> TLS_CFG_KEY,
>> TLS_CFG_OCSP_STAPLE,
>> };
>> @@ -598,6 +612,8 @@ int cmdline_symset(char *);
>> /* server.c */
>> void server(struct privsep *, struct privsep_proc *);
>> int server_tls_cmp(struct server *, struct server *, int);
>> +int server_tls_load_ca(struct server *);
>> +int server_tls_load_crl(struct server *);
>> int server_tls_load_keypair(struct server *);
>> int server_tls_load_ocsp(struct server *);
>> void server_generate_ticket_key(struct server_config *);
>> Index: parse.y
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
>> retrieving revision 1.94
>> diff -u -p -r1.94 parse.y
>> --- parse.y 26 Apr 2018 14:12:19 -0000 1.94
>> +++ parse.y 16 May 2018 07:59:11 -0000
>> @@ -134,6 +134,7 @@ typedef struct {
>> %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP
>> TICKET
>> %token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD
>> REQUEST
>> %token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
>> +%token CA CLIENT CRL OPTIONAL
>> %token <v.string> STRING
>> %token <v.number> NUMBER
>> %type <v.port> port
>> @@ -345,6 +346,22 @@ server : SERVER optmatch STRING {
>> YYERROR;
>> }
>>
>> + if (server_tls_load_ca(srv) == -1) {
>> + yyerror("server \"%s\": failed to load "
>> + "ca cert(s)", srv->srv_conf.name);
>> + serverconfig_free(srv_conf);
>> + free(srv);
>> + YYERROR;
>> + }
>> +
>> + if (server_tls_load_crl(srv) == -1) {
>> + yyerror("server \"%s\": failed to load crl(s)",
>> + srv->srv_conf.name);
>> + serverconfig_free(srv_conf);
>> + free(srv);
>> + YYERROR;
>> + }
>> +
>> if (server_tls_load_ocsp(srv) == -1) {
>> yyerror("server \"%s\": failed to load "
>> "ocsp staple", srv->srv_conf.name);
>> @@ -587,6 +604,7 @@ serveroptsl : LISTEN ON STRING opttls po
>> sizeof(s->srv_conf.ss));
>> s->srv_conf.port = srv->srv_conf.port;
>> s->srv_conf.prefixlen = srv->srv_conf.prefixlen;
>> + s->srv_conf.tls_flags = srv->srv_conf.tls_flags;
>>
>> if (last_server_id == INT_MAX) {
>> yyerror("too many servers/locations defined");
>> @@ -760,6 +778,13 @@ tlsopts : CERTIFICATE STRING {
>> }
>> free($2);
>> }
>> + | CLIENT CA STRING tlsclientopt {
>> + srv_conf->tls_flags |= TLSFLAG_CA;
>> + free(srv_conf->tls_ca_file);
>> + if ((srv_conf->tls_ca_file = strdup($3)) == NULL)
>> + fatal("out of memory");
>> + free($3);
>> + }
>> | DHE STRING {
>> if (strlcpy(srv_conf->tls_dhe_params, $2,
>> sizeof(srv_conf->tls_dhe_params)) >=
>> @@ -808,6 +833,18 @@ tlsopts : CERTIFICATE STRING {
>> }
>> ;
>>
>> +tlsclientopt : /* empty */
>> + | tlsclientopt CRL STRING {
>> + srv_conf->tls_flags = TLSFLAG_CRL;
>> + free(srv_conf->tls_crl_file);
>> + if ((srv_conf->tls_crl_file = strdup($3)) == NULL)
>> + fatal("out of memory");
>> + free($3);
>> + }
>> + | tlsclientopt OPTIONAL {
>> + srv_conf->tls_flags |= TLSFLAG_OPTIONAL;
>> + }
>> + ;
>> root : ROOT rootflags
>> | ROOT '{' optnl rootflags_l '}'
>> ;
>> @@ -1240,12 +1277,15 @@ lookup(char *s)
>> { "block", BLOCK },
>> { "body", BODY },
>> { "buffer", BUFFER },
>> + { "ca", CA },
>> { "certificate", CERTIFICATE },
>> { "chroot", CHROOT },
>> { "ciphers", CIPHERS },
>> + { "client", CLIENT },
>> { "combined", COMBINED },
>> { "common", COMMON },
>> { "connection", CONNECTION },
>> + { "crl", CRL },
>> { "default", DEFAULT },
>> { "dhe", DHE },
>> { "directory", DIRECTORY },
>> @@ -1270,6 +1310,7 @@ lookup(char *s)
>> { "nodelay", NODELAY },
>> { "ocsp", OCSP },
>> { "on", ON },
>> + { "optional", OPTIONAL },
>> { "pass", PASS },
>> { "port", PORT },
>> { "prefork", PREFORK },
>> @@ -2100,6 +2141,21 @@ server_inherit(struct server *src, struc
>> serverconfig_free(&dst->srv_conf);
>> free(dst);
>> return (NULL);
>> + }
>> +
>> + if (server_tls_load_ca(dst) == -1) {
>> + yyerror("falied to load ca cert(s) for server %s",
>> + dst->srv_conf.name);
>> + serverconfig_free(&dst->srv_conf);
>> + return NULL;
>> + }
>> +
>> + if (server_tls_load_crl(dst) == -1) {
>> + yyerror("failed to load crl(s) for server %s",
>> + dst->srv_conf.name);
>> + serverconfig_free(&dst->srv_conf);
>> + free(dst);
>> + return NULL;
>> }
>>
>> if (server_tls_load_ocsp(dst) == -1) {
>> Index: server.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/server.c,v
>> retrieving revision 1.113
>> diff -u -p -r1.113 server.c
>> --- server.c 29 Nov 2017 16:55:08 -0000 1.113
>> +++ server.c 16 May 2018 07:59:11 -0000
>> @@ -134,6 +134,8 @@ server_tls_cmp(struct server *s1, struct
>> sc1 = &s1->srv_conf;
>> sc2 = &s2->srv_conf;
>>
>> + if (sc1->tls_flags != sc2->tls_flags)
>> + return (-1);
>> if (sc1->tls_protocols != sc2->tls_protocols)
>> return (-1);
>> if (sc1->tls_ticket_lifetime != sc2->tls_ticket_lifetime)
>> @@ -207,6 +209,40 @@ server_tls_load_ocsp(struct server *srv)
>> }
>>
>> int
>> +server_tls_load_ca(struct server *srv)
>> +{
>> + if ((srv->srv_conf.tls_flags & TLSFLAG_CA) == 0 ||
>> + srv->srv_conf.tls_ca_file == NULL)
>> + return (0);
>> +
>> + if ((srv->srv_conf.tls_ca = tls_load_file(
>> + srv->srv_conf.tls_ca_file,
>> + &srv->srv_conf.tls_ca_len, NULL)) == NULL)
>> + return (-1);
>> + log_debug("%s: using ca cert(s) from %s", __func__,
>> + srv->srv_conf.tls_ca_file);
>> +
>> + return (0);
>> +}
>> +
>> +int
>> +server_tls_load_crl(struct server *srv)
>> +{
>> + if ((srv->srv_conf.tls_flags & TLSFLAG_CA) == 0 ||
>> + srv->srv_conf.tls_crl_file == NULL)
>> + return (0);
>> +
>> + if ((srv->srv_conf.tls_crl = tls_load_file(
>> + srv->srv_conf.tls_crl_file,
>> + &srv->srv_conf.tls_crl_len, NULL)) == NULL)
>> + return (-1);
>> + log_debug("%s: using crl(s) from %s", __func__,
>> + srv->srv_conf.tls_crl_file);
>> +
>> + return (0);
>> +}
>> +
>> +int
>> server_tls_init(struct server *srv)
>> {
>> struct server_config *srv_conf;
>> @@ -264,6 +300,27 @@ server_tls_init(struct server *srv)
>> return (-1);
>> }
>>
>> + if (srv->srv_conf.tls_ca != NULL) {
>> + if (tls_config_set_ca_mem(srv->srv_tls_config,
>> + srv->srv_conf.tls_ca, srv->srv_conf.tls_ca_len) != 0) {
>> + log_warnx("%s: failed to add ca cert(s)", __func__);
>> + return (-1);
>> + }
>> + if (srv->srv_conf.tls_flags & TLSFLAG_OPTIONAL)
>> + tls_config_verify_client_optional(srv->srv_tls_config);
>> + else
>> + tls_config_verify_client(srv->srv_tls_config);
>> +
>> + if (srv->srv_conf.tls_crl != NULL) {
>> + if (tls_config_set_crl_mem(srv->srv_tls_config,
>> + srv->srv_conf.tls_crl,
>> + srv->srv_conf.tls_crl_len) != 0) {
>> + log_warnx("%s: failed to add crl(s)", __func__);
>> + return (-1);
>> + }
>> + }
>> + }
>> +
>> TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
>> if (srv_conf->tls_cert == NULL || srv_conf->tls_key == NULL)
>> continue;
>> @@ -277,6 +334,26 @@ server_tls_init(struct server *srv)
>> log_warnx("%s: failed to add tls keypair", __func__);
>> return (-1);
>> }
>> +
>> + if (srv->srv_conf.tls_ca == NULL)
>> + continue;
>> + log_debug("%s: adding ca cert(s) for server %s", __func__,
>> + srv->srv_conf.name);
>> + if (tls_config_set_ca_mem(srv->srv_tls_config,
>> + srv_conf->tls_ca, srv_conf->tls_ca_len) != 0) {
>> + log_warnx("%s: failed to add ca cert(s)", __func__);
>> + return (-1);
>> + }
>> +
>> + if (srv->srv_conf.tls_crl == NULL)
>> + continue;
>> +
>> + log_debug("%s: adding crl(s) for server %s", __func__,
>> + srv->srv_conf.name);
>> + if (tls_config_set_crl_mem(srv->srv_tls_config,
>> + srv_conf->tls_crl, srv_conf->tls_crl_len) != 0) {
>> + return (-1);
>> + }
>> }
>>
>> /* set common session ID among all processes */
>> @@ -310,13 +387,19 @@ server_tls_init(struct server *srv)
>> return (-1);
>> }
>>
>> - /* We're now done with the public/private key... */
>> + /* We're now done with the public/private key & ca/crl... */
>> tls_config_clear_keys(srv->srv_tls_config);
>> freezero(srv->srv_conf.tls_cert, srv->srv_conf.tls_cert_len);
>> freezero(srv->srv_conf.tls_key, srv->srv_conf.tls_key_len);
>> + free(srv->srv_conf.tls_ca);
>> + free(srv->srv_conf.tls_crl);
>> + srv->srv_conf.tls_ca = NULL;
>> srv->srv_conf.tls_cert = NULL;
>> + srv->srv_conf.tls_crl = NULL;
>> srv->srv_conf.tls_key = NULL;
>> + srv->srv_conf.tls_ca_len = 0;
>> srv->srv_conf.tls_cert_len = 0;
>> + srv->srv_conf.tls_crl_len = 0;
>> srv->srv_conf.tls_key_len = 0;
>>
>> return (0);
>> @@ -422,7 +505,11 @@ void
>> serverconfig_free(struct server_config *srv_conf)
>> {
>> free(srv_conf->return_uri);
>> + free(srv_conf->tls_ca_file);
>> + free(srv_conf->tls_ca);
>> free(srv_conf->tls_cert_file);
>> + free(srv_conf->tls_crl_file);
>> + free(srv_conf->tls_crl);
>> free(srv_conf->tls_key_file);
>> free(srv_conf->tls_ocsp_staple_file);
>> free(srv_conf->tls_ocsp_staple);
>> @@ -435,8 +522,12 @@ serverconfig_reset(struct server_config
>> {
>> srv_conf->auth = NULL;
>> srv_conf->return_uri = NULL;
>> + srv_conf->tls_ca = NULL;
>> + srv_conf->tls_ca_file = NULL;
>> srv_conf->tls_cert = NULL;
>> srv_conf->tls_cert_file = NULL;
>> + srv_conf->tls_crl = NULL;
>> + srv_conf->tls_crl_file = NULL;
>> srv_conf->tls_key = NULL;
>> srv_conf->tls_key_file = NULL;
>> srv_conf->tls_ocsp_staple = NULL;
>> Index: server_fcgi.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/httpd/server_fcgi.c,v
>> retrieving revision 1.75
>> diff -u -p -r1.75 server_fcgi.c
>> --- server_fcgi.c 31 Jul 2017 08:02:49 -0000 1.75
>> +++ server_fcgi.c 16 May 2018 07:59:12 -0000
>> @@ -282,11 +282,18 @@ server_fcgi(struct httpd *env, struct cl
>> goto fail;
>> }
>>
>> - if (srv_conf->flags & SRVFLAG_TLS)
>> + if (srv_conf->flags & SRVFLAG_TLS) {
>> if (fcgi_add_param(¶m, "HTTPS", "on", clt) == -1) {
>> errstr = "failed to encode param";
>> goto fail;
>> }
>> + if (srv_conf->tls_flags != 0 && fcgi_add_param(¶m,
>> + "TLS_PEER_VERIFY", printb_flags(srv_conf->tls_flags,
>> + TLSFLAG_BITS), clt) == -1) {
>> + errstr = "failed to encode param";
>> + goto fail;
>> + }
>> + }
>>
>> (void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf));
>> if (fcgi_add_param(¶m, "REMOTE_ADDR", hbuf, clt) == -1) {
>>
>