tls: modularize trusted CA providers (#5784)

* tls: modularize client authentication trusted CA

* add `omitempty` to `CARaw`

* docs

* initial caddyfile support

* revert anything related to leaf cert validation

The certs are used differently than the CA pool flow

* complete caddyfile unmarshalling implementation

* Caddyfile syntax documentation

* enhance caddyfile parsing and documentation

Apply suggestions from code review

Co-authored-by: Francis Lavoie <lavofr@gmail.com>

* add client_auth caddyfile tests

* add caddyfile unmarshalling tests

* fix and add missed adapt tests

* fix rebase issue

---------

Co-authored-by: Francis Lavoie <lavofr@gmail.com>
This commit is contained in:
Mohammed Al Sahaf 2024-01-25 11:44:41 +03:00 committed by GitHub
parent b9c40e7111
commit e965b111cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 2409 additions and 108 deletions

View file

@ -15,12 +15,9 @@
package httpcaddyfile
import (
"encoding/base64"
"encoding/pem"
"fmt"
"html"
"net/http"
"os"
"reflect"
"strconv"
"strings"
@ -215,83 +212,9 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
case "client_auth":
cp.ClientAuthentication = &caddytls.ClientAuthentication{}
for nesting := h.Nesting(); h.NextBlock(nesting); {
subdir := h.Val()
switch subdir {
case "verifier":
if !h.NextArg() {
return nil, h.ArgErr()
}
vType := h.Val()
modID := "tls.client_auth." + vType
unm, err := caddyfile.UnmarshalModule(h.Dispenser, modID)
if err != nil {
return nil, err
}
_, ok := unm.(caddytls.ClientCertificateVerifier)
if !ok {
return nil, h.Dispenser.Errf("module %s is not a caddytls.ClientCertificatVerifier", modID)
}
cp.ClientAuthentication.VerifiersRaw = append(cp.ClientAuthentication.VerifiersRaw, caddyconfig.JSONModuleObject(unm, "verifier", vType, h.warnings))
case "mode":
if !h.Args(&cp.ClientAuthentication.Mode) {
return nil, h.ArgErr()
}
if h.NextArg() {
return nil, h.ArgErr()
}
case "trusted_ca_cert",
"trusted_leaf_cert":
if !h.NextArg() {
return nil, h.ArgErr()
}
if subdir == "trusted_ca_cert" {
cp.ClientAuthentication.TrustedCACerts = append(cp.ClientAuthentication.TrustedCACerts, h.Val())
} else {
cp.ClientAuthentication.TrustedLeafCerts = append(cp.ClientAuthentication.TrustedLeafCerts, h.Val())
}
case "trusted_ca_cert_file",
"trusted_leaf_cert_file":
if !h.NextArg() {
return nil, h.ArgErr()
}
filename := h.Val()
certDataPEM, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
// while block is not nil, we have more certificates in the file
for block, rest := pem.Decode(certDataPEM); block != nil; block, rest = pem.Decode(rest) {
if block.Type != "CERTIFICATE" {
return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
}
if subdir == "trusted_ca_cert_file" {
cp.ClientAuthentication.TrustedCACerts = append(
cp.ClientAuthentication.TrustedCACerts,
base64.StdEncoding.EncodeToString(block.Bytes),
)
} else {
cp.ClientAuthentication.TrustedLeafCerts = append(
cp.ClientAuthentication.TrustedLeafCerts,
base64.StdEncoding.EncodeToString(block.Bytes),
)
}
}
// if we decoded nothing, return an error
if len(cp.ClientAuthentication.TrustedCACerts) == 0 && len(cp.ClientAuthentication.TrustedLeafCerts) == 0 {
return nil, h.Errf("no CERTIFICATE pem block found in %s", filename)
}
default:
return nil, h.Errf("unknown subdirective for client_auth: %s", subdir)
}
if err := cp.ClientAuthentication.UnmarshalCaddyfile(h.NewFromNextSegment()); err != nil {
return nil, err
}
case "alpn":
args := h.RemainingArgs()
if len(args) == 0 {