diff options
author | Matthew Holt <mholt@users.noreply.github.com> | 2019-10-09 19:41:45 -0600 |
---|---|---|
committer | Matthew Holt <mholt@users.noreply.github.com> | 2019-10-09 19:41:45 -0600 |
commit | 85ce15a5ad0c0a0e24ed026b1f06a5a573c74283 (patch) | |
tree | bfebde7f17249a129256250d3535675e9204d54c | |
parent | dedcfd4e3da1297cda2d09776e7c8135e0d960ce (diff) |
tls: Add custom certificate selection policy
This migrates a feature that was previously reserved for enterprise
users, according to https://github.com/caddyserver/caddy/issues/2786.
Custom certificate selection policies allow advanced control over which
cert is selected when multiple qualify to satisfy a TLS handshake.
-rw-r--r-- | modules/caddytls/certselection.go | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/modules/caddytls/certselection.go b/modules/caddytls/certselection.go new file mode 100644 index 0000000..b56185a --- /dev/null +++ b/modules/caddytls/certselection.go @@ -0,0 +1,71 @@ +package caddytls + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + "math/big" + + "github.com/caddyserver/caddy/v2" + "github.com/mholt/certmagic" +) + +func init() { + caddy.RegisterModule(Policy{}) +} + +// Policy represents a policy for selecting the certificate used to +// complete a handshake when there may be multiple options. All fields +// specified must match the candidate certificate for it to be chosen. +// This was needed to solve https://github.com/caddyserver/caddy/issues/2588. +type Policy struct { + SerialNumber *big.Int `json:"serial_number,omitempty"` + SubjectOrganization string `json:"subject_organization,omitempty"` + PublicKeyAlgorithm PublicKeyAlgorithm `json:"public_key_algorithm,omitempty"` + Tag string `json:"tag,omitempty"` +} + +// CaddyModule returns the Caddy module information. +func (Policy) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls.certificate_selection.custom", + New: func() caddy.Module { return new(Policy) }, + } +} + +// SelectCertificate implements certmagic.CertificateSelector. +func (p Policy) SelectCertificate(_ *tls.ClientHelloInfo, choices []certmagic.Certificate) (certmagic.Certificate, error) { + for _, cert := range choices { + if p.SerialNumber != nil && cert.SerialNumber.Cmp(p.SerialNumber) != 0 { + continue + } + + if p.PublicKeyAlgorithm != PublicKeyAlgorithm(x509.UnknownPublicKeyAlgorithm) && + PublicKeyAlgorithm(cert.PublicKeyAlgorithm) != p.PublicKeyAlgorithm { + continue + } + + if p.SubjectOrganization != "" { + var matchOrg bool + for _, org := range cert.Subject.Organization { + if p.SubjectOrganization == org { + matchOrg = true + break + } + } + if !matchOrg { + continue + } + } + + if p.Tag != "" && !cert.HasTag(p.Tag) { + continue + } + + return cert, nil + } + return certmagic.Certificate{}, fmt.Errorf("no certificates matched custom selection policy") +} + +// Interface guard +var _ certmagic.CertificateSelector = (*Policy)(nil) |