Beispiel #1
0
func ExampleConvertToPEM() {
	var p12, _ = base64.StdEncoding.DecodeString(`MIIJzgIBAzCCCZQGCS ... CA+gwggPk==`)
	blocks, err := ConvertToPEM(p12, []byte("password"))
	if err != nil {
		panic(err)
	}

	pemData := []byte{}
	for _, b := range blocks {
		pemData = append(pemData, pem.EncodeToMemory(b)...)
	}

	// then use PEM data for tls to construct tls certificate:

	cert, err := tls.X509KeyPair(pemData, pemData)
	if err != nil {
		panic(err)
	}

	config := tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	config.BuildNameToCertificate()
	for name := range config.NameToCertificate {
		fmt.Println(name)
	}
}
Beispiel #2
0
// NewTLSConfig returns an initialized TLS configuration suitable for client
// authentication. If caFile is non-empty, it will be loaded.
func NewTLSConfig(caFile string, mutualTLS bool) (*tls.Config, error) {
	var c tls.Config

	// TLS 1.0 at a minimum (for mysql)
	c.MinVersion = tls.VersionTLS10
	c.PreferServerCipherSuites = true

	if mutualTLS {
		log.Info("MutualTLS requested, client certificates will be verified")
		c.ClientAuth = tls.VerifyClientCertIfGiven
	}
	if caFile != "" {
		data, err := ioutil.ReadFile(caFile)
		if err != nil {
			return &c, err
		}
		c.ClientCAs = x509.NewCertPool()
		if !c.ClientCAs.AppendCertsFromPEM(data) {
			return &c, errors.New("No certificates parsed")
		}
		log.Info("Read in CA file:", caFile)
	}
	c.BuildNameToCertificate()
	return &c, nil
}
Beispiel #3
0
func TestPEM(t *testing.T) {
	for commonName, base64P12 := range testdata {
		p12, _ := base64.StdEncoding.DecodeString(base64P12)

		blocks, err := ToPEM(p12, "")
		if err != nil {
			t.Fatalf("error while converting to PEM: %s", err)
		}

		var pemData []byte
		for _, b := range blocks {
			pemData = append(pemData, pem.EncodeToMemory(b)...)
		}

		cert, err := tls.X509KeyPair(pemData, pemData)
		if err != nil {
			t.Errorf("err while converting to key pair: %v", err)
		}
		config := tls.Config{
			Certificates: []tls.Certificate{cert},
		}
		config.BuildNameToCertificate()

		if _, exists := config.NameToCertificate[commonName]; !exists {
			t.Errorf("did not find our cert in PEM?: %v", config.NameToCertificate)
		}
	}
}
func (cfg ConfigT) HttpsClient(tmout time.Duration) *http.Client {
	var httpclient http.Client
	var tlsConfig *tls.Config

	tlsConfig = &tls.Config{
		Certificates:       []tls.Certificate{cfg.ClientCert},
		RootCAs:            cfg.ClientCA,
		InsecureSkipVerify: true,
	}
	tlsConfig.BuildNameToCertificate()

	httpclient = http.Client{
		Transport: &http.Transport{
			TLSClientConfig:    tlsConfig,
			DisableCompression: true,
		},
	}

	if tmout > time.Duration(0) {
		httpclient.Transport.(*http.Transport).Dial = func(network, addr string) (net.Conn, error) {
			return net.DialTimeout(network, addr, tmout)
		}
	}

	return &httpclient
}
Beispiel #5
0
func getTLSConfig(clientCertPEMData, clientKeyPEMData []byte) (*tls.Config, error) {
	certPool := x509.NewCertPool()

	certChainPath := os.Getenv("ORCHARD_HOST_CA")
	if certChainPath != "" {
		certChainData, err := ioutil.ReadFile(certChainPath)
		if err != nil {
			return nil, err
		}
		certPool.AppendCertsFromPEM(certChainData)
	} else {
		certPool.AppendCertsFromPEM([]byte(orchardCerts))
	}

	clientCert, err := tls.X509KeyPair(clientCertPEMData, clientKeyPEMData)
	if err != nil {
		return nil, err
	}

	config := new(tls.Config)
	config.RootCAs = certPool
	config.Certificates = []tls.Certificate{clientCert}
	config.BuildNameToCertificate()

	return config, nil
}
Beispiel #6
0
//func (ck *CertKit) GetTLSConfig(AuthRequired bool) (*tls.Config, error) {
func (ck *CertKit) GetTLSConfig(Access uint8) (*tls.Config, error) {
	var atype tls.ClientAuthType
	var tlsConfig *tls.Config
	var roots *x509.CertPool

	switch Access {
	case stonelizard.AccessNone:
		atype = tls.NoClientCert
	case stonelizard.AccessAuth, stonelizard.AccessAuthInfo:
		atype = tls.RequestClientCert
	case stonelizard.AccessVerifyAuth, stonelizard.AccessVerifyAuthInfo:
		atype = tls.RequireAndVerifyClientCert

		// Code adapted from crypto/x509/root_unix.go
		roots = x509.NewCertPool()

		for _, directory := range CertDirectories {
			fis, err := ioutil.ReadDir(directory)
			if err != nil {
				Goose.Auth.Logf(5, "Error scanning certificate directory %s: %s", directory, err)
				continue
			}
			for _, fi := range fis {
				data, err := ioutil.ReadFile(fmt.Sprintf("%s%c%s", directory, os.PathSeparator, fi.Name()))
				if err != nil {
					Goose.Auth.Logf(5, "Error load CA certificate from %s%c%s: %s", directory, os.PathSeparator, fi.Name(), err)
					continue
				}
				Goose.Auth.Logf(5, "Loaded CA certificate from %s%c%s: %s", directory, os.PathSeparator, fi.Name(), err)

				roots.AppendCertsFromPEM(data)
			}
		}
	}

	Goose.Auth.Logf(6, "authtype: %#v", atype)
	Goose.Auth.Logf(6, "CAs: %#v", roots)

	tlsConfig = &tls.Config{
		ClientAuth: atype,
		ClientCAs:  roots,
		//      InsecureSkipVerify: true,
		Certificates: make([]tls.Certificate, 1),
	}

	/*
	   srv.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(svc.PemPath + "/server.crt", svc.PemPath + "/server.key")
	   if err != nil {
	      Goose.InitServe.Logf(1,"Failed reading server certificates: %s",err)
	      return err
	   }
	*/

	tlsConfig.Certificates[0] = ck.ServerX509KeyPair
	Goose.Auth.Logf(5, "X509KeyPair used: %#v", tlsConfig.Certificates[0])
	tlsConfig.BuildNameToCertificate()

	return tlsConfig, nil
}
Beispiel #7
0
func NewNSQD(options *nsqdOptions) *NSQD {
	var tlsConfig *tls.Config

	if options.MaxDeflateLevel < 1 || options.MaxDeflateLevel > 9 {
		log.Fatalf("--max-deflate-level must be [1,9]")
	}

	tcpAddr, err := net.ResolveTCPAddr("tcp", options.TCPAddress)
	if err != nil {
		log.Fatal(err)
	}

	httpAddr, err := net.ResolveTCPAddr("tcp", options.HTTPAddress)
	if err != nil {
		log.Fatal(err)
	}

	if options.StatsdPrefix != "" {
		statsdHostKey := util.StatsdHostKey(net.JoinHostPort(options.BroadcastAddress,
			strconv.Itoa(httpAddr.Port)))
		prefixWithHost := strings.Replace(options.StatsdPrefix, "%s", statsdHostKey, -1)
		if prefixWithHost[len(prefixWithHost)-1] != '.' {
			prefixWithHost += "."
		}
		options.StatsdPrefix = prefixWithHost
	}

	if options.TLSCert != "" || options.TLSKey != "" {
		cert, err := tls.LoadX509KeyPair(options.TLSCert, options.TLSKey)
		if err != nil {
			log.Fatalf("ERROR: failed to LoadX509KeyPair %s", err.Error())
		}
		tlsConfig = &tls.Config{
			Certificates: []tls.Certificate{cert},
			ClientAuth:   tls.VerifyClientCertIfGiven,
		}
		tlsConfig.BuildNameToCertificate()
	}

	n := &NSQD{
		options:    options,
		tcpAddr:    tcpAddr,
		httpAddr:   httpAddr,
		topicMap:   make(map[string]*Topic),
		idChan:     make(chan nsq.MessageID, 4096),
		exitChan:   make(chan int),
		notifyChan: make(chan interface{}),
		tlsConfig:  tlsConfig,
	}

	n.waitGroup.Wrap(func() { n.idPump() })

	return n
}
Beispiel #8
0
func httpClient() (client *http.Client) {
	chain := rootCertificate()
	config := tls.Config{}
	config.RootCAs = x509.NewCertPool()
	for _, cert := range chain.Certificate {
		x509Cert, err := x509.ParseCertificate(cert)
		if err != nil {
			panic(err)
		}
		config.RootCAs.AddCert(x509Cert)
	}
	config.BuildNameToCertificate()
	tr := http.Transport{TLSClientConfig: &config}
	client = &http.Client{Transport: &tr}
	return
}
Beispiel #9
0
// Include our root certificate in TLS.
//
// THIS IS A MODIFICATION TO THE ORIGINAL
// VERSION OF THE SOURCE CODE.
// CHANGED ON SEPTEMBER 05, 2013
//
// This builds on the gist available at:
// https://gist.github.com/laher/5795578
// and is meant to resolve the error:
// "x509: failed to load system roots and no roots provided"
// This happens since cross-compiling disables cgo -
// however cgo is required to find system root
// certificates on darwin machines. Note that the client
// returned can only connect successfully to the
// supplied s3's region.
func getHttpClient(s3 *S3) (*http.Client, error) {
	// get the pem string by running openssl. Note that the
	// endpoint will only work for the regional s3 endpoint
	// supplied
	out, err := exec.Command("openssl", "s_client", "-showcerts", "-connect", strings.Replace(s3.Region.S3Endpoint, "https://", "", -1)+":443").Output()
	if err != nil {
		return nil, err
	}
	certInput := string(out)

	// decode the pem string returned by openssl
	var certChain tls.Certificate
	certPEMBlock := []byte(certInput)
	var certDERBlock *pem.Block
	for {
		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
		if certDERBlock == nil {
			break
		}
		if certDERBlock.Type == "CERTIFICATE" {
			certChain.Certificate = append(certChain.Certificate, certDERBlock.Bytes)
		}
	}

	// inititalize our tls certificate config
	conf := tls.Config{}

	// we're creating a new cert pool here
	// to use for TLS
	conf.RootCAs = x509.NewCertPool()
	for _, cert := range certChain.Certificate {
		x509Cert, err := x509.ParseCertificate(cert)
		if err != nil {
			return nil, err
		}
		conf.RootCAs.AddCert(x509Cert)
	}

	// map certificate names to actual certificates
	conf.BuildNameToCertificate()

	// create a Transport which inlcudes our TLS config
	tr := http.Transport{TLSClientConfig: &conf}

	// add the Transport to our http client
	return &http.Client{Transport: &tr}, nil
}
Beispiel #10
0
// ListenAndServeTLSWithSNI serves TLS with Server Name Indication (SNI) support, which allows
// multiple sites (different hostnames) to be served from the same address. This method is
// adapted directly from the std lib's net/http ListenAndServeTLS function, which was
// written by the Go Authors. It has been modified to support multiple certificate/key pairs.
func ListenAndServeTLSWithSNI(srv *http.Server, tlsConfigs []TLSConfig) error {
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	config := new(tls.Config)
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	// Here we diverge from the stdlib a bit by loading multiple certs/key pairs
	// then we map the server names to their certs
	var err error
	config.Certificates = make([]tls.Certificate, len(tlsConfigs))
	for i, tlsConfig := range tlsConfigs {
		config.Certificates[i], err = tls.LoadX509KeyPair(tlsConfig.Certificate, tlsConfig.Key)
		if err != nil {
			return err
		}
	}
	config.BuildNameToCertificate()

	// Customize our TLS configuration
	config.MinVersion = tlsConfigs[0].ProtocolMinVersion
	config.MaxVersion = tlsConfigs[0].ProtocolMaxVersion
	config.CipherSuites = tlsConfigs[0].Ciphers
	config.PreferServerCipherSuites = tlsConfigs[0].PreferServerCipherSuites

	// TLS client authentication, if user enabled it
	err = setupClientAuth(tlsConfigs, config)
	if err != nil {
		return err
	}

	// Create listener and we're on our way
	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	tlsListener := tls.NewListener(conn, config)

	return srv.Serve(tlsListener)
}
Beispiel #11
0
func buildTLSConfig(opts *nsqd.Options) (*tls.Config, error) {
	var tlsConfig *tls.Config

	if opts.TLSCert == "" && opts.TLSKey == "" {
		return nil, nil
	}

	tlsClientAuthPolicy := tls.VerifyClientCertIfGiven

	cert, err := tls.LoadX509KeyPair(opts.TLSCert, opts.TLSKey)
	if err != nil {
		return nil, err
	}
	switch opts.TLSClientAuthPolicy {
	case "require":
		tlsClientAuthPolicy = tls.RequireAnyClientCert
	case "require-verify":
		tlsClientAuthPolicy = tls.RequireAndVerifyClientCert
	default:
		tlsClientAuthPolicy = tls.NoClientCert
	}

	tlsConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tlsClientAuthPolicy,
		MinVersion:   opts.TLSMinVersion,
		MaxVersion:   tls.VersionTLS12, // enable TLS_FALLBACK_SCSV prior to Go 1.5: https://go-review.googlesource.com/#/c/1776/
	}

	if opts.TLSRootCAFile != "" {
		tlsCertPool := x509.NewCertPool()
		caCertFile, err := ioutil.ReadFile(opts.TLSRootCAFile)
		if err != nil {
			return nil, err
		}
		if !tlsCertPool.AppendCertsFromPEM(caCertFile) {
			return nil, errors.New("failed to append certificate to pool")
		}
		tlsConfig.ClientCAs = tlsCertPool
	}

	tlsConfig.BuildNameToCertificate()

	return tlsConfig, nil
}
Beispiel #12
0
func buildTLSConfig(opts *nsqdOptions) (*tls.Config, error) {
	var tlsConfig *tls.Config

	if opts.TLSCert == "" && opts.TLSKey == "" {
		return nil, nil
	}

	tlsClientAuthPolicy := tls.VerifyClientCertIfGiven

	cert, err := tls.LoadX509KeyPair(opts.TLSCert, opts.TLSKey)
	if err != nil {
		return nil, err
	}
	switch opts.TLSClientAuthPolicy {
	case "require":
		tlsClientAuthPolicy = tls.RequireAnyClientCert
	case "require-verify":
		tlsClientAuthPolicy = tls.RequireAndVerifyClientCert
	default:
		tlsClientAuthPolicy = tls.NoClientCert
	}

	tlsConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tlsClientAuthPolicy,
	}

	if opts.TLSRootCAFile != "" {
		tlsCertPool := x509.NewCertPool()
		ca_cert_file, err := ioutil.ReadFile(opts.TLSRootCAFile)
		if err != nil {
			return nil, err
		}
		if !tlsCertPool.AppendCertsFromPEM(ca_cert_file) {
			return nil, errors.New("failed to append certificate to pool")
		}
		tlsConfig.ClientCAs = tlsCertPool
	}

	tlsConfig.BuildNameToCertificate()

	return tlsConfig, nil
}
Beispiel #13
0
func buildTLSConfig(options *nsqdOptions) *tls.Config {
	var tlsConfig *tls.Config

	if options.TLSCert == "" && options.TLSKey == "" {
		return nil
	}

	tlsClientAuthPolicy := tls.VerifyClientCertIfGiven

	cert, err := tls.LoadX509KeyPair(options.TLSCert, options.TLSKey)
	if err != nil {
		log.Fatalf("ERROR: failed to LoadX509KeyPair %s", err.Error())
	}
	switch options.TLSClientAuthPolicy {
	case "require":
		tlsClientAuthPolicy = tls.RequireAnyClientCert
	case "require-verify":
		tlsClientAuthPolicy = tls.RequireAndVerifyClientCert
	default:
		tlsClientAuthPolicy = tls.NoClientCert
	}

	tlsConfig = &tls.Config{
		Certificates: []tls.Certificate{cert},
		ClientAuth:   tlsClientAuthPolicy,
	}

	if options.TLSRootCAFile != "" {
		tlsCertPool := x509.NewCertPool()
		ca_cert_file, err := ioutil.ReadFile(options.TLSRootCAFile)
		if err != nil {
			log.Fatalf("ERROR: failed to read custom Certificate Authority file %s", err.Error())
		}
		if !tlsCertPool.AppendCertsFromPEM(ca_cert_file) {
			log.Fatalf("ERROR: failed to append certificates from Certificate Authority file")
		}
		tlsConfig.ClientCAs = tlsCertPool
	}

	tlsConfig.BuildNameToCertificate()

	return tlsConfig
}
Beispiel #14
0
func ListenAndServeTLSWithSNI(srv *http.Server, tlsConfigs []TLSConfig) error {
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}

	config := new(tls.Config)
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error
	config.Certificates = make([]tls.Certificate, len(tlsConfigs))
	for i, tlsConfig := range tlsConfigs {
		config.Certificates[i], err = tls.LoadX509KeyPair(tlsConfig.Certificate, tlsConfig.Key)
		if err != nil {
			return err
		}
	}
	config.BuildNameToCertificate()

	config.MinVersion = tlsConfigs[0].ProtocolMinVersion
	config.MaxVersion = tlsConfigs[0].ProtocolMaxVersion
	config.CipherSuites = tlsConfigs[0].Ciphers
	config.PreferServerCipherSuites = tlsConfigs[0].PreferServerCipherSuites

	err = setupClientAuth(tlsConfigs, config)
	if err != nil {
		return err
	}

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	tlsListener := tls.NewListener(conn, config)

	return srv.Serve(tlsListener)
}
Beispiel #15
0
func httpClient() (client *http.Client) {
	if CustomEndpoint == "" {
		chain := rootCertificate()
		config := tls.Config{InsecureSkipVerify: true}
		config.RootCAs = x509.NewCertPool()
		for _, cert := range chain.Certificate {
			x509Cert, err := x509.ParseCertificate(cert)
			if err != nil {
				panic(err)
			}
			config.RootCAs.AddCert(x509Cert)
		}
		config.BuildNameToCertificate()
		tr := http.Transport{TLSClientConfig: &config}
		client = &http.Client{Transport: &tr}
	} else {
		client = &http.Client{}
	}
	return
}
Beispiel #16
0
func NewBroker(options *brokerOptions) *Broker {

	var tlsConfig *tls.Config
	if options.MaxDeflateLevel < 1 || options.MaxDeflateLevel > 9 {
		log.Fatalf("--max-deflate-level must be [1,9]")
	}

	tcpAddr, err := net.ResolveTCPAddr("tcp", options.TCPAddress)
	if err != nil {
		log.Fatal(err)
	}

	httpAddr, err := net.ResolveTCPAddr("tcp", options.HTTPAddress)
	if err != nil {
		log.Fatal(err)
	}

	if options.TLSCert != "" || options.TLSKey != "" {
		cert, err := tls.LoadX509KeyPair(options.TLSCert, options.TLSKey)
		if err != nil {
			log.Fatalf("ERROR: failed to LoadX509KeyPair %s", err.Error())
		}
		tlsConfig = &tls.Config{
			Certificates: []tls.Certificate{cert},
			ClientAuth:   tls.VerifyClientCertIfGiven,
		}
		tlsConfig.BuildNameToCertificate()
	}

	b := &Broker{
		options:  options,
		tcpAddr:  tcpAddr,
		httpAddr: httpAddr,
		clients:  make(map[string]*client, DefaultClientMapSize), //default client map size
		exitChan: make(chan int),
		// notifyChan: make(chan interface{}),
		tlsConfig: tlsConfig,
	}

	return b
}
Beispiel #17
0
func finalizeTLSConfig(tlsConfig *tls.Config, tlsRemoteCert *x509.Certificate) {
	// Trusted certificates
	if tlsRemoteCert != nil {
		caCertPool := x509.NewCertPool()

		// Make it a valid RootCA
		tlsRemoteCert.IsCA = true
		tlsRemoteCert.KeyUsage = x509.KeyUsageCertSign

		// Setup the pool
		caCertPool.AddCert(tlsRemoteCert)
		tlsConfig.RootCAs = caCertPool

		// Set the ServerName
		if tlsRemoteCert.DNSNames != nil {
			tlsConfig.ServerName = tlsRemoteCert.DNSNames[0]
		}
	}

	tlsConfig.BuildNameToCertificate()
}
Beispiel #18
0
// tlsConfig builds a *tls.Config from the given options.
func tlsConfig(insecure bool, certf, keyf string, rootCerts []string) (*tls.Config, error) {
	var err error
	files := map[string][]byte{}
	filenames := append([]string{certf, keyf}, rootCerts...)
	for _, f := range filenames {
		if f != "" {
			if files[f], err = ioutil.ReadFile(f); err != nil {
				return nil, err
			}
		}
	}

	c := tls.Config{InsecureSkipVerify: insecure}
	if cert, ok := files[certf]; ok {
		key, ok := files[keyf]
		if !ok {
			key = cert
		}

		certificate, err := tls.X509KeyPair(cert, key)
		if err != nil {
			return nil, err
		}

		c.Certificates = append(c.Certificates, certificate)
		c.BuildNameToCertificate()
	}

	if len(rootCerts) > 0 {
		c.RootCAs = x509.NewCertPool()
		for _, f := range rootCerts {
			if !c.RootCAs.AppendCertsFromPEM(files[f]) {
				return nil, errBadCert
			}
		}
	}

	return &c, nil
}
Beispiel #19
0
func loadTLS(keyPath, certPath string) (*tls.Config, error) {
	tlsConfig := new(tls.Config)

	tlsConfig.PreferServerCipherSuites = true
	tlsConfig.CipherSuites = []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}

	cert, err := tls.LoadX509KeyPair(certPath, keyPath)
	if err != nil {
		logging.Error("config", "Error loading tls certificate and key files.")
		logging.Error("config", err.Error())
		return nil, err
	}

	tlsConfig.Certificates = []tls.Certificate{cert}
	tlsConfig.BuildNameToCertificate()

	return tlsConfig, nil
}
Beispiel #20
0
func GetConfig(ca_f []byte, ee_f []byte, key_f []byte) (*tls.Config, error) {
	ca, err := x509.ParseCertificate(ca_f)
	if err != nil {
		return nil, err
	}
	pkey, err := x509.ParsePKCS1PrivateKey(key_f)
	if err != nil {
		return nil, err
	}
	ca_pool := x509.NewCertPool()
	ca_pool.AddCert(ca)
	ee_cert := tls.Certificate{
		Certificate: [][]byte{ee_f},
		PrivateKey:  pkey,
	}
	config := new(tls.Config)
	config.ClientAuth = tls.RequireAndVerifyClientCert
	config.Certificates = []tls.Certificate{ee_cert}
	config.ClientCAs = ca_pool
	config.RootCAs = ca_pool
	config.Rand = rand.Reader
	config.BuildNameToCertificate()
	return config, nil
}
Beispiel #21
0
func main() {

	flag.Parse()

	log.Printf("Rosella v%s Initialising.", VERSION)

	//Init rosella itself
	server := NewServer()
	server.name = *serverName

	if *authFile != "" {
		log.Printf("Loading auth file: %q", *authFile)

		f, err := os.Open(*authFile)
		if err != nil {
			log.Fatal(err)
		}
		data := make([]byte, 1024)
		size, err := f.Read(data)
		if err != nil {
			log.Fatal(err)
		}

		lines := strings.Split(string(data[:size]), "\n")
		for _, line := range lines {
			if strings.HasPrefix(line, "#") {
				continue
			}
			fields := strings.Fields(line)

			if len(fields) == 2 {
				server.operatorMap[fields[0]] = fields[1]
			}
		}
	}

	if *motdFile != "" {
		log.Printf("Loading motd file: %q", *motdFile)

		f, err := os.Open(*motdFile)
		if err != nil {
			log.Fatal(err)
		}
		data := make([]byte, 1024)
		size, err := f.Read(data)
		if err != nil {
			log.Fatal(err)
		}

		server.motd = string(data[:size])
	}

	go server.Run()

	tlsConfig := new(tls.Config)

	tlsConfig.PreferServerCipherSuites = true
	tlsConfig.CipherSuites = []uint16{
		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA}

	cert, err := tls.LoadX509KeyPair(*tlsCertFile, *tlsKeyFile)
	if err != nil {
		log.Printf("Error loading tls certificate and key files.")
		log.Printf(err.Error())
		return
	}

	log.Printf("Loaded certificate and key successfully.")

	tlsConfig.Certificates = []tls.Certificate{cert}

	//Fills out tlsConfig.NameToCertificate
	tlsConfig.BuildNameToCertificate()

	tlsListener, err := tls.Listen("tcp", *ircAddress, tlsConfig)
	if err != nil {
		log.Printf("Could not open tls listener.")
		log.Printf(err.Error())
		return
	}

	log.Printf("Listening on %s", *ircAddress)

	if syscall.Getuid() == 0 {
		if *groupId < 1 || *userId < 1 {
			log.Printf("Rosella may not be run as root. Please specify a non-root uid and gid that it may drop to.")
			return
		}
		if syscall.Setgid(*groupId) != nil {
			log.Printf("Failed to set gid to %i", *groupId)
			return
		}
		if syscall.Setuid(*userId) != nil {
			log.Printf("Failed to set uid to %i", *userId)
			return
		}
	}

	for {
		conn, err := tlsListener.Accept()
		if err != nil {
			log.Printf("Error accepting connection.")
			log.Printf(err.Error())
			continue
		}

		server.HandleConnection(conn)
	}
}
Beispiel #22
0
func main() {

	devP := flag.Bool("d", false, "use development push server")

	flag.Parse()
	if flag.NArg() < 1 {
		log.Fatalf("usage: %s [-d] cert.p12", os.Args[0])
	}

	var server string
	if *devP {
		server = "api.development.push.apple.com"
	} else {
		server = "api.push.apple.com"
	}

	d, err := ioutil.ReadFile(flag.Arg(0))
	if err != nil {
		log.Fatal(err)
	}

	key, cert, err := pkcs12.Decode(d, "")
	if err != nil {
		log.Fatal(err)
	}

	tlsConfig := tls.Config{
		Certificates: []tls.Certificate{{
			Certificate: [][]byte{cert.Raw},
			PrivateKey:  key.(*rsa.PrivateKey),
		}},
	}
	tlsConfig.BuildNameToCertificate()

	client := http.Client{
		Transport: &http2.Transport{
			TLSClientConfig: &tlsConfig,
		},
	}

	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		var notification Notification
		err := json.Unmarshal([]byte(scanner.Text()), &notification)
		if err != nil {
			log.Fatal(err)
		}

		resp, err := client.Post(fmt.Sprintf(
			"https://%s/3/device/%s",
			server,
			url.QueryEscape(notification.Token),
		), "", bytes.NewReader(notification.Payload))

		if err != nil {
			log.Fatal(err)
		}

		defer resp.Body.Close()
		var buf bytes.Buffer
		buf.ReadFrom(resp.Body)

		var rawRes *json.RawMessage
		if len(buf.Bytes()) != 0 {
			rm := json.RawMessage(buf.Bytes())
			rawRes = &rm
		}

		json, err := json.Marshal(struct {
			Status int              `json:"status"`
			Body   *json.RawMessage `json:"body,omitempty"`
		}{resp.StatusCode, rawRes})

		if err != nil {
			log.Fatal(err)
		}

		os.Stdout.Write(json)
		os.Stdout.Write([]byte{'\n'})
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}

}
// CreateConsulClient creates a new Consul API client from the given input.
func (c *ClientSet) CreateConsulClient(i *CreateConsulClientInput) error {
	consulConfig := consulapi.DefaultConfig()

	if i.Address != "" {
		consulConfig.Address = i.Address
	}

	if i.Token != "" {
		consulConfig.Token = i.Token
	}

	if i.AuthEnabled {
		consulConfig.HttpAuth = &consulapi.HttpBasicAuth{
			Username: i.AuthUsername,
			Password: i.AuthPassword,
		}
	}

	// This transport will attempt to keep connections open to the Consul server.
	transport := cleanhttp.DefaultPooledTransport()

	// Configure SSL
	if i.SSLEnabled {
		consulConfig.Scheme = "https"

		var tlsConfig tls.Config

		// Custom certificate or certificate and key
		if i.SSLCert != "" && i.SSLKey != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLKey)
			if err != nil {
				return fmt.Errorf("client set: consul: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		} else if i.SSLCert != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLCert)
			if err != nil {
				return fmt.Errorf("client set: consul: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}

		// Custom CA certificate
		if i.SSLCACert != "" || i.SSLCAPath != "" {
			rootConfig := &rootcerts.Config{
				CAFile: i.SSLCACert,
				CAPath: i.SSLCAPath,
			}
			if err := rootcerts.ConfigureTLS(&tlsConfig, rootConfig); err != nil {
				return fmt.Errorf("client set: consul configuring TLS failed: %s", err)
			}
		}

		// Construct all the certificates now
		tlsConfig.BuildNameToCertificate()

		// SSL verification
		if i.ServerName != "" {
			tlsConfig.ServerName = i.ServerName
			tlsConfig.InsecureSkipVerify = false
		}
		if !i.SSLVerify {
			log.Printf("[WARN] (clients) disabling consul SSL verification")
			tlsConfig.InsecureSkipVerify = true
		}

		// Save the TLS config on our transport
		transport.TLSClientConfig = &tlsConfig
	}

	// Setup the new transport
	consulConfig.HttpClient.Transport = transport

	// Create the API client
	client, err := consulapi.NewClient(consulConfig)
	if err != nil {
		return fmt.Errorf("client set: consul: %s", err)
	}

	// Save the data on ourselves
	c.Lock()
	c.consul = &consulClient{
		client:     client,
		httpClient: consulConfig.HttpClient,
	}
	c.Unlock()

	return nil
}
func (c *ClientSet) CreateVaultClient(i *CreateVaultClientInput) error {
	vaultConfig := vaultapi.DefaultConfig()

	if i.Address != "" {
		vaultConfig.Address = i.Address
	}

	// This transport will attempt to keep connections open to the Vault server.
	transport := cleanhttp.DefaultPooledTransport()

	// Configure SSL
	if i.SSLEnabled {
		var tlsConfig tls.Config

		// Custom certificate or certificate and key
		if i.SSLCert != "" && i.SSLKey != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLKey)
			if err != nil {
				return fmt.Errorf("client set: vault: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		} else if i.SSLCert != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLCert)
			if err != nil {
				return fmt.Errorf("client set: vault: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}

		// Custom CA certificate
		if i.SSLCACert != "" || i.SSLCAPath != "" {
			rootConfig := &rootcerts.Config{
				CAFile: i.SSLCACert,
				CAPath: i.SSLCAPath,
			}
			if err := rootcerts.ConfigureTLS(&tlsConfig, rootConfig); err != nil {
				return fmt.Errorf("client set: vault configuring TLS failed: %s", err)
			}
		}

		// Construct all the certificates now
		tlsConfig.BuildNameToCertificate()

		// SSL verification
		if i.ServerName != "" {
			tlsConfig.ServerName = i.ServerName
			tlsConfig.InsecureSkipVerify = false
		}
		if !i.SSLVerify {
			log.Printf("[WARN] (clients) disabling vault SSL verification")
			tlsConfig.InsecureSkipVerify = true
		}

		// Save the TLS config on our transport
		transport.TLSClientConfig = &tlsConfig
	}

	// Setup the new transport
	vaultConfig.HttpClient.Transport = transport

	// Create the client
	client, err := vaultapi.NewClient(vaultConfig)
	if err != nil {
		return fmt.Errorf("client set: vault: %s", err)
	}

	// Set the token if given
	if i.Token != "" {
		client.SetToken(i.Token)
	}

	// Check if we are unwrapping
	if i.UnwrapToken {
		secret, err := client.Logical().Unwrap(i.Token)
		if err != nil {
			return fmt.Errorf("client set: vault unwrap: %s", err)
		}

		if secret == nil {
			return fmt.Errorf("client set: vault unwrap: no secret")
		}

		if secret.Auth == nil {
			return fmt.Errorf("client set: vault unwrap: no secret auth")
		}

		if secret.Auth.ClientToken == "" {
			return fmt.Errorf("client set: vault unwrap: no token returned")
		}

		client.SetToken(secret.Auth.ClientToken)
	}

	// Save the data on ourselves
	c.Lock()
	c.vault = &vaultClient{
		client:     client,
		httpClient: vaultConfig.HttpClient,
	}
	c.Unlock()

	return nil
}
Beispiel #25
0
func StartClient(url_, heads, requestBody string, meth string, dka bool, responseChan chan *Response, waitGroup *sync.WaitGroup, tc int) {
	defer waitGroup.Done()

	var tr *http.Transport

	u, err := url.Parse(url_)

	if err == nil && u.Scheme == "https" {
		var tlsConfig *tls.Config
		if *insecure {
			tlsConfig = &tls.Config{
				InsecureSkipVerify: true,
			}
		} else {
			// Load client cert
			cert, err := tls.LoadX509KeyPair(*certFile, *keyFile)
			if err != nil {
				log.Fatal(err)
			}

			// Load CA cert
			caCert, err := ioutil.ReadFile(*caFile)
			if err != nil {
				log.Fatal(err)
			}
			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(caCert)

			// Setup HTTPS client
			tlsConfig = &tls.Config{
				Certificates: []tls.Certificate{cert},
				RootCAs:      caCertPool,
			}
			tlsConfig.BuildNameToCertificate()
		}

		tr = &http.Transport{TLSClientConfig: tlsConfig, DisableKeepAlives: dka}
	} else {
		tr = &http.Transport{DisableKeepAlives: dka}
	}

	requestBodyReader := strings.NewReader(requestBody)

	req, _ := http.NewRequest(meth, url_, requestBodyReader)
	sets := strings.Split(heads, "\n")

	//Split incoming header string by \n and build header pairs
	for i := range sets {
		split := strings.SplitN(sets[i], ":", 2)
		if len(split) == 2 {
			req.Header.Set(split[0], split[1])
		}
	}

	timer := NewTimer()
	for {
		timer.Reset()

		resp, err := tr.RoundTrip(req)

		respObj := &Response{}

		if err != nil {
			respObj.Error = true
		} else {
			if resp.ContentLength < 0 { // -1 if the length is unknown
				data, err := ioutil.ReadAll(resp.Body)
				if err == nil {
					respObj.Size = int64(len(data))
				}
			} else {
				respObj.Size = resp.ContentLength
			}
			respObj.StatusCode = resp.StatusCode
			resp.Body.Close()
		}

		respObj.Duration = timer.Duration()

		if len(responseChan) >= tc {
			break
		}
		responseChan <- respObj
	}
}
Beispiel #26
0
func (c *ClientSet) CreateVaultClient(i *CreateVaultClientInput) error {
	log.Printf("[INFO] (clients) creating vault/api client")

	// Generate the default config
	vaultConfig := vaultapi.DefaultConfig()

	// Set the address
	if i.Address != "" {
		log.Printf("[DEBUG] (clients) setting vault address to %q", i.Address)
		vaultConfig.Address = i.Address
	}

	// This transport will attempt to keep connections open to the Vault server.
	transport := cleanhttp.DefaultPooledTransport()

	// Configure SSL
	if i.SSLEnabled {
		log.Printf("[DEBUG] (clients) enabling vault SSL")
		var tlsConfig tls.Config

		// Custom certificate or certificate and key
		if i.SSLCert != "" && i.SSLKey != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLKey)
			if err != nil {
				return fmt.Errorf("client set: vault: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		} else if i.SSLCert != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLCert)
			if err != nil {
				return fmt.Errorf("client set: vault: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}

		// Custom CA certificate
		if i.SSLCACert != "" {
			cacert, err := ioutil.ReadFile(i.SSLCACert)
			if err != nil {
				return fmt.Errorf("client set: vault: %s", err)
			}
			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(cacert)

			tlsConfig.RootCAs = caCertPool
		}

		// Construct all the certificates now
		tlsConfig.BuildNameToCertificate()

		// SSL verification
		if !i.SSLVerify {
			log.Printf("[WARN] (clients) disabling vault SSL verification")
			tlsConfig.InsecureSkipVerify = true
		}

		// Save the TLS config on our transport
		transport.TLSClientConfig = &tlsConfig
	}

	// Setup the new transport
	vaultConfig.HttpClient.Transport = transport

	// Create the client
	client, err := vaultapi.NewClient(vaultConfig)
	if err != nil {
		return fmt.Errorf("client set: vault: %s", err)
	}

	// Set the token if given
	if i.Token != "" {
		log.Printf("[DEBUG] (clients) setting vault token")
		client.SetToken(i.Token)
	}

	// Check if we are unwrapping
	if i.UnwrapToken {
		log.Printf("[INFO] (clients) unwrapping vault token")
		secret, err := client.Logical().Unwrap(i.Token)
		if err != nil {
			return fmt.Errorf("client set: vault unwrap: %s", err)
		}

		if secret == nil {
			return fmt.Errorf("client set: vault unwrap: no secret")
		}

		if secret.Auth == nil {
			return fmt.Errorf("client set: vault unwrap: no secret auth")
		}

		if secret.Auth.ClientToken == "" {
			return fmt.Errorf("client set: vault unwrap: no token returned")
		}

		client.SetToken(secret.Auth.ClientToken)
	}

	// Save the data on ourselves
	c.vault = &vaultClient{
		client:     client,
		httpClient: vaultConfig.HttpClient,
	}

	return nil
}
Beispiel #27
0
// CreateConsulClient creates a new Consul API client from the given input.
func (c *ClientSet) CreateConsulClient(i *CreateConsulClientInput) error {
	log.Printf("[INFO] (clients) creating consul/api client")

	// Generate the default config
	consulConfig := consulapi.DefaultConfig()

	// Set the address
	if i.Address != "" {
		log.Printf("[DEBUG] (clients) setting consul address to %q", i.Address)
		consulConfig.Address = i.Address
	}

	// Configure the token
	if i.Token != "" {
		log.Printf("[DEBUG] (clients) setting consul token")
		consulConfig.Token = i.Token
	}

	// Add basic auth
	if i.AuthEnabled {
		log.Printf("[DEBUG] (clients) setting basic auth")
		consulConfig.HttpAuth = &consulapi.HttpBasicAuth{
			Username: i.AuthUsername,
			Password: i.AuthPassword,
		}
	}

	// This transport will attempt to keep connections open to the Consul server.
	transport := cleanhttp.DefaultPooledTransport()

	// Configure SSL
	if i.SSLEnabled {
		log.Printf("[DEBUG] (clients) enabling consul SSL")
		consulConfig.Scheme = "https"

		var tlsConfig tls.Config

		// Custom certificate or certificate and key
		if i.SSLCert != "" && i.SSLKey != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLKey)
			if err != nil {
				return fmt.Errorf("client set: consul: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		} else if i.SSLCert != "" {
			cert, err := tls.LoadX509KeyPair(i.SSLCert, i.SSLCert)
			if err != nil {
				return fmt.Errorf("client set: consul: %s", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
		}

		// Custom CA certificate
		if i.SSLCACert != "" {
			cacert, err := ioutil.ReadFile(i.SSLCACert)
			if err != nil {
				return fmt.Errorf("client set: consul: %s", err)
			}
			caCertPool := x509.NewCertPool()
			caCertPool.AppendCertsFromPEM(cacert)

			tlsConfig.RootCAs = caCertPool
		}

		// Construct all the certificates now
		tlsConfig.BuildNameToCertificate()

		// SSL verification
		if !i.SSLVerify {
			log.Printf("[WARN] (clients) disabling consul SSL verification")
			tlsConfig.InsecureSkipVerify = true
		}

		// Save the TLS config on our transport
		transport.TLSClientConfig = &tlsConfig
	}

	// Setup the new transport
	consulConfig.HttpClient.Transport = transport

	// Create the API client
	client, err := consulapi.NewClient(consulConfig)
	if err != nil {
		return fmt.Errorf("client set: consul: %s", err)
	}

	// Save the data on ourselves
	c.consul = &consulClient{
		client:     client,
		httpClient: consulConfig.HttpClient,
	}

	return nil
}
Beispiel #28
0
// Process a single connection.
func process(cid int, nc net.Conn, certs []tls.Certificate, logf io.Writer, smtplog io.Writer, baserules []*Rule) {
	var evt smtpd.EventInfo
	var convo *smtpd.Conn
	var logger *smtpLogger
	var l2 io.Writer
	var gotsomewhere, stall, sesscounts bool
	var cfg smtpd.Config

	defer nc.Close()

	trans := &smtpTransaction{}
	trans.savedir = savedir
	trans.raddr = nc.RemoteAddr()
	trans.laddr = nc.LocalAddr()
	prefix := fmt.Sprintf("%d/%d", os.Getpid(), cid)
	trans.rip, _, _ = net.SplitHostPort(trans.raddr.String())
	trans.lip, _, _ = net.SplitHostPort(trans.laddr.String())

	var c *Context
	// nit: in the presence of yakkers, we must know whether or not
	// the rules are good because bad rules turn *everyone* into
	// yakkers (since they prevent clients from successfully EHLO'ing).
	rules, rulesgood := setupRules(baserules)

	// A yakker is a client that is repeatedly connecting to us
	// without doing anything successfully. After a certain number
	// of attempts we turn them off. We only do this if we're logging
	// SMTP commands; if we're not logging, we don't care.
	// This is kind of a hack, but this code is for Chris and this is
	// what Chris cares about.
	// sesscounts is true if this session should count for being a
	// 'bad' session if we don't get far enough. Sessions with TLS
	// errors don't count, as do sessions with bad rules or sessions
	// where yakCount == 0.
	sesscounts = rulesgood && yakCount > 0
	hit, cnt := yakkers.Lookup(trans.rip, yakTimeout)
	if yakCount > 0 && hit && cnt >= yakCount && smtplog != nil {
		// nit: if the rules are bad and we're stalling anyways,
		// yakkers still have their SMTP transactions not logged.
		c = newContext(trans, stallall)
		stall = true
		sesscounts = false
	} else {
		c = newContext(trans, rules)
	}
	//fmt.Printf("rules are:\n%+v\n", c.ruleset)

	if smtplog != nil && !stall {
		logger = &smtpLogger{}
		logger.prefix = []byte(prefix)
		logger.writer = bufio.NewWriterSize(smtplog, 8*1024)
		trans.log = logger
		l2 = logger
	}

	sname := trans.laddr.String()
	if srvname != "" {
		sname = srvname
	} else {
		lip, _, _ := net.SplitHostPort(sname)
		// we don't do a verified lookup of the local IP address
		// because it's theoretically under your control, so if
		// you want to forge stuff that's up to you.
		nlst, err := net.LookupAddr(lip)
		if err == nil && len(nlst) > 0 {
			sname = nlst[0]
			if sname[len(sname)-1] == '.' {
				sname = sname[:len(sname)-1]
			}
		}
	}

	if connfile != "" {
		dm, err := loadConnFile(connfile)
		if err != nil {
			warnf("error loading per-connection rules '%s': %s\n", connfile, err)
		}
		// dm.find() explicitly works even on nil dm, so we don't
		// need to guard it.
		if pd := dm.find(nc); pd != nil {
			if pd.myname != "" {
				sname = pd.myname
			}
			certs = pd.certs
		}
	}

	cfg.LocalName = sname
	cfg.SayTime = true
	cfg.SftName = "sinksmtp"
	cfg.Announce = "This server does not deliver email."

	// stalled conversations are always slow, even if -S is not set.
	// TODO: make them even slower than this? I probably don't care.
	if goslow || stall {
		cfg.Delay = time.Second / 10
	}

	// Don't offer TLS to hosts that have too many TLS failures.
	// We give hosts *two* tries at setting up TLS because some
	// hosts start by offering SSLv2, which is an instant-fail,
	// even if they support stuff that we do. We hope that their
	// SSLv2 failure will cause them to try again in another
	// connection with TLS only.
	// See https://code.google.com/p/go/issues/detail?id=3930
	blocktls, blcount := notls.Lookup(trans.rip, tlsTimeout)
	if len(certs) > 0 && !(blocktls && blcount >= 2) {
		var tlsc tls.Config
		tlsc.Certificates = certs
		// if there is already one TLS failure for this host,
		// it might be because of a bad client certificate.
		// so on the second time around we don't ask for one.
		// (More precisely we only ask for a client cert if
		// there are no failures so far.)
		// Another reason for failure here is a SSLv3 only
		// host without a client certificate. This produces
		// the error:
		// tls: received unexpected handshake message of type *tls.clientKeyExchangeMsg when waiting for *tls.certificateMsg
		//if blcount == 0 {
		//	tlsc.ClientAuth = tls.VerifyClientCertIfGiven
		//}
		// Now generally disabled since I discovered it causes
		// SSLv3 handshakes to always fail. TODO: better fix with
		// config-file control or something.
		tlsc.SessionTicketsDisabled = true
		tlsc.ServerName = sname
		tlsc.BuildNameToCertificate()
		cfg.TLSConfig = &tlsc
	}

	// With everything set up we can now create the connection.
	convo = smtpd.NewConn(nc, cfg, l2)

	// Yes, we do rDNS lookup before our initial greeting banner and
	// thus can pause a bit here. Clients will cope, or at least we
	// don't care if impatient ones don't.
	trans.rdns, _ = LookupAddrVerified(trans.rip)

	// Check for an immediate result on the initial connection. This
	// may disable TLS or refuse things immediately.
	if decider(pConnect, evt, c, convo, "") {
		// TODO: somehow write a message and maybe log it.
		// this probably needs smtpd.go cooperation.
		// Right now we just close abruptly.
		if !stall {
			writeLog(logger, "! %s dropped on connect due to rule at %s\n", trans.rip, time.Now().Format(smtpd.TimeFmt))
		}
		return
	}

	// Main transaction loop. We gather up email messages as they come
	// in, possibly failing various operations as we're told to.
	for {
		evt = convo.Next()
		switch evt.What {
		case smtpd.COMMAND:
			switch evt.Cmd {
			case smtpd.EHLO, smtpd.HELO:
				if decider(pHelo, evt, c, convo, "") {
					continue
				}
				trans.heloname = evt.Arg
				trans.from = ""
				trans.data = ""
				trans.hash = ""
				trans.bodyhash = ""
				trans.rcptto = []string{}
				if minphase == "helo" {
					gotsomewhere = true
				}
			case smtpd.MAILFROM:
				if decider(pMfrom, evt, c, convo, "") {
					continue
				}
				if trans.from != "" && !gotsomewhere && sesscounts {
					// We've been RSET, which potentially
					// counts as a failure for do-nothing
					// client detection. Note that we are
					// implicitly adding the *last* failed
					// attempt, the one that was RSET from.
					cnt = yakkers.Add(trans.rip, yakTimeout)
					// We're slightly generous with RSETs.
					// This has no net effect unless this
					// final attempt succeeds.
					if cnt > yakCount {
						writeLog(logger, "! %s added as a yakker at hit %d due to RSET\n", trans.rip, cnt)
						convo.TempfailMsg("Too many unsuccessful delivery attempts")
						// this will implicitly close
						// the connection.
						return
					}
				}
				trans.from = evt.Arg
				trans.data = ""
				trans.rcptto = []string{}
				if minphase == "from" {
					gotsomewhere = true
				}
				doAccept(convo, c, "")
			case smtpd.RCPTTO:
				if decider(pRto, evt, c, convo, "") {
					continue
				}
				trans.rcptto = append(trans.rcptto, evt.Arg)
				if minphase == "to" {
					gotsomewhere = true
				}
				doAccept(convo, c, "")
			case smtpd.DATA:
				if decider(pData, evt, c, convo, "") {
					continue
				}
				if minphase == "data" {
					gotsomewhere = true
				}
				doAccept(convo, c, "")
			}
		case smtpd.GOTDATA:
			// -minphase=message means 'message
			// successfully transmitted to us' as opposed
			// to 'message accepted'.
			if minphase == "message" {
				gotsomewhere = true
			}
			// message rejection is deferred until after logging
			// et al.
			trans.data = evt.Arg
			trans.when = time.Now()
			trans.tlson = convo.TLSOn
			trans.cipher = convo.TLSState.CipherSuite
			trans.servername = convo.TLSState.ServerName
			trans.tlsversion = convo.TLSState.Version
			trans.hash, trans.bodyhash = getHashes(trans)
			transid, err := handleMessage(prefix, trans, logf)
			// errors when handling a message always force
			// a tempfail regardless of how we're
			// configured.
			switch {
			case err != nil:
				convo.Tempfail()
				gotsomewhere = true
			case decider(pMessage, evt, c, convo, transid):
				// do nothing, already handled
			default:
				if minphase == "accepted" {
					gotsomewhere = true
				}
				doAccept(convo, c, transid)
			}
		case smtpd.TLSERROR:
			// any TLS error means we'll avoid offering TLS
			// to this source IP for a while.
			notls.Add(trans.rip, tlsTimeout)
			sesscounts = false
		}
		if evt.What == smtpd.DONE || evt.What == smtpd.ABORT {
			break
		}
	}
	// if the client did not issue any successful meaningful commands,
	// remember this. we squelch people who yak too long.
	// Once people are yakkers we don't count their continued failure
	// to do anything against them.
	// And we have to have good rules to start with because duh.
	switch {
	case !gotsomewhere && sesscounts:
		cnt = yakkers.Add(trans.rip, yakTimeout)
		// See if this transaction has pushed the client over the
		// edge to becoming a yakker. If so, report it to the SMTP
		// log.
		if cnt >= yakCount {
			writeLog(logger, "! %s added as a yakker at hit %d\n", trans.rip, cnt)
		}
	case yakCount > 0 && gotsomewhere:
		yakkers.Del(trans.rip)
	}
}