diff options
author | Matt Holt <mholt@users.noreply.github.com> | 2019-08-21 11:28:03 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-21 11:28:03 -0600 |
commit | 0544f0266a11874efb305a46db762248e64bc62d (patch) | |
tree | 3e75e6f59047bb967c52915e1e75aee6ad67c0ea /modules/caddytls | |
parent | 42f75a4ca94ef3fb5e15a74e5dc9ef8b4f1f0b39 (diff) | |
parent | b2aa679c33f63ebec5bc1a21bca01f345dffebdd (diff) |
Merge pull request #2699 from caddyserver/cfadapter
v2: Implement config adapters and WIP Caddyfile adapter
Diffstat (limited to 'modules/caddytls')
-rw-r--r-- | modules/caddytls/acmemanager.go | 19 | ||||
-rw-r--r-- | modules/caddytls/connpolicy.go | 8 | ||||
-rw-r--r-- | modules/caddytls/fileloader.go | 21 | ||||
-rw-r--r-- | modules/caddytls/folderloader.go | 21 | ||||
-rw-r--r-- | modules/caddytls/matchers.go | 13 | ||||
-rw-r--r-- | modules/caddytls/sessiontickets.go | 2 | ||||
-rw-r--r-- | modules/caddytls/standardstek/stek.go | 13 | ||||
-rw-r--r-- | modules/caddytls/tls.go | 52 | ||||
-rw-r--r-- | modules/caddytls/values.go | 36 |
9 files changed, 114 insertions, 71 deletions
diff --git a/modules/caddytls/acmemanager.go b/modules/caddytls/acmemanager.go index 578cdb3..36f1c21 100644 --- a/modules/caddytls/acmemanager.go +++ b/modules/caddytls/acmemanager.go @@ -28,10 +28,7 @@ import ( ) func init() { - caddy.RegisterModule(caddy.Module{ - Name: "tls.management.acme", - New: func() interface{} { return new(ACMEManagerMaker) }, - }) + caddy.RegisterModule(ACMEManagerMaker{}) } // ACMEManagerMaker makes an ACME manager @@ -57,9 +54,17 @@ type ACMEManagerMaker struct { keyType certcrypto.KeyType } -// newManager is a no-op to satisfy the ManagerMaker interface, +// CaddyModule returns the Caddy module information. +func (ACMEManagerMaker) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls.management.acme", + New: func() caddy.Module { return new(ACMEManagerMaker) }, + } +} + +// NewManager is a no-op to satisfy the ManagerMaker interface, // because this manager type is a special case. -func (m *ACMEManagerMaker) newManager(interactive bool) (certmagic.Manager, error) { +func (m ACMEManagerMaker) NewManager(interactive bool) (certmagic.Manager, error) { return nil, nil } @@ -203,4 +208,4 @@ func onDemandAskRequest(ask string, name string) error { } // Interface guard -var _ managerMaker = (*ACMEManagerMaker)(nil) +var _ ManagerMaker = (*ACMEManagerMaker)(nil) diff --git a/modules/caddytls/connpolicy.go b/modules/caddytls/connpolicy.go index 8cb6ffe..e061281 100644 --- a/modules/caddytls/connpolicy.go +++ b/modules/caddytls/connpolicy.go @@ -172,7 +172,7 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error { // add all the cipher suites in order, without duplicates cipherSuitesAdded := make(map[uint16]struct{}) for _, csName := range p.CipherSuites { - csID := supportedCipherSuites[csName] + csID := SupportedCipherSuites[csName] if _, ok := cipherSuitesAdded[csID]; !ok { cipherSuitesAdded[csID] = struct{}{} cfg.CipherSuites = append(cfg.CipherSuites, csID) @@ -182,7 +182,7 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error { // add all the curve preferences in order, without duplicates curvesAdded := make(map[tls.CurveID]struct{}) for _, curveName := range p.Curves { - curveID := supportedCurves[curveName] + curveID := SupportedCurves[curveName] if _, ok := curvesAdded[curveID]; !ok { curvesAdded[curveID] = struct{}{} cfg.CurvePreferences = append(cfg.CurvePreferences, curveID) @@ -203,10 +203,10 @@ func (p *ConnectionPolicy) buildStandardTLSConfig(ctx caddy.Context) error { // min and max protocol versions if p.ProtocolMin != "" { - cfg.MinVersion = supportedProtocols[p.ProtocolMin] + cfg.MinVersion = SupportedProtocols[p.ProtocolMin] } if p.ProtocolMax != "" { - cfg.MaxVersion = supportedProtocols[p.ProtocolMax] + cfg.MaxVersion = SupportedProtocols[p.ProtocolMax] } if p.ProtocolMin > p.ProtocolMax { return fmt.Errorf("protocol min (%x) cannot be greater than protocol max (%x)", p.ProtocolMin, p.ProtocolMax) diff --git a/modules/caddytls/fileloader.go b/modules/caddytls/fileloader.go index 5f277c8..b2cc132 100644 --- a/modules/caddytls/fileloader.go +++ b/modules/caddytls/fileloader.go @@ -23,14 +23,19 @@ import ( ) func init() { - caddy.RegisterModule(caddy.Module{ - Name: "tls.certificates.load_files", - New: func() interface{} { return fileLoader{} }, - }) + caddy.RegisterModule(FileLoader{}) } -// fileLoader loads certificates and their associated keys from disk. -type fileLoader []CertKeyFilePair +// FileLoader loads certificates and their associated keys from disk. +type FileLoader []CertKeyFilePair + +// CaddyModule returns the Caddy module information. +func (FileLoader) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls.certificates.load_files", + New: func() caddy.Module { return new(FileLoader) }, + } +} // CertKeyFilePair pairs certificate and key file names along with their // encoding format so that they can be loaded from disk. @@ -42,7 +47,7 @@ type CertKeyFilePair struct { } // LoadCertificates returns the certificates to be loaded by fl. -func (fl fileLoader) LoadCertificates() ([]Certificate, error) { +func (fl FileLoader) LoadCertificates() ([]Certificate, error) { var certs []Certificate for _, pair := range fl { certData, err := ioutil.ReadFile(pair.Certificate) @@ -73,4 +78,4 @@ func (fl fileLoader) LoadCertificates() ([]Certificate, error) { } // Interface guard -var _ CertificateLoader = (fileLoader)(nil) +var _ CertificateLoader = (FileLoader)(nil) diff --git a/modules/caddytls/folderloader.go b/modules/caddytls/folderloader.go index 24a7fbb..da1dff0 100644 --- a/modules/caddytls/folderloader.go +++ b/modules/caddytls/folderloader.go @@ -28,22 +28,27 @@ import ( ) func init() { - caddy.RegisterModule(caddy.Module{ - Name: "tls.certificates.load_folders", - New: func() interface{} { return folderLoader{} }, - }) + caddy.RegisterModule(FolderLoader{}) } -// folderLoader loads certificates and their associated keys from disk +// FolderLoader loads certificates and their associated keys from disk // by recursively walking the specified directories, looking for PEM // files which contain both a certificate and a key. -type folderLoader []string +type FolderLoader []string + +// CaddyModule returns the Caddy module information. +func (FolderLoader) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls.certificates.load_folders", + New: func() caddy.Module { return new(FolderLoader) }, + } +} // LoadCertificates loads all the certificates+keys in the directories // listed in fl from all files ending with .pem. This method of loading // certificates expects the certificate and key to be bundled into the // same file. -func (fl folderLoader) LoadCertificates() ([]Certificate, error) { +func (fl FolderLoader) LoadCertificates() ([]Certificate, error) { var certs []Certificate for _, dir := range fl { err := filepath.Walk(dir, func(fpath string, info os.FileInfo, err error) error { @@ -135,4 +140,4 @@ func x509CertFromCertAndKeyPEMFile(fpath string) (tls.Certificate, error) { return cert, nil } -var _ CertificateLoader = (folderLoader)(nil) +var _ CertificateLoader = (FolderLoader)(nil) diff --git a/modules/caddytls/matchers.go b/modules/caddytls/matchers.go index ee146d4..47fb296 100644 --- a/modules/caddytls/matchers.go +++ b/modules/caddytls/matchers.go @@ -20,14 +20,19 @@ import ( "github.com/caddyserver/caddy/v2" ) +func init() { + caddy.RegisterModule(MatchServerName{}) +} + // MatchServerName matches based on SNI. type MatchServerName []string -func init() { - caddy.RegisterModule(caddy.Module{ +// CaddyModule returns the Caddy module information. +func (MatchServerName) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ Name: "tls.handshake_match.sni", - New: func() interface{} { return MatchServerName{} }, - }) + New: func() caddy.Module { return new(MatchServerName) }, + } } // Match matches hello based on SNI. diff --git a/modules/caddytls/sessiontickets.go b/modules/caddytls/sessiontickets.go index c47f823..2eb0773 100644 --- a/modules/caddytls/sessiontickets.go +++ b/modules/caddytls/sessiontickets.go @@ -29,7 +29,7 @@ import ( // SessionTicketService configures and manages TLS session tickets. type SessionTicketService struct { KeySource json.RawMessage `json:"key_source,omitempty"` - RotationInterval caddy.Duration `json:"rotation_interval,omitempty"` + RotationInterval caddy.Duration `json:"rotation_interval,omitempty"` MaxKeys int `json:"max_keys,omitempty"` DisableRotation bool `json:"disable_rotation,omitempty"` Disabled bool `json:"disabled,omitempty"` diff --git a/modules/caddytls/standardstek/stek.go b/modules/caddytls/standardstek/stek.go index 6a4b1c8..6d10c76 100644 --- a/modules/caddytls/standardstek/stek.go +++ b/modules/caddytls/standardstek/stek.go @@ -24,10 +24,7 @@ import ( ) func init() { - caddy.RegisterModule(caddy.Module{ - Name: "tls.stek.standard", - New: func() interface{} { return new(standardSTEKProvider) }, - }) + caddy.RegisterModule(standardSTEKProvider{}) } type standardSTEKProvider struct { @@ -35,6 +32,14 @@ type standardSTEKProvider struct { timer *time.Timer } +// CaddyModule returns the Caddy module information. +func (standardSTEKProvider) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls.stek.standard", + New: func() caddy.Module { return new(standardSTEKProvider) }, + } +} + // Initialize sets the configuration for s and returns the starting keys. func (s *standardSTEKProvider) Initialize(config *caddytls.SessionTicketService) ([][32]byte, error) { // keep a reference to the config; we'll need it when rotating keys diff --git a/modules/caddytls/tls.go b/modules/caddytls/tls.go index e70fbd1..88b7790 100644 --- a/modules/caddytls/tls.go +++ b/modules/caddytls/tls.go @@ -30,10 +30,7 @@ import ( ) func init() { - caddy.RegisterModule(caddy.Module{ - Name: "tls", - New: func() interface{} { return new(TLS) }, - }) + caddy.RegisterModule(TLS{}) // opt-in TLS 1.3 for Go1.12 // TODO: remove this line when Go1.13 is released. @@ -45,14 +42,22 @@ func init() { // TLS represents a process-wide TLS configuration. type TLS struct { Certificates map[string]json.RawMessage `json:"certificates,omitempty"` - Automation AutomationConfig `json:"automation,omitempty"` - SessionTickets SessionTicketService `json:"session_tickets,omitempty"` + Automation AutomationConfig `json:"automation"` + SessionTickets SessionTicketService `json:"session_tickets"` certificateLoaders []CertificateLoader certCache *certmagic.Cache ctx caddy.Context } +// CaddyModule returns the Caddy module information. +func (TLS) CaddyModule() caddy.ModuleInfo { + return caddy.ModuleInfo{ + Name: "tls", + New: func() caddy.Module { return new(TLS) }, + } +} + // Provision sets up the configuration for the TLS app. func (t *TLS) Provision(ctx caddy.Context) error { t.ctx = ctx @@ -73,7 +78,7 @@ func (t *TLS) Provision(ctx caddy.Context) error { if err != nil { return fmt.Errorf("loading TLS automation management module: %s", err) } - t.Automation.Policies[i].Management = val.(managerMaker) + t.Automation.Policies[i].Management = val.(ManagerMaker) t.Automation.Policies[i].ManagementRaw = nil // allow GC to deallocate - TODO: Does this help? } @@ -105,16 +110,12 @@ func (t *TLS) Provision(ctx caddy.Context) error { onDemandRateLimiter.SetLimit(0) } - return nil -} - -// Start activates the TLS module. -func (t *TLS) Start() error { + // load manual/static (unmanaged) certificates - we do this in + // provision so that other apps (such as http) can know which + // certificates have been manually loaded magic := certmagic.New(t.certCache, certmagic.Config{ - Storage: t.ctx.Storage(), + Storage: ctx.Storage(), }) - - // load manual/static (unmanaged) certificates for _, loader := range t.certificateLoaders { certs, err := loader.LoadCertificates() if err != nil { @@ -128,6 +129,11 @@ func (t *TLS) Start() error { } } + return nil +} + +// Start activates the TLS module. +func (t *TLS) Start() error { // load automated (managed) certificates if automatedRawMsg, ok := t.Certificates[automateKey]; ok { var names []string @@ -204,6 +210,12 @@ func (t *TLS) getAutomationPolicyForName(name string) AutomationPolicy { return AutomationPolicy{Management: mgmt} } +// CertificatesWithSAN returns the list of all certificates +// in the cache the match the given SAN value. +func (t *TLS) CertificatesWithSAN(san string) []certmagic.Certificate { + return t.certCache.CertificatesWithSAN(san) +} + // CertificateLoader is a type that can load certificates. // Certificates can optionally be associated with tags. type CertificateLoader interface { @@ -230,7 +242,7 @@ type AutomationPolicy struct { Hosts []string `json:"hosts,omitempty"` ManagementRaw json.RawMessage `json:"management,omitempty"` - Management managerMaker `json:"-"` + Management ManagerMaker `json:"-"` } // makeCertMagicConfig converts ap into a CertMagic config. Passing onDemand @@ -245,7 +257,7 @@ func (ap AutomationPolicy) makeCertMagicConfig(ctx caddy.Context) certmagic.Conf } return certmagic.Config{ - NewManager: ap.Management.newManager, + NewManager: ap.Management.NewManager, } } @@ -283,9 +295,9 @@ type RateLimit struct { Burst int `json:"burst,omitempty"` } -// managerMaker makes a certificate manager. -type managerMaker interface { - newManager(interactive bool) (certmagic.Manager, error) +// ManagerMaker makes a certificate manager. +type ManagerMaker interface { + NewManager(interactive bool) (certmagic.Manager, error) } // These perpetual values are used for on-demand TLS. diff --git a/modules/caddytls/values.go b/modules/caddytls/values.go index 0c62058..b10fe22 100644 --- a/modules/caddytls/values.go +++ b/modules/caddytls/values.go @@ -22,12 +22,16 @@ import ( "github.com/klauspost/cpuid" ) -// supportedCipherSuites is the unordered map of cipher suite +// SupportedCipherSuites is the unordered map of cipher suite // string names to their definition in crypto/tls. All values // should be IANA-reserved names. See // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml +// Two of the cipher suite constants in the standard lib do not use the +// full IANA name, but we do; see: +// https://github.com/golang/go/issues/32061 and +// https://github.com/golang/go/issues/30325#issuecomment-512862374. // TODO: might not be needed much longer: https://github.com/golang/go/issues/30325 -var supportedCipherSuites = map[string]uint16{ +var SupportedCipherSuites = map[string]uint16{ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, @@ -84,22 +88,24 @@ func getOptimalDefaultCipherSuites() []uint16 { return defaultCipherSuitesWithoutAESNI } -// supportedCurves is the unordered map of supported curves. +// SupportedCurves is the unordered map of supported curves. // https://golang.org/pkg/crypto/tls/#CurveID -var supportedCurves = map[string]tls.CurveID{ - "X25519": tls.X25519, - "P256": tls.CurveP256, - "P384": tls.CurveP384, - "P521": tls.CurveP521, +var SupportedCurves = map[string]tls.CurveID{ + // TODO: Use IANA names, probably? see https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 + // All named crypto/elliptic curves have secpXXXr1 IANA names. + "x25519": tls.X25519, // x25519, 29 + "p256": tls.CurveP256, // secp256r1, 23 + "p384": tls.CurveP384, // secp384r1, 24 + "p521": tls.CurveP521, // secp521r1, 25 } // supportedCertKeyTypes is all the key types that are supported // for certificates that are obtained through ACME. var supportedCertKeyTypes = map[string]certcrypto.KeyType{ - "RSA2048": certcrypto.RSA2048, - "RSA4096": certcrypto.RSA4096, - "P256": certcrypto.EC256, - "P384": certcrypto.EC384, + "rsa_2048": certcrypto.RSA2048, + "rsa_4096": certcrypto.RSA4096, + "ec_p256": certcrypto.EC256, + "ec_p384": certcrypto.EC384, } // defaultCurves is the list of only the curves we want to use @@ -115,9 +121,9 @@ var defaultCurves = []tls.CurveID{ tls.CurveP256, } -// supportedProtocols is a map of supported protocols. -// HTTP/2 only supports TLS 1.2 and higher. -var supportedProtocols = map[string]uint16{ +// SupportedProtocols is a map of supported protocols. +// Note that HTTP/2 only supports TLS 1.2 and higher. +var SupportedProtocols = map[string]uint16{ "tls1.0": tls.VersionTLS10, "tls1.1": tls.VersionTLS11, "tls1.2": tls.VersionTLS12, |