On Tue, 8 Aug 2017 15:10:36 +0930
Jack Burton <j...@saosce.com.au> wrote:
> On Tue, 08 Aug 2017 14:23:02 +1000
> Joel Sing <j...@sing.id.au> wrote:
> > On Saturday 29 July 2017 20:49:18 Jan Klemkow wrote:
> > > In the End, I found and fixed the real bug here:
> > > 
> > > @@ -430,7 +438,11 @@ config_getserver_config(struct httpd *en
> > >                 }
> > > 
> > >                 f = SRVFLAG_TLS;
> > > -               srv_conf->flags |= parent->flags & f;
> > > +               if ((srv_conf->flags & f) == 0) {
> > > +                       srv_conf->flags |= parent->flags & f;
> > > +                       srv_conf->tls_ca = parent->tls_ca;
> > > +                       srv_conf->tls_crl = parent->tls_crl;    
> > 
> > I'd have to double check, however I'm pretty sure that this will
> > result in a double-free since you're copying the pointer (without a
> > reference count) across server config structs. Both will likely be
> > passed to serverconfig_free(), which means free() will then be
> > passed the same pointer twice.  
> 
> You're absolutely right. That happens when purging config on reload,
> if the old config for a server doing tls client verify has two or more
> location blocks...
> 
> ...and my 30 July diff suffers from the same problem.
<...>
> Perhaps a better alternative would be to free the CA & CRL mem at the
> end of server_tls_init() -- like we do already for the key pair --
> then add flags for CA & CRL use instead of just checking for null
> pointers everywhere (as both my & Jan's diffs have been doing so far).
> 
> It seems I have a couple of other changes to make too, so will roll
> something like that in with them & post a revised diff later today or
> tomorrow.

Okay, here's a further revised diff that takes the approach I proposed
above to fixing the bug that Joel pointed out and also makes a few
other small changes that were suggested to me off list:
* the tls client ca directive now has an "optional" option (to request
  a client cert but not require it);
* the extra bit string I got rid off a diff or two ago is back again,
  now passed through to fcgi as TLS_PEER_VERIFY (since there are now
  multiple possible modes of operation for tls client certs, so fcgi
  responders should have some way of knowing which are in use);
* reworded the descriptions of the TLS_PEER_* fcgi vars in
  httpd.conf(5); and
* fixed a minor typo in httpd.conf(5) that my earlier diff
  had introduced.

Thoughts?

Index: usr.sbin/httpd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/config.c,v
retrieving revision 1.53
diff -u -p -r1.53 config.c
--- usr.sbin/httpd/config.c     19 Jul 2017 17:36:25 -0000      1.53
+++ usr.sbin/httpd/config.c     8 Aug 2017 12:36:19 -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->tlsflags = parent->tlsflags;
 
                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: usr.sbin/httpd/httpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v
retrieving revision 1.82
diff -u -p -r1.82 httpd.conf.5
--- usr.sbin/httpd/httpd.conf.5 9 Apr 2017 09:13:28 -0000       1.82
+++ usr.sbin/httpd/httpd.conf.5 8 Aug 2017 12:36:19 -0000
@@ -342,7 +342,37 @@ The revision of the HTTP specification u
 .It Ic SERVER_SOFTWARE
 The server software name of
 .Xr httpd 8 .
+.It Ic TLS_PEER_CHAIN
+The TLS client certificate chain, PEM encoded, with newlines translated to
+tabs.
+.It Ic TLS_PEER_EXPIRES
+The time at which the TLS client certificate expires, in seconds since the
+epoch.
+.It Ic TLS_PEER_HASH
+A hash of the TLS client certificate.
+See
+.Xr tls_peer_cert_hash 3 .
+.It Ic TLS_PEER_ISSUER
+The issuer of the TLS client certificate.
+.It Ic TLS_PEER_OCSP_URL
+The OCSP URL from the TLS client certificate.
+.It Ic TLS_PEER_SUBJECT
+The subject of the TLS client certificate.
+.It Ic TLS_PEER_VERIFY
+A variable that is set to a comma separated list of TLS client verification
+features in use.
 .El
+.Pp
+All
+.Ic TLS_PEER_*
+variables are omitted if TLS client verification is not in use.
+All except
+.Ic TLS_PEER_VERIFY
+are also omitted if no TLS client certificate is offered when the
+.Ic optional
+argument to the
+.Ic tls client ca
+directive is in use.
 .It Ic hsts Oo Ar option Oc
 Enable HTTP Strict Transport Security.
 Valid options are:
@@ -526,6 +556,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.
@@ -688,6 +735,7 @@ server "www.example.com" {
 .Ed
 .Sh SEE ALSO
 .Xr htpasswd 1 ,
+.Xr tls_peer_cert_hash 3 ,
 .Xr patterns 7 ,
 .Xr httpd 8 ,
 .Xr ocspcheck 8 ,
Index: usr.sbin/httpd/httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.133
diff -u -p -r1.133 httpd.h
--- usr.sbin/httpd/httpd.h      19 Jul 2017 17:36:25 -0000      1.133
+++ usr.sbin/httpd/httpd.h      8 Aug 2017 12:36:19 -0000
@@ -420,6 +420,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\03OPTIONAL"
+
 enum log_format {
        LOG_FORMAT_COMMON,
        LOG_FORMAT_COMBINED,
@@ -476,9 +481,15 @@ 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;
+       uint8_t                 *tls_crl;
+       char                    *tls_crl_file;
+       size_t                   tls_crl_len;
        char                     tls_ciphers[NAME_MAX];
        char                     tls_dhe_params[NAME_MAX];
        char                     tls_ecdhe_curve[NAME_MAX];
@@ -491,6 +502,7 @@ struct server_config {
        char                    *tls_ocsp_staple_file;
        struct server_tls_ticket tls_ticket_key;
        int                      tls_ticket_lifetime;
+       uint8_t                  tlsflags;
 
        uint32_t                 flags;
        int                      strip;
@@ -520,7 +532,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,
 };
@@ -594,6 +608,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: usr.sbin/httpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
retrieving revision 1.90
diff -u -p -r1.90 parse.y
--- usr.sbin/httpd/parse.y      25 Mar 2017 17:25:34 -0000      1.90
+++ usr.sbin/httpd/parse.y      8 Aug 2017 12:36:20 -0000
@@ -135,6 +135,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
@@ -344,6 +345,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);
@@ -564,6 +581,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.tlsflags = srv->srv_conf.tlsflags;
 
                        if (last_server_id == INT_MAX) {
                                yyerror("too many servers/locations defined");
@@ -737,6 +755,13 @@ tlsopts            : CERTIFICATE STRING            {
                        }
                        free($2);
                }
+               | CLIENT CA STRING tlsclientopt {
+                       srv_conf->tlsflags |= 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)) >=
@@ -785,6 +810,19 @@ tlsopts            : CERTIFICATE STRING            {
                }
                ;
 
+tlsclientopt   : /* empty */
+               | tlsclientopt CRL STRING       {
+                       srv_conf->tlsflags |= 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->tlsflags |= TLSFLAG_OPTIONAL;
+               }
+               ;
+
 root           : ROOT rootflags
                | ROOT '{' optnl rootflags_l '}'
                ;
@@ -1217,12 +1255,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 },
@@ -1247,6 +1288,7 @@ lookup(char *s)
                { "nodelay",            NODELAY },
                { "ocsp",               OCSP },
                { "on",                 ON },
+               { "optional",           OPTIONAL },
                { "pass",               PASS },
                { "port",               PORT },
                { "prefork",            PREFORK },
@@ -2087,6 +2129,22 @@ server_inherit(struct server *src, struc
 
        if (server_tls_load_keypair(dst) == -1) {
                yyerror("failed to load public/private keys "
+                   "for server %s", dst->srv_conf.name);
+               serverconfig_free(&dst->srv_conf);
+               free(dst);
+               return (NULL);
+       }
+
+       if (server_tls_load_ca(dst) == -1) {
+               yyerror("failed to load ca cert(s) "
+                   "for server %s", dst->srv_conf.name);
+               serverconfig_free(&dst->srv_conf);
+               free(dst);
+               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);
Index: usr.sbin/httpd/server.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server.c,v
retrieving revision 1.110
diff -u -p -r1.110 server.c
--- usr.sbin/httpd/server.c     19 Jul 2017 17:36:25 -0000      1.110
+++ usr.sbin/httpd/server.c     8 Aug 2017 12:36:20 -0000
@@ -134,6 +134,8 @@ server_tls_cmp(struct server *s1, struct
        sc1 = &s1->srv_conf;
        sc2 = &s2->srv_conf;
 
+       if (sc1->tlsflags != sc2->tlsflags)
+               return (-1);
        if (sc1->tls_protocols != sc2->tls_protocols)
                return (-1);
        if (sc1->tls_ticket_lifetime != sc2->tls_ticket_lifetime)
@@ -197,6 +199,40 @@ server_tls_load_ocsp(struct server *srv)
 }
 
 int
+server_tls_load_ca(struct server *srv)
+{
+       if ((srv->srv_conf.tlsflags & 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.tlsflags & TLSFLAG_CRL) == 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;
@@ -254,6 +290,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.tlsflags & 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;
@@ -267,6 +324,28 @@ 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) {
+                       log_warnx("%s: failed to add crl(s)", __func__);
+                       return (-1);
+               }
        }
 
        /* set common session ID among all processes */
@@ -300,13 +379,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);
@@ -412,7 +497,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);
@@ -425,8 +514,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: usr.sbin/httpd/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
--- usr.sbin/httpd/server_fcgi.c        31 Jul 2017 08:02:49 -0000      1.75
+++ usr.sbin/httpd/server_fcgi.c        8 Aug 2017 12:36:20 -0000
@@ -93,11 +93,12 @@ server_fcgi(struct httpd *env, struct cl
        struct fcgi_record_header       *h;
        struct fcgi_begin_request_body  *begin;
        char                             hbuf[HOST_NAME_MAX+1];
-       size_t                           scriptlen;
+       size_t                           chainlen, scriptlen;
        int                              pathlen;
        int                              fd = -1, ret;
        const char                      *stripped, *p, *alias, *errstr = NULL;
-       char                            *str, *script = NULL;
+       char                            *chainc, *chainp, *str, *script = NULL;
+       const uint8_t                   *chain;
 
        if (srv_conf->socket[0] == ':') {
                struct sockaddr_storage  ss;
@@ -282,11 +283,58 @@ 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(&param, "HTTPS", "on", clt) == -1) {
                        errstr = "failed to encode param";
                        goto fail;
                }
+               if ((srv_conf->tlsflags & TLSFLAG_CA) &&
+                   (chain = tls_peer_cert_chain_pem(clt->clt_tls_ctx,
+                   &chainlen)) != NULL) {
+                       if ((chainc = strndup(chain, chainlen)) == NULL)
+                               goto fail;
+                       chainp = chainc;
+                       while ((chainp = strchr(chainp, '\n')) != NULL)
+                               *chainp = '\t';
+                       ret = fcgi_add_param(&param, "TLS_PEER_CHAIN", chainc,
+                           clt);
+                       free(chainc);
+                       if (ret == -1) {
+                               errstr = "failed to encode param";
+                               goto fail;
+                       }
+                       if (fcgi_add_param(&param, "TLS_PEER_SUBJECT",
+                           tls_peer_cert_subject(clt->clt_tls_ctx), clt) == -1
+                           || fcgi_add_param(&param, "TLS_PEER_ISSUER",
+                           tls_peer_cert_issuer(clt->clt_tls_ctx), clt) == -1
+                           || fcgi_add_param(&param, "TLS_PEER_HASH",
+                           tls_peer_cert_hash(clt->clt_tls_ctx), clt) == -1) {
+                               errstr = "failed to encode param";
+                               goto fail;
+                       }
+                       if (asprintf(&str, "%lld",
+                           tls_peer_cert_notafter(clt->clt_tls_ctx)) == -1
+                           || fcgi_add_param(&param, "TLS_PEER_EXPIRES", str,
+                           clt) == -1) {
+                               errstr = "failed to encode param";
+                               goto fail;
+                       }
+                       free(str);
+                       str = NULL;
+                       if (tls_peer_ocsp_url(clt->clt_tls_ctx) != NULL
+                           && fcgi_add_param(&param, "TLS_PEER_OCSP_URL",
+                           tls_peer_ocsp_url(clt->clt_tls_ctx), clt) == -1) {
+                               errstr = "failed to encode param";
+                               goto fail;
+                       }
+               }
+               if (srv_conf->tlsflags != 0 && fcgi_add_param(&param,
+                   "TLS_PEER_VERIFY", printb_flags(srv_conf->tlsflags,
+                   TLSFLAG_BITS), clt) == -1) {
+                       errstr = "failed to encode param";
+                       goto fail;
+               }
+       }
 
        (void)print_host(&clt->clt_ss, hbuf, sizeof(hbuf));
        if (fcgi_add_param(&param, "REMOTE_ADDR", hbuf, clt) == -1) {
Index: regress/usr.sbin/httpd/tests/Client.pm
===================================================================
RCS file: /cvs/src/regress/usr.sbin/httpd/tests/Client.pm,v
retrieving revision 1.1
diff -u -p -r1.1 Client.pm
--- regress/usr.sbin/httpd/tests/Client.pm      16 Jul 2015 16:35:57 -0000      
1.1
+++ regress/usr.sbin/httpd/tests/Client.pm      8 Aug 2017 12:36:20 -0000
@@ -59,6 +59,11 @@ sub child {
            PeerAddr            => $self->{connectaddr},
            PeerPort            => $self->{connectport},
            SSL_verify_mode     => SSL_VERIFY_NONE,
+           SSL_use_cert        => $self->{offertlscert} ? 1 : 0,
+           SSL_cert_file       => $self->{offertlscert} ?
+                                       $self->{chroot}."/client.crt" : "",
+           SSL_key_file        => $self->{offertlscert} ?
+                                       $self->{chroot}."/client.key" : "",
        ) or die ref($self), " $iosocket socket connect failed: $!,$SSL_ERROR";
        print STDERR "connect sock: ",$cs->sockhost()," ",$cs->sockport(),"\n";
        print STDERR "connect peer: ",$cs->peerhost()," ",$cs->peerport(),"\n";
Index: regress/usr.sbin/httpd/tests/Httpd.pm
===================================================================
RCS file: /cvs/src/regress/usr.sbin/httpd/tests/Httpd.pm,v
retrieving revision 1.2
diff -u -p -r1.2 Httpd.pm
--- regress/usr.sbin/httpd/tests/Httpd.pm       30 Jan 2017 21:18:24 -0000      
1.2
+++ regress/usr.sbin/httpd/tests/Httpd.pm       8 Aug 2017 12:36:20 -0000
@@ -72,6 +72,8 @@ sub new {
            print $fh "\n";
            print $fh "\ttls certificate \"".$args{chroot}."/server.crt\"\n";
            print $fh "\ttls key \"".$args{chroot}."/server.key\"";
+           $self->{verifytls}
+               and print $fh "\ntls client ca \"".$args{chroot}."/ca.crt\"";
        }
        print $fh "\n\troot \"/\"";
        print $fh "\n\tlog style combined";
Index: regress/usr.sbin/httpd/tests/Makefile
===================================================================
RCS file: /cvs/src/regress/usr.sbin/httpd/tests/Makefile,v
retrieving revision 1.8
diff -u -p -r1.8 Makefile
--- regress/usr.sbin/httpd/tests/Makefile       14 Jul 2017 13:31:44 -0000      
1.8
+++ regress/usr.sbin/httpd/tests/Makefile       8 Aug 2017 12:36:20 -0000
@@ -77,10 +77,16 @@ ca.crt:
 server.req:
        openssl req -batch -new -subj 
/L=OpenBSD/O=httpd-regress/OU=server/CN=localhost/ -nodes -newkey rsa -keyout 
server.key -out server.req
 
+client.req:
+       openssl req -batch -new -subj 
/L=OpenBSD/O=httpd-regress/OU=client/CN=localhost/ -nodes -newkey rsa -keyout 
client.key -out $@
+
 server.crt: ca.crt server.req
        openssl x509 -CAcreateserial -CAkey ca.key -CA ca.crt -req -in 
server.req -out server.crt
 
-${REGRESS_TARGETS:M*tls*} ${REGRESS_TARGETS:M*https*}: server.crt
+client.crt: ca.crt client.req
+       openssl x509 -CAcreateserial -CAkey ca.key -CA ca.crt -req -in 
client.req -out $@
+
+${REGRESS_TARGETS:M*tls*} ${REGRESS_TARGETS:M*https*}: server.crt client.crt
 
 # make perl syntax check for all args files
 
Index: regress/usr.sbin/httpd/tests/args-tls-verify.pl
===================================================================
RCS file: regress/usr.sbin/httpd/tests/args-tls-verify.pl
diff -N regress/usr.sbin/httpd/tests/args-tls-verify.pl
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/usr.sbin/httpd/tests/args-tls-verify.pl     8 Aug 2017 12:36:20 
-0000
@@ -0,0 +1,20 @@
+# test https connection, verifying client cert
+
+use strict;
+use warnings;
+
+our %args = (
+    client => {
+       tls => 1,
+       offertlscert => 1,
+       loggrep => 'Issuer.*/OU=ca/',
+    },
+    httpd => {
+       listentls => 1,
+       verifytls => 1,
+    },
+    len => 512,
+    md5 => path_md5("512")
+);
+
+1;

Reply via email to