1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-23 15:37:01 +00:00

dkim: Implement internal dkim signing and verification

This patch implements internal DKIM signing and verification.
This commit is contained in:
Alberto Bertogli
2024-02-10 23:55:05 +00:00
parent f13fdf0ac8
commit 76a72367ae
90 changed files with 4902 additions and 112 deletions

View File

@@ -2,18 +2,26 @@
package smtpsrv
import (
"crypto"
"crypto/ed25519"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"net"
"net/http"
"net/url"
"os"
"path"
"strings"
"time"
"blitiri.com.ar/go/chasquid/internal/aliases"
"blitiri.com.ar/go/chasquid/internal/auth"
"blitiri.com.ar/go/chasquid/internal/courier"
"blitiri.com.ar/go/chasquid/internal/dkim"
"blitiri.com.ar/go/chasquid/internal/domaininfo"
"blitiri.com.ar/go/chasquid/internal/localrpc"
"blitiri.com.ar/go/chasquid/internal/maillog"
@@ -65,6 +73,9 @@ type Server struct {
// Domain info database.
dinfo *domaininfo.DB
// Map of domain -> DKIM signers.
dkimSigners map[string][]*dkim.Signer
// Time before we give up on a connection, even if it's sending data.
connTimeout time.Duration
@@ -91,6 +102,7 @@ func NewServer() *Server {
localDomains: &set.String{},
authr: authr,
aliasesR: aliasesR,
dkimSigners: map[string][]*dkim.Signer{},
}
}
@@ -130,6 +142,48 @@ func (s *Server) AddAliasesFile(domain, f string) error {
return s.aliasesR.AddAliasesFile(domain, f)
}
var (
errDecodingPEMBlock = fmt.Errorf("error decoding PEM block")
errUnsupportedBlockType = fmt.Errorf("unsupported block type")
errUnsupportedKeyType = fmt.Errorf("unsupported key type")
)
// AddDKIMSigner for the given domain and selector.
func (s *Server) AddDKIMSigner(domain, selector, keyPath string) error {
key, err := os.ReadFile(keyPath)
if err != nil {
return err
}
block, _ := pem.Decode(key)
if block == nil {
return errDecodingPEMBlock
}
if strings.ToUpper(block.Type) != "PRIVATE KEY" {
return fmt.Errorf("%w: %s", errUnsupportedBlockType, block.Type)
}
signer, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return err
}
switch k := signer.(type) {
case *rsa.PrivateKey, ed25519.PrivateKey:
// These are supported, nothing to do.
default:
return fmt.Errorf("%w: %T", errUnsupportedKeyType, k)
}
s.dkimSigners[domain] = append(s.dkimSigners[domain], &dkim.Signer{
Domain: domain,
Selector: selector,
Signer: signer.(crypto.Signer),
})
return nil
}
// SetAuthFallback sets the authentication backend to use as fallback.
func (s *Server) SetAuthFallback(be auth.Backend) {
s.authr.Fallback = be
@@ -287,6 +341,7 @@ func (s *Server) serve(l net.Listener, mode SocketMode) {
aliasesR: s.aliasesR,
localDomains: s.localDomains,
dinfo: s.dinfo,
dkimSigners: s.dkimSigners,
deadline: time.Now().Add(s.connTimeout),
commandTimeout: s.commandTimeout,
queue: s.queue,