> 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

Reply via email to