derp/derpserver,cmd/derper: don't mutate cert provider's shared tls.Certificate (#20478)
ModifyTLSConfigToAddMetaCert (and its inline copy in cmd/derper) appended the DERP meta cert directly to the *tls.Certificate returned by the underlying GetCertificate. autocert returns a certificate sharing a cached chain slice (and, on the TLS-ALPN token path, the same pointer) across concurrent handshakes, so the in-place append was a data race and could grow the served chain unboundedly. Return a shallow copy with the meta cert appended to a fresh backing array instead, and have cmd/derper reuse ModifyTLSConfigToAddMetaCert rather than duplicating the wrapper. Fixes #20352 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
This commit is contained in:
+5
-6
@@ -35,10 +35,9 @@ var unsafeHostnameCharacters = regexp.MustCompile(`[^a-zA-Z0-9-\.]`)
|
||||
type certProvider interface {
|
||||
// TLSConfig creates a new TLS config suitable for net/http.Server servers.
|
||||
//
|
||||
// The returned Config must have a GetCertificate function set and that
|
||||
// function must return a unique *tls.Certificate for each call. The
|
||||
// returned *tls.Certificate will be mutated by the caller to append to the
|
||||
// (*tls.Certificate).Certificate field.
|
||||
// The returned Config must have a GetCertificate function set. The
|
||||
// *tls.Certificate values it returns may be shared and cached, so
|
||||
// callers must not mutate them.
|
||||
TLSConfig() *tls.Config
|
||||
// HTTPHandler handle ACME related request, if any.
|
||||
HTTPHandler(fallback http.Handler) http.Handler
|
||||
@@ -157,8 +156,8 @@ func (m *manualCertManager) getCertificate(hi *tls.ClientHelloInfo) (*tls.Certif
|
||||
return nil, fmt.Errorf("cert mismatch with hostname: %q", hi.ServerName)
|
||||
}
|
||||
|
||||
// Return a shallow copy of the cert so the caller can append to its
|
||||
// Certificate field.
|
||||
// Return a shallow copy of the cert with a capacity-clamped chain
|
||||
// so callers can never mutate the manager's long-lived certificate.
|
||||
certCopy := new(tls.Certificate)
|
||||
*certCopy = *m.cert
|
||||
certCopy.Certificate = certCopy.Certificate[:len(certCopy.Certificate):len(certCopy.Certificate)]
|
||||
|
||||
@@ -354,15 +354,7 @@ func main() {
|
||||
log.Fatalf("derper: can not start cert provider: %v", err)
|
||||
}
|
||||
httpsrv.TLSConfig = certManager.TLSConfig()
|
||||
getCert := httpsrv.TLSConfig.GetCertificate
|
||||
httpsrv.TLSConfig.GetCertificate = func(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
cert, err := getCert(hi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.Certificate = append(cert.Certificate, s.MetaCert())
|
||||
return cert, nil
|
||||
}
|
||||
s.ModifyTLSConfigToAddMetaCert(httpsrv.TLSConfig)
|
||||
// Disable TLS 1.0 and 1.1, which are obsolete and have security issues.
|
||||
httpsrv.TLSConfig.MinVersion = tls.VersionTLS12
|
||||
httpsrv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user