Download raw body.
[PATCH] relayd client certificate validation again
Hi!
When we (me and Rivo) got the patch ready and submitted it, there simply
didn't get any replies from the maintainers. IIRC, I did try to direct
attention to it more than once but with no success. (I also understand that
people do this for free, so assumed they were busy with other things.)
I still think the feature is useful, and also that adapting the patch to
the latest version of relayd wouldn't be that difficult.
On Mon, Sep 30, 2024 at 7:57 PM Sören Tempel <soeren@soeren-tempel.net>
wrote:
> Hello!
>
> Is there a reason why this patch never got a review? The feature (TLS
> client certificate validation within relayd) seems to be requested
> frequently [1]. I just came across this while looking into working on
> such a patch myself.
>
> Is the feature not deemed useful, or is the patch not in a good shape?
> If the latter is the case, I would be willing to revise the patch.
>
> I would also be fine with just implementing the validation part without
> adding the capability to forward the validated certificate, which should
> shrink the patchset a bit.
>
> Cheers
> Sören
>
> [1]: https://marc.info/?t=154295268000001&r=1&w=2
>
> Markus Läll <markus.l2ll@gmail.com> wrote:
> > Hi, we've got the patch ready for client certificate validation, cc'ing
> > related people.
> >
> > The patch adds two features:
> > 1. client certificate validation itself
> > 2. passing on certificate and select fields in HTTP headers
> >
> >
> > ## Brief description of client certificates (for whoever else is reading)
> >
> > Client certificates, also known as mutual authentication, are the reverse
> > to TLS server certificates (like letsencrypt) where the server
> > authenticates the user instead of the other way around.
> >
> > In principle client certificates work as follows:
> > - the server has keypair and a CA certificate created from this keypair
> > - the user has a keypair and submits their public key for certification
> (to
> > being signed by the CA)
> > - the server (relayd) has the CA certificate configured as 'client ca
> > "/path/to/ca.pem"'
> > - the user provides their certificate when connecting, the provided
> > certificate is validated against the CA certificate.
> >
> > How this is set up in practice is up to whoever implements the
> > infrastructure. Client certificates can be installed to operating
> systems'
> > certificate stores (Windows, macOS) where browsers can use them, or into
> > browsers own certificate stores (Firefox has its own), or specified on
> the
> > command line (curl, wget) etc.
> >
> >
> > ## Configuration
> >
> > To turn on client certificate validation add
> >
> > tls { client ca "/path/to/ca-cert.pem" }
> >
> > to relayd.conf.
> >
> > Add "optional" flag to make the certificate not required:
> >
> > tls { client ca "/path/to/cert.pem" optional }
> >
> > With "optional" relayd will succeed in the TLS handshake when no client
> > certificate is provided. But if a certificate *is* provided then it
> *must*
> > validate with the configured CA, otherwise the TLS handshake fails.
> >
> >
> > ## Pass certificate on in HTTP header
> >
> > To pass on the certificate in an url-encoded PEM:
> >
> > match header set "ANY_HEADER_NAME" value "$CLIENT_CERT_CHAIN"
> >
> > With this configuration the downstream can inspect the known-to-be-valid
> > certificate further (e.g extract identity or other info from x509
> > extensions).
> >
> > There was discussion privately on is there any standard for putting
> > certificates in HTTP headers, repeating the reply here as well:
> >
> > There appears to be no standard, but this is how other HTTP servers do
> it:
> > - nginx urlencodes the PEM file with $ssl_client_escaped_cert[1] (this is
> > what is done in this patch too). There is also the $ssl_client_cert
> > variable which adds a tab to each next new line, but this way of doing
> > multiline HTTP headers is deprecated[2]. There is also
> > $ssl_client_raw_cert, but the raw multiline PEM is invalid HTTP header;
> > - envoy also urlencodes the PEM[3];
> > - haproxy has only the binary DER, but base64 encoding it like
> > %[ssl_c_der,base64]) should result in PEM with no newlines and no
> headers;
> > - apache has the %{SSL_CLIENT_CERT} with raw (multiline) PEM[4], which is
> > invalid in HTTP headers, but this can be processed with the escape
> > function[5], something like "expr=3D %{escape:SSL_CLIENT_CERT}"
> >
> > [1]
> >
> https://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_esca=
> > ped_cert
> > [2] https://tools.ietf.org/html/rfc7230#section-3.2.4
> > [3]
> >
> https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_ma=
> > n/headers#x-forwarded-client-cert
> > [4] https://httpd.apache.org/docs/current/mod/mod_ssl.html#envvars
> > [5] https://httpd.apache.org/docs/current/expr.html#functions
> >
> > In addition to extracting the entire certificate, subject and issuer can
> be
> > put to HTTP headers too for convenience:
> >
> > match header set "CS_SUBJECT" value "$CLIENT_CERT_SUBJECT"
> > match header set "CS_ISSUER" value "$CLIENT_CERT_ISSUER"
> >
> >
> >
> > --=20
> > Markus L=C3=A4ll
> >
> > On Thu, Dec 16, 2021 at 11:23 PM rivo nurges <rivo@elnit.ee> wrote:
> >
> > > Hi!
> > >
> > > Here comes the support for relayd client certificate validation.
> > > Full certificate chain, subject and issuer can be passed over in http
> > > headers.
> > > It supports mandatory validation and optional validation(if client
> chooses
> > > to
> > > provide certificate it will be validated).
> > >
> > > Part of my sample config.
> > >
> > > http protocol test {
> > > match header set "CS_SUBJECT" value "$CLIENT_CERT_SUBJECT"
> > > match header set "CS_ISSUER" value "$CLIENT_CERT_ISSUER"
> > > match header set "CS_CERT" value "$CLIENT_CERT_CHAIN"
> > > pass
> > > tls {client ca "/tmp/easyrsa3/pki/ca.crt" optional }
> > > }
> > >
> > > This uses code from the patches submitted by Ashe Connor.
> > >
> > > Rivo
> > >
> > > diff refs/heads/master refs/heads/relay-clc3
> > > blob - a2f1c130d6b45e3082048218c11537dca485998a
> > > blob + 5070a7d48f58403f53d818231e1676db749aa9d7
> > > --- usr.sbin/relayd/config.c
> > > +++ usr.sbin/relayd/config.c
> > > @@ -954,6 +954,15 @@ config_setrelay(struct relayd *env, struct relay
> *rl=
> > ay
> > > rlay->rl_conf.name);
> > > return (-1);
> > > }
> > > + if (rlay->rl_tls_client_ca_fd !=3D -1
> &&
> > > + config_setrelayfd(ps, id, n, 0,
> > > + rlay->rl_conf.id,
> > > RELAY_FD_CLIENTCACERT,
> > > + rlay->rl_tls_client_ca_fd) =3D=3D
> -1)=
> > {
> > > + log_warn("%s: fd passing failed
> > > for "
> > > + "`%s'", __func__,
> > > + rlay->rl_conf.name);
> > > + return (-1);
> > > + }
> > > /* Prevent fd exhaustion in the
> parent. */
> > > if (proc_flush_imsg(ps, id, n) =3D=3D
> -1)=
> > {
> > > log_warn("%s: failed to flush "
> > > @@ -987,6 +996,10 @@ config_setrelay(struct relayd *env, struct relay
> *rl=
> > ay
> > > close(rlay->rl_s);
> > > rlay->rl_s =3D -1;
> > > }
> > > + if (rlay->rl_tls_client_ca_fd !=3D -1) {
> > > + close(rlay->rl_tls_client_ca_fd);
> > > + rlay->rl_tls_client_ca_fd =3D -1;
> > > + }
> > > if (rlay->rl_tls_cacert_fd !=3D -1) {
> > > close(rlay->rl_tls_cacert_fd);
> > > rlay->rl_tls_cacert_fd =3D -1;
> > > @@ -1012,6 +1025,10 @@ config_setrelay(struct relayd *env, struct relay
> > > *rlay
> > > cert->cert_ocsp_fd =3D -1;
> > > }
> > > }
> > > + if (rlay->rl_tls_client_ca_fd !=3D -1) {
> > > + close(rlay->rl_tls_client_ca_fd);
> > > + rlay->rl_tls_client_ca_fd =3D -1;
> > > + }
> > >
> > > return (0);
> > > }
> > > @@ -1034,6 +1051,7 @@ config_getrelay(struct relayd *env, struct imsg
> > > *imsg)
> > > rlay->rl_s =3D imsg->fd;
> > > rlay->rl_tls_ca_fd =3D -1;
> > > rlay->rl_tls_cacert_fd =3D -1;
> > > + rlay->rl_tls_client_ca_fd =3D -1;
> > >
> > > if (ps->ps_what[privsep_process] & CONFIG_PROTOS) {
> > > if (rlay->rl_conf.proto =3D=3D EMPTY_ID)
> > > @@ -1163,6 +1181,9 @@ config_getrelayfd(struct relayd *env, struct imsg
> > > *ims
> > > case RELAY_FD_CAFILE:
> > > rlay->rl_tls_cacert_fd =3D imsg->fd;
> > > break;
> > > + case RELAY_FD_CLIENTCACERT:
> > > + rlay->rl_tls_client_ca_fd =3D imsg->fd;
> > > + break;
> > > }
> > >
> > > DPRINTF("%s: %s %d received relay fd %d type %d for relay %s",
> > > __func__,
> > > blob - 22beb857229a16e5b2c17a25a2944231d41e7e08
> > > blob + fe5e8ff4dfed10e8f09e3226bdfe33f8bc031c8e
> > > --- usr.sbin/relayd/parse.y
> > > +++ usr.sbin/relayd/parse.y
> > > @@ -172,14 +172,14 @@ typedef struct {
> > > %token CODE COOKIE DEMOTE DIGEST DISABLE ERROR EXPECT PASS
> BLOCK
> > > EXTERNAL
> > > %token FILENAME FORWARD FROM HASH HEADER HEADERLEN HOST HTTP
> ICMP
> > > INCLUDE INET
> > > %token INET6 INTERFACE INTERVAL IP KEYPAIR LABEL LISTEN VALUE
> > > LOADBALANCE LOG
> > > -%token LOOKUP METHOD MODE NAT NO DESTINATION NODELAY NOTHING ON PARENT
> > > PATH
> > > +%token LOOKUP METHOD MODE NAT NO DESTINATION NODELAY NOTHING ON
> OPTIONAL
> > > PARENT PATH
> > > %token PFTAG PORT PREFORK PRIORITY PROTO QUERYSTR REAL
> REDIRECT
> > > RELAY REMOVE
> > > %token REQUEST RESPONSE RETRY QUICK RETURN ROUNDROBIN ROUTE
> SACK
> > > SCRIPT SEND
> > > %token SESSION SOCKET SPLICE SSL STICKYADDR STRIP STYLE TABLE
> TAG
> > > TAGGED TCP
> > > %token TIMEOUT TLS TO ROUTER RTLABEL TRANSPARENT URL WITH TTL
> > > RTABLE
> > > %token MATCH PARAMS RANDOM LEASTSTATES SRCHASH KEY CERTIFICATE
> > > PASSWORD ECDHE
> > > %token EDH TICKETS CONNECTION CONNECTIONS CONTEXT ERRORS STATE
> > > CHANGES CHECKS
> > > -%token WEBSOCKETS
> > > +%token WEBSOCKETS CLIENT
> > > %token <v.string> STRING
> > > %token <v.number> NUMBER
> > > %type <v.string> context hostname interface table value path
> > > @@ -188,6 +188,7 @@ typedef struct {
> > > %type <v.number> opttls opttlsclient
> > > %type <v.number> redirect_proto relay_proto match
> > > %type <v.number> action ruleaf key_option
> > > +%type <v.number> clientcaopt
> > > %type <v.port> port
> > > %type <v.host> host
> > > %type <v.addr> address rulesrc ruledst addrprefix
> > > @@ -244,6 +245,10 @@ opttlsclient : /*empty*/ { $$ =3D 0; }
> > > | WITH ssltls { $$ =3D 1; }
> > > ;
> > >
> > > +clientcaopt : /*empty*/ { $$ =3D 0; }
> > > + | OPTIONAL { $$ =3D 1; }
> > > + ;
> > > +
> > > http_type : HTTP { $$ =3D 0; }
> > > | STRING {
> > > if (strcmp("https", $1) =3D=3D 0) {
> > > @@ -1353,6 +1358,19 @@ tlsflags : SESSION TICKETS { proto->tickets =3D
> 1;=
> > }
> > > name->name =3D $2;
> > > TAILQ_INSERT_TAIL(&proto->tlscerts, name,
> entry);
> > > }
> > > + | CLIENT CA STRING clientcaopt {
> > > + if (strlcpy(proto->tlsclientca, $3,
> > > + sizeof(proto->tlsclientca)) >=3D
> > > + sizeof(proto->tlsclientca)) {
> > > + yyerror("tlsclientca truncated");
> > > + free($3);
> > > + YYERROR;
> > > + }
> > > + if ($4) {
> > > + proto->tlsflags |=3D
> > > TLSFLAG_CLIENT_OPTIONAL;
> > > + }
> > > + free($3);
> > > + }
> > > | NO flag { proto->tlsflags &=3D
> > > ~($2); }
> > > | flag { proto->tlsflags |=3D
> $1=
> > ; }
> > > ;
> > > @@ -1824,6 +1842,7 @@ relay : RELAY STRING {
> > > r->rl_conf.dstretry =3D 0;
> > > r->rl_tls_ca_fd =3D -1;
> > > r->rl_tls_cacert_fd =3D -1;
> > > + r->rl_tls_client_ca_fd =3D -1;
> > > TAILQ_INIT(&r->rl_tables);
> > > if (last_relay_id =3D=3D INT_MAX) {
> > > yyerror("too many relays defined");
> > > @@ -2413,6 +2432,7 @@ lookup(char *s)
> > > { "check", CHECK },
> > > { "checks", CHECKS },
> > > { "ciphers", CIPHERS },
> > > + { "client", CLIENT },
> > > { "code", CODE },
> > > { "connection", CONNECTION },
> > > { "context", CONTEXT },
> > > @@ -2458,6 +2478,7 @@ lookup(char *s)
> > > { "nodelay", NODELAY },
> > > { "nothing", NOTHING },
> > > { "on", ON },
> > > + { "optional", OPTIONAL },
> > > { "params", PARAMS },
> > > { "parent", PARENT },
> > > { "pass", PASS },
> > > @@ -3399,6 +3420,7 @@ relay_inherit(struct relay *ra, struct relay *rb)
> > > if (!(rb->rl_conf.flags & F_TLS)) {
> > > rb->rl_tls_cacert_fd =3D -1;
> > > rb->rl_tls_ca_fd =3D -1;
> > > + rb->rl_tls_client_ca_fd =3D -1;
> > > }
> > > TAILQ_INIT(&rb->rl_tables);
> > >
> > > blob - da4a1aa0cc1158b22506c6d81e4d36b8810c025c
> > > blob + 2d16b9d91e594a06d4b1b2bfc791c7f0c861fc57
> > > --- usr.sbin/relayd/relay.c
> > > +++ usr.sbin/relayd/relay.c
> > > @@ -2255,6 +2255,30 @@ relay_tls_ctx_create(struct relay *rlay)
> > > }
> > > rlay->rl_tls_cacert_fd =3D -1;
> > >
> > > + if (rlay->rl_tls_client_ca_fd !=3D -1) {
> > > + if ((buf =3D
> relay_load_fd(rlay->rl_tls_client_ca=
> > _fd,
> > > + &len)) =3D=3D
> > > + NULL) {
> > > + log_warn(
> > > + "failed to read tls client CA
> > > certificate");
> > > + goto err;
> > > + }
> > > +
> > > + if (tls_config_set_ca_mem(tls_cfg, buf, len)
> !=3D=
> > 0)
> > > {
> > > + log_warnx(
> > > + "failed to set tls client CA cert:
> %s=
> > ",
> > > + tls_config_error(tls_cfg));
> > > + goto err;
> > > + }
> > > + purge_key(&buf, len);
> > > +
> > > + if (rlay->rl_proto->tlsflags &
> > > TLSFLAG_CLIENT_OPTIONAL)
> > > +
> tls_config_verify_client_optional(tls_cfg=
> > );
> > > + else
> > > + tls_config_verify_client(tls_cfg);
> > > + }
> > > + rlay->rl_tls_client_ca_fd =3D -1;
> > > +
> > > tls =3D tls_server();
> > > if (tls =3D=3D NULL) {
> > > log_warnx("unable to allocate TLS context");
> > > blob - d493c238813cfc692d83f65a88d4556b2fa35b0f
> > > blob + 58ba35c16ea8d80b36796d977ad7920d3bed3a9c
> > > --- usr.sbin/relayd/relay_http.c
> > > +++ usr.sbin/relayd/relay_http.c
> > > @@ -78,6 +78,7 @@ int relay_match_actions(struct
> > > ctl_relay_event *,
> > > struct relay_table **);
> > > void relay_httpdesc_free(struct http_descriptor *);
> > > char * server_root_strip(char *, int);
> > > +char *url_encode(const char *);
> > >
> > > static struct relayd *env =3D NULL;
> > >
> > > @@ -1279,7 +1280,32 @@ relay_expand_http(struct ctl_relay_event *cre,
> char
> > > *v
> > > if (expand_string(buf, len, "$TIMEOUT", ibuf) !=3D 0)
> > > return (NULL);
> > > }
> > > -
> > > + if (strstr(val, "$CLIENT_CERT_") !=3D NULL &&
> > > tls_peer_cert_provided(cre->tls)) {
> > > + if (strstr(val, "$CLIENT_CERT_SUBJECT") !=3D NULL) {
> > > + if (expand_string(buf, len,
> > > + "$CLIENT_CERT_SUBJECT",
> > > tls_peer_cert_subject(cre->tls)) !=3D 0)
> > > + return (NULL);
> > > + }
> > > + if (strstr(val, "$CLIENT_CERT_ISSUER") !=3D NULL) {
> > > + if (expand_string(buf, len,
> > > + "$CLIENT_CERT_ISSUER",
> > > tls_peer_cert_issuer(cre->tls)) !=3D 0)
> > > + return (NULL);
> > > + }
> > > + if (strstr(val, "$CLIENT_CERT_CHAIN") !=3D NULL) {
> > > + const char *pem;
> > > + char *cbuf;
> > > + size_t plen;
> > > + pem =3D tls_peer_cert_chain_pem(cre->tls,
> &plen);
> > > + cbuf =3D malloc(plen);
> > > + sprintf(cbuf, "%.*s", (int)plen - 1, pem);
> > > + if (expand_string(buf, len,
> > > + "$CLIENT_CERT_CHAIN", url_encode(cbuf))
> !=3D =
> > 0) {
> > > + free(cbuf);
> > > + return (NULL);
> > > + } else
> > > + free(cbuf);
> > > + }
> > > + }
> > > return (buf);
> > > }
> > >
> > > @@ -2045,3 +2071,27 @@ server_root_strip(char *path, int n)
> > > return (path);
> > > }
> > >
> > > +char *
> > > +url_encode(const char *src)
> > > +{
> > > + static char hex[] =3D "0123456789ABCDEF";
> > > + char *dp, *dst;
> > > + unsigned char c;
> > > +
> > > + /* We need 3 times the memory if every letter is encoded. */
> > > + if ((dst =3D calloc(3, strlen(src) + 1)) =3D=3D NULL)
> > > + return (NULL);
> > > +
> > > + for (dp =3D dst; *src !=3D 0; src++) {
> > > + c =3D (unsigned char) *src;
> > > + if (c =3D=3D ' ' || c =3D=3D '#' || c =3D=3D '%' || c
> =3D=
> > =3D '?' || c =3D=3D
> > > '"' ||
> > > + c =3D=3D '&' || c =3D=3D '<' || c <=3D 0x1f || c
> >=3D=
> > 0x7f) {
> > > + *dp++ =3D '%';
> > > + *dp++ =3D '%';
> > > + *dp++ =3D hex[c >> 4];
> > > + *dp++ =3D hex[c & 0x0f];
> > > + } else
> > > + *dp++ =3D *src;
> > > + }
> > > + return (dst);
> > > +}
> > > blob - 54e26e646fae5804e66d2d3cfeba68e06914ab2b
> > > blob + cd99c21d7cdaf9fc5fdc33e5a0ad886afaa9b889
> > > --- usr.sbin/relayd/relayd.c
> > > +++ usr.sbin/relayd/relayd.c
> > > @@ -1360,6 +1360,15 @@ relay_load_certfiles(struct relayd *env, struct
> > > relay
> > > if ((rlay->rl_conf.flags & F_TLS) =3D=3D 0)
> > > return (0);
> > >
> > > + if (strlen(proto->tlsclientca) &&
> > > + rlay->rl_tls_client_ca_fd =3D=3D -1) {
> > > + if ((rlay->rl_tls_client_ca_fd =3D
> > > + open(proto->tlsclientca, O_RDONLY)) =3D=3D -1)
> > > + return (-1);
> > > + log_debug("%s: using client ca %s", __func__,
> > > + proto->tlsclientca);
> > > + }
> > > +
> > > if (name =3D=3D NULL &&
> > > print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) =3D=3D
> NULL)
> > > goto fail;
> > > blob - cecbae71f87e603b3e30d4c0114bf1c60a82b52a
> > > blob + cfb7a314811730723449a5109d500014711db3ae
> > > --- usr.sbin/relayd/relayd.conf.5
> > > +++ usr.sbin/relayd/relayd.conf.5
> > > @@ -948,6 +948,13 @@ will be used (strong crypto cipher suites without
> an=
> > on
> > > See the CIPHERS section of
> > > .Xr openssl 1
> > > for information about SSL/TLS cipher suites and preference lists.
> > > +.It Ic client ca Ar path Op optional
> > > +Require TLS client certificates whose authenticity can be verified
> > > +against the CA certificate(s) in the specified file in order to
> > > +proceed beyond the TLS handshake.
> > > +If the
> > > +.Ic optional
> > > +keyword is present, the certificate is verified only if presented.
> > > .It Ic client-renegotiation
> > > Allow client-initiated renegotiation.
> > > To mitigate a potential DoS risk,
> > > @@ -1361,6 +1368,12 @@ The value string may contain predefined macros
> that
> > > wi
> > > at runtime:
> > > .Pp
> > > .Bl -tag -width $SERVER_ADDR -offset indent -compact
> > > +.It Ic $CLIENT_CERT_CHAIN
> > > +The certificate chain of the client certificate.
> > > +.It Ic $CLIENT_CERT_ISSUER
> > > +The issuer of the client certificate.
> > > +.It Ic $CLIENT_CERT_SUBJECT
> > > +The subject of the client certificate.
> > > .It Ic $HOST
> > > The Host header's value of the relay.
> > > .It Ic $REMOTE_ADDR
> > > blob - 2236d140f7e6b9477bac401cbcdd559db171680b
> > > blob + 2a1166599bfd57b0682c4d4bacd15d340ff9b5ad
> > > --- usr.sbin/relayd/relayd.h
> > > +++ usr.sbin/relayd/relayd.h
> > > @@ -139,11 +139,12 @@ struct ctl_relaytable {
> > > };
> > >
> > > enum fd_type {
> > > - RELAY_FD_CERT =3D 1,
> > > - RELAY_FD_CACERT =3D 2,
> > > - RELAY_FD_CAFILE =3D 3,
> > > - RELAY_FD_KEY =3D 4,
> > > - RELAY_FD_OCSP =3D 5
> > > + RELAY_FD_CERT =3D 1,
> > > + RELAY_FD_CACERT =3D 2,
> > > + RELAY_FD_CAFILE =3D 3,
> > > + RELAY_FD_KEY =3D 4,
> > > + RELAY_FD_OCSP =3D 5,
> > > + RELAY_FD_CLIENTCACERT =3D 6
> > > };
> > >
> > > struct ctl_relayfd {
> > > @@ -403,6 +404,7 @@ union hashkey {
> > > #define F_TLSINSPECT 0x04000000
> > > #define F_HASHKEY 0x08000000
> > > #define F_AGENTX_TRAPONLY 0x10000000
> > > +#define F_TLSVERIFY 0x20000000
> > >
> > > #define F_BITS
> > > \
> > > "\10\01DISABLE\02BACKUP\03USED\04DOWN\05ADD\06DEL\07CHANGED"
> \
> > > @@ -703,6 +705,7 @@ TAILQ_HEAD(relay_rules, relay_rule);
> > > #define TLSFLAG_VERSION 0x1f
> > > #define TLSFLAG_CIPHER_SERVER_PREF 0x20
> > > #define TLSFLAG_CLIENT_RENEG 0x40
> > > +#define TLSFLAG_CLIENT_OPTIONAL 0x80
> > > #define TLSFLAG_DEFAULT \
> > > (TLSFLAG_TLSV1_2|TLSFLAG_TLSV1_3|TLSFLAG_CIPHER_SERVER_PREF)
> > >
> > > @@ -746,6 +749,7 @@ struct protocol {
> > > char tlscacert[PATH_MAX];
> > > char tlscakey[PATH_MAX];
> > > char *tlscapass;
> > > + char tlsclientca[PATH_MAX];
> > > struct keynamelist tlscerts;
> > > char name[MAX_NAME_SIZE];
> > > int tickets;
> > > @@ -835,6 +839,7 @@ struct relay {
> > >
> > > int rl_tls_ca_fd;
> > > int rl_tls_cacert_fd;
> > > + int rl_tls_client_ca_fd;
> > > EVP_PKEY *rl_tls_pkey;
> > > X509 *rl_tls_cacertx509;
> > > char *rl_tls_cakey;
>
--
Markus Läll
[PATCH] relayd client certificate validation again