maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package tls
 20
 21import (
 22	"crypto/tls"
 23
 24	"github.com/foxcpp/maddy/framework/config"
 25	modconfig "github.com/foxcpp/maddy/framework/config/module"
 26	"github.com/foxcpp/maddy/framework/log"
 27	"github.com/foxcpp/maddy/framework/module"
 28)
 29
 30type TLSConfig struct {
 31	loader  module.TLSLoader
 32	baseCfg *tls.Config
 33}
 34
 35func (cfg *TLSConfig) Get() (*tls.Config, error) {
 36	if cfg.loader == nil {
 37		return nil, nil
 38	}
 39	tlsCfg := cfg.baseCfg.Clone()
 40
 41	err := cfg.loader.ConfigureTLS(tlsCfg)
 42	if err != nil {
 43		return nil, err
 44	}
 45
 46	return tlsCfg, nil
 47}
 48
 49// TLSDirective reads the TLS configuration and adds the reload handler to
 50// reread certificates on SIGUSR2.
 51//
 52// The returned value is *tls.Config with GetConfigForClient set.
 53// If the 'tls off' is used, returned value is nil.
 54func TLSDirective(m *config.Map, node config.Node) (interface{}, error) {
 55	cfg, err := readTLSBlock(m.Globals, node)
 56	if err != nil {
 57		return nil, err
 58	}
 59
 60	if cfg == nil {
 61		return nil, nil
 62	}
 63
 64	return &tls.Config{
 65		GetConfigForClient: func(hello *tls.ClientHelloInfo) (*tls.Config, error) {
 66			return cfg.Get()
 67		},
 68	}, nil
 69}
 70
 71func readTLSBlock(globals map[string]interface{}, blockNode config.Node) (*TLSConfig, error) {
 72	baseCfg := tls.Config{
 73		// Workaround for issue https://github.com/foxcpp/maddy/issues/730
 74		SessionTicketsDisabled: true,
 75	}
 76
 77	var loader module.TLSLoader
 78	if len(blockNode.Args) > 0 {
 79		if blockNode.Args[0] == "off" {
 80			return nil, nil
 81		}
 82
 83		err := modconfig.ModuleFromNode("tls.loader", blockNode.Args, config.Node{}, globals, &loader)
 84		if err != nil {
 85			return nil, err
 86		}
 87	}
 88
 89	childM := config.NewMap(globals, blockNode)
 90	var tlsVersions [2]uint16
 91
 92	childM.Custom("loader", false, false, func() (interface{}, error) {
 93		return loader, nil
 94	}, func(_ *config.Map, node config.Node) (interface{}, error) {
 95		var l module.TLSLoader
 96		err := modconfig.ModuleFromNode("tls.loader", node.Args, node, globals, &l)
 97		return l, err
 98	}, &loader)
 99
100	childM.Custom("protocols", false, false, func() (interface{}, error) {
101		return [2]uint16{tls.VersionTLS10, 0}, nil
102	}, TLSVersionsDirective, &tlsVersions)
103
104	childM.Custom("ciphers", false, false, func() (interface{}, error) {
105		return nil, nil
106	}, TLSCiphersDirective, &baseCfg.CipherSuites)
107
108	childM.Custom("curves", false, false, func() (interface{}, error) {
109		return nil, nil
110	}, TLSCurvesDirective, &baseCfg.CurvePreferences)
111
112	if _, err := childM.Process(); err != nil {
113		return nil, err
114	}
115
116	baseCfg.MinVersion = tlsVersions[0]
117	baseCfg.MaxVersion = tlsVersions[1]
118	log.Debugf("tls: min version: %x, max version: %x", tlsVersions[0], tlsVersions[1])
119
120	return &TLSConfig{
121		loader:  loader,
122		baseCfg: &baseCfg,
123	}, nil
124}