From ef4187459e64e5623ed2ad6e94700419f81ef5a5 Mon Sep 17 00:00:00 2001 From: LowEel Date: Sat, 31 Jul 2021 13:26:20 +0200 Subject: [PATCH] Now Zangtumb will create its own selfsigned certificates --- handler.go | 12 +- run.sh | 2 +- smtpd/smtp.go | 3 +- tls.go | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++ zangtumb.go | 11 +- 5 files changed, 315 insertions(+), 11 deletions(-) create mode 100644 tls.go diff --git a/handler.go b/handler.go index d0ba17b..aa276a8 100644 --- a/handler.go +++ b/handler.go @@ -5,11 +5,9 @@ import ( "log" "net" "time" + ) -func init() { - ZangSmtpServer.HandlerRcpt = handlerRcpt -} func mailHandler(origin net.Addr, from string, to []string, data []byte) { @@ -26,7 +24,7 @@ func mailHandler(origin net.Addr, from string, to []string, data []byte) { if dataErr := SmtpSession.Data(bytes.NewReader(data)); dataErr != nil { log.Println("Problem Saving Message: ", dataErr.Error()) } - log.Println("Session is: ", SmtpSession) + } else { log.Println(rcptErr) } @@ -40,14 +38,14 @@ func handlerRcpt(remoteAddr net.Addr, from string, to string) bool { log.Println("CHECK #2 Rcpt to:", to) if !SmtpBackend.CheckValidRcpt(to) { - log.Printf("%s [ %s -> $s ] %s BAD!!!!", "YU NO MAIL!!! WE NU RELAY!!! ", from, to, remoteAddr.String() ) + log.Printf("%s [ %s -> %s ] %s BAD!!!!", "YU NO MAIL!!! WE NU RELAY!!! ", from, to, remoteAddr.String() ) time.Sleep(10 * time.Second) return false }else{ - log.Printf("%s [ %s -> $s ] %s GOOD!!!!", "WE DO!!!", from, to, remoteAddr.String() ) + log.Printf("%s [ %s -> %s ] %s GOOD!!!!", "WE DO!!!", from, to, remoteAddr.String() ) } return true -} \ No newline at end of file +} diff --git a/run.sh b/run.sh index ebb3b12..ee6fa9f 100755 --- a/run.sh +++ b/run.sh @@ -8,7 +8,7 @@ export LISTEN=":1025" ##SESSION -export RECIPIENTS="./recipients.conf" +export RECIPIENTS="./recipients.conf.example" export MAILFOLDER="mail" ##MAIN diff --git a/smtpd/smtp.go b/smtpd/smtp.go index 7b5a241..b226ff8 100644 --- a/smtpd/smtp.go +++ b/smtpd/smtp.go @@ -41,9 +41,10 @@ type AuthHandler func(remoteAddr net.Addr, mechanism string, username []byte, pa // ListenAndServe listens on the TCP network address addr // and then calls Serve with handler to handle requests // on incoming connections. -func ListenAndServe(addr string, handler Handler, appname string, hostname string, instance *Server) error { +func ListenAndServe(addr string, handler Handler, rcpthandler HandlerRcpt, appname string, hostname string, instance *Server) error { srv := instance srv.Addr = addr + srv.HandlerRcpt = rcpthandler srv.Handler = handler srv.Appname = appname srv.Hostname = hostname diff --git a/tls.go b/tls.go new file mode 100644 index 0000000..a4c8538 --- /dev/null +++ b/tls.go @@ -0,0 +1,298 @@ +package main + + +import ( + + "crypto/ecdsa" + + "crypto/ed25519" + + "crypto/elliptic" + + "crypto/rand" + + "crypto/rsa" + + "crypto/x509" + + "crypto/x509/pkix" + + "encoding/pem" + + "log" + + "math/big" + + "net" + + "os" + + "strings" + + "time" + +) + + + + + +func publicKey(priv interface{}) interface{} { + + switch k := priv.(type) { + + case *rsa.PrivateKey: + + return &k.PublicKey + + case *ecdsa.PrivateKey: + + return &k.PublicKey + + case ed25519.PrivateKey: + + return k.Public().(ed25519.PublicKey) + + default: + + return nil + + } + +} + + +func ZMakecert() { + + + + host := ZangSmtpServer.Hostname + + validFrom := "" + + validFor := time.Duration(3650 * 24 * time.Hour) + + isCA := false + + rsaBits := 4096 + + ecdsaCurve := "P256" + + ed25519Key := true + + + var priv interface{} + + var err error + + switch ecdsaCurve { + + case "": + + if ed25519Key { + + _, priv, err = ed25519.GenerateKey(rand.Reader) + + } else { + + priv, err = rsa.GenerateKey(rand.Reader, rsaBits) + + } + + case "P224": + + priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + + case "P256": + + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + + case "P384": + + priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + + case "P521": + + priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + + default: + + log.Fatalf("Unrecognized elliptic curve: %q", ecdsaCurve) + + } + + if err != nil { + + log.Fatalf("Failed to generate private key: %v", err) + + } + + + // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature + + // KeyUsage bits set in the x509.Certificate template + + keyUsage := x509.KeyUsageDigitalSignature + + // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In + + // the context of TLS this KeyUsage is particular to RSA key exchange and + + // authentication. + + if _, isRSA := priv.(*rsa.PrivateKey); isRSA { + + keyUsage |= x509.KeyUsageKeyEncipherment + + } + + + var notBefore time.Time + + if len(validFrom) == 0 { + + notBefore = time.Now() + + } else { + + notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom) + + if err != nil { + + log.Fatalf("Failed to parse creation date: %v", err) + + } + + } + + + notAfter := notBefore.Add(validFor) + + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + + if err != nil { + + log.Fatalf("Failed to generate serial number: %v", err) + + } + + + template := x509.Certificate{ + + SerialNumber: serialNumber, + + Subject: pkix.Name{ + + Organization: []string{"ZangTumb SMTP Server Department"}, + + }, + + NotBefore: notBefore, + + NotAfter: notAfter, + + + KeyUsage: keyUsage, + + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + + BasicConstraintsValid: true, + + } + + + hosts := strings.Split(host, ",") + + for _, h := range hosts { + + if ip := net.ParseIP(h); ip != nil { + + template.IPAddresses = append(template.IPAddresses, ip) + + } else { + + template.DNSNames = append(template.DNSNames, h) + + } + + } + + + if isCA { + + template.IsCA = true + + template.KeyUsage |= x509.KeyUsageCertSign + + } + + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + + if err != nil { + + log.Fatalf("Failed to create certificate: %v", err) + + } + + + + certOut, err := os.Create(CrtFile) + + if err != nil { + + log.Fatalf("Failed to open cert.pem for writing: %v", err) + + } + + if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { + + log.Fatalf("Failed to write data to cert.pem: %v", err) + + } + + if err := certOut.Close(); err != nil { + + log.Fatalf("Error closing cert.pem: %v", err) + + } + + log.Println("Finished creating: ", CrtFile) + + + keyOut, err := os.OpenFile(KeyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) + + if err != nil { + + log.Fatalf("Failed to open key.pem for writing: %v", err) + + return + + } + + privBytes, err := x509.MarshalPKCS8PrivateKey(priv) + + if err != nil { + + log.Fatalf("Unable to marshal private key: %v", err) + + } + + if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { + + log.Fatalf("Failed to write data to key.pem: %v", err) + + } + + if err := keyOut.Close(); err != nil { + + log.Fatalf("Error closing key.pem: %v", err) + + } + + log.Println("Finished creating: ", KeyFile) + +} diff --git a/zangtumb.go b/zangtumb.go index 34fb708..fbe4830 100644 --- a/zangtumb.go +++ b/zangtumb.go @@ -49,12 +49,19 @@ func init() { log.Println("WARNING: NOT Using TLS") } + ZMakecert() + + log.Println("Ready to start the server.") + } func main() { - if err := smtpd.ListenAndServe(ListenAddr, mailHandler, AppName, ServerName, ZangSmtpServer); err != nil { + log.Println("Starting the server....") + + defer log.Println("Shutting down the server") + + if err := smtpd.ListenAndServe(ListenAddr, mailHandler, handlerRcpt, AppName, ServerName, ZangSmtpServer); err != nil { log.Panicln("Ops. Something went wrong: ", err.Error()) } - }