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: handshake fails with EOF #13523

Closed
rszewczyk opened this issue Dec 7, 2015 · 15 comments
Closed

crypto/tls: handshake fails with EOF #13523

rszewczyk opened this issue Dec 7, 2015 · 15 comments

Comments

@rszewczyk
Copy link

Go Version: 1.5.1
OS/Arch: Linux & Darwin/amd64

I'm trying to connect to a web service hosted by a third party using mutual TLS. Here is the simple test case I am trying:

https://play.golang.org/p/wr8x8awD8u

I am able to connect as expected to the same web service with the same parameters for key, cert, etc using curl:

curl --cacert /home/nifi/robtest/nexusproxy/guard_ca.pem --cert /path/to/public_crt.pem --key /path/to/private_key.pem https://some.server.com:8000/some/path

The go test case fails with an EOF error.

Further:

I've traced the error to this line in the tls client handshake:

https://github.com/golang/go/blob/go1.5.1/src/crypto/tls/handshake_client.go#L561

This section https://github.com/golang/go/blob/go1.5.1/src/crypto/tls/conn.go#L541-L546 would seem to suggest that an EOF is expected in some cases but there doesn't appear to be any code to handle such a case.

@bradfitz
Copy link
Contributor

bradfitz commented Dec 7, 2015

The code you referenced in conn.go is about alertCloseNotify (secure EOF). The comment there makes sense in context.

But an EOF during handshake? I don't see how that can be ignored. If you get an EOF during handshake you won't be using that TLS connection. Seems like it failed for a reason.

@allgeek
Copy link

allgeek commented Dec 7, 2015

I'd double-check the supported cipher suites on the third-party service. We recently tracked down an EOF during TLS handshake that was a result of the remote service not allowing the default cipher suites Go's TLS implementation uses (though explicitly enabling one of the four non-default ciphers did work). curl would be using different ciphers than your Go test case...

@axaxs
Copy link

axaxs commented Dec 7, 2015

Regardless of whether this is cause of original error, I feel the issue should stand even if just to clean up wording (unless I'm reading it incorrectly). It states that it cannot make io.EOF an error, but on the next line sets it as an error since it would fail the net.Error type assertion. Am I misreading?

@rszewczyk
Copy link
Author

@allgeek good call... adding -v to curl reveals that it's using: TLS_DHE_RSA_WITH_AES_128_CBC_SHA by default. However after modifying the command to:

curl -v \
  --tlsv1.2 \
  --ciphers ecdhe_rsa_aes_128_sha \
  --cacert /home/nifi/robtest/nexusproxy/guard_ca.pem \
  --cert /path/to/public_crt.pem \
  --key /path/to/private_key.pem https://some.server.com:8000/some/path \

It's still connecting, but with a supported cipher this time. That's not to say it still couldn't be an issue of curl doing something automagically for me (I guess since it works, that's pretty likely).

Since opening the issue I've learned that this is what's running on the other side:

https://nifi.apache.org/index.html

I'm trying to get more information on configuration, but at least I might have a chance of getting something running to test against now.

@mikioh mikioh changed the title TLS handshake fails with EOF crypto/tls: handshake fails with EOF Dec 8, 2015
@rsc
Copy link
Contributor

rsc commented Dec 28, 2015

It sounds like what's going on is that if you use Go's TLS client to connect to a server that doesn't like any of the client's suggested protocols, the server just hangs up, and the Go client reports just "EOF". It should probably at least say something about being in a handshake. Does it? I don't see the actual output in the original bug report.

@rsc rsc added this to the Go1.6Maybe milestone Dec 28, 2015
@rszewczyk
Copy link
Author

@rsc - Yes, it just reports EOF.

Personally, I didn't find the abbreviated error to be all that limiting. It only took me a few minutes to modify crypto/tls and find the line that was returning the error. I was just thrown off by the section in conn.go that I referenced above - but bradfitz cleared that up.

I wasn't able to reproduce this on my own - that is I couldn't get a test case (with my own server) where the go client failed and curl succeeded (they either both succeeded or both failed) so this seems to be some weird edge case. Unfortunately I'm unable to find out anything more about the third party server that would help.

As far as I'm concerned, I feel like the issue is resolved as well as it can be, although I can see how a more precise error message could help in some cases.

@rsc
Copy link
Contributor

rsc commented Jan 5, 2016

OK, well it would be good to return unexpected EOF when its truly unexpected. But not a blocker for the release. Leaving open in case someone wants to work on it later.

@rsc rsc modified the milestones: Unplanned, Go1.6Maybe Jan 5, 2016
@agl agl self-assigned this Aug 19, 2016
@einthusan
Copy link

I manage a site with very large traffic and using Go 1.8 beta in production. We moved over from a PHP implementation by re-writing everything from scratch in go. We saw a significant drop in our users, and seeing our logs flooding with http: TLS handshake error from <IP>:<PORT>: EOF errors. I am not sure if this is related to the issue being discussed here. Is there anything we can do to help test why these errors are happening? Every browser we tested seems to work fine. We used BrowerStack for our testing on various OS and browser versions. However, we are pretty sure something is problematic in either our code or our TLS certificates. Any help would be appreciated. The domain in question is einthusan.tv

@bradfitz
Copy link
Contributor

@einthusan, that seems unrelated. This bug was about client-side TLS. I'd move your server-side question to https://golang.org/wiki/Questions for now.

I think I'm actually going to close this bug as TimedOut, since it's been a year now (two releases) and there's nothing quite actionable here.

Anybody, feel free to reopen either this or another perhaps ideally a new bug with details of client-side TLS problems with Go 1.8beta+.

@agl
Copy link
Contributor

agl commented Jan 16, 2017

@einthusan your site requires SNI support, which will exclude clients that don't send SNI (like IE 8). That could be your problem. I'd look at how you're selecting certificates at handshake time.

@einthusan
Copy link

@agl I will look into what SNI is and how to support it... It really sucks that "Go" doesn't have a "true" full-compatability SSL support by default. The entire "being really secure" model is causing all sorts of problems in the wild by not having "99%" support for all browsers out there.

@agl
Copy link
Contributor

agl commented Jan 25, 2017

@einthusan SNI is the server name that some clients send (i.e. the ServerName in ClientHelloInfo. To be clear: dependence on SNI is something that has been done on top of Go's standard libraries, it's not typical of Go servers.

@rsc
Copy link
Contributor

rsc commented Jan 25, 2017

@einthusan The behavior depends on the tls.Config you use to run the server. If you set config.Certificates to the certificate for einthusan.tv, then clients not using SNI will be able to connect just fine. If you only set config.GetCertificate, leaving config.Certificates nil, then only SNI clients will work.

einthusan.tv is serving using a Let's Encrypt-issued cert. The Go clients I know about that integrate directly into the web server hook in with config.GetCertificate, for decent reasons. That would have the side-effect of requiring SNI. If you were serving HTTPS with PHP before, you should have an old certificate you can drop into config.Certificate. If not, you can probably get one with a command-line Let's Encrypt client and drop it in (but note that it expires in a short time interval, like three months).

@agl
Copy link
Contributor

agl commented Jan 25, 2017

The GetCertificate callback will be made, even without SNI, if config.Certificates is empty [1]. However, it's certainly possible that the callback itself is returning an error if ServerName is empty.

@rsc
Copy link
Contributor

rsc commented Jan 25, 2017

I filed #18785, assuming that einthusan.tv is using golang.org/x/crypto/acme/autocert. Let's move the conversation there.

@golang golang locked and limited conversation to collaborators Jan 25, 2018
@rsc rsc unassigned agl Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants