summaryrefslogtreecommitdiff
path: root/modules/caddytls/connpolicy.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-05-27 11:31:47 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-05-27 11:31:47 -0600
commit9cd6f35e9d4873946060e79cb50643bae8ba8e2c (patch)
treedfc561042c375890014e529c6fc4badb53a91f80 /modules/caddytls/connpolicy.go
parent210d0cf7f1040c1372a79869b8b279a92a52baf5 (diff)
Separate out certificate selection
Diffstat (limited to 'modules/caddytls/connpolicy.go')
-rw-r--r--modules/caddytls/connpolicy.go75
1 files changed, 24 insertions, 51 deletions
diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go
index fb999df..43ddb23 100644
--- a/modules/caddytls/connpolicy.go
+++ b/modules/caddytls/connpolicy.go
@@ -5,7 +5,6 @@ import (
"crypto/x509"
"encoding/json"
"fmt"
- "math/big"
"strings"
"bitbucket.org/lightcodelabs/caddy2"
@@ -22,16 +21,27 @@ type ConnectionPolicies []*ConnectionPolicy
// TLS configuration which selects the first matching policy based on
// the ClientHello.
func (cp ConnectionPolicies) TLSConfig(ctx caddy2.Context) (*tls.Config, error) {
- // connection policy matchers
+ // set up each of the connection policies
for i, pol := range cp {
- for modName, rawMsg := range pol.MatchersRaw {
+ // matchers
+ for modName, rawMsg := range pol.Matchers {
val, err := ctx.LoadModule("tls.handshake_match."+modName, rawMsg)
if err != nil {
return nil, fmt.Errorf("loading handshake matcher module '%s': %s", modName, err)
}
cp[i].matchers = append(cp[i].matchers, val.(ConnectionMatcher))
}
- cp[i].MatchersRaw = nil // allow GC to deallocate - TODO: Does this help?
+ cp[i].Matchers = nil // allow GC to deallocate - TODO: Does this help?
+
+ // certificate selector
+ if pol.CertSelection != nil {
+ val, err := ctx.LoadModuleInline("policy", "tls.certificate_selection", pol.CertSelection)
+ if err != nil {
+ return nil, fmt.Errorf("loading certificate selection module: %s", err)
+ }
+ cp[i].certSelector = val.(certmagic.CertificateSelector)
+ cp[i].CertSelection = nil // allow GC to deallocate - TODO: Does this help?
+ }
}
// pre-build standard TLS configs so we don't have to at handshake-time
@@ -83,7 +93,8 @@ func (cp ConnectionPolicies) TLSConfig(ctx caddy2.Context) (*tls.Config, error)
// ConnectionPolicy specifies the logic for handling a TLS handshake.
type ConnectionPolicy struct {
- MatchersRaw map[string]json.RawMessage `json:"match,omitempty"`
+ Matchers map[string]json.RawMessage `json:"match,omitempty"`
+ CertSelection json.RawMessage `json:"certificate_selection,omitempty"`
CipherSuites []string `json:"cipher_suites,omitempty"`
Curves []string `json:"curves,omitempty"`
@@ -91,14 +102,14 @@ type ConnectionPolicy struct {
ProtocolMin string `json:"protocol_min,omitempty"`
ProtocolMax string `json:"protocol_max,omitempty"`
- CertSelection *CertSelectionPolicy `json:"certificate_selection,omitempty"`
-
// TODO: Client auth
// TODO: see if starlark could be useful here - enterprise only
StarlarkHandshake string `json:"starlark_handshake,omitempty"`
matchers []ConnectionMatcher
+ certSelector certmagic.CertificateSelector
+
stdTLSConfig *tls.Config
}
@@ -118,8 +129,8 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy2.Context) error {
return nil, fmt.Errorf("getting config for name %s: %v", hello.ServerName, err)
}
newCfg := certmagic.New(tlsApp.certCache, cfgTpl)
- if p.CertSelection != nil {
- newCfg.CertSelector = makeCertSelector(p)
+ if p.certSelector != nil {
+ newCfg.CertSelection = p.certSelector
}
return newCfg.GetCertificate(hello)
},
@@ -178,56 +189,18 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy2.Context) error {
return nil
}
-// CertSelectionPolicy 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/mholt/caddy/issues/2588.
-type CertSelectionPolicy struct {
- SerialNumber *big.Int `json:"serial_number,omitempty"`
- SubjectOrganization string `json:"subject.organization,omitempty"`
- PublicKeyAlgorithm pkAlgorithm `json:"public_key_algorithm,omitempty"`
-}
-
-func makeCertSelector(p *ConnectionPolicy) func(*tls.ClientHelloInfo, []certmagic.Certificate) (certmagic.Certificate, error) {
- return func(hello *tls.ClientHelloInfo, choices []certmagic.Certificate) (certmagic.Certificate, error) {
- for _, cert := range choices {
- var matchOrg bool
- if p.CertSelection.SubjectOrganization != "" {
- for _, org := range cert.Subject.Organization {
- if p.CertSelection.SubjectOrganization == org {
- matchOrg = true
- break
- }
- }
- }
- if !matchOrg {
- continue
- }
- if p.CertSelection.PublicKeyAlgorithm != pkAlgorithm(x509.UnknownPublicKeyAlgorithm) &&
- pkAlgorithm(cert.PublicKeyAlgorithm) != p.CertSelection.PublicKeyAlgorithm {
- continue
- }
- if p.CertSelection.SerialNumber != nil &&
- cert.SerialNumber.Cmp(p.CertSelection.SerialNumber) != 0 {
- continue
- }
- return cert, nil
- }
- return certmagic.Certificate{}, fmt.Errorf("no certificates matched custom selection policy")
- }
-}
-
-type pkAlgorithm x509.PublicKeyAlgorithm
+// PublicKeyAlgorithm is a JSON-unmarshalable wrapper type.
+type PublicKeyAlgorithm x509.PublicKeyAlgorithm
// UnmarshalJSON satisfies json.Unmarshaler.
-func (a *pkAlgorithm) UnmarshalJSON(b []byte) error {
+func (a *PublicKeyAlgorithm) UnmarshalJSON(b []byte) error {
algoStr := strings.ToLower(strings.Trim(string(b), `"`))
algo, ok := publicKeyAlgorithms[algoStr]
if !ok {
return fmt.Errorf("unrecognized public key algorithm: %s (expected one of %v)",
algoStr, publicKeyAlgorithms)
}
- a = &algo
+ *a = PublicKeyAlgorithm(algo)
return nil
}