TLS ALPN Proposal v3

Bradford Wetmore bradford.wetmore at oracle.com
Wed Jul 8 23:42:59 UTC 2015


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



More information about the security-dev mailing list