Darn those Chicken/Eggs [1]!
Yes, you are correct. The steps for the current server code:
1. The ClientHello is parsed, and the SNI matcher callback is called.
It does not return which value was matched in the ServerHello, just
whether a SNI name was matched or not:
The "extension_data" field of this extension SHALL be
empty.
2. Begin generating the ServerHello, choose the Protocol Version.
3. Iterate through the list of client's ciphersuites and call the
Server's KeyManager (KM) callback until the KM returns key material we
can use. A return string selects the proposed ciphersuite.
So we currently don't know the selected ciphersuite until the KM has
been called (possibly multiple times).
If we choose the ALPN before the ciphersuite, the ciphersuite selection
may end up being inappropriate (HTTP/2 blacklist). If we choose the
ciphersuite first, then the ALPN value wasn't used to drive the
certificate selection.
Two suggestions in preferred order below.
In each of these cases, unfortunately there is currently no indication
of the proposed Ciphersuite, so we need to modify the behavior of
getHandshakeSession().getCipherSuite() to fill in the proposed
CipherSuite before the call to the KM. This seems ok with the current
wording, but we'd need to make that explicit. This value will change
for each ciphersuite/KM choice attempt.
Each suggestion below is followed by our previously proposed ALPN
callback to make the actual ALPN value selection:
1a. Add a parallel method to ExtendedSSLSession:
public List<String> getRequestedApplicationProtocolNames();
along with the previously proposed selected name:
public String getApplicationProtocol()
(I'll be changing these names. I'm open to suggestions).
When the KM is called, the TLS protocol (e.g. TLSv1.2) has already been
selected.
Both of the major selection parameters (protocol/proposed ciphersuite)
are now available, and applications have access to the ordered ALPN list
to see what the client's requested values were.
-or-
1b. Keep API as is, and make two callbacks. This first is an advisory
value, the TLS protocol version and proposed ciphersuite will be
available in getHandshakeSession(). The second callback sets the final
value that will be sent.
I think 1.a is my preference.
To answer some of the other questions.
On 5/25/2015 3:08 AM, Michael McMahon wrote:
2) The notion of client preference needs to be made explicit. This could
just be a matter
of javadoc given that List<String> is ordered. So, it could be
enough to say the same
order is used in the protocol.
Yes, I'll add that.
3) It's a shame that the RFC didn't mandate UTF8 encoded byte sequences
for the
protocol name, because it's theoretically possible that non UTF8
byte sequences
could get registered, but that's not a concern for HTTP/2 at least.
No. Not sure what we can do about that, short of going back to the
byte[] option. Given that IANA operates mainly in English, I would
expect the namespaces will probably be ASCII, but that is just conjecture.
> This would be possible, IIUC, using
> sslEngine.getHandshakeSession().getRequestedServerNames() in the
> ApplicationProtocolSelector implementation.
Yes.
> but I understand it's mentioned in RFC 7301.
Yes, see the last sentence section 1.
Brad
[1] https://www.youtube.com/watch?v=ixgf5SlvOB4&feature=youtu.be&t=27