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	"github.com/foxcpp/maddy/framework/log"
 26)
 27
 28var strVersionsMap = map[string]uint16{
 29	"tls1.0": tls.VersionTLS10,
 30	"tls1.1": tls.VersionTLS11,
 31	"tls1.2": tls.VersionTLS12,
 32	"tls1.3": tls.VersionTLS13,
 33	"":       0, // use crypto/tls defaults if value is not specified
 34}
 35
 36var strCiphersMap = map[string]uint16{
 37	// TLS 1.0 - 1.2 cipher suites.
 38	"RSA-WITH-RC4128-SHA":                tls.TLS_RSA_WITH_RC4_128_SHA,
 39	"RSA-WITH-3DES-EDE-CBC-SHA":          tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
 40	"RSA-WITH-AES128-CBC-SHA":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,
 41	"RSA-WITH-AES256-CBC-SHA":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
 42	"RSA-WITH-AES128-CBC-SHA256":         tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
 43	"RSA-WITH-AES128-GCM-SHA256":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
 44	"RSA-WITH-AES256-GCM-SHA384":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
 45	"ECDHE-ECDSA-WITH-RC4128-SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
 46	"ECDHE-ECDSA-WITH-AES128-CBC-SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
 47	"ECDHE-ECDSA-WITH-AES256-CBC-SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
 48	"ECDHE-RSA-WITH-RC4128-SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
 49	"ECDHE-RSA-WITH-3DES-EDE-CBC-SHA":    tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
 50	"ECDHE-RSA-WITH-AES128-CBC-SHA":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
 51	"ECDHE-RSA-WITH-AES256-CBC-SHA":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
 52	"ECDHE-ECDSA-WITH-AES128-CBC-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
 53	"ECDHE-RSA-WITH-AES128-CBC-SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
 54	"ECDHE-RSA-WITH-AES128-GCM-SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
 55	"ECDHE-ECDSA-WITH-AES128-GCM-SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
 56	"ECDHE-RSA-WITH-AES256-GCM-SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
 57	"ECDHE-ECDSA-WITH-AES256-GCM-SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
 58	"ECDHE-RSA-WITH-CHACHA20-POLY1305":   tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
 59	"ECDHE-ECDSA-WITH-CHACHA20-POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
 60}
 61
 62var strCurvesMap = map[string]tls.CurveID{
 63	"p256":   tls.CurveP256,
 64	"p384":   tls.CurveP384,
 65	"p521":   tls.CurveP521,
 66	"X25519": tls.X25519,
 67}
 68
 69// TLSversionsDirective parses directive with arguments that specify
 70// minimum and maximum supported TLS versions.
 71//
 72// It returns [2]uint16 value for use in corresponding fields from tls.Config.
 73func TLSVersionsDirective(_ *config.Map, node config.Node) (interface{}, error) {
 74	switch len(node.Args) {
 75	case 1:
 76		value, ok := strVersionsMap[node.Args[0]]
 77		if !ok {
 78			return nil, config.NodeErr(node, "invalid TLS version value: %s", node.Args[0])
 79		}
 80		return [2]uint16{value, value}, nil
 81	case 2:
 82		minValue, ok := strVersionsMap[node.Args[0]]
 83		if !ok {
 84			return nil, config.NodeErr(node, "invalid TLS version value: %s", node.Args[0])
 85		}
 86		maxValue, ok := strVersionsMap[node.Args[1]]
 87		if !ok {
 88			return nil, config.NodeErr(node, "invalid TLS version value: %s", node.Args[1])
 89		}
 90		return [2]uint16{minValue, maxValue}, nil
 91	default:
 92		return nil, config.NodeErr(node, "expected 1 or 2 arguments")
 93	}
 94}
 95
 96// TLSCiphersDirective parses directive with arguments that specify
 97// list of ciphers to offer to clients (or to use for outgoing connections).
 98//
 99// It returns list of []uint16 with corresponding cipher IDs.
100func TLSCiphersDirective(_ *config.Map, node config.Node) (interface{}, error) {
101	if len(node.Args) == 0 {
102		return nil, config.NodeErr(node, "expected at least 1 argument, got 0")
103	}
104
105	res := make([]uint16, 0, len(node.Args))
106	for _, arg := range node.Args {
107		cipherId, ok := strCiphersMap[arg]
108		if !ok {
109			return nil, config.NodeErr(node, "unknown cipher: %s", arg)
110		}
111		res = append(res, cipherId)
112	}
113	log.Debugln("tls: using non-default cipherset:", node.Args)
114	return res, nil
115}
116
117// TLSCurvesDirective parses directive with arguments that specify
118// elliptic curves to use during TLS key exchange.
119//
120// It returns []tls.CurveID.
121func TLSCurvesDirective(_ *config.Map, node config.Node) (interface{}, error) {
122	if len(node.Args) == 0 {
123		return nil, config.NodeErr(node, "expected at least 1 argument, got 0")
124	}
125
126	res := make([]tls.CurveID, 0, len(node.Args))
127	for _, arg := range node.Args {
128		curveId, ok := strCurvesMap[arg]
129		if !ok {
130			return nil, config.NodeErr(node, "unknown curve: %s", arg)
131		}
132		res = append(res, curveId)
133	}
134	log.Debugln("tls: using non-default curve preferences:", node.Args)
135	return res, nil
136}