From ca6e54bbb8ab2bad3cc9192bd4857be7e9501c6c Mon Sep 17 00:00:00 2001 From: evtr Date: Sun, 8 Mar 2020 16:48:25 +0100 Subject: [PATCH] caddytls: customizable client auth modes (#2913) * ability to specify that client cert must be present in SSL * changed the clientauthtype to string and make room for the values supported by go as in caddy1 * renamed the config parameter according to review comments and added documentation on allowed values * missed a reference * Minor cleanup; docs enhancements Co-authored-by: Matthew Holt --- modules/caddytls/connpolicy.go | 43 +++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go index 9c61c72c..5b830f98 100644 --- a/modules/caddytls/connpolicy.go +++ b/modules/caddytls/connpolicy.go @@ -276,6 +276,20 @@ type ClientAuthentication struct { // which are not in this list will be rejected. TrustedLeafCerts []string `json:"trusted_leaf_certs,omitempty"` + // The mode for authenticating the client. Allowed values are: + // + // Mode | Description + // -----|--------------- + // `request` | Ask clients for a certificate, but allow even if there isn't one; do not verify it + // `require` | Require clients to present a certificate, but do not verify it + // `verify_if_given` | Ask clients for a certificate; allow even if there isn't one, but verify it if there is + // `require_and_verify` | Require clients to present a valid certificate that is verified + // + // The default mode is `require_and_verify` if any + // TrustedCACerts or TrustedLeafCerts are provided; + // otherwise, the default mode is `require`. + Mode string `json:"mode,omitempty"` + // state established with the last call to ConfigureTLSConfig trustedLeafCerts []*x509.Certificate existingVerifyPeerCert func([][]byte, [][]*x509.Certificate) error @@ -283,7 +297,7 @@ type ClientAuthentication struct { // Active returns true if clientauth has an actionable configuration. func (clientauth ClientAuthentication) Active() bool { - return len(clientauth.TrustedCACerts) > 0 || len(clientauth.TrustedLeafCerts) > 0 + return len(clientauth.TrustedCACerts) > 0 || len(clientauth.TrustedLeafCerts) > 0 || len(clientauth.Mode) > 0 } // ConfigureTLSConfig sets up cfg to enforce clientauth's configuration. @@ -294,8 +308,28 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro return nil } - // otherwise, at least require any client certificate - cfg.ClientAuth = tls.RequireAnyClientCert + // enforce desired mode of client authentication + if len(clientauth.Mode) > 0 { + switch clientauth.Mode { + case "request": + cfg.ClientAuth = tls.RequestClientCert + case "require": + cfg.ClientAuth = tls.RequireAnyClientCert + case "verify_if_given": + cfg.ClientAuth = tls.VerifyClientCertIfGiven + case "require_and_verify": + cfg.ClientAuth = tls.RequireAndVerifyClientCert + default: + return fmt.Errorf("client auth mode %s not allowed", clientauth.Mode) + } + } else { + // otherwise, set a safe default mode + if len(clientauth.TrustedCACerts) > 0 || len(clientauth.TrustedLeafCerts) > 0 { + cfg.ClientAuth = tls.RequireAndVerifyClientCert + } else { + cfg.ClientAuth = tls.RequireAnyClientCert + } + } // enforce CA verification by adding CA certs to the ClientCAs pool if len(clientauth.TrustedCACerts) > 0 { @@ -308,9 +342,6 @@ func (clientauth *ClientAuthentication) ConfigureTLSConfig(cfg *tls.Config) erro caPool.AddCert(clientCA) } cfg.ClientCAs = caPool - - // now ensure the standard lib will verify client certificates - cfg.ClientAuth = tls.RequireAndVerifyClientCert } // enforce leaf verification by writing our own verify function