Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto/tls: revert CL 107627, which writes memory it does not own #28744

rsc opened this issue Nov 12, 2018 · 3 comments

crypto/tls: revert CL 107627, which writes memory it does not own #28744

rsc opened this issue Nov 12, 2018 · 3 comments


Copy link

rsc commented Nov 12, 2018

User code creates a tls.Config by initializing various fields
and then passes that tls.Config to the crypto/tls library for
use in places like server and client.

There are methods on tls.Config that clearly modify the Config.
One such method is BuildNameToCertificate, which is documented as:

// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
// from the CommonName and SubjectAlternateName fields of each of the leaf
// certificates.

Fields in tls.Config point at other data, which may or may not be
unique to the Config. For example, there are some x509.CertPools.
It would be problematic for the TLS server or client to assume the
tls.Config held the only reference to the cert pool and that it was
OK to do things like call AddCert to modify the pool.

Same for modifying CipherSuites and CurvePreferences.
For example maybe the server would run faster if it first
filtered out the suites or curves that aren't supported, so that
those entries don't have to be skipped over all the time.
Too bad: that's not the server's memory and it cannot modify those.

CL 107627 did something like that: it is assuming that the
certificates listed in config.Certificates are allowed to be
scribbled on. I don't believe we've ever said that was OK in the past,
and it seems plausible that there might be user code that relies
on the fact that the slice is NOT scribbled over by the server.

Specifically, BuildNameToCertificate is now filling in
config.Certificates[0].Leaf, where before it did not.
I think that slice's memory must be treated as read-only
and should not be modified at all.

At the very least, if you have two different configs sharing the
same Certificate slice, there is now a race where they are both
reading and writing to that cert.Leaf field without coordination.

CL 107627 should be reverted. The original justification said:

I am working on a TLS server program, which issues new TLS certificates
on demand. The new certificates will be added into tls.Config.Certificates.

If it is important for performance that the parsing be
avoided, then the code could be changed to do:

x509Cert := cert.Leaf
if x509Cert == nil {
	... parse into x509Cert but DO NOT MODIFY cert.Leaf ...

Then at least the code that cares could pre-populate Leaf
and bypass the x509.ParseCertificate.

@rsc rsc added this to the Go1.12 milestone Nov 12, 2018
Copy link

FiloSottile commented Nov 12, 2018

I got too distracted thinking through if there was a scenario where this behavior was globally safe, and didn't stop to think about ownership separation. I agree this is wrong, and that we can make all the performance gain available by optionally using (but not setting) cert.Leaf.

Mailing a CL for that.

(It also didn't help that it's a []Certificate, not a []*Certificate, which feels like the Config owns a copy to a cursory look.)

Copy link

Change mentions this issue: crypto/tls: don't modify Config.Certificates in BuildNameToCertificate

Copy link

I've added a suggestion for a test on that CL, PTAL and thank you.

@golang golang locked and limited conversation to collaborators Nov 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet

No branches or pull requests

4 participants