Browse Source
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.master
Matthew Holt
5 years ago
1 changed files with 71 additions and 0 deletions
@ -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) |
Loading…
Reference in new issue