From 5a9471f884eeb53087704da69c8aae1e8896a85f Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Tue, 7 Jan 2025 23:53:44 +0300 Subject: [PATCH] client_auth: wire up leaf verifier Caddyfile Signed-off-by: Mohammed Al Sahaf --- ...th_leaf_verifier_file_loader.caddyfiletest | 87 +++++++++++++++++++ modules/caddytls/connpolicy.go | 26 ++++++ modules/caddytls/leaffileloader.go | 21 +++-- modules/caddytls/leaffolderloader.go | 9 ++ 4 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 caddytest/integration/caddyfile_adapt/tls_client_auth_leaf_verifier_file_loader.caddyfiletest diff --git a/caddytest/integration/caddyfile_adapt/tls_client_auth_leaf_verifier_file_loader.caddyfiletest b/caddytest/integration/caddyfile_adapt/tls_client_auth_leaf_verifier_file_loader.caddyfiletest new file mode 100644 index 000000000..70341f4f2 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/tls_client_auth_leaf_verifier_file_loader.caddyfiletest @@ -0,0 +1,87 @@ +localhost + +respond "hello from localhost" +tls { + client_auth { + mode request + trust_pool inline { + trust_der MIIDSzCCAjOgAwIBAgIUfIRObjWNUA4jxQ/0x8BOCvE2Vw4wDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMTkwODI4MTYyNTU5WhcNMjkwODI1MTYyNTU5WjAWMRQwEgYDVQQDDAtFYXN5LVJTQSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK5m5elxhQfMp/3aVJ4JnpN9PUSz6LlP6LePAPFU7gqohVVFVtDkChJAG3FNkNQNlieVTja/bgH9IcC6oKbROwdY1h0MvNV8AHHigvl03WuJD8g2ReVFXXwsnrPmKXCFzQyMI6TYk3m2gYrXsZOU1GLnfMRC3KAMRgE2F45twOs9hqG169YJ6mM2eQjzjCHWI6S2/iUYvYxRkCOlYUbLsMD/AhgAf1plzg6LPqNxtdlwxZnA0ytgkmhK67HtzJu0+ovUCsMv0RwcMhsEo9T8nyFAGt9XLZ63X5WpBCTUApaAUhnG0XnerjmUWb6eUWw4zev54sEfY5F3x002iQaW6cECAwEAAaOBkDCBjTAdBgNVHQ4EFgQU4CBUbZsS2GaNIkGRz/cBsD5ivjswUQYDVR0jBEowSIAU4CBUbZsS2GaNIkGRz/cBsD5ivjuhGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBghR8hE5uNY1QDiPFD/THwE4K8TZXDjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAKB3V4HIzoiO/Ch6WMj9bLJ2FGbpkMrcb/Eq01hT5zcfKD66lVS1MlK+cRL446Z2b2KDP1oFyVs+qmrmtdwrWgD+nfe2sBmmIHo9m9KygMkEOfG3MghGTEcS+0cTKEcoHYWYyOqQh6jnedXY8Cdm4GM1hAc9MiL3/sqV8YCVSLNnkoNysmr06/rZ0MCUZPGUtRmfd0heWhrfzAKw2HLgX+RAmpOE2MZqWcjvqKGyaRiaZks4nJkP6521aC2Lgp0HhCz1j8/uQ5ldoDszCnu/iro0NAsNtudTMD+YoLQxLqdleIh6CW+illc2VdXwj7mn6J04yns9jfE2jRjW/yTLFuQ== + } + verifier leaf { + load_file ../caddy.ca.cer + } + } +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "hello from localhost", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ], + "tls_connection_policies": [ + { + "match": { + "sni": [ + "localhost" + ] + }, + "client_authentication": { + "ca": { + "provider": "inline", + "trusted_ca_certs": [ + "MIIDSzCCAjOgAwIBAgIUfIRObjWNUA4jxQ/0x8BOCvE2Vw4wDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAwwLRWFzeS1SU0EgQ0EwHhcNMTkwODI4MTYyNTU5WhcNMjkwODI1MTYyNTU5WjAWMRQwEgYDVQQDDAtFYXN5LVJTQSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK5m5elxhQfMp/3aVJ4JnpN9PUSz6LlP6LePAPFU7gqohVVFVtDkChJAG3FNkNQNlieVTja/bgH9IcC6oKbROwdY1h0MvNV8AHHigvl03WuJD8g2ReVFXXwsnrPmKXCFzQyMI6TYk3m2gYrXsZOU1GLnfMRC3KAMRgE2F45twOs9hqG169YJ6mM2eQjzjCHWI6S2/iUYvYxRkCOlYUbLsMD/AhgAf1plzg6LPqNxtdlwxZnA0ytgkmhK67HtzJu0+ovUCsMv0RwcMhsEo9T8nyFAGt9XLZ63X5WpBCTUApaAUhnG0XnerjmUWb6eUWw4zev54sEfY5F3x002iQaW6cECAwEAAaOBkDCBjTAdBgNVHQ4EFgQU4CBUbZsS2GaNIkGRz/cBsD5ivjswUQYDVR0jBEowSIAU4CBUbZsS2GaNIkGRz/cBsD5ivjuhGqQYMBYxFDASBgNVBAMMC0Vhc3ktUlNBIENBghR8hE5uNY1QDiPFD/THwE4K8TZXDjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAKB3V4HIzoiO/Ch6WMj9bLJ2FGbpkMrcb/Eq01hT5zcfKD66lVS1MlK+cRL446Z2b2KDP1oFyVs+qmrmtdwrWgD+nfe2sBmmIHo9m9KygMkEOfG3MghGTEcS+0cTKEcoHYWYyOqQh6jnedXY8Cdm4GM1hAc9MiL3/sqV8YCVSLNnkoNysmr06/rZ0MCUZPGUtRmfd0heWhrfzAKw2HLgX+RAmpOE2MZqWcjvqKGyaRiaZks4nJkP6521aC2Lgp0HhCz1j8/uQ5ldoDszCnu/iro0NAsNtudTMD+YoLQxLqdleIh6CW+illc2VdXwj7mn6J04yns9jfE2jRjW/yTLFuQ==" + ] + }, + "verifiers": [ + { + "leaf_certs_loaders": [ + { + "files": [ + "../caddy.ca.cer" + ], + "loader": "file" + } + ], + "verifier": "leaf" + } + ], + "mode": "request" + } + }, + {} + ] + } + } + } + } +} \ No newline at end of file diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go index d9fc6bcfe..b0c24f8bb 100644 --- a/modules/caddytls/connpolicy.go +++ b/modules/caddytls/connpolicy.go @@ -941,6 +941,31 @@ func (l *LeafCertClientAuth) Provision(ctx caddy.Context) error { return nil } +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (l *LeafCertClientAuth) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + d.NextArg() + for nesting := d.Nesting(); d.NextBlock(nesting); { + modName := d.Val() + if !strings.HasPrefix(modName, "load_") { + return d.Err("expected a leaf certificate loader module name prefixed with `load_`") + } + modName = strings.TrimPrefix(modName, "load_") + mod, err := caddyfile.UnmarshalModule(d, "tls.leaf_cert_loader."+modName) + if err != nil { + return d.WrapErr(err) + } + vMod, ok := mod.(LeafCertificateLoader) + if !ok { + return fmt.Errorf("leaf module '%s' is not a leaf certificate loader", vMod) + } + l.LeafCertificateLoadersRaw = append( + l.LeafCertificateLoadersRaw, + caddyconfig.JSONModuleObject(vMod, "loader", modName, nil), + ) + } + return nil +} + func (l LeafCertClientAuth) VerifyClientCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error { if len(rawCerts) == 0 { return fmt.Errorf("no client certificate provided") @@ -1004,6 +1029,7 @@ var secretsLogPool = caddy.NewUsagePool() var ( _ caddyfile.Unmarshaler = (*ClientAuthentication)(nil) _ caddyfile.Unmarshaler = (*ConnectionPolicy)(nil) + _ caddyfile.Unmarshaler = (*LeafCertClientAuth)(nil) ) // ParseCaddyfileNestedMatcherSet parses the Caddyfile tokens for a nested diff --git a/modules/caddytls/leaffileloader.go b/modules/caddytls/leaffileloader.go index 1d3f3a3e5..c2177ab55 100644 --- a/modules/caddytls/leaffileloader.go +++ b/modules/caddytls/leaffileloader.go @@ -21,6 +21,7 @@ import ( "os" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" ) func init() { @@ -32,6 +33,14 @@ type LeafFileLoader struct { Files []string `json:"files,omitempty"` } +// CaddyModule returns the Caddy module information. +func (LeafFileLoader) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + ID: "tls.leaf_cert_loader.file", + New: func() caddy.Module { return new(LeafFileLoader) }, + } +} + // Provision implements caddy.Provisioner. func (fl *LeafFileLoader) Provision(ctx caddy.Context) error { repl, ok := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer) @@ -44,12 +53,11 @@ func (fl *LeafFileLoader) Provision(ctx caddy.Context) error { return nil } -// CaddyModule returns the Caddy module information. -func (LeafFileLoader) CaddyModule() caddy.ModuleInfo { - return caddy.ModuleInfo{ - ID: "tls.leaf_cert_loader.file", - New: func() caddy.Module { return new(LeafFileLoader) }, - } +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (fl *LeafFileLoader) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + d.NextArg() + fl.Files = append(fl.Files, d.RemainingArgs()...) + return nil } // LoadLeafCertificates returns the certificates to be loaded by fl. @@ -96,4 +104,5 @@ func convertPEMFilesToDERBytes(filename string) ([]byte, error) { var ( _ LeafCertificateLoader = (*LeafFileLoader)(nil) _ caddy.Provisioner = (*LeafFileLoader)(nil) + _ caddyfile.Unmarshaler = (*LeafFileLoader)(nil) ) diff --git a/modules/caddytls/leaffolderloader.go b/modules/caddytls/leaffolderloader.go index 5c7b06e76..20f5aa82c 100644 --- a/modules/caddytls/leaffolderloader.go +++ b/modules/caddytls/leaffolderloader.go @@ -22,6 +22,7 @@ import ( "strings" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" ) func init() { @@ -55,6 +56,13 @@ func (fl *LeafFolderLoader) Provision(ctx caddy.Context) error { return nil } +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (fl *LeafFolderLoader) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + d.NextArg() + fl.Folders = append(fl.Folders, d.RemainingArgs()...) + return nil +} + // LoadLeafCertificates loads all the leaf certificates in the directories // listed in fl from all files ending with .pem. func (fl LeafFolderLoader) LoadLeafCertificates() ([]*x509.Certificate, error) { @@ -94,4 +102,5 @@ func (fl LeafFolderLoader) LoadLeafCertificates() ([]*x509.Certificate, error) { var ( _ LeafCertificateLoader = (*LeafFolderLoader)(nil) _ caddy.Provisioner = (*LeafFolderLoader)(nil) + _ caddyfile.Unmarshaler = (*LeafFolderLoader)(nil) )