Greetings,

Xuelei wrote:

> I think Brad would consider our information for his design.

I did, and thanks for the all of the detailed discussion, Simone/Michael/Xuelei. I've taken into account the feedback from the previous discussion back in June. Here is v3 of the public ALPN API.

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

Main points:

1.  SSLBase/SSLFunction gone

2.  New ApplicationProtocolSelector class with two select methods:

        select(SSLSocket), select(SSLEngine)
            throws SSLHandshakeException instead
                of SSLProtocolException (oops/sorry!)

3.  "@since 1.9" changes to "@since 9"  (changes for JDK 9)

4.  SSLSession.getCipherSuite()
        a getHandshakeSession.getCipherSuite() no longer dynamic value
        ALPN Selector will be called after suite has been set.

5.  Psuedo code in the SunJSSEimplementation for ALPN selection.

6.  Working HTTP 2 & 1.1 client/server configuration example (test).

Various responses, I'll try to attribute the original author correctly. :) If I missed a point you feel is important, please restate.

Simone wrote:
>>  ExtendedSSLSession
>>     public List<String> getReceivedApplicationProtocols() {
>
> This is a constant once the application protocols are received, so it
> can be surely retrieved from SSLParameters.
> I don't understand why it is replicated here ?

SSLParameters is a configuration class which is used to configure SSLSockets/SSLEngines. SSLSession/ExtendedSSLSession is a class which holds negotiated Session values. getReceivedApplicationProtocols() represents the Application Protocol values received from the peer, thus belongs in the SSLSession.

One other point that is not always obvious to folks is that a single SSLParameters object can be used to initialize multiple SSLEngine/SSLSocket objects. You can configure sockets as part of a customer SSLSocketFactory, or by using SSLParameters.

Regarding the old SSLFunction/SSLBase:

> I'm not sure about this one being a marker interface.
> I could understand if it extracted the common functionality of
> SSLEngine and SSLSocket, but a marker interface does not really add
> much, and perhaps I would prefer it entirely gone.

Previously it was suggested that the ALPN selector could be a @FunctionalInterface (Simone?) and generic (Sean?), so I was trying to accommodate that. Both are gone now. We could still introduce a SSLBase with these methods:

---begin---
public abstract String[] getEnabledCipherSuites()
public abstract void setEnabledCipherSuites(String[] suites)

public abstract String[] getEnabledProtocols()
public abstract void setEnabledProtocols(String[] protocols)

public abstract boolean getEnableSessionCreation()
public abstract void setEnableSessionCreation(boolean flag)

public SSLSession getHandshakeSession()
    minor tweak for SSLSocket about getSession()

public abstract void setNeedClientAuth(boolean need)
public abstract boolean getNeedClientAuth()

public abstract SSLSession getSession()
    minor tweak needed in SSLSocket

public abstract String[] getSupportedCipherSuites()

public abstract String[] getSupportedProtocols()

public abstract boolean getUseClientMode()
public abstract void setUseClientMode(boolean mode)

public abstract boolean getWantClientAuth()
public abstract void setWantClientAuth(boolean want)

public SSLParameters getSSLParameters()
public void setSSLParameters(SSLParameters params)
---end---

which would eliminate the SSLEngine/SSLSocket-specific methods in ApplicationProtocolSelector.java, but I'm not sure it's worth the effort to isolate all these methods just to lose one method in the ALPN selector.

To do this as a @FunctionInterface, I wanted to use java.util.function.Function, but needed it to return a checked Exception. Anyway, it's gone for now.

> On the same note, why is SSLFunction generic at all ?

This was an internal idea that in the future there might be additional SSL functions we could do as lambdas.

Xuelei/Simone 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.

Simone wrote:

> Currently, IIUC, the cipher selection is an iterative process where a
> cipher is attempted until one is negotiated.

Yes.

Simone wrote:

> Yesterday a browser could open a page and browse the site over
> http/1.1.

From my readings of the RFC, I agree with Simone and think the intent of the RFC writers was that if a sufficient connection state does not exist for HTTP/2, then it should be possible to fallback to something else instead of killing the connection. If the implementation wants to insist on HTTP/2 only, the ALPN selector can certainly enforce that, but it needs to try the H2 ciphersuites first.

With this API, we can do either style.

Simone wrote:

> If the server chooses a blacklisted cipher, and then "h2" as protocol,
> it's a non compliant server.

IIUC, the HTTP/2 blacklist is just strongly recommended ("...SHOULD NOT use any of the cipher suites...black list"), but not required. Such potential peers must also support such a configuration, but in general, it will not. See section 9.2.2. I think it's still considered compliant to the spec tho.

Simone wrote two different ways to do selection:

> 1) ... so that TLS protocol, cipher (possibly the alias too) and
> application protocol are chosen together, or
> 2) we separate the TLS protocol and
> cipher negotiation (and alias) in one step, and we perform application
> protocol selection afterwards.

Rather than completely redo the JSSE selection mechanism with the (version/ciphersuite/ALPN)-tuple idea (which would be a much more involved API and behavior change), I think the more straightforward solution (2) is better.

Simon wrote:

> Alternatively, the ciphers on the server are sorted so that those
> valid for h2 have higher priority (they are attempted before all the
> others), so that there is a high chance that a h2 valid cipher is
> chosen (but no guarantee) before choosing the application protocol.

This is the best approach to date. Applications can simply order the enabled ciphersuites based on the server's ALPN preference. For example, say three ALPN values are known/supported by a server: "h2" > "spdy/3" > "http/1.1".

If the ALPN-enabled app provides the ordered list of ciphersuites {h2[] spdy/3[], http/1.1[]}, then calls sslParameters.setUseCipherSuitesOrder(true), during handshaking, the server will intersect the received client ciphersuites with the server's enabled ciphersuites, which will then be tried for h2 first, then spdy/3, then http/1.1. Once the server has selected the protocol version and ciphersuite, the ALPN selector is called to select an appropriate ALPN value. For a concrete example, please see my test case in the webrev, and below.

Micheal wrote:

> If (internally) the server
> chooses that cipher first,
> without knowing the application protocol is going to be HTTP/2
> then you end up with a non-compliant connection that will probably
> have to be closed for reason of insufficient security.

That assumes the peer won't accept a down-version, see above.

I also had another API approach that I played with where the ALPN selector was also tasked with the job of "pre-approving" ciphersuites before they were tried. That is, if a ciphersuite would never work for a preferred ALPN value, we would remove it from consideration. However, things got really complicated because if we got to the end of the ciphersuite list because we were insisting on finding an h2-compatible suites, we couldn't jump back and try the http/1.1 suites as a fallback.

The server-ordered ciphersuite approach took care of that problem.

> Also, it is critical to detail how the mechanism work.
>
> Example implementations for SSLFunction would be great to have: the
> typical HTTP/2 case is to select the application protocol based on the
> TLS protocol and the already negotiated cipher.

I have a "working" test example which shows how the ALPN APIs can be used for HTTP/2 clients and servers. It is a minor configuration tweak to the jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java test that we use as the basis for JSSE SSLEngine testing.


http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/SSLEngineAlpnHttp2.java.html

See the configuration in createSSLEngines() around line 265 and 280.


http://cr.openjdk.java.net/~wetmore/8051498/webrev.04/test/javax/net/ssl/ALPN/Http2ApplicationSelector.java.html

Note the HTTP/2 blacklist and reordering code.

The code is not actually "working" yet (haven't merged API/impl repos yet), but shows how to configure/use this API.

Michael wrote:

> Okay. I've been looking at it from the client point of view, and
> as far as I understand it, all of the information is available to the
> client at the right time.

For ALPN, for clients the protocol version/ciphersuite/ALPN do come back in the ServerHello in one chunk. As you've realized by now, the discussion is about the server side selection.

Brad

BTW, in our current default configuration, for HTTP/2 only these ciphersuites are available (not blacklisted).

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256

Reply via email to