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