Resume the control session on the data connection - #82
Open
christhomas wants to merge 1 commit into
Open
Conversation
Fixes secsy#49. Servers commonly require the data connection to resume the control connection's TLS session. It is proftpd's default and vsftpd's require_ssl_reuse, and a data connection that has not resumed is refused: 425-Unable to build data connection: Operation not permitted 522-SSL connection failed; session reuse required Two things have to be true for crypto/tls to resume, and the advice in the issue — set ClientSessionCache — supplies only the first. That is why several people tried it and reported no change. The second is that the cache key has to match. With ServerName empty, crypto/tls keys the cache by *address*, and the address includes the port. The data connection is on a different port, so it never finds the control connection's session; resumption simply does not happen, and nothing says so. Setting ServerName to the host makes both channels agree on one key. So: one cache per client, shared by every connection it opens, and a ServerName defaulted to the host when the caller has not set one. The caller's tls.Config is cloned rather than modified — it is theirs and may be shared with connections this package knows nothing about — and a cache they supplied is used rather than replaced. Both are tested. InsecureSkipVerify is carried across explicitly, so naming the server for the cache key does not start verifying a certificate the caller did not ask to have verified. test-servers/proftpd.conf carried TLSOptions NoSessionReuseRequired, which is exactly the workaround the reporter found. With it, the suite was passing against a configuration almost nobody runs, and this bug was invisible. It is gone. Removing it turned TestExplicitTLS and TestStoreEmptyFileOverTLS red with the reported error, which is how this was reproduced; both pass now. Full suite green three consecutive runs against the stricter server.
This was referenced Aug 26, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #49.
Servers commonly require the data connection to resume the control connection's TLS session — it is proftpd's default and vsftpd's
require_ssl_reuse— and refuse one that has not:Why
ClientSessionCachealone did nothingYou suggested it in the thread, and @wackerm and @mickael-kerjean both reported it changed nothing. They were right, and here is why.
Two conditions have to hold for
crypto/tlsto resume, and the cache is only one:ServerNameis empty,crypto/tlskeys the cache by address, which includes the port. The data connection is on a different port, so it never finds the control connection's session. Resumption simply does not happen, and nothing reports that it didn't.Setting
ServerNameto the host makes both channels agree on one key. That is the missing half.So: one cache per client, shared by every connection it opens, and
ServerNamedefaulted to the host when the caller has not set one.What it does not do
The caller's
tls.Configis cloned, not modified — it is theirs and may be shared with connections this package knows nothing about — and a cache they supplied is used rather than replaced. Both are tested.InsecureSkipVerifyis carried across explicitly, so naming the server for a cache key does not quietly start verifying a certificate the caller did not ask to have verified.On the two resumption mechanisms
@wackerm's analysis in the thread is correct: session IDs are what older proftpd and vsftpd use, and Go's client does not implement them — only session tickets. This fixes the ticket path, which modern builds of both support. A server old enough to offer only session IDs still cannot be resumed against, and that is a
crypto/tlslimitation rather than one this package can route around.Verified against proftpd 1.3.8 configured to require reuse, which is its default. My test config had
TLSOptions NoSessionReuseRequired— the workaround from the issue — and removing it reproduced the reported error exactly; the tests pass with it removed.The server-config half of that lives in #73, so this branch carries only the library change. Same note as my other PRs: off
master, soTestMainstill needs./build_test_server.sh.