-
Notifications
You must be signed in to change notification settings - Fork 149
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
client-side ALPN support #5107
base: master
Are you sure you want to change the base?
client-side ALPN support #5107
Conversation
78f4949
to
c9714b3
Compare
This needs #5097 to land first |
f3450f3
to
ba38150
Compare
@ksmurchison Can I get your input on this please? Especially the "WIP various: add client-side ALPN maps for IANA registered protocols" commit. We have a bunch of things that act as http clients, but it's not clear to me which http protocol version(s) they support. And for http_proxy.c, which looks like it supports 1.0, 1.1, and h2 on the backend -- I think I'll need to implement a check_availability callback for h2 like httpd.c does, but its callback relies on http2_init and http2_start_session, neither of which http_proxy.c ever calls, so I'm not sure. Also, if you have any suggestions for imtest and imclient, I'm all ears. They both implement their own |
We don't have any client-side HTTP/2 code so any connection that we create will be only HTTP/1.1. I think HTTP/1.1 should be the only ALPN token for our client code/
See above.
I'd use the stuff in tls.c if it works. Not sure why there are separate implementations. |
0004221
to
4b94cd2
Compare
@ksmurchison I've added a rfc7301 says:
From my reading, this is saying that the server chooses in order of its preference. That is, if the client supports ("foo", "bar") and the server supports ("bar", "foo"), the server should choose "bar". Our implementation processes them in client preference order and short-circuits at the first match, so it ends up choosing "foo" even though the server would prefer "bar" and both sides support it. The spec says "SHOULD", so this isn't technically wrong. But was this choice deliberate, and if so why? Or is it just something that's shaken out of how you implemented it? My test for this case currently fails, and I'm not sure whether I should change the implementation or just change the test to match. Also, I was scratching my head over this in the next paragraph:
The implication is that accepting a protocol in the TLS negotiation must also configure us to speak that protocol right from the start. At first I couldn't see how this happens for httpd (which is the only server that supports multiple protocols), but I eventually realised that the But I think this logic only works if we examine the client preferences first -- if we simply inverted the pair of loops to choose in the server's preferred order instead of the client's, then h2_is_available would set the connection up for h2 before we know whether the client even supports it. So maybe that's why you made it use the client's preference instead of the server's? Given there's now a way to query the chosen protocol after the TLS session is established, what if we pull the http2_start_session call out of h2_is_available, and instead choose how to proceed based on tls_get_alpn_protocl() after tls_start_servertls() returns? |
e282c2a
to
1c118c0
Compare
Needs #5126 to land first |
7196e4c
to
c63771f
Compare
if (ref $talk->{Socket} ne 'IO::Socket::SSL') { | ||
# STARTTLS failed! Rummage inside Mail::IMAPTalk to put it back into | ||
# a sane state, because the tag having two responses confuses it | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-reading RFC 2595, I'm wondering if imapd, pop3d, etc should just call shutdown() if STARTTLS fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an interesting thought, giving that RFC a read now myself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, it doesn't really give any clear direction about what to do when the TLS negotiation fails, does it. This paragraph is about as close as it gets:
Both the client and server MUST check the result of the STARTTLS command and subsequent TLS negotiation to see whether acceptable authentication or privacy was achieved. Ignoring this step completely invalidates using TLS for security. The decision about whether acceptable authentication or privacy was achieved is made locally, is implementation-dependent, and is beyond the scope of this document.
I think that's giving us permission to handle it however we like. I would argue that a client which has issued STARTTLS expects to get a secure connection, and may not correctly handle the case where the TLS negotiation fails and the connection remains unencrypted. A naive client might just send their password over the wire at this point. That being the case, the server should drop the connection rather than give them the opportunity to do so.
I'm not sure I'm comfortable bundling such a change into this PR though, though it is highlighting the need for it. Guess I'll add it to the pile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can workin that if you like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I actually just wrote up a linear task for it. It's in the triage queue if you wanna grab it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this makes it easier to test
based on a patch from @ksmurchison
Also replace O(mn) algorithm with O(m+n) one. Not sure if this makes a useful difference in normal use, but it feels better.
5d69132
to
87ed240
Compare
87ed240
to
8b73732
Compare
$self->assert_num_equals(1, $response->{success}); | ||
# XXX if we negotiated HTTP/1.0 via ALPN, the server still talks HTTP/1.1 | ||
# XXX anyway... | ||
$self->assert_str_equals('HTTP/1.1', $response->{protocol}); | ||
$self->assert_alpn_protocol(undef, $alpn_map->[0]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ksmurchison Ignoring ALPN for a minute, how do we handle clients that only support HTTP/1.0? I'm thinking about if we can extend the do_h2
stuff after the starttls()
call to also set up HTTP/1.0 vs HTTP/1.1 based on the ALPN negotiation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like that's handled in txn->flags.ver
, but that isn't available until cmdloop, hmm.
While I'm poking around, I notice we also call starttls()
if (I think) the client requests to upgrade the connection to one using TLS. I guess this is the http equivalent of imap STARTTLS. Perhaps we need to check tls_get_alpn_protocol()
there too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elliefm With HTTP/1.x, the client determines the protocol used on the request line. If the client uses HTTP/1.0, the server will respond as such. If the client negotiates 1.0 via ALPN and uses 1.1 or vice-versa, I don't see that as a huge problem. The major difference is that HTTP/1.0 has non-persistent connections by default.
As far as upgrading from plaintext to TLS, this code is only used in a Murder. No existing HTTP clients that I'm aware of use the Upgrade mechanism for anything other than bootstrapping websockets. Even upgrading from HTTP/1.1 to h2 via Upgrade has been deprecated. I wouldn't worry about ALPN here.
No description provided.