pkg/transport/listener.go
func (info TLSInfo) baseConfig() (*tls.Config, error) {
	if info.KeyFile == "" || info.CertFile == "" {
		return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
	}
	if info.Logger == nil {
		info.Logger = zap.NewNop()
	}

	_, err := tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
	if err != nil {
		return nil, err
	}

	cfg := &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: info.ServerName,
	}

	if len(info.CipherSuites) > 0 {
		cfg.CipherSuites = info.CipherSuites
	}

	if info.AllowedCN != "" {
		cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
			for _, chains := range verifiedChains {
				if len(chains) != 0 {
					if info.AllowedCN == chains[0].Subject.CommonName {
						return nil
					}
				}
			}
			return errors.New("CommonName authentication failed")
		}
	}

	// this only reloads certs when there's a client request
	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
		cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
		if os.IsNotExist(err) {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to find peer cert files",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		} else if err != nil {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to create peer certificate",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		}
		return cert, err
	}
	cfg.GetClientCertificate = func(unused *tls.CertificateRequestInfo) (cert *tls.Certificate, err error) {
		cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
		if os.IsNotExist(err) {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to find client cert files",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		} else if err != nil {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to create client certificate",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		}
		return cert, err
	}
	return cfg, nil
}
func (info TLSInfo) baseConfig() (*tls.Config, error) {
	if info.KeyFile == "" || info.CertFile == "" {
		return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", info.KeyFile, info.CertFile)
	}
	if info.Logger == nil {
		info.Logger = zap.NewNop()
	}

	_, err := tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
	if err != nil {
		return nil, err
	}

	cfg := &tls.Config{
		MinVersion: tls.VersionTLS12,
		ServerName: info.ServerName,
	}

	if len(info.CipherSuites) > 0 {
		cfg.CipherSuites = info.CipherSuites
	}

	if info.AllowedCN != "" {
		cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
			for _, chains := range verifiedChains {
				if len(chains) != 0 {
					if info.AllowedCN == chains[0].Subject.CommonName {
						return nil
					}
				}
			}
			return errors.New("CommonName authentication failed")
		}
	}

	// this only reloads certs when there's a client request
	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (cert *tls.Certificate, err error) {
		cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
		if os.IsNotExist(err) {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to find peer cert files",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		} else if err != nil {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to create peer certificate",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		}
		return cert, err
	}
	cfg.GetClientCertificate = func(unused *tls.CertificateRequestInfo) (cert *tls.Certificate, err error) {
		cert, err = tlsutil.NewCert(info.CertFile, info.KeyFile, info.parseFunc)
		if os.IsNotExist(err) {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to find client cert files",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		} else if err != nil {
			if info.Logger != nil {
				info.Logger.Warn(
					"failed to create client certificate",
					zap.String("cert-file", info.CertFile),
					zap.String("key-file", info.KeyFile),
					zap.Error(err),
				)
			}
		}
		return cert, err
	}
	return cfg, nil
}
func ( info TLSInfo ) baseConfig ( ) ( * tls . Config , error ) { if info . KeyFile == " " || info . CertFile == " " { return nil , fmt . Errorf ( " " , info . KeyFile , info . CertFile ) } if info . Logger == nil { info . Logger = zap . NewNop ( ) } _ , err := tlsutil . NewCert ( info . CertFile , info . KeyFile , info . parseFunc ) if err != nil { return nil , err } cfg := & tls . Config { MinVersion : tls . VersionTLS12 , ServerName : info . ServerName , } if len ( info . CipherSuites ) > 0 { cfg . CipherSuites = info . CipherSuites } if info . AllowedCN != " " { cfg . VerifyPeerCertificate = func ( rawCerts [ ] [ ] byte , verifiedChains [ ] [ ] * x509 . Certificate ) error { for _ , chains := range verifiedChains { if len ( chains ) != 0 { if info . AllowedCN == chains [ 0 ] . Subject . CommonName { return nil } } } return errors . New ( " " ) } } // this only reloads certs when there's a client request // TODO: support server-side refresh (e.g. inotify, SIGHUP), caching cfg . GetCertificate = func ( clientHello * tls . ClientHelloInfo ) ( cert * tls . Certificate , err error ) { cert , err = tlsutil . NewCert ( info . CertFile , info . KeyFile , info . parseFunc ) if os . IsNotExist ( err ) { if info . Logger != nil { info . Logger . Warn ( " " , zap . String ( " " , info . CertFile ) , zap . String ( " " , info . KeyFile ) , zap . Error ( err ) , ) } } else if err != nil { if info . Logger != nil { info . Logger . Warn ( " " , zap . String ( " " , info . CertFile ) , zap . String ( " " , info . KeyFile ) , zap . Error ( err ) , ) } } return cert , err } cfg . GetClientCertificate = func ( unused * tls . CertificateRequestInfo ) ( cert * tls . Certificate , err error ) { cert , err = tlsutil . NewCert ( info . CertFile , info . KeyFile , info . parseFunc ) if os . IsNotExist ( err ) { if info . Logger != nil { info . Logger . Warn ( " " , zap . String ( " " , info . CertFile ) , zap . String ( " " , info . KeyFile ) , zap . Error ( err ) , ) } } else if err != nil { if info . Logger != nil { info . Logger . Warn ( " " , zap . String ( " " , info . CertFile ) , zap . String ( " " , info . KeyFile ) , zap . Error ( err ) , ) } } return cert , err } return cfg , nil }
// baseConfig is called on initial TLS handshake start.
//
// Previously,
// 1. Server has non-empty (*tls.Config).Certificates on client hello
// 2. Server calls (*tls.Config).GetCertificate iff:
//    - Server's (*tls.Config).Certificates is not empty, or
//    - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
//
// When (*tls.Config).Certificates is always populated on initial handshake,
// client is expected to provide a valid matching SNI to pass the TLS
// verification, thus trigger server (*tls.Config).GetCertificate to reload
// TLS assets. However, a cert whose SAN field does not include domain names
// but only IP addresses, has empty (*tls.ClientHelloInfo).ServerName, thus
// it was never able to trigger TLS reload on initial handshake; first
// ceritifcate object was being used, never being updated.
//
// Now, (*tls.Config).Certificates is created empty on initial TLS client
// handshake, in order to trigger (*tls.Config).GetCertificate and populate
// rest of the certificates on every new TLS connection, even when client
// SNI is empty (e.g. cert only includes IPs).
baseConfig is called on initial TLS handshake start . Previously 1 . Server has non - empty ( * tls . Config ) . Certificates on client hello 2 . Server calls ( * tls . Config ) . GetCertificate iff : - Server s ( * tls . Config ) . Certificates is not empty or - Client supplies SNI ; non - empty ( * tls . ClientHelloInfo ) . ServerName When ( * tls . Config ) . Certificates is always populated on initial handshake client is expected to provide a valid matching SNI to pass the TLS verification thus trigger server ( * tls . Config ) . GetCertificate to reload TLS assets . However a cert whose SAN field does not include domain names but only IP addresses has empty ( * tls . ClientHelloInfo ) . ServerName thus it was never able to trigger TLS reload on initial handshake ; first ceritifcate object was being used never being updated . Now ( * tls . Config ) . Certificates is created empty on initial TLS client handshake in order to trigger ( * tls . Config ) . GetCertificate and populate rest of the certificates on every new TLS connection even when client SNI is empty ( e . g . cert only includes IPs ) .