summaryrefslogtreecommitdiff
path: root/src/pkg/net/smtp/smtp_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/smtp/smtp_test.go')
-rw-r--r--src/pkg/net/smtp/smtp_test.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index 2133dc7c7..3fba1ea5a 100644
--- a/src/pkg/net/smtp/smtp_test.go
+++ b/src/pkg/net/smtp/smtp_test.go
@@ -7,6 +7,8 @@ package smtp
import (
"bufio"
"bytes"
+ "crypto/tls"
+ "crypto/x509"
"io"
"net"
"net/textproto"
@@ -548,3 +550,145 @@ AUTH PLAIN AHVzZXIAcGFzcw==
*
QUIT
`
+
+func TestTLSClient(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+ errc := make(chan error)
+ go func() {
+ errc <- sendMail(ln.Addr().String())
+ }()
+ conn, err := ln.Accept()
+ if err != nil {
+ t.Fatalf("failed to accept connection: %v", err)
+ }
+ defer conn.Close()
+ if err := serverHandle(conn, t); err != nil {
+ t.Fatalf("failed to handle connection: %v", err)
+ }
+ if err := <-errc; err != nil {
+ t.Fatalf("client error: %v", err)
+ }
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+type smtpSender struct {
+ w io.Writer
+}
+
+func (s smtpSender) send(f string) {
+ s.w.Write([]byte(f + "\r\n"))
+}
+
+// smtp server, finely tailored to deal with our own client only!
+func serverHandle(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ send("220 127.0.0.1 ESMTP service ready")
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250-127.0.0.1 ESMTP offers a warm hug of welcome")
+ send("250-STARTTLS")
+ send("250 Ok")
+ case "STARTTLS":
+ send("220 Go ahead")
+ keypair, err := tls.X509KeyPair(localhostCert, localhostKey)
+ if err != nil {
+ return err
+ }
+ config := &tls.Config{Certificates: []tls.Certificate{keypair}}
+ c = tls.Server(c, config)
+ defer c.Close()
+ return serverHandleTLS(c, t)
+ default:
+ t.Fatalf("unrecognized command: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func serverHandleTLS(c net.Conn, t *testing.T) error {
+ send := smtpSender{c}.send
+ s := bufio.NewScanner(c)
+ for s.Scan() {
+ switch s.Text() {
+ case "EHLO localhost":
+ send("250 Ok")
+ case "MAIL FROM:<joe1@example.com>":
+ send("250 Ok")
+ case "RCPT TO:<joe2@example.com>":
+ send("250 Ok")
+ case "DATA":
+ send("354 send the mail data, end with .")
+ send("250 Ok")
+ case "Subject: test":
+ case "":
+ case "howdy!":
+ case ".":
+ case "QUIT":
+ send("221 127.0.0.1 Service closing transmission channel")
+ return nil
+ default:
+ t.Fatalf("unrecognized command during TLS: %q", s.Text())
+ }
+ }
+ return s.Err()
+}
+
+func init() {
+ testRootCAs := x509.NewCertPool()
+ testRootCAs.AppendCertsFromPEM(localhostCert)
+ testHookStartTLS = func(config *tls.Config) {
+ config.RootCAs = testRootCAs
+ }
+}
+
+func sendMail(hostPort string) error {
+ host, _, err := net.SplitHostPort(hostPort)
+ if err != nil {
+ return err
+ }
+ auth := PlainAuth("", "", "", host)
+ from := "joe1@example.com"
+ to := []string{"joe2@example.com"}
+ return SendMail(hostPort, auth, from, to, []byte("Subject: test\n\nhowdy!"))
+}
+
+// (copied from net/http/httptest)
+// localhostCert is a PEM-encoded TLS cert with SAN IPs
+// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
+// of ASN.1 time).
+// generated from src/pkg/crypto/tls:
+// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
+bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
+bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
+IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
+AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
+AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
+Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+-----END CERTIFICATE-----`)
+
+// localhostKey is the private key for localhostCert.
+var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
+0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
+NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
+AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
+MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
+EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
+1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+-----END RSA PRIVATE KEY-----`)