jsr369-experts@servlet-spec.java.net

[jsr369-experts] Re: [servlet-spec users] Re: Re: Re: Re: Servlet 4.0 and ALPN

From: <edward.burns_at_oracle.com>
Date: Wed, 5 Oct 2016 19:49:50 +0000 (UTC)

Executive Summary: I'm working with the JDK team to get this resolved
using the approach suggested by Greg: 1st make the Java SE 9 approach
work better, then see about exposing the feature in a JDK 8 vehicle.

Comments inline. I've elided the messages from that single day of
remarkable discussion here.

On 2016-07-29 Stuart Douglas wrote about a workaround to the lack of
JDK8 ALPN support:

SD> Basically it works by modifying the handshake that is sent over the
SD> wire by manually parsing and modifying the TLS frames, and then
SD> using reflection to update the engines internal hash state to match
SD> what was actually sent over the wire (like I said, very hacky).

Yes, very hacky. Now that I have the ear of the JDK team I'm hopeful
we
can do much better than that.

SD> The advantage of this approach is that as long as the SSLEngine
SD> internals do not change too much it works across different versions
SD> of the Oracle JDK and does not require modifying the boot class
SD> path. The major disadvantage is that it is possible that a future
SD> JDK update could break this (and potentially break it in a way that
SD> it cannot be fixed), which makes it very problematic from a support
SD> point of view.

Well, even if we get something in JDK 8, it's still a support burden,
but in that case it would be that support is Oracle's to own.

On 2016-07-29 Greg Wilkins wrote:

GW> Unfortunately even the ALPN solution provided in java9 is looking
GW> like it has problems and the Jetty team has been trying to get some
GW> consideration
GW>
<http://openjdk.5641.n7.nabble.com/Issues-with-ALPN-implementation-in-J
DK-9-tt274952.html#a275096>,
GW> but without much success.

GW> The issue in java 9 is where the intercept points are. In order to
GW> implement their ALPN support, you need to parse the TLS hello
GW> message yourself to determine the offered protocols. However, the
GW> selection of which protocol to accept cannot be done in isolation,
GW> as the HTTP2 spec requires consideration of the cipher that is
GW> negotiated as well. The negotiated cipher is only known after you
GW> allow the SslEngine to also parse the Hello message. So that's a
GW> good point to insert your http2 logic to look at both the protocols
GW> offered and the cipher negotiated in order to select the protocol
GW> before sending the Hello response.

GW> Unfortunately the current implementation of SslEngine does not
allow
GW> the negotiated protocol to be set after the Hello has been
unwrapped
GW> but before the response has been wrapped. This means that as well
GW> has parsing the Hello message yourself, you have to duplicate the
GW> SslEngine logic to work out which cipher it is going to select
GW> (including any SNI and certificate considerations which can be
GW> complex and forever changing), before calling the SslEngine. This
GW> is needless duplication of effort and will be exceedingly fragile
GW> (unless you use two copies of SslEngine for every connection!).

GW> The Oracle team appear to busy on other matters to give this
GW> important issue proper consideration, but have said they will try
GW> <https://www.mail-archive.com/search?l=
GW>
security-dev_at_openjdk.java.net&q=subject:%22Re%5C%3A+Issues+with+ALPN+im
plementation+in+JDK+9%22&o=newest&f=1>,
GW> but no result yet.

GW> I fear we are sleep walking into a poor JDK9 solution that will
GW> cause portability problems. I think we really need to sort that
out
GW> as our highest priority. Once we have a good target in 9, then we
GW> can lobby to have a similar solution in 8.1 or come up with agents
GW> or other patches that provide similar logic.

I respect your sleepwalking analogy. We're awake now.

GW> For clarity, this is the handshake process we would like to see:

GW> 1. Hello frame arrives and is parsed (no library code for this
but
GW> is simple enough)

GW> 2. With knowledge of the protocols & ciphers offered in the
Hello,
GW> the available ciphers of the SslEngine may be trimmed/customized.

GW> 3. The SslEngine unwraps the Hello frame and selects a specific
GW> cipher and SNI based on available ciphers and certificates.

GW> 4. With knowledge of the offered protocols, negotiated cipher,
GW> selected SNI/Certificate a protocol can be selected and set on the
GW> SslEngine.

GW> 5. The SslEngine wraps the Hello frame response with the results
of
GW> all the negotiations.

Greg, can you please send a link to the JavaDocs you've been using to
understand the latest state of the API?

SD> Why would you need two SslEngines per connection? Won't that
SD> situation only arise if the initial negotiation resulted in an
SD> invalid combination (which I think should be very rare in practice,
SD> as clients/servers that do not have strong ciphers should not be
SD> advertising h2 anyway)?

GW> the process to negotiate a cipher is rather complex and relies on:

GW> - ciphers offered

GW> - ciphers available

GW> - certificates available, including signing their signing
GW> algorithms

GW> - SNI names of the certificates and their alternative names

GW> This is all done by SslEngine in an extensible way that will be
GW> updated with new ciphers and certificates over time. All good so
GW> far!

GW> But ALPN/HTTP2 require us to consider the negotiated cipher when
GW> selecting a protocol. It may be that whilst h2 is on offer and
GW> acceptable, the SNI caused a particular certificate to be used that
GW> forced a cipher selection that was unacceptable to h2, and thus
GW> http1 needs to be selected.

GW> So in order to make the protocol selection, we need to know the
GW> selected cipher. But the problem is that with the current
SslEngine
GW> implementation, if you allow it to select a cipher (by unwrapping
GW> the hello), then it is too late to set your protocol selection.

GW> The current solution we are considering is to create 2 SslEngines.
GW> We unwrap the hello frame in the first SslEngine and see what
cipher
GW> it selects. We then discard that SslEngine, configure the 2nd
GW> SslEngine with our choice of protocol and replay the Hello frame to
GW> the 2nd Engine. It now selects the same cipher again and can send
a
GW> hello response with our selected protocol.

GW> The alternate solution, which I believe Redhat are going for, is to
GW> duplicate all the cipher selection logic themselves, which sounds
GW> like a maintenance nightmare to me, as they will need to maintain
GW> forever to track new ciphers and certificates and ensure they never
GW> make a different choice to the SslEngine - Ugh!

GW> The real solution is for Oracle to start listening and to make a
GW> small patch to SslEngine to allow the protocol to be change up
until
GW> the Hello response is wrapped. Only then can we fully implement
the
GW> h2 requirements to select a protocol considering which cipher is
GW> negotiated.

GW> Once we have that logic settled for 9, we can then see what we can
GW> do to implement in 8 - replacing our current partial solution.

SD> My question was basically why do you need to discard the first
SD> SslEngine if it comes up with an acceptable protocol+cipher combo
SD> (which should be the case the majority of the time).

GW> Sure, you can make a pretty good educated guess that the cipher
will
GW> be h2 acceptable and set that on the SslEngine before doing the
GW> unwrap. If the selected cipher is indeed acceptable, then you can
GW> proceed with that SslEngine.

GW> But the edge case still exi ts where the negotiated cipher will not
GW> be h2 acceptable, so in that case the only current option is to
GW> discard the SslEngine and replay the hello to a new one.

Is this edge case entirely due to the "TLS 1.2 Cipher Suite Black List"
provision in HTTP/2 RFC 7540?

GW> I suspect that this will be too much for many implementations and
GW> they will not implement that code and will either fail on these
edge
GW> cases or attempt to use the unacceptable cipher (which will then
put
GW> it back to the client if they fail the connection or also
continue).

GW> So yes we can be more efficient i the hopefully common case of
GW> mostly having h2 acceptable ciphers. But in general, the current
GW> SslEngine does not allow you to set a protocol choice until after
GW> the selection of a cipher that may influence the protocol choice.
GW> Note that eventually we may get h3 or other ALPN protocols to
GW> negotiate and thus any happenstance efficiencies may not continue
GW> unless the design is right.

Ed