package station import ( "crypto/tls" "crypto/x509" "errors" "net" "strings" ) var errHostMismatch = errors.New("host mismatch") func tlsConfig(host string, caPEM []byte, client tls.Certificate, present bool) (*tls.Config, error) { pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(caPEM) { return nil, errors.New("ca bundle") } cfg := &tls.Config{ MinVersion: tls.VersionTLS12, RootCAs: pool, InsecureSkipVerify: true, VerifyConnection: func(cs tls.ConnectionState) error { return verifyPeer(host, pool, cs) }, } if present { cfg.Certificates = []tls.Certificate{client} } return cfg, nil } func verifyPeer(host string, pool *x509.CertPool, cs tls.ConnectionState) error { if len(cs.PeerCertificates) == 0 { return errors.New("no peer certificate") } leaf := cs.PeerCertificates[0] opts := x509.VerifyOptions{Roots: pool, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}} if len(cs.PeerCertificates) > 1 { opts.Intermediates = x509.NewCertPool() for _, cert := range cs.PeerCertificates[1:] { opts.Intermediates.AddCert(cert) } } if _, err := leaf.Verify(opts); err != nil { return err } host = strings.TrimSuffix(host, ".") if ip := net.ParseIP(host); ip != nil { for _, cand := range leaf.IPAddresses { if cand.Equal(ip) { return nil } } return errHostMismatch } if err := leaf.VerifyHostname(host); err != nil { return errHostMismatch } return nil }