TLS ALPN Proposal v5

Bradford Wetmore bradford.wetmore at oracle.com
Wed Sep 23 05:04:00 UTC 2015


 > This new proposal still requires that ciphers are sorted in a way that
 > matches the ApplicationProtocol order.
 > Would be nice if, along with the HTTP/2 blacklist, there is a HTTP/2
 > comparator that sorts ciphers putting the blacklisted ones at the end.

Hm...is the sample code at the end of the initial class description 
insufficient?  Adding a comparator seems a little heavyweight in that it 
could require access to the ciphersuite internals and would add a lot of 
complexity for this one known use case.  When TLSv1.3 is done, the 
blacklist stuff in HTTP/2 goes away.

 > I don't like the first parameter of ApplicationProtocol.match() to be
 > a Map<String, String>;

I personally don't like the Map<String,String> either, but for 
situations where we don't have a connection yet (e.g. trying to reduce 
the set of protocols and/or ciphersuites for setEnabledCiphersuites()), 
this worked.

Xuelei suggested the String->String map for future expansion, making it 
easier to add new parameters in between major releases if new ALPN 
protocols are introduced.  (For those who aren't aware, adding 
classes/methods/variables/etc. is pretty much forbidden in update 
(minor) releases, but simply adding a new string to a Map is generally OK.)

 > I would prefer a full blown class at this
 > point, that contains all the parameters, for example:
 >
 > inner class ApplicationProtocol.Info
 > {
 >      tlsProtocol
 >      cipher
 >      sslEngine
 >      sessionIsResuming
 >      etc.
 > }

The other problem here is having a way to get at all the parameters of a 
connection.  Enumerating them all in such a class is essentially 
duplicating methods that are already currently available in the 
SSLSession (handshakeSession) + SSLSocket/SSLEngines classes.  Any 
future enhancements to SSLSocket/SSLEngine would have to be added here 
again in such a class.

 > I also don't understand why there are 2 methods for the protocol name
 > ? What value does it bring to have 2 methods for the same thing ?

Please see the IANA registry:

 
http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids

for RFC 7301:

     http://www.rfc-editor.org/info/rfc7301

getProtocolName() is the IANA/IETF textual representation of the 
protocol name (i.e. "Protocol" column), for example "HTTP/1.1", 
"SPDY/3", and "HTTP/2 over TLS".  I suppose toString() could be used 
instead, but thought it might eventually output additional ALPN value 
state.  I don't have any concrete plans at this point.

getNetworkSequence() is the identification sequence for the protocol 
(i.e. "Identification Sequence" column), and represents the actual byte 
identifiers that will travel the network in an ALPN extension.

     0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1")
     0x73 0x70 0x64 0x79 0x2f 0x33 ("spdy/3")
     0x68 0x32 ("h2")

When client wants to send the extension over the network, it grabs the 
ApplicationProtocols values from the SSLParameters, then calls 
getNetworkSequence() on each ApplicationProtocol to obtain the actual 
opaque ProtocolName(1..2^8-1) to send.  Likewise on the server side, we 
match the incoming active ALPN opaque values with the list of mutually 
agreeable ALPN values.  And of course, send back the final selected value.

 > RFC 7301 hints that the bytes to send over the network are the UTF-8
 > bytes from that string.

Intentional, this ApplicationProtocol class and these two contained 
values eliminate that problem.  There is no UTF-8 to network byte 
conversion needed.  The network sequence is hard-coded into the 
ApplicationProtocol and is used directly as the network bytes.  The 
protocolName string is for user clarity.

 > There are still a lot of details missing, such as where is the chosen
 > ALPN value stored

In SSLSocket/SSLEngine.

If the connection is in the middle of a handshake and you need the 
handshake value:

     getHandshakeApplicationProtocol()

Once the connection has finished handshaking, you can get the 
final/active value:

     getApplicationProtocol()

The ALPN value is no longer in SSLSession, since it needs to be 
per-connection, not per session.

 >  (and how it can be retrieved by the KeyManager, for
 > example),

JSSE makes calls to X509KeyManagers (for SSLSockets) and 
X509ExtendedKeyManager (for SSLEngines).  The chooseServerAlias methods 
are passed SSLSocket/SSLEngines for the connection being negotiated.

As above, SSLSocket/SSLEngine now have:

     getHandshakeApplicationProtocol();  // if handshaking
     getApplicationProtocol();           // if not handshaking

So if chooseServerAlias is called, we're in the middle of a handshake, 
and can get the ALPN value thusly:

     chooseClientAlias(String[] keyType,
             Principal[] issuers, Socket socket) {

         ...deleted...

         ApplicationProtocol alpn =
             socket.getHandshakeApplicationProtocol();

         ...deleted...

 > as well as the webrev not showing any real implementation,

Yes, I'm using pseudo-code at this point, Vinnie has merged the actual 
code but is waiting on the API.

 > and how exactly the ApplicationProtocol instances are called, etc.

See the test code for typical application examples.  The line numbers 
are for the latest webrev (see below).  Look in SSLEngineAlpnHttp2.java:

SSLParameter ALPN Configuration:
server:  line 340-342
client:  lines 353-355

Ciphersuite reordering for H2:
server:  line 330-337/360-387
     This is directly from the class description.

ALPN client-side verification of server's choice:
client:  line 272-287

The server check could be added in a similar manner.

I also added a SSLSocket test, which is almost identical with the 
exception of the handshake completion.  In SSLEngine, you look for the 
HANDSHAKE_COMPLETED result.  But in SSLSocket, a call to 
startHandshake() will complete the initial handshake.  You then call 
sslSocket.getApplicationProtocol() and do your verification.  If you 
want, you could also register a HandshakeCompletedListener, but that 
isn't very useful in this case.

 > For example, client sends ["h2"], server has ["http/1.1", "h2"]. Will
 > the instance of ApplicationProtocol corresponding to "http/1.1" be
 > invoked at all ?

No.

 > If not, there is a missing step in your algorithm above, where the
 > implementation intersects the ALPN values from both peers.

Missing?  You mean in this part?

     Select TLS version

     for each ciphersuite
         ...deleted...
         for each ALPN value

Yes, I didn't mention the ALPN value calculation, it's just the 
intersection as you would expect.  That code is in ServerHandshaker.java.

536 // apl = alpn.getPeerAPs() intersection localApl()) {

 > Finally, I think this API may be suitable for the server, but not much
 > for the client, which is equally important.

Absolutely.  The client must know which protocol was negotiated before 
sending any application data (e.g. H2 vs http/1.1 requests).

 > I don't see how a client application can figure out what protocol has
 > been chosen by the server, because there is no final notification
 > about that and the API seems totally geared towards server "matching"
 > more than client notification. For me this is a blocker.

Please see the above.

 > Can you please provide an example of how a client application would
 > use this new API to be notified that the server has chosen protocol
 > "foo" ?

I've updated the webrev to include an SSLSocket test variant, and added 
a few more comments.

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

Hopefully things are more clear now.  Thanks for your review/comments.

Brad



More information about the security-dev mailing list