Repository: traefik/traefik
File: pkg/tls/tlsmanager.go (Go)

Code before:
		sniStrict = config.SniStrict
		tlsConfig, err = buildTLSConfig(config)
	} else {
		err = fmt.Errorf("unknown TLS options: %s", configName)
	}
	if err != nil {
		tlsConfig = &tls.Config{}
	}

	store := m.getStore(storeName)
	if store == nil {
		err = fmt.Errorf("TLS store %s not found", storeName)
	}
	acmeTLSStore := m.getStore(tlsalpn01.ACMETLS1Protocol)
	if acmeTLSStore == nil {
		err = fmt.Errorf("ACME TLS store %s not found", tlsalpn01.ACMETLS1Protocol)
	}

	tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		domainToCheck := types.CanonicalDomain(clientHello.ServerName)

		if isACMETLS(clientHello) {
			certificate := acmeTLSStore.GetBestCertificate(clientHello)
			if certificate == nil {
				log.WithoutContext().Debugf("TLS: no certificate for TLSALPN challenge: %s", domainToCheck)
				// Let crypto/tls determine the appropriate error and the TLS alert.
				// https://cs.opensource.google/go/go/+/dev.boringcrypto.go1.17:src/crypto/tls/common.go;l=1058
				return nil, nil
			}

			return certificate, nil
		}

		bestCertificate := store.GetBestCertificate(clientHello)
		if bestCertificate != nil {
			return bestCertificate, nil
		}

		if sniStrict {
			log.WithoutContext().Debugf("TLS: strict SNI enabled - No certificate found for domain: %q, closing connection", domainToCheck)
			// Let crypto/tls determine the appropriate error and the TLS alert.
			// https://cs.opensource.google/go/go/+/dev.boringcrypto.go1.17:src/crypto/tls/common.go;l=1058
			return nil, nil
		}

		log.WithoutContext().Debugf("Serving default certificate for request: %q", domainToCheck)
		return store.DefaultCertificate, nil
	}

	return tlsConfig, err
}

Review comment (bug):
```suggestion
				// We want the user to eventually get the (alertUnrecognizedName) "unrecognized
				// name" error.
				// Unfortunately, if we returned an error here, since we can't use
				// the unexported error (errNoCertificates) that our caller (config.getCertificate
				// in crypto/tls) uses as a sentinel, it would report an (alertInternalError)
				// "internal error" instead of an alertUnrecognizedName.
				// Which is why we return no error, and we let the caller detect that there's
				// actually no certificate, and fall back into the flow that will report
				// the desired error.
```

Code after:
		sniStrict = config.SniStrict
		tlsConfig, err = buildTLSConfig(config)
	} else {
		err = fmt.Errorf("unknown TLS options: %s", configName)
	}
	if err != nil {
		tlsConfig = &tls.Config{}
	}

	store := m.getStore(storeName)
	if store == nil {
		err = fmt.Errorf("TLS store %s not found", storeName)
	}
	acmeTLSStore := m.getStore(tlsalpn01.ACMETLS1Protocol)
	if acmeTLSStore == nil {
		err = fmt.Errorf("ACME TLS store %s not found", tlsalpn01.ACMETLS1Protocol)
	}

	tlsConfig.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
		domainToCheck := types.CanonicalDomain(clientHello.ServerName)

		if isACMETLS(clientHello) {
			certificate := acmeTLSStore.GetBestCertificate(clientHello)
			if certificate == nil {
				log.WithoutContext().Debugf("TLS: no certificate for TLSALPN challenge: %s", domainToCheck)
				// We want the user to eventually get the (alertUnrecognizedName) "unrecognized
				// name" error.
				// Unfortunately, if we returned an error here, since we can't use
				// the unexported error (errNoCertificates) that our caller (config.getCertificate
				// in crypto/tls) uses as a sentinel, it would report an (alertInternalError)
				// "internal error" instead of an alertUnrecognizedName.
				// Which is why we return no error, and we let the caller detect that there's
				// actually no certificate, and fall back into the flow that will report
				// the desired error.
				// https://cs.opensource.google/go/go/+/dev.boringcrypto.go1.17:src/crypto/tls/common.go;l=1058
				return nil, nil
			}

			return certificate, nil
		}

		bestCertificate := store.GetBestCertificate(clientHello)
		if bestCertificate != nil {
			return bestCertificate, nil
		}

		if sniStrict {
			log.WithoutContext().Debugf("TLS: strict SNI enabled - No certificate found for domain: %q, closing connection", domainToCheck)
			// Same comment as above, as in the isACMETLS case.
			return nil, nil
		}