1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package module2021import (22 "context"23 "crypto/tls"24)2526const (27 AuthDisabled = "off"28 AuthMTASTS = "mtasts"29 AuthDNSSEC = "dnssec"30 AuthCommonDomain = "common_domain"31)3233type (34 TLSLevel int35 MXLevel int36)3738const (39 TLSNone TLSLevel = iota40 TLSEncrypted41 TLSAuthenticated42)4344const (45 MXNone MXLevel = iota46 MX_MTASTS47 MX_DNSSEC48)4950func (l TLSLevel) String() string {51 switch l {52 case TLSNone:53 return "none"54 case TLSEncrypted:55 return "encrypted"56 case TLSAuthenticated:57 return "authenticated"58 }59 return "???"60}6162func (l MXLevel) String() string {63 switch l {64 case MXNone:65 return "none"66 case MX_MTASTS:67 return "mtasts"68 case MX_DNSSEC:69 return "dnssec"70 }71 return "???"72}7374type (75 // MXAuthPolicy is an object that provides security check for outbound connections.76 // It can do one of the following:77 //78 // - Check effective TLS level or MX level against some configured or79 // discovered value.80 // E.g. local policy.81 //82 // - Raise the security level if certain condition about used MX or83 // connection is met.84 // E.g. DANE MXAuthPolicy raises TLS level to Authenticated if a matching85 // TLSA record is discovered.86 //87 // - Reject the connection if certain condition about used MX or88 // connection is _not_ met.89 // E.g. An enforced MTA-STS MXAuthPolicy rejects MX records not matching it.90 //91 // It is not recommended to mix different types of behavior described above92 // in the same implementation.93 // Specifically, the first type is used mostly for local policies and is not94 // really practical.95 //96 // Modules implementing this interface should be registered with "mx_auth."97 // prefix in name.98 MXAuthPolicy interface {99 Start(*MsgMetadata) DeliveryMXAuthPolicy100101 // Weight is an integer in range 0-1000 that represents relative102 // ordering of policy application.103 Weight() int104 }105106 // DeliveryMXAuthPolicy is an interface of per-delivery object that estabilishes107 // and verifies required and effective security for MX records and TLS108 // connections.109 DeliveryMXAuthPolicy interface {110 // PrepareDomain is called before DNS MX lookup and may asynchronously111 // start additional lookups necessary for policy application in CheckMX112 // or CheckConn.113 //114 // If there any errors - they should be deferred to the CheckMX or115 // CheckConn call.116 PrepareDomain(ctx context.Context, domain string)117118 // PrepareConn is called before connection and may asynchronously119 // start additional lookups necessary for policy application in120 // CheckConn.121 //122 // If there are any errors - they should be deferred to the CheckConn123 // call.124 PrepareConn(ctx context.Context, mx string)125126 // CheckMX is called to check whether the policy permits to use a MX.127 //128 // mxLevel contains the MX security level estabilished by checks129 // executed before.130 //131 // domain is passed to the CheckMX to allow simpler implementation132 // of stateless policy objects.133 //134 // dnssec is true if the MX lookup was performed using DNSSEC-enabled135 // resolver and the zone is signed and its signature is valid.136 CheckMX(ctx context.Context, mxLevel MXLevel, domain, mx string, dnssec bool) (MXLevel, error)137138 // CheckConn is called to check whether the policy permits to use this139 // connection.140 //141 // tlsLevel and mxLevel contain the TLS security level estabilished by142 // checks executed before.143 //144 // domain is passed to the CheckConn to allow simpler implementation145 // of stateless policy objects.146 //147 // If tlsState.HandshakeCompleted is false, TLS is not used. If148 // tlsState.VerifiedChains is nil, InsecureSkipVerify was used (no149 // ServerName or PKI check was done).150 CheckConn(ctx context.Context, mxLevel MXLevel, tlsLevel TLSLevel, domain, mx string, tlsState tls.ConnectionState) (TLSLevel, error)151152 // Reset cleans the internal object state for use with another message.153 // newMsg may be nil if object is not needed anymore.154 Reset(newMsg *MsgMetadata)155 }156)