Hi all,

Simone/Xuelei/I wrote:
Per my understanding, application protocol should be negotiated before
>>>cipher suite and protocol version negotiated.
>>
>>This is not possible for HTTP/2.
>>Application protocol negotiation MUST happen*after*  the TLS protocol
>>and the TLS cipher are negotiated.
>
>Yes, that's my understanding as well.
What are the behaviors of other vendors?  Can we ask for a clarification
from both HTTP/2 and TLS WG?

and then Simone wrote:
I support Xuelei in that you should ask confirmation to the HTTP/2
editor.

Thanks for the encouragement, Simone. As you've probably heard, I did contact the IETF HTTP/2 working group and posed several questions about expected usage[1]. I'm combining those responses plus several other points that came up since the last discussion. This may be repeating some things already said, but serves as useful background info for those here that might not be following closely:

1. HTTP/2 (aka H2) and TLSv1.3 were developed in parallel. The H2 designers wanted the ciphersuite restrictions in the proposed TLSv1.3. But since TLSv1.3 wasn't ready, they compromised by allowing TLSv1.2 to be used but with the restriction that only those ciphersuites that were expected/allowed for TLSv1.3 could be used. That is, there is a blacklist of ciphersuites for TLSv1.2: if a suite is present, it can't be used in TLSv1.2. (e.g. no RSA KeyExchange, no CBC-based block ciphers, no stream ciphers, etc.)

2. RFC 7301 says in a couple places that it would be advantageous to have the chosen ALPN value used by the certificate selection mechanism (See sections 1 & 4). Without a radical rewrite of the current selection mechanism (n-tuple), that means ALPN selection should be done before the ciphersuite is selected. We could also check after, but I have a different approach (see below).

3. From the H2 working group discussion, a server instance will very likely support both H2 and legacy HTTP/1.1. This means for servers that prefer H2, any iterative cipher selection mechanisms needs to try the H2-specific ciphersuites first, then legacy non-H2 suites. That is, the suites must be ordered appropriately so that the ciphersuite selection mechanism won't attempt a blacklisted suite before exhausting all H2-acceptable suites. This ordering can be requested today in JSSE by the server calling sslParameters.setUseCipherSuitesOrder(true). This particular point won't matter when TLSv1.3 is in play, as we wouldn't try those suites at all.

4. Clients may not know whether a server will be H2 or HTTP/1.1, so they should also appropriately sort ciphersuites based on their ALPN preferences. (H2 first, H1 second.)

5. For our SunJSSE, while I think our current enabled list order is generally ok, we should probably reorder the ciphersuite priorities so that the TLSv1.3 acceptable suites are up front, with the others following. This prefers forward secrecy ciphersuites to our current ordering. I am thinking we should probably do this for JDK 9, and maybe backport as well. The current webrev (link below) doesn't have this yet.

6. To avoid downgrade attacks, applications should not provide for a fallback mechanism. This includes ALPN selection.

Connection#1:  {"h2", "http/1.1"}     // Don't make two connections.
Connection#2:  {"http/1.1"}

POODLE was a good example where allowing fallbacks bit hard.

Of course, we can't control this at the JSSE layer, it's the application layer responsibility.

Tradeoff between A) change radically the OpenJDK implementation to
support an iterative processing of TLS protocols, extensions (all of
them), ciphers, aliases, etc. that would be future proof (if that is
even possible) and B) hack in just enough of what is needed to support
H2 today (for which we already have working examples) ?

Given where we are now schedule wise (integration currently due at the end of September), and that SunJSSE is such an iterative implementation, coming up with a multi-selector API is likely beyond what we can do at this point.

(webrev link below).

IMHO, the following works well. I've added a new method that contains the ordered list of ciphersuites still to be tried which is a hint for ALPN selection, but we delay the actual ciphersuite selection until after the ALPN value is chosen. So the algorithm is now:

    0.  Applications (especially server) might order suites with h2
        first for TLSv1.2. sslParameters.setUseCipherSuitesOrder(true)
        should be called on the server to ensure those suites are
        tried first.

    1.  Start Handshake.

    2.  Internal server handshaker chooses the TLS version.

    3.  The internal server handshaker finds the client/server/protocol
        version intersection of the suites, loads the initial ordered
        list into a new method on a SSLSession (obtained by the
        getHandshakeSSLSession()), then iterates through the
        ordered list of ciphersuites as usual.

    4.  For each "candidate" ciphersuite, first call the
        ApplicationProtocolSelector to choose an appropriate ALPN value.
        The getHandshakeSSLSession() contains the negotiated TLS
        protocol version and the ordered ciphersuite list with the
        "candidate" suite as the first entry.

        Note:  If the client sent unsupported ALPN values, the Selector
        can throw a SSLHandshakeException at this point and generate the
        "no_application_protocol" alert.

        The Selector can also either choose to ignore/skip the suite, or
        accept the suite but choose no ALPN value.

    5.  Continue the ciphersuite selection routine as usual (check for
        appropriate Keys, etc).  The KeyManager now has access to the
        negotiated TLS version and ALPN value along with the
        ciphersuite via the same/usual
        getHandshakeSSLSession().
        This satisfies the RFC 7301 goal of having
        the certificate selection mechanism use the ALPN value.

        As ciphersuites are removed from consideration via the
        internal iterator in 3, they are also removed from the
        corresponding SSLSession entry.

    6.  When handshaking is complete, the applications should verify
        that the session parameters (protocol version, ALPN value, and
        ciphersuites, etc.) are suitable, and send a HTTP-level
        INADEQUATE_SECURITY (H2) if there's a problem.

In general, if the ciphersuites aren't ordered properly, that should be considered a configuration error on the part of the application(s). However, this dynamic ALPN selection approach still allows for appropriate ALPN values to be selected for each possible ciphersuite. That is, if the suites were ordered H1/H2, the ALPN value should be H1.

For an example of such a selector, please see the new H2/H2+H1/H1 ApplicationProtocolSelector implementions in ApplicationProtocolSelector.java, and how they are called in ServerHandshaker.java.


Here is the latest:

http://cr.openjdk.java.net/~wetmore/8051498/webrev.09


The main changes from the previous webrev:

    ApplicationProtocolSelector.java
    ================================

1. Added default implementations for H2, H2+H1, H1 so that people don't have to write their own. This makes things much more convenient.

If folks want to insert their own SPDY implementations (H2/SPDY*/H1), they can use the these implementation as a wrapper class to their own code:

    public class MySpdyALPN implements ApplicationProtocolSelector {

        ApplicationProtocolSelector aps;

        MySpdyALPN(ApplicationProtocolSelector aps) {
            this.aps = aps;
        }

        public String select() {
            String retval = aps.select();
            if (retval.equals("h2")) {
                return retval;
            }
            if (someSPDY3Conditions()) {
                return "spdy/3";
            }
            if (someSPDY2Conditions()) {
                return "spdy/2";
            }
            return retval;
        }
    }

2. Added a public List of the RFC 7540 Blacklisted ciphersuites. For historical reasons, the Standard Names prefixes for JSSE ciphersuites are a mix of "SSL_" and "TLS_", so everyone who wants to implement a blacklist would have to get these values right. I've added this both for my default implementations and for developer convenience.

3.  Added some examples in the class descriptor.


    ExtendedSSLSession.java
    =======================
    public String[] getHandshakeCipherSuiteList()

1. This returns an ordered dynamic list of ciphersuites still under consideration for this handshake. As ciphersuites are removed from consideration, successive calls will return smaller arrays.

2. ApplicationSelector now distinguishes between null and empty String return values:

* @return a non-empty protocol {@code String} to send to the client,
*     an empty string if no protocol indication (i.e. extension)
*     should be sent, or null if the current most-preferred ciphersuite
*     should be skipped.

That is, if the return value is null, we skip this suite from consideration and go to the next one. This is useful if only H2 is being considered, and we find out that a suite is on the blacklist. There is no reason to consider it further.


    SSLParameters.java
    =======================

Added an examples in the class description.


As far as backporting goes, this API is not particularly friendly in that it requires a ApplicationProtocolSelector. We could add a private API, or use a system property and provide a default selector that looks at the property and takes the most preferred one.

Vinnie is reworking his original ALPN code to use the new API, so we should be in pretty good shape for integration at the end of Sept.

Thanks,

Brad

[1] https://lists.w3.org/Archives/Public/ietf-http-wg/2015JulSep/0154.html

Reply via email to